From 96bd6224f07b8bf73e0359f15a3d7678118494e6 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:23:56 +0900 Subject: clk: samsung: exynos5433: Add clocks using common clock framework This patch adds support for the CMU (Clock Management Units) of Exynos5433 which is an Octa-core 64bit SoC. This patch supports necessary clocks (PLL/MMC/UART/MCT/I2C/SPI) for kernel boot and includes binding documentation for Exynos5433 clock controller. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae [s.nawrocki@samsung.com: whitespace cleanup in dt-bindings/clock/exynos5433.h] [ added U suffix to first arguments of PLL_35XX_RATE()] Signed-off-by: Sylwester Nawrocki --- include/dt-bindings/clock/exynos5433.h | 199 +++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 include/dt-bindings/clock/exynos5433.h (limited to 'include') diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h new file mode 100644 index 000000000000..5c4e2e39ce49 --- /dev/null +++ b/include/dt-bindings/clock/exynos5433.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Author: Chanwoo Choi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _DT_BINDINGS_CLOCK_EXYNOS5433_H +#define _DT_BINDINGS_CLOCK_EXYNOS5433_H + +/* CMU_TOP */ +#define CLK_FOUT_ISP_PLL 1 +#define CLK_FOUT_AUD_PLL 2 + +#define CLK_MOUT_AUD_PLL 10 +#define CLK_MOUT_ISP_PLL 11 +#define CLK_MOUT_AUD_PLL_USER_T 12 +#define CLK_MOUT_MPHY_PLL_USER 13 +#define CLK_MOUT_MFC_PLL_USER 14 +#define CLK_MOUT_BUS_PLL_USER 15 +#define CLK_MOUT_ACLK_HEVC_400 16 +#define CLK_MOUT_ACLK_CAM1_333 17 +#define CLK_MOUT_ACLK_CAM1_552_B 18 +#define CLK_MOUT_ACLK_CAM1_552_A 19 +#define CLK_MOUT_ACLK_ISP_DIS_400 20 +#define CLK_MOUT_ACLK_ISP_400 21 +#define CLK_MOUT_ACLK_BUS0_400 22 +#define CLK_MOUT_ACLK_MSCL_400_B 23 +#define CLK_MOUT_ACLK_MSCL_400_A 24 +#define CLK_MOUT_ACLK_GSCL_333 25 +#define CLK_MOUT_ACLK_G2D_400_B 26 +#define CLK_MOUT_ACLK_G2D_400_A 27 +#define CLK_MOUT_SCLK_JPEG_C 28 +#define CLK_MOUT_SCLK_JPEG_B 29 +#define CLK_MOUT_SCLK_JPEG_A 30 +#define CLK_MOUT_SCLK_MMC2_B 31 +#define CLK_MOUT_SCLK_MMC2_A 32 +#define CLK_MOUT_SCLK_MMC1_B 33 +#define CLK_MOUT_SCLK_MMC1_A 34 +#define CLK_MOUT_SCLK_MMC0_D 35 +#define CLK_MOUT_SCLK_MMC0_C 36 +#define CLK_MOUT_SCLK_MMC0_B 37 +#define CLK_MOUT_SCLK_MMC0_A 38 +#define CLK_MOUT_SCLK_SPI4 39 +#define CLK_MOUT_SCLK_SPI3 40 +#define CLK_MOUT_SCLK_UART2 41 +#define CLK_MOUT_SCLK_UART1 42 +#define CLK_MOUT_SCLK_UART0 43 +#define CLK_MOUT_SCLK_SPI2 44 +#define CLK_MOUT_SCLK_SPI1 45 +#define CLK_MOUT_SCLK_SPI0 46 + +#define CLK_DIV_ACLK_FSYS_200 100 +#define CLK_DIV_ACLK_IMEM_SSSX_266 101 +#define CLK_DIV_ACLK_IMEM_200 102 +#define CLK_DIV_ACLK_IMEM_266 103 +#define CLK_DIV_ACLK_PERIC_66_B 104 +#define CLK_DIV_ACLK_PERIC_66_A 105 +#define CLK_DIV_ACLK_PERIS_66_B 106 +#define CLK_DIV_ACLK_PERIS_66_A 107 +#define CLK_DIV_SCLK_MMC1_B 108 +#define CLK_DIV_SCLK_MMC1_A 109 +#define CLK_DIV_SCLK_MMC0_B 110 +#define CLK_DIV_SCLK_MMC0_A 111 +#define CLK_DIV_SCLK_MMC2_B 112 +#define CLK_DIV_SCLK_MMC2_A 113 +#define CLK_DIV_SCLK_SPI1_B 114 +#define CLK_DIV_SCLK_SPI1_A 115 +#define CLK_DIV_SCLK_SPI0_B 116 +#define CLK_DIV_SCLK_SPI0_A 117 +#define CLK_DIV_SCLK_SPI2_B 118 +#define CLK_DIV_SCLK_SPI2_A 119 +#define CLK_DIV_SCLK_UART2 120 +#define CLK_DIV_SCLK_UART1 121 +#define CLK_DIV_SCLK_UART0 122 +#define CLK_DIV_SCLK_SPI4_B 123 +#define CLK_DIV_SCLK_SPI4_A 124 +#define CLK_DIV_SCLK_SPI3_B 125 +#define CLK_DIV_SCLK_SPI3_A 126 + +#define CLK_ACLK_PERIC_66 200 +#define CLK_ACLK_PERIS_66 201 +#define CLK_ACLK_FSYS_200 202 +#define CLK_SCLK_MMC2_FSYS 203 +#define CLK_SCLK_MMC1_FSYS 204 +#define CLK_SCLK_MMC0_FSYS 205 +#define CLK_SCLK_SPI4_PERIC 206 +#define CLK_SCLK_SPI3_PERIC 207 +#define CLK_SCLK_UART2_PERIC 208 +#define CLK_SCLK_UART1_PERIC 209 +#define CLK_SCLK_UART0_PERIC 210 +#define CLK_SCLK_SPI2_PERIC 211 +#define CLK_SCLK_SPI1_PERIC 212 +#define CLK_SCLK_SPI0_PERIC 213 + +#define TOP_NR_CLK 214 + +/* CMU_CPIF */ +#define CLK_FOUT_MPHY_PLL 1 + +#define CLK_MOUT_MPHY_PLL 2 + +#define CLK_DIV_SCLK_MPHY 10 + +#define CLK_SCLK_MPHY_PLL 11 +#define CLK_SCLK_UFS_MPHY 11 + +#define CPIF_NR_CLK 12 + +/* CMU_MIF */ +#define CLK_FOUT_MEM0_PLL 1 +#define CLK_FOUT_MEM1_PLL 2 +#define CLK_FOUT_BUS_PLL 3 +#define CLK_FOUT_MFC_PLL 4 + +#define MIF_NR_CLK 5 + +/* CMU_PERIC */ +#define CLK_PCLK_SPI2 1 +#define CLK_PCLK_SPI1 2 +#define CLK_PCLK_SPI0 3 +#define CLK_PCLK_UART2 4 +#define CLK_PCLK_UART1 5 +#define CLK_PCLK_UART0 6 +#define CLK_PCLK_HSI2C3 7 +#define CLK_PCLK_HSI2C2 8 +#define CLK_PCLK_HSI2C1 9 +#define CLK_PCLK_HSI2C0 10 +#define CLK_PCLK_I2C7 11 +#define CLK_PCLK_I2C6 12 +#define CLK_PCLK_I2C5 13 +#define CLK_PCLK_I2C4 14 +#define CLK_PCLK_I2C3 15 +#define CLK_PCLK_I2C2 16 +#define CLK_PCLK_I2C1 17 +#define CLK_PCLK_I2C0 18 +#define CLK_PCLK_SPI4 19 +#define CLK_PCLK_SPI3 20 +#define CLK_PCLK_HSI2C11 21 +#define CLK_PCLK_HSI2C10 22 +#define CLK_PCLK_HSI2C9 23 +#define CLK_PCLK_HSI2C8 24 +#define CLK_PCLK_HSI2C7 25 +#define CLK_PCLK_HSI2C6 26 +#define CLK_PCLK_HSI2C5 27 +#define CLK_PCLK_HSI2C4 28 +#define CLK_SCLK_SPI4 29 +#define CLK_SCLK_SPI3 30 +#define CLK_SCLK_SPI2 31 +#define CLK_SCLK_SPI1 32 +#define CLK_SCLK_SPI0 33 +#define CLK_SCLK_UART2 34 +#define CLK_SCLK_UART1 35 +#define CLK_SCLK_UART0 36 + +#define PERIC_NR_CLK 37 + +/* CMU_PERIS */ +#define CLK_PCLK_HPM_APBIF 1 +#define CLK_PCLK_TMU1_APBIF 2 +#define CLK_PCLK_TMU0_APBIF 3 +#define CLK_PCLK_PMU_PERIS 4 +#define CLK_PCLK_SYSREG_PERIS 5 +#define CLK_PCLK_CMU_TOP_APBIF 6 +#define CLK_PCLK_WDT_APOLLO 7 +#define CLK_PCLK_WDT_ATLAS 8 +#define CLK_PCLK_MCT 9 +#define CLK_PCLK_HDMI_CEC 10 + +#define PERIS_NR_CLK 11 + +/* CMU_FSYS */ +#define CLK_MOUT_ACLK_FSYS_200_USER 1 +#define CLK_MOUT_SCLK_MMC2_USER 2 +#define CLK_MOUT_SCLK_MMC1_USER 3 +#define CLK_MOUT_SCLK_MMC0_USER 4 + +#define CLK_ACLK_PCIE 50 +#define CLK_ACLK_PDMA1 51 +#define CLK_ACLK_TSI 52 +#define CLK_ACLK_MMC2 53 +#define CLK_ACLK_MMC1 54 +#define CLK_ACLK_MMC0 55 +#define CLK_ACLK_UFS 56 +#define CLK_ACLK_USBHOST20 57 +#define CLK_ACLK_USBHOST30 58 +#define CLK_ACLK_USBDRD30 59 +#define CLK_ACLK_PDMA0 60 +#define CLK_SCLK_MMC2 61 +#define CLK_SCLK_MMC1 62 +#define CLK_SCLK_MMC0 63 +#define CLK_PDMA1 64 +#define CLK_PDMA0 65 + +#define FSYS_NR_CLK 66 + +#endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 232364969d8a8a17c52fd9b754d15924abf98d6a Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:23:57 +0900 Subject: clk: samsung: exynos5433: Add MUX clocks of CMU_TOP domain This patch adds the MUX (multiplexer) clocks for CMU_TOP domain of Exynos5433. CMU_TOP domain provides source clocks to other CMU domains. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 90 ++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 31 +++++++++++- 2 files changed, 119 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index a4047390bfc2..5585dce04a38 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -208,6 +208,7 @@ PNAME(mout_mphy_pll_user_p) = { "oscclk", "sclk_mphy_pll", }; PNAME(mout_mfc_pll_user_p) = { "oscclk", "sclk_mfc_pll", }; PNAME(mout_bus_pll_user_p) = { "oscclk", "sclk_bus_pll", }; PNAME(mout_bus_pll_user_t_p) = { "oscclk", "mout_bus_pll_user", }; +PNAME(mout_mphy_pll_user_t_p) = { "oscclk", "mout_mphy_pll_user", }; PNAME(mout_bus_mfc_pll_user_p) = { "mout_bus_pll_user", "mout_mfc_pll_user",}; PNAME(mout_mfc_bus_pll_user_p) = { "mout_mfc_pll_user", "mout_bus_pll_user",}; @@ -215,6 +216,12 @@ PNAME(mout_aclk_cam1_552_b_p) = { "mout_aclk_cam1_552_a", "mout_mfc_pll_user", }; PNAME(mout_aclk_cam1_552_a_p) = { "mout_isp_pll", "mout_bus_pll_user", }; +PNAME(mout_aclk_mfc_400_c_p) = { "mout_aclk_mfc_400_b", + "mout_mphy_pll_user", }; +PNAME(mout_aclk_mfc_400_b_p) = { "mout_aclk_mfc_400_a", + "mout_bus_pll_user", }; +PNAME(mout_aclk_mfc_400_a_p) = { "mout_mfc_pll_user", "mout_isp_pll", }; + PNAME(mout_bus_mphy_pll_user_p) = { "mout_bus_pll_user", "mout_mphy_pll_user", }; PNAME(mout_aclk_mscl_b_p) = { "mout_aclk_mscl_400_a", @@ -231,6 +238,21 @@ PNAME(mout_sclk_mmc0_d_p) = { "mout_sclk_mmc0_c", "mout_isp_pll", }; PNAME(mout_sclk_mmc0_c_p) = { "mout_sclk_mmc0_b", "mout_mphy_pll_user",}; PNAME(mout_sclk_mmc0_b_p) = { "mout_sclk_mmc0_a", "mout_mfc_pll_user", }; +PNAME(mout_sclk_spdif_p) = { "sclk_audio0", "sclk_audio1", + "oscclk", "ioclk_spdif_extclk", }; +PNAME(mout_sclk_audio1_p) = { "ioclk_audiocdclk1", "oscclk", + "mout_aud_pll_user_t",}; +PNAME(mout_sclk_audio0_p) = { "ioclk_audiocdclk0", "oscclk", + "mout_aud_pll_user_t",}; + +static struct samsung_fixed_rate_clock top_fixed_clks[] __initdata = { + /* Xi2s{0|1}CDCLK input clock for I2S/PCM */ + FRATE(0, "ioclk_audiocdclk1", NULL, CLK_IS_ROOT, 100000000), + FRATE(0, "ioclk_audiocdclk0", NULL, CLK_IS_ROOT, 100000000), + /* Xi2s1SDI input clock for SPDIF */ + FRATE(0, "ioclk_spdif_extclk", NULL, CLK_IS_ROOT, 100000000), +}; + static struct samsung_mux_clock top_mux_clks[] __initdata = { /* MUX_SEL_TOP0 */ MUX(CLK_MOUT_AUD_PLL, "mout_aud_pll", mout_aud_pll_p, MUX_SEL_TOP0, @@ -276,6 +298,14 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { MUX(CLK_MOUT_ACLK_G2D_400_A, "mout_aclk_g2d_400_a", mout_bus_mfc_pll_user_p, MUX_SEL_TOP3, 0, 1), + /* MUX_SEL_TOP4 */ + MUX(CLK_MOUT_ACLK_MFC_400_C, "mout_aclk_mfc_400_c", + mout_aclk_mfc_400_c_p, MUX_SEL_TOP4, 8, 1), + MUX(CLK_MOUT_ACLK_MFC_400_B, "mout_aclk_mfc_400_b", + mout_aclk_mfc_400_b_p, MUX_SEL_TOP4, 4, 1), + MUX(CLK_MOUT_ACLK_MFC_400_A, "mout_aclk_mfc_400_a", + mout_aclk_mfc_400_a_p, MUX_SEL_TOP4, 0, 1), + /* MUX_SEL_TOP_MSCL */ MUX(CLK_MOUT_SCLK_JPEG_C, "mout_sclk_jpeg_c", mout_sclk_jpeg_c_p, MUX_SEL_TOP_MSCL, 8, 1), @@ -284,6 +314,20 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { MUX(CLK_MOUT_SCLK_JPEG_A, "mout_sclk_jpeg_a", mout_bus_pll_user_t_p, MUX_SEL_TOP_MSCL, 0, 1), + /* MUX_SEL_TOP_CAM1 */ + MUX(CLK_MOUT_SCLK_ISP_SENSOR2, "mout_sclk_isp_sensor2", + mout_bus_pll_user_t_p, MUX_SEL_TOP_CAM1, 24, 1), + MUX(CLK_MOUT_SCLK_ISP_SENSOR1, "mout_sclk_isp_sensor1", + mout_bus_pll_user_t_p, MUX_SEL_TOP_CAM1, 20, 1), + MUX(CLK_MOUT_SCLK_ISP_SENSOR0, "mout_sclk_isp_sensor0", + mout_bus_pll_user_t_p, MUX_SEL_TOP_CAM1, 16, 1), + MUX(CLK_MOUT_SCLK_ISP_UART, "mout_sclk_isp_uart", + mout_bus_pll_user_t_p, MUX_SEL_TOP_CAM1, 8, 1), + MUX(CLK_MOUT_SCLK_ISP_SPI1, "mout_sclk_isp_spi1", + mout_bus_pll_user_t_p, MUX_SEL_TOP_CAM1, 4, 1), + MUX(CLK_MOUT_SCLK_ISP_SPI0, "mout_sclk_isp_spi0", + mout_bus_pll_user_t_p, MUX_SEL_TOP_CAM1, 0, 1), + /* MUX_SEL_TOP_FSYS0 */ MUX(CLK_MOUT_SCLK_MMC2_B, "mout_sclk_mmc2_b", mout_sclk_mmc2_b_p, MUX_SEL_TOP_FSYS0, 28, 1), @@ -302,6 +346,16 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { MUX(CLK_MOUT_SCLK_MMC0_A, "mout_sclk_mmc0_a", mout_bus_pll_user_t_p, MUX_SEL_TOP_FSYS0, 0, 1), + /* MUX_SEL_TOP_FSYS1 */ + MUX(CLK_MOUT_SCLK_PCIE_100, "mout_sclk_pcie_100", mout_bus_pll_user_t_p, + MUX_SEL_TOP_FSYS1, 12, 1), + MUX(CLK_MOUT_SCLK_UFSUNIPRO, "mout_sclk_ufsunipro", + mout_mphy_pll_user_t_p, MUX_SEL_TOP_FSYS1, 8, 1), + MUX(CLK_MOUT_SCLK_USBHOST30, "mout_sclk_usbhost30", + mout_bus_pll_user_t_p, MUX_SEL_TOP_FSYS1, 4, 1), + MUX(CLK_MOUT_SCLK_USBDRD30, "mout_sclk_usbdrd30", + mout_bus_pll_user_t_p, MUX_SEL_TOP_FSYS1, 0, 1), + /* MUX_SEL_TOP_PERIC0 */ MUX(CLK_MOUT_SCLK_SPI4, "mout_sclk_spi4", mout_bus_pll_user_t_p, MUX_SEL_TOP_PERIC0, 28, 1), @@ -319,6 +373,16 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { MUX_SEL_TOP_PERIC0, 4, 1), MUX(CLK_MOUT_SCLK_SPI0, "mout_sclk_spi0", mout_bus_pll_user_t_p, MUX_SEL_TOP_PERIC0, 0, 1), + + /* MUX_SEL_TOP_PERIC1 */ + MUX(CLK_MOUT_SCLK_SLIMBUS, "mout_sclk_slimbus", mout_aud_pll_user_p, + MUX_SEL_TOP_PERIC1, 16, 1), + MUX(CLK_MOUT_SCLK_SPDIF, "mout_sclk_spdif", mout_sclk_spdif_p, + MUX_SEL_TOP_PERIC1, 12, 2), + MUX(CLK_MOUT_SCLK_AUDIO1, "mout_sclk_audio1", mout_sclk_audio1_p, + MUX_SEL_TOP_PERIC1, 4, 2), + MUX(CLK_MOUT_SCLK_AUDIO0, "mout_sclk_audio0", mout_sclk_audio0_p, + MUX_SEL_TOP_PERIC1, 0, 2), }; static struct samsung_div_clock top_div_clks[] __initdata = { @@ -382,6 +446,16 @@ static struct samsung_div_clock top_div_clks[] __initdata = { DIV(CLK_DIV_SCLK_UART0, "div_sclk_uart0", "mout_sclk_uart1", DIV_TOP_PERIC2, 0, 4), + /* DIV_TOP_PERIC3 */ + DIV(CLK_DIV_SCLK_I2S1, "div_sclk_i2s1", "sclk_audio1", + DIV_TOP_PERIC3, 16, 6), + DIV(CLK_DIV_SCLK_PCM1, "div_sclk_pcm1", "sclk_audio1", + DIV_TOP_PERIC3, 8, 8), + DIV(CLK_DIV_SCLK_AUDIO1, "div_sclk_audio1", "mout_sclk_audio1", + DIV_TOP_PERIC3, 4, 4), + DIV(CLK_DIV_SCLK_AUDIO0, "div_sclk_audio0", "mout_sclk_audio0", + DIV_TOP_PERIC3, 0, 4), + /* DIV_TOP_PERIC4 */ DIV(CLK_DIV_SCLK_SPI4_B, "div_sclk_spi4_b", "div_sclk_spi4_a", DIV_TOP_PERIC4, 16, 8), @@ -418,6 +492,12 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { ENABLE_SCLK_TOP_PERIC, 12, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI3_PERIC, "sclk_spi3_peric", "div_sclk_spi3_b", ENABLE_SCLK_TOP_PERIC, 11, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_SPDIF_PERIC, "sclk_spdif_peric", "mout_sclk_spdif", + ENABLE_SCLK_TOP_PERIC, 9, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_I2S1_PERIC, "sclk_i2s1_peric", "div_sclk_i2s1", + ENABLE_SCLK_TOP_PERIC, 8, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_PCM1_PERIC, "sclk_pcm1_peric", "div_sclk_pcm1", + ENABLE_SCLK_TOP_PERIC, 7, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_UART2_PERIC, "sclk_uart2_peric", "div_sclk_uart2", ENABLE_SCLK_TOP_PERIC, 5, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_UART1_PERIC, "sclk_uart1_peric", "div_sclk_uart1", @@ -430,6 +510,14 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { ENABLE_SCLK_TOP_PERIC, 1, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI0_PERIC, "sclk_spi0_peric", "div_sclk_spi0_b", ENABLE_SCLK_TOP_PERIC, 0, CLK_SET_RATE_PARENT, 0), + + /* MUX_ENABLE_TOP_PERIC1 */ + GATE(CLK_SCLK_SLIMBUS, "sclk_slimbus", "mout_sclk_slimbus", + MUX_ENABLE_TOP_PERIC1, 16, 0, 0), + GATE(CLK_SCLK_AUDIO1, "sclk_audio1", "div_sclk_audio1", + MUX_ENABLE_TOP_PERIC1, 4, 0, 0), + GATE(CLK_SCLK_AUDIO0, "sclk_audio0", "div_sclk_audio0", + MUX_ENABLE_TOP_PERIC1, 0, 0, 0), }; /* @@ -516,6 +604,8 @@ static struct samsung_cmu_info top_cmu_info __initdata = { .nr_div_clks = ARRAY_SIZE(top_div_clks), .gate_clks = top_gate_clks, .nr_gate_clks = ARRAY_SIZE(top_gate_clks), + .fixed_clks = top_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(top_fixed_clks), .nr_clk_ids = TOP_NR_CLK, .clk_regs = top_clk_regs, .nr_clk_regs = ARRAY_SIZE(top_clk_regs), diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 5c4e2e39ce49..8f0ee5a13db4 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -51,6 +51,23 @@ #define CLK_MOUT_SCLK_SPI2 44 #define CLK_MOUT_SCLK_SPI1 45 #define CLK_MOUT_SCLK_SPI0 46 +#define CLK_MOUT_ACLK_MFC_400_C 47 +#define CLK_MOUT_ACLK_MFC_400_B 48 +#define CLK_MOUT_ACLK_MFC_400_A 49 +#define CLK_MOUT_SCLK_ISP_SENSOR2 50 +#define CLK_MOUT_SCLK_ISP_SENSOR1 51 +#define CLK_MOUT_SCLK_ISP_SENSOR0 52 +#define CLK_MOUT_SCLK_ISP_UART 53 +#define CLK_MOUT_SCLK_ISP_SPI1 54 +#define CLK_MOUT_SCLK_ISP_SPI0 55 +#define CLK_MOUT_SCLK_PCIE_100 56 +#define CLK_MOUT_SCLK_UFSUNIPRO 57 +#define CLK_MOUT_SCLK_USBHOST30 58 +#define CLK_MOUT_SCLK_USBDRD30 59 +#define CLK_MOUT_SCLK_SLIMBUS 60 +#define CLK_MOUT_SCLK_SPDIF 61 +#define CLK_MOUT_SCLK_AUDIO1 62 +#define CLK_MOUT_SCLK_AUDIO0 63 #define CLK_DIV_ACLK_FSYS_200 100 #define CLK_DIV_ACLK_IMEM_SSSX_266 101 @@ -79,6 +96,10 @@ #define CLK_DIV_SCLK_SPI4_A 124 #define CLK_DIV_SCLK_SPI3_B 125 #define CLK_DIV_SCLK_SPI3_A 126 +#define CLK_DIV_SCLK_I2S1 127 +#define CLK_DIV_SCLK_PCM1 128 +#define CLK_DIV_SCLK_AUDIO1 129 +#define CLK_DIV_SCLK_AUDIO0 130 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -94,8 +115,14 @@ #define CLK_SCLK_SPI2_PERIC 211 #define CLK_SCLK_SPI1_PERIC 212 #define CLK_SCLK_SPI0_PERIC 213 - -#define TOP_NR_CLK 214 +#define CLK_SCLK_SPDIF_PERIC 214 +#define CLK_SCLK_I2S1_PERIC 215 +#define CLK_SCLK_PCM1_PERIC 216 +#define CLK_SCLK_SLIMBUS 217 +#define CLK_SCLK_AUDIO1 218 +#define CLK_SCLK_AUDIO0 219 + +#define TOP_NR_CLK 220 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 -- cgit v1.2.3 From d0f5de6677de4405c9acdb88db7c7cf7b9cc954e Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:23:58 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_PERIC domain This patch adds missing divider/gate clocks of CMU_PERIC domain which includes I2S/PCM/SPDIF/PWM/SLIMBUS IPs. The SPI/I2S may use external input clock which has 'ioclk_*' prefix. Signed-off-by: Chanwoo Choi [ideal.song: Change clk flags of to pclk_gpio_* clk, pclk_gpio_* should be always on] Signed-off-by: Inha Song Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 83 +++++++++++++++++++++++++++++++++- include/dt-bindings/clock/exynos5433.h | 34 +++++++++++++- 2 files changed, 114 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 5585dce04a38..10a9f8313c24 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -251,6 +251,14 @@ static struct samsung_fixed_rate_clock top_fixed_clks[] __initdata = { FRATE(0, "ioclk_audiocdclk0", NULL, CLK_IS_ROOT, 100000000), /* Xi2s1SDI input clock for SPDIF */ FRATE(0, "ioclk_spdif_extclk", NULL, CLK_IS_ROOT, 100000000), + /* XspiCLK[4:0] input clock for SPI */ + FRATE(0, "ioclk_spi4_clk_in", NULL, CLK_IS_ROOT, 50000000), + FRATE(0, "ioclk_spi3_clk_in", NULL, CLK_IS_ROOT, 50000000), + FRATE(0, "ioclk_spi2_clk_in", NULL, CLK_IS_ROOT, 50000000), + FRATE(0, "ioclk_spi1_clk_in", NULL, CLK_IS_ROOT, 50000000), + FRATE(0, "ioclk_spi0_clk_in", NULL, CLK_IS_ROOT, 50000000), + /* Xi2s1SCLK input clock for I2S1_BCLK */ + FRATE(0, "ioclk_i2s1_bclk_in", NULL, CLK_IS_ROOT, 12288000), }; static struct samsung_mux_clock top_mux_clks[] __initdata = { @@ -756,6 +764,7 @@ CLK_OF_DECLARE(exynos5433_cmu_mif, "samsung,exynos5433-cmu-mif", * Register offset definitions for CMU_PERIC */ #define DIV_PERIC 0x0600 +#define DIV_STAT_PERIC 0x0700 #define ENABLE_ACLK_PERIC 0x0800 #define ENABLE_PCLK_PERIC0 0x0900 #define ENABLE_PCLK_PERIC1 0x0904 @@ -766,6 +775,7 @@ CLK_OF_DECLARE(exynos5433_cmu_mif, "samsung,exynos5433-cmu-mif", static unsigned long peric_clk_regs[] __initdata = { DIV_PERIC, + DIV_STAT_PERIC, ENABLE_ACLK_PERIC, ENABLE_PCLK_PERIC0, ENABLE_PCLK_PERIC1, @@ -775,14 +785,57 @@ static unsigned long peric_clk_regs[] __initdata = { ENABLE_IP_PERIC2, }; +static struct samsung_div_clock peric_div_clks[] __initdata = { + /* DIV_PERIC */ + DIV(CLK_DIV_SCLK_SCI, "div_sclk_sci", "oscclk", DIV_PERIC, 4, 4), + DIV(CLK_DIV_SCLK_SC_IN, "div_sclk_sc_in", "oscclk", DIV_PERIC, 0, 4), +}; + static struct samsung_gate_clock peric_gate_clks[] __initdata = { + /* ENABLE_ACLK_PERIC */ + GATE(CLK_ACLK_AHB2APB_PERIC2P, "aclk_ahb2apb_peric2p", "aclk_peric_66", + ENABLE_ACLK_PERIC, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_PERIC1P, "aclk_ahb2apb_peric1p", "aclk_peric_66", + ENABLE_ACLK_PERIC, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_PERIC0P, "aclk_ahb2apb_peric0p", "aclk_peric_66", + ENABLE_ACLK_PERIC, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PERICNP_66, "aclk_pericnp_66", "aclk_peric_66", + ENABLE_ACLK_PERIC, 0, CLK_IGNORE_UNUSED, 0), + /* ENABLE_PCLK_PERIC0 */ + GATE(CLK_PCLK_SCI, "pclk_sci", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 31, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_GPIO_FINGER, "pclk_gpio_finger", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 30, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_GPIO_ESE, "pclk_gpio_ese", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 29, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PWM, "pclk_pwm", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 28, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_SPDIF, "pclk_spdif", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 26, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_PCM1, "pclk_pcm1", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 25, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_I2S1, "pclk_i2s", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 24, CLK_SET_RATE_PARENT, 0), GATE(CLK_PCLK_SPI2, "pclk_spi2", "aclk_peric_66", ENABLE_PCLK_PERIC0, 23, CLK_SET_RATE_PARENT, 0), GATE(CLK_PCLK_SPI1, "pclk_spi1", "aclk_peric_66", ENABLE_PCLK_PERIC0, 22, CLK_SET_RATE_PARENT, 0), GATE(CLK_PCLK_SPI0, "pclk_spi0", "aclk_peric_66", ENABLE_PCLK_PERIC0, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_ADCIF, "pclk_adcif", "aclk_peric_66", ENABLE_PCLK_PERIC0, + 20, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_GPIO_TOUCH, "pclk_gpio_touch", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_GPIO_NFC, "pclk_gpio_nfc", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_GPIO_PERIC, "pclk_gpio_peric", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_PERIC, "pclk_pmu_peric", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 16, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PCLK_SYSREG_PERIC, "pclk_sysreg_peric", "aclk_peric_66", + ENABLE_PCLK_PERIC0, 15, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_PCLK_UART2, "pclk_uart2", "aclk_peric_66", ENABLE_PCLK_PERIC0, 14, CLK_SET_RATE_PARENT, 0), GATE(CLK_PCLK_UART1, "pclk_uart1", "aclk_peric_66", ENABLE_PCLK_PERIC0, @@ -837,15 +890,39 @@ static struct samsung_gate_clock peric_gate_clks[] __initdata = { ENABLE_PCLK_PERIC1, 0, CLK_SET_RATE_PARENT, 0), /* ENABLE_SCLK_PERIC */ + GATE(CLK_SCLK_IOCLK_SPI4, "sclk_ioclk_spi4", "ioclk_spi4_clk_in", + ENABLE_SCLK_PERIC, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_IOCLK_SPI3, "sclk_ioclk_spi3", "ioclk_spi3_clk_in", + ENABLE_SCLK_PERIC, 20, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI4, "sclk_spi4", "sclk_spi4_peric", ENABLE_SCLK_PERIC, 19, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI3, "sclk_spi3", "sclk_spi3_peric", ENABLE_SCLK_PERIC, 18, CLK_SET_RATE_PARENT, 0), - + GATE(CLK_SCLK_SCI, "sclk_sci", "div_sclk_sci", ENABLE_SCLK_PERIC, + 17, 0, 0), + GATE(CLK_SCLK_SC_IN, "sclk_sc_in", "div_sclk_sc_in", ENABLE_SCLK_PERIC, + 16, 0, 0), + GATE(CLK_SCLK_PWM, "sclk_pwm", "oscclk", ENABLE_SCLK_PERIC, 15, 0, 0), + GATE(CLK_SCLK_IOCLK_SPI2, "sclk_ioclk_spi2", "ioclk_spi2_clk_in", + ENABLE_SCLK_PERIC, 13, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_IOCLK_SPI1, "sclk_ioclk_spi1", "ioclk_spi1_clk_in", + ENABLE_SCLK_PERIC, 12, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_IOCLK_SPI0, "sclk_ioclk_spi0", "ioclk_spi0_clk_in", + ENABLE_SCLK_PERIC, 11, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_IOCLK_I2S1_BCLK, "sclk_ioclk_i2s1_bclk", + "ioclk_i2s1_bclk_in", ENABLE_SCLK_PERIC, 10, + CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_SPDIF, "sclk_spdif", "sclk_spdif_peric", + ENABLE_SCLK_PERIC, 8, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_PCM1, "sclk_pcm1", "sclk_pcm1_peric", + ENABLE_SCLK_PERIC, 7, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_I2S1, "sclk_i2s1", "sclk_i2s1_peric", + ENABLE_SCLK_PERIC, 6, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI2, "sclk_spi2", "sclk_spi2_peric", ENABLE_SCLK_PERIC, 5, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI1, "sclk_spi1", "sclk_spi1_peric", ENABLE_SCLK_PERIC, - 4, CLK_SET_RATE_PARENT, 0), + 4, CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_SPI0, "sclk_spi0", "sclk_spi0_peric", ENABLE_SCLK_PERIC, 3, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_UART2, "sclk_uart2", "sclk_uart2_peric", @@ -857,6 +934,8 @@ static struct samsung_gate_clock peric_gate_clks[] __initdata = { }; static struct samsung_cmu_info peric_cmu_info __initdata = { + .div_clks = peric_div_clks, + .nr_div_clks = ARRAY_SIZE(peric_div_clks), .gate_clks = peric_gate_clks, .nr_gate_clks = ARRAY_SIZE(peric_gate_clks), .nr_clk_ids = PERIC_NR_CLK, diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 8f0ee5a13db4..b5c66f7b83be 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -181,8 +181,40 @@ #define CLK_SCLK_UART2 34 #define CLK_SCLK_UART1 35 #define CLK_SCLK_UART0 36 +#define CLK_ACLK_AHB2APB_PERIC2P 37 +#define CLK_ACLK_AHB2APB_PERIC1P 38 +#define CLK_ACLK_AHB2APB_PERIC0P 39 +#define CLK_ACLK_PERICNP_66 40 +#define CLK_PCLK_SCI 41 +#define CLK_PCLK_GPIO_FINGER 42 +#define CLK_PCLK_GPIO_ESE 43 +#define CLK_PCLK_PWM 44 +#define CLK_PCLK_SPDIF 45 +#define CLK_PCLK_PCM1 46 +#define CLK_PCLK_I2S1 47 +#define CLK_PCLK_ADCIF 48 +#define CLK_PCLK_GPIO_TOUCH 49 +#define CLK_PCLK_GPIO_NFC 50 +#define CLK_PCLK_GPIO_PERIC 51 +#define CLK_PCLK_PMU_PERIC 52 +#define CLK_PCLK_SYSREG_PERIC 53 +#define CLK_SCLK_IOCLK_SPI4 54 +#define CLK_SCLK_IOCLK_SPI3 55 +#define CLK_SCLK_SCI 56 +#define CLK_SCLK_SC_IN 57 +#define CLK_SCLK_PWM 58 +#define CLK_SCLK_IOCLK_SPI2 59 +#define CLK_SCLK_IOCLK_SPI1 60 +#define CLK_SCLK_IOCLK_SPI0 61 +#define CLK_SCLK_IOCLK_I2S1_BCLK 62 +#define CLK_SCLK_SPDIF 63 +#define CLK_SCLK_PCM1 64 +#define CLK_SCLK_I2S1 65 -#define PERIC_NR_CLK 37 +#define CLK_DIV_SCLK_SCI 70 +#define CLK_DIV_SCLK_SC_IN 71 + +#define PERIC_NR_CLK 72 /* CMU_PERIS */ #define CLK_PCLK_HPM_APBIF 1 -- cgit v1.2.3 From 56bcf3f3ea39402acff09cba9558a0d3b13fc56f Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:23:59 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_PERIS domain This patch adds missing gate clocks of CMU_PERIS domain which includes TMU/TZPC/SECKEY/CHIPID/TOPRTC/EFUSE IPs. The special clocks of CMU_PERIS use oscclk source clock directly. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 151 ++++++++++++++++++++++++++++++++- include/dt-bindings/clock/exynos5433.h | 33 ++++++- 2 files changed, 181 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 10a9f8313c24..5ba9311624aa 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -245,6 +245,10 @@ PNAME(mout_sclk_audio1_p) = { "ioclk_audiocdclk1", "oscclk", PNAME(mout_sclk_audio0_p) = { "ioclk_audiocdclk0", "oscclk", "mout_aud_pll_user_t",}; +static struct samsung_fixed_factor_clock top_fixed_factor_clks[] __initdata = { + FFACTOR(0, "oscclk_efuse_common", "oscclk", 1, 1, 0), +}; + static struct samsung_fixed_rate_clock top_fixed_clks[] __initdata = { /* Xi2s{0|1}CDCLK input clock for I2S/PCM */ FRATE(0, "ioclk_audiocdclk1", NULL, CLK_IS_ROOT, 100000000), @@ -614,6 +618,8 @@ static struct samsung_cmu_info top_cmu_info __initdata = { .nr_gate_clks = ARRAY_SIZE(top_gate_clks), .fixed_clks = top_fixed_clks, .nr_fixed_clks = ARRAY_SIZE(top_fixed_clks), + .fixed_factor_clks = top_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(top_fixed_factor_clks), .nr_clk_ids = TOP_NR_CLK, .clk_regs = top_clk_regs, .nr_clk_regs = ARRAY_SIZE(top_clk_regs), @@ -954,15 +960,69 @@ CLK_OF_DECLARE(exynos5433_cmu_peric, "samsung,exynos5433-cmu-peric", /* * Register offset definitions for CMU_PERIS */ -#define ENABLE_ACLK_PERIS 0x0800 -#define ENABLE_PCLK_PERIS 0x0900 +#define ENABLE_ACLK_PERIS 0x0800 +#define ENABLE_PCLK_PERIS 0x0900 +#define ENABLE_PCLK_PERIS_SECURE_TZPC 0x0904 +#define ENABLE_PCLK_PERIS_SECURE_SECKEY_APBIF 0x0908 +#define ENABLE_PCLK_PERIS_SECURE_CHIPID_APBIF 0x090c +#define ENABLE_PCLK_PERIS_SECURE_TOPRTC 0x0910 +#define ENABLE_PCLK_PERIS_SECURE_CUSTOM_EFUSE_APBIF 0x0914 +#define ENABLE_PCLK_PERIS_SECURE_ANTIRBK_CNT_APBIF 0x0918 +#define ENABLE_PCLK_PERIS_SECURE_OTP_CON_APBIF 0x091c +#define ENABLE_SCLK_PERIS 0x0a00 +#define ENABLE_SCLK_PERIS_SECURE_SECKEY 0x0a04 +#define ENABLE_SCLK_PERIS_SECURE_CHIPID 0x0a08 +#define ENABLE_SCLK_PERIS_SECURE_TOPRTC 0x0a0c +#define ENABLE_SCLK_PERIS_SECURE_CUSTOM_EFUSE 0x0a10 +#define ENABLE_SCLK_PERIS_SECURE_ANTIRBK_CNT 0x0a14 +#define ENABLE_SCLK_PERIS_SECURE_OTP_CON 0x0a18 +#define ENABLE_IP_PERIS0 0x0b00 +#define ENABLE_IP_PERIS1 0x0b04 +#define ENABLE_IP_PERIS_SECURE_TZPC 0x0b08 +#define ENABLE_IP_PERIS_SECURE_SECKEY 0x0b0c +#define ENABLE_IP_PERIS_SECURE_CHIPID 0x0b10 +#define ENABLE_IP_PERIS_SECURE_TOPRTC 0x0b14 +#define ENABLE_IP_PERIS_SECURE_CUSTOM_EFUSE 0x0b18 +#define ENABLE_IP_PERIS_SECURE_ANTIBRK_CNT 0x0b1c +#define ENABLE_IP_PERIS_SECURE_OTP_CON 0x0b20 static unsigned long peris_clk_regs[] __initdata = { ENABLE_ACLK_PERIS, ENABLE_PCLK_PERIS, + ENABLE_PCLK_PERIS_SECURE_TZPC, + ENABLE_PCLK_PERIS_SECURE_SECKEY_APBIF, + ENABLE_PCLK_PERIS_SECURE_CHIPID_APBIF, + ENABLE_PCLK_PERIS_SECURE_TOPRTC, + ENABLE_PCLK_PERIS_SECURE_CUSTOM_EFUSE_APBIF, + ENABLE_PCLK_PERIS_SECURE_ANTIRBK_CNT_APBIF, + ENABLE_PCLK_PERIS_SECURE_OTP_CON_APBIF, + ENABLE_SCLK_PERIS, + ENABLE_SCLK_PERIS_SECURE_SECKEY, + ENABLE_SCLK_PERIS_SECURE_CHIPID, + ENABLE_SCLK_PERIS_SECURE_TOPRTC, + ENABLE_SCLK_PERIS_SECURE_CUSTOM_EFUSE, + ENABLE_SCLK_PERIS_SECURE_ANTIRBK_CNT, + ENABLE_SCLK_PERIS_SECURE_OTP_CON, + ENABLE_IP_PERIS0, + ENABLE_IP_PERIS1, + ENABLE_IP_PERIS_SECURE_TZPC, + ENABLE_IP_PERIS_SECURE_SECKEY, + ENABLE_IP_PERIS_SECURE_CHIPID, + ENABLE_IP_PERIS_SECURE_TOPRTC, + ENABLE_IP_PERIS_SECURE_CUSTOM_EFUSE, + ENABLE_IP_PERIS_SECURE_ANTIBRK_CNT, + ENABLE_IP_PERIS_SECURE_OTP_CON, }; static struct samsung_gate_clock peris_gate_clks[] __initdata = { + /* ENABLE_ACLK_PERIS */ + GATE(CLK_ACLK_AHB2APB_PERIS1P, "aclk_ahb2apb_peris1p", "aclk_peris_66", + ENABLE_ACLK_PERIS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_PERIS0P, "aclk_ahb2apb_peris0p", "aclk_peris_66", + ENABLE_ACLK_PERIS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PERISNP_66, "aclk_perisnp_66", "aclk_peris_66", + ENABLE_ACLK_PERIS, 0, CLK_IGNORE_UNUSED, 0), + /* ENABLE_PCLK_PERIS */ GATE(CLK_PCLK_HPM_APBIF, "pclk_hpm_apbif", "aclk_peris_66", ENABLE_PCLK_PERIS, 30, CLK_IGNORE_UNUSED, 0), @@ -984,6 +1044,93 @@ static struct samsung_gate_clock peris_gate_clks[] __initdata = { ENABLE_PCLK_PERIS, 15, CLK_IGNORE_UNUSED, 0), GATE(CLK_PCLK_HDMI_CEC, "pclk_hdmi_cec", "aclk_peris_66", ENABLE_PCLK_PERIS, 14, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_PERIS_SECURE_TZPC */ + GATE(CLK_PCLK_TZPC12, "pclk_tzpc12", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 12, 0, 0), + GATE(CLK_PCLK_TZPC11, "pclk_tzpc11", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 11, 0, 0), + GATE(CLK_PCLK_TZPC10, "pclk_tzpc10", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 10, 0, 0), + GATE(CLK_PCLK_TZPC9, "pclk_tzpc9", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 9, 0, 0), + GATE(CLK_PCLK_TZPC8, "pclk_tzpc8", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 8, 0, 0), + GATE(CLK_PCLK_TZPC7, "pclk_tzpc7", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 7, 0, 0), + GATE(CLK_PCLK_TZPC6, "pclk_tzpc6", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 6, 0, 0), + GATE(CLK_PCLK_TZPC5, "pclk_tzpc5", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 5, 0, 0), + GATE(CLK_PCLK_TZPC4, "pclk_tzpc4", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 4, 0, 0), + GATE(CLK_PCLK_TZPC3, "pclk_tzpc3", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 3, 0, 0), + GATE(CLK_PCLK_TZPC2, "pclk_tzpc2", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 2, 0, 0), + GATE(CLK_PCLK_TZPC1, "pclk_tzpc1", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 1, 0, 0), + GATE(CLK_PCLK_TZPC0, "pclk_tzpc0", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TZPC, 0, 0, 0), + + /* ENABLE_PCLK_PERIS_SECURE_SECKEY_APBIF */ + GATE(CLK_PCLK_SECKEY_APBIF, "pclk_seckey_apbif", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_SECKEY_APBIF, 0, 0, 0), + + /* ENABLE_PCLK_PERIS_SECURE_CHIPID_APBIF */ + GATE(CLK_PCLK_CHIPID_APBIF, "pclk_chipid_apbif", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_CHIPID_APBIF, 0, 0, 0), + + /* ENABLE_PCLK_PERIS_SECURE_TOPRTC */ + GATE(CLK_PCLK_TOPRTC, "pclk_toprtc", "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_TOPRTC, 0, 0, 0), + + /* ENABLE_PCLK_PERIS_SECURE_CUSTOM_EFUSE_APBIF */ + GATE(CLK_PCLK_CUSTOM_EFUSE_APBIF, "pclk_custom_efuse_apbif", + "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_CUSTOM_EFUSE_APBIF, 0, 0, 0), + + /* ENABLE_PCLK_PERIS_SECURE_ANTIRBK_CNT_APBIF */ + GATE(CLK_PCLK_ANTIRBK_CNT_APBIF, "pclk_antirbk_cnt_apbif", + "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_ANTIRBK_CNT_APBIF, 0, 0, 0), + + /* ENABLE_PCLK_PERIS_SECURE_OTP_CON_APBIF */ + GATE(CLK_PCLK_OTP_CON_APBIF, "pclk_otp_con_apbif", + "aclk_peris_66", + ENABLE_PCLK_PERIS_SECURE_OTP_CON_APBIF, 0, 0, 0), + + /* ENABLE_SCLK_PERIS */ + GATE(CLK_SCLK_ASV_TB, "sclk_asv_tb", "oscclk_efuse_common", + ENABLE_SCLK_PERIS, 10, 0, 0), + GATE(CLK_SCLK_TMU1, "sclk_tmu1", "oscclk_efuse_common", + ENABLE_SCLK_PERIS, 4, 0, 0), + GATE(CLK_SCLK_TMU0, "sclk_tmu0", "oscclk_efuse_common", + ENABLE_SCLK_PERIS, 3, 0, 0), + + /* ENABLE_SCLK_PERIS_SECURE_SECKEY */ + GATE(CLK_SCLK_SECKEY, "sclk_seckey", "oscclk_efuse_common", + ENABLE_SCLK_PERIS_SECURE_SECKEY, 0, 0, 0), + + /* ENABLE_SCLK_PERIS_SECURE_CHIPID */ + GATE(CLK_SCLK_CHIPID, "sclk_chipid", "oscclk_efuse_common", + ENABLE_SCLK_PERIS_SECURE_CHIPID, 0, 0, 0), + + /* ENABLE_SCLK_PERIS_SECURE_TOPRTC */ + GATE(CLK_SCLK_TOPRTC, "sclk_toprtc", "oscclk_efuse_common", + ENABLE_SCLK_PERIS_SECURE_TOPRTC, 0, 0, 0), + + /* ENABLE_SCLK_PERIS_SECURE_CUSTOM_EFUSE */ + GATE(CLK_SCLK_CUSTOM_EFUSE, "sclk_custom_efuse", "oscclk_efuse_common", + ENABLE_SCLK_PERIS_SECURE_CUSTOM_EFUSE, 0, 0, 0), + + /* ENABLE_SCLK_PERIS_SECURE_ANTIRBK_CNT */ + GATE(CLK_SCLK_ANTIRBK_CNT, "sclk_antirbk_cnt", "oscclk_efuse_common", + ENABLE_SCLK_PERIS_SECURE_ANTIRBK_CNT, 0, 0, 0), + + /* ENABLE_SCLK_PERIS_SECURE_OTP_CON */ + GATE(CLK_SCLK_OTP_CON, "sclk_otp_con", "oscclk_efuse_common", + ENABLE_SCLK_PERIS_SECURE_OTP_CON, 0, 0, 0), }; static struct samsung_cmu_info peris_cmu_info __initdata = { diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index b5c66f7b83be..5b3397d9843a 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -227,8 +227,39 @@ #define CLK_PCLK_WDT_ATLAS 8 #define CLK_PCLK_MCT 9 #define CLK_PCLK_HDMI_CEC 10 +#define CLK_ACLK_AHB2APB_PERIS1P 11 +#define CLK_ACLK_AHB2APB_PERIS0P 12 +#define CLK_ACLK_PERISNP_66 13 +#define CLK_PCLK_TZPC12 14 +#define CLK_PCLK_TZPC11 15 +#define CLK_PCLK_TZPC10 16 +#define CLK_PCLK_TZPC9 17 +#define CLK_PCLK_TZPC8 18 +#define CLK_PCLK_TZPC7 19 +#define CLK_PCLK_TZPC6 20 +#define CLK_PCLK_TZPC5 21 +#define CLK_PCLK_TZPC4 22 +#define CLK_PCLK_TZPC3 23 +#define CLK_PCLK_TZPC2 24 +#define CLK_PCLK_TZPC1 25 +#define CLK_PCLK_TZPC0 26 +#define CLK_PCLK_SECKEY_APBIF 27 +#define CLK_PCLK_CHIPID_APBIF 28 +#define CLK_PCLK_TOPRTC 29 +#define CLK_PCLK_CUSTOM_EFUSE_APBIF 30 +#define CLK_PCLK_ANTIRBK_CNT_APBIF 31 +#define CLK_PCLK_OTP_CON_APBIF 32 +#define CLK_SCLK_ASV_TB 33 +#define CLK_SCLK_TMU1 34 +#define CLK_SCLK_TMU0 35 +#define CLK_SCLK_SECKEY 36 +#define CLK_SCLK_CHIPID 37 +#define CLK_SCLK_TOPRTC 38 +#define CLK_SCLK_CUSTOM_EFUSE 39 +#define CLK_SCLK_ANTIRBK_CNT 40 +#define CLK_SCLK_OTP_CON 41 -#define PERIS_NR_CLK 11 +#define PERIS_NR_CLK 42 /* CMU_FSYS */ #define CLK_MOUT_ACLK_FSYS_200_USER 1 -- cgit v1.2.3 From a29308dad5dc4695a344ed9042cae8a1b8e35267 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:00 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_G2D domain This patch adds ths mux/divider/gate clocks of CMU_G2D domain which includes G2D/MDMA IPs. The CMU_G2D requires its parent defined in the CMU_TOP domain. Hence this patch adds G2D related clocks to the CMU_TOP domain. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 146 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 42 +++++++++- 2 files changed, 187 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 5ba9311624aa..24218dba8218 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -398,6 +398,20 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { }; static struct samsung_div_clock top_div_clks[] __initdata = { + /* DIV_TOP1 */ + DIV(CLK_DIV_ACLK_GSCL_111, "div_aclk_gscl_111", "mout_aclk_gscl_333", + DIV_TOP1, 28, 3), + DIV(CLK_DIV_ACLK_GSCL_333, "div_aclk_gscl_333", "mout_aclk_gscl_333", + DIV_TOP1, 24, 3), + DIV(CLK_DIV_ACLK_HEVC_400, "div_aclk_hevc_400", "mout_aclk_hevc_400", + DIV_TOP1, 20, 3), + DIV(CLK_DIV_ACLK_MFC_400, "div_aclk_mfc_400", "mout_aclk_mfc_400_c", + DIV_TOP1, 12, 3), + DIV(CLK_DIV_ACLK_G2D_266, "div_aclk_g2d_266", "mout_bus_pll_user", + DIV_TOP1, 8, 3), + DIV(CLK_DIV_ACLK_G2D_400, "div_aclk_g2d_400", "mout_aclk_g2d_400_b", + DIV_TOP1, 0, 3), + /* DIV_TOP2 */ DIV(CLK_DIV_ACLK_FSYS_200, "div_aclk_fsys_200", "mout_bus_pll_user", DIV_TOP2, 0, 3), @@ -490,6 +504,12 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_FSYS_200, "aclk_fsys_200", "div_aclk_fsys_200", ENABLE_ACLK_TOP, 18, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G2D_266, "aclk_g2d_266", "div_aclk_g2d_266", + ENABLE_ACLK_TOP, 2, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G2D_400, "aclk_g2d_400", "div_aclk_g2d_400", + ENABLE_ACLK_TOP, 0, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), /* ENABLE_SCLK_TOP_FSYS */ GATE(CLK_SCLK_MMC2_FSYS, "sclk_mmc2_fsys", "div_sclk_mmc2_b", @@ -1277,3 +1297,129 @@ static void __init exynos5433_cmu_fsys_init(struct device_node *np) CLK_OF_DECLARE(exynos5433_cmu_fsys, "samsung,exynos5433-cmu-fsys", exynos5433_cmu_fsys_init); + +/* + * Register offset definitions for CMU_G2D + */ +#define MUX_SEL_G2D0 0x0200 +#define MUX_SEL_ENABLE_G2D0 0x0300 +#define MUX_SEL_STAT_G2D0 0x0400 +#define DIV_G2D 0x0600 +#define DIV_STAT_G2D 0x0700 +#define DIV_ENABLE_ACLK_G2D 0x0800 +#define DIV_ENABLE_ACLK_G2D_SECURE_SMMU_G2D 0x0804 +#define DIV_ENABLE_PCLK_G2D 0x0900 +#define DIV_ENABLE_PCLK_G2D_SECURE_SMMU_G2D 0x0904 +#define DIV_ENABLE_IP_G2D0 0x0b00 +#define DIV_ENABLE_IP_G2D1 0x0b04 +#define DIV_ENABLE_IP_G2D_SECURE_SMMU_G2D 0x0b08 + +static unsigned long g2d_clk_regs[] __initdata = { + MUX_SEL_G2D0, + MUX_SEL_ENABLE_G2D0, + MUX_SEL_STAT_G2D0, + DIV_G2D, + DIV_STAT_G2D, + DIV_ENABLE_ACLK_G2D, + DIV_ENABLE_ACLK_G2D_SECURE_SMMU_G2D, + DIV_ENABLE_PCLK_G2D, + DIV_ENABLE_PCLK_G2D_SECURE_SMMU_G2D, + DIV_ENABLE_IP_G2D0, + DIV_ENABLE_IP_G2D1, + DIV_ENABLE_IP_G2D_SECURE_SMMU_G2D, +}; + +/* list of all parent clock list */ +PNAME(mout_aclk_g2d_266_user_p) = { "oscclk", "aclk_g2d_266", }; +PNAME(mout_aclk_g2d_400_user_p) = { "oscclk", "aclk_g2d_400", }; + +static struct samsung_mux_clock g2d_mux_clks[] __initdata = { + /* MUX_SEL_G2D0 */ + MUX(CLK_MUX_ACLK_G2D_266_USER, "mout_aclk_g2d_266_user", + mout_aclk_g2d_266_user_p, MUX_SEL_G2D0, 4, 1), + MUX(CLK_MUX_ACLK_G2D_400_USER, "mout_aclk_g2d_400_user", + mout_aclk_g2d_400_user_p, MUX_SEL_G2D0, 0, 1), +}; + +static struct samsung_div_clock g2d_div_clks[] __initdata = { + /* DIV_G2D */ + DIV(CLK_DIV_PCLK_G2D, "div_pclk_g2d", "mout_aclk_g2d_266_user", + DIV_G2D, 0, 2), +}; + +static struct samsung_gate_clock g2d_gate_clks[] __initdata = { + /* DIV_ENABLE_ACLK_G2D */ + GATE(CLK_ACLK_SMMU_MDMA1, "aclk_smmu_mdma1", "mout_aclk_g2d_266_user", + DIV_ENABLE_ACLK_G2D, 12, 0, 0), + GATE(CLK_ACLK_BTS_MDMA1, "aclk_bts_mdam1", "mout_aclk_g2d_266_user", + DIV_ENABLE_ACLK_G2D, 11, 0, 0), + GATE(CLK_ACLK_BTS_G2D, "aclk_bts_g2d", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D, 10, 0, 0), + GATE(CLK_ACLK_ALB_G2D, "aclk_alb_g2d", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D, 9, 0, 0), + GATE(CLK_ACLK_AXIUS_G2DX, "aclk_axius_g2dx", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D, 8, 0, 0), + GATE(CLK_ACLK_ASYNCAXI_SYSX, "aclk_asyncaxi_sysx", + "mout_aclk_g2d_400_user", DIV_ENABLE_ACLK_G2D, + 7, 0, 0), + GATE(CLK_ACLK_AHB2APB_G2D1P, "aclk_ahb2apb_g2d1p", "div_pclk_g2d", + DIV_ENABLE_ACLK_G2D, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_G2D0P, "aclk_ahb2apb_g2d0p", "div_pclk_g2d", + DIV_ENABLE_ACLK_G2D, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_G2DX, "aclk_xiu_g2dx", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G2DNP_133, "aclk_g2dnp_133", "div_pclk_g2d", + DIV_ENABLE_ACLK_G2D, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G2DND_400, "aclk_g2dnd_400", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MDMA1, "aclk_mdma1", "mout_aclk_g2d_266_user", + DIV_ENABLE_ACLK_G2D, 1, 0, 0), + GATE(CLK_ACLK_G2D, "aclk_g2d", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D, 0, 0, 0), + + /* DIV_ENABLE_ACLK_G2D_SECURE_SMMU_G2D */ + GATE(CLK_ACLK_SMMU_G2D, "aclk_smmu_g2d", "mout_aclk_g2d_400_user", + DIV_ENABLE_ACLK_G2D_SECURE_SMMU_G2D, 0, 0, 0), + + /* DIV_ENABLE_PCLK_G2D */ + GATE(CLK_PCLK_SMMU_MDMA1, "pclk_smmu_mdma1", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 7, 0, 0), + GATE(CLK_PCLK_BTS_MDMA1, "pclk_bts_mdam1", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 6, 0, 0), + GATE(CLK_PCLK_BTS_G2D, "pclk_bts_g2d", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 5, 0, 0), + GATE(CLK_PCLK_ALB_G2D, "pclk_alb_g2d", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 4, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_SYSX, "pclk_asyncaxi_sysx", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 3, 0, 0), + GATE(CLK_PCLK_PMU_G2D, "pclk_pmu_g2d", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_G2D, "pclk_sysreg_g2d", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_G2D, "pclk_g2d", "div_pclk_g2d", DIV_ENABLE_PCLK_G2D, + 0, 0, 0), + + /* DIV_ENABLE_PCLK_G2D_SECURE_SMMU_G2D */ + GATE(CLK_PCLK_SMMU_G2D, "pclk_smmu_g2d", "div_pclk_g2d", + DIV_ENABLE_PCLK_G2D_SECURE_SMMU_G2D, 0, 0, 0), +}; + +static struct samsung_cmu_info g2d_cmu_info __initdata = { + .mux_clks = g2d_mux_clks, + .nr_mux_clks = ARRAY_SIZE(g2d_mux_clks), + .div_clks = g2d_div_clks, + .nr_div_clks = ARRAY_SIZE(g2d_div_clks), + .gate_clks = g2d_gate_clks, + .nr_gate_clks = ARRAY_SIZE(g2d_gate_clks), + .nr_clk_ids = G2D_NR_CLK, + .clk_regs = g2d_clk_regs, + .nr_clk_regs = ARRAY_SIZE(g2d_clk_regs), +}; + +static void __init exynos5433_cmu_g2d_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &g2d_cmu_info); +} + +CLK_OF_DECLARE(exynos5433_cmu_g2d, "samsung,exynos5433-cmu-g2d", + exynos5433_cmu_g2d_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 5b3397d9843a..818d6b6bbdc4 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -100,6 +100,12 @@ #define CLK_DIV_SCLK_PCM1 128 #define CLK_DIV_SCLK_AUDIO1 129 #define CLK_DIV_SCLK_AUDIO0 130 +#define CLK_DIV_ACLK_GSCL_111 131 +#define CLK_DIV_ACLK_GSCL_333 132 +#define CLK_DIV_ACLK_HEVC_400 133 +#define CLK_DIV_ACLK_MFC_400 134 +#define CLK_DIV_ACLK_G2D_266 135 +#define CLK_DIV_ACLK_G2D_400 136 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -121,8 +127,10 @@ #define CLK_SCLK_SLIMBUS 217 #define CLK_SCLK_AUDIO1 218 #define CLK_SCLK_AUDIO0 219 +#define CLK_ACLK_G2D_266 220 +#define CLK_ACLK_G2D_400 221 -#define TOP_NR_CLK 220 +#define TOP_NR_CLK 222 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -286,4 +294,36 @@ #define FSYS_NR_CLK 66 +/* CMU_G2D */ +#define CLK_MUX_ACLK_G2D_266_USER 1 +#define CLK_MUX_ACLK_G2D_400_USER 2 + +#define CLK_DIV_PCLK_G2D 3 + +#define CLK_ACLK_SMMU_MDMA1 4 +#define CLK_ACLK_BTS_MDMA1 5 +#define CLK_ACLK_BTS_G2D 6 +#define CLK_ACLK_ALB_G2D 7 +#define CLK_ACLK_AXIUS_G2DX 8 +#define CLK_ACLK_ASYNCAXI_SYSX 9 +#define CLK_ACLK_AHB2APB_G2D1P 10 +#define CLK_ACLK_AHB2APB_G2D0P 11 +#define CLK_ACLK_XIU_G2DX 12 +#define CLK_ACLK_G2DNP_133 13 +#define CLK_ACLK_G2DND_400 14 +#define CLK_ACLK_MDMA1 15 +#define CLK_ACLK_G2D 16 +#define CLK_ACLK_SMMU_G2D 17 +#define CLK_PCLK_SMMU_MDMA1 18 +#define CLK_PCLK_BTS_MDMA1 19 +#define CLK_PCLK_BTS_G2D 20 +#define CLK_PCLK_ALB_G2D 21 +#define CLK_PCLK_ASYNCAXI_SYSX 22 +#define CLK_PCLK_PMU_G2D 23 +#define CLK_PCLK_SYSREG_G2D 24 +#define CLK_PCLK_G2D 25 +#define CLK_PCLK_SMMU_G2D 26 + +#define G2D_NR_CLK 27 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 06d2f9dfa663367e8cc1690d7e5ce4113e5dbcc1 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:01 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_MIF domain This patch adds the mux/divider/gate clocks of CMU_MIF domain which includes the clocks for DMC(DRAM memory controller) and CCI(Cache Coherent Interconnect). The CMU_MIF domain provides the source clocks for CMU_DISP/CMU_BUS2. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 599 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 190 ++++++++++- 2 files changed, 788 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 24218dba8218..09ccf11bab64 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -740,6 +740,66 @@ CLK_OF_DECLARE(exynos5433_cmu_cpif, "samsung,exynos5433-cmu-cpif", #define MFC_PLL_CON0 0x0130 #define MFC_PLL_CON1 0x0134 #define MFC_PLL_FREQ_DET 0x013c +#define MUX_SEL_MIF0 0x0200 +#define MUX_SEL_MIF1 0x0204 +#define MUX_SEL_MIF2 0x0208 +#define MUX_SEL_MIF3 0x020c +#define MUX_SEL_MIF4 0x0210 +#define MUX_SEL_MIF5 0x0214 +#define MUX_SEL_MIF6 0x0218 +#define MUX_SEL_MIF7 0x021c +#define MUX_ENABLE_MIF0 0x0300 +#define MUX_ENABLE_MIF1 0x0304 +#define MUX_ENABLE_MIF2 0x0308 +#define MUX_ENABLE_MIF3 0x030c +#define MUX_ENABLE_MIF4 0x0310 +#define MUX_ENABLE_MIF5 0x0314 +#define MUX_ENABLE_MIF6 0x0318 +#define MUX_ENABLE_MIF7 0x031c +#define MUX_STAT_MIF0 0x0400 +#define MUX_STAT_MIF1 0x0404 +#define MUX_STAT_MIF2 0x0408 +#define MUX_STAT_MIF3 0x040c +#define MUX_STAT_MIF4 0x0410 +#define MUX_STAT_MIF5 0x0414 +#define MUX_STAT_MIF6 0x0418 +#define MUX_STAT_MIF7 0x041c +#define DIV_MIF1 0x0604 +#define DIV_MIF2 0x0608 +#define DIV_MIF3 0x060c +#define DIV_MIF4 0x0610 +#define DIV_MIF5 0x0614 +#define DIV_MIF_PLL_FREQ_DET 0x0618 +#define DIV_STAT_MIF1 0x0704 +#define DIV_STAT_MIF2 0x0708 +#define DIV_STAT_MIF3 0x070c +#define DIV_STAT_MIF4 0x0710 +#define DIV_STAT_MIF5 0x0714 +#define DIV_STAT_MIF_PLL_FREQ_DET 0x0718 +#define ENABLE_ACLK_MIF0 0x0800 +#define ENABLE_ACLK_MIF1 0x0804 +#define ENABLE_ACLK_MIF2 0x0808 +#define ENABLE_ACLK_MIF3 0x080c +#define ENABLE_PCLK_MIF 0x0900 +#define ENABLE_PCLK_MIF_SECURE_DREX0_TZ 0x0904 +#define ENABLE_PCLK_MIF_SECURE_DREX1_TZ 0x0908 +#define ENABLE_PCLK_MIF_SECURE_MONOTONIC_CNT 0x090c +#define ENABLE_PCLK_MIF_SECURE_RTC 0x0910 +#define ENABLE_SCLK_MIF 0x0a00 +#define ENABLE_IP_MIF0 0x0b00 +#define ENABLE_IP_MIF1 0x0b04 +#define ENABLE_IP_MIF2 0x0b08 +#define ENABLE_IP_MIF3 0x0b0c +#define ENABLE_IP_MIF_SECURE_DREX0_TZ 0x0b10 +#define ENABLE_IP_MIF_SECURE_DREX1_TZ 0x0b14 +#define ENABLE_IP_MIF_SECURE_MONOTONIC_CNT 0x0b18 +#define ENABLE_IP_MIF_SECURE_RTC 0x0b1c +#define CLKOUT_CMU_MIF 0x0c00 +#define CLKOUT_CMU_MIF_DIV_STAT 0x0c04 +#define DREX_FREQ_CTRL0 0x1000 +#define DREX_FREQ_CTRL1 0x1004 +#define PAUSE 0x1008 +#define DDRPHY_LOCK_CTRL 0x100c static unsigned long mif_clk_regs[] __initdata = { MEM0_PLL_LOCK, @@ -758,6 +818,66 @@ static unsigned long mif_clk_regs[] __initdata = { MFC_PLL_CON0, MFC_PLL_CON1, MFC_PLL_FREQ_DET, + MUX_SEL_MIF0, + MUX_SEL_MIF1, + MUX_SEL_MIF2, + MUX_SEL_MIF3, + MUX_SEL_MIF4, + MUX_SEL_MIF5, + MUX_SEL_MIF6, + MUX_SEL_MIF7, + MUX_ENABLE_MIF0, + MUX_ENABLE_MIF1, + MUX_ENABLE_MIF2, + MUX_ENABLE_MIF3, + MUX_ENABLE_MIF4, + MUX_ENABLE_MIF5, + MUX_ENABLE_MIF6, + MUX_ENABLE_MIF7, + MUX_STAT_MIF0, + MUX_STAT_MIF1, + MUX_STAT_MIF2, + MUX_STAT_MIF3, + MUX_STAT_MIF4, + MUX_STAT_MIF5, + MUX_STAT_MIF6, + MUX_STAT_MIF7, + DIV_MIF1, + DIV_MIF2, + DIV_MIF3, + DIV_MIF4, + DIV_MIF5, + DIV_MIF_PLL_FREQ_DET, + DIV_STAT_MIF1, + DIV_STAT_MIF2, + DIV_STAT_MIF3, + DIV_STAT_MIF4, + DIV_STAT_MIF5, + DIV_STAT_MIF_PLL_FREQ_DET, + ENABLE_ACLK_MIF0, + ENABLE_ACLK_MIF1, + ENABLE_ACLK_MIF2, + ENABLE_ACLK_MIF3, + ENABLE_PCLK_MIF, + ENABLE_PCLK_MIF_SECURE_DREX0_TZ, + ENABLE_PCLK_MIF_SECURE_DREX1_TZ, + ENABLE_PCLK_MIF_SECURE_MONOTONIC_CNT, + ENABLE_PCLK_MIF_SECURE_RTC, + ENABLE_SCLK_MIF, + ENABLE_IP_MIF0, + ENABLE_IP_MIF1, + ENABLE_IP_MIF2, + ENABLE_IP_MIF3, + ENABLE_IP_MIF_SECURE_DREX0_TZ, + ENABLE_IP_MIF_SECURE_DREX1_TZ, + ENABLE_IP_MIF_SECURE_MONOTONIC_CNT, + ENABLE_IP_MIF_SECURE_RTC, + CLKOUT_CMU_MIF, + CLKOUT_CMU_MIF_DIV_STAT, + DREX_FREQ_CTRL0, + DREX_FREQ_CTRL1, + PAUSE, + DDRPHY_LOCK_CTRL, }; static struct samsung_pll_clock mif_pll_clks[] __initdata = { @@ -771,9 +891,488 @@ static struct samsung_pll_clock mif_pll_clks[] __initdata = { MFC_PLL_LOCK, MFC_PLL_CON0, exynos5443_pll_rates), }; +/* list of all parent clock list */ +PNAME(mout_mfc_pll_div2_p) = { "mout_mfc_pll", "dout_mfc_pll", }; +PNAME(mout_bus_pll_div2_p) = { "mout_bus_pll", "dout_bus_pll", }; +PNAME(mout_mem1_pll_div2_p) = { "mout_mem1_pll", "dout_mem1_pll", }; +PNAME(mout_mem0_pll_div2_p) = { "mout_mem0_pll", "dout_mem0_pll", }; +PNAME(mout_mfc_pll_p) = { "oscclk", "fout_mfc_pll", }; +PNAME(mout_bus_pll_p) = { "oscclk", "fout_bus_pll", }; +PNAME(mout_mem1_pll_p) = { "oscclk", "fout_mem1_pll", }; +PNAME(mout_mem0_pll_p) = { "oscclk", "fout_mem0_pll", }; + +PNAME(mout_clk2x_phy_c_p) = { "mout_mem0_pll_div2", "mout_clkm_phy_b", }; +PNAME(mout_clk2x_phy_b_p) = { "mout_bus_pll_div2", "mout_clkm_phy_a", }; +PNAME(mout_clk2x_phy_a_p) = { "mout_bus_pll_div2", "mout_mfc_pll_div2", }; +PNAME(mout_clkm_phy_b_p) = { "mout_mem1_pll_div2", "mout_clkm_phy_a", }; + +PNAME(mout_aclk_mifnm_200_p) = { "mout_mem0_pll_div2", "div_mif_pre", }; +PNAME(mout_aclk_mifnm_400_p) = { "mout_mem1_pll_div2", "mout_bus_pll_div2",}; + +PNAME(mout_aclk_disp_333_b_p) = { "mout_aclk_disp_333_a", + "mout_bus_pll_div2", }; +PNAME(mout_aclk_disp_333_a_p) = { "mout_mfc_pll_div2", "sclk_mphy_pll", }; + +PNAME(mout_sclk_decon_vclk_c_p) = { "mout_sclk_decon_vclk_b", + "sclk_mphy_pll", }; +PNAME(mout_sclk_decon_vclk_b_p) = { "mout_sclk_decon_vclk_a", + "mout_mfc_pll_div2", }; +PNAME(mout_sclk_decon_p) = { "oscclk", "mout_bus_pll_div2", }; +PNAME(mout_sclk_decon_eclk_c_p) = { "mout_sclk_decon_eclk_b", + "sclk_mphy_pll", }; +PNAME(mout_sclk_decon_eclk_b_p) = { "mout_sclk_decon_eclk_a", + "mout_mfc_pll_div2", }; + +PNAME(mout_sclk_decon_tv_eclk_c_p) = { "mout_sclk_decon_tv_eclk_b", + "sclk_mphy_pll", }; +PNAME(mout_sclk_decon_tv_eclk_b_p) = { "mout_sclk_decon_tv_eclk_a", + "mout_mfc_pll_div2", }; +PNAME(mout_sclk_dsd_c_p) = { "mout_sclk_dsd_b", "mout_bus_pll_div2", }; +PNAME(mout_sclk_dsd_b_p) = { "mout_sclk_dsd_a", "sclk_mphy_pll", }; +PNAME(mout_sclk_dsd_a_p) = { "oscclk", "mout_mfc_pll_div2", }; + +PNAME(mout_sclk_dsim0_c_p) = { "mout_sclk_dsim0_b", "sclk_mphy_pll", }; +PNAME(mout_sclk_dsim0_b_p) = { "mout_sclk_dsim0_a", "mout_mfc_pll_div2" }; + +PNAME(mout_sclk_decon_tv_vclk_c_p) = { "mout_sclk_decon_tv_vclk_b", + "sclk_mphy_pll", }; +PNAME(mout_sclk_decon_tv_vclk_b_p) = { "mout_sclk_decon_tv_vclk_a", + "mout_mfc_pll_div2", }; +PNAME(mout_sclk_dsim1_c_p) = { "mout_sclk_dsim1_b", "sclk_mphy_pll", }; +PNAME(mout_sclk_dsim1_b_p) = { "mout_sclk_dsim1_a", "mout_mfc_pll_div2",}; + +static struct samsung_fixed_factor_clock mif_fixed_factor_clks[] __initdata = { + /* dout_{mfc|bus|mem1|mem0}_pll is half fixed rate from parent mux */ + FFACTOR(CLK_DOUT_MFC_PLL, "dout_mfc_pll", "mout_mfc_pll", 1, 1, 0), + FFACTOR(CLK_DOUT_BUS_PLL, "dout_bus_pll", "mout_bus_pll", 1, 1, 0), + FFACTOR(CLK_DOUT_MEM1_PLL, "dout_mem1_pll", "mout_mem1_pll", 1, 1, 0), + FFACTOR(CLK_DOUT_MEM0_PLL, "dout_mem0_pll", "mout_mem0_pll", 1, 1, 0), +}; + +static struct samsung_mux_clock mif_mux_clks[] __initdata = { + /* MUX_SEL_MIF0 */ + MUX(CLK_MOUT_MFC_PLL_DIV2, "mout_mfc_pll_div2", mout_mfc_pll_div2_p, + MUX_SEL_MIF0, 28, 1), + MUX(CLK_MOUT_BUS_PLL_DIV2, "mout_bus_pll_div2", mout_bus_pll_div2_p, + MUX_SEL_MIF0, 24, 1), + MUX(CLK_MOUT_MEM1_PLL_DIV2, "mout_mem1_pll_div2", mout_mem1_pll_div2_p, + MUX_SEL_MIF0, 20, 1), + MUX(CLK_MOUT_MEM0_PLL_DIV2, "mout_mem0_pll_div2", mout_mem0_pll_div2_p, + MUX_SEL_MIF0, 16, 1), + MUX(CLK_MOUT_MFC_PLL, "mout_mfc_pll", mout_mfc_pll_p, MUX_SEL_MIF0, + 12, 1), + MUX(CLK_MOUT_BUS_PLL, "mout_bus_pll", mout_bus_pll_p, MUX_SEL_MIF0, + 8, 1), + MUX(CLK_MOUT_MEM1_PLL, "mout_mem1_pll", mout_mem1_pll_p, MUX_SEL_MIF0, + 4, 1), + MUX(CLK_MOUT_MEM0_PLL, "mout_mem0_pll", mout_mem0_pll_p, MUX_SEL_MIF0, + 0, 1), + + /* MUX_SEL_MIF1 */ + MUX(CLK_MOUT_CLK2X_PHY_C, "mout_clk2x_phy_c", mout_clk2x_phy_c_p, + MUX_SEL_MIF1, 24, 1), + MUX(CLK_MOUT_CLK2X_PHY_B, "mout_clk2x_phy_b", mout_clk2x_phy_b_p, + MUX_SEL_MIF1, 20, 1), + MUX(CLK_MOUT_CLK2X_PHY_A, "mout_clk2x_phy_a", mout_clk2x_phy_a_p, + MUX_SEL_MIF1, 16, 1), + MUX(CLK_MOUT_CLKM_PHY_C, "mout_clkm_phy_c", mout_clk2x_phy_c_p, + MUX_SEL_MIF1, 12, 1), + MUX(CLK_MOUT_CLKM_PHY_B, "mout_clkm_phy_b", mout_clkm_phy_b_p, + MUX_SEL_MIF1, 8, 1), + MUX(CLK_MOUT_CLKM_PHY_A, "mout_clkm_phy_a", mout_clk2x_phy_a_p, + MUX_SEL_MIF1, 4, 1), + + /* MUX_SEL_MIF2 */ + MUX(CLK_MOUT_ACLK_MIFNM_200, "mout_aclk_mifnm_200", + mout_aclk_mifnm_200_p, MUX_SEL_MIF2, 8, 1), + MUX(CLK_MOUT_ACLK_MIFNM_400, "mout_aclk_mifnm_400", + mout_aclk_mifnm_400_p, MUX_SEL_MIF2, 0, 1), + + /* MUX_SEL_MIF3 */ + MUX(CLK_MOUT_ACLK_DISP_333_B, "mout_aclk_disp_333_b", + mout_aclk_disp_333_b_p, MUX_SEL_MIF3, 4, 1), + MUX(CLK_MOUT_ACLK_DISP_333_A, "mout_aclk_disp_333_a", + mout_aclk_disp_333_a_p, MUX_SEL_MIF3, 0, 1), + + /* MUX_SEL_MIF4 */ + MUX(CLK_MOUT_SCLK_DECON_VCLK_C, "mout_sclk_decon_vclk_c", + mout_sclk_decon_vclk_c_p, MUX_SEL_MIF4, 24, 1), + MUX(CLK_MOUT_SCLK_DECON_VCLK_B, "mout_sclk_decon_vclk_b", + mout_sclk_decon_vclk_b_p, MUX_SEL_MIF4, 20, 1), + MUX(CLK_MOUT_SCLK_DECON_VCLK_A, "mout_sclk_decon_vclk_a", + mout_sclk_decon_p, MUX_SEL_MIF4, 16, 1), + MUX(CLK_MOUT_SCLK_DECON_ECLK_C, "mout_sclk_decon_eclk_c", + mout_sclk_decon_eclk_c_p, MUX_SEL_MIF4, 8, 1), + MUX(CLK_MOUT_SCLK_DECON_ECLK_B, "mout_sclk_decon_eclk_b", + mout_sclk_decon_eclk_b_p, MUX_SEL_MIF4, 4, 1), + MUX(CLK_MOUT_SCLK_DECON_ECLK_A, "mout_sclk_decon_eclk_a", + mout_sclk_decon_p, MUX_SEL_MIF4, 0, 1), + + /* MUX_SEL_MIF5 */ + MUX(CLK_MOUT_SCLK_DECON_TV_ECLK_C, "mout_sclk_decon_tv_eclk_c", + mout_sclk_decon_tv_eclk_c_p, MUX_SEL_MIF5, 24, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_ECLK_B, "mout_sclk_decon_tv_eclk_b", + mout_sclk_decon_tv_eclk_b_p, MUX_SEL_MIF5, 20, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_ECLK_A, "mout_sclk_decon_tv_eclk_a", + mout_sclk_decon_p, MUX_SEL_MIF5, 16, 1), + MUX(CLK_MOUT_SCLK_DSD_C, "mout_sclk_dsd_c", mout_sclk_dsd_c_p, + MUX_SEL_MIF5, 8, 1), + MUX(CLK_MOUT_SCLK_DSD_B, "mout_sclk_dsd_b", mout_sclk_dsd_b_p, + MUX_SEL_MIF5, 4, 1), + MUX(CLK_MOUT_SCLK_DSD_A, "mout_sclk_dsd_a", mout_sclk_dsd_a_p, + MUX_SEL_MIF5, 0, 1), + + /* MUX_SEL_MIF6 */ + MUX(CLK_MOUT_SCLK_DSIM0_C, "mout_sclk_dsim0_c", mout_sclk_dsim0_c_p, + MUX_SEL_MIF6, 8, 1), + MUX(CLK_MOUT_SCLK_DSIM0_B, "mout_sclk_dsim0_b", mout_sclk_dsim0_b_p, + MUX_SEL_MIF6, 4, 1), + MUX(CLK_MOUT_SCLK_DSIM0_A, "mout_sclk_dsim0_a", mout_sclk_decon_p, + MUX_SEL_MIF6, 0, 1), + + /* MUX_SEL_MIF7 */ + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_C, "mout_sclk_decon_tv_vclk_c", + mout_sclk_decon_tv_vclk_c_p, MUX_SEL_MIF7, 24, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_B, "mout_sclk_decon_tv_vclk_b", + mout_sclk_decon_tv_vclk_b_p, MUX_SEL_MIF7, 20, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_A, "mout_sclk_decon_tv_vclk_a", + mout_sclk_decon_p, MUX_SEL_MIF7, 16, 1), + MUX(CLK_MOUT_SCLK_DSIM1_C, "mout_sclk_dsim1_c", mout_sclk_dsim1_c_p, + MUX_SEL_MIF7, 8, 1), + MUX(CLK_MOUT_SCLK_DSIM1_B, "mout_sclk_dsim1_b", mout_sclk_dsim1_b_p, + MUX_SEL_MIF7, 4, 1), + MUX(CLK_MOUT_SCLK_DSIM1_A, "mout_sclk_dsim1_a", mout_sclk_decon_p, + MUX_SEL_MIF7, 0, 1), +}; + +static struct samsung_div_clock mif_div_clks[] __initdata = { + /* DIV_MIF1 */ + DIV(CLK_DIV_SCLK_HPM_MIF, "div_sclk_hpm_mif", "div_clk2x_phy", + DIV_MIF1, 16, 2), + DIV(CLK_DIV_ACLK_DREX1, "div_aclk_drex1", "div_clk2x_phy", DIV_MIF1, + 12, 2), + DIV(CLK_DIV_ACLK_DREX0, "div_aclk_drex0", "div_clk2x_phy", DIV_MIF1, + 8, 2), + DIV(CLK_DIV_CLK2XPHY, "div_clk2x_phy", "mout_clk2x_phy_c", DIV_MIF1, + 4, 4), + + /* DIV_MIF2 */ + DIV(CLK_DIV_ACLK_MIF_266, "div_aclk_mif_266", "mout_bus_pll_div2", + DIV_MIF2, 20, 3), + DIV(CLK_DIV_ACLK_MIFND_133, "div_aclk_mifnd_133", "div_mif_pre", + DIV_MIF2, 16, 4), + DIV(CLK_DIV_ACLK_MIF_133, "div_aclk_mif_133", "div_mif_pre", + DIV_MIF2, 12, 4), + DIV(CLK_DIV_ACLK_MIFNM_200, "div_aclk_mifnm_200", + "mout_aclk_mifnm_200", DIV_MIF2, 8, 3), + DIV(CLK_DIV_ACLK_MIF_200, "div_aclk_mif_200", "div_aclk_mif_400", + DIV_MIF2, 4, 2), + DIV(CLK_DIV_ACLK_MIF_400, "div_aclk_mif_400", "mout_aclk_mifnm_400", + DIV_MIF2, 0, 3), + + /* DIV_MIF3 */ + DIV(CLK_DIV_ACLK_BUS2_400, "div_aclk_bus2_400", "div_mif_pre", + DIV_MIF3, 16, 4), + DIV(CLK_DIV_ACLK_DISP_333, "div_aclk_disp_333", "mout_aclk_disp_333_b", + DIV_MIF3, 4, 3), + DIV(CLK_DIV_ACLK_CPIF_200, "div_aclk_cpif_200", "mout_aclk_mifnm_200", + DIV_MIF3, 0, 3), + + /* DIV_MIF4 */ + DIV(CLK_DIV_SCLK_DSIM1, "div_sclk_dsim1", "mout_sclk_dsim1_c", + DIV_MIF4, 24, 4), + DIV(CLK_DIV_SCLK_DECON_TV_VCLK, "div_sclk_decon_tv_vclk", + "mout_sclk_decon_tv_vclk_c", DIV_MIF4, 20, 4), + DIV(CLK_DIV_SCLK_DSIM0, "div_sclk_dsim0", "mout_sclk_dsim0_c", + DIV_MIF4, 16, 4), + DIV(CLK_DIV_SCLK_DSD, "div_sclk_dsd", "mout_sclk_dsd_c", + DIV_MIF4, 12, 4), + DIV(CLK_DIV_SCLK_DECON_TV_ECLK, "div_sclk_decon_tv_eclk", + "mout_sclk_decon_tv_eclk_c", DIV_MIF4, 8, 4), + DIV(CLK_DIV_SCLK_DECON_VCLK, "div_sclk_decon_vclk", + "mout_sclk_decon_vclk_c", DIV_MIF4, 4, 4), + DIV(CLK_DIV_SCLK_DECON_ECLK, "div_sclk_decon_eclk", + "mout_sclk_decon_eclk_c", DIV_MIF4, 0, 4), + + /* DIV_MIF5 */ + DIV(CLK_DIV_MIF_PRE, "div_mif_pre", "mout_bus_pll_div2", DIV_MIF5, + 0, 3), +}; + +static struct samsung_gate_clock mif_gate_clks[] __initdata = { + /* ENABLE_ACLK_MIF0 */ + GATE(CLK_CLK2X_PHY1, "clk2k_phy1", "div_clk2x_phy", ENABLE_ACLK_MIF0, + 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_CLK2X_PHY0, "clk2x_phy0", "div_clk2x_phy", ENABLE_ACLK_MIF0, + 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_CLKM_PHY1, "clkm_phy1", "mout_clkm_phy_c", ENABLE_ACLK_MIF0, + 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_CLKM_PHY0, "clkm_phy0", "mout_clkm_phy_c", ENABLE_ACLK_MIF0, + 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_RCLK_DREX1, "rclk_drex1", "oscclk", ENABLE_ACLK_MIF0, + 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_RCLK_DREX0, "rclk_drex0", "oscclk", ENABLE_ACLK_MIF0, + 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1_TZ, "aclk_drex1_tz", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0_TZ, "aclk_drex0_tz", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1_PEREV, "aclk_drex1_perev", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0_PEREV, "aclk_drex0_perev", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1_MEMIF, "aclk_drex1_memif", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0_MEMIF, "aclk_drex0_memif", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1_SCH, "aclk_drex1_sch", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0_SCH, "aclk_drex0_sch", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1_BUSIF, "aclk_drex1_busif", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0_BUSIF, "aclk_drex0_busif", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1_BUSIF_RD, "aclk_drex1_busif_rd", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0_BUSIF_RD, "aclk_drex0_busif_rd", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX1, "aclk_drex1", "div_aclk_drex1", + ENABLE_ACLK_MIF0, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DREX0, "aclk_drex0", "div_aclk_drex0", + ENABLE_ACLK_MIF0, 1, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_MIF1 */ + GATE(CLK_ACLK_ASYNCAXIS_MIF_IMEM, "aclk_asyncaxis_mif_imem", + "div_aclk_mif_200", ENABLE_ACLK_MIF1, 28, + CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_NOC_P_CCI, "aclk_asyncaxis_noc_p_cci", + "div_aclk_mif_200", ENABLE_ACLK_MIF1, + 27, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_NOC_P_CCI, "aclk_asyncaxim_noc_p_cci", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_CP1, "aclk_asyncaxis_cp1", + "div_aclk_mifnm_200", ENABLE_ACLK_MIF1, + 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_CP1, "aclk_asyncaxim_cp1", + "div_aclk_drex1", ENABLE_ACLK_MIF1, + 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_CP0, "aclk_asyncaxis_cp0", + "div_aclk_mifnm_200", ENABLE_ACLK_MIF1, + 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_CP0, "aclk_asyncaxim_cp0", + "div_aclk_drex0", ENABLE_ACLK_MIF1, + 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DREX1_3, "aclk_asyncaxis_drex1_3", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DREX1_3, "aclk_asyncaxim_drex1_3", + "div_aclk_drex1", ENABLE_ACLK_MIF1, + 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DREX1_1, "aclk_asyncaxis_drex1_1", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DREX1_1, "aclk_asyncaxim_drex1_1", + "div_aclk_drex1", ENABLE_ACLK_MIF1, + 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DREX1_0, "aclk_asyncaxis_drex1_0", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DREX1_0, "aclk_asyncaxim_drex1_0", + "div_aclk_drex1", ENABLE_ACLK_MIF1, + 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DREX0_3, "aclk_asyncaxis_drex0_3", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DREX0_3, "aclk_asyncaxim_drex0_3", + "div_aclk_drex0", ENABLE_ACLK_MIF1, + 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DREX0_1, "aclk_asyncaxis_drex0_1", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DREX0_1, "aclk_asyncaxim_drex0_1", + "div_aclk_drex0", ENABLE_ACLK_MIF1, + 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DREX0_0, "aclk_asyncaxis_drex0_0", + "div_aclk_mif_133", ENABLE_ACLK_MIF1, + 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DREX0_0, "aclk_asyncaxim_drex0_0", + "div_aclk_drex0", ENABLE_ACLK_MIF1, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_MIF2P, "aclk_ahb2apb_mif2p", "div_aclk_mif_133", + ENABLE_ACLK_MIF1, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_MIF1P, "aclk_ahb2apb_mif1p", "div_aclk_mif_133", + ENABLE_ACLK_MIF1, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_MIF0P, "aclk_ahb2apb_mif0p", "div_aclk_mif_133", + ENABLE_ACLK_MIF1, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_IXIU_CCI, "aclk_ixiu_cci", "div_aclk_mif_400", + ENABLE_ACLK_MIF1, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_MIFSFRX, "aclk_xiu_mifsfrx", "div_aclk_mif_200", + ENABLE_ACLK_MIF1, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MIFNP_133, "aclk_mifnp_133", "div_aclk_mif_133", + ENABLE_ACLK_MIF1, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MIFNM_200, "aclk_mifnm_200", "div_aclk_mifnm_200", + ENABLE_ACLK_MIF1, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MIFND_133, "aclk_mifnd_133", "div_aclk_mifnd_133", + ENABLE_ACLK_MIF1, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MIFND_400, "aclk_mifnd_400", "div_aclk_mif_400", + ENABLE_ACLK_MIF1, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CCI, "aclk_cci", "div_aclk_mif_400", ENABLE_ACLK_MIF1, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_MIF2 */ + GATE(CLK_ACLK_MIFND_266, "aclk_mifnd_266", "div_aclk_mif_266", + ENABLE_ACLK_MIF2, 20, 0, 0), + GATE(CLK_ACLK_PPMU_DREX1S3, "aclk_ppmu_drex1s3", "div_aclk_drex1", + ENABLE_ACLK_MIF2, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PPMU_DREX1S1, "aclk_ppmu_drex1s1", "div_aclk_drex1", + ENABLE_ACLK_MIF2, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PPMU_DREX1S0, "aclk_ppmu_drex1s0", "div_aclk_drex1", + ENABLE_ACLK_MIF2, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PPMU_DREX0S3, "aclk_ppmu_drex0s3", "div_aclk_drex0", + ENABLE_ACLK_MIF2, 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PPMU_DREX0S1, "aclk_ppmu_drex0s1", "div_aclk_drex0", + ENABLE_ACLK_MIF2, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_PPMU_DREX0S0, "aclk_ppmu_drex0s0", "div_aclk_drex0", + ENABLE_ACLK_MIF2, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIDS_CCI_MIFSFRX, "aclk_axids_cci_mifsfrx", + "div_aclk_mif_200", ENABLE_ACLK_MIF2, 7, + CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXISYNCDNS_CCI, "aclk_axisyncdns_cci", + "div_aclk_mif_400", ENABLE_ACLK_MIF2, + 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXISYNCDN_CCI, "aclk_axisyncdn_cci", "div_aclk_mif_400", + ENABLE_ACLK_MIF2, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXISYNCDN_NOC_D, "aclk_axisyncdn_noc_d", + "div_aclk_mif_200", ENABLE_ACLK_MIF2, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_MIF_CSSYS, "aclk_asyncapbs_mif_cssys", + "div_aclk_mifnd_133", ENABLE_ACLK_MIF2, 0, 0, 0), + + /* ENABLE_ACLK_MIF3 */ + GATE(CLK_ACLK_BUS2_400, "aclk_bus2_400", "div_aclk_bus2_400", + ENABLE_ACLK_MIF3, 4, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_ACLK_DISP_333, "aclk_disp_333", "div_aclk_disp_333", + ENABLE_ACLK_MIF3, 1, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_ACLK_CPIF_200, "aclk_cpif_200", "div_aclk_cpif_200", + ENABLE_ACLK_MIF3, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + + /* ENABLE_PCLK_MIF */ + GATE(CLK_PCLK_PPMU_DREX1S3, "pclk_ppmu_drex1s3", "div_aclk_drex1", + ENABLE_PCLK_MIF, 29, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PPMU_DREX1S1, "pclk_ppmu_drex1s1", "div_aclk_drex1", + ENABLE_PCLK_MIF, 28, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PPMU_DREX1S0, "pclk_ppmu_drex1s0", "div_aclk_drex1", + ENABLE_PCLK_MIF, 27, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PPMU_DREX0S3, "pclk_ppmu_drex0s3", "div_aclk_drex0", + ENABLE_PCLK_MIF, 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PPMU_DREX0S1, "pclk_ppmu_drex0s1", "div_aclk_drex0", + ENABLE_PCLK_MIF, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PPMU_DREX0S0, "pclk_ppmu_drex0s0", "div_aclk_drex0", + ENABLE_PCLK_MIF, 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_NOC_P_CCI, "pclk_asyncaxi_noc_p_cci", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 21, + CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_CP1, "pclk_asyncaxi_cp1", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 19, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_CP0, "pclk_asyncaxi_cp0", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 18, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_DREX1_3, "pclk_asyncaxi_drex1_3", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 17, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_DREX1_1, "pclk_asyncaxi_drex1_1", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 16, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_DREX1_0, "pclk_asyncaxi_drex1_0", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 15, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_DREX0_3, "pclk_asyncaxi_drex0_3", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 14, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_DREX0_1, "pclk_asyncaxi_drex0_1", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 13, 0, 0), + GATE(CLK_PCLK_ASYNCAXI_DREX0_0, "pclk_asyncaxi_drex0_0", + "div_aclk_mif_133", ENABLE_PCLK_MIF, 12, 0, 0), + GATE(CLK_PCLK_MIFSRVND_133, "pclk_mifsrvnd_133", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 11, 0, 0), + GATE(CLK_PCLK_PMU_MIF, "pclk_pmu_mif", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_MIF, "pclk_sysreg_mif", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_GPIO_ALIVE, "pclk_gpio_alive", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ABB, "pclk_abb", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 7, 0, 0), + GATE(CLK_PCLK_PMU_APBIF, "pclk_pmu_apbif", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DDR_PHY1, "pclk_ddr_phy1", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 5, 0, 0), + GATE(CLK_PCLK_DREX1, "pclk_drex1", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DDR_PHY0, "pclk_ddr_phy0", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 2, 0, 0), + GATE(CLK_PCLK_DREX0, "pclk_drex0", "div_aclk_mif_133", + ENABLE_PCLK_MIF, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_MIF_SECURE_DREX0_TZ */ + GATE(CLK_PCLK_DREX0_TZ, "pclk_drex0_tz", "div_aclk_mif_133", + ENABLE_PCLK_MIF_SECURE_DREX0_TZ, 0, 0, 0), + + /* ENABLE_PCLK_MIF_SECURE_DREX1_TZ */ + GATE(CLK_PCLK_DREX1_TZ, "pclk_drex1_tz", "div_aclk_mif_133", + ENABLE_PCLK_MIF_SECURE_DREX1_TZ, 0, 0, 0), + + /* ENABLE_PCLK_MIF_SECURE_MONOTONIC_CNT */ + GATE(CLK_PCLK_MONOTONIC_CNT, "pclk_monotonic_cnt", "div_aclk_mif_133", + ENABLE_PCLK_MIF_SECURE_RTC, 0, 0, 0), + + /* ENABLE_PCLK_MIF_SECURE_RTC */ + GATE(CLK_PCLK_RTC, "pclk_rtc", "div_aclk_mif_133", + ENABLE_PCLK_MIF_SECURE_RTC, 0, 0, 0), + + /* ENABLE_SCLK_MIF */ + GATE(CLK_SCLK_DSIM1_DISP, "sclk_dsim1_disp", "div_sclk_dsim1", + ENABLE_SCLK_MIF, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_DECON_TV_VCLK_DISP, "sclk_decon_tv_vclk_disp", + "div_sclk_decon_tv_vclk", ENABLE_SCLK_MIF, + 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_DSIM0_DISP, "sclk_dsim0_disp", "div_sclk_dsim0", + ENABLE_SCLK_MIF, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_DSD_DISP, "sclk_dsd_disp", "div_sclk_dsd", + ENABLE_SCLK_MIF, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_DECON_TV_ECLK_DISP, "sclk_decon_tv_eclk_disp", + "div_sclk_decon_tv_eclk", ENABLE_SCLK_MIF, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_DECON_VCLK_DISP, "sclk_decon_vclk_disp", + "div_sclk_decon_vclk", ENABLE_SCLK_MIF, + 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_DECON_ECLK_DISP, "sclk_decon_eclk_disp", + "div_sclk_decon_eclk", ENABLE_SCLK_MIF, + 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_HPM_MIF, "sclk_hpm_mif", "div_sclk_hpm_mif", + ENABLE_SCLK_MIF, 4, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_MFC_PLL, "sclk_mfc_pll", "mout_mfc_pll_div2", + ENABLE_SCLK_MIF, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_BUS_PLL, "sclk_bus_pll", "mout_bus_pll_div2", + ENABLE_SCLK_MIF, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_BUS_PLL_APOLLO, "sclk_bus_pll_apollo", "sclk_bus_pll", + ENABLE_SCLK_MIF, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_BUS_PLL_ATLAS, "sclk_bus_pll_atlas", "sclk_bus_pll", + ENABLE_SCLK_MIF, 0, CLK_IGNORE_UNUSED, 0), +}; + static struct samsung_cmu_info mif_cmu_info __initdata = { .pll_clks = mif_pll_clks, .nr_pll_clks = ARRAY_SIZE(mif_pll_clks), + .mux_clks = mif_mux_clks, + .nr_mux_clks = ARRAY_SIZE(mif_mux_clks), + .div_clks = mif_div_clks, + .nr_div_clks = ARRAY_SIZE(mif_div_clks), + .gate_clks = mif_gate_clks, + .nr_gate_clks = ARRAY_SIZE(mif_gate_clks), + .fixed_factor_clks = mif_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(mif_fixed_factor_clks), .nr_clk_ids = MIF_NR_CLK, .clk_regs = mif_clk_regs, .nr_clk_regs = ARRAY_SIZE(mif_clk_regs), diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 818d6b6bbdc4..6a3ce113e1e5 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -149,8 +149,196 @@ #define CLK_FOUT_MEM1_PLL 2 #define CLK_FOUT_BUS_PLL 3 #define CLK_FOUT_MFC_PLL 4 +#define CLK_DOUT_MFC_PLL 5 +#define CLK_DOUT_BUS_PLL 6 +#define CLK_DOUT_MEM1_PLL 7 +#define CLK_DOUT_MEM0_PLL 8 -#define MIF_NR_CLK 5 +#define CLK_MOUT_MFC_PLL_DIV2 10 +#define CLK_MOUT_BUS_PLL_DIV2 11 +#define CLK_MOUT_MEM1_PLL_DIV2 12 +#define CLK_MOUT_MEM0_PLL_DIV2 13 +#define CLK_MOUT_MFC_PLL 14 +#define CLK_MOUT_BUS_PLL 15 +#define CLK_MOUT_MEM1_PLL 16 +#define CLK_MOUT_MEM0_PLL 17 +#define CLK_MOUT_CLK2X_PHY_C 18 +#define CLK_MOUT_CLK2X_PHY_B 19 +#define CLK_MOUT_CLK2X_PHY_A 20 +#define CLK_MOUT_CLKM_PHY_C 21 +#define CLK_MOUT_CLKM_PHY_B 22 +#define CLK_MOUT_CLKM_PHY_A 23 +#define CLK_MOUT_ACLK_MIFNM_200 24 +#define CLK_MOUT_ACLK_MIFNM_400 25 +#define CLK_MOUT_ACLK_DISP_333_B 26 +#define CLK_MOUT_ACLK_DISP_333_A 27 +#define CLK_MOUT_SCLK_DECON_VCLK_C 28 +#define CLK_MOUT_SCLK_DECON_VCLK_B 29 +#define CLK_MOUT_SCLK_DECON_VCLK_A 30 +#define CLK_MOUT_SCLK_DECON_ECLK_C 31 +#define CLK_MOUT_SCLK_DECON_ECLK_B 32 +#define CLK_MOUT_SCLK_DECON_ECLK_A 33 +#define CLK_MOUT_SCLK_DECON_TV_ECLK_C 34 +#define CLK_MOUT_SCLK_DECON_TV_ECLK_B 35 +#define CLK_MOUT_SCLK_DECON_TV_ECLK_A 36 +#define CLK_MOUT_SCLK_DSD_C 37 +#define CLK_MOUT_SCLK_DSD_B 38 +#define CLK_MOUT_SCLK_DSD_A 39 +#define CLK_MOUT_SCLK_DSIM0_C 40 +#define CLK_MOUT_SCLK_DSIM0_B 41 +#define CLK_MOUT_SCLK_DSIM0_A 42 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_C 46 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_B 47 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_A 48 +#define CLK_MOUT_SCLK_DSIM1_C 49 +#define CLK_MOUT_SCLK_DSIM1_B 50 +#define CLK_MOUT_SCLK_DSIM1_A 51 + +#define CLK_DIV_SCLK_HPM_MIF 55 +#define CLK_DIV_ACLK_DREX1 56 +#define CLK_DIV_ACLK_DREX0 57 +#define CLK_DIV_CLK2XPHY 58 +#define CLK_DIV_ACLK_MIF_266 59 +#define CLK_DIV_ACLK_MIFND_133 60 +#define CLK_DIV_ACLK_MIF_133 61 +#define CLK_DIV_ACLK_MIFNM_200 62 +#define CLK_DIV_ACLK_MIF_200 63 +#define CLK_DIV_ACLK_MIF_400 64 +#define CLK_DIV_ACLK_BUS2_400 65 +#define CLK_DIV_ACLK_DISP_333 66 +#define CLK_DIV_ACLK_CPIF_200 67 +#define CLK_DIV_SCLK_DSIM1 68 +#define CLK_DIV_SCLK_DECON_TV_VCLK 69 +#define CLK_DIV_SCLK_DSIM0 70 +#define CLK_DIV_SCLK_DSD 71 +#define CLK_DIV_SCLK_DECON_TV_ECLK 72 +#define CLK_DIV_SCLK_DECON_VCLK 73 +#define CLK_DIV_SCLK_DECON_ECLK 74 +#define CLK_DIV_MIF_PRE 75 + +#define CLK_CLK2X_PHY1 80 +#define CLK_CLK2X_PHY0 81 +#define CLK_CLKM_PHY1 82 +#define CLK_CLKM_PHY0 83 +#define CLK_RCLK_DREX1 84 +#define CLK_RCLK_DREX0 85 +#define CLK_ACLK_DREX1_TZ 86 +#define CLK_ACLK_DREX0_TZ 87 +#define CLK_ACLK_DREX1_PEREV 88 +#define CLK_ACLK_DREX0_PEREV 89 +#define CLK_ACLK_DREX1_MEMIF 90 +#define CLK_ACLK_DREX0_MEMIF 91 +#define CLK_ACLK_DREX1_SCH 92 +#define CLK_ACLK_DREX0_SCH 93 +#define CLK_ACLK_DREX1_BUSIF 94 +#define CLK_ACLK_DREX0_BUSIF 95 +#define CLK_ACLK_DREX1_BUSIF_RD 96 +#define CLK_ACLK_DREX0_BUSIF_RD 97 +#define CLK_ACLK_DREX1 98 +#define CLK_ACLK_DREX0 99 +#define CLK_ACLK_ASYNCAXIM_ATLAS_CCIX 100 +#define CLK_ACLK_ASYNCAXIS_ATLAS_MIF 101 +#define CLK_ACLK_ASYNCAXIM_ATLAS_MIF 102 +#define CLK_ACLK_ASYNCAXIS_MIF_IMEM 103 +#define CLK_ACLK_ASYNCAXIS_NOC_P_CCI 104 +#define CLK_ACLK_ASYNCAXIM_NOC_P_CCI 105 +#define CLK_ACLK_ASYNCAXIS_CP1 106 +#define CLK_ACLK_ASYNCAXIM_CP1 107 +#define CLK_ACLK_ASYNCAXIS_CP0 108 +#define CLK_ACLK_ASYNCAXIM_CP0 109 +#define CLK_ACLK_ASYNCAXIS_DREX1_3 110 +#define CLK_ACLK_ASYNCAXIM_DREX1_3 111 +#define CLK_ACLK_ASYNCAXIS_DREX1_1 112 +#define CLK_ACLK_ASYNCAXIM_DREX1_1 113 +#define CLK_ACLK_ASYNCAXIS_DREX1_0 114 +#define CLK_ACLK_ASYNCAXIM_DREX1_0 115 +#define CLK_ACLK_ASYNCAXIS_DREX0_3 116 +#define CLK_ACLK_ASYNCAXIM_DREX0_3 117 +#define CLK_ACLK_ASYNCAXIS_DREX0_1 118 +#define CLK_ACLK_ASYNCAXIM_DREX0_1 119 +#define CLK_ACLK_ASYNCAXIS_DREX0_0 120 +#define CLK_ACLK_ASYNCAXIM_DREX0_0 121 +#define CLK_ACLK_AHB2APB_MIF2P 122 +#define CLK_ACLK_AHB2APB_MIF1P 123 +#define CLK_ACLK_AHB2APB_MIF0P 124 +#define CLK_ACLK_IXIU_CCI 125 +#define CLK_ACLK_XIU_MIFSFRX 126 +#define CLK_ACLK_MIFNP_133 127 +#define CLK_ACLK_MIFNM_200 128 +#define CLK_ACLK_MIFND_133 129 +#define CLK_ACLK_MIFND_400 130 +#define CLK_ACLK_CCI 131 +#define CLK_ACLK_MIFND_266 132 +#define CLK_ACLK_PPMU_DREX1S3 133 +#define CLK_ACLK_PPMU_DREX1S1 134 +#define CLK_ACLK_PPMU_DREX1S0 135 +#define CLK_ACLK_PPMU_DREX0S3 136 +#define CLK_ACLK_PPMU_DREX0S1 137 +#define CLK_ACLK_PPMU_DREX0S0 138 +#define CLK_ACLK_BTS_APOLLO 139 +#define CLK_ACLK_BTS_ATLAS 140 +#define CLK_ACLK_ACE_SEL_APOLL 141 +#define CLK_ACLK_ACE_SEL_ATLAS 142 +#define CLK_ACLK_AXIDS_CCI_MIFSFRX 143 +#define CLK_ACLK_AXIUS_ATLAS_CCI 144 +#define CLK_ACLK_AXISYNCDNS_CCI 145 +#define CLK_ACLK_AXISYNCDN_CCI 146 +#define CLK_ACLK_AXISYNCDN_NOC_D 147 +#define CLK_ACLK_ASYNCACEM_APOLLO_CCI 148 +#define CLK_ACLK_ASYNCACEM_ATLAS_CCI 149 +#define CLK_ACLK_ASYNCAPBS_MIF_CSSYS 150 +#define CLK_ACLK_BUS2_400 151 +#define CLK_ACLK_DISP_333 152 +#define CLK_ACLK_CPIF_200 153 +#define CLK_PCLK_PPMU_DREX1S3 154 +#define CLK_PCLK_PPMU_DREX1S1 155 +#define CLK_PCLK_PPMU_DREX1S0 156 +#define CLK_PCLK_PPMU_DREX0S3 157 +#define CLK_PCLK_PPMU_DREX0S1 158 +#define CLK_PCLK_PPMU_DREX0S0 159 +#define CLK_PCLK_BTS_APOLLO 160 +#define CLK_PCLK_BTS_ATLAS 161 +#define CLK_PCLK_ASYNCAXI_NOC_P_CCI 162 +#define CLK_PCLK_ASYNCAXI_CP1 163 +#define CLK_PCLK_ASYNCAXI_CP0 164 +#define CLK_PCLK_ASYNCAXI_DREX1_3 165 +#define CLK_PCLK_ASYNCAXI_DREX1_1 166 +#define CLK_PCLK_ASYNCAXI_DREX1_0 167 +#define CLK_PCLK_ASYNCAXI_DREX0_3 168 +#define CLK_PCLK_ASYNCAXI_DREX0_1 169 +#define CLK_PCLK_ASYNCAXI_DREX0_0 170 +#define CLK_PCLK_MIFSRVND_133 171 +#define CLK_PCLK_PMU_MIF 172 +#define CLK_PCLK_SYSREG_MIF 173 +#define CLK_PCLK_GPIO_ALIVE 174 +#define CLK_PCLK_ABB 175 +#define CLK_PCLK_PMU_APBIF 176 +#define CLK_PCLK_DDR_PHY1 177 +#define CLK_PCLK_DREX1 178 +#define CLK_PCLK_DDR_PHY0 179 +#define CLK_PCLK_DREX0 180 +#define CLK_PCLK_DREX0_TZ 181 +#define CLK_PCLK_DREX1_TZ 182 +#define CLK_PCLK_MONOTONIC_CNT 183 +#define CLK_PCLK_RTC 184 +#define CLK_SCLK_DSIM1_DISP 185 +#define CLK_SCLK_DECON_TV_VCLK_DISP 186 +#define CLK_SCLK_FREQ_DET_BUS_PLL 187 +#define CLK_SCLK_FREQ_DET_MFC_PLL 188 +#define CLK_SCLK_FREQ_DET_MEM0_PLL 189 +#define CLK_SCLK_FREQ_DET_MEM1_PLL 190 +#define CLK_SCLK_DSIM0_DISP 191 +#define CLK_SCLK_DSD_DISP 192 +#define CLK_SCLK_DECON_TV_ECLK_DISP 193 +#define CLK_SCLK_DECON_VCLK_DISP 194 +#define CLK_SCLK_DECON_ECLK_DISP 195 +#define CLK_SCLK_HPM_MIF 196 +#define CLK_SCLK_MFC_PLL 197 +#define CLK_SCLK_BUS_PLL 198 +#define CLK_SCLK_BUS_PLL_APOLLO 199 +#define CLK_SCLK_BUS_PLL_ATLAS 200 + +#define MIF_NR_CLK 201 /* CMU_PERIC */ #define CLK_PCLK_SPI2 1 -- cgit v1.2.3 From 2a1808a6c00fb6d75ebfa596add57638b9290926 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:02 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_DISP domain This patch adds the the mux/divider/gate clocks for CMU_DISP domain which includes clocks of the display IPs (DECON/HDMI/DSIM/MIXER). Also, CMU_DISP requires 'sclk_hdmi_spdif_disp' source clock from CMU_TOP domain. This patch adds the clocks of CMU_TOP related to HDMI. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 437 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 114 ++++++++- 2 files changed, 550 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 09ccf11bab64..3e6c3d595e96 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -245,6 +245,8 @@ PNAME(mout_sclk_audio1_p) = { "ioclk_audiocdclk1", "oscclk", PNAME(mout_sclk_audio0_p) = { "ioclk_audiocdclk0", "oscclk", "mout_aud_pll_user_t",}; +PNAME(mout_sclk_hdmi_spdif_p) = { "sclk_audio1", "ioclk_spdif_extclk", }; + static struct samsung_fixed_factor_clock top_fixed_factor_clks[] __initdata = { FFACTOR(0, "oscclk_efuse_common", "oscclk", 1, 1, 0), }; @@ -395,6 +397,10 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { MUX_SEL_TOP_PERIC1, 4, 2), MUX(CLK_MOUT_SCLK_AUDIO0, "mout_sclk_audio0", mout_sclk_audio0_p, MUX_SEL_TOP_PERIC1, 0, 2), + + /* MUX_SEL_TOP_DISP */ + MUX(CLK_MOUT_SCLK_HDMI_SPDIF, "mout_sclk_hdmi_spdif", + mout_sclk_hdmi_spdif_p, MUX_SEL_TOP_DISP, 0, 1), }; static struct samsung_div_clock top_div_clks[] __initdata = { @@ -1360,6 +1366,11 @@ static struct samsung_gate_clock mif_gate_clks[] __initdata = { ENABLE_SCLK_MIF, 1, CLK_IGNORE_UNUSED, 0), GATE(CLK_SCLK_BUS_PLL_ATLAS, "sclk_bus_pll_atlas", "sclk_bus_pll", ENABLE_SCLK_MIF, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_TOP_DISP */ + GATE(CLK_SCLK_HDMI_SPDIF_DISP, "sclk_hdmi_spdif_disp", + "mout_sclk_hdmi_spdif", ENABLE_SCLK_TOP_DISP, 0, + CLK_IGNORE_UNUSED, 0), }; static struct samsung_cmu_info mif_cmu_info __initdata = { @@ -2022,3 +2033,429 @@ static void __init exynos5433_cmu_g2d_init(struct device_node *np) CLK_OF_DECLARE(exynos5433_cmu_g2d, "samsung,exynos5433-cmu-g2d", exynos5433_cmu_g2d_init); + +/* + * Register offset definitions for CMU_DISP + */ +#define DISP_PLL_LOCK 0x0000 +#define DISP_PLL_CON0 0x0100 +#define DISP_PLL_CON1 0x0104 +#define DISP_PLL_FREQ_DET 0x0108 +#define MUX_SEL_DISP0 0x0200 +#define MUX_SEL_DISP1 0x0204 +#define MUX_SEL_DISP2 0x0208 +#define MUX_SEL_DISP3 0x020c +#define MUX_SEL_DISP4 0x0210 +#define MUX_ENABLE_DISP0 0x0300 +#define MUX_ENABLE_DISP1 0x0304 +#define MUX_ENABLE_DISP2 0x0308 +#define MUX_ENABLE_DISP3 0x030c +#define MUX_ENABLE_DISP4 0x0310 +#define MUX_STAT_DISP0 0x0400 +#define MUX_STAT_DISP1 0x0404 +#define MUX_STAT_DISP2 0x0408 +#define MUX_STAT_DISP3 0x040c +#define MUX_STAT_DISP4 0x0410 +#define MUX_IGNORE_DISP2 0x0508 +#define DIV_DISP 0x0600 +#define DIV_DISP_PLL_FREQ_DET 0x0604 +#define DIV_STAT_DISP 0x0700 +#define DIV_STAT_DISP_PLL_FREQ_DET 0x0704 +#define ENABLE_ACLK_DISP0 0x0800 +#define ENABLE_ACLK_DISP1 0x0804 +#define ENABLE_PCLK_DISP 0x0900 +#define ENABLE_SCLK_DISP 0x0a00 +#define ENABLE_IP_DISP0 0x0b00 +#define ENABLE_IP_DISP1 0x0b04 +#define CLKOUT_CMU_DISP 0x0c00 +#define CLKOUT_CMU_DISP_DIV_STAT 0x0c04 + +static unsigned long disp_clk_regs[] __initdata = { + DISP_PLL_LOCK, + DISP_PLL_CON0, + DISP_PLL_CON1, + DISP_PLL_FREQ_DET, + MUX_SEL_DISP0, + MUX_SEL_DISP1, + MUX_SEL_DISP2, + MUX_SEL_DISP3, + MUX_SEL_DISP4, + MUX_ENABLE_DISP0, + MUX_ENABLE_DISP1, + MUX_ENABLE_DISP2, + MUX_ENABLE_DISP3, + MUX_ENABLE_DISP4, + MUX_STAT_DISP0, + MUX_STAT_DISP1, + MUX_STAT_DISP2, + MUX_STAT_DISP3, + MUX_STAT_DISP4, + MUX_IGNORE_DISP2, + DIV_DISP, + DIV_DISP_PLL_FREQ_DET, + DIV_STAT_DISP, + DIV_STAT_DISP_PLL_FREQ_DET, + ENABLE_ACLK_DISP0, + ENABLE_ACLK_DISP1, + ENABLE_PCLK_DISP, + ENABLE_SCLK_DISP, + ENABLE_IP_DISP0, + ENABLE_IP_DISP1, + CLKOUT_CMU_DISP, + CLKOUT_CMU_DISP_DIV_STAT, +}; + +/* list of all parent clock list */ +PNAME(mout_disp_pll_p) = { "oscclk", "fout_disp_pll", }; +PNAME(mout_sclk_dsim1_user_p) = { "oscclk", "sclk_dsim1_disp", }; +PNAME(mout_sclk_dsim0_user_p) = { "oscclk", "sclk_dsim0_disp", }; +PNAME(mout_sclk_dsd_user_p) = { "oscclk", "sclk_dsd_disp", }; +PNAME(mout_sclk_decon_tv_eclk_user_p) = { "oscclk", + "sclk_decon_tv_eclk_disp", }; +PNAME(mout_sclk_decon_vclk_user_p) = { "oscclk", + "sclk_decon_vclk_disp", }; +PNAME(mout_sclk_decon_eclk_user_p) = { "oscclk", + "sclk_decon_eclk_disp", }; +PNAME(mout_sclk_decon_tv_vlkc_user_p) = { "oscclk", + "sclk_decon_tv_vclk_disp", }; +PNAME(mout_aclk_disp_333_user_p) = { "oscclk", "aclk_disp_333", }; + +PNAME(mout_phyclk_mipidphy1_bitclkdiv8_user_p) = { "oscclk", + "phyclk_mipidphy1_bitclkdiv8_phy", }; +PNAME(mout_phyclk_mipidphy1_rxclkesc0_user_p) = { "oscclk", + "phyclk_mipidphy1_rxclkesc0_phy", }; +PNAME(mout_phyclk_mipidphy0_bitclkdiv8_user_p) = { "oscclk", + "phyclk_mipidphy0_bitclkdiv8_phy", }; +PNAME(mout_phyclk_mipidphy0_rxclkesc0_user_p) = { "oscclk", + "phyclk_mipidphy0_rxclkesc0_phy", }; +PNAME(mout_phyclk_hdmiphy_tmds_clko_user_p) = { "oscclk", + "phyclk_hdmiphy_tmds_clko_phy", }; +PNAME(mout_phyclk_hdmiphy_pixel_clko_user_p) = { "oscclk", + "phyclk_hdmiphy_pixel_clko_phy", }; + +PNAME(mout_sclk_dsim0_p) = { "mout_disp_pll", + "mout_sclk_dsim0_user", }; +PNAME(mout_sclk_decon_tv_eclk_p) = { "mout_disp_pll", + "mout_sclk_decon_tv_eclk_user", }; +PNAME(mout_sclk_decon_vclk_p) = { "mout_disp_pll", + "mout_sclk_decon_vclk_user", }; +PNAME(mout_sclk_decon_eclk_p) = { "mout_disp_pll", + "mout_sclk_decon_eclk_user", }; + +PNAME(mout_sclk_dsim1_b_disp_p) = { "mout_sclk_dsim1_a_disp", + "mout_sclk_dsim1_user", }; +PNAME(mout_sclk_decon_tv_vclk_c_disp_p) = { + "mout_phyclk_hdmiphy_pixel_clko_user", + "mout_sclk_decon_tv_vclk_b_disp", }; +PNAME(mout_sclk_decon_tv_vclk_b_disp_p) = { "mout_sclk_decon_tv_vclk_a_disp", + "mout_sclk_decon_tv_vclk_user", }; + +static struct samsung_pll_clock disp_pll_clks[] __initdata = { + PLL(pll_35xx, CLK_FOUT_DISP_PLL, "fout_disp_pll", "oscclk", + DISP_PLL_LOCK, DISP_PLL_CON0, exynos5443_pll_rates), +}; + +static struct samsung_fixed_factor_clock disp_fixed_factor_clks[] __initdata = { + /* + * sclk_rgb_{vclk|tv_vclk} is half clock of sclk_decon_{vclk|tv_vclk}. + * The divider has fixed value (2) between sclk_rgb_{vclk|tv_vclk} + * and sclk_decon_{vclk|tv_vclk}. + */ + FFACTOR(CLK_SCLK_RGB_VCLK, "sclk_rgb_vclk", "sclk_decon_vclk", + 1, 2, 0), + FFACTOR(CLK_SCLK_RGB_TV_VCLK, "sclk_rgb_tv_vclk", "sclk_decon_tv_vclk", + 1, 2, 0), +}; + +static struct samsung_fixed_rate_clock disp_fixed_clks[] __initdata = { + /* PHY clocks from MIPI_DPHY1 */ + FRATE(0, "phyclk_mipidphy1_bitclkdiv8_phy", NULL, CLK_IS_ROOT, + 188000000), + FRATE(0, "phyclk_mipidphy1_rxclkesc0_phy", NULL, CLK_IS_ROOT, + 100000000), + /* PHY clocks from MIPI_DPHY0 */ + FRATE(0, "phyclk_mipidphy0_bitclkdiv8_phy", NULL, CLK_IS_ROOT, + 188000000), + FRATE(0, "phyclk_mipidphy0_rxclkesc0_phy", NULL, CLK_IS_ROOT, + 100000000), + /* PHY clocks from HDMI_PHY */ + FRATE(0, "phyclk_hdmiphy_tmds_clko_phy", NULL, CLK_IS_ROOT, 300000000), + FRATE(0, "phyclk_hdmiphy_pixel_clko_phy", NULL, CLK_IS_ROOT, 166000000), +}; + +static struct samsung_mux_clock disp_mux_clks[] __initdata = { + /* MUX_SEL_DISP0 */ + MUX(CLK_MOUT_DISP_PLL, "mout_disp_pll", mout_disp_pll_p, MUX_SEL_DISP0, + 0, 1), + + /* MUX_SEL_DISP1 */ + MUX(CLK_MOUT_SCLK_DSIM1_USER, "mout_sclk_dsim1_user", + mout_sclk_dsim1_user_p, MUX_SEL_DISP1, 28, 1), + MUX(CLK_MOUT_SCLK_DSIM0_USER, "mout_sclk_dsim0_user", + mout_sclk_dsim0_user_p, MUX_SEL_DISP1, 24, 1), + MUX(CLK_MOUT_SCLK_DSD_USER, "mout_sclk_dsd_user", mout_sclk_dsd_user_p, + MUX_SEL_DISP1, 20, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_ECLK_USER, "mout_sclk_decon_tv_eclk_user", + mout_sclk_decon_tv_eclk_user_p, MUX_SEL_DISP1, 16, 1), + MUX(CLK_MOUT_SCLK_DECON_VCLK_USER, "mout_sclk_decon_vclk_user", + mout_sclk_decon_vclk_user_p, MUX_SEL_DISP1, 12, 1), + MUX(CLK_MOUT_SCLK_DECON_ECLK_USER, "mout_sclk_decon_eclk_user", + mout_sclk_decon_eclk_user_p, MUX_SEL_DISP1, 8, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_USER, "mout_sclk_decon_tv_vclk_user", + mout_sclk_decon_tv_vlkc_user_p, MUX_SEL_DISP1, 4, 1), + MUX(CLK_MOUT_ACLK_DISP_333_USER, "mout_aclk_disp_333_user", + mout_aclk_disp_333_user_p, MUX_SEL_DISP1, 0, 1), + + /* MUX_SEL_DISP2 */ + MUX(CLK_MOUT_PHYCLK_MIPIDPHY1_BITCLKDIV8_USER, + "mout_phyclk_mipidphy1_bitclkdiv8_user", + mout_phyclk_mipidphy1_bitclkdiv8_user_p, MUX_SEL_DISP2, + 20, 1), + MUX(CLK_MOUT_PHYCLK_MIPIDPHY1_RXCLKESC0_USER, + "mout_phyclk_mipidphy1_rxclkesc0_user", + mout_phyclk_mipidphy1_rxclkesc0_user_p, MUX_SEL_DISP2, + 16, 1), + MUX(CLK_MOUT_PHYCLK_MIPIDPHY0_BITCLKDIV8_USER, + "mout_phyclk_mipidphy0_bitclkdiv8_user", + mout_phyclk_mipidphy0_bitclkdiv8_user_p, MUX_SEL_DISP2, + 12, 1), + MUX(CLK_MOUT_PHYCLK_MIPIDPHY0_RXCLKESC0_USER, + "mout_phyclk_mipidphy0_rxclkesc0_user", + mout_phyclk_mipidphy0_rxclkesc0_user_p, MUX_SEL_DISP2, + 8, 1), + MUX(CLK_MOUT_PHYCLK_HDMIPHY_TMDS_CLKO_USER, + "mout_phyclk_hdmiphy_tmds_clko_user", + mout_phyclk_hdmiphy_tmds_clko_user_p, MUX_SEL_DISP2, + 4, 1), + MUX(CLK_MOUT_PHYCLK_HDMIPHY_PIXEL_CLKO_USER, + "mout_phyclk_hdmiphy_pixel_clko_user", + mout_phyclk_hdmiphy_pixel_clko_user_p, MUX_SEL_DISP2, + 0, 1), + + /* MUX_SEL_DISP3 */ + MUX(CLK_MOUT_SCLK_DSIM0, "mout_sclk_dsim0", mout_sclk_dsim0_p, + MUX_SEL_DISP3, 12, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_ECLK, "mout_sclk_decon_tv_eclk", + mout_sclk_decon_tv_eclk_p, MUX_SEL_DISP3, 8, 1), + MUX(CLK_MOUT_SCLK_DECON_VCLK, "mout_sclk_decon_vclk", + mout_sclk_decon_vclk_p, MUX_SEL_DISP3, 4, 1), + MUX(CLK_MOUT_SCLK_DECON_ECLK, "mout_sclk_decon_eclk", + mout_sclk_decon_eclk_p, MUX_SEL_DISP3, 0, 1), + + /* MUX_SEL_DISP4 */ + MUX(CLK_MOUT_SCLK_DSIM1_B_DISP, "mout_sclk_dsim1_b_disp", + mout_sclk_dsim1_b_disp_p, MUX_SEL_DISP4, 16, 1), + MUX(CLK_MOUT_SCLK_DSIM1_A_DISP, "mout_sclk_dsim1_a_disp", + mout_sclk_dsim0_p, MUX_SEL_DISP4, 12, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_C_DISP, + "mout_sclk_decon_tv_vclk_c_disp", + mout_sclk_decon_tv_vclk_c_disp_p, MUX_SEL_DISP4, 8, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_B_DISP, + "mout_sclk_decon_tv_vclk_b_disp", + mout_sclk_decon_tv_vclk_b_disp_p, MUX_SEL_DISP4, 4, 1), + MUX(CLK_MOUT_SCLK_DECON_TV_VCLK_A_DISP, + "mout_sclk_decon_tv_vclk_a_disp", + mout_sclk_decon_vclk_p, MUX_SEL_DISP4, 0, 1), +}; + +static struct samsung_div_clock disp_div_clks[] __initdata = { + /* DIV_DISP */ + DIV(CLK_DIV_SCLK_DSIM1_DISP, "div_sclk_dsim1_disp", + "mout_sclk_dsim1_b_disp", DIV_DISP, 24, 3), + DIV(CLK_DIV_SCLK_DECON_TV_VCLK_DISP, "div_sclk_decon_tv_vclk_disp", + "mout_sclk_decon_tv_vclk_c_disp", DIV_DISP, 20, 3), + DIV(CLK_DIV_SCLK_DSIM0_DISP, "div_sclk_dsim0_disp", "mout_sclk_dsim0", + DIV_DISP, 16, 3), + DIV(CLK_DIV_SCLK_DECON_TV_ECLK_DISP, "div_sclk_decon_tv_eclk_disp", + "mout_sclk_decon_tv_eclk", DIV_DISP, 12, 3), + DIV(CLK_DIV_SCLK_DECON_VCLK_DISP, "div_sclk_decon_vclk_disp", + "mout_sclk_decon_vclk", DIV_DISP, 8, 3), + DIV(CLK_DIV_SCLK_DECON_ECLK_DISP, "div_sclk_decon_eclk_disp", + "mout_sclk_decon_eclk", DIV_DISP, 4, 3), + DIV(CLK_DIV_PCLK_DISP, "div_pclk_disp", "mout_aclk_disp_333_user", + DIV_DISP, 0, 2), +}; + +static struct samsung_gate_clock disp_gate_clks[] __initdata = { + /* ENABLE_ACLK_DISP0 */ + GATE(CLK_ACLK_DECON_TV, "aclk_decon_tv", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP0, 2, 0, 0), + GATE(CLK_ACLK_DECON, "aclk_decon", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP0, 0, 0, 0), + + /* ENABLE_ACLK_DISP1 */ + GATE(CLK_ACLK_SMMU_TV1X, "aclk_smmu_tv1x", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP1, 25, 0, 0), + GATE(CLK_ACLK_SMMU_TV0X, "aclk_smmu_tv0x", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP1, 24, 0, 0), + GATE(CLK_ACLK_SMMU_DECON1X, "aclk_smmu_decon1x", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 23, 0, 0), + GATE(CLK_ACLK_SMMU_DECON0X, "aclk_smmu_decon0x", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 22, 0, 0), + GATE(CLK_ACLK_BTS_DECON_TV_M3, "aclk_bts_decon_tv_m3", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 21, 0, 0), + GATE(CLK_ACLK_BTS_DECON_TV_M2, "aclk_bts_decon_tv_m2", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 20, 0, 0), + GATE(CLK_ACLK_BTS_DECON_TV_M1, "aclk_bts_decon_tv_m1", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 19, 0, 0), + GATE(CLK_ACLK_BTS_DECON_TV_M0, "aclk-bts_decon_tv_m0", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 18, 0, 0), + GATE(CLK_ACLK_BTS_DECON_NM4, "aclk_bts_decon_nm4", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 17, 0, 0), + GATE(CLK_ACLK_BTS_DECON_NM3, "aclk_bts_decon_nm3", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 16, 0, 0), + GATE(CLK_ACLK_BTS_DECON_NM2, "aclk_bts_decon_nm2", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 15, 0, 0), + GATE(CLK_ACLK_BTS_DECON_NM1, "aclk_bts_decon_nm1", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 14, 0, 0), + GATE(CLK_ACLK_BTS_DECON_NM0, "aclk_bts_decon_nm0", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 13, 0, 0), + GATE(CLK_ACLK_AHB2APB_DISPSFR2P, "aclk_ahb2apb_dispsfr2p", + "div_pclk_disp", ENABLE_ACLK_DISP1, + 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_DISPSFR1P, "aclk_ahb2apb_dispsfr1p", + "div_pclk_disp", ENABLE_ACLK_DISP1, + 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_DISPSFR0P, "aclk_ahb2apb_dispsfr0p", + "div_pclk_disp", ENABLE_ACLK_DISP1, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB_DISPH, "aclk_ahb_disph", "div_pclk_disp", + ENABLE_ACLK_DISP1, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_TV1X, "aclk_xiu_tv1x", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP1, 7, 0, 0), + GATE(CLK_ACLK_XIU_TV0X, "aclk_xiu_tv0x", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP1, 6, 0, 0), + GATE(CLK_ACLK_XIU_DECON1X, "aclk_xiu_decon1x", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 5, 0, 0), + GATE(CLK_ACLK_XIU_DECON0X, "aclk_xiu_decon0x", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 4, 0, 0), + GATE(CLK_ACLK_XIU_DISP1X, "aclk_xiu_disp1x", "mout_aclk_disp_333_user", + ENABLE_ACLK_DISP1, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_DISPNP_100, "aclk_xiu_dispnp_100", "div_pclk_disp", + ENABLE_ACLK_DISP1, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DISP1ND_333, "aclk_disp1nd_333", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, 1, + CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_DISP0ND_333, "aclk_disp0nd_333", + "mout_aclk_disp_333_user", ENABLE_ACLK_DISP1, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_DISP */ + GATE(CLK_PCLK_SMMU_TV1X, "pclk_smmu_tv1x", "div_pclk_disp", + ENABLE_PCLK_DISP, 23, 0, 0), + GATE(CLK_PCLK_SMMU_TV0X, "pclk_smmu_tv0x", "div_pclk_disp", + ENABLE_PCLK_DISP, 22, 0, 0), + GATE(CLK_PCLK_SMMU_DECON1X, "pclk_smmu_decon1x", "div_pclk_disp", + ENABLE_PCLK_DISP, 21, 0, 0), + GATE(CLK_PCLK_SMMU_DECON0X, "pclk_smmu_decon0x", "div_pclk_disp", + ENABLE_PCLK_DISP, 20, 0, 0), + GATE(CLK_PCLK_BTS_DECON_TV_M3, "pclk_bts_decon_tv_m3", "div_pclk_disp", + ENABLE_PCLK_DISP, 19, 0, 0), + GATE(CLK_PCLK_BTS_DECON_TV_M2, "pclk_bts_decon_tv_m2", "div_pclk_disp", + ENABLE_PCLK_DISP, 18, 0, 0), + GATE(CLK_PCLK_BTS_DECON_TV_M1, "pclk_bts_decon_tv_m1", "div_pclk_disp", + ENABLE_PCLK_DISP, 17, 0, 0), + GATE(CLK_PCLK_BTS_DECON_TV_M0, "pclk_bts_decon_tv_m0", "div_pclk_disp", + ENABLE_PCLK_DISP, 16, 0, 0), + GATE(CLK_PCLK_BTS_DECONM4, "pclk_bts_deconm4", "div_pclk_disp", + ENABLE_PCLK_DISP, 15, 0, 0), + GATE(CLK_PCLK_BTS_DECONM3, "pclk_bts_deconm3", "div_pclk_disp", + ENABLE_PCLK_DISP, 14, 0, 0), + GATE(CLK_PCLK_BTS_DECONM2, "pclk_bts_deconm2", "div_pclk_disp", + ENABLE_PCLK_DISP, 13, 0, 0), + GATE(CLK_PCLK_BTS_DECONM1, "pclk_bts_deconm1", "div_pclk_disp", + ENABLE_PCLK_DISP, 12, 0, 0), + GATE(CLK_PCLK_BTS_DECONM0, "pclk_bts_deconm0", "div_pclk_disp", + ENABLE_PCLK_DISP, 11, 0, 0), + GATE(CLK_PCLK_MIC1, "pclk_mic1", "div_pclk_disp", + ENABLE_PCLK_DISP, 10, 0, 0), + GATE(CLK_PCLK_PMU_DISP, "pclk_pmu_disp", "div_pclk_disp", + ENABLE_PCLK_DISP, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_DISP, "pclk_sysreg_disp", "div_pclk_disp", + ENABLE_PCLK_DISP, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_HDMIPHY, "pclk_hdmiphy", "div_pclk_disp", + ENABLE_PCLK_DISP, 7, 0, 0), + GATE(CLK_PCLK_HDMI, "pclk_hdmi", "div_pclk_disp", + ENABLE_PCLK_DISP, 6, 0, 0), + GATE(CLK_PCLK_MIC0, "pclk_mic0", "div_pclk_disp", + ENABLE_PCLK_DISP, 5, 0, 0), + GATE(CLK_PCLK_DSIM1, "pclk_dsim1", "div_pclk_disp", + ENABLE_PCLK_DISP, 3, 0, 0), + GATE(CLK_PCLK_DSIM0, "pclk_dsim0", "div_pclk_disp", + ENABLE_PCLK_DISP, 2, 0, 0), + GATE(CLK_PCLK_DECON_TV, "pclk_decon_tv", "div_pclk_disp", + ENABLE_PCLK_DISP, 1, 0, 0), + + /* ENABLE_SCLK_DISP */ + GATE(CLK_PHYCLK_MIPIDPHY1_BITCLKDIV8, "phyclk_mipidphy1_bitclkdiv8", + "mout_phyclk_mipidphy1_bitclkdiv8_user", + ENABLE_SCLK_DISP, 26, 0, 0), + GATE(CLK_PHYCLK_MIPIDPHY1_RXCLKESC0, "phyclk_mipidphy1_rxclkesc0", + "mout_phyclk_mipidphy1_rxclkesc0_user", + ENABLE_SCLK_DISP, 25, 0, 0), + GATE(CLK_SCLK_RGB_TV_VCLK_TO_DSIM1, "sclk_rgb_tv_vclk_to_dsim1", + "sclk_rgb_tv_vclk", ENABLE_SCLK_DISP, 24, 0, 0), + GATE(CLK_SCLK_RGB_TV_VCLK_TO_MIC1, "sclk_rgb_tv_vclk_to_mic1", + "sclk_rgb_tv_vclk", ENABLE_SCLK_DISP, 23, 0, 0), + GATE(CLK_SCLK_DSIM1, "sclk_dsim1", "div_sclk_dsim1_disp", + ENABLE_SCLK_DISP, 22, 0, 0), + GATE(CLK_SCLK_DECON_TV_VCLK, "sclk_decon_tv_vclk", + "div_sclk_decon_tv_vclk_disp", + ENABLE_SCLK_DISP, 21, 0, 0), + GATE(CLK_PHYCLK_MIPIDPHY0_BITCLKDIV8, "phyclk_mipidphy0_bitclkdiv8", + "mout_phyclk_mipidphy0_bitclkdiv8_user", + ENABLE_SCLK_DISP, 15, 0, 0), + GATE(CLK_PHYCLK_MIPIDPHY0_RXCLKESC0, "phyclk_mipidphy0_rxclkesc0", + "mout_phyclk_mipidphy0_rxclkesc0_user", + ENABLE_SCLK_DISP, 14, 0, 0), + GATE(CLK_PHYCLK_HDMIPHY_TMDS_CLKO, "phyclk_hdmiphy_tmds_clko", + "mout_phyclk_hdmiphy_tmds_clko_user", + ENABLE_SCLK_DISP, 13, 0, 0), + GATE(CLK_PHYCLK_HDMI_PIXEL, "phyclk_hdmi_pixel", + "sclk_rgb_tv_vclk", ENABLE_SCLK_DISP, 12, 0, 0), + GATE(CLK_SCLK_RGB_VCLK_TO_SMIES, "sclk_rgb_vclk_to_smies", + "sclk_rgb_vclk", ENABLE_SCLK_DISP, 11, 0, 0), + GATE(CLK_SCLK_RGB_VCLK_TO_DSIM0, "sclk_rgb_vclk_to_dsim0", + "sclk_rgb_vclk", ENABLE_SCLK_DISP, 9, 0, 0), + GATE(CLK_SCLK_RGB_VCLK_TO_MIC0, "sclk_rgb_vclk_to_mic0", + "sclk_rgb_vclk", ENABLE_SCLK_DISP, 8, 0, 0), + GATE(CLK_SCLK_DSD, "sclk_dsd", "mout_sclk_dsd_user", + ENABLE_SCLK_DISP, 7, 0, 0), + GATE(CLK_SCLK_HDMI_SPDIF, "sclk_hdmi_spdif", "sclk_hdmi_spdif_disp", + ENABLE_SCLK_DISP, 6, 0, 0), + GATE(CLK_SCLK_DSIM0, "sclk_dsim0", "div_sclk_dsim0_disp", + ENABLE_SCLK_DISP, 5, 0, 0), + GATE(CLK_SCLK_DECON_TV_ECLK, "sclk_decon_tv_eclk", + "div_sclk_decon_tv_eclk_disp", + ENABLE_SCLK_DISP, 4, 0, 0), + GATE(CLK_SCLK_DECON_VCLK, "sclk_decon_vclk", + "div_sclk_decon_vclk_disp", ENABLE_SCLK_DISP, 3, 0, 0), + GATE(CLK_SCLK_DECON_ECLK, "sclk_decon_eclk", + "div_sclk_decon_eclk_disp", ENABLE_SCLK_DISP, 2, 0, 0), +}; + +static struct samsung_cmu_info disp_cmu_info __initdata = { + .pll_clks = disp_pll_clks, + .nr_pll_clks = ARRAY_SIZE(disp_pll_clks), + .mux_clks = disp_mux_clks, + .nr_mux_clks = ARRAY_SIZE(disp_mux_clks), + .div_clks = disp_div_clks, + .nr_div_clks = ARRAY_SIZE(disp_div_clks), + .gate_clks = disp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(disp_gate_clks), + .fixed_clks = disp_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(disp_fixed_clks), + .fixed_factor_clks = disp_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(disp_fixed_factor_clks), + .nr_clk_ids = DISP_NR_CLK, + .clk_regs = disp_clk_regs, + .nr_clk_regs = ARRAY_SIZE(disp_clk_regs), +}; + +static void __init exynos5433_cmu_disp_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &disp_cmu_info); +} + +CLK_OF_DECLARE(exynos5433_cmu_disp, "samsung,exynos5433-cmu-disp", + exynos5433_cmu_disp_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 6a3ce113e1e5..fe0650fad766 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -68,6 +68,7 @@ #define CLK_MOUT_SCLK_SPDIF 61 #define CLK_MOUT_SCLK_AUDIO1 62 #define CLK_MOUT_SCLK_AUDIO0 63 +#define CLK_MOUT_SCLK_HDMI_SPDIF 64 #define CLK_DIV_ACLK_FSYS_200 100 #define CLK_DIV_ACLK_IMEM_SSSX_266 101 @@ -337,8 +338,9 @@ #define CLK_SCLK_BUS_PLL 198 #define CLK_SCLK_BUS_PLL_APOLLO 199 #define CLK_SCLK_BUS_PLL_ATLAS 200 +#define CLK_SCLK_HDMI_SPDIF_DISP 201 -#define MIF_NR_CLK 201 +#define MIF_NR_CLK 202 /* CMU_PERIC */ #define CLK_PCLK_SPI2 1 @@ -514,4 +516,114 @@ #define G2D_NR_CLK 27 +/* CMU_DISP */ +#define CLK_FOUT_DISP_PLL 1 + +#define CLK_MOUT_DISP_PLL 2 +#define CLK_MOUT_SCLK_DSIM1_USER 3 +#define CLK_MOUT_SCLK_DSIM0_USER 4 +#define CLK_MOUT_SCLK_DSD_USER 5 +#define CLK_MOUT_SCLK_DECON_TV_ECLK_USER 6 +#define CLK_MOUT_SCLK_DECON_VCLK_USER 7 +#define CLK_MOUT_SCLK_DECON_ECLK_USER 8 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_USER 9 +#define CLK_MOUT_ACLK_DISP_333_USER 10 +#define CLK_MOUT_PHYCLK_MIPIDPHY1_BITCLKDIV8_USER 11 +#define CLK_MOUT_PHYCLK_MIPIDPHY1_RXCLKESC0_USER 12 +#define CLK_MOUT_PHYCLK_MIPIDPHY0_BITCLKDIV8_USER 13 +#define CLK_MOUT_PHYCLK_MIPIDPHY0_RXCLKESC0_USER 14 +#define CLK_MOUT_PHYCLK_HDMIPHY_TMDS_CLKO_USER 15 +#define CLK_MOUT_PHYCLK_HDMIPHY_PIXEL_CLKO_USER 16 +#define CLK_MOUT_SCLK_DSIM0 17 +#define CLK_MOUT_SCLK_DECON_TV_ECLK 18 +#define CLK_MOUT_SCLK_DECON_VCLK 19 +#define CLK_MOUT_SCLK_DECON_ECLK 20 +#define CLK_MOUT_SCLK_DSIM1_B_DISP 21 +#define CLK_MOUT_SCLK_DSIM1_A_DISP 22 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_C_DISP 23 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_B_DISP 24 +#define CLK_MOUT_SCLK_DECON_TV_VCLK_A_DISP 25 + +#define CLK_DIV_SCLK_DSIM1_DISP 30 +#define CLK_DIV_SCLK_DECON_TV_VCLK_DISP 31 +#define CLK_DIV_SCLK_DSIM0_DISP 32 +#define CLK_DIV_SCLK_DECON_TV_ECLK_DISP 33 +#define CLK_DIV_SCLK_DECON_VCLK_DISP 34 +#define CLK_DIV_SCLK_DECON_ECLK_DISP 35 +#define CLK_DIV_PCLK_DISP 36 + +#define CLK_ACLK_DECON_TV 40 +#define CLK_ACLK_DECON 41 +#define CLK_ACLK_SMMU_TV1X 42 +#define CLK_ACLK_SMMU_TV0X 43 +#define CLK_ACLK_SMMU_DECON1X 44 +#define CLK_ACLK_SMMU_DECON0X 45 +#define CLK_ACLK_BTS_DECON_TV_M3 46 +#define CLK_ACLK_BTS_DECON_TV_M2 47 +#define CLK_ACLK_BTS_DECON_TV_M1 48 +#define CLK_ACLK_BTS_DECON_TV_M0 49 +#define CLK_ACLK_BTS_DECON_NM4 50 +#define CLK_ACLK_BTS_DECON_NM3 51 +#define CLK_ACLK_BTS_DECON_NM2 52 +#define CLK_ACLK_BTS_DECON_NM1 53 +#define CLK_ACLK_BTS_DECON_NM0 54 +#define CLK_ACLK_AHB2APB_DISPSFR2P 55 +#define CLK_ACLK_AHB2APB_DISPSFR1P 56 +#define CLK_ACLK_AHB2APB_DISPSFR0P 57 +#define CLK_ACLK_AHB_DISPH 58 +#define CLK_ACLK_XIU_TV1X 59 +#define CLK_ACLK_XIU_TV0X 60 +#define CLK_ACLK_XIU_DECON1X 61 +#define CLK_ACLK_XIU_DECON0X 62 +#define CLK_ACLK_XIU_DISP1X 63 +#define CLK_ACLK_XIU_DISPNP_100 64 +#define CLK_ACLK_DISP1ND_333 65 +#define CLK_ACLK_DISP0ND_333 66 +#define CLK_PCLK_SMMU_TV1X 67 +#define CLK_PCLK_SMMU_TV0X 68 +#define CLK_PCLK_SMMU_DECON1X 69 +#define CLK_PCLK_SMMU_DECON0X 70 +#define CLK_PCLK_BTS_DECON_TV_M3 71 +#define CLK_PCLK_BTS_DECON_TV_M2 72 +#define CLK_PCLK_BTS_DECON_TV_M1 73 +#define CLK_PCLK_BTS_DECON_TV_M0 74 +#define CLK_PCLK_BTS_DECONM4 75 +#define CLK_PCLK_BTS_DECONM3 76 +#define CLK_PCLK_BTS_DECONM2 77 +#define CLK_PCLK_BTS_DECONM1 78 +#define CLK_PCLK_BTS_DECONM0 79 +#define CLK_PCLK_MIC1 80 +#define CLK_PCLK_PMU_DISP 81 +#define CLK_PCLK_SYSREG_DISP 82 +#define CLK_PCLK_HDMIPHY 83 +#define CLK_PCLK_HDMI 84 +#define CLK_PCLK_MIC0 85 +#define CLK_PCLK_DSIM1 86 +#define CLK_PCLK_DSIM0 87 +#define CLK_PCLK_DECON_TV 88 +#define CLK_PHYCLK_MIPIDPHY1_BITCLKDIV8 89 +#define CLK_PHYCLK_MIPIDPHY1_RXCLKESC0 90 +#define CLK_SCLK_RGB_TV_VCLK_TO_DSIM1 91 +#define CLK_SCLK_RGB_TV_VCLK_TO_MIC1 92 +#define CLK_SCLK_DSIM1 93 +#define CLK_SCLK_DECON_TV_VCLK 94 +#define CLK_PHYCLK_MIPIDPHY0_BITCLKDIV8 95 +#define CLK_PHYCLK_MIPIDPHY0_RXCLKESC0 96 +#define CLK_PHYCLK_HDMIPHY_TMDS_CLKO 97 +#define CLK_PHYCLK_HDMI_PIXEL 98 +#define CLK_SCLK_RGB_VCLK_TO_SMIES 99 +#define CLK_SCLK_FREQ_DET_DISP_PLL 100 +#define CLK_SCLK_RGB_VCLK_TO_DSIM0 101 +#define CLK_SCLK_RGB_VCLK_TO_MIC0 102 +#define CLK_SCLK_DSD 103 +#define CLK_SCLK_HDMI_SPDIF 104 +#define CLK_SCLK_DSIM0 105 +#define CLK_SCLK_DECON_TV_ECLK 106 +#define CLK_SCLK_DECON_VCLK 107 +#define CLK_SCLK_DECON_ECLK 108 +#define CLK_SCLK_RGB_VCLK 109 +#define CLK_SCLK_RGB_TV_VCLK 110 + +#define DISP_NR_CLK 111 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 2e997c035945784fb8c564305c0f0ddacc374fe4 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:03 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_AUD domain This patch adds the mux/divider/gate clocks for CMU_AUD domain which includes the clocks of Cortex-A5/Bus/Audio clocks. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 172 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 53 ++++++++++ 2 files changed, 225 insertions(+) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 3e6c3d595e96..ad0105aa0de6 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -2459,3 +2459,175 @@ static void __init exynos5433_cmu_disp_init(struct device_node *np) CLK_OF_DECLARE(exynos5433_cmu_disp, "samsung,exynos5433-cmu-disp", exynos5433_cmu_disp_init); + +/* + * Register offset definitions for CMU_AUD + */ +#define MUX_SEL_AUD0 0x0200 +#define MUX_SEL_AUD1 0x0204 +#define MUX_ENABLE_AUD0 0x0300 +#define MUX_ENABLE_AUD1 0x0304 +#define MUX_STAT_AUD0 0x0400 +#define DIV_AUD0 0x0600 +#define DIV_AUD1 0x0604 +#define DIV_STAT_AUD0 0x0700 +#define DIV_STAT_AUD1 0x0704 +#define ENABLE_ACLK_AUD 0x0800 +#define ENABLE_PCLK_AUD 0x0900 +#define ENABLE_SCLK_AUD0 0x0a00 +#define ENABLE_SCLK_AUD1 0x0a04 +#define ENABLE_IP_AUD0 0x0b00 +#define ENABLE_IP_AUD1 0x0b04 + +static unsigned long aud_clk_regs[] __initdata = { + MUX_SEL_AUD0, + MUX_SEL_AUD1, + MUX_ENABLE_AUD0, + MUX_ENABLE_AUD1, + MUX_STAT_AUD0, + DIV_AUD0, + DIV_AUD1, + DIV_STAT_AUD0, + DIV_STAT_AUD1, + ENABLE_ACLK_AUD, + ENABLE_PCLK_AUD, + ENABLE_SCLK_AUD0, + ENABLE_SCLK_AUD1, + ENABLE_IP_AUD0, + ENABLE_IP_AUD1, +}; + +/* list of all parent clock list */ +PNAME(mout_aud_pll_user_aud_p) = { "oscclk", "fout_aud_pll", }; +PNAME(mout_sclk_aud_pcm_p) = { "mout_aud_pll_user", "ioclk_audiocdclk0",}; + +static struct samsung_fixed_rate_clock aud_fixed_clks[] __initdata = { + FRATE(0, "ioclk_jtag_tclk", NULL, CLK_IS_ROOT, 33000000), + FRATE(0, "ioclk_slimbus_clk", NULL, CLK_IS_ROOT, 25000000), + FRATE(0, "ioclk_i2s_bclk", NULL, CLK_IS_ROOT, 50000000), +}; + +static struct samsung_mux_clock aud_mux_clks[] __initdata = { + /* MUX_SEL_AUD0 */ + MUX(CLK_MOUT_AUD_PLL_USER, "mout_aud_pll_user", + mout_aud_pll_user_aud_p, MUX_SEL_AUD0, 0, 1), + + /* MUX_SEL_AUD1 */ + MUX(CLK_MOUT_SCLK_AUD_PCM, "mout_sclk_aud_pcm", mout_sclk_aud_pcm_p, + MUX_SEL_AUD1, 8, 1), + MUX(CLK_MOUT_SCLK_AUD_I2S, "mout_sclk_aud_i2s", mout_sclk_aud_pcm_p, + MUX_SEL_AUD1, 0, 1), +}; + +static struct samsung_div_clock aud_div_clks[] __initdata = { + /* DIV_AUD0 */ + DIV(CLK_DIV_ATCLK_AUD, "div_atclk_aud", "div_aud_ca5", DIV_AUD0, + 12, 4), + DIV(CLK_DIV_PCLK_DBG_AUD, "div_pclk_dbg_aud", "div_aud_ca5", DIV_AUD0, + 8, 4), + DIV(CLK_DIV_ACLK_AUD, "div_aclk_aud", "div_aud_ca5", DIV_AUD0, + 4, 4), + DIV(CLK_DIV_AUD_CA5, "div_aud_ca5", "mout_aud_pll_user", DIV_AUD0, + 0, 4), + + /* DIV_AUD1 */ + DIV(CLK_DIV_SCLK_AUD_SLIMBUS, "div_sclk_aud_slimbus", + "mout_aud_pll_user", DIV_AUD1, 16, 5), + DIV(CLK_DIV_SCLK_AUD_UART, "div_sclk_aud_uart", "mout_aud_pll_user", + DIV_AUD1, 12, 4), + DIV(CLK_DIV_SCLK_AUD_PCM, "div_sclk_aud_pcm", "mout_sclk_aud_pcm", + DIV_AUD1, 4, 8), + DIV(CLK_DIV_SCLK_AUD_I2S, "div_sclk_aud_i2s", "mout_sclk_aud_i2s", + DIV_AUD1, 0, 4), +}; + +static struct samsung_gate_clock aud_gate_clks[] __initdata = { + /* ENABLE_ACLK_AUD */ + GATE(CLK_ACLK_INTR_CTRL, "aclk_intr_ctrl", "div_aclk_aud", + ENABLE_ACLK_AUD, 12, 0, 0), + GATE(CLK_ACLK_SMMU_LPASSX, "aclk_smmu_lpassx", "div_aclk_aud", + ENABLE_ACLK_AUD, 7, 0, 0), + GATE(CLK_ACLK_XIU_LPASSX, "aclk_xiu_lpassx", "div_aclk_aud", + ENABLE_ACLK_AUD, 0, 4, 0), + GATE(CLK_ACLK_AUDNP_133, "aclk_audnp_133", "div_aclk_aud", + ENABLE_ACLK_AUD, 0, 3, 0), + GATE(CLK_ACLK_AUDND_133, "aclk_audnd_133", "div_aclk_aud", + ENABLE_ACLK_AUD, 0, 2, 0), + GATE(CLK_ACLK_SRAMC, "aclk_sramc", "div_aclk_aud", ENABLE_ACLK_AUD, + 0, 1, 0), + GATE(CLK_ACLK_DMAC, "aclk_dmac", "div_aclk_aud", ENABLE_ACLK_AUD, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_AUD */ + GATE(CLK_PCLK_WDT1, "pclk_wdt1", "div_aclk_aud", ENABLE_PCLK_AUD, + 13, 0, 0), + GATE(CLK_PCLK_WDT0, "pclk_wdt0", "div_aclk_aud", ENABLE_PCLK_AUD, + 12, 0, 0), + GATE(CLK_PCLK_SFR1, "pclk_sfr1", "div_aclk_aud", ENABLE_PCLK_AUD, + 11, 0, 0), + GATE(CLK_PCLK_SMMU_LPASSX, "pclk_smmu_lpassx", "div_aclk_aud", + ENABLE_PCLK_AUD, 10, 0, 0), + GATE(CLK_PCLK_GPIO_AUD, "pclk_gpio_aud", "div_aclk_aud", + ENABLE_PCLK_AUD, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_AUD, "pclk_pmu_aud", "div_aclk_aud", + ENABLE_PCLK_AUD, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_AUD, "pclk_sysreg_aud", "div_aclk_aud", + ENABLE_PCLK_AUD, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_AUD_SLIMBUS, "pclk_aud_slimbus", "div_aclk_aud", + ENABLE_PCLK_AUD, 6, 0, 0), + GATE(CLK_PCLK_AUD_UART, "pclk_aud_uart", "div_aclk_aud", + ENABLE_PCLK_AUD, 5, 0, 0), + GATE(CLK_PCLK_AUD_PCM, "pclk_aud_pcm", "div_aclk_aud", + ENABLE_PCLK_AUD, 4, 0, 0), + GATE(CLK_PCLK_AUD_I2S, "pclk_aud_i2s", "div_aclk_aud", + ENABLE_PCLK_AUD, 3, 0, 0), + GATE(CLK_PCLK_TIMER, "pclk_timer", "div_aclk_aud", ENABLE_PCLK_AUD, + 2, 0, 0), + GATE(CLK_PCLK_SFR0_CTRL, "pclk_sfr0_ctrl", "div_aclk_aud", + ENABLE_PCLK_AUD, 0, 0, 0), + + /* ENABLE_SCLK_AUD0 */ + GATE(CLK_ATCLK_AUD, "atclk_aud", "div_atclk_aud", ENABLE_SCLK_AUD0, + 2, 0, 0), + GATE(CLK_PCLK_DBG_AUD, "pclk_dbg_aud", "div_pclk_dbg_aud", + ENABLE_SCLK_AUD0, 1, 0, 0), + GATE(CLK_SCLK_AUD_CA5, "sclk_aud_ca5", "div_aud_ca5", ENABLE_SCLK_AUD0, + 0, 0, 0), + + /* ENABLE_SCLK_AUD1 */ + GATE(CLK_SCLK_JTAG_TCK, "sclk_jtag_tck", "ioclk_jtag_tclk", + ENABLE_SCLK_AUD1, 6, 0, 0), + GATE(CLK_SCLK_SLIMBUS_CLKIN, "sclk_slimbus_clkin", "ioclk_slimbus_clk", + ENABLE_SCLK_AUD1, 5, 0, 0), + GATE(CLK_SCLK_AUD_SLIMBUS, "sclk_aud_slimbus", "div_sclk_aud_slimbus", + ENABLE_SCLK_AUD1, 4, 0, 0), + GATE(CLK_SCLK_AUD_UART, "sclk_aud_uart", "div_sclk_aud_uart", + ENABLE_SCLK_AUD1, 3, 0, 0), + GATE(CLK_SCLK_AUD_PCM, "sclk_aud_pcm", "div_sclk_aud_pcm", + ENABLE_SCLK_AUD1, 2, 0, 0), + GATE(CLK_SCLK_I2S_BCLK, "sclk_i2s_bclk", "ioclk_i2s_bclk", + ENABLE_SCLK_AUD1, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_AUD_I2S, "sclk_aud_i2s", "div_sclk_aud_i2s", + ENABLE_SCLK_AUD1, 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info aud_cmu_info __initdata = { + .mux_clks = aud_mux_clks, + .nr_mux_clks = ARRAY_SIZE(aud_mux_clks), + .div_clks = aud_div_clks, + .nr_div_clks = ARRAY_SIZE(aud_div_clks), + .gate_clks = aud_gate_clks, + .nr_gate_clks = ARRAY_SIZE(aud_gate_clks), + .fixed_clks = aud_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(aud_fixed_clks), + .nr_clk_ids = AUD_NR_CLK, + .clk_regs = aud_clk_regs, + .nr_clk_regs = ARRAY_SIZE(aud_clk_regs), +}; + +static void __init exynos5433_cmu_aud_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &aud_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_aud, "samsung,exynos5433-cmu-aud", + exynos5433_cmu_aud_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index fe0650fad766..4d150e244057 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -626,4 +626,57 @@ #define DISP_NR_CLK 111 +/* CMU_AUD */ +#define CLK_MOUT_AUD_PLL_USER 1 +#define CLK_MOUT_SCLK_AUD_PCM 2 +#define CLK_MOUT_SCLK_AUD_I2S 3 + +#define CLK_DIV_ATCLK_AUD 4 +#define CLK_DIV_PCLK_DBG_AUD 5 +#define CLK_DIV_ACLK_AUD 6 +#define CLK_DIV_AUD_CA5 7 +#define CLK_DIV_SCLK_AUD_SLIMBUS 8 +#define CLK_DIV_SCLK_AUD_UART 9 +#define CLK_DIV_SCLK_AUD_PCM 10 +#define CLK_DIV_SCLK_AUD_I2S 11 + +#define CLK_ACLK_INTR_CTRL 12 +#define CLK_ACLK_AXIDS2_LPASSP 13 +#define CLK_ACLK_AXIDS1_LPASSP 14 +#define CLK_ACLK_AXI2APB1_LPASSP 15 +#define CLK_ACLK_AXI2APH_LPASSP 16 +#define CLK_ACLK_SMMU_LPASSX 17 +#define CLK_ACLK_AXIDS0_LPASSP 18 +#define CLK_ACLK_AXI2APB0_LPASSP 19 +#define CLK_ACLK_XIU_LPASSX 20 +#define CLK_ACLK_AUDNP_133 21 +#define CLK_ACLK_AUDND_133 22 +#define CLK_ACLK_SRAMC 23 +#define CLK_ACLK_DMAC 24 +#define CLK_PCLK_WDT1 25 +#define CLK_PCLK_WDT0 26 +#define CLK_PCLK_SFR1 27 +#define CLK_PCLK_SMMU_LPASSX 28 +#define CLK_PCLK_GPIO_AUD 29 +#define CLK_PCLK_PMU_AUD 30 +#define CLK_PCLK_SYSREG_AUD 31 +#define CLK_PCLK_AUD_SLIMBUS 32 +#define CLK_PCLK_AUD_UART 33 +#define CLK_PCLK_AUD_PCM 34 +#define CLK_PCLK_AUD_I2S 35 +#define CLK_PCLK_TIMER 36 +#define CLK_PCLK_SFR0_CTRL 37 +#define CLK_ATCLK_AUD 38 +#define CLK_PCLK_DBG_AUD 39 +#define CLK_SCLK_AUD_CA5 40 +#define CLK_SCLK_JTAG_TCK 41 +#define CLK_SCLK_SLIMBUS_CLKIN 42 +#define CLK_SCLK_AUD_SLIMBUS 43 +#define CLK_SCLK_AUD_UART 44 +#define CLK_SCLK_AUD_PCM 45 +#define CLK_SCLK_I2S_BCLK 46 +#define CLK_SCLK_AUD_I2S 47 + +#define AUD_NR_CLK 48 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 5785d6e61f27f7af4d239c1647d5a22e0dbff19b Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:04 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_BUS{0|1|2} domains This patch adds the mux/divider/gate clocks for CMU_BUS{0|1|2} domains which contain global data buses clocked at up the 400MHz. These blocks transfer data between DRAM and various sub-blocks. These clock domains also contain global peripheral buses clocked at 67/111/200/222/266/333/400 MHz and used for register accesses. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 187 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 27 ++++- 2 files changed, 213 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index ad0105aa0de6..7c4e91a440e5 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -438,6 +438,14 @@ static struct samsung_div_clock top_div_clks[] __initdata = { DIV(CLK_DIV_ACLK_PERIS_66_A, "div_aclk_peris_66_a", "mout_bus_pll_user", DIV_TOP3, 0, 3), + /* DIV_TOP4 */ + DIV(CLK_DIV_ACLK_G3D_400, "div_aclk_g3d_400", "mout_bus_pll_user", + DIV_TOP4, 8, 3), + DIV(CLK_DIV_ACLK_BUS0_400, "div_aclk_bus0_400", "mout_aclk_bus0_400", + DIV_TOP4, 4, 3), + DIV(CLK_DIV_ACLK_BUS1_400, "div_aclk_bus1_400", "mout_bus_pll_user", + DIV_TOP4, 0, 3), + /* DIV_TOP_FSYS0 */ DIV(CLK_DIV_SCLK_MMC1_B, "div_sclk_mmc1_b", "div_sclk_mmc1_a", DIV_TOP_FSYS0, 16, 8), @@ -501,6 +509,23 @@ static struct samsung_div_clock top_div_clks[] __initdata = { static struct samsung_gate_clock top_gate_clks[] __initdata = { /* ENABLE_ACLK_TOP */ + GATE(CLK_ACLK_G3D_400, "aclk_g3d_400", "div_aclk_g3d_400", + ENABLE_ACLK_TOP, 30, 0, 0), + GATE(CLK_ACLK_IMEM_SSX_266, "aclk_imem_ssx_266", + "div_aclk_imem_sssx_266", ENABLE_ACLK_TOP, + 29, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUS0_400, "aclk_bus0_400", "div_aclk_bus0_400", + ENABLE_ACLK_TOP, 26, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_ACLK_BUS1_400, "aclk_bus1_400", "div_aclk_bus1_400", + ENABLE_ACLK_TOP, 25, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_ACLK_IMEM_200, "aclk_imem_200", "div_aclk_imem_266", + ENABLE_ACLK_TOP, 24, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), + GATE(CLK_ACLK_IMEM_266, "aclk_imem_266", "div_aclk_imem_200", + ENABLE_ACLK_TOP, 23, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), GATE(CLK_ACLK_PERIC_66, "aclk_peric_66", "div_aclk_peric_66_b", ENABLE_ACLK_TOP, 22, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -2631,3 +2656,165 @@ static void __init exynos5433_cmu_aud_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_aud, "samsung,exynos5433-cmu-aud", exynos5433_cmu_aud_init); + + +/* + * Register offset definitions for CMU_BUS{0|1|2} + */ +#define DIV_BUS 0x0600 +#define DIV_STAT_BUS 0x0700 +#define ENABLE_ACLK_BUS 0x0800 +#define ENABLE_PCLK_BUS 0x0900 +#define ENABLE_IP_BUS0 0x0b00 +#define ENABLE_IP_BUS1 0x0b04 + +#define MUX_SEL_BUS2 0x0200 /* Only for CMU_BUS2 */ +#define MUX_ENABLE_BUS2 0x0300 /* Only for CMU_BUS2 */ +#define MUX_STAT_BUS2 0x0400 /* Only for CMU_BUS2 */ + +/* list of all parent clock list */ +PNAME(mout_aclk_bus2_400_p) = { "oscclk", "aclk_bus2_400", }; + +#define CMU_BUS_COMMON_CLK_REGS \ + DIV_BUS, \ + DIV_STAT_BUS, \ + ENABLE_ACLK_BUS, \ + ENABLE_PCLK_BUS, \ + ENABLE_IP_BUS0, \ + ENABLE_IP_BUS1 + +static unsigned long bus01_clk_regs[] __initdata = { + CMU_BUS_COMMON_CLK_REGS, +}; + +static unsigned long bus2_clk_regs[] __initdata = { + MUX_SEL_BUS2, + MUX_ENABLE_BUS2, + MUX_STAT_BUS2, + CMU_BUS_COMMON_CLK_REGS, +}; + +static struct samsung_div_clock bus0_div_clks[] __initdata = { + /* DIV_BUS0 */ + DIV(CLK_DIV_PCLK_BUS_133, "div_pclk_bus0_133", "aclk_bus0_400", + DIV_BUS, 0, 3), +}; + +/* CMU_BUS0 clocks */ +static struct samsung_gate_clock bus0_gate_clks[] __initdata = { + /* ENABLE_ACLK_BUS0 */ + GATE(CLK_ACLK_AHB2APB_BUSP, "aclk_ahb2apb_bus0p", "div_pclk_bus0_133", + ENABLE_ACLK_BUS, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUSNP_133, "aclk_bus0np_133", "div_pclk_bus0_133", + ENABLE_ACLK_BUS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUSND_400, "aclk_bus0nd_400", "aclk_bus0_400", + ENABLE_ACLK_BUS, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_BUS0 */ + GATE(CLK_PCLK_BUSSRVND_133, "pclk_bus0srvnd_133", "div_pclk_bus0_133", + ENABLE_PCLK_BUS, 2, 0, 0), + GATE(CLK_PCLK_PMU_BUS, "pclk_pmu_bus0", "div_pclk_bus0_133", + ENABLE_PCLK_BUS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_BUS, "pclk_sysreg_bus0", "div_pclk_bus0_133", + ENABLE_PCLK_BUS, 0, CLK_IGNORE_UNUSED, 0), +}; + +/* CMU_BUS1 clocks */ +static struct samsung_div_clock bus1_div_clks[] __initdata = { + /* DIV_BUS1 */ + DIV(CLK_DIV_PCLK_BUS_133, "div_pclk_bus1_133", "aclk_bus1_400", + DIV_BUS, 0, 3), +}; + +static struct samsung_gate_clock bus1_gate_clks[] __initdata = { + /* ENABLE_ACLK_BUS1 */ + GATE(CLK_ACLK_AHB2APB_BUSP, "aclk_ahb2apb_bus1p", "div_pclk_bus1_133", + ENABLE_ACLK_BUS, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUSNP_133, "aclk_bus1np_133", "div_pclk_bus1_133", + ENABLE_ACLK_BUS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUSND_400, "aclk_bus1nd_400", "aclk_bus1_400", + ENABLE_ACLK_BUS, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_BUS1 */ + GATE(CLK_PCLK_BUSSRVND_133, "pclk_bus1srvnd_133", "div_pclk_bus1_133", + ENABLE_PCLK_BUS, 2, 0, 0), + GATE(CLK_PCLK_PMU_BUS, "pclk_pmu_bus1", "div_pclk_bus1_133", + ENABLE_PCLK_BUS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_BUS, "pclk_sysreg_bus1", "div_pclk_bus1_133", + ENABLE_PCLK_BUS, 0, CLK_IGNORE_UNUSED, 0), +}; + +/* CMU_BUS2 clocks */ +static struct samsung_mux_clock bus2_mux_clks[] __initdata = { + /* MUX_SEL_BUS2 */ + MUX(CLK_MOUT_ACLK_BUS2_400_USER, "mout_aclk_bus2_400_user", + mout_aclk_bus2_400_p, MUX_SEL_BUS2, 0, 1), +}; + +static struct samsung_div_clock bus2_div_clks[] __initdata = { + /* DIV_BUS2 */ + DIV(CLK_DIV_PCLK_BUS_133, "div_pclk_bus2_133", + "mout_aclk_bus2_400_user", DIV_BUS, 0, 3), +}; + +static struct samsung_gate_clock bus2_gate_clks[] __initdata = { + /* ENABLE_ACLK_BUS2 */ + GATE(CLK_ACLK_AHB2APB_BUSP, "aclk_ahb2apb_bus2p", "div_pclk_bus2_133", + ENABLE_ACLK_BUS, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUSNP_133, "aclk_bus2np_133", "div_pclk_bus2_133", + ENABLE_ACLK_BUS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUS2BEND_400, "aclk_bus2bend_400", + "mout_aclk_bus2_400_user", ENABLE_ACLK_BUS, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BUS2RTND_400, "aclk_bus2rtnd_400", + "mout_aclk_bus2_400_user", ENABLE_ACLK_BUS, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_BUS2 */ + GATE(CLK_PCLK_BUSSRVND_133, "pclk_bus2srvnd_133", "div_pclk_bus2_133", + ENABLE_PCLK_BUS, 2, 0, 0), + GATE(CLK_PCLK_PMU_BUS, "pclk_pmu_bus2", "div_pclk_bus2_133", + ENABLE_PCLK_BUS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_BUS, "pclk_sysreg_bus2", "div_pclk_bus2_133", + ENABLE_PCLK_BUS, 0, CLK_IGNORE_UNUSED, 0), +}; + +#define CMU_BUS_INFO_CLKS(id) \ + .div_clks = bus##id##_div_clks, \ + .nr_div_clks = ARRAY_SIZE(bus##id##_div_clks), \ + .gate_clks = bus##id##_gate_clks, \ + .nr_gate_clks = ARRAY_SIZE(bus##id##_gate_clks), \ + .nr_clk_ids = BUSx_NR_CLK + +static struct samsung_cmu_info bus0_cmu_info __initdata = { + CMU_BUS_INFO_CLKS(0), + .clk_regs = bus01_clk_regs, + .nr_clk_regs = ARRAY_SIZE(bus01_clk_regs), +}; + +static struct samsung_cmu_info bus1_cmu_info __initdata = { + CMU_BUS_INFO_CLKS(1), + .clk_regs = bus01_clk_regs, + .nr_clk_regs = ARRAY_SIZE(bus01_clk_regs), +}; + +static struct samsung_cmu_info bus2_cmu_info __initdata = { + CMU_BUS_INFO_CLKS(2), + .mux_clks = bus2_mux_clks, + .nr_mux_clks = ARRAY_SIZE(bus2_mux_clks), + .clk_regs = bus2_clk_regs, + .nr_clk_regs = ARRAY_SIZE(bus2_clk_regs), +}; + +#define exynos5433_cmu_bus_init(id) \ +static void __init exynos5433_cmu_bus##id##_init(struct device_node *np)\ +{ \ + samsung_cmu_register_one(np, &bus##id##_cmu_info); \ +} \ +CLK_OF_DECLARE(exynos5433_cmu_bus##id, \ + "samsung,exynos5433-cmu-bus"#id, \ + exynos5433_cmu_bus##id##_init) + +exynos5433_cmu_bus_init(0); +exynos5433_cmu_bus_init(1); +exynos5433_cmu_bus_init(2); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 4d150e244057..8d388e700a80 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -107,6 +107,9 @@ #define CLK_DIV_ACLK_MFC_400 134 #define CLK_DIV_ACLK_G2D_266 135 #define CLK_DIV_ACLK_G2D_400 136 +#define CLK_DIV_ACLK_G3D_400 137 +#define CLK_DIV_ACLK_BUS0_400 138 +#define CLK_DIV_ACLK_BUS1_400 139 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -130,8 +133,14 @@ #define CLK_SCLK_AUDIO0 219 #define CLK_ACLK_G2D_266 220 #define CLK_ACLK_G2D_400 221 +#define CLK_ACLK_G3D_400 222 +#define CLK_ACLK_IMEM_SSX_266 223 +#define CLK_ACLK_BUS0_400 224 +#define CLK_ACLK_BUS1_400 225 +#define CLK_ACLK_IMEM_200 226 +#define CLK_ACLK_IMEM_266 227 -#define TOP_NR_CLK 222 +#define TOP_NR_CLK 228 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -679,4 +688,20 @@ #define AUD_NR_CLK 48 +/* CMU_BUS{0|1|2} */ +#define CLK_DIV_PCLK_BUS_133 1 + +#define CLK_ACLK_AHB2APB_BUSP 2 +#define CLK_ACLK_BUSNP_133 3 +#define CLK_ACLK_BUSND_400 4 +#define CLK_PCLK_BUSSRVND_133 5 +#define CLK_PCLK_PMU_BUS 6 +#define CLK_PCLK_SYSREG_BUS 7 + +#define CLK_MOUT_ACLK_BUS2_400_USER 8 /* Only CMU_BUS2 */ +#define CLK_ACLK_BUS2BEND_400 9 /* Only CMU_BUS2 */ +#define CLK_ACLK_BUS2RTND_400 10 /* Only CMU_BUS2 */ + +#define BUSx_NR_CLK 11 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 4b8013554b0454984e71bc20bc31966886079e15 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:05 +0900 Subject: clk: samsung: exynos5433: Add missing clocks for CMU_FSYS domain This patch adds the mux/divider/gate clocks for CMU_FSYS domain which contains the clocks of USB/UFS/SDMMC/TSI/PDMA IPs. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 302 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 96 ++++++++++- 2 files changed, 395 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 7c4e91a440e5..1cdc47e05ac1 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -462,6 +462,16 @@ static struct samsung_div_clock top_div_clks[] __initdata = { DIV(CLK_DIV_SCLK_MMC2_A, "div_sclk_mmc2_a", "mout_sclk_mmc2_b", DIV_TOP_FSYS1, 0, 4), + /* DIV_TOP_FSYS2 */ + DIV(CLK_DIV_SCLK_PCIE_100, "div_sclk_pcie_100", "mout_sclk_pcie_100", + DIV_TOP_FSYS2, 12, 3), + DIV(CLK_DIV_SCLK_USBHOST30, "div_sclk_usbhost30", + "mout_sclk_usbhost30", DIV_TOP_FSYS2, 8, 4), + DIV(CLK_DIV_SCLK_UFSUNIPRO, "div_sclk_ufsunipro", + "mout_sclk_ufsunipro", DIV_TOP_FSYS2, 4, 4), + DIV(CLK_DIV_SCLK_USBDRD30, "div_sclk_usbdrd30", "mout_sclk_usbdrd30", + DIV_TOP_FSYS2, 0, 4), + /* DIV_TOP_PERIC0 */ DIV(CLK_DIV_SCLK_SPI1_B, "div_sclk_spi1_b", "div_sclk_spi1_a", DIV_TOP_PERIC0, 16, 8), @@ -543,12 +553,23 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), /* ENABLE_SCLK_TOP_FSYS */ + GATE(CLK_SCLK_PCIE_100_FSYS, "sclk_pcie_100_fsys", "div_sclk_pcie_100", + ENABLE_SCLK_TOP_FSYS, 7, 0, 0), GATE(CLK_SCLK_MMC2_FSYS, "sclk_mmc2_fsys", "div_sclk_mmc2_b", ENABLE_SCLK_TOP_FSYS, 6, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_MMC1_FSYS, "sclk_mmc1_fsys", "div_sclk_mmc1_b", ENABLE_SCLK_TOP_FSYS, 5, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_MMC0_FSYS, "sclk_mmc0_fsys", "div_sclk_mmc0_b", ENABLE_SCLK_TOP_FSYS, 4, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_UFSUNIPRO_FSYS, "sclk_ufsunipro_fsys", + "div_sclk_ufsunipro", ENABLE_SCLK_TOP_FSYS, + 3, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_USBHOST30_FSYS, "sclk_usbhost30_fsys", + "div_sclk_usbhost30", ENABLE_SCLK_TOP_FSYS, + 1, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_USBDRD30_FSYS, "sclk_usbdrd30_fsys", + "div_sclk_usbdrd30", ENABLE_SCLK_TOP_FSYS, + 0, CLK_SET_RATE_PARENT, 0), /* ENABLE_SCLK_TOP_PERIC */ GATE(CLK_SCLK_SPI4_PERIC, "sclk_spi4_peric", "div_sclk_spi4_b", @@ -1832,10 +1853,45 @@ CLK_OF_DECLARE(exynos5433_cmu_peris, "samsung,exynos5433-cmu-peris", #define ENABLE_IP_FSYS1 0x0b04 /* list of all parent clock list */ +PNAME(mout_sclk_ufs_mphy_user_p) = { "oscclk", "sclk_ufs_mphy", }; PNAME(mout_aclk_fsys_200_user_p) = { "oscclk", "div_aclk_fsys_200", }; +PNAME(mout_sclk_pcie_100_user_p) = { "oscclk", "sclk_pcie_100_fsys",}; +PNAME(mout_sclk_ufsunipro_user_p) = { "oscclk", "sclk_ufsunipro_fsys",}; PNAME(mout_sclk_mmc2_user_p) = { "oscclk", "sclk_mmc2_fsys", }; PNAME(mout_sclk_mmc1_user_p) = { "oscclk", "sclk_mmc1_fsys", }; PNAME(mout_sclk_mmc0_user_p) = { "oscclk", "sclk_mmc0_fsys", }; +PNAME(mout_sclk_usbhost30_user_p) = { "oscclk", "sclk_usbhost30_fsys",}; +PNAME(mout_sclk_usbdrd30_user_p) = { "oscclk", "sclk_usbdrd30_fsys", }; + +PNAME(mout_phyclk_usbhost30_uhost30_pipe_pclk_user_p) + = { "oscclk", "phyclk_usbhost30_uhost30_pipe_pclk_phy", }; +PNAME(mout_phyclk_usbhost30_uhost30_phyclock_user_p) + = { "oscclk", "phyclk_usbhost30_uhost30_phyclock_phy", }; +PNAME(mout_phyclk_usbhost20_phy_hsic1_p) + = { "oscclk", "phyclk_usbhost20_phy_hsic1_phy", }; +PNAME(mout_phyclk_usbhost20_phy_clk48mohci_user_p) + = { "oscclk", "phyclk_usbhost20_phy_clk48mohci_phy", }; +PNAME(mout_phyclk_usbhost20_phy_phyclock_user_p) + = { "oscclk", "phyclk_usbhost20_phy_phyclock_phy", }; +PNAME(mout_phyclk_usbhost20_phy_freeclk_user_p) + = { "oscclk", "phyclk_usbhost20_phy_freeclk_phy", }; +PNAME(mout_phyclk_usbdrd30_udrd30_pipe_pclk_p) + = { "oscclk", "phyclk_usbdrd30_udrd30_pipe_pclk_phy", }; +PNAME(mout_phyclk_usbdrd30_udrd30_phyclock_user_p) + = { "oscclk", "phyclk_usbdrd30_udrd30_phyclock_phy", }; +PNAME(mout_phyclk_ufs_rx1_symbol_user_p) + = { "oscclk", "phyclk_ufs_rx1_symbol_phy", }; +PNAME(mout_phyclk_ufs_rx0_symbol_user_p) + = { "oscclk", "phyclk_ufs_rx0_symbol_phy", }; +PNAME(mout_phyclk_ufs_tx1_symbol_user_p) + = { "oscclk", "phyclk_ufs_tx1_symbol_phy", }; +PNAME(mout_phyclk_ufs_tx0_symbol_user_p) + = { "oscclk", "phyclk_ufs_tx0_symbol_phy", }; +PNAME(mout_phyclk_lli_mphy_to_ufs_user_p) + = { "oscclk", "phyclk_lli_mphy_to_ufs_phy", }; +PNAME(mout_sclk_mphy_p) + = { "mout_sclk_ufs_mphy_user", + "mout_phyclk_lli_mphy_to_ufs_user", }; static unsigned long fsys_clk_regs[] __initdata = { MUX_SEL_FSYS0, @@ -1863,18 +1919,130 @@ static unsigned long fsys_clk_regs[] __initdata = { ENABLE_IP_FSYS1, }; +static struct samsung_fixed_rate_clock fsys_fixed_clks[] __initdata = { + /* PHY clocks from USBDRD30_PHY */ + FRATE(CLK_PHYCLK_USBDRD30_UDRD30_PHYCLOCK_PHY, + "phyclk_usbdrd30_udrd30_phyclock_phy", NULL, + CLK_IS_ROOT, 60000000), + FRATE(CLK_PHYCLK_USBDRD30_UDRD30_PIPE_PCLK_PHY, + "phyclk_usbdrd30_udrd30_pipe_pclk_phy", NULL, + CLK_IS_ROOT, 125000000), + /* PHY clocks from USBHOST30_PHY */ + FRATE(CLK_PHYCLK_USBHOST30_UHOST30_PHYCLOCK_PHY, + "phyclk_usbhost30_uhost30_phyclock_phy", NULL, + CLK_IS_ROOT, 60000000), + FRATE(CLK_PHYCLK_USBHOST30_UHOST30_PIPE_PCLK_PHY, + "phyclk_usbhost30_uhost30_pipe_pclk_phy", NULL, + CLK_IS_ROOT, 125000000), + /* PHY clocks from USBHOST20_PHY */ + FRATE(CLK_PHYCLK_USBHOST20_PHY_FREECLK_PHY, + "phyclk_usbhost20_phy_freeclk_phy", NULL, CLK_IS_ROOT, + 60000000), + FRATE(CLK_PHYCLK_USBHOST20_PHY_PHYCLOCK_PHY, + "phyclk_usbhost20_phy_phyclock_phy", NULL, CLK_IS_ROOT, + 60000000), + FRATE(CLK_PHYCLK_USBHOST20_PHY_CLK48MOHCI_PHY, + "phyclk_usbhost20_phy_clk48mohci_phy", NULL, + CLK_IS_ROOT, 48000000), + FRATE(CLK_PHYCLK_USBHOST20_PHY_HSIC1_PHY, + "phyclk_usbhost20_phy_hsic1_phy", NULL, CLK_IS_ROOT, + 60000000), + /* PHY clocks from UFS_PHY */ + FRATE(CLK_PHYCLK_UFS_TX0_SYMBOL_PHY, "phyclk_ufs_tx0_symbol_phy", + NULL, CLK_IS_ROOT, 300000000), + FRATE(CLK_PHYCLK_UFS_RX0_SYMBOL_PHY, "phyclk_ufs_rx0_symbol_phy", + NULL, CLK_IS_ROOT, 300000000), + FRATE(CLK_PHYCLK_UFS_TX1_SYMBOL_PHY, "phyclk_ufs_tx1_symbol_phy", + NULL, CLK_IS_ROOT, 300000000), + FRATE(CLK_PHYCLK_UFS_RX1_SYMBOL_PHY, "phyclk_ufs_rx1_symbol_phy", + NULL, CLK_IS_ROOT, 300000000), + /* PHY clocks from LLI_PHY */ + FRATE(CLK_PHYCLK_LLI_MPHY_TO_UFS_PHY, "phyclk_lli_mphy_to_ufs_phy", + NULL, CLK_IS_ROOT, 26000000), +}; + static struct samsung_mux_clock fsys_mux_clks[] __initdata = { /* MUX_SEL_FSYS0 */ + MUX(CLK_MOUT_SCLK_UFS_MPHY_USER, "mout_sclk_ufs_mphy_user", + mout_sclk_ufs_mphy_user_p, MUX_SEL_FSYS0, 4, 1), MUX(CLK_MOUT_ACLK_FSYS_200_USER, "mout_aclk_fsys_200_user", mout_aclk_fsys_200_user_p, MUX_SEL_FSYS0, 0, 1), /* MUX_SEL_FSYS1 */ + MUX(CLK_MOUT_SCLK_PCIE_100_USER, "mout_sclk_pcie_100_user", + mout_sclk_pcie_100_user_p, MUX_SEL_FSYS1, 28, 1), + MUX(CLK_MOUT_SCLK_UFSUNIPRO_USER, "mout_sclk_ufsunipro_user", + mout_sclk_ufsunipro_user_p, MUX_SEL_FSYS1, 24, 1), MUX(CLK_MOUT_SCLK_MMC2_USER, "mout_sclk_mmc2_user", mout_sclk_mmc2_user_p, MUX_SEL_FSYS1, 20, 1), MUX(CLK_MOUT_SCLK_MMC1_USER, "mout_sclk_mmc1_user", mout_sclk_mmc1_user_p, MUX_SEL_FSYS1, 16, 1), MUX(CLK_MOUT_SCLK_MMC0_USER, "mout_sclk_mmc0_user", mout_sclk_mmc0_user_p, MUX_SEL_FSYS1, 12, 1), + MUX(CLK_MOUT_SCLK_USBHOST30_USER, "mout_sclk_usbhost30_user", + mout_sclk_usbhost30_user_p, MUX_SEL_FSYS1, 4, 1), + MUX(CLK_MOUT_SCLK_USBDRD30_USER, "mout_sclk_usbdrd30_user", + mout_sclk_usbdrd30_user_p, MUX_SEL_FSYS1, 0, 1), + + /* MUX_SEL_FSYS2 */ + MUX(CLK_MOUT_PHYCLK_USBHOST30_UHOST30_PIPE_PCLK_USER, + "mout_phyclk_usbhost30_uhost30_pipe_pclk_user", + mout_phyclk_usbhost30_uhost30_pipe_pclk_user_p, + MUX_SEL_FSYS2, 28, 1), + MUX(CLK_MOUT_PHYCLK_USBHOST30_UHOST30_PHYCLOCK_USER, + "mout_phyclk_usbhost30_uhost30_phyclock_user", + mout_phyclk_usbhost30_uhost30_phyclock_user_p, + MUX_SEL_FSYS2, 24, 1), + MUX(CLK_MOUT_PHYCLK_USBHOST20_PHY_HSIC1_USER, + "mout_phyclk_usbhost20_phy_hsic1", + mout_phyclk_usbhost20_phy_hsic1_p, + MUX_SEL_FSYS2, 20, 1), + MUX(CLK_MOUT_PHYCLK_USBHOST20_PHY_CLK48MOHCI_USER, + "mout_phyclk_usbhost20_phy_clk48mohci_user", + mout_phyclk_usbhost20_phy_clk48mohci_user_p, + MUX_SEL_FSYS2, 16, 1), + MUX(CLK_MOUT_PHYCLK_USBHOST20_PHY_PHYCLOCK_USER, + "mout_phyclk_usbhost20_phy_phyclock_user", + mout_phyclk_usbhost20_phy_phyclock_user_p, + MUX_SEL_FSYS2, 12, 1), + MUX(CLK_MOUT_PHYCLK_USBHOST20_PHY_PHY_FREECLK_USER, + "mout_phyclk_usbhost20_phy_freeclk_user", + mout_phyclk_usbhost20_phy_freeclk_user_p, + MUX_SEL_FSYS2, 8, 1), + MUX(CLK_MOUT_PHYCLK_USBDRD30_UDRD30_PIPE_PCLK_USER, + "mout_phyclk_usbdrd30_udrd30_pipe_pclk_user", + mout_phyclk_usbdrd30_udrd30_pipe_pclk_p, + MUX_SEL_FSYS2, 4, 1), + MUX(CLK_MOUT_PHYCLK_USBDRD30_UDRD30_PHYCLOCK_USER, + "mout_phyclk_usbdrd30_udrd30_phyclock_user", + mout_phyclk_usbdrd30_udrd30_phyclock_user_p, + MUX_SEL_FSYS2, 0, 1), + + /* MUX_SEL_FSYS3 */ + MUX(CLK_MOUT_PHYCLK_UFS_RX1_SYMBOL_USER, + "mout_phyclk_ufs_rx1_symbol_user", + mout_phyclk_ufs_rx1_symbol_user_p, + MUX_SEL_FSYS3, 16, 1), + MUX(CLK_MOUT_PHYCLK_UFS_RX0_SYMBOL_USER, + "mout_phyclk_ufs_rx0_symbol_user", + mout_phyclk_ufs_rx0_symbol_user_p, + MUX_SEL_FSYS3, 12, 1), + MUX(CLK_MOUT_PHYCLK_UFS_TX1_SYMBOL_USER, + "mout_phyclk_ufs_tx1_symbol_user", + mout_phyclk_ufs_tx1_symbol_user_p, + MUX_SEL_FSYS3, 8, 1), + MUX(CLK_MOUT_PHYCLK_UFS_TX0_SYMBOL_USER, + "mout_phyclk_ufs_tx0_symbol_user", + mout_phyclk_ufs_tx0_symbol_user_p, + MUX_SEL_FSYS3, 4, 1), + MUX(CLK_MOUT_PHYCLK_LLI_MPHY_TO_UFS_USER, + "mout_phyclk_lli_mphy_to_ufs_user", + mout_phyclk_lli_mphy_to_ufs_user_p, + MUX_SEL_FSYS3, 0, 1), + + /* MUX_SEL_FSYS4 */ + MUX(CLK_MOUT_SCLK_MPHY, "mout_sclk_mphy", mout_sclk_mphy_p, + MUX_SEL_FSYS4, 0, 1), }; static struct samsung_gate_clock fsys_gate_clks[] __initdata = { @@ -1902,13 +2070,145 @@ static struct samsung_gate_clock fsys_gate_clks[] __initdata = { GATE(CLK_ACLK_PDMA0, "aclk_pdma0", "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS0, 0, CLK_IGNORE_UNUSED, 0), + /* ENABLE_ACLK_FSYS1 */ + GATE(CLK_ACLK_XIU_FSYSPX, "aclk_xiu_fsyspx", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 27, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB_USBLINKH1, "aclk_ahb_usblinkh1", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_PDMA1, "aclk_smmu_pdma1", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_PCIE, "aclk_bts_pcie", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 24, 0, 0), + GATE(CLK_ACLK_AXIUS_PDMA1, "aclk_axius_pdma1", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_PDMA0, "aclk_smmu_pdma0", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_UFS, "aclk_bts_ufs", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_USBHOST30, "aclk_bts_usbhost30", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 13, 0, 0), + GATE(CLK_ACLK_BTS_USBDRD30, "aclk_bts_usbdrd30", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 12, 0, 0), + GATE(CLK_ACLK_AXIUS_PDMA0, "aclk_axius_pdma0", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_USBHS, "aclk_axius_usbhs", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_FSYSSX, "aclk_axius_fsyssx", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_FSYSP, "aclk_ahb2apb_fsysp", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2AXI_USBHS, "aclk_ahb2axi_usbhs", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB_USBLINKH0, "aclk_ahb_usblinkh0", + "mout_aclk_fsys_200_user", ENABLE_ACLK_FSYS1, + 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB_USBHS, "aclk_ahb_usbhs", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB_FSYSH, "aclk_ahb_fsysh", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_FSYSX, "aclk_xiu_fsysx", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_FSYSSX, "aclk_xiu_fsyssx", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_FSYSNP_200, "aclk_fsysnp_200", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_FSYSND_200, "aclk_fsysnd_200", "mout_aclk_fsys_200_user", + ENABLE_ACLK_FSYS1, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_FSYS */ + GATE(CLK_PCLK_PCIE_CTRL, "pclk_pcie_ctrl", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 17, 0, 0), + GATE(CLK_PCLK_SMMU_PDMA1, "pclk_smmu_pdma1", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PCIE_PHY, "pclk_pcie_phy", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 14, 0, 0), + GATE(CLK_PCLK_BTS_PCIE, "pclk_bts_pcie", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 13, 0, 0), + GATE(CLK_PCLK_SMMU_PDMA0, "pclk_smmu_pdma0", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_UFS, "pclk_bts_ufs", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 5, 0, 0), + GATE(CLK_PCLK_BTS_USBHOST30, "pclk_bts_usbhost30", + "mout_aclk_fsys_200_user", ENABLE_PCLK_FSYS, 4, 0, 0), + GATE(CLK_PCLK_BTS_USBDRD30, "pclk_bts_usbdrd30", + "mout_aclk_fsys_200_user", ENABLE_PCLK_FSYS, 3, 0, 0), + GATE(CLK_PCLK_GPIO_FSYS, "pclk_gpio_fsys", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_FSYS, "pclk_pmu_fsys", "mout_aclk_fsys_200_user", + ENABLE_PCLK_FSYS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_FSYS, "pclk_sysreg_fsys", + "mout_aclk_fsys_200_user", ENABLE_PCLK_FSYS, + 0, CLK_IGNORE_UNUSED, 0), + /* ENABLE_SCLK_FSYS */ + GATE(CLK_SCLK_PCIE_100, "sclk_pcie_100", "mout_sclk_pcie_100_user", + ENABLE_SCLK_FSYS, 21, 0, 0), + GATE(CLK_PHYCLK_USBHOST30_UHOST30_PIPE_PCLK, + "phyclk_usbhost30_uhost30_pipe_pclk", + "mout_phyclk_usbhost30_uhost30_pipe_pclk_user", + ENABLE_SCLK_FSYS, 18, 0, 0), + GATE(CLK_PHYCLK_USBHOST30_UHOST30_PHYCLOCK, + "phyclk_usbhost30_uhost30_phyclock", + "mout_phyclk_usbhost30_uhost30_phyclock_user", + ENABLE_SCLK_FSYS, 17, 0, 0), + GATE(CLK_PHYCLK_UFS_RX1_SYMBOL, "phyclk_ufs_rx1_symbol", + "mout_phyclk_ufs_rx1_symbol_user", ENABLE_SCLK_FSYS, + 16, 0, 0), + GATE(CLK_PHYCLK_UFS_RX0_SYMBOL, "phyclk_ufs_rx0_symbol", + "mout_phyclk_ufs_rx0_symbol_user", ENABLE_SCLK_FSYS, + 15, 0, 0), + GATE(CLK_PHYCLK_UFS_TX1_SYMBOL, "phyclk_ufs_tx1_symbol", + "mout_phyclk_ufs_tx1_symbol_user", ENABLE_SCLK_FSYS, + 14, 0, 0), + GATE(CLK_PHYCLK_UFS_TX0_SYMBOL, "phyclk_ufs_tx0_symbol", + "mout_phyclk_ufs_tx0_symbol_user", ENABLE_SCLK_FSYS, + 13, 0, 0), + GATE(CLK_PHYCLK_USBHOST20_PHY_HSIC1, "phyclk_usbhost20_phy_hsic1", + "mout_phyclk_usbhost20_phy_hsic1", ENABLE_SCLK_FSYS, + 12, 0, 0), + GATE(CLK_PHYCLK_USBHOST20_PHY_CLK48MOHCI, + "phyclk_usbhost20_phy_clk48mohci", + "mout_phyclk_usbhost20_phy_clk48mohci_user", + ENABLE_SCLK_FSYS, 11, 0, 0), + GATE(CLK_PHYCLK_USBHOST20_PHY_PHYCLOCK, + "phyclk_usbhost20_phy_phyclock", + "mout_phyclk_usbhost20_phy_phyclock_user", + ENABLE_SCLK_FSYS, 10, 0, 0), + GATE(CLK_PHYCLK_USBHOST20_PHY_FREECLK, + "phyclk_usbhost20_phy_freeclk", + "mout_phyclk_usbhost20_phy_freeclk_user", + ENABLE_SCLK_FSYS, 9, 0, 0), + GATE(CLK_PHYCLK_USBDRD30_UDRD30_PIPE_PCLK, + "phyclk_usbdrd30_udrd30_pipe_pclk", + "mout_phyclk_usbdrd30_udrd30_pipe_pclk_user", + ENABLE_SCLK_FSYS, 8, 0, 0), + GATE(CLK_PHYCLK_USBDRD30_UDRD30_PHYCLOCK, + "phyclk_usbdrd30_udrd30_phyclock", + "mout_phyclk_usbdrd30_udrd30_phyclock_user", + ENABLE_SCLK_FSYS, 7, 0, 0), + GATE(CLK_SCLK_MPHY, "sclk_mphy", "mout_sclk_mphy", + ENABLE_SCLK_FSYS, 6, 0, 0), + GATE(CLK_SCLK_UFSUNIPRO, "sclk_ufsunipro", "mout_sclk_ufsunipro_user", + ENABLE_SCLK_FSYS, 5, 0, 0), GATE(CLK_SCLK_MMC2, "sclk_mmc2", "mout_sclk_mmc2_user", ENABLE_SCLK_FSYS, 4, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_MMC1, "sclk_mmc1", "mout_sclk_mmc1_user", ENABLE_SCLK_FSYS, 3, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_MMC0, "sclk_mmc0", "mout_sclk_mmc0_user", ENABLE_SCLK_FSYS, 2, CLK_SET_RATE_PARENT, 0), + GATE(CLK_SCLK_USBHOST30, "sclk_usbhost30", "mout_sclk_usbhost30_user", + ENABLE_SCLK_FSYS, 1, 0, 0), + GATE(CLK_SCLK_USBDRD30, "sclk_usbdrd30", "mout_sclk_usbdrd30_user", + ENABLE_SCLK_FSYS, 0, 0, 0), /* ENABLE_IP_FSYS0 */ GATE(CLK_PDMA1, "pdma1", "aclk_pdma1", ENABLE_IP_FSYS0, 15, 0, 0), @@ -1920,6 +2220,8 @@ static struct samsung_cmu_info fsys_cmu_info __initdata = { .nr_mux_clks = ARRAY_SIZE(fsys_mux_clks), .gate_clks = fsys_gate_clks, .nr_gate_clks = ARRAY_SIZE(fsys_gate_clks), + .fixed_clks = fsys_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(fsys_fixed_clks), .nr_clk_ids = FSYS_NR_CLK, .clk_regs = fsys_clk_regs, .nr_clk_regs = ARRAY_SIZE(fsys_clk_regs), diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 8d388e700a80..294a2d0a67ff 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -110,6 +110,10 @@ #define CLK_DIV_ACLK_G3D_400 137 #define CLK_DIV_ACLK_BUS0_400 138 #define CLK_DIV_ACLK_BUS1_400 139 +#define CLK_DIV_SCLK_PCIE_100 140 +#define CLK_DIV_SCLK_USBHOST30 141 +#define CLK_DIV_SCLK_UFSUNIPRO 142 +#define CLK_DIV_SCLK_USBDRD30 143 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -139,8 +143,12 @@ #define CLK_ACLK_BUS1_400 225 #define CLK_ACLK_IMEM_200 226 #define CLK_ACLK_IMEM_266 227 +#define CLK_SCLK_PCIE_100_FSYS 228 +#define CLK_SCLK_UFSUNIPRO_FSYS 229 +#define CLK_SCLK_USBHOST30_FSYS 230 +#define CLK_SCLK_USBDRD30_FSYS 231 -#define TOP_NR_CLK 228 +#define TOP_NR_CLK 232 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -473,6 +481,39 @@ #define CLK_MOUT_SCLK_MMC2_USER 2 #define CLK_MOUT_SCLK_MMC1_USER 3 #define CLK_MOUT_SCLK_MMC0_USER 4 +#define CLK_MOUT_SCLK_UFS_MPHY_USER 5 +#define CLK_MOUT_SCLK_PCIE_100_USER 6 +#define CLK_MOUT_SCLK_UFSUNIPRO_USER 7 +#define CLK_MOUT_SCLK_USBHOST30_USER 8 +#define CLK_MOUT_SCLK_USBDRD30_USER 9 +#define CLK_MOUT_PHYCLK_USBHOST30_UHOST30_PIPE_PCLK_USER 10 +#define CLK_MOUT_PHYCLK_USBHOST30_UHOST30_PHYCLOCK_USER 11 +#define CLK_MOUT_PHYCLK_USBHOST20_PHY_HSIC1_USER 12 +#define CLK_MOUT_PHYCLK_USBHOST20_PHY_CLK48MOHCI_USER 13 +#define CLK_MOUT_PHYCLK_USBHOST20_PHY_PHYCLOCK_USER 14 +#define CLK_MOUT_PHYCLK_USBHOST20_PHY_PHY_FREECLK_USER 15 +#define CLK_MOUT_PHYCLK_USBDRD30_UDRD30_PIPE_PCLK_USER 16 +#define CLK_MOUT_PHYCLK_USBDRD30_UDRD30_PHYCLOCK_USER 17 +#define CLK_MOUT_PHYCLK_UFS_RX1_SYMBOL_USER 18 +#define CLK_MOUT_PHYCLK_UFS_RX0_SYMBOL_USER 19 +#define CLK_MOUT_PHYCLK_UFS_TX1_SYMBOL_USER 20 +#define CLK_MOUT_PHYCLK_UFS_TX0_SYMBOL_USER 21 +#define CLK_MOUT_PHYCLK_LLI_MPHY_TO_UFS_USER 22 +#define CLK_MOUT_SCLK_MPHY 23 + +#define CLK_PHYCLK_USBDRD30_UDRD30_PHYCLOCK_PHY 25 +#define CLK_PHYCLK_USBDRD30_UDRD30_PIPE_PCLK_PHY 26 +#define CLK_PHYCLK_USBHOST30_UHOST30_PHYCLOCK_PHY 27 +#define CLK_PHYCLK_USBHOST30_UHOST30_PIPE_PCLK_PHY 28 +#define CLK_PHYCLK_USBHOST20_PHY_FREECLK_PHY 29 +#define CLK_PHYCLK_USBHOST20_PHY_PHYCLOCK_PHY 30 +#define CLK_PHYCLK_USBHOST20_PHY_CLK48MOHCI_PHY 31 +#define CLK_PHYCLK_USBHOST20_PHY_HSIC1_PHY 32 +#define CLK_PHYCLK_UFS_TX0_SYMBOL_PHY 33 +#define CLK_PHYCLK_UFS_RX0_SYMBOL_PHY 34 +#define CLK_PHYCLK_UFS_TX1_SYMBOL_PHY 35 +#define CLK_PHYCLK_UFS_RX1_SYMBOL_PHY 36 +#define CLK_PHYCLK_LLI_MPHY_TO_UFS_PHY 37 #define CLK_ACLK_PCIE 50 #define CLK_ACLK_PDMA1 51 @@ -490,8 +531,57 @@ #define CLK_SCLK_MMC0 63 #define CLK_PDMA1 64 #define CLK_PDMA0 65 - -#define FSYS_NR_CLK 66 +#define CLK_ACLK_XIU_FSYSPX 66 +#define CLK_ACLK_AHB_USBLINKH1 67 +#define CLK_ACLK_SMMU_PDMA1 68 +#define CLK_ACLK_BTS_PCIE 69 +#define CLK_ACLK_AXIUS_PDMA1 70 +#define CLK_ACLK_SMMU_PDMA0 71 +#define CLK_ACLK_BTS_UFS 72 +#define CLK_ACLK_BTS_USBHOST30 73 +#define CLK_ACLK_BTS_USBDRD30 74 +#define CLK_ACLK_AXIUS_PDMA0 75 +#define CLK_ACLK_AXIUS_USBHS 76 +#define CLK_ACLK_AXIUS_FSYSSX 77 +#define CLK_ACLK_AHB2APB_FSYSP 78 +#define CLK_ACLK_AHB2AXI_USBHS 79 +#define CLK_ACLK_AHB_USBLINKH0 80 +#define CLK_ACLK_AHB_USBHS 81 +#define CLK_ACLK_AHB_FSYSH 82 +#define CLK_ACLK_XIU_FSYSX 83 +#define CLK_ACLK_XIU_FSYSSX 84 +#define CLK_ACLK_FSYSNP_200 85 +#define CLK_ACLK_FSYSND_200 86 +#define CLK_PCLK_PCIE_CTRL 87 +#define CLK_PCLK_SMMU_PDMA1 88 +#define CLK_PCLK_PCIE_PHY 89 +#define CLK_PCLK_BTS_PCIE 90 +#define CLK_PCLK_SMMU_PDMA0 91 +#define CLK_PCLK_BTS_UFS 92 +#define CLK_PCLK_BTS_USBHOST30 93 +#define CLK_PCLK_BTS_USBDRD30 94 +#define CLK_PCLK_GPIO_FSYS 95 +#define CLK_PCLK_PMU_FSYS 96 +#define CLK_PCLK_SYSREG_FSYS 97 +#define CLK_SCLK_PCIE_100 98 +#define CLK_PHYCLK_USBHOST30_UHOST30_PIPE_PCLK 99 +#define CLK_PHYCLK_USBHOST30_UHOST30_PHYCLOCK 100 +#define CLK_PHYCLK_UFS_RX1_SYMBOL 101 +#define CLK_PHYCLK_UFS_RX0_SYMBOL 102 +#define CLK_PHYCLK_UFS_TX1_SYMBOL 103 +#define CLK_PHYCLK_UFS_TX0_SYMBOL 104 +#define CLK_PHYCLK_USBHOST20_PHY_HSIC1 105 +#define CLK_PHYCLK_USBHOST20_PHY_CLK48MOHCI 106 +#define CLK_PHYCLK_USBHOST20_PHY_PHYCLOCK 107 +#define CLK_PHYCLK_USBHOST20_PHY_FREECLK 108 +#define CLK_PHYCLK_USBDRD30_UDRD30_PIPE_PCLK 109 +#define CLK_PHYCLK_USBDRD30_UDRD30_PHYCLOCK 110 +#define CLK_SCLK_MPHY 111 +#define CLK_SCLK_UFSUNIPRO 112 +#define CLK_SCLK_USBHOST30 113 +#define CLK_SCLK_USBDRD30 114 + +#define FSYS_NR_CLK 115 /* CMU_G2D */ #define CLK_MUX_ACLK_G2D_266_USER 1 -- cgit v1.2.3 From 453e519e5aed806c1b70bcbe92aeab39a93dda22 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:06 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_G3D domain This patch adds the mux/divider/gate clocks for CMU_G3D domain which contains the clocks for GPU(3D Graphics Engine). Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 127 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 25 +++++++ 2 files changed, 152 insertions(+) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 1cdc47e05ac1..f422485a92c0 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -3120,3 +3120,130 @@ CLK_OF_DECLARE(exynos5433_cmu_bus##id, \ exynos5433_cmu_bus_init(0); exynos5433_cmu_bus_init(1); exynos5433_cmu_bus_init(2); + +/* + * Register offset definitions for CMU_G3D + */ +#define G3D_PLL_LOCK 0x0000 +#define G3D_PLL_CON0 0x0100 +#define G3D_PLL_CON1 0x0104 +#define G3D_PLL_FREQ_DET 0x010c +#define MUX_SEL_G3D 0x0200 +#define MUX_ENABLE_G3D 0x0300 +#define MUX_STAT_G3D 0x0400 +#define DIV_G3D 0x0600 +#define DIV_G3D_PLL_FREQ_DET 0x0604 +#define DIV_STAT_G3D 0x0700 +#define DIV_STAT_G3D_PLL_FREQ_DET 0x0704 +#define ENABLE_ACLK_G3D 0x0800 +#define ENABLE_PCLK_G3D 0x0900 +#define ENABLE_SCLK_G3D 0x0a00 +#define ENABLE_IP_G3D0 0x0b00 +#define ENABLE_IP_G3D1 0x0b04 +#define CLKOUT_CMU_G3D 0x0c00 +#define CLKOUT_CMU_G3D_DIV_STAT 0x0c04 +#define CLK_STOPCTRL 0x1000 + +static unsigned long g3d_clk_regs[] __initdata = { + G3D_PLL_LOCK, + G3D_PLL_CON0, + G3D_PLL_CON1, + G3D_PLL_FREQ_DET, + MUX_SEL_G3D, + MUX_ENABLE_G3D, + MUX_STAT_G3D, + DIV_G3D, + DIV_G3D_PLL_FREQ_DET, + DIV_STAT_G3D, + DIV_STAT_G3D_PLL_FREQ_DET, + ENABLE_ACLK_G3D, + ENABLE_PCLK_G3D, + ENABLE_SCLK_G3D, + ENABLE_IP_G3D0, + ENABLE_IP_G3D1, + CLKOUT_CMU_G3D, + CLKOUT_CMU_G3D_DIV_STAT, + CLK_STOPCTRL, +}; + +/* list of all parent clock list */ +PNAME(mout_aclk_g3d_400_p) = { "mout_g3d_pll", "aclk_g3d_400", }; +PNAME(mout_g3d_pll_p) = { "oscclk", "fout_g3d_pll", }; + +static struct samsung_pll_clock g3d_pll_clks[] __initdata = { + PLL(pll_35xx, CLK_FOUT_G3D_PLL, "fout_g3d_pll", "oscclk", + G3D_PLL_LOCK, G3D_PLL_CON0, exynos5443_pll_rates), +}; + +static struct samsung_mux_clock g3d_mux_clks[] __initdata = { + /* MUX_SEL_G3D */ + MUX(CLK_MOUT_ACLK_G3D_400, "mout_aclk_g3d_400", mout_aclk_g3d_400_p, + MUX_SEL_G3D, 8, 1), + MUX(CLK_MOUT_G3D_PLL, "mout_g3d_pll", mout_g3d_pll_p, + MUX_SEL_G3D, 0, 1), +}; + +static struct samsung_div_clock g3d_div_clks[] __initdata = { + /* DIV_G3D */ + DIV(CLK_DIV_SCLK_HPM_G3D, "div_sclk_hpm_g3d", "mout_g3d_pll", DIV_G3D, + 8, 2), + DIV(CLK_DIV_PCLK_G3D, "div_pclk_g3d", "div_aclk_g3d", DIV_G3D, + 4, 3), + DIV(CLK_DIV_ACLK_G3D, "div_aclk_g3d", "mout_aclk_g3d_400", DIV_G3D, + 0, 3), +}; + +static struct samsung_gate_clock g3d_gate_clks[] __initdata = { + /* ENABLE_ACLK_G3D */ + GATE(CLK_ACLK_BTS_G3D1, "aclk_bts_g3d1", "div_aclk_g3d", + ENABLE_ACLK_G3D, 7, 0, 0), + GATE(CLK_ACLK_BTS_G3D0, "aclk_bts_g3d0", "div_aclk_g3d", + ENABLE_ACLK_G3D, 6, 0, 0), + GATE(CLK_ACLK_ASYNCAPBS_G3D, "aclk_asyncapbs_g3d", "div_pclk_g3d", + ENABLE_ACLK_G3D, 5, 0, 0), + GATE(CLK_ACLK_ASYNCAPBM_G3D, "aclk_asyncapbm_g3d", "div_aclk_g3d", + ENABLE_ACLK_G3D, 4, 0, 0), + GATE(CLK_ACLK_AHB2APB_G3DP, "aclk_ahb2apb_g3dp", "div_pclk_g3d", + ENABLE_ACLK_G3D, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G3DNP_150, "aclk_g3dnp_150", "div_pclk_g3d", + ENABLE_ACLK_G3D, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G3DND_600, "aclk_g3dnd_600", "div_aclk_g3d", + ENABLE_ACLK_G3D, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_G3D, "aclk_g3d", "div_aclk_g3d", + ENABLE_ACLK_G3D, 0, 0, 0), + + /* ENABLE_PCLK_G3D */ + GATE(CLK_PCLK_BTS_G3D1, "pclk_bts_g3d1", "div_pclk_g3d", + ENABLE_PCLK_G3D, 3, 0, 0), + GATE(CLK_PCLK_BTS_G3D0, "pclk_bts_g3d0", "div_pclk_g3d", + ENABLE_PCLK_G3D, 2, 0, 0), + GATE(CLK_PCLK_PMU_G3D, "pclk_pmu_g3d", "div_pclk_g3d", + ENABLE_PCLK_G3D, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_G3D, "pclk_sysreg_g3d", "div_pclk_g3d", + ENABLE_PCLK_G3D, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_G3D */ + GATE(CLK_SCLK_HPM_G3D, "sclk_hpm_g3d", "div_sclk_hpm_g3d", + ENABLE_SCLK_G3D, 0, 0, 0), +}; + +static struct samsung_cmu_info g3d_cmu_info __initdata = { + .pll_clks = g3d_pll_clks, + .nr_pll_clks = ARRAY_SIZE(g3d_pll_clks), + .mux_clks = g3d_mux_clks, + .nr_mux_clks = ARRAY_SIZE(g3d_mux_clks), + .div_clks = g3d_div_clks, + .nr_div_clks = ARRAY_SIZE(g3d_div_clks), + .gate_clks = g3d_gate_clks, + .nr_gate_clks = ARRAY_SIZE(g3d_gate_clks), + .nr_clk_ids = G3D_NR_CLK, + .clk_regs = g3d_clk_regs, + .nr_clk_regs = ARRAY_SIZE(g3d_clk_regs), +}; + +static void __init exynos5433_cmu_g3d_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &g3d_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_g3d, "samsung,exynos5433-cmu-g3d", + exynos5433_cmu_g3d_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 294a2d0a67ff..60ccc169e9ff 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -794,4 +794,29 @@ #define BUSx_NR_CLK 11 +/* CMU_G3D */ +#define CLK_FOUT_G3D_PLL 1 + +#define CLK_MOUT_ACLK_G3D_400 2 +#define CLK_MOUT_G3D_PLL 3 + +#define CLK_DIV_SCLK_HPM_G3D 4 +#define CLK_DIV_PCLK_G3D 5 +#define CLK_DIV_ACLK_G3D 6 +#define CLK_ACLK_BTS_G3D1 7 +#define CLK_ACLK_BTS_G3D0 8 +#define CLK_ACLK_ASYNCAPBS_G3D 9 +#define CLK_ACLK_ASYNCAPBM_G3D 10 +#define CLK_ACLK_AHB2APB_G3DP 11 +#define CLK_ACLK_G3DNP_150 12 +#define CLK_ACLK_G3DND_600 13 +#define CLK_ACLK_G3D 14 +#define CLK_PCLK_BTS_G3D1 15 +#define CLK_PCLK_BTS_G3D0 16 +#define CLK_PCLK_PMU_G3D 17 +#define CLK_PCLK_SYSREG_G3D 18 +#define CLK_SCLK_HPM_G3D 19 + +#define G3D_NR_CLK 20 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 2a2f33e83ddb6c0abe3d32075f795aa14e4b9476 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 2 Feb 2015 23:24:07 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_GSCL domain This patch adds the divider/gate of CMU_GSCL domain which contains gscaler clocks. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 146 +++++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 37 ++++++++- 2 files changed, 182 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index f422485a92c0..12f60c6a5a7a 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -545,6 +545,12 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_FSYS_200, "aclk_fsys_200", "div_aclk_fsys_200", ENABLE_ACLK_TOP, 18, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_GSCL_111, "aclk_gscl_111", "div_aclk_gscl_111", + ENABLE_ACLK_TOP, 15, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_GSCL_333, "aclk_gscl_333", "div_aclk_gscl_333", + ENABLE_ACLK_TOP, 14, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_G2D_266, "aclk_g2d_266", "div_aclk_g2d_266", ENABLE_ACLK_TOP, 2, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -3247,3 +3253,143 @@ static void __init exynos5433_cmu_g3d_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_g3d, "samsung,exynos5433-cmu-g3d", exynos5433_cmu_g3d_init); + +/* + * Register offset definitions for CMU_GSCL + */ +#define MUX_SEL_GSCL 0x0200 +#define MUX_ENABLE_GSCL 0x0300 +#define MUX_STAT_GSCL 0x0400 +#define ENABLE_ACLK_GSCL 0x0800 +#define ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL0 0x0804 +#define ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL1 0x0808 +#define ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL2 0x080c +#define ENABLE_PCLK_GSCL 0x0900 +#define ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0 0x0904 +#define ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL1 0x0908 +#define ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL2 0x090c +#define ENABLE_IP_GSCL0 0x0b00 +#define ENABLE_IP_GSCL1 0x0b04 +#define ENABLE_IP_GSCL_SECURE_SMMU_GSCL0 0x0b08 +#define ENABLE_IP_GSCL_SECURE_SMMU_GSCL1 0x0b0c +#define ENABLE_IP_GSCL_SECURE_SMMU_GSCL2 0x0b10 + +static unsigned long gscl_clk_regs[] __initdata = { + MUX_SEL_GSCL, + MUX_ENABLE_GSCL, + MUX_STAT_GSCL, + ENABLE_ACLK_GSCL, + ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL0, + ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL1, + ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL2, + ENABLE_PCLK_GSCL, + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0, + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL1, + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL2, + ENABLE_IP_GSCL0, + ENABLE_IP_GSCL1, + ENABLE_IP_GSCL_SECURE_SMMU_GSCL0, + ENABLE_IP_GSCL_SECURE_SMMU_GSCL1, + ENABLE_IP_GSCL_SECURE_SMMU_GSCL2, +}; + +/* list of all parent clock list */ +PNAME(aclk_gscl_111_user_p) = { "oscclk", "aclk_gscl_111", }; +PNAME(aclk_gscl_333_user_p) = { "oscclk", "aclk_gscl_333", }; + +static struct samsung_mux_clock gscl_mux_clks[] __initdata = { + /* MUX_SEL_GSCL */ + MUX(CLK_MOUT_ACLK_GSCL_111_USER, "mout_aclk_gscl_111_user", + aclk_gscl_111_user_p, MUX_SEL_GSCL, 4, 1), + MUX(CLK_MOUT_ACLK_GSCL_333_USER, "mout_aclk_gscl_333_user", + aclk_gscl_333_user_p, MUX_SEL_GSCL, 0, 1), +}; + +static struct samsung_gate_clock gscl_gate_clks[] __initdata = { + /* ENABLE_ACLK_GSCL */ + GATE(CLK_ACLK_BTS_GSCL2, "aclk_bts_gscl2", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 11, 0, 0), + GATE(CLK_ACLK_BTS_GSCL1, "aclk_bts_gscl1", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 10, 0, 0), + GATE(CLK_ACLK_BTS_GSCL0, "aclk_bts_gscl0", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 9, 0, 0), + GATE(CLK_ACLK_AHB2APB_GSCLP, "aclk_ahb2apb_gsclp", + "mout_aclk_gscl_111_user", ENABLE_ACLK_GSCL, + 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_GSCLX, "aclk_xiu_gsclx", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 7, 0, 0), + GATE(CLK_ACLK_GSCLNP_111, "aclk_gsclnp_111", "mout_aclk_gscl_111_user", + ENABLE_ACLK_GSCL, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_GSCLRTND_333, "aclk_gsclrtnd_333", + "mout_aclk_gscl_333_user", ENABLE_ACLK_GSCL, 5, 0, 0), + GATE(CLK_ACLK_GSCLBEND_333, "aclk_gsclbend_333", + "mout_aclk_gscl_333_user", ENABLE_ACLK_GSCL, 4, 0, 0), + GATE(CLK_ACLK_GSD, "aclk_gsd", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 3, 0, 0), + GATE(CLK_ACLK_GSCL2, "aclk_gscl2", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 2, 0, 0), + GATE(CLK_ACLK_GSCL1, "aclk_gscl1", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 1, 0, 0), + GATE(CLK_ACLK_GSCL0, "aclk_gscl0", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL, 0, 0, 0), + + /* ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL0 */ + GATE(CLK_ACLK_SMMU_GSCL0, "aclk_smmu_gscl0", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL0, 0, 0, 0), + + /* ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL1 */ + GATE(CLK_ACLK_SMMU_GSCL1, "aclk_smmu_gscl1", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL1, 0, 0, 0), + + /* ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL2 */ + GATE(CLK_ACLK_SMMU_GSCL2, "aclk_smmu_gscl2", "mout_aclk_gscl_333_user", + ENABLE_ACLK_GSCL_SECURE_SMMU_GSCL2, 0, 0, 0), + + /* ENABLE_PCLK_GSCL */ + GATE(CLK_PCLK_BTS_GSCL2, "pclk_bts_gscl2", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 7, 0, 0), + GATE(CLK_PCLK_BTS_GSCL1, "pclk_bts_gscl1", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 6, 0, 0), + GATE(CLK_PCLK_BTS_GSCL0, "pclk_bts_gscl0", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 5, 0, 0), + GATE(CLK_PCLK_PMU_GSCL, "pclk_pmu_gscl", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_GSCL, "pclk_sysreg_gscl", + "mout_aclk_gscl_111_user", ENABLE_PCLK_GSCL, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_GSCL2, "pclk_gscl2", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 2, 0, 0), + GATE(CLK_PCLK_GSCL1, "pclk_gscl1", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 1, 0, 0), + GATE(CLK_PCLK_GSCL0, "pclk_gscl0", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL, 0, 0, 0), + + /* ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0 */ + GATE(CLK_PCLK_SMMU_GSCL0, "pclk_smmu_gscl0", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0, 0, 0, 0), + + /* ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL1 */ + GATE(CLK_PCLK_SMMU_GSCL1, "pclk_smmu_gscl1", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0, 0, 0, 0), + + /* ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL2 */ + GATE(CLK_PCLK_SMMU_GSCL2, "pclk_smmu_gscl2", "mout_aclk_gscl_111_user", + ENABLE_PCLK_GSCL_SECURE_SMMU_GSCL0, 0, 0, 0), +}; + +static struct samsung_cmu_info gscl_cmu_info __initdata = { + .mux_clks = gscl_mux_clks, + .nr_mux_clks = ARRAY_SIZE(gscl_mux_clks), + .gate_clks = gscl_gate_clks, + .nr_gate_clks = ARRAY_SIZE(gscl_gate_clks), + .nr_clk_ids = GSCL_NR_CLK, + .clk_regs = gscl_clk_regs, + .nr_clk_regs = ARRAY_SIZE(gscl_clk_regs), +}; + +static void __init exynos5433_cmu_gscl_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &gscl_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_gscl, "samsung,exynos5433-cmu-gscl", + exynos5433_cmu_gscl_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 60ccc169e9ff..fef8893c3ec2 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -147,8 +147,10 @@ #define CLK_SCLK_UFSUNIPRO_FSYS 229 #define CLK_SCLK_USBHOST30_FSYS 230 #define CLK_SCLK_USBDRD30_FSYS 231 +#define CLK_ACLK_GSCL_111 232 +#define CLK_ACLK_GSCL_333 233 -#define TOP_NR_CLK 232 +#define TOP_NR_CLK 234 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -819,4 +821,37 @@ #define G3D_NR_CLK 20 +/* CMU_GSCL */ +#define CLK_MOUT_ACLK_GSCL_111_USER 1 +#define CLK_MOUT_ACLK_GSCL_333_USER 2 + +#define CLK_ACLK_BTS_GSCL2 3 +#define CLK_ACLK_BTS_GSCL1 4 +#define CLK_ACLK_BTS_GSCL0 5 +#define CLK_ACLK_AHB2APB_GSCLP 6 +#define CLK_ACLK_XIU_GSCLX 7 +#define CLK_ACLK_GSCLNP_111 8 +#define CLK_ACLK_GSCLRTND_333 9 +#define CLK_ACLK_GSCLBEND_333 10 +#define CLK_ACLK_GSD 11 +#define CLK_ACLK_GSCL2 12 +#define CLK_ACLK_GSCL1 13 +#define CLK_ACLK_GSCL0 14 +#define CLK_ACLK_SMMU_GSCL0 15 +#define CLK_ACLK_SMMU_GSCL1 16 +#define CLK_ACLK_SMMU_GSCL2 17 +#define CLK_PCLK_BTS_GSCL2 18 +#define CLK_PCLK_BTS_GSCL1 19 +#define CLK_PCLK_BTS_GSCL0 20 +#define CLK_PCLK_PMU_GSCL 21 +#define CLK_PCLK_SYSREG_GSCL 22 +#define CLK_PCLK_GSCL2 23 +#define CLK_PCLK_GSCL1 24 +#define CLK_PCLK_GSCL0 25 +#define CLK_PCLK_SMMU_GSCL0 26 +#define CLK_PCLK_SMMU_GSCL1 27 +#define CLK_PCLK_SMMU_GSCL2 28 + +#define GSCL_NR_CLK 29 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From df40a13ca53e6f83ead88e718dd96654e75365ec Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:49 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_APOLLO domain This patch adds the mux/divider/gate clocks for CMU_APOLLO domain which generates the clocks for Cortex-A53 Quad-core processsor. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae [s.nawrocki@samsung.com: Renamed pclk_pmu_sysreg_apollo to pclk_sysreg_apollo] Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 15 ++ drivers/clk/samsung/clk-exynos5433.c | 193 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 37 ++++ 3 files changed, 245 insertions(+) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 9e7ed2d43a15..0a7146861a27 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -32,6 +32,8 @@ Required Properties: which generates clocks for 3D Graphics Engine IP. - "samsung,exynos5433-cmu-gscl" - clock controller compatible for CMU_GSCL which generates clocks for GSCALER IPs. + - "samsung,exynos5433-cmu-apollo"- clock controller compatible for CMU_APOLLO + which generates clocks for Cortex-A53 Quad-core processor. - reg: physical base address of the controller and length of memory mapped region. @@ -105,6 +107,10 @@ Required Properties: - aclk_gscl_111 - aclk_gscl_333 + Input clocks for apollo clock controller: + - oscclk + - sclk_bus_pll_apollo + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -289,6 +295,15 @@ Example 2: Examples of clock controller nodes are listed below. <&cmu_top CLK_ACLK_GSCL_333>; }; + cmu_apollo: clock-controller@11900000 { + compatible = "samsung,exynos5433-cmu-apollo"; + reg = <0x11900000 0x1088>; + #clock-cells = <1>; + + clock-names = "oscclk", "sclk_bus_pll_apollo"; + clocks = <&xxti>, <&cmu_mif CLK_SCLK_BUS_PLL_APOLLO>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 12f60c6a5a7a..f7d1e8390cdf 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -3393,3 +3393,196 @@ static void __init exynos5433_cmu_gscl_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_gscl, "samsung,exynos5433-cmu-gscl", exynos5433_cmu_gscl_init); + +/* + * Register offset definitions for CMU_APOLLO + */ +#define APOLLO_PLL_LOCK 0x0000 +#define APOLLO_PLL_CON0 0x0100 +#define APOLLO_PLL_CON1 0x0104 +#define APOLLO_PLL_FREQ_DET 0x010c +#define MUX_SEL_APOLLO0 0x0200 +#define MUX_SEL_APOLLO1 0x0204 +#define MUX_SEL_APOLLO2 0x0208 +#define MUX_ENABLE_APOLLO0 0x0300 +#define MUX_ENABLE_APOLLO1 0x0304 +#define MUX_ENABLE_APOLLO2 0x0308 +#define MUX_STAT_APOLLO0 0x0400 +#define MUX_STAT_APOLLO1 0x0404 +#define MUX_STAT_APOLLO2 0x0408 +#define DIV_APOLLO0 0x0600 +#define DIV_APOLLO1 0x0604 +#define DIV_APOLLO_PLL_FREQ_DET 0x0608 +#define DIV_STAT_APOLLO0 0x0700 +#define DIV_STAT_APOLLO1 0x0704 +#define DIV_STAT_APOLLO_PLL_FREQ_DET 0x0708 +#define ENABLE_ACLK_APOLLO 0x0800 +#define ENABLE_PCLK_APOLLO 0x0900 +#define ENABLE_SCLK_APOLLO 0x0a00 +#define ENABLE_IP_APOLLO0 0x0b00 +#define ENABLE_IP_APOLLO1 0x0b04 +#define CLKOUT_CMU_APOLLO 0x0c00 +#define CLKOUT_CMU_APOLLO_DIV_STAT 0x0c04 +#define ARMCLK_STOPCTRL 0x1000 +#define APOLLO_PWR_CTRL 0x1020 +#define APOLLO_PWR_CTRL2 0x1024 +#define APOLLO_INTR_SPREAD_ENABLE 0x1080 +#define APOLLO_INTR_SPREAD_USE_STANDBYWFI 0x1084 +#define APOLLO_INTR_SPREAD_BLOCKING_DURATION 0x1088 + +static unsigned long apollo_clk_regs[] __initdata = { + APOLLO_PLL_LOCK, + APOLLO_PLL_CON0, + APOLLO_PLL_CON1, + APOLLO_PLL_FREQ_DET, + MUX_SEL_APOLLO0, + MUX_SEL_APOLLO1, + MUX_SEL_APOLLO2, + MUX_ENABLE_APOLLO0, + MUX_ENABLE_APOLLO1, + MUX_ENABLE_APOLLO2, + MUX_STAT_APOLLO0, + MUX_STAT_APOLLO1, + MUX_STAT_APOLLO2, + DIV_APOLLO0, + DIV_APOLLO1, + DIV_APOLLO_PLL_FREQ_DET, + DIV_STAT_APOLLO0, + DIV_STAT_APOLLO1, + DIV_STAT_APOLLO_PLL_FREQ_DET, + ENABLE_ACLK_APOLLO, + ENABLE_PCLK_APOLLO, + ENABLE_SCLK_APOLLO, + ENABLE_IP_APOLLO0, + ENABLE_IP_APOLLO1, + CLKOUT_CMU_APOLLO, + CLKOUT_CMU_APOLLO_DIV_STAT, + ARMCLK_STOPCTRL, + APOLLO_PWR_CTRL, + APOLLO_PWR_CTRL2, + APOLLO_INTR_SPREAD_ENABLE, + APOLLO_INTR_SPREAD_USE_STANDBYWFI, + APOLLO_INTR_SPREAD_BLOCKING_DURATION, +}; + +/* list of all parent clock list */ +PNAME(mout_apollo_pll_p) = { "oscclk", "fout_apollo_pll", }; +PNAME(mout_bus_pll_apollo_user_p) = { "oscclk", "sclk_bus_pll_apollo", }; +PNAME(mout_apollo_p) = { "mout_apollo_pll", + "mout_bus_pll_apollo_user", }; + +static struct samsung_pll_clock apollo_pll_clks[] __initdata = { + PLL(pll_35xx, CLK_FOUT_APOLLO_PLL, "fout_apollo_pll", "oscclk", + APOLLO_PLL_LOCK, APOLLO_PLL_CON0, exynos5443_pll_rates), +}; + +static struct samsung_mux_clock apollo_mux_clks[] __initdata = { + /* MUX_SEL_APOLLO0 */ + MUX_F(CLK_MOUT_APOLLO_PLL, "mout_apollo_pll", mout_apollo_pll_p, + MUX_SEL_APOLLO0, 0, 1, 0, CLK_MUX_READ_ONLY), + + /* MUX_SEL_APOLLO1 */ + MUX(CLK_MOUT_BUS_PLL_APOLLO_USER, "mout_bus_pll_apollo_user", + mout_bus_pll_apollo_user_p, MUX_SEL_APOLLO1, 0, 1), + + /* MUX_SEL_APOLLO2 */ + MUX_F(CLK_MOUT_APOLLO, "mout_apollo", mout_apollo_p, MUX_SEL_APOLLO2, + 0, 1, 0, CLK_MUX_READ_ONLY), +}; + +static struct samsung_div_clock apollo_div_clks[] __initdata = { + /* DIV_APOLLO0 */ + DIV_F(CLK_DIV_CNTCLK_APOLLO, "div_cntclk_apollo", "div_apollo2", + DIV_APOLLO0, 24, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_PCLK_DBG_APOLLO, "div_pclk_dbg_apollo", "div_apollo2", + DIV_APOLLO0, 20, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ATCLK_APOLLO, "div_atclk_apollo", "div_apollo2", + DIV_APOLLO0, 16, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_PCLK_APOLLO, "div_pclk_apollo", "div_apollo2", + DIV_APOLLO0, 12, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ACLK_APOLLO, "div_aclk_apollo", "div_apollo2", + DIV_APOLLO0, 8, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_APOLLO2, "div_apollo2", "div_apollo1", + DIV_APOLLO0, 4, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_APOLLO1, "div_apollo1", "mout_apollo", + DIV_APOLLO0, 0, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + + /* DIV_APOLLO1 */ + DIV_F(CLK_DIV_SCLK_HPM_APOLLO, "div_sclk_hpm_apollo", "mout_apollo", + DIV_APOLLO1, 4, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_APOLLO_PLL, "div_apollo_pll", "mout_apollo", + DIV_APOLLO1, 0, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), +}; + +static struct samsung_gate_clock apollo_gate_clks[] __initdata = { + /* ENABLE_ACLK_APOLLO */ + GATE(CLK_ACLK_ASATBSLV_APOLLO_3_CSSYS, "aclk_asatbslv_apollo_3_cssys", + "div_atclk_apollo", ENABLE_ACLK_APOLLO, + 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASATBSLV_APOLLO_2_CSSYS, "aclk_asatbslv_apollo_2_cssys", + "div_atclk_apollo", ENABLE_ACLK_APOLLO, + 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASATBSLV_APOLLO_1_CSSYS, "aclk_asatbslv_apollo_1_cssys", + "div_atclk_apollo", ENABLE_ACLK_APOLLO, + 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASATBSLV_APOLLO_0_CSSYS, "aclk_asatbslv_apollo_0_cssys", + "div_atclk_apollo", ENABLE_ACLK_APOLLO, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCACES_APOLLO_CCI, "aclk_asyncaces_apollo_cci", + "div_aclk_apollo", ENABLE_ACLK_APOLLO, + 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_APOLLOP, "aclk_ahb2apb_apollop", + "div_pclk_apollo", ENABLE_ACLK_APOLLO, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_APOLLONP_200, "aclk_apollonp_200", + "div_pclk_apollo", ENABLE_ACLK_APOLLO, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_APOLLO */ + GATE(CLK_PCLK_ASAPBMST_CSSYS_APOLLO, "pclk_asapbmst_cssys_apollo", + "div_pclk_dbg_apollo", ENABLE_PCLK_APOLLO, + 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_APOLLO, "pclk_pmu_apollo", "div_pclk_apollo", + ENABLE_PCLK_APOLLO, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_APOLLO, "pclk_sysreg_apollo", + "div_pclk_apollo", ENABLE_PCLK_APOLLO, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_APOLLO */ + GATE(CLK_CNTCLK_APOLLO, "cntclk_apollo", "div_cntclk_apollo", + ENABLE_SCLK_APOLLO, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_HPM_APOLLO, "sclk_hpm_apollo", "div_sclk_hpm_apollo", + ENABLE_SCLK_APOLLO, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_APOLLO, "sclk_apollo", "div_apollo_pll", + ENABLE_SCLK_APOLLO, 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info apollo_cmu_info __initdata = { + .pll_clks = apollo_pll_clks, + .nr_pll_clks = ARRAY_SIZE(apollo_pll_clks), + .mux_clks = apollo_mux_clks, + .nr_mux_clks = ARRAY_SIZE(apollo_mux_clks), + .div_clks = apollo_div_clks, + .nr_div_clks = ARRAY_SIZE(apollo_div_clks), + .gate_clks = apollo_gate_clks, + .nr_gate_clks = ARRAY_SIZE(apollo_gate_clks), + .nr_clk_ids = APOLLO_NR_CLK, + .clk_regs = apollo_clk_regs, + .nr_clk_regs = ARRAY_SIZE(apollo_clk_regs), +}; + +static void __init exynos5433_cmu_apollo_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &apollo_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_apollo, "samsung,exynos5433-cmu-apollo", + exynos5433_cmu_apollo_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index fef8893c3ec2..90184e3a42d5 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -854,4 +854,41 @@ #define GSCL_NR_CLK 29 +/* CMU_APOLLO */ +#define CLK_FOUT_APOLLO_PLL 1 + +#define CLK_MOUT_APOLLO_PLL 2 +#define CLK_MOUT_BUS_PLL_APOLLO_USER 3 +#define CLK_MOUT_APOLLO 4 + +#define CLK_DIV_CNTCLK_APOLLO 5 +#define CLK_DIV_PCLK_DBG_APOLLO 6 +#define CLK_DIV_ATCLK_APOLLO 7 +#define CLK_DIV_PCLK_APOLLO 8 +#define CLK_DIV_ACLK_APOLLO 9 +#define CLK_DIV_APOLLO2 10 +#define CLK_DIV_APOLLO1 11 +#define CLK_DIV_SCLK_HPM_APOLLO 12 +#define CLK_DIV_APOLLO_PLL 13 + +#define CLK_ACLK_ATBDS_APOLLO_3 14 +#define CLK_ACLK_ATBDS_APOLLO_2 15 +#define CLK_ACLK_ATBDS_APOLLO_1 16 +#define CLK_ACLK_ATBDS_APOLLO_0 17 +#define CLK_ACLK_ASATBSLV_APOLLO_3_CSSYS 18 +#define CLK_ACLK_ASATBSLV_APOLLO_2_CSSYS 19 +#define CLK_ACLK_ASATBSLV_APOLLO_1_CSSYS 20 +#define CLK_ACLK_ASATBSLV_APOLLO_0_CSSYS 21 +#define CLK_ACLK_ASYNCACES_APOLLO_CCI 22 +#define CLK_ACLK_AHB2APB_APOLLOP 23 +#define CLK_ACLK_APOLLONP_200 24 +#define CLK_PCLK_ASAPBMST_CSSYS_APOLLO 25 +#define CLK_PCLK_PMU_APOLLO 26 +#define CLK_PCLK_SYSREG_APOLLO 27 +#define CLK_CNTCLK_APOLLO 28 +#define CLK_SCLK_HPM_APOLLO 29 +#define CLK_SCLK_APOLLO 30 + +#define APOLLO_NR_CLK 31 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 6c5d76d15ab6da9b30af020a44e071eb5145e1a0 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:50 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_ATLAS domain This patch adds the mux/divider/gate clocks for CMU_ATLAS domain which generates the clocks for Cortex-A57 Quad-core processsor, L2 cache controller and CoreSight. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 16 ++ drivers/clk/samsung/clk-exynos5433.c | 219 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 46 +++++ 3 files changed, 281 insertions(+) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 0a7146861a27..7c1dccc4d72e 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -34,6 +34,9 @@ Required Properties: which generates clocks for GSCALER IPs. - "samsung,exynos5433-cmu-apollo"- clock controller compatible for CMU_APOLLO which generates clocks for Cortex-A53 Quad-core processor. + - "samsung,exynos5433-cmu-atlas" - clock controller compatible for CMU_ATLAS + which generates clocks for Cortex-A57 Quad-core processor, CoreSight and + L2 cache controller. - reg: physical base address of the controller and length of memory mapped region. @@ -111,6 +114,10 @@ Required Properties: - oscclk - sclk_bus_pll_apollo + Input clocks for atlas clock controller: + - oscclk + - sclk_bus_pll_atlas + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -304,6 +311,15 @@ Example 2: Examples of clock controller nodes are listed below. clocks = <&xxti>, <&cmu_mif CLK_SCLK_BUS_PLL_APOLLO>; }; + cmu_atlas: clock-controller@11800000 { + compatible = "samsung,exynos5433-cmu-atlas"; + reg = <0x11800000 0x1088>; + #clock-cells = <1>; + + clock-names = "oscclk", "sclk_bus_pll_atlas"; + clocks = <&xxti>, <&cmu_mif CLK_SCLK_BUS_PLL_ATLAS>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index f7d1e8390cdf..c44062d2904e 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -3586,3 +3586,222 @@ static void __init exynos5433_cmu_apollo_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_apollo, "samsung,exynos5433-cmu-apollo", exynos5433_cmu_apollo_init); + +/* + * Register offset definitions for CMU_ATLAS + */ +#define ATLAS_PLL_LOCK 0x0000 +#define ATLAS_PLL_CON0 0x0100 +#define ATLAS_PLL_CON1 0x0104 +#define ATLAS_PLL_FREQ_DET 0x010c +#define MUX_SEL_ATLAS0 0x0200 +#define MUX_SEL_ATLAS1 0x0204 +#define MUX_SEL_ATLAS2 0x0208 +#define MUX_ENABLE_ATLAS0 0x0300 +#define MUX_ENABLE_ATLAS1 0x0304 +#define MUX_ENABLE_ATLAS2 0x0308 +#define MUX_STAT_ATLAS0 0x0400 +#define MUX_STAT_ATLAS1 0x0404 +#define MUX_STAT_ATLAS2 0x0408 +#define DIV_ATLAS0 0x0600 +#define DIV_ATLAS1 0x0604 +#define DIV_ATLAS_PLL_FREQ_DET 0x0608 +#define DIV_STAT_ATLAS0 0x0700 +#define DIV_STAT_ATLAS1 0x0704 +#define DIV_STAT_ATLAS_PLL_FREQ_DET 0x0708 +#define ENABLE_ACLK_ATLAS 0x0800 +#define ENABLE_PCLK_ATLAS 0x0900 +#define ENABLE_SCLK_ATLAS 0x0a00 +#define ENABLE_IP_ATLAS0 0x0b00 +#define ENABLE_IP_ATLAS1 0x0b04 +#define CLKOUT_CMU_ATLAS 0x0c00 +#define CLKOUT_CMU_ATLAS_DIV_STAT 0x0c04 +#define ARMCLK_STOPCTRL 0x1000 +#define ATLAS_PWR_CTRL 0x1020 +#define ATLAS_PWR_CTRL2 0x1024 +#define ATLAS_INTR_SPREAD_ENABLE 0x1080 +#define ATLAS_INTR_SPREAD_USE_STANDBYWFI 0x1084 +#define ATLAS_INTR_SPREAD_BLOCKING_DURATION 0x1088 + +static unsigned long atlas_clk_regs[] __initdata = { + ATLAS_PLL_LOCK, + ATLAS_PLL_CON0, + ATLAS_PLL_CON1, + ATLAS_PLL_FREQ_DET, + MUX_SEL_ATLAS0, + MUX_SEL_ATLAS1, + MUX_SEL_ATLAS2, + MUX_ENABLE_ATLAS0, + MUX_ENABLE_ATLAS1, + MUX_ENABLE_ATLAS2, + MUX_STAT_ATLAS0, + MUX_STAT_ATLAS1, + MUX_STAT_ATLAS2, + DIV_ATLAS0, + DIV_ATLAS1, + DIV_ATLAS_PLL_FREQ_DET, + DIV_STAT_ATLAS0, + DIV_STAT_ATLAS1, + DIV_STAT_ATLAS_PLL_FREQ_DET, + ENABLE_ACLK_ATLAS, + ENABLE_PCLK_ATLAS, + ENABLE_SCLK_ATLAS, + ENABLE_IP_ATLAS0, + ENABLE_IP_ATLAS1, + CLKOUT_CMU_ATLAS, + CLKOUT_CMU_ATLAS_DIV_STAT, + ARMCLK_STOPCTRL, + ATLAS_PWR_CTRL, + ATLAS_PWR_CTRL2, + ATLAS_INTR_SPREAD_ENABLE, + ATLAS_INTR_SPREAD_USE_STANDBYWFI, + ATLAS_INTR_SPREAD_BLOCKING_DURATION, +}; + +/* list of all parent clock list */ +PNAME(mout_atlas_pll_p) = { "oscclk", "fout_atlas_pll", }; +PNAME(mout_bus_pll_atlas_user_p) = { "oscclk", "sclk_bus_pll_atlas", }; +PNAME(mout_atlas_p) = { "mout_atlas_pll", + "mout_bus_pll_atlas_user", }; + +static struct samsung_pll_clock atlas_pll_clks[] __initdata = { + PLL(pll_35xx, CLK_FOUT_ATLAS_PLL, "fout_atlas_pll", "oscclk", + ATLAS_PLL_LOCK, ATLAS_PLL_CON0, exynos5443_pll_rates), +}; + +static struct samsung_mux_clock atlas_mux_clks[] __initdata = { + /* MUX_SEL_ATLAS0 */ + MUX_F(CLK_MOUT_ATLAS_PLL, "mout_atlas_pll", mout_atlas_pll_p, + MUX_SEL_ATLAS0, 0, 1, 0, CLK_MUX_READ_ONLY), + + /* MUX_SEL_ATLAS1 */ + MUX(CLK_MOUT_BUS_PLL_ATLAS_USER, "mout_bus_pll_atlas_user", + mout_bus_pll_atlas_user_p, MUX_SEL_ATLAS1, 0, 1), + + /* MUX_SEL_ATLAS2 */ + MUX_F(CLK_MOUT_ATLAS, "mout_atlas", mout_atlas_p, MUX_SEL_ATLAS2, + 0, 1, 0, CLK_MUX_READ_ONLY), +}; + +static struct samsung_div_clock atlas_div_clks[] __initdata = { + /* DIV_ATLAS0 */ + DIV_F(CLK_DIV_CNTCLK_ATLAS, "div_cntclk_atlas", "div_atlas2", + DIV_ATLAS0, 24, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_PCLK_DBG_ATLAS, "div_pclk_dbg_atlas", "div_atclk_atlas", + DIV_ATLAS0, 20, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ATCLK_ATLASO, "div_atclk_atlas", "div_atlas2", + DIV_ATLAS0, 16, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_PCLK_ATLAS, "div_pclk_atlas", "div_atlas2", + DIV_ATLAS0, 12, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ACLK_ATLAS, "div_aclk_atlas", "div_atlas2", + DIV_ATLAS0, 8, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ATLAS2, "div_atlas2", "div_atlas1", + DIV_ATLAS0, 4, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ATLAS1, "div_atlas1", "mout_atlas", + DIV_ATLAS0, 0, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + + /* DIV_ATLAS1 */ + DIV_F(CLK_DIV_SCLK_HPM_ATLAS, "div_sclk_hpm_atlas", "mout_atlas", + DIV_ATLAS1, 4, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), + DIV_F(CLK_DIV_ATLAS_PLL, "div_atlas_pll", "mout_atlas", + DIV_ATLAS1, 0, 3, CLK_GET_RATE_NOCACHE, + CLK_DIVIDER_READ_ONLY), +}; + +static struct samsung_gate_clock atlas_gate_clks[] __initdata = { + /* ENABLE_ACLK_ATLAS */ + GATE(CLK_ACLK_ATB_AUD_CSSYS, "aclk_atb_aud_cssys", + "div_atclk_atlas", ENABLE_ACLK_ATLAS, + 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ATB_APOLLO3_CSSYS, "aclk_atb_apollo3_cssys", + "div_atclk_atlas", ENABLE_ACLK_ATLAS, + 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ATB_APOLLO2_CSSYS, "aclk_atb_apollo2_cssys", + "div_atclk_atlas", ENABLE_ACLK_ATLAS, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ATB_APOLLO1_CSSYS, "aclk_atb_apollo1_cssys", + "div_atclk_atlas", ENABLE_ACLK_ATLAS, + 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ATB_APOLLO0_CSSYS, "aclk_atb_apollo0_cssys", + "div_atclk_atlas", ENABLE_ACLK_ATLAS, + 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAHBS_CSSYS_SSS, "aclk_asyncahbs_cssys_sss", + "div_atclk_atlas", ENABLE_ACLK_ATLAS, + 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_CSSYS_CCIX, "aclk_asyncaxis_cssys_ccix", + "div_pclk_dbg_atlas", ENABLE_ACLK_ATLAS, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCACES_ATLAS_CCI, "aclk_asyncaces_atlas_cci", + "div_aclk_atlas", ENABLE_ACLK_ATLAS, + 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_ATLASP, "aclk_ahb2apb_atlasp", "div_pclk_atlas", + ENABLE_ACLK_ATLAS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ATLASNP_200, "aclk_atlasnp_200", "div_pclk_atlas", + ENABLE_ACLK_ATLAS, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_ATLAS */ + GATE(CLK_PCLK_ASYNCAPB_AUD_CSSYS, "pclk_asyncapb_aud_cssys", + "div_pclk_dbg_atlas", ENABLE_PCLK_ATLAS, + 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAPB_ISP_CSSYS, "pclk_asyncapb_isp_cssys", + "div_pclk_dbg_atlas", ENABLE_PCLK_ATLAS, + 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAPB_APOLLO_CSSYS, "pclk_asyncapb_apollo_cssys", + "div_pclk_dbg_atlas", ENABLE_PCLK_ATLAS, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_ATLAS, "pclk_pmu_atlas", "div_pclk_atlas", + ENABLE_PCLK_ATLAS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_ATLAS, "pclk_sysreg_atlas", "div_pclk_atlas", + ENABLE_PCLK_ATLAS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SECJTAG, "pclk_secjtag", "div_pclk_dbg_atlas", + ENABLE_PCLK_ATLAS, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_ATLAS */ + GATE(CLK_CNTCLK_ATLAS, "cntclk_atlas", "div_cntclk_atlas", + ENABLE_SCLK_ATLAS, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_HPM_ATLAS, "sclk_hpm_atlas", "div_sclk_hpm_atlas", + ENABLE_SCLK_ATLAS, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_TRACECLK, "traceclk", "div_atclk_atlas", + ENABLE_SCLK_ATLAS, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_CTMCLK, "ctmclk", "div_atclk_atlas", + ENABLE_SCLK_ATLAS, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_HCLK_CSSYS, "hclk_cssys", "div_atclk_atlas", + ENABLE_SCLK_ATLAS, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DBG_CSSYS, "pclk_dbg_cssys", "div_pclk_dbg_atlas", + ENABLE_SCLK_ATLAS, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DBG, "pclk_dbg", "div_pclk_dbg_atlas", + ENABLE_SCLK_ATLAS, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ATCLK, "atclk", "div_atclk_atlas", + ENABLE_SCLK_ATLAS, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_ATLAS, "sclk_atlas", "div_atlas2", + ENABLE_SCLK_ATLAS, 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info atlas_cmu_info __initdata = { + .pll_clks = atlas_pll_clks, + .nr_pll_clks = ARRAY_SIZE(atlas_pll_clks), + .mux_clks = atlas_mux_clks, + .nr_mux_clks = ARRAY_SIZE(atlas_mux_clks), + .div_clks = atlas_div_clks, + .nr_div_clks = ARRAY_SIZE(atlas_div_clks), + .gate_clks = atlas_gate_clks, + .nr_gate_clks = ARRAY_SIZE(atlas_gate_clks), + .nr_clk_ids = ATLAS_NR_CLK, + .clk_regs = atlas_clk_regs, + .nr_clk_regs = ARRAY_SIZE(atlas_clk_regs), +}; + +static void __init exynos5433_cmu_atlas_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &atlas_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_atlas, "samsung,exynos5433-cmu-atlas", + exynos5433_cmu_atlas_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 90184e3a42d5..cdc91f7e6ec8 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -891,4 +891,50 @@ #define APOLLO_NR_CLK 31 +/* CMU_ATLAS */ +#define CLK_FOUT_ATLAS_PLL 1 + +#define CLK_MOUT_ATLAS_PLL 2 +#define CLK_MOUT_BUS_PLL_ATLAS_USER 3 +#define CLK_MOUT_ATLAS 4 + +#define CLK_DIV_CNTCLK_ATLAS 5 +#define CLK_DIV_PCLK_DBG_ATLAS 6 +#define CLK_DIV_ATCLK_ATLASO 7 +#define CLK_DIV_PCLK_ATLAS 8 +#define CLK_DIV_ACLK_ATLAS 9 +#define CLK_DIV_ATLAS2 10 +#define CLK_DIV_ATLAS1 11 +#define CLK_DIV_SCLK_HPM_ATLAS 12 +#define CLK_DIV_ATLAS_PLL 13 + +#define CLK_ACLK_ATB_AUD_CSSYS 14 +#define CLK_ACLK_ATB_APOLLO3_CSSYS 15 +#define CLK_ACLK_ATB_APOLLO2_CSSYS 16 +#define CLK_ACLK_ATB_APOLLO1_CSSYS 17 +#define CLK_ACLK_ATB_APOLLO0_CSSYS 18 +#define CLK_ACLK_ASYNCAHBS_CSSYS_SSS 19 +#define CLK_ACLK_ASYNCAXIS_CSSYS_CCIX 20 +#define CLK_ACLK_ASYNCACES_ATLAS_CCI 21 +#define CLK_ACLK_AHB2APB_ATLASP 22 +#define CLK_ACLK_ATLASNP_200 23 +#define CLK_PCLK_ASYNCAPB_AUD_CSSYS 24 +#define CLK_PCLK_ASYNCAPB_ISP_CSSYS 25 +#define CLK_PCLK_ASYNCAPB_APOLLO_CSSYS 26 +#define CLK_PCLK_PMU_ATLAS 27 +#define CLK_PCLK_SYSREG_ATLAS 28 +#define CLK_PCLK_SECJTAG 29 +#define CLK_CNTCLK_ATLAS 30 +#define CLK_SCLK_FREQ_DET_ATLAS_PLL 31 +#define CLK_SCLK_HPM_ATLAS 32 +#define CLK_TRACECLK 33 +#define CLK_CTMCLK 34 +#define CLK_HCLK_CSSYS 35 +#define CLK_PCLK_DBG_CSSYS 36 +#define CLK_PCLK_DBG 37 +#define CLK_ATCLK 38 +#define CLK_SCLK_ATLAS 39 + +#define ATLAS_NR_CLK 40 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From b274bbfd8b4a94cb5bd6fe21801264a27dd8ec75 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:51 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_MSCL domain This patch adds the mux/divider/gate clocks for CMU_MSCL domain which generates the clocks for M2M (Memory to Memory) scaler, JPEG IPs. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Reviewed-by: Pankaj Dubey Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 20 +++ drivers/clk/samsung/clk-exynos5433.c | 185 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 41 ++++- 3 files changed, 245 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 7c1dccc4d72e..ecb9534c2ea6 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -37,6 +37,8 @@ Required Properties: - "samsung,exynos5433-cmu-atlas" - clock controller compatible for CMU_ATLAS which generates clocks for Cortex-A57 Quad-core processor, CoreSight and L2 cache controller. + - "samsung,exynos5433-cmu-mscl" - clock controller compatible for CMU_MSCL + which generates clocks for M2M (Memory to Memory) scaler and JPEG IPs. - reg: physical base address of the controller and length of memory mapped region. @@ -118,6 +120,11 @@ Required Properties: - oscclk - sclk_bus_pll_atlas + Input clocks for mscl clock controller: + - oscclk + - sclk_jpeg_mscl + - aclk_mscl_400 + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -320,6 +327,19 @@ Example 2: Examples of clock controller nodes are listed below. clocks = <&xxti>, <&cmu_mif CLK_SCLK_BUS_PLL_ATLAS>; }; + cmu_mscl: clock-controller@105d0000 { + compatible = "samsung,exynos5433-cmu-mscl"; + reg = <0x105d0000 0x0b10>; + #clock-cells = <1>; + + clock-names = "oscclk", + "sclk_jpeg_mscl", + "aclk_mscl_400"; + clocks = <&xxti>, + <&cmu_top CLK_SCLK_JPEG_MSCL>, + <&cmu_top CLK_ACLK_MSCL_400>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index c44062d2904e..d272e42eb48c 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -419,6 +419,8 @@ static struct samsung_div_clock top_div_clks[] __initdata = { DIV_TOP1, 0, 3), /* DIV_TOP2 */ + DIV(CLK_DIV_ACLK_MSCL_400, "div_aclk_mscl_400", "mout_aclk_mscl_400_b", + DIV_TOP2, 4, 3), DIV(CLK_DIV_ACLK_FSYS_200, "div_aclk_fsys_200", "mout_bus_pll_user", DIV_TOP2, 0, 3), @@ -446,6 +448,10 @@ static struct samsung_div_clock top_div_clks[] __initdata = { DIV(CLK_DIV_ACLK_BUS1_400, "div_aclk_bus1_400", "mout_bus_pll_user", DIV_TOP4, 0, 3), + /* DIV_TOP_MSCL */ + DIV(CLK_DIV_SCLK_JPEG, "div_sclk_jpeg", "mout_sclk_jpeg_c", + DIV_TOP_MSCL, 0, 4), + /* DIV_TOP_FSYS0 */ DIV(CLK_DIV_SCLK_MMC1_B, "div_sclk_mmc1_b", "div_sclk_mmc1_a", DIV_TOP_FSYS0, 16, 8), @@ -542,6 +548,9 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_PERIS_66, "aclk_peris_66", "div_aclk_peris_66_b", ENABLE_ACLK_TOP, 21, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MSCL_400, "aclk_mscl_400", "div_aclk_mscl_400", + ENABLE_ACLK_TOP, 19, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_FSYS_200, "aclk_fsys_200", "div_aclk_fsys_200", ENABLE_ACLK_TOP, 18, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -558,6 +567,10 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { ENABLE_ACLK_TOP, 0, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + /* ENABLE_SCLK_TOP_MSCL */ + GATE(CLK_SCLK_JPEG_MSCL, "sclk_jpeg_mscl", "div_sclk_jpeg", + ENABLE_SCLK_TOP_MSCL, 0, 0, 0), + /* ENABLE_SCLK_TOP_FSYS */ GATE(CLK_SCLK_PCIE_100_FSYS, "sclk_pcie_100_fsys", "div_sclk_pcie_100", ENABLE_SCLK_TOP_FSYS, 7, 0, 0), @@ -3805,3 +3818,175 @@ static void __init exynos5433_cmu_atlas_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_atlas, "samsung,exynos5433-cmu-atlas", exynos5433_cmu_atlas_init); + +/* + * Register offset definitions for CMU_MSCL + */ +#define MUX_SEL_MSCL0 0x0200 +#define MUX_SEL_MSCL1 0x0204 +#define MUX_ENABLE_MSCL0 0x0300 +#define MUX_ENABLE_MSCL1 0x0304 +#define MUX_STAT_MSCL0 0x0400 +#define MUX_STAT_MSCL1 0x0404 +#define DIV_MSCL 0x0600 +#define DIV_STAT_MSCL 0x0700 +#define ENABLE_ACLK_MSCL 0x0800 +#define ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER0 0x0804 +#define ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER1 0x0808 +#define ENABLE_ACLK_MSCL_SECURE_SMMU_JPEG 0x080c +#define ENABLE_PCLK_MSCL 0x0900 +#define ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER0 0x0904 +#define ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER1 0x0908 +#define ENABLE_PCLK_MSCL_SECURE_SMMU_JPEG 0x000c +#define ENABLE_SCLK_MSCL 0x0a00 +#define ENABLE_IP_MSCL0 0x0b00 +#define ENABLE_IP_MSCL1 0x0b04 +#define ENABLE_IP_MSCL_SECURE_SMMU_M2MSCALER0 0x0b08 +#define ENABLE_IP_MSCL_SECURE_SMMU_M2MSCALER1 0x0b0c +#define ENABLE_IP_MSCL_SECURE_SMMU_JPEG 0x0b10 + +static unsigned long mscl_clk_regs[] __initdata = { + MUX_SEL_MSCL0, + MUX_SEL_MSCL1, + MUX_ENABLE_MSCL0, + MUX_ENABLE_MSCL1, + MUX_STAT_MSCL0, + MUX_STAT_MSCL1, + DIV_MSCL, + DIV_STAT_MSCL, + ENABLE_ACLK_MSCL, + ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER0, + ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER1, + ENABLE_ACLK_MSCL_SECURE_SMMU_JPEG, + ENABLE_PCLK_MSCL, + ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER0, + ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER1, + ENABLE_PCLK_MSCL_SECURE_SMMU_JPEG, + ENABLE_SCLK_MSCL, + ENABLE_IP_MSCL0, + ENABLE_IP_MSCL1, + ENABLE_IP_MSCL_SECURE_SMMU_M2MSCALER0, + ENABLE_IP_MSCL_SECURE_SMMU_M2MSCALER1, + ENABLE_IP_MSCL_SECURE_SMMU_JPEG, +}; + +/* list of all parent clock list */ +PNAME(mout_sclk_jpeg_user_p) = { "oscclk", "sclk_jpeg_mscl", }; +PNAME(mout_aclk_mscl_400_user_p) = { "oscclk", "aclk_mscl_400", }; +PNAME(mout_sclk_jpeg_p) = { "mout_sclk_jpeg_user", + "mout_aclk_mscl_400_user", }; + +static struct samsung_mux_clock mscl_mux_clks[] __initdata = { + /* MUX_SEL_MSCL0 */ + MUX(CLK_MOUT_SCLK_JPEG_USER, "mout_sclk_jpeg_user", + mout_sclk_jpeg_user_p, MUX_SEL_MSCL0, 4, 1), + MUX(CLK_MOUT_ACLK_MSCL_400_USER, "mout_aclk_mscl_400_user", + mout_aclk_mscl_400_user_p, MUX_SEL_MSCL0, 0, 1), + + /* MUX_SEL_MSCL1 */ + MUX(CLK_MOUT_SCLK_JPEG, "mout_sclk_jpeg", mout_sclk_jpeg_p, + MUX_SEL_MSCL1, 0, 1), +}; + +static struct samsung_div_clock mscl_div_clks[] __initdata = { + /* DIV_MSCL */ + DIV(CLK_DIV_PCLK_MSCL, "div_pclk_mscl", "mout_aclk_mscl_400_user", + DIV_MSCL, 0, 3), +}; + +static struct samsung_gate_clock mscl_gate_clks[] __initdata = { + /* ENABLE_ACLK_MSCL */ + GATE(CLK_ACLK_BTS_JPEG, "aclk_bts_jpeg", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL, 9, 0, 0), + GATE(CLK_ACLK_BTS_M2MSCALER1, "aclk_bts_m2mscaler1", + "mout_aclk_mscl_400_user", ENABLE_ACLK_MSCL, 8, 0, 0), + GATE(CLK_ACLK_BTS_M2MSCALER0, "aclk_bts_m2mscaler0", + "mout_aclk_mscl_400_user", ENABLE_ACLK_MSCL, 7, 0, 0), + GATE(CLK_ACLK_AHB2APB_MSCL0P, "aclk_abh2apb_mscl0p", "div_pclk_mscl", + ENABLE_ACLK_MSCL, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_MSCLX, "aclk_xiu_msclx", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MSCLNP_100, "aclk_msclnp_100", "div_pclk_mscl", + ENABLE_ACLK_MSCL, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MSCLND_400, "aclk_msclnd_400", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_JPEG, "aclk_jpeg", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL, 2, 0, 0), + GATE(CLK_ACLK_M2MSCALER1, "aclk_m2mscaler1", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL, 1, 0, 0), + GATE(CLK_ACLK_M2MSCALER0, "aclk_m2mscaler0", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL, 0, 0, 0), + + /* ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER0 */ + GATE(CLK_ACLK_SMMU_M2MSCALER0, "aclk_smmu_m2mscaler0", + "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER0, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER1 */ + GATE(CLK_ACLK_SMMU_M2MSCALER1, "aclk_smmu_m2mscaler1", + "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL_SECURE_SMMU_M2MSCALER1, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_MSCL_SECURE_SMMU_JPEG */ + GATE(CLK_ACLK_SMMU_JPEG, "aclk_smmu_jpeg", "mout_aclk_mscl_400_user", + ENABLE_ACLK_MSCL_SECURE_SMMU_JPEG, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_MSCL */ + GATE(CLK_PCLK_BTS_JPEG, "pclk_bts_jpeg", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 7, 0, 0), + GATE(CLK_PCLK_BTS_M2MSCALER1, "pclk_bts_m2mscaler1", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 6, 0, 0), + GATE(CLK_PCLK_BTS_M2MSCALER0, "pclk_bts_m2mscaler0", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 5, 0, 0), + GATE(CLK_PCLK_PMU_MSCL, "pclk_pmu_mscl", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_MSCL, "pclk_sysreg_mscl", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_JPEG, "pclk_jpeg", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 2, 0, 0), + GATE(CLK_PCLK_M2MSCALER1, "pclk_m2mscaler1", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 1, 0, 0), + GATE(CLK_PCLK_M2MSCALER0, "pclk_m2mscaler0", "div_pclk_mscl", + ENABLE_PCLK_MSCL, 0, 0, 0), + + /* ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER0 */ + GATE(CLK_PCLK_SMMU_M2MSCALER0, "pclk_smmu_m2mscaler0", "div_pclk_mscl", + ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER0, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER1 */ + GATE(CLK_PCLK_SMMU_M2MSCALER1, "pclk_smmu_m2mscaler1", "div_pclk_mscl", + ENABLE_PCLK_MSCL_SECURE_SMMU_M2MSCALER1, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_MSCL_SECURE_SMMU_JPEG */ + GATE(CLK_PCLK_SMMU_JPEG, "pclk_smmu_jpeg", "div_pclk_mscl", + ENABLE_PCLK_MSCL_SECURE_SMMU_JPEG, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_MSCL */ + GATE(CLK_SCLK_JPEG, "sclk_jpeg", "mout_sclk_jpeg", ENABLE_SCLK_MSCL, 0, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), +}; + +static struct samsung_cmu_info mscl_cmu_info __initdata = { + .mux_clks = mscl_mux_clks, + .nr_mux_clks = ARRAY_SIZE(mscl_mux_clks), + .div_clks = mscl_div_clks, + .nr_div_clks = ARRAY_SIZE(mscl_div_clks), + .gate_clks = mscl_gate_clks, + .nr_gate_clks = ARRAY_SIZE(mscl_gate_clks), + .nr_clk_ids = MSCL_NR_CLK, + .clk_regs = mscl_clk_regs, + .nr_clk_regs = ARRAY_SIZE(mscl_clk_regs), +}; + +static void __init exynos5433_cmu_mscl_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &mscl_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_mscl, "samsung,exynos5433-cmu-mscl", + exynos5433_cmu_mscl_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index cdc91f7e6ec8..9898390710e6 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -114,6 +114,8 @@ #define CLK_DIV_SCLK_USBHOST30 141 #define CLK_DIV_SCLK_UFSUNIPRO 142 #define CLK_DIV_SCLK_USBDRD30 143 +#define CLK_DIV_SCLK_JPEG 144 +#define CLK_DIV_ACLK_MSCL_400 145 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -149,8 +151,10 @@ #define CLK_SCLK_USBDRD30_FSYS 231 #define CLK_ACLK_GSCL_111 232 #define CLK_ACLK_GSCL_333 233 +#define CLK_SCLK_JPEG_MSCL 234 +#define CLK_ACLK_MSCL_400 235 -#define TOP_NR_CLK 234 +#define TOP_NR_CLK 236 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -937,4 +941,39 @@ #define ATLAS_NR_CLK 40 +/* CMU_MSCL */ +#define CLK_MOUT_SCLK_JPEG_USER 1 +#define CLK_MOUT_ACLK_MSCL_400_USER 2 +#define CLK_MOUT_SCLK_JPEG 3 + +#define CLK_DIV_PCLK_MSCL 4 + +#define CLK_ACLK_BTS_JPEG 5 +#define CLK_ACLK_BTS_M2MSCALER1 6 +#define CLK_ACLK_BTS_M2MSCALER0 7 +#define CLK_ACLK_AHB2APB_MSCL0P 8 +#define CLK_ACLK_XIU_MSCLX 9 +#define CLK_ACLK_MSCLNP_100 10 +#define CLK_ACLK_MSCLND_400 11 +#define CLK_ACLK_JPEG 12 +#define CLK_ACLK_M2MSCALER1 13 +#define CLK_ACLK_M2MSCALER0 14 +#define CLK_ACLK_SMMU_M2MSCALER0 15 +#define CLK_ACLK_SMMU_M2MSCALER1 16 +#define CLK_ACLK_SMMU_JPEG 17 +#define CLK_PCLK_BTS_JPEG 18 +#define CLK_PCLK_BTS_M2MSCALER1 19 +#define CLK_PCLK_BTS_M2MSCALER0 20 +#define CLK_PCLK_PMU_MSCL 21 +#define CLK_PCLK_SYSREG_MSCL 22 +#define CLK_PCLK_JPEG 23 +#define CLK_PCLK_M2MSCALER1 24 +#define CLK_PCLK_M2MSCALER0 25 +#define CLK_PCLK_SMMU_M2MSCALER0 26 +#define CLK_PCLK_SMMU_M2MSCALER1 27 +#define CLK_PCLK_SMMU_JPEG 28 +#define CLK_SCLK_JPEG 29 + +#define MSCL_NR_CLK 30 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 9910b6bbaa7b16cd3a8a7d8be53980fa1b8183a6 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:52 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_MFC domain This patch adds the mux/divider/gate clocks for CMU_MFC domain which generates the clocks for MFC(Multi-Format Codec) IP. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 15 +++ drivers/clk/samsung/clk-exynos5433.c | 113 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 27 ++++- 3 files changed, 154 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index ecb9534c2ea6..0f35167ec15c 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -39,6 +39,8 @@ Required Properties: L2 cache controller. - "samsung,exynos5433-cmu-mscl" - clock controller compatible for CMU_MSCL which generates clocks for M2M (Memory to Memory) scaler and JPEG IPs. + - "samsung,exynos5433-cmu-mfc" - clock controller compatible for CMU_MFC + which generates clocks for MFC(Multi-Format Codec) IP. - reg: physical base address of the controller and length of memory mapped region. @@ -125,6 +127,10 @@ Required Properties: - sclk_jpeg_mscl - aclk_mscl_400 + Input clocks for mfc clock controller: + - oscclk + - aclk_mfc_400 + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -340,6 +346,15 @@ Example 2: Examples of clock controller nodes are listed below. <&cmu_top CLK_ACLK_MSCL_400>; }; + cmu_mfc: clock-controller@15280000 { + compatible = "samsung,exynos5433-cmu-mfc"; + reg = <0x15280000 0x0b08>; + #clock-cells = <1>; + + clock-names = "oscclk", "aclk_mfc_400"; + clocks = <&xxti>, <&cmu_top CLK_ACLK_MFC_400>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index d272e42eb48c..40558930711f 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -560,6 +560,9 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_GSCL_333, "aclk_gscl_333", "div_aclk_gscl_333", ENABLE_ACLK_TOP, 14, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MFC_400, "aclk_mfc_400", "div_aclk_mfc_400", + ENABLE_ACLK_TOP, 3, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_G2D_266, "aclk_g2d_266", "div_aclk_g2d_266", ENABLE_ACLK_TOP, 2, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -3990,3 +3993,113 @@ static void __init exynos5433_cmu_mscl_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_mscl, "samsung,exynos5433-cmu-mscl", exynos5433_cmu_mscl_init); + +/* + * Register offset definitions for CMU_MFC + */ +#define MUX_SEL_MFC 0x0200 +#define MUX_ENABLE_MFC 0x0300 +#define MUX_STAT_MFC 0x0400 +#define DIV_MFC 0x0600 +#define DIV_STAT_MFC 0x0700 +#define ENABLE_ACLK_MFC 0x0800 +#define ENABLE_ACLK_MFC_SECURE_SMMU_MFC 0x0804 +#define ENABLE_PCLK_MFC 0x0900 +#define ENABLE_PCLK_MFC_SECURE_SMMU_MFC 0x0904 +#define ENABLE_IP_MFC0 0x0b00 +#define ENABLE_IP_MFC1 0x0b04 +#define ENABLE_IP_MFC_SECURE_SMMU_MFC 0x0b08 + +static unsigned long mfc_clk_regs[] __initdata = { + MUX_SEL_MFC, + MUX_ENABLE_MFC, + MUX_STAT_MFC, + DIV_MFC, + DIV_STAT_MFC, + ENABLE_ACLK_MFC, + ENABLE_ACLK_MFC_SECURE_SMMU_MFC, + ENABLE_PCLK_MFC, + ENABLE_PCLK_MFC_SECURE_SMMU_MFC, + ENABLE_IP_MFC0, + ENABLE_IP_MFC1, + ENABLE_IP_MFC_SECURE_SMMU_MFC, +}; + +PNAME(mout_aclk_mfc_400_user_p) = { "oscclk", "aclk_mfc_400", }; + +static struct samsung_mux_clock mfc_mux_clks[] __initdata = { + /* MUX_SEL_MFC */ + MUX(CLK_MOUT_ACLK_MFC_400_USER, "mout_aclk_mfc_400_user", + mout_aclk_mfc_400_user_p, MUX_SEL_MFC, 0, 0), +}; + +static struct samsung_div_clock mfc_div_clks[] __initdata = { + /* DIV_MFC */ + DIV(CLK_DIV_PCLK_MFC, "div_pclk_mfc", "mout_aclk_mfc_400_user", + DIV_MFC, 0, 2), +}; + +static struct samsung_gate_clock mfc_gate_clks[] __initdata = { + /* ENABLE_ACLK_MFC */ + GATE(CLK_ACLK_BTS_MFC_1, "aclk_bts_mfc_1", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC, 6, 0, 0), + GATE(CLK_ACLK_BTS_MFC_0, "aclk_bts_mfc_0", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC, 5, 0, 0), + GATE(CLK_ACLK_AHB2APB_MFCP, "aclk_ahb2apb_mfcp", "div_pclk_mfc", + ENABLE_ACLK_MFC, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_MFCX, "aclk_xiu_mfcx", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MFCNP_100, "aclk_mfcnp_100", "div_pclk_mfc", + ENABLE_ACLK_MFC, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MFCND_400, "aclk_mfcnd_400", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_MFC, "aclk_mfc", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC, 0, 0, 0), + + /* ENABLE_ACLK_MFC_SECURE_SMMU_MFC */ + GATE(CLK_ACLK_SMMU_MFC_1, "aclk_smmu_mfc_1", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC_SECURE_SMMU_MFC, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_MFC_0, "aclk_smmu_mfc_0", "mout_aclk_mfc_400_user", + ENABLE_ACLK_MFC_SECURE_SMMU_MFC, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_MFC */ + GATE(CLK_PCLK_BTS_MFC_1, "pclk_bts_mfc_1", "div_pclk_mfc", + ENABLE_PCLK_MFC, 4, 0, 0), + GATE(CLK_PCLK_BTS_MFC_0, "pclk_bts_mfc_0", "div_pclk_mfc", + ENABLE_PCLK_MFC, 3, 0, 0), + GATE(CLK_PCLK_PMU_MFC, "pclk_pmu_mfc", "div_pclk_mfc", + ENABLE_PCLK_MFC, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_MFC, "pclk_sysreg_mfc", "div_pclk_mfc", + ENABLE_PCLK_MFC, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_MFC, "pclk_mfc", "div_pclk_mfc", + ENABLE_PCLK_MFC, 4, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_MFC_SECURE_SMMU_MFC */ + GATE(CLK_PCLK_SMMU_MFC_1, "pclk_smmu_mfc_1", "div_pclk_mfc", + ENABLE_PCLK_MFC_SECURE_SMMU_MFC, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_MFC_0, "pclk_smmu_mfc_0", "div_pclk_mfc", + ENABLE_PCLK_MFC_SECURE_SMMU_MFC, + 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info mfc_cmu_info __initdata = { + .mux_clks = mfc_mux_clks, + .nr_mux_clks = ARRAY_SIZE(mfc_mux_clks), + .div_clks = mfc_div_clks, + .nr_div_clks = ARRAY_SIZE(mfc_div_clks), + .gate_clks = mfc_gate_clks, + .nr_gate_clks = ARRAY_SIZE(mfc_gate_clks), + .nr_clk_ids = MFC_NR_CLK, + .clk_regs = mfc_clk_regs, + .nr_clk_regs = ARRAY_SIZE(mfc_clk_regs), +}; + +static void __init exynos5433_cmu_mfc_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &mfc_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_mfc, "samsung,exynos5433-cmu-mfc", + exynos5433_cmu_mfc_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 9898390710e6..3301ab72c80d 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -153,8 +153,9 @@ #define CLK_ACLK_GSCL_333 233 #define CLK_SCLK_JPEG_MSCL 234 #define CLK_ACLK_MSCL_400 235 +#define CLK_ACLK_MFC_400 236 -#define TOP_NR_CLK 236 +#define TOP_NR_CLK 237 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -976,4 +977,28 @@ #define MSCL_NR_CLK 30 +/* CMU_MFC */ +#define CLK_MOUT_ACLK_MFC_400_USER 1 + +#define CLK_DIV_PCLK_MFC 2 + +#define CLK_ACLK_BTS_MFC_1 3 +#define CLK_ACLK_BTS_MFC_0 4 +#define CLK_ACLK_AHB2APB_MFCP 5 +#define CLK_ACLK_XIU_MFCX 6 +#define CLK_ACLK_MFCNP_100 7 +#define CLK_ACLK_MFCND_400 8 +#define CLK_ACLK_MFC 9 +#define CLK_ACLK_SMMU_MFC_1 10 +#define CLK_ACLK_SMMU_MFC_0 11 +#define CLK_PCLK_BTS_MFC_1 12 +#define CLK_PCLK_BTS_MFC_0 13 +#define CLK_PCLK_PMU_MFC 14 +#define CLK_PCLK_SYSREG_MFC 15 +#define CLK_PCLK_MFC 16 +#define CLK_PCLK_SMMU_MFC_1 17 +#define CLK_PCLK_SMMU_MFC_0 18 + +#define MFC_NR_CLK 19 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 45e58aa5f751fd861d46f7b6d438c1be147458c6 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:53 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_HEVC domain This patch adds the mux/divider/gate clocks for CMU_HEVC domain which generates the clocks for HEVC(High Efficiency Video Codec) decoder IP. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 15 +++ drivers/clk/samsung/clk-exynos5433.c | 115 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 27 ++++- 3 files changed, 156 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 0f35167ec15c..acc1d8aac95c 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -41,6 +41,8 @@ Required Properties: which generates clocks for M2M (Memory to Memory) scaler and JPEG IPs. - "samsung,exynos5433-cmu-mfc" - clock controller compatible for CMU_MFC which generates clocks for MFC(Multi-Format Codec) IP. + - "samsung,exynos5433-cmu-hevc" - clock controller compatible for CMU_HEVC + which generates clocks for HEVC(High Efficiency Video Codec) decoder IP. - reg: physical base address of the controller and length of memory mapped region. @@ -131,6 +133,10 @@ Required Properties: - oscclk - aclk_mfc_400 + Input clocks for hevc clock controller: + - oscclk + - aclk_hevc_400 + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -355,6 +361,15 @@ Example 2: Examples of clock controller nodes are listed below. clocks = <&xxti>, <&cmu_top CLK_ACLK_MFC_400>; }; + cmu_hevc: clock-controller@14f80000 { + compatible = "samsung,exynos5433-cmu-hevc"; + reg = <0x14f80000 0x0b08>; + #clock-cells = <1>; + + clock-names = "oscclk", "aclk_hevc_400"; + clocks = <&xxti>, <&cmu_top CLK_ACLK_HEVC_400>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 40558930711f..482a603c7e6b 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -560,6 +560,9 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_GSCL_333, "aclk_gscl_333", "div_aclk_gscl_333", ENABLE_ACLK_TOP, 14, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_HEVC_400, "aclk_hevc_400", "div_aclk_hevc_400", + ENABLE_ACLK_TOP, 5, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_MFC_400, "aclk_mfc_400", "div_aclk_mfc_400", ENABLE_ACLK_TOP, 3, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -4103,3 +4106,115 @@ static void __init exynos5433_cmu_mfc_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_mfc, "samsung,exynos5433-cmu-mfc", exynos5433_cmu_mfc_init); + +/* + * Register offset definitions for CMU_HEVC + */ +#define MUX_SEL_HEVC 0x0200 +#define MUX_ENABLE_HEVC 0x0300 +#define MUX_STAT_HEVC 0x0400 +#define DIV_HEVC 0x0600 +#define DIV_STAT_HEVC 0x0700 +#define ENABLE_ACLK_HEVC 0x0800 +#define ENABLE_ACLK_HEVC_SECURE_SMMU_HEVC 0x0804 +#define ENABLE_PCLK_HEVC 0x0900 +#define ENABLE_PCLK_HEVC_SECURE_SMMU_HEVC 0x0904 +#define ENABLE_IP_HEVC0 0x0b00 +#define ENABLE_IP_HEVC1 0x0b04 +#define ENABLE_IP_HEVC_SECURE_SMMU_HEVC 0x0b08 + +static unsigned long hevc_clk_regs[] __initdata = { + MUX_SEL_HEVC, + MUX_ENABLE_HEVC, + MUX_STAT_HEVC, + DIV_HEVC, + DIV_STAT_HEVC, + ENABLE_ACLK_HEVC, + ENABLE_ACLK_HEVC_SECURE_SMMU_HEVC, + ENABLE_PCLK_HEVC, + ENABLE_PCLK_HEVC_SECURE_SMMU_HEVC, + ENABLE_IP_HEVC0, + ENABLE_IP_HEVC1, + ENABLE_IP_HEVC_SECURE_SMMU_HEVC, +}; + +PNAME(mout_aclk_hevc_400_user_p) = { "oscclk", "aclk_hevc_400", }; + +static struct samsung_mux_clock hevc_mux_clks[] __initdata = { + /* MUX_SEL_HEVC */ + MUX(CLK_MOUT_ACLK_HEVC_400_USER, "mout_aclk_hevc_400_user", + mout_aclk_hevc_400_user_p, MUX_SEL_HEVC, 0, 0), +}; + +static struct samsung_div_clock hevc_div_clks[] __initdata = { + /* DIV_HEVC */ + DIV(CLK_DIV_PCLK_HEVC, "div_pclk_hevc", "mout_aclk_hevc_400_user", + DIV_HEVC, 0, 2), +}; + +static struct samsung_gate_clock hevc_gate_clks[] __initdata = { + /* ENABLE_ACLK_HEVC */ + GATE(CLK_ACLK_BTS_HEVC_1, "aclk_bts_hevc_1", "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC, 6, 0, 0), + GATE(CLK_ACLK_BTS_HEVC_0, "aclk_bts_hevc_0", "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC, 5, 0, 0), + GATE(CLK_ACLK_AHB2APB_HEVCP, "aclk_ahb2apb_hevcp", "div_pclk_hevc", + ENABLE_ACLK_HEVC, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_HEVCX, "aclk_xiu_hevcx", "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_HEVCNP_100, "aclk_hevcnp_100", "div_pclk_hevc", + ENABLE_ACLK_HEVC, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_HEVCND_400, "aclk_hevcnd_400", "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_HEVC, "aclk_hevc", "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC, 0, 0, 0), + + /* ENABLE_ACLK_HEVC_SECURE_SMMU_HEVC */ + GATE(CLK_ACLK_SMMU_HEVC_1, "aclk_smmu_hevc_1", + "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC_SECURE_SMMU_HEVC, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_HEVC_0, "aclk_smmu_hevc_0", + "mout_aclk_hevc_400_user", + ENABLE_ACLK_HEVC_SECURE_SMMU_HEVC, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_HEVC */ + GATE(CLK_PCLK_BTS_HEVC_1, "pclk_bts_hevc_1", "div_pclk_hevc", + ENABLE_PCLK_HEVC, 4, 0, 0), + GATE(CLK_PCLK_BTS_HEVC_0, "pclk_bts_hevc_0", "div_pclk_hevc", + ENABLE_PCLK_HEVC, 3, 0, 0), + GATE(CLK_PCLK_PMU_HEVC, "pclk_pmu_hevc", "div_pclk_hevc", + ENABLE_PCLK_HEVC, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_HEVC, "pclk_sysreg_hevc", "div_pclk_hevc", + ENABLE_PCLK_HEVC, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_HEVC, "pclk_hevc", "div_pclk_hevc", + ENABLE_PCLK_HEVC, 4, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_HEVC_SECURE_SMMU_HEVC */ + GATE(CLK_PCLK_SMMU_HEVC_1, "pclk_smmu_hevc_1", "div_pclk_hevc", + ENABLE_PCLK_HEVC_SECURE_SMMU_HEVC, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_HEVC_0, "pclk_smmu_hevc_0", "div_pclk_hevc", + ENABLE_PCLK_HEVC_SECURE_SMMU_HEVC, + 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info hevc_cmu_info __initdata = { + .mux_clks = hevc_mux_clks, + .nr_mux_clks = ARRAY_SIZE(hevc_mux_clks), + .div_clks = hevc_div_clks, + .nr_div_clks = ARRAY_SIZE(hevc_div_clks), + .gate_clks = hevc_gate_clks, + .nr_gate_clks = ARRAY_SIZE(hevc_gate_clks), + .nr_clk_ids = HEVC_NR_CLK, + .clk_regs = hevc_clk_regs, + .nr_clk_regs = ARRAY_SIZE(hevc_clk_regs), +}; + +static void __init exynos5433_cmu_hevc_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &hevc_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_hevc, "samsung,exynos5433-cmu-hevc", + exynos5433_cmu_hevc_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 3301ab72c80d..1b2d333c1786 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -154,8 +154,9 @@ #define CLK_SCLK_JPEG_MSCL 234 #define CLK_ACLK_MSCL_400 235 #define CLK_ACLK_MFC_400 236 +#define CLK_ACLK_HEVC_400 237 -#define TOP_NR_CLK 237 +#define TOP_NR_CLK 238 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -1001,4 +1002,28 @@ #define MFC_NR_CLK 19 +/* CMU_HEVC */ +#define CLK_MOUT_ACLK_HEVC_400_USER 1 + +#define CLK_DIV_PCLK_HEVC 2 + +#define CLK_ACLK_BTS_HEVC_1 3 +#define CLK_ACLK_BTS_HEVC_0 4 +#define CLK_ACLK_AHB2APB_HEVCP 5 +#define CLK_ACLK_XIU_HEVCX 6 +#define CLK_ACLK_HEVCNP_100 7 +#define CLK_ACLK_HEVCND_400 8 +#define CLK_ACLK_HEVC 9 +#define CLK_ACLK_SMMU_HEVC_1 10 +#define CLK_ACLK_SMMU_HEVC_0 11 +#define CLK_PCLK_BTS_HEVC_1 12 +#define CLK_PCLK_BTS_HEVC_0 13 +#define CLK_PCLK_PMU_HEVC 14 +#define CLK_PCLK_SYSREG_HEVC 15 +#define CLK_PCLK_HEVC 16 +#define CLK_PCLK_SMMU_HEVC_1 17 +#define CLK_PCLK_SMMU_HEVC_0 18 + +#define HEVC_NR_CLK 19 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 8e46c4b84faf317773d5a4ec6d807ceae2d0eb41 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:54 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_ISP domain This patch adds the mux/divider/gate clocks for CMU_ISP domain which generates the clocks for FIMC-ISP/DRC/SCLC/DIS/3DNR IPs. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 20 ++ drivers/clk/samsung/clk-exynos5433.c | 267 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 89 ++++++- 3 files changed, 375 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index acc1d8aac95c..4f3bfcd366a3 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -43,6 +43,8 @@ Required Properties: which generates clocks for MFC(Multi-Format Codec) IP. - "samsung,exynos5433-cmu-hevc" - clock controller compatible for CMU_HEVC which generates clocks for HEVC(High Efficiency Video Codec) decoder IP. + - "samsung,exynos5433-cmu-isp" - clock controller compatible for CMU_ISP + which generates clocks for FIMC-ISP/DRC/SCLC/DIS/3DNR IPs. - reg: physical base address of the controller and length of memory mapped region. @@ -137,6 +139,11 @@ Required Properties: - oscclk - aclk_hevc_400 + Input clocks for isp clock controller: + - oscclk + - aclk_isp_dis_400 + - aclk_isp_400 + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -370,6 +377,19 @@ Example 2: Examples of clock controller nodes are listed below. clocks = <&xxti>, <&cmu_top CLK_ACLK_HEVC_400>; }; + cmu_isp: clock-controller@146d0000 { + compatible = "samsung,exynos5433-cmu-isp"; + reg = <0x146d0000 0x0b0c>; + #clock-cells = <1>; + + clock-names = "oscclk", + "aclk_isp_dis_400", + "aclk_isp_400"; + clocks = <&xxti>, + <&cmu_top CLK_ACLK_ISP_DIS_400>, + <&cmu_top CLK_ACLK_ISP_400>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 482a603c7e6b..a8ea6e1fbffc 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -404,6 +404,12 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { }; static struct samsung_div_clock top_div_clks[] __initdata = { + /* DIV_TOP0 */ + DIV(CLK_DIV_ACLK_ISP_DIS_400, "div_aclk_isp_dis_400", + "mout_aclk_isp_dis_400", DIV_TOP0, 4, 4), + DIV(CLK_DIV_ACLK_ISP_400, "div_aclk_isp_400", + "mout_aclk_isp_400", DIV_TOP0, 0, 4), + /* DIV_TOP1 */ DIV(CLK_DIV_ACLK_GSCL_111, "div_aclk_gscl_111", "mout_aclk_gscl_333", DIV_TOP1, 28, 3), @@ -560,6 +566,12 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_GSCL_333, "aclk_gscl_333", "div_aclk_gscl_333", ENABLE_ACLK_TOP, 14, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ISP_DIS_400, "aclk_isp_dis_400", "div_aclk_isp_dis_400", + ENABLE_ACLK_TOP, 7, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ISP_400, "aclk_isp_400", "div_aclk_isp_400", + ENABLE_ACLK_TOP, 6, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_HEVC_400, "aclk_hevc_400", "div_aclk_hevc_400", ENABLE_ACLK_TOP, 5, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -4218,3 +4230,258 @@ static void __init exynos5433_cmu_hevc_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_hevc, "samsung,exynos5433-cmu-hevc", exynos5433_cmu_hevc_init); + +/* + * Register offset definitions for CMU_ISP + */ +#define MUX_SEL_ISP 0x0200 +#define MUX_ENABLE_ISP 0x0300 +#define MUX_STAT_ISP 0x0400 +#define DIV_ISP 0x0600 +#define DIV_STAT_ISP 0x0700 +#define ENABLE_ACLK_ISP0 0x0800 +#define ENABLE_ACLK_ISP1 0x0804 +#define ENABLE_ACLK_ISP2 0x0808 +#define ENABLE_PCLK_ISP 0x0900 +#define ENABLE_SCLK_ISP 0x0a00 +#define ENABLE_IP_ISP0 0x0b00 +#define ENABLE_IP_ISP1 0x0b04 +#define ENABLE_IP_ISP2 0x0b08 +#define ENABLE_IP_ISP3 0x0b0c + +static unsigned long isp_clk_regs[] __initdata = { + MUX_SEL_ISP, + MUX_ENABLE_ISP, + MUX_STAT_ISP, + DIV_ISP, + DIV_STAT_ISP, + ENABLE_ACLK_ISP0, + ENABLE_ACLK_ISP1, + ENABLE_ACLK_ISP2, + ENABLE_PCLK_ISP, + ENABLE_SCLK_ISP, + ENABLE_IP_ISP0, + ENABLE_IP_ISP1, + ENABLE_IP_ISP2, + ENABLE_IP_ISP3, +}; + +PNAME(mout_aclk_isp_dis_400_user_p) = { "oscclk", "aclk_isp_dis_400", }; +PNAME(mout_aclk_isp_400_user_p) = { "oscclk", "aclk_isp_400", }; + +static struct samsung_mux_clock isp_mux_clks[] __initdata = { + /* MUX_SEL_ISP */ + MUX(CLK_MOUT_ACLK_ISP_DIS_400_USER, "mout_aclk_isp_dis_400_user", + mout_aclk_isp_dis_400_user_p, MUX_SEL_ISP, 4, 0), + MUX(CLK_MOUT_ACLK_ISP_400_USER, "mout_aclk_isp_400_user", + mout_aclk_isp_400_user_p, MUX_SEL_ISP, 0, 0), +}; + +static struct samsung_div_clock isp_div_clks[] __initdata = { + /* DIV_ISP */ + DIV(CLK_DIV_PCLK_ISP_DIS, "div_pclk_isp_dis", + "mout_aclk_isp_dis_400_user", DIV_ISP, 12, 3), + DIV(CLK_DIV_PCLK_ISP, "div_pclk_isp", "mout_aclk_isp_400_user", + DIV_ISP, 8, 3), + DIV(CLK_DIV_ACLK_ISP_D_200, "div_aclk_isp_d_200", + "mout_aclk_isp_400_user", DIV_ISP, 4, 3), + DIV(CLK_DIV_ACLK_ISP_C_200, "div_aclk_isp_c_200", + "mout_aclk_isp_400_user", DIV_ISP, 0, 3), +}; + +static struct samsung_gate_clock isp_gate_clks[] __initdata = { + /* ENABLE_ACLK_ISP0 */ + GATE(CLK_ACLK_ISP_D_GLUE, "aclk_isp_d_glue", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP0, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SCALERP, "aclk_scalerp", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP0, 5, 0, 0), + GATE(CLK_ACLK_3DNR, "aclk_3dnr", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP0, 4, 0, 0), + GATE(CLK_ACLK_DIS, "aclk_dis", "mout_aclk_isp_dis_400_user", + ENABLE_ACLK_ISP0, 3, 0, 0), + GATE(CLK_ACLK_SCALERC, "aclk_scalerc", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP0, 2, 0, 0), + GATE(CLK_ACLK_DRC, "aclk_drc", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP0, 1, 0, 0), + GATE(CLK_ACLK_ISP, "aclk_isp", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP0, 0, 0, 0), + + /* ENABLE_ACLK_ISP1 */ + GATE(CLK_ACLK_AXIUS_SCALERP, "aclk_axius_scalerp", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP1, + 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_SCALERC, "aclk_axius_scalerc", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP1, + 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_DRC, "aclk_axius_drc", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP1, + 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAHBM_ISP2P, "aclk_asyncahbm_isp2p", + "div_pclk_isp", ENABLE_ACLK_ISP1, + 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAHBM_ISP1P, "aclk_asyncahbm_isp1p", + "div_pclk_isp", ENABLE_ACLK_ISP1, + 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DIS1, "aclk_asyncaxis_dis1", + "mout_aclk_isp_dis_400_user", ENABLE_ACLK_ISP1, + 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_DIS0, "aclk_asyncaxis_dis0", + "mout_aclk_isp_dis_400_user", ENABLE_ACLK_ISP1, + 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DIS1, "aclk_asyncaxim_dis1", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP1, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_DIS0, "aclk_asyncaxim_dis0", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP1, + 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_ISP2P, "aclk_asyncaxim_isp2p", + "div_aclk_isp_d_200", ENABLE_ACLK_ISP1, + 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_ISP1P, "aclk_asyncaxim_isp1p", + "div_aclk_isp_c_200", ENABLE_ACLK_ISP1, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_ISP2P, "aclk_ahb2apb_isp2p", "div_pclk_isp", + ENABLE_ACLK_ISP1, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_ISP1P, "aclk_ahb2apb_isp1p", "div_pclk_isp", + ENABLE_ACLK_ISP1, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI2APB_ISP2P, "aclk_axi2apb_isp2p", + "div_aclk_isp_d_200", ENABLE_ACLK_ISP1, + 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI2APB_ISP1P, "aclk_axi2apb_isp1p", + "div_aclk_isp_c_200", ENABLE_ACLK_ISP1, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_ISPEX1, "aclk_xiu_ispex1", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP1, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_ISPEX0, "aclk_xiu_ispex0", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP1, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ISPND_400, "aclk_ispnd_400", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP1, 1, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_ISP2 */ + GATE(CLK_ACLK_SMMU_SCALERP, "aclk_smmu_scalerp", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP2, + 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_3DNR, "aclk_smmu_3dnr", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_DIS1, "aclk_smmu_dis1", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_DIS0, "aclk_smmu_dis0", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_SCALERC, "aclk_smmu_scalerc", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP2, + 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_DRC, "aclk_smmu_drc", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_ISP, "aclk_smmu_isp", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_SCALERP, "aclk_bts_scalerp", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP2, + 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_3DR, "aclk_bts_3dnr", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_DIS1, "aclk_bts_dis1", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_DIS0, "aclk_bts_dis0", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_SCALERC, "aclk_bts_scalerc", + "mout_aclk_isp_400_user", ENABLE_ACLK_ISP2, + 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_DRC, "aclk_bts_drc", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_ISP, "aclk_bts_isp", "mout_aclk_isp_400_user", + ENABLE_ACLK_ISP2, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_ISP */ + GATE(CLK_PCLK_SMMU_SCALERP, "pclk_smmu_scalerp", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_3DNR, "pclk_smmu_3dnr", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_DIS1, "pclk_smmu_dis1", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_DIS0, "pclk_smmu_dis0", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_SCALERC, "pclk_smmu_scalerc", "div_aclk_isp_c_200", + ENABLE_PCLK_ISP, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_DRC, "pclk_smmu_drc", "div_aclk_isp_c_200", + ENABLE_PCLK_ISP, 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_ISP, "pclk_smmu_isp", "div_aclk_isp_c_200", + ENABLE_PCLK_ISP, 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_SCALERP, "pclk_bts_scalerp", "div_pclk_isp", + ENABLE_PCLK_ISP, 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_3DNR, "pclk_bts_3dnr", "div_pclk_isp", + ENABLE_PCLK_ISP, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_DIS1, "pclk_bts_dis1", "div_pclk_isp", + ENABLE_PCLK_ISP, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_DIS0, "pclk_bts_dis0", "div_pclk_isp", + ENABLE_PCLK_ISP, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_SCALERC, "pclk_bts_scalerc", "div_pclk_isp", + ENABLE_PCLK_ISP, 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_DRC, "pclk_bts_drc", "div_pclk_isp", + ENABLE_PCLK_ISP, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_ISP, "pclk_bts_isp", "div_pclk_isp", + ENABLE_PCLK_ISP, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_DIS1, "pclk_asyncaxi_dis1", "div_pclk_isp", + ENABLE_PCLK_ISP, 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_DIS0, "pclk_asyncaxi_dis0", "div_pclk_isp", + ENABLE_PCLK_ISP, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_ISP, "pclk_pmu_isp", "div_pclk_isp", + ENABLE_PCLK_ISP, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_ISP, "pclk_sysreg_isp", "div_pclk_isp", + ENABLE_PCLK_ISP, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_CMU_ISP_LOCAL, "pclk_cmu_isp_local", + "div_aclk_isp_c_200", ENABLE_PCLK_ISP, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SCALERP, "pclk_scalerp", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_3DNR, "pclk_3dnr", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DIS_CORE, "pclk_dis_core", "div_pclk_isp_dis", + ENABLE_PCLK_ISP, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DIS, "pclk_dis", "div_aclk_isp_d_200", + ENABLE_PCLK_ISP, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SCALERC, "pclk_scalerc", "div_aclk_isp_c_200", + ENABLE_PCLK_ISP, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_DRC, "pclk_drc", "div_aclk_isp_c_200", + ENABLE_PCLK_ISP, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP, "pclk_isp", "div_aclk_isp_c_200", + ENABLE_PCLK_ISP, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_ISP */ + GATE(CLK_SCLK_PIXELASYNCS_DIS, "sclk_pixelasyncs_dis", + "mout_aclk_isp_dis_400_user", ENABLE_SCLK_ISP, + 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_PIXELASYNCM_DIS, "sclk_pixelasyncm_dis", + "mout_aclk_isp_dis_400_user", ENABLE_SCLK_ISP, + 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_PIXELASYNCS_SCALERP, "sclk_pixelasyncs_scalerp", + "mout_aclk_isp_400_user", ENABLE_SCLK_ISP, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_PIXELASYNCM_ISPD, "sclk_pixelasyncm_ispd", + "mout_aclk_isp_400_user", ENABLE_SCLK_ISP, + 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_PIXELASYNCS_ISPC, "sclk_pixelasyncs_ispc", + "mout_aclk_isp_400_user", ENABLE_SCLK_ISP, + 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCLK_PIXELASYNCM_ISPC, "sclk_pixelasyncm_ispc", + "mout_aclk_isp_400_user", ENABLE_SCLK_ISP, + 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info isp_cmu_info __initdata = { + .mux_clks = isp_mux_clks, + .nr_mux_clks = ARRAY_SIZE(isp_mux_clks), + .div_clks = isp_div_clks, + .nr_div_clks = ARRAY_SIZE(isp_div_clks), + .gate_clks = isp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(isp_gate_clks), + .nr_clk_ids = ISP_NR_CLK, + .clk_regs = isp_clk_regs, + .nr_clk_regs = ARRAY_SIZE(isp_clk_regs), +}; + +static void __init exynos5433_cmu_isp_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &isp_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_isp, "samsung,exynos5433-cmu-isp", + exynos5433_cmu_isp_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 1b2d333c1786..fbc81e3424a6 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -116,6 +116,8 @@ #define CLK_DIV_SCLK_USBDRD30 143 #define CLK_DIV_SCLK_JPEG 144 #define CLK_DIV_ACLK_MSCL_400 145 +#define CLK_DIV_ACLK_ISP_DIS_400 146 +#define CLK_DIV_ACLK_ISP_400 147 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -155,8 +157,10 @@ #define CLK_ACLK_MSCL_400 235 #define CLK_ACLK_MFC_400 236 #define CLK_ACLK_HEVC_400 237 +#define CLK_ACLK_ISP_DIS_400 238 +#define CLK_ACLK_ISP_400 239 -#define TOP_NR_CLK 238 +#define TOP_NR_CLK 240 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -1026,4 +1030,87 @@ #define HEVC_NR_CLK 19 +/* CMU_ISP */ +#define CLK_MOUT_ACLK_ISP_DIS_400_USER 1 +#define CLK_MOUT_ACLK_ISP_400_USER 2 + +#define CLK_DIV_PCLK_ISP_DIS 3 +#define CLK_DIV_PCLK_ISP 4 +#define CLK_DIV_ACLK_ISP_D_200 5 +#define CLK_DIV_ACLK_ISP_C_200 6 + +#define CLK_ACLK_ISP_D_GLUE 7 +#define CLK_ACLK_SCALERP 8 +#define CLK_ACLK_3DNR 9 +#define CLK_ACLK_DIS 10 +#define CLK_ACLK_SCALERC 11 +#define CLK_ACLK_DRC 12 +#define CLK_ACLK_ISP 13 +#define CLK_ACLK_AXIUS_SCALERP 14 +#define CLK_ACLK_AXIUS_SCALERC 15 +#define CLK_ACLK_AXIUS_DRC 16 +#define CLK_ACLK_ASYNCAHBM_ISP2P 17 +#define CLK_ACLK_ASYNCAHBM_ISP1P 18 +#define CLK_ACLK_ASYNCAXIS_DIS1 19 +#define CLK_ACLK_ASYNCAXIS_DIS0 20 +#define CLK_ACLK_ASYNCAXIM_DIS1 21 +#define CLK_ACLK_ASYNCAXIM_DIS0 22 +#define CLK_ACLK_ASYNCAXIM_ISP2P 23 +#define CLK_ACLK_ASYNCAXIM_ISP1P 24 +#define CLK_ACLK_AHB2APB_ISP2P 25 +#define CLK_ACLK_AHB2APB_ISP1P 26 +#define CLK_ACLK_AXI2APB_ISP2P 27 +#define CLK_ACLK_AXI2APB_ISP1P 28 +#define CLK_ACLK_XIU_ISPEX1 29 +#define CLK_ACLK_XIU_ISPEX0 30 +#define CLK_ACLK_ISPND_400 31 +#define CLK_ACLK_SMMU_SCALERP 32 +#define CLK_ACLK_SMMU_3DNR 33 +#define CLK_ACLK_SMMU_DIS1 34 +#define CLK_ACLK_SMMU_DIS0 35 +#define CLK_ACLK_SMMU_SCALERC 36 +#define CLK_ACLK_SMMU_DRC 37 +#define CLK_ACLK_SMMU_ISP 38 +#define CLK_ACLK_BTS_SCALERP 39 +#define CLK_ACLK_BTS_3DR 40 +#define CLK_ACLK_BTS_DIS1 41 +#define CLK_ACLK_BTS_DIS0 42 +#define CLK_ACLK_BTS_SCALERC 43 +#define CLK_ACLK_BTS_DRC 44 +#define CLK_ACLK_BTS_ISP 45 +#define CLK_PCLK_SMMU_SCALERP 46 +#define CLK_PCLK_SMMU_3DNR 47 +#define CLK_PCLK_SMMU_DIS1 48 +#define CLK_PCLK_SMMU_DIS0 49 +#define CLK_PCLK_SMMU_SCALERC 50 +#define CLK_PCLK_SMMU_DRC 51 +#define CLK_PCLK_SMMU_ISP 52 +#define CLK_PCLK_BTS_SCALERP 53 +#define CLK_PCLK_BTS_3DNR 54 +#define CLK_PCLK_BTS_DIS1 55 +#define CLK_PCLK_BTS_DIS0 56 +#define CLK_PCLK_BTS_SCALERC 57 +#define CLK_PCLK_BTS_DRC 58 +#define CLK_PCLK_BTS_ISP 59 +#define CLK_PCLK_ASYNCAXI_DIS1 60 +#define CLK_PCLK_ASYNCAXI_DIS0 61 +#define CLK_PCLK_PMU_ISP 62 +#define CLK_PCLK_SYSREG_ISP 63 +#define CLK_PCLK_CMU_ISP_LOCAL 64 +#define CLK_PCLK_SCALERP 65 +#define CLK_PCLK_3DNR 66 +#define CLK_PCLK_DIS_CORE 67 +#define CLK_PCLK_DIS 68 +#define CLK_PCLK_SCALERC 69 +#define CLK_PCLK_DRC 70 +#define CLK_PCLK_ISP 71 +#define CLK_SCLK_PIXELASYNCS_DIS 72 +#define CLK_SCLK_PIXELASYNCM_DIS 73 +#define CLK_SCLK_PIXELASYNCS_SCALERP 74 +#define CLK_SCLK_PIXELASYNCM_ISPD 75 +#define CLK_SCLK_PIXELASYNCS_ISPC 76 +#define CLK_SCLK_PIXELASYNCM_ISPC 77 + +#define ISP_NR_CLK 78 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 6958f22f39f9292f6e871b4383a11f183c1271ed Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:55 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_CAM0 domain This patch adds the mux/divider/gate clocks for CMU_CAM0 domain which generates the clocks for MIPI_CSIS{0|1}/FIMC_LITE_{A|B|D}/FIMC_3AA{0|1} IPs. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 24 + drivers/clk/samsung/clk-exynos5433.c | 501 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 146 +++++- 3 files changed, 670 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 4f3bfcd366a3..84002e4b52e5 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -45,6 +45,9 @@ Required Properties: which generates clocks for HEVC(High Efficiency Video Codec) decoder IP. - "samsung,exynos5433-cmu-isp" - clock controller compatible for CMU_ISP which generates clocks for FIMC-ISP/DRC/SCLC/DIS/3DNR IPs. + - "samsung,exynos5433-cmu-cam0" - clock controller compatible for CMU_CAM0 + which generates clocks for MIPI_CSIS{0|1}/FIMC_LITE_{A|B|D}/FIMC_3AA{0|1} + IPs. - reg: physical base address of the controller and length of memory mapped region. @@ -144,6 +147,12 @@ Required Properties: - aclk_isp_dis_400 - aclk_isp_400 + Input clocks for cam0 clock controller: + - oscclk + - aclk_cam0_333 + - aclk_cam0_400 + - aclk_cam0_552 + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -390,6 +399,21 @@ Example 2: Examples of clock controller nodes are listed below. <&cmu_top CLK_ACLK_ISP_400>; }; + cmu_cam0: clock-controller@120d0000 { + compatible = "samsung,exynos5433-cmu-cam0"; + reg = <0x120d0000 0x0b0c>; + #clock-cells = <1>; + + clock-names = "oscclk", + "aclk_cam0_333", + "aclk_cam0_400", + "aclk_cam0_552"; + clocks = <&xxti>, + <&cmu_top CLK_ACLK_CAM0_333>, + <&cmu_top CLK_ACLK_CAM0_400>, + <&cmu_top CLK_ACLK_CAM0_552>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index a8ea6e1fbffc..ce6487375670 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -405,6 +405,12 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { static struct samsung_div_clock top_div_clks[] __initdata = { /* DIV_TOP0 */ + DIV(CLK_DIV_ACLK_CAM0_333, "div_aclk_cam0_333", "mout_mfc_pll_user", + DIV_TOP0, 16, 3), + DIV(CLK_DIV_ACLK_CAM0_400, "div_aclk_cam0_400", "mout_bus_pll_user", + DIV_TOP0, 12, 3), + DIV(CLK_DIV_ACLK_CAM0_552, "div_aclk_cam0_552", "mout_isp_pll", + DIV_TOP0, 8, 3), DIV(CLK_DIV_ACLK_ISP_DIS_400, "div_aclk_isp_dis_400", "mout_aclk_isp_dis_400", DIV_TOP0, 4, 4), DIV(CLK_DIV_ACLK_ISP_400, "div_aclk_isp_400", @@ -566,6 +572,15 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_GSCL_333, "aclk_gscl_333", "div_aclk_gscl_333", ENABLE_ACLK_TOP, 14, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM0_333, "aclk_cam0_333", "div_aclk_cam0_333", + ENABLE_ACLK_TOP, 10, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM0_400, "aclk_cam0_400", "div_aclk_cam0_400", + ENABLE_ACLK_TOP, 9, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM0_552, "aclk_cam0_552", "div_aclk_cam0_552", + ENABLE_ACLK_TOP, 8, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_ISP_DIS_400, "aclk_isp_dis_400", "div_aclk_isp_dis_400", ENABLE_ACLK_TOP, 7, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -4485,3 +4500,489 @@ static void __init exynos5433_cmu_isp_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_isp, "samsung,exynos5433-cmu-isp", exynos5433_cmu_isp_init); + +/* + * Register offset definitions for CMU_CAM0 + */ +#define MUX_SEL_CAM00 0x0200 +#define MUX_SEL_CAM01 0x0204 +#define MUX_SEL_CAM02 0x0208 +#define MUX_SEL_CAM03 0x020c +#define MUX_SEL_CAM04 0x0210 +#define MUX_ENABLE_CAM00 0x0300 +#define MUX_ENABLE_CAM01 0x0304 +#define MUX_ENABLE_CAM02 0x0308 +#define MUX_ENABLE_CAM03 0x030c +#define MUX_ENABLE_CAM04 0x0310 +#define MUX_STAT_CAM00 0x0400 +#define MUX_STAT_CAM01 0x0404 +#define MUX_STAT_CAM02 0x0408 +#define MUX_STAT_CAM03 0x040c +#define MUX_STAT_CAM04 0x0410 +#define MUX_IGNORE_CAM01 0x0504 +#define DIV_CAM00 0x0600 +#define DIV_CAM01 0x0604 +#define DIV_CAM02 0x0608 +#define DIV_CAM03 0x060c +#define DIV_STAT_CAM00 0x0700 +#define DIV_STAT_CAM01 0x0704 +#define DIV_STAT_CAM02 0x0708 +#define DIV_STAT_CAM03 0x070c +#define ENABLE_ACLK_CAM00 0X0800 +#define ENABLE_ACLK_CAM01 0X0804 +#define ENABLE_ACLK_CAM02 0X0808 +#define ENABLE_PCLK_CAM0 0X0900 +#define ENABLE_SCLK_CAM0 0X0a00 +#define ENABLE_IP_CAM00 0X0b00 +#define ENABLE_IP_CAM01 0X0b04 +#define ENABLE_IP_CAM02 0X0b08 +#define ENABLE_IP_CAM03 0X0b0C + +static unsigned long cam0_clk_regs[] __initdata = { + MUX_SEL_CAM00, + MUX_SEL_CAM01, + MUX_SEL_CAM02, + MUX_SEL_CAM03, + MUX_SEL_CAM04, + MUX_ENABLE_CAM00, + MUX_ENABLE_CAM01, + MUX_ENABLE_CAM02, + MUX_ENABLE_CAM03, + MUX_ENABLE_CAM04, + MUX_STAT_CAM00, + MUX_STAT_CAM01, + MUX_STAT_CAM02, + MUX_STAT_CAM03, + MUX_STAT_CAM04, + MUX_IGNORE_CAM01, + DIV_CAM00, + DIV_CAM01, + DIV_CAM02, + DIV_CAM03, + DIV_STAT_CAM00, + DIV_STAT_CAM01, + DIV_STAT_CAM02, + DIV_STAT_CAM03, + ENABLE_ACLK_CAM00, + ENABLE_ACLK_CAM01, + ENABLE_ACLK_CAM02, + ENABLE_PCLK_CAM0, + ENABLE_SCLK_CAM0, + ENABLE_IP_CAM00, + ENABLE_IP_CAM01, + ENABLE_IP_CAM02, + ENABLE_IP_CAM03, +}; +PNAME(mout_aclk_cam0_333_user_p) = { "oscclk", "aclk_cam0_333", }; +PNAME(mout_aclk_cam0_400_user_p) = { "oscclk", "aclk_cam0_400", }; +PNAME(mout_aclk_cam0_552_user_p) = { "oscclk", "aclk_cam0_552", }; + +PNAME(mout_phyclk_rxbyteclkhs0_s4_user_p) = { "oscclk", + "phyclk_rxbyteclkhs0_s4_phy", }; +PNAME(mout_phyclk_rxbyteclkhs0_s2a_user_p) = { "oscclk", + "phyclk_rxbyteclkhs0_s2a_phy", }; + +PNAME(mout_aclk_lite_d_b_p) = { "mout_aclk_lite_d_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_aclk_lite_d_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; +PNAME(mout_aclk_lite_b_b_p) = { "mout_aclk_lite_b_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_aclk_lite_b_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; +PNAME(mout_aclk_lite_a_b_p) = { "mout_aclk_lite_a_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_aclk_lite_a_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; +PNAME(mout_aclk_cam0_400_p) = { "mout_aclk_cam0_400_user", + "mout_aclk_cam0_333_user", }; + +PNAME(mout_aclk_csis1_b_p) = { "mout_aclk_csis1_a", + "mout_aclk_cam0_333_user" }; +PNAME(mout_aclk_csis1_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; +PNAME(mout_aclk_csis0_b_p) = { "mout_aclk_csis0_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_aclk_csis0_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk-cam0_400_user", }; +PNAME(mout_aclk_3aa1_b_p) = { "mout_aclk_3aa1_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_aclk_3aa1_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; +PNAME(mout_aclk_3aa0_b_p) = { "mout_aclk_3aa0_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_aclk_3aa0_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; + +PNAME(mout_sclk_lite_freecnt_c_p) = { "mout_sclk_lite_freecnt_b", + "div_pclk_lite_d", }; +PNAME(mout_sclk_lite_freecnt_b_p) = { "mout_sclk_lite_freecnt_a", + "div_pclk_pixelasync_lite_c", }; +PNAME(mout_sclk_lite_freecnt_a_p) = { "div_pclk_lite_a", + "div_pclk_lite_b", }; +PNAME(mout_sclk_pixelasync_lite_c_b_p) = { "mout_sclk_pixelasync_lite_c_a", + "mout_aclk_cam0_333_user", }; +PNAME(mout_sclk_pixelasync_lite_c_a_p) = { "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; +PNAME(mout_sclk_pixelasync_lite_c_init_b_p) = { + "mout_sclk_pixelasync_lite_c_init_a", + "mout_aclk_cam0_400_user", }; +PNAME(mout_sclk_pixelasync_lite_c_init_a_p) = { + "mout_aclk_cam0_552_user", + "mout_aclk_cam0_400_user", }; + +static struct samsung_fixed_rate_clock cam0_fixed_clks[] __initdata = { + FRATE(CLK_PHYCLK_RXBYTEECLKHS0_S4_PHY, "phyclk_rxbyteclkhs0_s4_phy", + NULL, CLK_IS_ROOT, 100000000), + FRATE(CLK_PHYCLK_RXBYTEECLKHS0_S2A_PHY, "phyclk_rxbyteclkhs0_s2a_phy", + NULL, CLK_IS_ROOT, 100000000), +}; + +static struct samsung_mux_clock cam0_mux_clks[] __initdata = { + /* MUX_SEL_CAM00 */ + MUX(CLK_MOUT_ACLK_CAM0_333_USER, "mout_aclk_cam0_333_user", + mout_aclk_cam0_333_user_p, MUX_SEL_CAM00, 8, 1), + MUX(CLK_MOUT_ACLK_CAM0_400_USER, "mout_aclk_cam0_400_user", + mout_aclk_cam0_400_user_p, MUX_SEL_CAM00, 4, 1), + MUX(CLK_MOUT_ACLK_CAM0_552_USER, "mout_aclk_cam0_552_user", + mout_aclk_cam0_552_user_p, MUX_SEL_CAM00, 0, 1), + + /* MUX_SEL_CAM01 */ + MUX(CLK_MOUT_PHYCLK_RXBYTECLKHS0_S4_USER, + "mout_phyclk_rxbyteclkhs0_s4_user", + mout_phyclk_rxbyteclkhs0_s4_user_p, + MUX_SEL_CAM01, 4, 1), + MUX(CLK_MOUT_PHYCLK_RXBYTECLKHS0_S2A_USER, + "mout_phyclk_rxbyteclkhs0_s2a_user", + mout_phyclk_rxbyteclkhs0_s2a_user_p, + MUX_SEL_CAM01, 0, 1), + + /* MUX_SEL_CAM02 */ + MUX(CLK_MOUT_ACLK_LITE_D_B, "mout_aclk_lite_d_b", mout_aclk_lite_d_b_p, + MUX_SEL_CAM02, 24, 1), + MUX(CLK_MOUT_ACLK_LITE_D_A, "mout_aclk_lite_d_a", mout_aclk_lite_d_a_p, + MUX_SEL_CAM02, 20, 1), + MUX(CLK_MOUT_ACLK_LITE_B_B, "mout_aclk_lite_b_b", mout_aclk_lite_b_b_p, + MUX_SEL_CAM02, 16, 1), + MUX(CLK_MOUT_ACLK_LITE_B_A, "mout_aclk_lite_b_a", mout_aclk_lite_b_a_p, + MUX_SEL_CAM02, 12, 1), + MUX(CLK_MOUT_ACLK_LITE_A_B, "mout_aclk_lite_a_b", mout_aclk_lite_a_b_p, + MUX_SEL_CAM02, 8, 1), + MUX(CLK_MOUT_ACLK_LITE_A_A, "mout_aclk_lite_a_a", mout_aclk_lite_a_a_p, + MUX_SEL_CAM02, 4, 1), + MUX(CLK_MOUT_ACLK_CAM0_400, "mout_aclk_cam0_400", mout_aclk_cam0_400_p, + MUX_SEL_CAM02, 0, 1), + + /* MUX_SEL_CAM03 */ + MUX(CLK_MOUT_ACLK_CSIS1_B, "mout_aclk_csis1_b", mout_aclk_csis1_b_p, + MUX_SEL_CAM03, 28, 1), + MUX(CLK_MOUT_ACLK_CSIS1_A, "mout_aclk_csis1_a", mout_aclk_csis1_a_p, + MUX_SEL_CAM03, 24, 1), + MUX(CLK_MOUT_ACLK_CSIS0_B, "mout_aclk_csis0_b", mout_aclk_csis0_b_p, + MUX_SEL_CAM03, 20, 1), + MUX(CLK_MOUT_ACLK_CSIS0_A, "mout_aclk_csis0_a", mout_aclk_csis0_a_p, + MUX_SEL_CAM03, 16, 1), + MUX(CLK_MOUT_ACLK_3AA1_B, "mout_aclk_3aa1_b", mout_aclk_3aa1_b_p, + MUX_SEL_CAM03, 12, 1), + MUX(CLK_MOUT_ACLK_3AA1_A, "mout_aclk_3aa1_a", mout_aclk_3aa1_a_p, + MUX_SEL_CAM03, 8, 1), + MUX(CLK_MOUT_ACLK_3AA0_B, "mout_aclk_3aa0_b", mout_aclk_3aa0_b_p, + MUX_SEL_CAM03, 4, 1), + MUX(CLK_MOUT_ACLK_3AA0_A, "mout_aclk_3aa0_a", mout_aclk_3aa0_a_p, + MUX_SEL_CAM03, 0, 1), + + /* MUX_SEL_CAM04 */ + MUX(CLK_MOUT_SCLK_LITE_FREECNT_C, "mout_sclk_lite_freecnt_c", + mout_sclk_lite_freecnt_c_p, MUX_SEL_CAM04, 24, 1), + MUX(CLK_MOUT_SCLK_LITE_FREECNT_B, "mout_sclk_lite_freecnt_b", + mout_sclk_lite_freecnt_b_p, MUX_SEL_CAM04, 24, 1), + MUX(CLK_MOUT_SCLK_LITE_FREECNT_A, "mout_sclk_lite_freecnt_a", + mout_sclk_lite_freecnt_a_p, MUX_SEL_CAM04, 24, 1), + MUX(CLK_MOUT_SCLK_PIXELASYNC_LITE_C_B, "mout_sclk_pixelasync_lite_c_b", + mout_sclk_pixelasync_lite_c_b_p, MUX_SEL_CAM04, 24, 1), + MUX(CLK_MOUT_SCLK_PIXELASYNC_LITE_C_A, "mout_sclk_pixelasync_lite_c_a", + mout_sclk_pixelasync_lite_c_a_p, MUX_SEL_CAM04, 24, 1), + MUX(CLK_MOUT_SCLK_PIXELASYNC_LITE_C_INIT_B, + "mout_sclk_pixelasync_lite_c_init_b", + mout_sclk_pixelasync_lite_c_init_b_p, + MUX_SEL_CAM04, 24, 1), + MUX(CLK_MOUT_SCLK_PIXELASYNC_LITE_C_INIT_A, + "mout_sclk_pixelasync_lite_c_init_a", + mout_sclk_pixelasync_lite_c_init_a_p, + MUX_SEL_CAM04, 24, 1), +}; + +static struct samsung_div_clock cam0_div_clks[] __initdata = { + /* DIV_CAM00 */ + DIV(CLK_DIV_PCLK_CAM0_50, "div_pclk_cam0_50", "div_aclk_cam0_200", + DIV_CAM00, 8, 2), + DIV(CLK_DIV_ACLK_CAM0_200, "div_aclk_cam0_200", "mout_aclk_cam0_400", + DIV_CAM00, 4, 3), + DIV(CLK_DIV_ACLK_CAM0_BUS_400, "div_aclk_cam0_bus_400", + "mout_aclk_cam0_400", DIV_CAM00, 0, 3), + + /* DIV_CAM01 */ + DIV(CLK_DIV_PCLK_LITE_D, "div_pclk_lite_d", "div_aclk_lite_d", + DIV_CAM01, 20, 2), + DIV(CLK_DIV_ACLK_LITE_D, "div_aclk_lite_d", "mout_aclk_lite_d_b", + DIV_CAM01, 16, 3), + DIV(CLK_DIV_PCLK_LITE_B, "div_pclk_lite_b", "div_aclk_lite_b", + DIV_CAM01, 12, 2), + DIV(CLK_DIV_ACLK_LITE_B, "div_aclk_lite_b", "mout_aclk_lite_b_b", + DIV_CAM01, 8, 3), + DIV(CLK_DIV_PCLK_LITE_A, "div_pclk_lite_a", "div_aclk_lite_a", + DIV_CAM01, 4, 2), + DIV(CLK_DIV_ACLK_LITE_A, "div_aclk_lite_a", "mout_aclk_lite_a_b", + DIV_CAM01, 0, 3), + + /* DIV_CAM02 */ + DIV(CLK_DIV_ACLK_CSIS1, "div_aclk_csis1", "mout_aclk_csis1_b", + DIV_CAM02, 20, 3), + DIV(CLK_DIV_ACLK_CSIS0, "div_aclk_csis0", "mout_aclk_csis0_b", + DIV_CAM02, 16, 3), + DIV(CLK_DIV_PCLK_3AA1, "div_pclk_3aa1", "div_aclk_3aa1", + DIV_CAM02, 12, 2), + DIV(CLK_DIV_ACLK_3AA1, "div_aclk_3aa1", "mout_aclk_3aa1_b", + DIV_CAM02, 8, 3), + DIV(CLK_DIV_PCLK_3AA0, "div_pclk_3aa0", "div_aclk_3aa0", + DIV_CAM02, 4, 2), + DIV(CLK_DIV_ACLK_3AA0, "div_aclk_3aa0", "mout_aclk_3aa0_b", + DIV_CAM02, 0, 3), + + /* DIV_CAM03 */ + DIV(CLK_DIV_SCLK_PIXELASYNC_LITE_C, "div_sclk_pixelasync_lite_c", + "mout_sclk_pixelasync_lite_c_b", DIV_CAM03, 8, 3), + DIV(CLK_DIV_PCLK_PIXELASYNC_LITE_C, "div_pclk_pixelasync_lite_c", + "div_sclk_pixelasync_lite_c_init", DIV_CAM03, 4, 2), + DIV(CLK_DIV_SCLK_PIXELASYNC_LITE_C_INIT, + "div_sclk_pixelasync_lite_c_init", + "mout_sclk_pixelasync_lite_c_init_b", DIV_CAM03, 0, 3), +}; + +static struct samsung_gate_clock cam0_gate_clks[] __initdata = { + /* ENABLE_ACLK_CAM00 */ + GATE(CLK_ACLK_CSIS1, "aclk_csis1", "div_aclk_csis1", ENABLE_ACLK_CAM00, + 6, 0, 0), + GATE(CLK_ACLK_CSIS0, "aclk_csis0", "div_aclk_csis0", ENABLE_ACLK_CAM00, + 5, 0, 0), + GATE(CLK_ACLK_3AA1, "aclk_3aa1", "div_aclk_3aa1", ENABLE_ACLK_CAM00, + 4, 0, 0), + GATE(CLK_ACLK_3AA0, "aclk_3aa0", "div_aclk_3aa0", ENABLE_ACLK_CAM00, + 3, 0, 0), + GATE(CLK_ACLK_LITE_D, "aclk_lite_d", "div_aclk_lite_d", + ENABLE_ACLK_CAM00, 2, 0, 0), + GATE(CLK_ACLK_LITE_B, "aclk_lite_b", "div_aclk_lite_b", + ENABLE_ACLK_CAM00, 1, 0, 0), + GATE(CLK_ACLK_LITE_A, "aclk_lite_a", "div_aclk_lite_a", + ENABLE_ACLK_CAM00, 0, 0, 0), + + /* ENABLE_ACLK_CAM01 */ + GATE(CLK_ACLK_AHBSYNCDN, "aclk_ahbsyncdn", "div_aclk_cam0_200", + ENABLE_ACLK_CAM01, 31, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_LITE_D, "aclk_axius_lite_d", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM01, 30, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_LITE_B, "aclk_axius_lite_b", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM01, 29, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_LITE_A, "aclk_axius_lite_a", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM01, 28, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBM_3AA1, "aclk_asyncapbm_3aa1", "div_pclk_3aa1", + ENABLE_ACLK_CAM01, 27, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_3AA1, "aclk_asyncapbs_3aa1", "div_aclk_3aa1", + ENABLE_ACLK_CAM01, 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBM_3AA0, "aclk_asyncapbm_3aa0", "div_pclk_3aa0", + ENABLE_ACLK_CAM01, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_3AA0, "aclk_asyncapbs_3aa0", "div_aclk_3aa0", + ENABLE_ACLK_CAM01, 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBM_LITE_D, "aclk_asyncapbm_lite_d", + "div_pclk_lite_d", ENABLE_ACLK_CAM01, + 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_LITE_D, "aclk_asyncapbs_lite_d", + "div_aclk_cam0_200", ENABLE_ACLK_CAM01, + 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBM_LITE_B, "aclk_asyncapbm_lite_b", + "div_pclk_lite_b", ENABLE_ACLK_CAM01, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_LITE_B, "aclk_asyncapbs_lite_b", + "div_aclk_cam0_200", ENABLE_ACLK_CAM01, + 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBM_LITE_A, "aclk_asyncapbm_lite_a", + "div_pclk_lite_a", ENABLE_ACLK_CAM01, + 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_LITE_A, "aclk_asyncapbs_lite_a", + "div_aclk_cam0_200", ENABLE_ACLK_CAM01, + 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_ISP0P, "aclk_asyncaxim_isp0p", + "div_aclk_cam0_200", ENABLE_ACLK_CAM01, + 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_3AA1, "aclk_asyncaxim_3aa1", + "div_aclk_cam0_bus_400", ENABLE_ACLK_CAM01, + 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_3AA1, "aclk_asyncaxis_3aa1", + "div_aclk_3aa1", ENABLE_ACLK_CAM01, + 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_3AA0, "aclk_asyncaxim_3aa0", + "div_aclk_cam0_bus_400", ENABLE_ACLK_CAM01, + 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_3AA0, "aclk_asyncaxis_3aa0", + "div_aclk_3aa0", ENABLE_ACLK_CAM01, + 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_LITE_D, "aclk_asyncaxim_lite_d", + "div_aclk_cam0_bus_400", ENABLE_ACLK_CAM01, + 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_LITE_D, "aclk_asyncaxis_lite_d", + "div_aclk_lite_d", ENABLE_ACLK_CAM01, + 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_LITE_B, "aclk_asyncaxim_lite_b", + "div_aclk_cam0_bus_400", ENABLE_ACLK_CAM01, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_LITE_B, "aclk_asyncaxis_lite_b", + "div_aclk_lite_b", ENABLE_ACLK_CAM01, + 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_LITE_A, "aclk_asyncaxim_lite_a", + "div_aclk_cam0_bus_400", ENABLE_ACLK_CAM01, + 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_LITE_A, "aclk_asyncaxis_lite_a", + "div_aclk_lite_a", ENABLE_ACLK_CAM01, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_ISPSFRP, "aclk_ahb2apb_ispsfrp", + "div_pclk_cam0_50", ENABLE_ACLK_CAM01, + 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI2APB_ISP0P, "aclk_axi2apb_isp0p", "div_aclk_cam0_200", + ENABLE_ACLK_CAM01, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI2AHB_ISP0P, "aclk_axi2ahb_isp0p", "div_aclk_cam0_200", + ENABLE_ACLK_CAM01, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_IS0X, "aclk_xiu_is0x", "div_aclk_cam0_200", + ENABLE_ACLK_CAM01, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_ISP0EX, "aclk_xiu_isp0ex", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM01, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM0NP_276, "aclk_cam0np_276", "div_aclk_cam0_200", + ENABLE_ACLK_CAM01, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM0ND_400, "aclk_cam0nd_400", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM01, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_CAM02 */ + GATE(CLK_ACLK_SMMU_3AA1, "aclk_smmu_3aa1", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_3AA0, "aclk_smmu_3aa0", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_LITE_D, "aclk_smmu_lite_d", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_LITE_B, "aclk_smmu_lite_b", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_LITE_A, "aclk_smmu_lite_a", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_3AA1, "aclk_bts_3aa1", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_3AA0, "aclk_bts_3aa0", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_LITE_D, "aclk_bts_lite_d", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_LITE_B, "aclk_bts_lite_b", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_LITE_A, "aclk_bts_lite_a", "div_aclk_cam0_bus_400", + ENABLE_ACLK_CAM02, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_CAM0 */ + GATE(CLK_PCLK_SMMU_3AA1, "pclk_smmu_3aa1", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_3AA0, "pclk_smmu_3aa0", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_LITE_D, "pclk_smmu_lite_d", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_LITE_B, "pclk_smmu_lite_b", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_LITE_A, "pclk_smmu_lite_a", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_3AA1, "pclk_bts_3aa1", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_3AA0, "pclk_bts_3aa0", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_LITE_D, "pclk_bts_lite_d", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_LITE_B, "pclk_bts_lite_b", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_LITE_A, "pclk_bts_lite_a", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_CAM1, "pclk_asyncaxi_cam1", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_3AA1, "pclk_asyncaxi_3aa1", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_3AA0, "pclk_asyncaxi_3aa0", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_LITE_D, "pclk_asyncaxi_lite_d", + "div_pclk_cam0_50", ENABLE_PCLK_CAM0, + 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_LITE_B, "pclk_asyncaxi_lite_b", + "div_pclk_cam0_50", ENABLE_PCLK_CAM0, + 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXI_LITE_A, "pclk_asyncaxi_lite_a", + "div_pclk_cam0_50", ENABLE_PCLK_CAM0, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_CAM0, "pclk_pmu_cam0", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_CAM0, "pclk_sysreg_cam0", "div_pclk_cam0_50", + ENABLE_PCLK_CAM0, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_CMU_CAM0_LOCAL, "pclk_cmu_cam0_local", + "div_aclk_cam0_200", ENABLE_PCLK_CAM0, + 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_CSIS1, "pclk_csis1", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_CSIS0, "pclk_csis0", "div_aclk_cam0_200", + ENABLE_PCLK_CAM0, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_3AA1, "pclk_3aa1", "div_pclk_3aa1", + ENABLE_PCLK_CAM0, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_3AA0, "pclk_3aa0", "div_pclk_3aa0", + ENABLE_PCLK_CAM0, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_LITE_D, "pclk_lite_d", "div_pclk_lite_d", + ENABLE_PCLK_CAM0, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_LITE_B, "pclk_lite_b", "div_pclk_lite_b", + ENABLE_PCLK_CAM0, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_LITE_A, "pclk_lite_a", "div_pclk_lite_a", + ENABLE_PCLK_CAM0, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_CAM0 */ + GATE(CLK_PHYCLK_RXBYTECLKHS0_S4, "phyclk_rxbyteclkhs0_s4", + "mout_phyclk_rxbyteclkhs0_s4_user", + ENABLE_SCLK_CAM0, 8, 0, 0), + GATE(CLK_PHYCLK_RXBYTECLKHS0_S2A, "phyclk_rxbyteclkhs0_s2a", + "mout_phyclk_rxbyteclkhs0_s2a_user", + ENABLE_SCLK_CAM0, 7, 0, 0), + GATE(CLK_SCLK_LITE_FREECNT, "sclk_lite_freecnt", + "mout_sclk_lite_freecnt_c", ENABLE_SCLK_CAM0, 6, 0, 0), + GATE(CLK_SCLK_PIXELASYNCM_3AA1, "sclk_pixelasycm_3aa1", + "div_aclk_3aa1", ENABLE_SCLK_CAM0, 5, 0, 0), + GATE(CLK_SCLK_PIXELASYNCM_3AA0, "sclk_pixelasycm_3aa0", + "div_aclk_3aa0", ENABLE_SCLK_CAM0, 4, 0, 0), + GATE(CLK_SCLK_PIXELASYNCS_3AA0, "sclk_pixelasycs_3aa0", + "div_aclk_3aa0", ENABLE_SCLK_CAM0, 3, 0, 0), + GATE(CLK_SCLK_PIXELASYNCM_LITE_C, "sclk_pixelasyncm_lite_c", + "div_sclk_pixelasync_lite_c", + ENABLE_SCLK_CAM0, 2, 0, 0), + GATE(CLK_SCLK_PIXELASYNCM_LITE_C_INIT, "sclk_pixelasyncm_lite_c_init", + "div_sclk_pixelasync_lite_c_init", + ENABLE_SCLK_CAM0, 1, 0, 0), + GATE(CLK_SCLK_PIXELASYNCS_LITE_C_INIT, "sclk_pixelasyncs_lite_c_init", + "div_sclk_pixelasync_lite_c", + ENABLE_SCLK_CAM0, 0, 0, 0), +}; + +static struct samsung_cmu_info cam0_cmu_info __initdata = { + .mux_clks = cam0_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cam0_mux_clks), + .div_clks = cam0_div_clks, + .nr_div_clks = ARRAY_SIZE(cam0_div_clks), + .gate_clks = cam0_gate_clks, + .nr_gate_clks = ARRAY_SIZE(cam0_gate_clks), + .fixed_clks = cam0_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(cam0_fixed_clks), + .nr_clk_ids = CAM0_NR_CLK, + .clk_regs = cam0_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cam0_clk_regs), +}; + +static void __init exynos5433_cmu_cam0_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &cam0_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_cam0, "samsung,exynos5433-cmu-cam0", + exynos5433_cmu_cam0_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index fbc81e3424a6..f99cde7a278d 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -118,6 +118,9 @@ #define CLK_DIV_ACLK_MSCL_400 145 #define CLK_DIV_ACLK_ISP_DIS_400 146 #define CLK_DIV_ACLK_ISP_400 147 +#define CLK_DIV_ACLK_CAM0_333 148 +#define CLK_DIV_ACLK_CAM0_400 149 +#define CLK_DIV_ACLK_CAM0_552 150 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -159,8 +162,11 @@ #define CLK_ACLK_HEVC_400 237 #define CLK_ACLK_ISP_DIS_400 238 #define CLK_ACLK_ISP_400 239 +#define CLK_ACLK_CAM0_333 240 +#define CLK_ACLK_CAM0_400 241 +#define CLK_ACLK_CAM0_552 242 -#define TOP_NR_CLK 240 +#define TOP_NR_CLK 243 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -1113,4 +1119,142 @@ #define ISP_NR_CLK 78 +/* CMU_CAM0 */ +#define CLK_PHYCLK_RXBYTEECLKHS0_S4_PHY 1 +#define CLK_PHYCLK_RXBYTEECLKHS0_S2A_PHY 2 + +#define CLK_MOUT_ACLK_CAM0_333_USER 3 +#define CLK_MOUT_ACLK_CAM0_400_USER 4 +#define CLK_MOUT_ACLK_CAM0_552_USER 5 +#define CLK_MOUT_PHYCLK_RXBYTECLKHS0_S4_USER 6 +#define CLK_MOUT_PHYCLK_RXBYTECLKHS0_S2A_USER 7 +#define CLK_MOUT_ACLK_LITE_D_B 8 +#define CLK_MOUT_ACLK_LITE_D_A 9 +#define CLK_MOUT_ACLK_LITE_B_B 10 +#define CLK_MOUT_ACLK_LITE_B_A 11 +#define CLK_MOUT_ACLK_LITE_A_B 12 +#define CLK_MOUT_ACLK_LITE_A_A 13 +#define CLK_MOUT_ACLK_CAM0_400 14 +#define CLK_MOUT_ACLK_CSIS1_B 15 +#define CLK_MOUT_ACLK_CSIS1_A 16 +#define CLK_MOUT_ACLK_CSIS0_B 17 +#define CLK_MOUT_ACLK_CSIS0_A 18 +#define CLK_MOUT_ACLK_3AA1_B 19 +#define CLK_MOUT_ACLK_3AA1_A 20 +#define CLK_MOUT_ACLK_3AA0_B 21 +#define CLK_MOUT_ACLK_3AA0_A 22 +#define CLK_MOUT_SCLK_LITE_FREECNT_C 23 +#define CLK_MOUT_SCLK_LITE_FREECNT_B 24 +#define CLK_MOUT_SCLK_LITE_FREECNT_A 25 +#define CLK_MOUT_SCLK_PIXELASYNC_LITE_C_B 26 +#define CLK_MOUT_SCLK_PIXELASYNC_LITE_C_A 27 +#define CLK_MOUT_SCLK_PIXELASYNC_LITE_C_INIT_B 28 +#define CLK_MOUT_SCLK_PIXELASYNC_LITE_C_INIT_A 29 + +#define CLK_DIV_PCLK_CAM0_50 30 +#define CLK_DIV_ACLK_CAM0_200 31 +#define CLK_DIV_ACLK_CAM0_BUS_400 32 +#define CLK_DIV_PCLK_LITE_D 33 +#define CLK_DIV_ACLK_LITE_D 34 +#define CLK_DIV_PCLK_LITE_B 35 +#define CLK_DIV_ACLK_LITE_B 36 +#define CLK_DIV_PCLK_LITE_A 37 +#define CLK_DIV_ACLK_LITE_A 38 +#define CLK_DIV_ACLK_CSIS1 39 +#define CLK_DIV_ACLK_CSIS0 40 +#define CLK_DIV_PCLK_3AA1 41 +#define CLK_DIV_ACLK_3AA1 42 +#define CLK_DIV_PCLK_3AA0 43 +#define CLK_DIV_ACLK_3AA0 44 +#define CLK_DIV_SCLK_PIXELASYNC_LITE_C 45 +#define CLK_DIV_PCLK_PIXELASYNC_LITE_C 46 +#define CLK_DIV_SCLK_PIXELASYNC_LITE_C_INIT 47 + +#define CLK_ACLK_CSIS1 50 +#define CLK_ACLK_CSIS0 51 +#define CLK_ACLK_3AA1 52 +#define CLK_ACLK_3AA0 53 +#define CLK_ACLK_LITE_D 54 +#define CLK_ACLK_LITE_B 55 +#define CLK_ACLK_LITE_A 56 +#define CLK_ACLK_AHBSYNCDN 57 +#define CLK_ACLK_AXIUS_LITE_D 58 +#define CLK_ACLK_AXIUS_LITE_B 59 +#define CLK_ACLK_AXIUS_LITE_A 60 +#define CLK_ACLK_ASYNCAPBM_3AA1 61 +#define CLK_ACLK_ASYNCAPBS_3AA1 62 +#define CLK_ACLK_ASYNCAPBM_3AA0 63 +#define CLK_ACLK_ASYNCAPBS_3AA0 64 +#define CLK_ACLK_ASYNCAPBM_LITE_D 65 +#define CLK_ACLK_ASYNCAPBS_LITE_D 66 +#define CLK_ACLK_ASYNCAPBM_LITE_B 67 +#define CLK_ACLK_ASYNCAPBS_LITE_B 68 +#define CLK_ACLK_ASYNCAPBM_LITE_A 69 +#define CLK_ACLK_ASYNCAPBS_LITE_A 70 +#define CLK_ACLK_ASYNCAXIM_ISP0P 71 +#define CLK_ACLK_ASYNCAXIM_3AA1 72 +#define CLK_ACLK_ASYNCAXIS_3AA1 73 +#define CLK_ACLK_ASYNCAXIM_3AA0 74 +#define CLK_ACLK_ASYNCAXIS_3AA0 75 +#define CLK_ACLK_ASYNCAXIM_LITE_D 76 +#define CLK_ACLK_ASYNCAXIS_LITE_D 77 +#define CLK_ACLK_ASYNCAXIM_LITE_B 78 +#define CLK_ACLK_ASYNCAXIS_LITE_B 79 +#define CLK_ACLK_ASYNCAXIM_LITE_A 80 +#define CLK_ACLK_ASYNCAXIS_LITE_A 81 +#define CLK_ACLK_AHB2APB_ISPSFRP 82 +#define CLK_ACLK_AXI2APB_ISP0P 83 +#define CLK_ACLK_AXI2AHB_ISP0P 84 +#define CLK_ACLK_XIU_IS0X 85 +#define CLK_ACLK_XIU_ISP0EX 86 +#define CLK_ACLK_CAM0NP_276 87 +#define CLK_ACLK_CAM0ND_400 88 +#define CLK_ACLK_SMMU_3AA1 89 +#define CLK_ACLK_SMMU_3AA0 90 +#define CLK_ACLK_SMMU_LITE_D 91 +#define CLK_ACLK_SMMU_LITE_B 92 +#define CLK_ACLK_SMMU_LITE_A 93 +#define CLK_ACLK_BTS_3AA1 94 +#define CLK_ACLK_BTS_3AA0 95 +#define CLK_ACLK_BTS_LITE_D 96 +#define CLK_ACLK_BTS_LITE_B 97 +#define CLK_ACLK_BTS_LITE_A 98 +#define CLK_PCLK_SMMU_3AA1 99 +#define CLK_PCLK_SMMU_3AA0 100 +#define CLK_PCLK_SMMU_LITE_D 101 +#define CLK_PCLK_SMMU_LITE_B 102 +#define CLK_PCLK_SMMU_LITE_A 103 +#define CLK_PCLK_BTS_3AA1 104 +#define CLK_PCLK_BTS_3AA0 105 +#define CLK_PCLK_BTS_LITE_D 106 +#define CLK_PCLK_BTS_LITE_B 107 +#define CLK_PCLK_BTS_LITE_A 108 +#define CLK_PCLK_ASYNCAXI_CAM1 109 +#define CLK_PCLK_ASYNCAXI_3AA1 110 +#define CLK_PCLK_ASYNCAXI_3AA0 111 +#define CLK_PCLK_ASYNCAXI_LITE_D 112 +#define CLK_PCLK_ASYNCAXI_LITE_B 113 +#define CLK_PCLK_ASYNCAXI_LITE_A 114 +#define CLK_PCLK_PMU_CAM0 115 +#define CLK_PCLK_SYSREG_CAM0 116 +#define CLK_PCLK_CMU_CAM0_LOCAL 117 +#define CLK_PCLK_CSIS1 118 +#define CLK_PCLK_CSIS0 119 +#define CLK_PCLK_3AA1 120 +#define CLK_PCLK_3AA0 121 +#define CLK_PCLK_LITE_D 122 +#define CLK_PCLK_LITE_B 123 +#define CLK_PCLK_LITE_A 124 +#define CLK_PHYCLK_RXBYTECLKHS0_S4 125 +#define CLK_PHYCLK_RXBYTECLKHS0_S2A 126 +#define CLK_SCLK_LITE_FREECNT 127 +#define CLK_SCLK_PIXELASYNCM_3AA1 128 +#define CLK_SCLK_PIXELASYNCM_3AA0 129 +#define CLK_SCLK_PIXELASYNCS_3AA0 130 +#define CLK_SCLK_PIXELASYNCM_LITE_C 131 +#define CLK_SCLK_PIXELASYNCM_LITE_C_INIT 132 +#define CLK_SCLK_PIXELASYNCS_LITE_C_INIT 133 + +#define CAM0_NR_CLK 134 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From a5958a939bbf93e6b77cb3626c6aebde237ad759 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 3 Feb 2015 09:13:56 +0900 Subject: clk: samsung: exynos5433: Add clocks for CMU_CAM1 domain This patch adds the mux/divider/gate clocks for CMU_CAM1 domain which generates the clocks for Cortex-A5/MIPI_CSIS2/FIMC-LITE_C/FIMC-FD IPs. Signed-off-by: Chanwoo Choi Acked-by: Inki Dae Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 32 ++ drivers/clk/samsung/clk-exynos5433.c | 435 +++++++++++++++++++++ include/dt-bindings/clock/exynos5433.h | 147 ++++++- 3 files changed, 612 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 84002e4b52e5..63379b04e052 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -48,6 +48,8 @@ Required Properties: - "samsung,exynos5433-cmu-cam0" - clock controller compatible for CMU_CAM0 which generates clocks for MIPI_CSIS{0|1}/FIMC_LITE_{A|B|D}/FIMC_3AA{0|1} IPs. + - "samsung,exynos5433-cmu-cam1" - clock controller compatible for CMU_CAM1 + which generates clocks for Cortex-A5/MIPI_CSIS2/FIMC-LITE_C/FIMC-FD IPs. - reg: physical base address of the controller and length of memory mapped region. @@ -153,6 +155,15 @@ Required Properties: - aclk_cam0_400 - aclk_cam0_552 + Input clocks for cam1 clock controller: + - oscclk + - sclk_isp_uart_cam1 + - sclk_isp_spi1_cam1 + - sclk_isp_spi0_cam1 + - aclk_cam1_333 + - aclk_cam1_400 + - aclk_cam1_552 + Each clock is assigned an identifier and client nodes can use this identifier to specify the clock which they consume. @@ -414,6 +425,27 @@ Example 2: Examples of clock controller nodes are listed below. <&cmu_top CLK_ACLK_CAM0_552>; }; + cmu_cam1: clock-controller@145d0000 { + compatible = "samsung,exynos5433-cmu-cam1"; + reg = <0x145d0000 0x0b08>; + #clock-cells = <1>; + + clock-names = "oscclk", + "sclk_isp_uart_cam1", + "sclk_isp_spi1_cam1", + "sclk_isp_spi0_cam1", + "aclk_cam1_333", + "aclk_cam1_400", + "aclk_cam1_552"; + clocks = <&xxti>, + <&cmu_top CLK_SCLK_ISP_UART_CAM1>, + <&cmu_top CLK_SCLK_ISP_SPI1_CAM1>, + <&cmu_top CLK_SCLK_ISP_SPI0_CAM1>, + <&cmu_top CLK_ACLK_CAM1_333>, + <&cmu_top CLK_ACLK_CAM1_400>, + <&cmu_top CLK_ACLK_CAM1_552>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index ce6487375670..1a005c1f7c4b 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -405,6 +405,12 @@ static struct samsung_mux_clock top_mux_clks[] __initdata = { static struct samsung_div_clock top_div_clks[] __initdata = { /* DIV_TOP0 */ + DIV(CLK_DIV_ACLK_CAM1_333, "div_aclk_cam1_333", "mout_aclk_cam1_333", + DIV_TOP0, 28, 3), + DIV(CLK_DIV_ACLK_CAM1_400, "div_aclk_cam1_400", "mout_bus_pll_user", + DIV_TOP0, 24, 3), + DIV(CLK_DIV_ACLK_CAM1_552, "div_aclk_cam1_552", "mout_aclk_cam1_552_b", + DIV_TOP0, 20, 3), DIV(CLK_DIV_ACLK_CAM0_333, "div_aclk_cam0_333", "mout_mfc_pll_user", DIV_TOP0, 16, 3), DIV(CLK_DIV_ACLK_CAM0_400, "div_aclk_cam0_400", "mout_bus_pll_user", @@ -464,6 +470,32 @@ static struct samsung_div_clock top_div_clks[] __initdata = { DIV(CLK_DIV_SCLK_JPEG, "div_sclk_jpeg", "mout_sclk_jpeg_c", DIV_TOP_MSCL, 0, 4), + /* DIV_TOP_CAM10 */ + DIV(CLK_DIV_SCLK_ISP_UART, "div_sclk_isp_uart", "mout_sclk_isp_uart", + DIV_TOP_CAM10, 24, 5), + DIV(CLK_DIV_SCLK_ISP_SPI1_B, "div_sclk_isp_spi1_b", + "div_sclk_isp_spi1_a", DIV_TOP_CAM10, 16, 8), + DIV(CLK_DIV_SCLK_ISP_SPI1_A, "div_sclk_isp_spi1_a", + "mout_sclk_isp_spi1", DIV_TOP_CAM10, 12, 4), + DIV(CLK_DIV_SCLK_ISP_SPI0_B, "div_sclk_isp_spi0_b", + "div_sclk_isp_spi0_a", DIV_TOP_CAM10, 4, 8), + DIV(CLK_DIV_SCLK_ISP_SPI0_A, "div_sclk_isp_spi0_a", + "mout_sclk_isp_spi0", DIV_TOP_CAM10, 0, 4), + + /* DIV_TOP_CAM11 */ + DIV(CLK_DIV_SCLK_ISP_SENSOR2_B, "div_sclk_isp_sensor2_b", + "div_sclk_isp_sensor2_a", DIV_TOP_CAM11, 20, 4), + DIV(CLK_DIV_SCLK_ISP_SENSOR2_A, "div_sclk_isp_sensor2_a", + "mout_sclk_isp_sensor2", DIV_TOP_CAM11, 16, 4), + DIV(CLK_DIV_SCLK_ISP_SENSOR1_B, "div_sclk_isp_sensor1_b", + "div_sclk_isp_sensor1_a", DIV_TOP_CAM11, 12, 4), + DIV(CLK_DIV_SCLK_ISP_SENSOR1_A, "div_sclk_isp_sensor1_a", + "mout_sclk_isp_sensor1", DIV_TOP_CAM11, 8, 4), + DIV(CLK_DIV_SCLK_ISP_SENSOR0_B, "div_sclk_isp_sensor0_b", + "div_sclk_isp_sensor0_a", DIV_TOP_CAM11, 12, 4), + DIV(CLK_DIV_SCLK_ISP_SENSOR0_A, "div_sclk_isp_sensor0_a", + "mout_sclk_isp_sensor0", DIV_TOP_CAM11, 8, 4), + /* DIV_TOP_FSYS0 */ DIV(CLK_DIV_SCLK_MMC1_B, "div_sclk_mmc1_b", "div_sclk_mmc1_a", DIV_TOP_FSYS0, 16, 8), @@ -572,6 +604,15 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_ACLK_GSCL_333, "aclk_gscl_333", "div_aclk_gscl_333", ENABLE_ACLK_TOP, 14, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM1_333, "aclk_cam1_333", "div_aclk_cam1_333", + ENABLE_ACLK_TOP, 13, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM1_400, "aclk_cam1_400", "div_aclk_cam1_400", + ENABLE_ACLK_TOP, 12, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM1_552, "aclk_cam1_552", "div_aclk_cam1_552", + ENABLE_ACLK_TOP, 11, + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_CAM0_333, "aclk_cam0_333", "div_aclk_cam0_333", ENABLE_ACLK_TOP, 10, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), @@ -604,6 +645,22 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_SCLK_JPEG_MSCL, "sclk_jpeg_mscl", "div_sclk_jpeg", ENABLE_SCLK_TOP_MSCL, 0, 0, 0), + /* ENABLE_SCLK_TOP_CAM1 */ + GATE(CLK_SCLK_ISP_SENSOR2, "sclk_isp_sensor2", "div_sclk_isp_sensor2_b", + ENABLE_SCLK_TOP_CAM1, 7, 0, 0), + GATE(CLK_SCLK_ISP_SENSOR1, "sclk_isp_sensor1", "div_sclk_isp_sensor1_b", + ENABLE_SCLK_TOP_CAM1, 6, 0, 0), + GATE(CLK_SCLK_ISP_SENSOR0, "sclk_isp_sensor0", "div_sclk_isp_sensor0_b", + ENABLE_SCLK_TOP_CAM1, 5, 0, 0), + GATE(CLK_SCLK_ISP_MCTADC_CAM1, "sclk_isp_mctadc_cam1", "oscclk", + ENABLE_SCLK_TOP_CAM1, 4, 0, 0), + GATE(CLK_SCLK_ISP_UART_CAM1, "sclk_isp_uart_cam1", "div_sclk_isp_uart", + ENABLE_SCLK_TOP_CAM1, 2, 0, 0), + GATE(CLK_SCLK_ISP_SPI1_CAM1, "sclk_isp_spi1_cam1", "div_sclk_isp_spi1_b", + ENABLE_SCLK_TOP_CAM1, 1, 0, 0), + GATE(CLK_SCLK_ISP_SPI0_CAM1, "sclk_isp_spi0_cam1", "div_sclk_isp_spi0_b", + ENABLE_SCLK_TOP_CAM1, 0, 0, 0), + /* ENABLE_SCLK_TOP_FSYS */ GATE(CLK_SCLK_PCIE_100_FSYS, "sclk_pcie_100_fsys", "div_sclk_pcie_100", ENABLE_SCLK_TOP_FSYS, 7, 0, 0), @@ -4986,3 +5043,381 @@ static void __init exynos5433_cmu_cam0_init(struct device_node *np) } CLK_OF_DECLARE(exynos5433_cmu_cam0, "samsung,exynos5433-cmu-cam0", exynos5433_cmu_cam0_init); + +/* + * Register offset definitions for CMU_CAM1 + */ +#define MUX_SEL_CAM10 0x0200 +#define MUX_SEL_CAM11 0x0204 +#define MUX_SEL_CAM12 0x0208 +#define MUX_ENABLE_CAM10 0x0300 +#define MUX_ENABLE_CAM11 0x0304 +#define MUX_ENABLE_CAM12 0x0308 +#define MUX_STAT_CAM10 0x0400 +#define MUX_STAT_CAM11 0x0404 +#define MUX_STAT_CAM12 0x0408 +#define MUX_IGNORE_CAM11 0x0504 +#define DIV_CAM10 0x0600 +#define DIV_CAM11 0x0604 +#define DIV_STAT_CAM10 0x0700 +#define DIV_STAT_CAM11 0x0704 +#define ENABLE_ACLK_CAM10 0X0800 +#define ENABLE_ACLK_CAM11 0X0804 +#define ENABLE_ACLK_CAM12 0X0808 +#define ENABLE_PCLK_CAM1 0X0900 +#define ENABLE_SCLK_CAM1 0X0a00 +#define ENABLE_IP_CAM10 0X0b00 +#define ENABLE_IP_CAM11 0X0b04 +#define ENABLE_IP_CAM12 0X0b08 + +static unsigned long cam1_clk_regs[] __initdata = { + MUX_SEL_CAM10, + MUX_SEL_CAM11, + MUX_SEL_CAM12, + MUX_ENABLE_CAM10, + MUX_ENABLE_CAM11, + MUX_ENABLE_CAM12, + MUX_STAT_CAM10, + MUX_STAT_CAM11, + MUX_STAT_CAM12, + MUX_IGNORE_CAM11, + DIV_CAM10, + DIV_CAM11, + DIV_STAT_CAM10, + DIV_STAT_CAM11, + ENABLE_ACLK_CAM10, + ENABLE_ACLK_CAM11, + ENABLE_ACLK_CAM12, + ENABLE_PCLK_CAM1, + ENABLE_SCLK_CAM1, + ENABLE_IP_CAM10, + ENABLE_IP_CAM11, + ENABLE_IP_CAM12, +}; + +PNAME(mout_sclk_isp_uart_user_p) = { "oscclk", "sclk_isp_uart_cam1", }; +PNAME(mout_sclk_isp_spi1_user_p) = { "oscclk", "sclk_isp_spi1_cam1", }; +PNAME(mout_sclk_isp_spi0_user_p) = { "oscclk", "sclk_isp_spi0_cam1", }; + +PNAME(mout_aclk_cam1_333_user_p) = { "oscclk", "aclk_cam1_333", }; +PNAME(mout_aclk_cam1_400_user_p) = { "oscclk", "aclk_cam1_400", }; +PNAME(mout_aclk_cam1_552_user_p) = { "oscclk", "aclk_cam1_552", }; + +PNAME(mout_phyclk_rxbyteclkhs0_s2b_user_p) = { "oscclk", + "phyclk_rxbyteclkhs0_s2b_phy", }; + +PNAME(mout_aclk_csis2_b_p) = { "mout_aclk_csis2_a", + "mout_aclk_cam1_333_user", }; +PNAME(mout_aclk_csis2_a_p) = { "mout_aclk_cam1_552_user", + "mout_aclk_cam1_400_user", }; + +PNAME(mout_aclk_fd_b_p) = { "mout_aclk_fd_a", + "mout_aclk_cam1_333_user", }; +PNAME(mout_aclk_fd_a_p) = { "mout_aclk_cam1_552_user", + "mout_aclk_cam1_400_user", }; + +PNAME(mout_aclk_lite_c_b_p) = { "mout_aclk_lite_c_a", + "mout_aclk_cam1_333_user", }; +PNAME(mout_aclk_lite_c_a_p) = { "mout_aclk_cam1_552_user", + "mout_aclk_cam1_400_user", }; + +static struct samsung_fixed_rate_clock cam1_fixed_clks[] __initdata = { + FRATE(CLK_PHYCLK_RXBYTEECLKHS0_S2B, "phyclk_rxbyteclkhs0_s2b_phy", NULL, + CLK_IS_ROOT, 100000000), +}; + +static struct samsung_mux_clock cam1_mux_clks[] __initdata = { + /* MUX_SEL_CAM10 */ + MUX(CLK_MOUT_SCLK_ISP_UART_USER, "mout_sclk_isp_uart_user", + mout_sclk_isp_uart_user_p, MUX_SEL_CAM10, 20, 1), + MUX(CLK_MOUT_SCLK_ISP_SPI1_USER, "mout_sclk_isp_spi1_user", + mout_sclk_isp_spi1_user_p, MUX_SEL_CAM10, 16, 1), + MUX(CLK_MOUT_SCLK_ISP_SPI0_USER, "mout_sclk_isp_spi0_user", + mout_sclk_isp_spi0_user_p, MUX_SEL_CAM10, 12, 1), + MUX(CLK_MOUT_ACLK_CAM1_333_USER, "mout_aclk_cam1_333_user", + mout_aclk_cam1_333_user_p, MUX_SEL_CAM10, 8, 1), + MUX(CLK_MOUT_ACLK_CAM1_400_USER, "mout_aclk_cam1_400_user", + mout_aclk_cam1_400_user_p, MUX_SEL_CAM01, 4, 1), + MUX(CLK_MOUT_ACLK_CAM1_552_USER, "mout_aclk_cam1_552_user", + mout_aclk_cam1_552_user_p, MUX_SEL_CAM01, 0, 1), + + /* MUX_SEL_CAM11 */ + MUX(CLK_MOUT_PHYCLK_RXBYTECLKHS0_S2B_USER, + "mout_phyclk_rxbyteclkhs0_s2b_user", + mout_phyclk_rxbyteclkhs0_s2b_user_p, + MUX_SEL_CAM11, 0, 1), + + /* MUX_SEL_CAM12 */ + MUX(CLK_MOUT_ACLK_CSIS2_B, "mout_aclk_csis2_b", mout_aclk_csis2_b_p, + MUX_SEL_CAM12, 20, 1), + MUX(CLK_MOUT_ACLK_CSIS2_A, "mout_aclk_csis2_a", mout_aclk_csis2_a_p, + MUX_SEL_CAM12, 16, 1), + MUX(CLK_MOUT_ACLK_FD_B, "mout_aclk_fd_b", mout_aclk_fd_b_p, + MUX_SEL_CAM12, 12, 1), + MUX(CLK_MOUT_ACLK_FD_A, "mout_aclk_fd_a", mout_aclk_fd_a_p, + MUX_SEL_CAM12, 8, 1), + MUX(CLK_MOUT_ACLK_LITE_C_B, "mout_aclk_lite_c_b", mout_aclk_lite_c_b_p, + MUX_SEL_CAM12, 4, 1), + MUX(CLK_MOUT_ACLK_LITE_C_A, "mout_aclk_lite_c_a", mout_aclk_lite_c_a_p, + MUX_SEL_CAM12, 0, 1), +}; + +static struct samsung_div_clock cam1_div_clks[] __initdata = { + /* DIV_CAM10 */ + DIV(CLK_DIV_SCLK_ISP_WPWM, "div_sclk_isp_wpwm", + "div_pclk_cam1_83", DIV_CAM10, 16, 2), + DIV(CLK_DIV_PCLK_CAM1_83, "div_pclk_cam1_83", + "mout_aclk_cam1_333_user", DIV_CAM10, 12, 2), + DIV(CLK_DIV_PCLK_CAM1_166, "div_pclk_cam1_166", + "mout_aclk_cam1_333_user", DIV_CAM10, 8, 2), + DIV(CLK_DIV_PCLK_DBG_CAM1, "div_pclk_dbg_cam1", + "mout_aclk_cam1_552_user", DIV_CAM10, 4, 3), + DIV(CLK_DIV_ATCLK_CAM1, "div_atclk_cam1", "mout_aclk_cam1_552_user", + DIV_CAM10, 0, 3), + + /* DIV_CAM11 */ + DIV(CLK_DIV_ACLK_CSIS2, "div_aclk_csis2", "mout_aclk_csis2_b", + DIV_CAM11, 16, 3), + DIV(CLK_DIV_PCLK_FD, "div_pclk_fd", "div_aclk_fd", DIV_CAM11, 12, 2), + DIV(CLK_DIV_ACLK_FD, "div_aclk_fd", "mout_aclk_fd_b", DIV_CAM11, 8, 3), + DIV(CLK_DIV_PCLK_LITE_C, "div_pclk_lite_c", "div_aclk_lite_c", + DIV_CAM11, 4, 2), + DIV(CLK_DIV_ACLK_LITE_C, "div_aclk_lite_c", "mout_aclk_lite_c_b", + DIV_CAM11, 0, 3), +}; + +static struct samsung_gate_clock cam1_gate_clks[] __initdata = { + /* ENABLE_ACLK_CAM10 */ + GATE(CLK_ACLK_ISP_GIC, "aclk_isp_gic", "mout_aclk_cam1_333_user", + ENABLE_ACLK_CAM10, 4, 0, 0), + GATE(CLK_ACLK_FD, "aclk_fd", "div_aclk_fd", + ENABLE_ACLK_CAM10, 3, 0, 0), + GATE(CLK_ACLK_LITE_C, "aclk_lite_c", "div_aclk_lite_c", + ENABLE_ACLK_CAM10, 1, 0, 0), + GATE(CLK_ACLK_CSIS2, "aclk_csis2", "div_aclk_csis2", + ENABLE_ACLK_CAM10, 0, 0, 0), + + /* ENABLE_ACLK_CAM11 */ + GATE(CLK_ACLK_ASYNCAPBM_FD, "aclk_asyncapbm_fd", "div_pclk_fd", + ENABLE_ACLK_CAM11, 29, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_FD, "aclk_asyncapbs_fd", "div_pclk_cam1_166", + ENABLE_ACLK_CAM11, 28, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBM_LITE_C, "aclk_asyncapbm_lite_c", + "div_pclk_lite_c", ENABLE_ACLK_CAM11, + 27, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAPBS_LITE_C, "aclk_asyncapbs_lite_c", + "div_pclk_cam1_166", ENABLE_ACLK_CAM11, + 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAHBS_SFRISP2H2, "aclk_asyncahbs_sfrisp2h2", + "div_pclk_cam1_83", ENABLE_ACLK_CAM11, + 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAHBS_SFRISP2H1, "aclk_asyncahbs_sfrisp2h1", + "div_pclk_cam1_83", ENABLE_ACLK_CAM11, + 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_CA5, "aclk_asyncaxim_ca5", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM11, + 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_CA5, "aclk_asyncaxis_ca5", + "mout_aclk_cam1_552_user", ENABLE_ACLK_CAM11, + 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_ISPX2, "aclk_asyncaxis_ispx2", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM11, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_ISPX1, "aclk_asyncaxis_ispx1", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM11, + 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_ISPX0, "aclk_asyncaxis_ispx0", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM11, + 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_ISPEX, "aclk_asyncaxim_ispex", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM11, + 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_ISP3P, "aclk_asyncaxim_isp3p", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM11, + 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_ISP3P, "aclk_asyncaxis_isp3p", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM11, + 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_FD, "aclk_asyncaxim_fd", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM11, + 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_FD, "aclk_asyncaxis_fd", "div_aclk_fd", + ENABLE_ACLK_CAM11, 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIM_LITE_C, "aclk_asyncaxim_lite_c", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM11, + 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_ASYNCAXIS_LITE_C, "aclk_asyncaxis_lite_c", + "div_aclk_lite_c", ENABLE_ACLK_CAM11, + 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_ISP5P, "aclk_ahb2apb_isp5p", "div_pclk_cam1_83", + ENABLE_ACLK_CAM11, 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB2APB_ISP3P, "aclk_ahb2apb_isp3p", "div_pclk_cam1_83", + ENABLE_ACLK_CAM11, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI2APB_ISP3P, "aclk_axi2apb_isp3p", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM11, + 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHB_SFRISP2H, "aclk_ahb_sfrisp2h", "div_pclk_cam1_83", + ENABLE_ACLK_CAM11, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI_ISP_HX_R, "aclk_axi_isp_hx_r", "div_pclk_cam1_166", + ENABLE_ACLK_CAM11, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI_ISP_CX_R, "aclk_axi_isp_cx_r", "div_pclk_cam1_166", + ENABLE_ACLK_CAM11, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI_ISP_HX, "aclk_axi_isp_hx", "mout_aclk_cam1_333_user", + ENABLE_ACLK_CAM11, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXI_ISP_CX, "aclk_axi_isp_cx", "mout_aclk_cam1_333_user", + ENABLE_ACLK_CAM11, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_ISPX, "aclk_xiu_ispx", "mout_aclk_cam1_333_user", + ENABLE_ACLK_CAM11, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_XIU_ISPEX, "aclk_xiu_ispex", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM11, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM1NP_333, "aclk_cam1np_333", "mout_aclk_cam1_333_user", + ENABLE_ACLK_CAM11, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_CAM1ND_400, "aclk_cam1nd_400", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM11, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_ACLK_CAM12 */ + GATE(CLK_ACLK_SMMU_ISPCPU, "aclk_smmu_ispcpu", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM12, + 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_FD, "aclk_smmu_fd", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM12, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_SMMU_LITE_C, "aclk_smmu_lite_c", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM12, + 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_ISP3P, "aclk_bts_isp3p", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM12, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_FD, "aclk_bts_fd", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM12, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_BTS_LITE_C, "aclk_bts_lite_c", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM12, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHBDN_SFRISP2H, "aclk_ahbdn_sfrisp2h", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM12, + 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AHBDN_ISP5P, "aclk_aclk-shbdn_isp5p", + "mout_aclk_cam1_333_user", ENABLE_ACLK_CAM12, + 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_ISP3P, "aclk_axius_isp3p", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM12, + 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_FD, "aclk_axius_fd", "mout_aclk_cam1_400_user", + ENABLE_ACLK_CAM12, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ACLK_AXIUS_LITE_C, "aclk_axius_lite_c", + "mout_aclk_cam1_400_user", ENABLE_ACLK_CAM12, + 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_CAM1 */ + GATE(CLK_PCLK_SMMU_ISPCPU, "pclk_smmu_ispcpu", "div_pclk_cam1_166", + ENABLE_PCLK_CAM1, 27, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_FD, "pclk_smmu_fd", "div_pclk_cam1_166", + ENABLE_PCLK_CAM1, 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SMMU_LITE_C, "pclk_smmu_lite_c", "div_pclk_cam1_166", + ENABLE_PCLK_CAM1, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_ISP3P, "pclk_bts_isp3p", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_FD, "pclk_bts_fd", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_BTS_LITE_C, "pclk_bts_lite_c", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 22, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXIM_CA5, "pclk_asyncaxim_ca5", "div_pclk_cam1_166", + ENABLE_PCLK_CAM1, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXIM_ISPEX, "pclk_asyncaxim_ispex", + "div_pclk_cam1_83", ENABLE_PCLK_CAM1, + 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXIM_ISP3P, "pclk_asyncaxim_isp3p", + "div_pclk_cam1_83", ENABLE_PCLK_CAM1, + 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXIM_FD, "pclk_asyncaxim_fd", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ASYNCAXIM_LITE_C, "pclk_asyncaxim_lite_c", + "div_pclk_cam1_83", ENABLE_PCLK_CAM1, + 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_PMU_CAM1, "pclk_pmu_cam1", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_SYSREG_CAM1, "pclk_sysreg_cam1", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_CMU_CAM1_LOCAL, "pclk_cmu_cam1_local", + "div_pclk_cam1_166", ENABLE_PCLK_CAM1, + 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_MCTADC, "pclk_isp_mctadc", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_WDT, "pclk_isp_wdt", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_PWM, "pclk_isp_pwm", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_UART, "pclk_isp_uart", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_MCUCTL, "pclk_isp_mcuctl", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_SPI1, "pclk_isp_spi1", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_SPI0, "pclk_isp_spi0", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_I2C2, "pclk_isp_i2c2", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_I2C1, "pclk_isp_i2c1", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_I2C0, "pclk_isp_i2c0", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_ISP_MPWM, "pclk_isp_wpwm", "div_pclk_cam1_83", + ENABLE_PCLK_CAM1, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_FD, "pclk_fd", "div_pclk_fd", + ENABLE_PCLK_CAM1, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_LITE_C, "pclk_lite_c", "div_pclk_lite_c", + ENABLE_PCLK_CAM1, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PCLK_CSIS2, "pclk_csis2", "div_pclk_cam1_166", + ENABLE_PCLK_CAM1, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_SCLK_CAM1 */ + GATE(CLK_SCLK_ISP_I2C2, "sclk_isp_i2c2", "oscclk", ENABLE_SCLK_CAM1, + 15, 0, 0), + GATE(CLK_SCLK_ISP_I2C1, "sclk_isp_i2c1", "oscclk", ENABLE_SCLK_CAM1, + 14, 0, 0), + GATE(CLK_SCLK_ISP_I2C0, "sclk_isp_i2c0", "oscclk", ENABLE_SCLK_CAM1, + 13, 0, 0), + GATE(CLK_SCLK_ISP_PWM, "sclk_isp_pwm", "oscclk", ENABLE_SCLK_CAM1, + 12, 0, 0), + GATE(CLK_PHYCLK_RXBYTECLKHS0_S2B, "phyclk_rxbyteclkhs0_s2b", + "mout_phyclk_rxbyteclkhs0_s2b_user", + ENABLE_SCLK_CAM1, 11, 0, 0), + GATE(CLK_SCLK_LITE_C_FREECNT, "sclk_lite_c_freecnt", "div_pclk_lite_c", + ENABLE_SCLK_CAM1, 10, 0, 0), + GATE(CLK_SCLK_PIXELASYNCM_FD, "sclk_pixelasyncm_fd", "div_aclk_fd", + ENABLE_SCLK_CAM1, 9, 0, 0), + GATE(CLK_SCLK_ISP_MCTADC, "sclk_isp_mctadc", "sclk_isp_mctadc_cam1", + ENABLE_SCLK_CAM1, 7, 0, 0), + GATE(CLK_SCLK_ISP_UART, "sclk_isp_uart", "mout_sclk_isp_uart_user", + ENABLE_SCLK_CAM1, 6, 0, 0), + GATE(CLK_SCLK_ISP_SPI1, "sclk_isp_spi1", "mout_sclk_isp_spi1_user", + ENABLE_SCLK_CAM1, 5, 0, 0), + GATE(CLK_SCLK_ISP_SPI0, "sclk_isp_spi0", "mout_sclk_isp_spi0_user", + ENABLE_SCLK_CAM1, 4, 0, 0), + GATE(CLK_SCLK_ISP_MPWM, "sclk_isp_wpwm", "div_sclk_isp_wpwm", + ENABLE_SCLK_CAM1, 3, 0, 0), + GATE(CLK_PCLK_DBG_ISP, "sclk_dbg_isp", "div_pclk_dbg_cam1", + ENABLE_SCLK_CAM1, 2, 0, 0), + GATE(CLK_ATCLK_ISP, "atclk_isp", "div_atclk_cam1", + ENABLE_SCLK_CAM1, 1, 0, 0), + GATE(CLK_SCLK_ISP_CA5, "sclk_isp_ca5", "mout_aclk_cam1_552_user", + ENABLE_SCLK_CAM1, 0, 0, 0), +}; + +static struct samsung_cmu_info cam1_cmu_info __initdata = { + .mux_clks = cam1_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cam1_mux_clks), + .div_clks = cam1_div_clks, + .nr_div_clks = ARRAY_SIZE(cam1_div_clks), + .gate_clks = cam1_gate_clks, + .nr_gate_clks = ARRAY_SIZE(cam1_gate_clks), + .fixed_clks = cam1_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(cam1_fixed_clks), + .nr_clk_ids = CAM1_NR_CLK, + .clk_regs = cam1_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cam1_clk_regs), +}; + +static void __init exynos5433_cmu_cam1_init(struct device_node *np) +{ + samsung_cmu_register_one(np, &cam1_cmu_info); +} +CLK_OF_DECLARE(exynos5433_cmu_cam1, "samsung,exynos5433-cmu-cam1", + exynos5433_cmu_cam1_init); diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index f99cde7a278d..4853bc598b57 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -121,6 +121,20 @@ #define CLK_DIV_ACLK_CAM0_333 148 #define CLK_DIV_ACLK_CAM0_400 149 #define CLK_DIV_ACLK_CAM0_552 150 +#define CLK_DIV_ACLK_CAM1_333 151 +#define CLK_DIV_ACLK_CAM1_400 152 +#define CLK_DIV_ACLK_CAM1_552 153 +#define CLK_DIV_SCLK_ISP_UART 154 +#define CLK_DIV_SCLK_ISP_SPI1_B 155 +#define CLK_DIV_SCLK_ISP_SPI1_A 156 +#define CLK_DIV_SCLK_ISP_SPI0_B 157 +#define CLK_DIV_SCLK_ISP_SPI0_A 158 +#define CLK_DIV_SCLK_ISP_SENSOR2_B 159 +#define CLK_DIV_SCLK_ISP_SENSOR2_A 160 +#define CLK_DIV_SCLK_ISP_SENSOR1_B 161 +#define CLK_DIV_SCLK_ISP_SENSOR1_A 162 +#define CLK_DIV_SCLK_ISP_SENSOR0_B 163 +#define CLK_DIV_SCLK_ISP_SENSOR0_A 164 #define CLK_ACLK_PERIC_66 200 #define CLK_ACLK_PERIS_66 201 @@ -165,8 +179,18 @@ #define CLK_ACLK_CAM0_333 240 #define CLK_ACLK_CAM0_400 241 #define CLK_ACLK_CAM0_552 242 - -#define TOP_NR_CLK 243 +#define CLK_ACLK_CAM1_333 243 +#define CLK_ACLK_CAM1_400 244 +#define CLK_ACLK_CAM1_552 245 +#define CLK_SCLK_ISP_SENSOR2 246 +#define CLK_SCLK_ISP_SENSOR1 247 +#define CLK_SCLK_ISP_SENSOR0 248 +#define CLK_SCLK_ISP_MCTADC_CAM1 249 +#define CLK_SCLK_ISP_UART_CAM1 250 +#define CLK_SCLK_ISP_SPI1_CAM1 251 +#define CLK_SCLK_ISP_SPI0_CAM1 252 + +#define TOP_NR_CLK 253 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -1257,4 +1281,123 @@ #define CAM0_NR_CLK 134 +/* CMU_CAM1 */ +#define CLK_PHYCLK_RXBYTEECLKHS0_S2B 1 + +#define CLK_MOUT_SCLK_ISP_UART_USER 2 +#define CLK_MOUT_SCLK_ISP_SPI1_USER 3 +#define CLK_MOUT_SCLK_ISP_SPI0_USER 4 +#define CLK_MOUT_ACLK_CAM1_333_USER 5 +#define CLK_MOUT_ACLK_CAM1_400_USER 6 +#define CLK_MOUT_ACLK_CAM1_552_USER 7 +#define CLK_MOUT_PHYCLK_RXBYTECLKHS0_S2B_USER 8 +#define CLK_MOUT_ACLK_CSIS2_B 9 +#define CLK_MOUT_ACLK_CSIS2_A 10 +#define CLK_MOUT_ACLK_FD_B 11 +#define CLK_MOUT_ACLK_FD_A 12 +#define CLK_MOUT_ACLK_LITE_C_B 13 +#define CLK_MOUT_ACLK_LITE_C_A 14 + +#define CLK_DIV_SCLK_ISP_WPWM 15 +#define CLK_DIV_PCLK_CAM1_83 16 +#define CLK_DIV_PCLK_CAM1_166 17 +#define CLK_DIV_PCLK_DBG_CAM1 18 +#define CLK_DIV_ATCLK_CAM1 19 +#define CLK_DIV_ACLK_CSIS2 20 +#define CLK_DIV_PCLK_FD 21 +#define CLK_DIV_ACLK_FD 22 +#define CLK_DIV_PCLK_LITE_C 23 +#define CLK_DIV_ACLK_LITE_C 24 + +#define CLK_ACLK_ISP_GIC 25 +#define CLK_ACLK_FD 26 +#define CLK_ACLK_LITE_C 27 +#define CLK_ACLK_CSIS2 28 +#define CLK_ACLK_ASYNCAPBM_FD 29 +#define CLK_ACLK_ASYNCAPBS_FD 30 +#define CLK_ACLK_ASYNCAPBM_LITE_C 31 +#define CLK_ACLK_ASYNCAPBS_LITE_C 32 +#define CLK_ACLK_ASYNCAHBS_SFRISP2H2 33 +#define CLK_ACLK_ASYNCAHBS_SFRISP2H1 34 +#define CLK_ACLK_ASYNCAXIM_CA5 35 +#define CLK_ACLK_ASYNCAXIS_CA5 36 +#define CLK_ACLK_ASYNCAXIS_ISPX2 37 +#define CLK_ACLK_ASYNCAXIS_ISPX1 38 +#define CLK_ACLK_ASYNCAXIS_ISPX0 39 +#define CLK_ACLK_ASYNCAXIM_ISPEX 40 +#define CLK_ACLK_ASYNCAXIM_ISP3P 41 +#define CLK_ACLK_ASYNCAXIS_ISP3P 42 +#define CLK_ACLK_ASYNCAXIM_FD 43 +#define CLK_ACLK_ASYNCAXIS_FD 44 +#define CLK_ACLK_ASYNCAXIM_LITE_C 45 +#define CLK_ACLK_ASYNCAXIS_LITE_C 46 +#define CLK_ACLK_AHB2APB_ISP5P 47 +#define CLK_ACLK_AHB2APB_ISP3P 48 +#define CLK_ACLK_AXI2APB_ISP3P 49 +#define CLK_ACLK_AHB_SFRISP2H 50 +#define CLK_ACLK_AXI_ISP_HX_R 51 +#define CLK_ACLK_AXI_ISP_CX_R 52 +#define CLK_ACLK_AXI_ISP_HX 53 +#define CLK_ACLK_AXI_ISP_CX 54 +#define CLK_ACLK_XIU_ISPX 55 +#define CLK_ACLK_XIU_ISPEX 56 +#define CLK_ACLK_CAM1NP_333 57 +#define CLK_ACLK_CAM1ND_400 58 +#define CLK_ACLK_SMMU_ISPCPU 59 +#define CLK_ACLK_SMMU_FD 60 +#define CLK_ACLK_SMMU_LITE_C 61 +#define CLK_ACLK_BTS_ISP3P 62 +#define CLK_ACLK_BTS_FD 63 +#define CLK_ACLK_BTS_LITE_C 64 +#define CLK_ACLK_AHBDN_SFRISP2H 65 +#define CLK_ACLK_AHBDN_ISP5P 66 +#define CLK_ACLK_AXIUS_ISP3P 67 +#define CLK_ACLK_AXIUS_FD 68 +#define CLK_ACLK_AXIUS_LITE_C 69 +#define CLK_PCLK_SMMU_ISPCPU 70 +#define CLK_PCLK_SMMU_FD 71 +#define CLK_PCLK_SMMU_LITE_C 72 +#define CLK_PCLK_BTS_ISP3P 73 +#define CLK_PCLK_BTS_FD 74 +#define CLK_PCLK_BTS_LITE_C 75 +#define CLK_PCLK_ASYNCAXIM_CA5 76 +#define CLK_PCLK_ASYNCAXIM_ISPEX 77 +#define CLK_PCLK_ASYNCAXIM_ISP3P 78 +#define CLK_PCLK_ASYNCAXIM_FD 79 +#define CLK_PCLK_ASYNCAXIM_LITE_C 80 +#define CLK_PCLK_PMU_CAM1 81 +#define CLK_PCLK_SYSREG_CAM1 82 +#define CLK_PCLK_CMU_CAM1_LOCAL 83 +#define CLK_PCLK_ISP_MCTADC 84 +#define CLK_PCLK_ISP_WDT 85 +#define CLK_PCLK_ISP_PWM 86 +#define CLK_PCLK_ISP_UART 87 +#define CLK_PCLK_ISP_MCUCTL 88 +#define CLK_PCLK_ISP_SPI1 89 +#define CLK_PCLK_ISP_SPI0 90 +#define CLK_PCLK_ISP_I2C2 91 +#define CLK_PCLK_ISP_I2C1 92 +#define CLK_PCLK_ISP_I2C0 93 +#define CLK_PCLK_ISP_MPWM 94 +#define CLK_PCLK_FD 95 +#define CLK_PCLK_LITE_C 96 +#define CLK_PCLK_CSIS2 97 +#define CLK_SCLK_ISP_I2C2 98 +#define CLK_SCLK_ISP_I2C1 99 +#define CLK_SCLK_ISP_I2C0 100 +#define CLK_SCLK_ISP_PWM 101 +#define CLK_PHYCLK_RXBYTECLKHS0_S2B 102 +#define CLK_SCLK_LITE_C_FREECNT 103 +#define CLK_SCLK_PIXELASYNCM_FD 104 +#define CLK_SCLK_ISP_MCTADC 105 +#define CLK_SCLK_ISP_UART 106 +#define CLK_SCLK_ISP_SPI1 107 +#define CLK_SCLK_ISP_SPI0 108 +#define CLK_SCLK_ISP_MPWM 109 +#define CLK_PCLK_DBG_ISP 110 +#define CLK_ATCLK_ISP 111 +#define CLK_SCLK_ISP_CA5 112 + +#define CAM1_NR_CLK 113 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From b2f0e5f28e0686c0d5db238357a2e32555e97633 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 4 Feb 2015 10:12:59 +0900 Subject: clk: samsung: exynos5433: Move CLK_SCLK_HDMI_SPDIF_DISP clock to CMU_TOP domain This patch fixes the bug of CLK_SCLK_HDMI_SPDIF_DISP clock because this clock should be included in CMU_TOP domain. So, this patch moves the CLK_SCLK_HDMI_ SPDIF_DISP clock from CMU_MIF to CMU_TOP domain. Reported-by: Sylwester Nawrocki Signed-off-by: Chanwoo Choi Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 10 +++++----- include/dt-bindings/clock/exynos5433.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 1a005c1f7c4b..387e3e39e635 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -661,6 +661,11 @@ static struct samsung_gate_clock top_gate_clks[] __initdata = { GATE(CLK_SCLK_ISP_SPI0_CAM1, "sclk_isp_spi0_cam1", "div_sclk_isp_spi0_b", ENABLE_SCLK_TOP_CAM1, 0, 0, 0), + /* ENABLE_SCLK_TOP_DISP */ + GATE(CLK_SCLK_HDMI_SPDIF_DISP, "sclk_hdmi_spdif_disp", + "mout_sclk_hdmi_spdif", ENABLE_SCLK_TOP_DISP, 0, + CLK_IGNORE_UNUSED, 0), + /* ENABLE_SCLK_TOP_FSYS */ GATE(CLK_SCLK_PCIE_100_FSYS, "sclk_pcie_100_fsys", "div_sclk_pcie_100", ENABLE_SCLK_TOP_FSYS, 7, 0, 0), @@ -1521,11 +1526,6 @@ static struct samsung_gate_clock mif_gate_clks[] __initdata = { ENABLE_SCLK_MIF, 1, CLK_IGNORE_UNUSED, 0), GATE(CLK_SCLK_BUS_PLL_ATLAS, "sclk_bus_pll_atlas", "sclk_bus_pll", ENABLE_SCLK_MIF, 0, CLK_IGNORE_UNUSED, 0), - - /* ENABLE_SCLK_TOP_DISP */ - GATE(CLK_SCLK_HDMI_SPDIF_DISP, "sclk_hdmi_spdif_disp", - "mout_sclk_hdmi_spdif", ENABLE_SCLK_TOP_DISP, 0, - CLK_IGNORE_UNUSED, 0), }; static struct samsung_cmu_info mif_cmu_info __initdata = { diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 4853bc598b57..5bd80d5ecd0f 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -189,8 +189,9 @@ #define CLK_SCLK_ISP_UART_CAM1 250 #define CLK_SCLK_ISP_SPI1_CAM1 251 #define CLK_SCLK_ISP_SPI0_CAM1 252 +#define CLK_SCLK_HDMI_SPDIF_DISP 253 -#define TOP_NR_CLK 253 +#define TOP_NR_CLK 254 /* CMU_CPIF */ #define CLK_FOUT_MPHY_PLL 1 @@ -397,9 +398,8 @@ #define CLK_SCLK_BUS_PLL 198 #define CLK_SCLK_BUS_PLL_APOLLO 199 #define CLK_SCLK_BUS_PLL_ATLAS 200 -#define CLK_SCLK_HDMI_SPDIF_DISP 201 -#define MIF_NR_CLK 202 +#define MIF_NR_CLK 201 /* CMU_PERIC */ #define CLK_PCLK_SPI2 1 -- cgit v1.2.3 From bf2b8a515530ee7e3b25214d7ec52c6827f12d70 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 29 Jan 2015 14:13:38 +0000 Subject: drm/i915/skl: Split the SKL PCI ids by GT We need to have a separate GT3 struct intel_device_info to declare they have a second VCS. Let's start by splitting the PCI ids per-GT. Signed-off-by: Damien Lespiau Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- include/drm/i915_pciids.h | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index 180ad0e6de21..38a7c8049e47 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -259,21 +259,31 @@ INTEL_VGA_DEVICE(0x22b2, info), \ INTEL_VGA_DEVICE(0x22b3, info) -#define INTEL_SKL_IDS(info) \ - INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \ +#define INTEL_SKL_GT1_IDS(info) \ INTEL_VGA_DEVICE(0x1906, info), /* ULT GT1 */ \ - INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \ - INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \ INTEL_VGA_DEVICE(0x190E, info), /* ULX GT1 */ \ + INTEL_VGA_DEVICE(0x1902, info), /* DT GT1 */ \ + INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \ + INTEL_VGA_DEVICE(0x190A, info) /* SRV GT1 */ + +#define INTEL_SKL_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \ + INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \ INTEL_VGA_DEVICE(0x191E, info), /* ULX GT2 */ \ INTEL_VGA_DEVICE(0x1912, info), /* DT GT2 */ \ - INTEL_VGA_DEVICE(0x1902, info), /* DT GT1 */ \ INTEL_VGA_DEVICE(0x191B, info), /* Halo GT2 */ \ - INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \ - INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \ INTEL_VGA_DEVICE(0x191A, info), /* SRV GT2 */ \ - INTEL_VGA_DEVICE(0x192A, info), /* SRV GT3 */ \ - INTEL_VGA_DEVICE(0x190A, info), /* SRV GT1 */ \ INTEL_VGA_DEVICE(0x191D, info) /* WKS GT2 */ +#define INTEL_SKL_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \ + INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \ + INTEL_VGA_DEVICE(0x192A, info) /* SRV GT3 */ \ + +#define INTEL_SKL_IDS(info) \ + INTEL_SKL_GT1_IDS(info), \ + INTEL_SKL_GT2_IDS(info), \ + INTEL_SKL_GT3_IDS(info) + + #endif /* _I915_PCIIDS_H */ -- cgit v1.2.3 From e3eb3250d84ef97b766312345774367b6a310db8 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 5 Feb 2015 14:41:52 +0000 Subject: drm: add support for tiled/compressed/etc modifier in addfb2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In DRM/KMS we are lacking a good way to deal with tiled/compressed formats. Especially in the case of dmabuf/prime buffer sharing, where we cannot always rely on under-the-hood flags passed to driver specific gem-create ioctl to pass around these extra flags. The proposal is to add a per-plane format modifier. This allows to, if necessary, use different tiling patters for sub-sampled planes, etc. The format modifiers are added at the end of the ioctl struct, so for legacy userspace it will be zero padded. v1: original v1.5: increase modifier to 64b v2: Incorporate review comments from the big thread, plus a few more. - Add a getcap so that userspace doesn't have to jump through hoops. - Allow modifiers only when a flag is set. That way drivers know when they're dealing with old userspace and need to fish out e.g. tiling from other information. - After rolling out checks for ->modifier to all drivers I've decided that this is way too fragile and needs an explicit opt-in flag. So do that instead. - Add a define (just for documentation really) for the "NONE" modifier. Imo we don't need to add mask #defines since drivers really should only do exact matches against values defined with fourcc_mod_code. - Drop the Samsung tiling modifier on Rob's request since he's not yet sure whether that one is accurate. v3: - Also add a new ->modifier[] array to struct drm_framebuffer and fill it in drm_helper_mode_fill_fb_struct. Requested by Tvrkto Uruslin. - Remove TODO in comment and add code comment that modifiers should be properly documented, requested by Rob. Cc: Rob Clark Cc: Tvrtko Ursulin Cc: Laurent Pinchart Cc: Daniel Stone Cc: Ville Syrjälä Cc: Michel Dänzer Signed-off-by: Rob Clark (v1.5) Reviewed-by: Rob Clark Reviewed-by: Daniel Stone Acked-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 14 +++++++++++++- drivers/gpu/drm/drm_crtc_helper.c | 1 + drivers/gpu/drm/drm_ioctl.c | 3 +++ include/drm/drm_crtc.h | 4 ++++ include/uapi/drm/drm.h | 1 + include/uapi/drm/drm_fourcc.h | 32 ++++++++++++++++++++++++++++++++ include/uapi/drm/drm_mode.h | 9 +++++++++ 7 files changed, 63 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index ad2934ba0bd2..b15d720eda4c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3314,6 +3314,12 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); return -EINVAL; } + + if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) { + DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", + r->modifier[i], i); + return -EINVAL; + } } return 0; @@ -3327,7 +3333,7 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, struct drm_framebuffer *fb; int ret; - if (r->flags & ~DRM_MODE_FB_INTERLACED) { + if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) { DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); return ERR_PTR(-EINVAL); } @@ -3343,6 +3349,12 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, return ERR_PTR(-EINVAL); } + if (r->flags & DRM_MODE_FB_MODIFIERS && + !dev->mode_config.allow_fb_modifiers) { + DRM_DEBUG_KMS("driver does not support fb modifiers\n"); + return ERR_PTR(-EINVAL); + } + ret = framebuffer_check(r); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index b1979e7bdc88..3053aab968f9 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -837,6 +837,7 @@ void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, for (i = 0; i < 4; i++) { fb->pitches[i] = mode_cmd->pitches[i]; fb->offsets[i] = mode_cmd->offsets[i]; + fb->modifier[i] = mode_cmd->modifier[i]; } drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth, &fb->bits_per_pixel); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 3785d66721f2..a6d773a61c2d 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -321,6 +321,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_ else req->value = 64; break; + case DRM_CAP_ADDFB2_MODIFIERS: + req->value = dev->mode_config.allow_fb_modifiers; + break; default: return -EINVAL; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 0ebd9286b332..cee54c45eba9 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -202,6 +202,7 @@ struct drm_framebuffer { const struct drm_framebuffer_funcs *funcs; unsigned int pitches[4]; unsigned int offsets[4]; + uint64_t modifier[4]; unsigned int width; unsigned int height; /* depth can be 15 or 16 */ @@ -1152,6 +1153,9 @@ struct drm_mode_config { /* whether async page flip is supported or not */ bool async_page_flip; + /* whether the driver supports fb modifiers */ + bool allow_fb_modifiers; + /* cursor size */ uint32_t cursor_width, cursor_height; }; diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 01b2d6d0e355..ff6ef62d084b 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -630,6 +630,7 @@ struct drm_gem_open { */ #define DRM_CAP_CURSOR_WIDTH 0x8 #define DRM_CAP_CURSOR_HEIGHT 0x9 +#define DRM_CAP_ADDFB2_MODIFIERS 0x10 /** DRM_IOCTL_GET_CAP ioctl argument type */ struct drm_get_cap { diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 646ae5f39f42..622109677747 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -132,4 +132,36 @@ #define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ #define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ + +/* + * Format Modifiers: + * + * Format modifiers describe, typically, a re-ordering or modification + * of the data in a plane of an FB. This can be used to express tiled/ + * swizzled formats, or compression, or a combination of the two. + * + * The upper 8 bits of the format modifier are a vendor-id as assigned + * below. The lower 56 bits are assigned as vendor sees fit. + */ + +/* Vendor Ids: */ +#define DRM_FORMAT_MOD_NONE 0 +#define DRM_FORMAT_MOD_VENDOR_INTEL 0x01 +#define DRM_FORMAT_MOD_VENDOR_AMD 0x02 +#define DRM_FORMAT_MOD_VENDOR_NV 0x03 +#define DRM_FORMAT_MOD_VENDOR_SAMSUNG 0x04 +#define DRM_FORMAT_MOD_VENDOR_QCOM 0x05 +/* add more to the end as needed */ + +#define fourcc_mod_code(vendor, val) \ + ((((u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | (val & 0x00ffffffffffffffL)) + +/* + * Format Modifier tokens: + * + * When adding a new token please document the layout with a code comment, + * similar to the fourcc codes above. drm_fourcc.h is considered the + * authoritative source for all of these. + */ + #endif /* DRM_FOURCC_H */ diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index ca788e01dab2..dbeba949462a 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -336,6 +336,7 @@ struct drm_mode_fb_cmd { }; #define DRM_MODE_FB_INTERLACED (1<<0) /* for interlaced framebuffers */ +#define DRM_MODE_FB_MODIFIERS (1<<1) /* enables ->modifer[] */ struct drm_mode_fb_cmd2 { __u32 fb_id; @@ -356,10 +357,18 @@ struct drm_mode_fb_cmd2 { * So it would consist of Y as offsets[0] and UV as * offsets[1]. Note that offsets[0] will generally * be 0 (but this is not required). + * + * To accommodate tiled, compressed, etc formats, a per-plane + * modifier can be specified. The default value of zero + * indicates "native" format as specified by the fourcc. + * Vendor specific modifier token. This allows, for example, + * different tiling/swizzling pattern on different planes. + * See discussion above of DRM_FORMAT_MOD_xxx. */ __u32 handles[4]; __u32 pitches[4]; /* pitch for each plane */ __u32 offsets[4]; /* offset of each plane */ + __u64 modifier[4]; /* ie, tiling, compressed (per plane) */ }; #define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01 -- cgit v1.2.3 From 93b81f5102a7cd270a305c2741b17c8d44bb0629 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 10 Feb 2015 17:16:05 +0000 Subject: drm/i915: Add tiled framebuffer modifiers To be used from the new addfb2 extension. v2: - Drop Intel-specific untiled modfier. - Move to drm_fourcc.h. - Document layouts a bit and denote them as platform-specific and not useable for cross-driver sharing. - Add Y-tiling for completeness. - Drop special docstring markers to avoid confusing kerneldoc. v3: Give Y-tiling a unique idea, noticed by Tvrtko. Signed-off-by: Tvrtko Ursulin (v1) Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + include/uapi/drm/drm_fourcc.h | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3da3dc527315..99b25928df2f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -31,6 +31,7 @@ #define _I915_DRV_H_ #include +#include #include "i915_reg.h" #include "intel_bios.h" diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 622109677747..4837c3d2319a 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -164,4 +164,35 @@ * authoritative source for all of these. */ +/* Intel framebuffer modifiers */ + +/* + * Intel X-tiling layout + * + * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb) + * in row-major layout. Within the tile bytes are laid out row-major, with + * a platform-dependent stride. On top of that the memory can apply + * platform-depending swizzling of some higher address bits into bit6. + * + * This format is highly platforms specific and not useful for cross-driver + * sharing. It exists since on a given platform it does uniquely identify the + * layout in a simple way for i915-specific userspace. + */ +#define I915_FORMAT_MOD_X_TILED fourcc_mod_code(INTEL, 1) + +/* + * Intel Y-tiling layout + * + * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb) + * in row-major layout. Within the tile bytes are laid out in OWORD (16 bytes) + * chunks column-major, with a platform-dependent height. On top of that the + * memory can apply platform-depending swizzling of some higher address bits + * into bit6. + * + * This format is highly platforms specific and not useful for cross-driver + * sharing. It exists since on a given platform it does uniquely identify the + * layout in a simple way for i915-specific userspace. + */ +#define I915_FORMAT_MOD_Y_TILED fourcc_mod_code(INTEL, 2) + #endif /* DRM_FOURCC_H */ -- cgit v1.2.3 From e31a0ba7df6ce21ac4ed58c4182ec12ca8fd78fb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 2 Jan 2015 12:18:23 -0300 Subject: [media] media: Fix DVB devnode representation at media controller The previous provision for DVB media controller support were to define an ID (likely meaning the adapter number) for the DVB devnodes. This is just plain wrong. Just like V4L, DVB devices (and any other device node)) are uniquely identified via a (major, minor) tuple. This is enough to uniquely identify a devnode, no matter what API it implements. So, before we go too far, let's mark the old v4l, fb, dvb and alsa "devnode" info as deprecated, and just call it as "dev". We can latter add fields specific to each API if needed. As we don't want to break compilation on already existing apps, let's just keep the old definitions as-is, adding a note that those are deprecated at media-entity.h. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dev.c | 4 ++-- drivers/media/v4l2-core/v4l2-device.c | 4 ++-- include/media/media-entity.h | 12 +----------- include/uapi/linux/media.h | 15 +++++++++++++++ 4 files changed, 20 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 86bb93fd7db8..d89d5cb465d9 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -943,8 +943,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr, vdev->vfl_type != VFL_TYPE_SUBDEV) { vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; vdev->entity.name = vdev->name; - vdev->entity.info.v4l.major = VIDEO_MAJOR; - vdev->entity.info.v4l.minor = vdev->minor; + vdev->entity.info.dev.major = VIDEO_MAJOR; + vdev->entity.info.dev.minor = vdev->minor; ret = media_device_register_entity(vdev->v4l2_dev->mdev, &vdev->entity); if (ret < 0) diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index 015f92aab44a..204cc67c84e8 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -248,8 +248,8 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) goto clean_up; } #if defined(CONFIG_MEDIA_CONTROLLER) - sd->entity.info.v4l.major = VIDEO_MAJOR; - sd->entity.info.v4l.minor = vdev->minor; + sd->entity.info.dev.major = VIDEO_MAJOR; + sd->entity.info.dev.minor = vdev->minor; #endif sd->devnode = vdev; } diff --git a/include/media/media-entity.h b/include/media/media-entity.h index e00459185d20..d6d74bcfe183 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -87,17 +87,7 @@ struct media_entity { struct { u32 major; u32 minor; - } v4l; - struct { - u32 major; - u32 minor; - } fb; - struct { - u32 card; - u32 device; - u32 subdevice; - } alsa; - int dvb; + } dev; /* Sub-device specifications */ /* Nothing needed yet */ diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index d847c760e8f0..418f4fec391a 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -75,6 +75,20 @@ struct media_entity_desc { union { /* Node specifications */ + struct { + __u32 major; + __u32 minor; + } dev; + +#if 1 + /* + * DEPRECATED: previous node specifications. Kept just to + * avoid breaking compilation, but media_entity_desc.dev + * should be used instead. In particular, alsa and dvb + * fields below are wrong: for all devnodes, there should + * be just major/minor inside the struct, as this is enough + * to represent any devnode, no matter what type. + */ struct { __u32 major; __u32 minor; @@ -89,6 +103,7 @@ struct media_entity_desc { __u32 subdevice; } alsa; int dvb; +#endif /* Sub-device specifications */ /* Nothing needed yet */ -- cgit v1.2.3 From 1d20f9f6330c988505e51f5010656978fd70cd0c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Jan 2015 11:09:39 -0300 Subject: [media] media: add new types for DVB devnodes Most of the DVB subdevs have already their own devnode. Add support for them at the media controller API. Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/media.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index 418f4fec391a..4c8f26243252 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -50,7 +50,14 @@ struct media_device_info { #define MEDIA_ENT_T_DEVNODE_V4L (MEDIA_ENT_T_DEVNODE + 1) #define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENT_T_DEVNODE + 2) #define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_T_DEVNODE + 3) -#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_T_DEVNODE + 4) +#define MEDIA_ENT_T_DEVNODE_DVB_FE (MEDIA_ENT_T_DEVNODE + 4) +#define MEDIA_ENT_T_DEVNODE_DVB_DEMUX (MEDIA_ENT_T_DEVNODE + 5) +#define MEDIA_ENT_T_DEVNODE_DVB_DVR (MEDIA_ENT_T_DEVNODE + 6) +#define MEDIA_ENT_T_DEVNODE_DVB_CA (MEDIA_ENT_T_DEVNODE + 7) +#define MEDIA_ENT_T_DEVNODE_DVB_NET (MEDIA_ENT_T_DEVNODE + 8) + +/* Legacy symbol. Use it to avoid userspace compilation breakages */ +#define MEDIA_ENT_T_DEVNODE_DVB MEDIA_ENT_T_DEVNODE_DVB_FE #define MEDIA_ENT_T_V4L2_SUBDEV (2 << MEDIA_ENT_TYPE_SHIFT) #define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENT_T_V4L2_SUBDEV + 1) -- cgit v1.2.3 From 91b0f3a06e432d01c66cd05973628a2ec3bde9ed Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 26 Jan 2015 08:53:18 -0300 Subject: [media] media: add a subdev type for tuner Add MEDIA_ENT_T_V4L2_SUBDEV_TUNER to represent the V4L2 (and dvb) tuner subdevices. Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/media.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index 4c8f26243252..52cc2a6b19b7 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -66,6 +66,8 @@ struct media_device_info { /* A converter of analogue video to its digital representation. */ #define MEDIA_ENT_T_V4L2_SUBDEV_DECODER (MEDIA_ENT_T_V4L2_SUBDEV + 4) +#define MEDIA_ENT_T_V4L2_SUBDEV_TUNER (MEDIA_ENT_T_V4L2_SUBDEV + 5) + #define MEDIA_ENT_FL_DEFAULT (1 << 0) struct media_entity_desc { -- cgit v1.2.3 From 9625604cebcb3f5be2e692408274734e8ae63979 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 13 Feb 2015 21:03:42 +0100 Subject: drm/irq: Add drm_crtc_vblank_reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At driver load we need to tell the vblank code about the state of the pipes, so that the logic around reject vblank_get when the pipe is off works correctly. Thus far i915 used drm_vblank_off, but one of the side-effects of it is that it also saves the vblank counter. And for that it calls down into the ->get_vblank_counter hook. Which isn't really a good idea when the pipe is off for a few reasons: - With runtime pm the register might not respond. - If the pipe is off some datastructures might not be around or unitialized. The later is what blew up on gen3: We look at intel_crtc->config to compute the vblank counter, and for a disabled pipe at boot-up that's just not there. Thus far this was papered over by a check for intel_crtc->active, but I want to get rid of that (since it's fairly race, vblank hooks are called from all kinds of places). So prep for that by adding a _reset functions which only does what we really need to be done at driver load: Mark the vblank pipe as off, but don't do any vblank counter saving or event flushing - neither of that is required. v2: Clarify the code flow slightly as suggested by Ville. v3: Fix kerneldoc spelling, spotted by Laurent. Cc: Ville Syrjälä Cc: Laurent Pinchart Cc: Imre Deak Reviewed-by: Imre Deak (v2) Acked-by: Dave Airlie Acked-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 32 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 6 +++--- include/drm/drmP.h | 1 + 3 files changed, 36 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 75647e7f012b..e78a1f5cad9c 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1225,6 +1225,38 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_vblank_off); +/** + * drm_crtc_vblank_reset - reset vblank state to off on a CRTC + * @crtc: CRTC in question + * + * Drivers can use this function to reset the vblank state to off at load time. + * Drivers should use this together with the drm_crtc_vblank_off() and + * drm_crtc_vblank_on() functions. The difference compared to + * drm_crtc_vblank_off() is that this function doesn't save the vblank counter + * and hence doesn't need to call any driver hooks. + */ +void drm_crtc_vblank_reset(struct drm_crtc *drm_crtc) +{ + struct drm_device *dev = drm_crtc->dev; + unsigned long irqflags; + int crtc = drm_crtc_index(drm_crtc); + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; + + spin_lock_irqsave(&dev->vbl_lock, irqflags); + /* + * Prevent subsequent drm_vblank_get() from enabling the vblank + * interrupt by bumping the refcount. + */ + if (!vblank->inmodeset) { + atomic_inc(&vblank->refcount); + vblank->inmodeset = 1; + } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + + WARN_ON(!list_empty(&dev->vblank_event_list)); +} +EXPORT_SYMBOL(drm_crtc_vblank_reset); + /** * drm_vblank_on - enable vblank events on a CRTC * @dev: DRM device diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3b0fe9f1f3c9..b901b00a8f2e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13316,11 +13316,11 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); /* restore vblank interrupts to correct state */ + drm_crtc_vblank_reset(&crtc->base); if (crtc->active) { update_scanline_offset(crtc); - drm_vblank_on(dev, crtc->pipe); - } else - drm_vblank_off(dev, crtc->pipe); + drm_crtc_vblank_on(&crtc->base); + } /* We need to sanitize the plane -> pipe mapping first because this will * disable the crtc (and hence change the state) if it is wrong. Note diff --git a/include/drm/drmP.h b/include/drm/drmP.h index e928625a9da0..54c6ea1e5866 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -922,6 +922,7 @@ extern void drm_crtc_wait_one_vblank(struct drm_crtc *crtc); extern void drm_vblank_off(struct drm_device *dev, int crtc); extern void drm_vblank_on(struct drm_device *dev, int crtc); extern void drm_crtc_vblank_off(struct drm_crtc *crtc); +extern void drm_crtc_vblank_reset(struct drm_crtc *crtc); extern void drm_crtc_vblank_on(struct drm_crtc *crtc); extern void drm_vblank_cleanup(struct drm_device *dev); -- cgit v1.2.3 From 498b8738485ab1a327163f771953f32cf35ca3b5 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 16 Feb 2015 15:12:31 +0000 Subject: drm: Fix the CRTC_STEREO_DOUBLE_ONLY define to include stero modes The CRTC_STEREO_DOUBLE_ONLY define was introduced in commit: commit ecb7e16bf187bc369cf6a5cd108582c01329980d Author: Gustavo Padovan Date: Mon Dec 1 15:40:09 2014 -0800 drm: add helper to get crtc timings (v5) but if we want the stereo h/v adjustments, we need to set the CRTC_STEREO_DOUBLE flag. Otherwise, we'll get the wrong h/v for frame packing stereo 3d modes. Cc: Gustavo Padovan Cc: Matt Roper Cc: Ander Conselvan de Oliveira Signed-off-by: Damien Lespiau Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter --- include/drm/drm_modes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index d92f6dd1fb11..0616188c7801 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -92,7 +92,7 @@ enum drm_mode_status { #define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */ #define CRTC_NO_DBLSCAN (1 << 2) /* don't adjust doublescan */ #define CRTC_NO_VSCAN (1 << 3) /* don't adjust doublescan */ -#define CRTC_STEREO_DOUBLE_ONLY (CRTC_NO_DBLSCAN | CRTC_NO_VSCAN) +#define CRTC_STEREO_DOUBLE_ONLY (CRTC_STEREO_DOUBLE | CRTC_NO_DBLSCAN | CRTC_NO_VSCAN) #define DRM_MODE_FLAG_3D_MAX DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF -- cgit v1.2.3 From 17a38d9c254bf4e3b0d8b7ccd5c1988cb63730ff Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 22 Feb 2015 12:24:16 +0100 Subject: drm: Add DRM_DEBUG_ATOMIC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atomic state handling adds a lot of indirection and complexity between simple updates and drivers. For easier debugging the diagnostic output is therefore rather chatty. Which is great for tracking down atomic issues, but really annoying otherwise. Add a new DRM_DEBUG_ATOMIC to be able to filter this out. Cc: Ville Syrjälä Reviewed-by: Rob Clark Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 100 +++++++++++++++-------------- drivers/gpu/drm/drm_atomic_helper.c | 124 ++++++++++++++++++------------------ include/drm/drmP.h | 9 +++ 3 files changed, 122 insertions(+), 111 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index c2e9c5283136..321e098ddf04 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -92,7 +92,7 @@ drm_atomic_state_alloc(struct drm_device *dev) state->dev = dev; - DRM_DEBUG_KMS("Allocate atomic state %p\n", state); + DRM_DEBUG_ATOMIC("Allocate atomic state %p\n", state); return state; fail: @@ -122,7 +122,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state) struct drm_mode_config *config = &dev->mode_config; int i; - DRM_DEBUG_KMS("Clearing atomic state %p\n", state); + DRM_DEBUG_ATOMIC("Clearing atomic state %p\n", state); for (i = 0; i < state->num_connector; i++) { struct drm_connector *connector = state->connectors[i]; @@ -172,7 +172,7 @@ void drm_atomic_state_free(struct drm_atomic_state *state) { drm_atomic_state_clear(state); - DRM_DEBUG_KMS("Freeing atomic state %p\n", state); + DRM_DEBUG_ATOMIC("Freeing atomic state %p\n", state); kfree_state(state); } @@ -217,8 +217,8 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, state->crtcs[index] = crtc; crtc_state->state = state; - DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n", - crtc->base.id, crtc_state, state); + DRM_DEBUG_ATOMIC("Added [CRTC:%d] %p state to %p\n", + crtc->base.id, crtc_state, state); return crtc_state; } @@ -293,8 +293,8 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc, */ if (state->active && !state->enable) { - DRM_DEBUG_KMS("[CRTC:%d] active without enabled\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] active without enabled\n", + crtc->base.id); return -EINVAL; } @@ -340,8 +340,8 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state, state->planes[index] = plane; plane_state->state = state; - DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n", - plane->base.id, plane_state, state); + DRM_DEBUG_ATOMIC("Added [PLANE:%d] %p state to %p\n", + plane->base.id, plane_state, state); if (plane_state->crtc) { struct drm_crtc_state *crtc_state; @@ -477,10 +477,10 @@ static int drm_atomic_plane_check(struct drm_plane *plane, /* either *both* CRTC and FB must be set, or neither */ if (WARN_ON(state->crtc && !state->fb)) { - DRM_DEBUG_KMS("CRTC set but no FB\n"); + DRM_DEBUG_ATOMIC("CRTC set but no FB\n"); return -EINVAL; } else if (WARN_ON(state->fb && !state->crtc)) { - DRM_DEBUG_KMS("FB set but no CRTC\n"); + DRM_DEBUG_ATOMIC("FB set but no CRTC\n"); return -EINVAL; } @@ -490,7 +490,7 @@ static int drm_atomic_plane_check(struct drm_plane *plane, /* Check whether this plane is usable on this CRTC */ if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) { - DRM_DEBUG_KMS("Invalid crtc for plane\n"); + DRM_DEBUG_ATOMIC("Invalid crtc for plane\n"); return -EINVAL; } @@ -499,8 +499,8 @@ static int drm_atomic_plane_check(struct drm_plane *plane, if (state->fb->pixel_format == plane->format_types[i]) break; if (i == plane->format_count) { - DRM_DEBUG_KMS("Invalid pixel format %s\n", - drm_get_format_name(state->fb->pixel_format)); + DRM_DEBUG_ATOMIC("Invalid pixel format %s\n", + drm_get_format_name(state->fb->pixel_format)); return -EINVAL; } @@ -509,9 +509,9 @@ static int drm_atomic_plane_check(struct drm_plane *plane, state->crtc_x > INT_MAX - (int32_t) state->crtc_w || state->crtc_h > INT_MAX || state->crtc_y > INT_MAX - (int32_t) state->crtc_h) { - DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", - state->crtc_w, state->crtc_h, - state->crtc_x, state->crtc_y); + DRM_DEBUG_ATOMIC("Invalid CRTC coordinates %ux%u+%d+%d\n", + state->crtc_w, state->crtc_h, + state->crtc_x, state->crtc_y); return -ERANGE; } @@ -523,12 +523,12 @@ static int drm_atomic_plane_check(struct drm_plane *plane, state->src_x > fb_width - state->src_w || state->src_h > fb_height || state->src_y > fb_height - state->src_h) { - DRM_DEBUG_KMS("Invalid source coordinates " - "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", - state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10, - state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10, - state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10, - state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10); + DRM_DEBUG_ATOMIC("Invalid source coordinates " + "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", + state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10, + state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10, + state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10, + state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10); return -ENOSPC; } @@ -575,7 +575,7 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, * at most the array is a bit too large. */ if (index >= state->num_connector) { - DRM_DEBUG_KMS("Hot-added connector would overflow state array, restarting\n"); + DRM_DEBUG_ATOMIC("Hot-added connector would overflow state array, restarting\n"); return ERR_PTR(-EAGAIN); } @@ -590,8 +590,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, state->connectors[index] = connector; connector_state->state = state; - DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n", - connector->base.id, connector_state, state); + DRM_DEBUG_ATOMIC("Added [CONNECTOR:%d] %p state to %p\n", + connector->base.id, connector_state, state); if (connector_state->crtc) { struct drm_crtc_state *crtc_state; @@ -752,10 +752,11 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, } if (crtc) - DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n", - plane_state, crtc->base.id); + DRM_DEBUG_ATOMIC("Link plane state %p to [CRTC:%d]\n", + plane_state, crtc->base.id); else - DRM_DEBUG_KMS("Link plane state %p to [NOCRTC]\n", plane_state); + DRM_DEBUG_ATOMIC("Link plane state %p to [NOCRTC]\n", + plane_state); return 0; } @@ -782,10 +783,11 @@ drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, plane_state->fb = fb; if (fb) - DRM_DEBUG_KMS("Set [FB:%d] for plane state %p\n", - fb->base.id, plane_state); + DRM_DEBUG_ATOMIC("Set [FB:%d] for plane state %p\n", + fb->base.id, plane_state); else - DRM_DEBUG_KMS("Set [NOFB] for plane state %p\n", plane_state); + DRM_DEBUG_ATOMIC("Set [NOFB] for plane state %p\n", + plane_state); } EXPORT_SYMBOL(drm_atomic_set_fb_for_plane); @@ -818,11 +820,11 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, conn_state->crtc = crtc; if (crtc) - DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n", - conn_state, crtc->base.id); + DRM_DEBUG_ATOMIC("Link connector state %p to [CRTC:%d]\n", + conn_state, crtc->base.id); else - DRM_DEBUG_KMS("Link connector state %p to [NOCRTC]\n", - conn_state); + DRM_DEBUG_ATOMIC("Link connector state %p to [NOCRTC]\n", + conn_state); return 0; } @@ -858,8 +860,8 @@ drm_atomic_add_affected_connectors(struct drm_atomic_state *state, if (ret) return ret; - DRM_DEBUG_KMS("Adding all current connectors for [CRTC:%d] to %p\n", - crtc->base.id, state); + DRM_DEBUG_ATOMIC("Adding all current connectors for [CRTC:%d] to %p\n", + crtc->base.id, state); /* * Changed connectors are already in @state, so only need to look at the @@ -901,8 +903,8 @@ drm_atomic_connectors_for_crtc(struct drm_atomic_state *state, num_connected_connectors++; } - DRM_DEBUG_KMS("State %p has %i connectors for [CRTC:%d]\n", - state, num_connected_connectors, crtc->base.id); + DRM_DEBUG_ATOMIC("State %p has %i connectors for [CRTC:%d]\n", + state, num_connected_connectors, crtc->base.id); return num_connected_connectors; } @@ -953,7 +955,7 @@ int drm_atomic_check_only(struct drm_atomic_state *state) int ncrtcs = config->num_crtc; int i, ret = 0; - DRM_DEBUG_KMS("checking %p\n", state); + DRM_DEBUG_ATOMIC("checking %p\n", state); for (i = 0; i < nplanes; i++) { struct drm_plane *plane = state->planes[i]; @@ -963,8 +965,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) ret = drm_atomic_plane_check(plane, state->plane_states[i]); if (ret) { - DRM_DEBUG_KMS("[PLANE:%d] atomic core check failed\n", - plane->base.id); + DRM_DEBUG_ATOMIC("[PLANE:%d] atomic core check failed\n", + plane->base.id); return ret; } } @@ -977,8 +979,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) ret = drm_atomic_crtc_check(crtc, state->crtc_states[i]); if (ret) { - DRM_DEBUG_KMS("[CRTC:%d] atomic core check failed\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] atomic core check failed\n", + crtc->base.id); return ret; } } @@ -996,8 +998,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) if (crtc_state->mode_changed || crtc_state->active_changed) { - DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] requires full modeset\n", + crtc->base.id); return -EINVAL; } } @@ -1032,7 +1034,7 @@ int drm_atomic_commit(struct drm_atomic_state *state) if (ret) return ret; - DRM_DEBUG_KMS("commiting %p\n", state); + DRM_DEBUG_ATOMIC("commiting %p\n", state); return config->funcs->atomic_commit(state->dev, state, false); } @@ -1063,7 +1065,7 @@ int drm_atomic_async_commit(struct drm_atomic_state *state) if (ret) return ret; - DRM_DEBUG_KMS("commiting %p asynchronously\n", state); + DRM_DEBUG_ATOMIC("commiting %p asynchronously\n", state); return config->funcs->atomic_commit(state->dev, state, true); } diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index e70adfcb9e84..9e8767118edb 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -116,9 +116,9 @@ steal_encoder(struct drm_atomic_state *state, */ WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); - DRM_DEBUG_KMS("[ENCODER:%d:%s] in use on [CRTC:%d], stealing it\n", - encoder->base.id, encoder->name, - encoder_crtc->base.id); + DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d], stealing it\n", + encoder->base.id, encoder->name, + encoder_crtc->base.id); crtc_state = drm_atomic_get_crtc_state(state, encoder_crtc); if (IS_ERR(crtc_state)) @@ -130,9 +130,9 @@ steal_encoder(struct drm_atomic_state *state, if (connector->state->best_encoder != encoder) continue; - DRM_DEBUG_KMS("Stealing encoder from [CONNECTOR:%d:%s]\n", - connector->base.id, - connector->name); + DRM_DEBUG_ATOMIC("Stealing encoder from [CONNECTOR:%d:%s]\n", + connector->base.id, + connector->name); connector_state = drm_atomic_get_connector_state(state, connector); @@ -165,9 +165,9 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) if (!connector) return 0; - DRM_DEBUG_KMS("Updating routing for [CONNECTOR:%d:%s]\n", - connector->base.id, - connector->name); + DRM_DEBUG_ATOMIC("Updating routing for [CONNECTOR:%d:%s]\n", + connector->base.id, + connector->name); if (connector->state->crtc != connector_state->crtc) { if (connector->state->crtc) { @@ -186,7 +186,7 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) } if (!connector_state->crtc) { - DRM_DEBUG_KMS("Disabling [CONNECTOR:%d:%s]\n", + DRM_DEBUG_ATOMIC("Disabling [CONNECTOR:%d:%s]\n", connector->base.id, connector->name); @@ -199,19 +199,19 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) new_encoder = funcs->best_encoder(connector); if (!new_encoder) { - DRM_DEBUG_KMS("No suitable encoder found for [CONNECTOR:%d:%s]\n", - connector->base.id, - connector->name); + DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n", + connector->base.id, + connector->name); return -EINVAL; } if (new_encoder == connector_state->best_encoder) { - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d]\n", - connector->base.id, - connector->name, - new_encoder->base.id, - new_encoder->name, - connector_state->crtc->base.id); + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d]\n", + connector->base.id, + connector->name, + new_encoder->base.id, + new_encoder->name, + connector_state->crtc->base.id); return 0; } @@ -222,9 +222,9 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) if (encoder_crtc) { ret = steal_encoder(state, new_encoder, encoder_crtc); if (ret) { - DRM_DEBUG_KMS("Encoder stealing failed for [CONNECTOR:%d:%s]\n", - connector->base.id, - connector->name); + DRM_DEBUG_ATOMIC("Encoder stealing failed for [CONNECTOR:%d:%s]\n", + connector->base.id, + connector->name); return ret; } } @@ -235,12 +235,12 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) crtc_state = state->crtc_states[idx]; crtc_state->mode_changed = true; - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n", - connector->base.id, - connector->name, - new_encoder->base.id, - new_encoder->name, - connector_state->crtc->base.id); + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n", + connector->base.id, + connector->name, + new_encoder->base.id, + new_encoder->name, + connector_state->crtc->base.id); return 0; } @@ -292,7 +292,7 @@ mode_fixup(struct drm_atomic_state *state) encoder->bridge, &crtc_state->mode, &crtc_state->adjusted_mode); if (!ret) { - DRM_DEBUG_KMS("Bridge fixup failed\n"); + DRM_DEBUG_ATOMIC("Bridge fixup failed\n"); return -EINVAL; } } @@ -301,16 +301,16 @@ mode_fixup(struct drm_atomic_state *state) ret = funcs->atomic_check(encoder, crtc_state, conn_state); if (ret) { - DRM_DEBUG_KMS("[ENCODER:%d:%s] check failed\n", - encoder->base.id, encoder->name); + DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] check failed\n", + encoder->base.id, encoder->name); return ret; } } else { ret = funcs->mode_fixup(encoder, &crtc_state->mode, &crtc_state->adjusted_mode); if (!ret) { - DRM_DEBUG_KMS("[ENCODER:%d:%s] fixup failed\n", - encoder->base.id, encoder->name); + DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] fixup failed\n", + encoder->base.id, encoder->name); return -EINVAL; } } @@ -330,8 +330,8 @@ mode_fixup(struct drm_atomic_state *state) ret = funcs->mode_fixup(crtc, &crtc_state->mode, &crtc_state->adjusted_mode); if (!ret) { - DRM_DEBUG_KMS("[CRTC:%d] fixup failed\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] fixup failed\n", + crtc->base.id); return -EINVAL; } } @@ -384,14 +384,14 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, continue; if (!drm_mode_equal(&crtc->state->mode, &crtc_state->mode)) { - DRM_DEBUG_KMS("[CRTC:%d] mode changed\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] mode changed\n", + crtc->base.id); crtc_state->mode_changed = true; } if (crtc->state->enable != crtc_state->enable) { - DRM_DEBUG_KMS("[CRTC:%d] enable changed\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] enable changed\n", + crtc->base.id); crtc_state->mode_changed = true; } } @@ -428,17 +428,17 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, * a full modeset because update_connector_routing force that. */ if (crtc->state->active != crtc_state->active) { - DRM_DEBUG_KMS("[CRTC:%d] active changed\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] active changed\n", + crtc->base.id); crtc_state->active_changed = true; } if (!needs_modeset(crtc_state)) continue; - DRM_DEBUG_KMS("[CRTC:%d] needs all connectors, enable: %c, active: %c\n", - crtc->base.id, - crtc_state->enable ? 'y' : 'n', + DRM_DEBUG_ATOMIC("[CRTC:%d] needs all connectors, enable: %c, active: %c\n", + crtc->base.id, + crtc_state->enable ? 'y' : 'n', crtc_state->active ? 'y' : 'n'); ret = drm_atomic_add_affected_connectors(state, crtc); @@ -449,8 +449,8 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, crtc); if (crtc_state->enable != !!num_connectors) { - DRM_DEBUG_KMS("[CRTC:%d] enabled/connectors mismatch\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] enabled/connectors mismatch\n", + crtc->base.id); return -EINVAL; } @@ -497,8 +497,8 @@ drm_atomic_helper_check_planes(struct drm_device *dev, ret = funcs->atomic_check(plane, plane_state); if (ret) { - DRM_DEBUG_KMS("[PLANE:%d] atomic driver check failed\n", - plane->base.id); + DRM_DEBUG_ATOMIC("[PLANE:%d] atomic driver check failed\n", + plane->base.id); return ret; } } @@ -517,8 +517,8 @@ drm_atomic_helper_check_planes(struct drm_device *dev, ret = funcs->atomic_check(crtc, state->crtc_states[i]); if (ret) { - DRM_DEBUG_KMS("[CRTC:%d] atomic driver check failed\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("[CRTC:%d] atomic driver check failed\n", + crtc->base.id); return ret; } } @@ -600,8 +600,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) funcs = encoder->helper_private; - DRM_DEBUG_KMS("disabling [ENCODER:%d:%s]\n", - encoder->base.id, encoder->name); + DRM_DEBUG_ATOMIC("disabling [ENCODER:%d:%s]\n", + encoder->base.id, encoder->name); /* * Each encoder has at most one connector (since we always steal @@ -639,8 +639,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) funcs = crtc->helper_private; - DRM_DEBUG_KMS("disabling [CRTC:%d]\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("disabling [CRTC:%d]\n", + crtc->base.id); /* Right function depends upon target state. */ @@ -724,8 +724,8 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) funcs = crtc->helper_private; if (crtc->state->enable) { - DRM_DEBUG_KMS("modeset on [CRTC:%d]\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("modeset on [CRTC:%d]\n", + crtc->base.id); funcs->mode_set_nofb(crtc); } @@ -752,8 +752,8 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) if (!new_crtc_state->mode_changed) continue; - DRM_DEBUG_KMS("modeset on [ENCODER:%d:%s]\n", - encoder->base.id, encoder->name); + DRM_DEBUG_ATOMIC("modeset on [ENCODER:%d:%s]\n", + encoder->base.id, encoder->name); /* * Each encoder has at most one connector (since we always steal @@ -816,8 +816,8 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, funcs = crtc->helper_private; if (crtc->state->enable) { - DRM_DEBUG_KMS("enabling [CRTC:%d]\n", - crtc->base.id); + DRM_DEBUG_ATOMIC("enabling [CRTC:%d]\n", + crtc->base.id); if (funcs->enable) funcs->enable(crtc); @@ -842,8 +842,8 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, encoder = connector->state->best_encoder; funcs = encoder->helper_private; - DRM_DEBUG_KMS("enabling [ENCODER:%d:%s]\n", - encoder->base.id, encoder->name); + DRM_DEBUG_ATOMIC("enabling [ENCODER:%d:%s]\n", + encoder->base.id, encoder->name); /* * Each encoder has at most one connector (since we always steal diff --git a/include/drm/drmP.h b/include/drm/drmP.h index e928625a9da0..52999ba9fbaf 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -104,6 +104,9 @@ struct dma_buf_attachment; * PRIME: used in the prime code. * This is the category used by the DRM_DEBUG_PRIME() macro. * + * ATOMIC: used in the atomic code. + * This is the category used by the DRM_DEBUG_ATOMIC() macro. + * * Enabling verbose debug messages is done through the drm.debug parameter, * each category being enabled by a bit. * @@ -121,6 +124,7 @@ struct dma_buf_attachment; #define DRM_UT_DRIVER 0x02 #define DRM_UT_KMS 0x04 #define DRM_UT_PRIME 0x08 +#define DRM_UT_ATOMIC 0x10 extern __printf(2, 3) void drm_ut_debug_printk(const char *function_name, @@ -207,6 +211,11 @@ void drm_err(const char *format, ...); if (unlikely(drm_debug & DRM_UT_PRIME)) \ drm_ut_debug_printk(__func__, fmt, ##args); \ } while (0) +#define DRM_DEBUG_ATOMIC(fmt, args...) \ + do { \ + if (unlikely(drm_debug & DRM_UT_ATOMIC)) \ + drm_ut_debug_printk(__func__, fmt, ##args); \ + } while (0) /*@}*/ -- cgit v1.2.3 From ee8905963ed0bc9dfc0952dc35e16e233c10e212 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 14 Apr 2014 17:53:25 +0200 Subject: of: Add for_each_endpoint_of_node helper macro Note that while of_graph_get_next_endpoint decrements the reference count of the child node passed to it, of_node_put(child) still has to be called manually when breaking out of the loop. Signed-off-by: Philipp Zabel Acked-by: Laurent Pinchart --- include/linux/of_graph.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include') diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h index befef42e015b..e43442efcbe5 100644 --- a/include/linux/of_graph.h +++ b/include/linux/of_graph.h @@ -26,6 +26,17 @@ struct of_endpoint { const struct device_node *local_node; }; +/** + * for_each_endpoint_of_node - iterate over every endpoint in a device node + * @parent: parent device node containing ports and endpoints + * @child: loop variable pointing to the current endpoint node + * + * When breaking out of the loop, of_node_put(child) has to be called manually. + */ +#define for_each_endpoint_of_node(parent, child) \ + for (child = of_graph_get_next_endpoint(parent, NULL); child != NULL; \ + child = of_graph_get_next_endpoint(parent, child)) + #ifdef CONFIG_OF int of_graph_parse_endpoint(const struct device_node *node, struct of_endpoint *endpoint); -- cgit v1.2.3 From 411fdaf846afb0be1b54383c184f58a42fa416ff Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 17 Feb 2015 01:46:49 +0000 Subject: dmaengine: shdma: use normal interface for passing slave id in dma_slave_config, which is incompatible with the way that the dmaengine API normally works. I've had a closer look at the existing code now and found that all slave drivers that pass a slave_id in dma_slave_config for SH do that right after passing the same ID into shdma_chan_filter, so we can just rely on that. However, the various shdma drivers currently do not remember the slave ID that was passed into the filter function when used in non-DT mode and only check the value to find a matching channel, unlike all other drivers. There might still be drivers that are not part of the kernel that rely on setting the slave_id to some other value, so to be on the safe side, this adds another 'real_slave_id' field to shdma_chan that remembers the ID and uses it when a driver passes a zero slave_id in dma_slave_config, like most drivers do. Eventually, the real_slave_id and slave_id fields should just get merged into one field, but that requires other changes. Signed-off-by: Arnd Bergmann Signed-off-by: Kuninori Morimoto Signed-off-by: Vinod Koul --- drivers/dma/sh/shdma-base.c | 73 ++++++++++++++++++++++++++++++++------------- include/linux/shdma-base.h | 1 + 2 files changed, 54 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 8ee383d339a5..10fcabad80f3 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -171,8 +171,7 @@ static struct shdma_desc *shdma_get_desc(struct shdma_chan *schan) return NULL; } -static int shdma_setup_slave(struct shdma_chan *schan, int slave_id, - dma_addr_t slave_addr) +static int shdma_setup_slave(struct shdma_chan *schan, dma_addr_t slave_addr) { struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device); const struct shdma_ops *ops = sdev->ops; @@ -183,25 +182,23 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id, ret = ops->set_slave(schan, match, slave_addr, true); if (ret < 0) return ret; - - slave_id = schan->slave_id; } else { - match = slave_id; + match = schan->real_slave_id; } - if (slave_id < 0 || slave_id >= slave_num) + if (schan->real_slave_id < 0 || schan->real_slave_id >= slave_num) return -EINVAL; - if (test_and_set_bit(slave_id, shdma_slave_used)) + if (test_and_set_bit(schan->real_slave_id, shdma_slave_used)) return -EBUSY; ret = ops->set_slave(schan, match, slave_addr, false); if (ret < 0) { - clear_bit(slave_id, shdma_slave_used); + clear_bit(schan->real_slave_id, shdma_slave_used); return ret; } - schan->slave_id = slave_id; + schan->slave_id = schan->real_slave_id; return 0; } @@ -221,10 +218,12 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan) */ if (slave) { /* Legacy mode: .private is set in filter */ - ret = shdma_setup_slave(schan, slave->slave_id, 0); + schan->real_slave_id = slave->slave_id; + ret = shdma_setup_slave(schan, 0); if (ret < 0) goto esetslave; } else { + /* Normal mode: real_slave_id was set by filter */ schan->slave_id = -EINVAL; } @@ -258,11 +257,14 @@ esetslave: /* * This is the standard shdma filter function to be used as a replacement to the - * "old" method, using the .private pointer. If for some reason you allocate a - * channel without slave data, use something like ERR_PTR(-EINVAL) as a filter + * "old" method, using the .private pointer. + * You always have to pass a valid slave id as the argument, old drivers that + * pass ERR_PTR(-EINVAL) as a filter parameter and set it up in dma_slave_config + * need to be updated so we can remove the slave_id field from dma_slave_config. * parameter. If this filter is used, the slave driver, after calling * dma_request_channel(), will also have to call dmaengine_slave_config() with - * .slave_id, .direction, and either .src_addr or .dst_addr set. + * .direction, and either .src_addr or .dst_addr set. + * * NOTE: this filter doesn't support multiple DMAC drivers with the DMA_SLAVE * capability! If this becomes a requirement, hardware glue drivers, using this * services would have to provide their own filters, which first would check @@ -276,7 +278,7 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg) { struct shdma_chan *schan; struct shdma_dev *sdev; - int match = (long)arg; + int slave_id = (long)arg; int ret; /* Only support channels handled by this driver. */ @@ -284,19 +286,39 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg) shdma_alloc_chan_resources) return false; - if (match < 0) + schan = to_shdma_chan(chan); + sdev = to_shdma_dev(chan->device); + + /* + * For DT, the schan->slave_id field is generated by the + * set_slave function from the slave ID that is passed in + * from xlate. For the non-DT case, the slave ID is + * directly passed into the filter function by the driver + */ + if (schan->dev->of_node) { + ret = sdev->ops->set_slave(schan, slave_id, 0, true); + if (ret < 0) + return false; + + schan->real_slave_id = schan->slave_id; + return true; + } + + if (slave_id < 0) { /* No slave requested - arbitrary channel */ + dev_warn(sdev->dma_dev.dev, "invalid slave ID passed to dma_request_slave\n"); return true; + } - schan = to_shdma_chan(chan); - if (!schan->dev->of_node && match >= slave_num) + if (slave_id >= slave_num) return false; - sdev = to_shdma_dev(schan->dma_chan.device); - ret = sdev->ops->set_slave(schan, match, 0, true); + ret = sdev->ops->set_slave(schan, slave_id, 0, true); if (ret < 0) return false; + schan->real_slave_id = slave_id; + return true; } EXPORT_SYMBOL(shdma_chan_filter); @@ -452,6 +474,8 @@ static void shdma_free_chan_resources(struct dma_chan *chan) chan->private = NULL; } + schan->real_slave_id = 0; + spin_lock_irq(&schan->chan_lock); list_splice_init(&schan->ld_free, &list); @@ -764,11 +788,20 @@ static int shdma_config(struct dma_chan *chan, */ if (!config) return -EINVAL; + + /* + * overriding the slave_id through dma_slave_config is deprecated, + * but possibly some out-of-tree drivers still do it. + */ + if (WARN_ON_ONCE(config->slave_id && + config->slave_id != schan->real_slave_id)) + schan->real_slave_id = config->slave_id; + /* * We could lock this, but you shouldn't be configuring the * channel, while using it... */ - return shdma_setup_slave(schan, config->slave_id, + return shdma_setup_slave(schan, config->direction == DMA_DEV_TO_MEM ? config->src_addr : config->dst_addr); } diff --git a/include/linux/shdma-base.h b/include/linux/shdma-base.h index abdf1f229dc3..dd0ba502ccb3 100644 --- a/include/linux/shdma-base.h +++ b/include/linux/shdma-base.h @@ -69,6 +69,7 @@ struct shdma_chan { int id; /* Raw id of this channel */ int irq; /* Channel IRQ */ int slave_id; /* Client ID for slave DMA */ + int real_slave_id; /* argument passed to filter function */ int hw_req; /* DMA request line for slave DMA - same * as MID/RID, used with DT */ enum shdma_pm_state pm_state; -- cgit v1.2.3 From bfe446e37c4efd8ade454911e8f80414bcbfc10d Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 11 Mar 2014 11:21:11 +0100 Subject: of: Add of_graph_get_port_by_id function This patch adds a function to get a port device tree node by port id, or reg property value. Signed-off-by: Philipp Zabel Acked-by: Laurent Pinchart --- drivers/of/base.c | 32 ++++++++++++++++++++++++++++++++ include/linux/of_graph.h | 7 +++++++ 2 files changed, 39 insertions(+) (limited to 'include') diff --git a/drivers/of/base.c b/drivers/of/base.c index 05b20f1cca7b..6398b9ca9157 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2080,6 +2080,38 @@ int of_graph_parse_endpoint(const struct device_node *node, } EXPORT_SYMBOL(of_graph_parse_endpoint); +/** + * of_graph_get_port_by_id() - get the port matching a given id + * @parent: pointer to the parent device node + * @id: id of the port + * + * Return: A 'port' node pointer with refcount incremented. The caller + * has to use of_node_put() on it when done. + */ +struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id) +{ + struct device_node *node, *port; + + node = of_get_child_by_name(parent, "ports"); + if (node) + parent = node; + + for_each_child_of_node(parent, port) { + u32 port_id = 0; + + if (of_node_cmp(port->name, "port") != 0) + continue; + of_property_read_u32(port, "reg", &port_id); + if (id == port_id) + break; + } + + of_node_put(node); + + return port; +} +EXPORT_SYMBOL(of_graph_get_port_by_id); + /** * of_graph_get_next_endpoint() - get next endpoint node * @parent: pointer to the parent device node diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h index e43442efcbe5..3c1c95a39e0c 100644 --- a/include/linux/of_graph.h +++ b/include/linux/of_graph.h @@ -40,6 +40,7 @@ struct of_endpoint { #ifdef CONFIG_OF int of_graph_parse_endpoint(const struct device_node *node, struct of_endpoint *endpoint); +struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id); struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, struct device_node *previous); struct device_node *of_graph_get_remote_port_parent( @@ -53,6 +54,12 @@ static inline int of_graph_parse_endpoint(const struct device_node *node, return -ENOSYS; } +static inline struct device_node *of_graph_get_port_by_id( + struct device_node *node, u32 id) +{ + return NULL; +} + static inline struct device_node *of_graph_get_next_endpoint( const struct device_node *parent, struct device_node *previous) -- cgit v1.2.3 From ca8895d9bb41e743271c42a4438a296de891b73b Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Wed, 26 Nov 2014 12:22:03 -0600 Subject: Return MD_SB_CLUSTERED if mddev is clustered Signed-off-by: Goldwyn Rodrigues --- drivers/md/md.c | 3 +++ include/uapi/linux/raid/md_p.h | 1 + 2 files changed, 4 insertions(+) (limited to 'include') diff --git a/drivers/md/md.c b/drivers/md/md.c index 3387f940140b..5ed57688e5c5 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5634,6 +5634,9 @@ static int get_array_info(struct mddev *mddev, void __user *arg) info.state = (1<bitmap && mddev->bitmap_info.offset) info.state |= (1< Date: Wed, 29 Oct 2014 18:51:31 -0500 Subject: Add new disk to clustered array Algorithm: 1. Node 1 issues mdadm --manage /dev/mdX --add /dev/sdYY which issues ioctl(ADD_NEW_DISC with disc.state set to MD_DISK_CLUSTER_ADD) 2. Node 1 sends NEWDISK with uuid and slot number 3. Other nodes issue kobject_uevent_env with uuid and slot number (Steps 4,5 could be a udev rule) 4. In userspace, the node searches for the disk, perhaps using blkid -t SUB_UUID="" 5. Other nodes issue either of the following depending on whether the disk was found: ioctl(ADD_NEW_DISK with disc.state set to MD_DISK_CANDIDATE and disc.number set to slot number) ioctl(CLUSTERED_DISK_NACK) 6. Other nodes drop lock on no-new-devs (CR) if device is found 7. Node 1 attempts EX lock on no-new-devs 8. If node 1 gets the lock, it sends METADATA_UPDATED after unmarking the disk as SpareLocal 9. If not (get no-new-dev lock), it fails the operation and sends METADATA_UPDATED 10. Other nodes understand if the device is added or not by reading the superblock again after receiving the METADATA_UPDATED message. Signed-off-by: Lidong Zhong Signed-off-by: Goldwyn Rodrigues --- drivers/md/md-cluster.c | 104 ++++++++++++++++++++++++++++++++++++++++- drivers/md/md-cluster.h | 4 ++ drivers/md/md.c | 52 +++++++++++++++++++-- drivers/md/md.h | 5 ++ drivers/md/raid1.c | 1 + include/uapi/linux/raid/md_p.h | 6 +++ include/uapi/linux/raid/md_u.h | 1 + 7 files changed, 169 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index d85a6ca4443e..03e521a9ca7d 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -12,11 +12,13 @@ #include #include #include +#include #include "md.h" #include "bitmap.h" #include "md-cluster.h" #define LVB_SIZE 64 +#define NEW_DEV_TIMEOUT 5000 struct dlm_lock_resource { dlm_lockspace_t *ls; @@ -56,19 +58,25 @@ struct md_cluster_info { struct dlm_lock_resource *ack_lockres; struct dlm_lock_resource *message_lockres; struct dlm_lock_resource *token_lockres; + struct dlm_lock_resource *no_new_dev_lockres; struct md_thread *recv_thread; + struct completion newdisk_completion; }; enum msg_type { METADATA_UPDATED = 0, RESYNCING, + NEWDISK, }; struct cluster_msg { int type; int slot; + /* TODO: Unionize this for smaller footprint */ sector_t low; sector_t high; + char uuid[16]; + int raid_slot; }; static void sync_ast(void *arg) @@ -358,13 +366,41 @@ static void process_suspend_info(struct md_cluster_info *cinfo, spin_unlock_irq(&cinfo->suspend_lock); } +static void process_add_new_disk(struct mddev *mddev, struct cluster_msg *cmsg) +{ + char disk_uuid[64]; + struct md_cluster_info *cinfo = mddev->cluster_info; + char event_name[] = "EVENT=ADD_DEVICE"; + char raid_slot[16]; + char *envp[] = {event_name, disk_uuid, raid_slot, NULL}; + int len; + + len = snprintf(disk_uuid, 64, "DEVICE_UUID="); + pretty_uuid(disk_uuid + len, cmsg->uuid); + snprintf(raid_slot, 16, "RAID_DISK=%d", cmsg->raid_slot); + pr_info("%s:%d Sending kobject change with %s and %s\n", __func__, __LINE__, disk_uuid, raid_slot); + init_completion(&cinfo->newdisk_completion); + kobject_uevent_env(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE, envp); + wait_for_completion_timeout(&cinfo->newdisk_completion, + NEW_DEV_TIMEOUT); +} + + +static void process_metadata_update(struct mddev *mddev, struct cluster_msg *msg) +{ + struct md_cluster_info *cinfo = mddev->cluster_info; + + md_reload_sb(mddev); + dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR); +} + static void process_recvd_msg(struct mddev *mddev, struct cluster_msg *msg) { switch (msg->type) { case METADATA_UPDATED: pr_info("%s: %d Received message: METADATA_UPDATE from %d\n", __func__, __LINE__, msg->slot); - md_reload_sb(mddev); + process_metadata_update(mddev, msg); break; case RESYNCING: pr_info("%s: %d Received message: RESYNCING from %d\n", @@ -372,6 +408,10 @@ static void process_recvd_msg(struct mddev *mddev, struct cluster_msg *msg) process_suspend_info(mddev->cluster_info, msg->slot, msg->low, msg->high); break; + case NEWDISK: + pr_info("%s: %d Received message: NEWDISK from %d\n", + __func__, __LINE__, msg->slot); + process_add_new_disk(mddev, msg); }; } @@ -593,10 +633,18 @@ static int join(struct mddev *mddev, int nodes) cinfo->ack_lockres = lockres_init(mddev, "ack", ack_bast, 0); if (!cinfo->ack_lockres) goto err; + cinfo->no_new_dev_lockres = lockres_init(mddev, "no-new-dev", NULL, 0); + if (!cinfo->no_new_dev_lockres) + goto err; + /* get sync CR lock on ACK. */ if (dlm_lock_sync(cinfo->ack_lockres, DLM_LOCK_CR)) pr_err("md-cluster: failed to get a sync CR lock on ACK!(%d)\n", ret); + /* get sync CR lock on no-new-dev. */ + if (dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR)) + pr_err("md-cluster: failed to get a sync CR lock on no-new-dev!(%d)\n", ret); + pr_info("md-cluster: Joined cluster %s slot %d\n", str, cinfo->slot_number); snprintf(str, 64, "bitmap%04d", cinfo->slot_number - 1); @@ -621,6 +669,7 @@ err: lockres_free(cinfo->message_lockres); lockres_free(cinfo->token_lockres); lockres_free(cinfo->ack_lockres); + lockres_free(cinfo->no_new_dev_lockres); lockres_free(cinfo->bitmap_lockres); lockres_free(cinfo->sb_lock); if (cinfo->lockspace) @@ -642,6 +691,7 @@ static int leave(struct mddev *mddev) lockres_free(cinfo->message_lockres); lockres_free(cinfo->token_lockres); lockres_free(cinfo->ack_lockres); + lockres_free(cinfo->no_new_dev_lockres); lockres_free(cinfo->sb_lock); lockres_free(cinfo->bitmap_lockres); dlm_release_lockspace(cinfo->lockspace, 2); @@ -742,6 +792,55 @@ out: return ret; } +static int add_new_disk_start(struct mddev *mddev, struct md_rdev *rdev) +{ + struct md_cluster_info *cinfo = mddev->cluster_info; + struct cluster_msg cmsg; + int ret = 0; + struct mdp_superblock_1 *sb = page_address(rdev->sb_page); + char *uuid = sb->device_uuid; + + memset(&cmsg, 0, sizeof(cmsg)); + cmsg.type = cpu_to_le32(NEWDISK); + memcpy(cmsg.uuid, uuid, 16); + cmsg.raid_slot = rdev->desc_nr; + lock_comm(cinfo); + ret = __sendmsg(cinfo, &cmsg); + if (ret) + return ret; + cinfo->no_new_dev_lockres->flags |= DLM_LKF_NOQUEUE; + ret = dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_EX); + cinfo->no_new_dev_lockres->flags &= ~DLM_LKF_NOQUEUE; + /* Some node does not "see" the device */ + if (ret == -EAGAIN) + ret = -ENOENT; + else + dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR); + return ret; +} + +static int add_new_disk_finish(struct mddev *mddev) +{ + struct cluster_msg cmsg; + struct md_cluster_info *cinfo = mddev->cluster_info; + int ret; + /* Write sb and inform others */ + md_update_sb(mddev, 1); + cmsg.type = METADATA_UPDATED; + ret = __sendmsg(cinfo, &cmsg); + unlock_comm(cinfo); + return ret; +} + +static void new_disk_ack(struct mddev *mddev, bool ack) +{ + struct md_cluster_info *cinfo = mddev->cluster_info; + + if (ack) + dlm_unlock_sync(cinfo->no_new_dev_lockres); + complete(&cinfo->newdisk_completion); +} + static struct md_cluster_operations cluster_ops = { .join = join, .leave = leave, @@ -753,6 +852,9 @@ static struct md_cluster_operations cluster_ops = { .metadata_update_finish = metadata_update_finish, .metadata_update_cancel = metadata_update_cancel, .area_resyncing = area_resyncing, + .add_new_disk_start = add_new_disk_start, + .add_new_disk_finish = add_new_disk_finish, + .new_disk_ack = new_disk_ack, }; static int __init cluster_init(void) diff --git a/drivers/md/md-cluster.h b/drivers/md/md-cluster.h index 03785402afaa..60d7e58964f5 100644 --- a/drivers/md/md-cluster.h +++ b/drivers/md/md-cluster.h @@ -6,6 +6,7 @@ #include "md.h" struct mddev; +struct md_rdev; struct md_cluster_operations { int (*join)(struct mddev *mddev, int nodes); @@ -18,6 +19,9 @@ struct md_cluster_operations { int (*metadata_update_finish)(struct mddev *mddev); int (*metadata_update_cancel)(struct mddev *mddev); int (*area_resyncing)(struct mddev *mddev, sector_t lo, sector_t hi); + int (*add_new_disk_start)(struct mddev *mddev, struct md_rdev *rdev); + int (*add_new_disk_finish)(struct mddev *mddev); + void (*new_disk_ack)(struct mddev *mddev, bool ack); }; #endif /* _MD_CLUSTER_H */ diff --git a/drivers/md/md.c b/drivers/md/md.c index fe0484648de4..5703c2e89f3a 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2210,7 +2210,7 @@ static void sync_sbs(struct mddev *mddev, int nospares) } } -static void md_update_sb(struct mddev *mddev, int force_change) +void md_update_sb(struct mddev *mddev, int force_change) { struct md_rdev *rdev; int sync_req; @@ -2371,6 +2371,7 @@ repeat: wake_up(&rdev->blocked_wait); } } +EXPORT_SYMBOL(md_update_sb); /* words written to sysfs files may, or may not, be \n terminated. * We want to accept with case. For this we use cmd_match. @@ -3151,7 +3152,7 @@ static void analyze_sbs(struct mddev *mddev) kick_rdev_from_array(rdev); continue; } - if (rdev != freshest) + if (rdev != freshest) { if (super_types[mddev->major_version]. validate_super(mddev, rdev)) { printk(KERN_WARNING "md: kicking non-fresh %s" @@ -3160,6 +3161,15 @@ static void analyze_sbs(struct mddev *mddev) kick_rdev_from_array(rdev); continue; } + /* No device should have a Candidate flag + * when reading devices + */ + if (test_bit(Candidate, &rdev->flags)) { + pr_info("md: kicking Cluster Candidate %s from array!\n", + bdevname(rdev->bdev, b)); + kick_rdev_from_array(rdev); + } + } if (mddev->level == LEVEL_MULTIPATH) { rdev->desc_nr = i++; rdev->raid_disk = rdev->desc_nr; @@ -5655,7 +5665,6 @@ static int get_array_info(struct mddev *mddev, void __user *arg) info.state |= (1<major,info->minor); + if (mddev_is_clustered(mddev) && + !(info->state & ((1 << MD_DISK_CLUSTER_ADD) | (1 << MD_DISK_CANDIDATE)))) { + pr_err("%s: Cannot add to clustered mddev. Try --cluster-add\n", + mdname(mddev)); + return -EINVAL; + } + if (info->major != MAJOR(dev) || info->minor != MINOR(dev)) return -EOVERFLOW; @@ -5830,6 +5846,25 @@ static int add_new_disk(struct mddev *mddev, mdu_disk_info_t *info) else clear_bit(WriteMostly, &rdev->flags); + /* + * check whether the device shows up in other nodes + */ + if (mddev_is_clustered(mddev)) { + if (info->state & (1 << MD_DISK_CANDIDATE)) { + /* Through --cluster-confirm */ + set_bit(Candidate, &rdev->flags); + md_cluster_ops->new_disk_ack(mddev, true); + } else if (info->state & (1 << MD_DISK_CLUSTER_ADD)) { + /* --add initiated by this node */ + err = md_cluster_ops->add_new_disk_start(mddev, rdev); + if (err) { + md_cluster_ops->add_new_disk_finish(mddev); + export_rdev(rdev); + return err; + } + } + } + rdev->raid_disk = -1; err = bind_rdev_to_array(rdev, mddev); if (!err && !mddev->pers->hot_remove_disk) { @@ -5855,6 +5890,9 @@ static int add_new_disk(struct mddev *mddev, mdu_disk_info_t *info) if (!err) md_new_event(mddev); md_wakeup_thread(mddev->thread); + if (mddev_is_clustered(mddev) && + (info->state & (1 << MD_DISK_CLUSTER_ADD))) + md_cluster_ops->add_new_disk_finish(mddev); return err; } @@ -6456,6 +6494,7 @@ static inline bool md_ioctl_valid(unsigned int cmd) case SET_DISK_FAULTY: case STOP_ARRAY: case STOP_ARRAY_RO: + case CLUSTERED_DISK_NACK: return true; default: return false; @@ -6728,6 +6767,13 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, goto unlock; } + case CLUSTERED_DISK_NACK: + if (mddev_is_clustered(mddev)) + md_cluster_ops->new_disk_ack(mddev, false); + else + err = -EINVAL; + goto unlock; + case HOT_ADD_DISK: err = hot_add_disk(mddev, new_decode_dev(arg)); goto unlock; diff --git a/drivers/md/md.h b/drivers/md/md.h index bfebcfdf54e6..6dc0ce09f50c 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -171,6 +171,10 @@ enum flag_bits { * a want_replacement device with same * raid_disk number. */ + Candidate, /* For clustered environments only: + * This device is seen locally but not + * by the whole cluster + */ }; #define BB_LEN_MASK (0x00000000000001FFULL) @@ -666,6 +670,7 @@ extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, extern void md_unplug(struct blk_plug_cb *cb, bool from_schedule); extern void md_reload_sb(struct mddev *mddev); +extern void md_update_sb(struct mddev *mddev, int force); static inline int mddev_check_plugged(struct mddev *mddev) { return !!blk_check_plugged(md_unplug, mddev, diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index f70d74189d16..53ed5d48308f 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1571,6 +1571,7 @@ static int raid1_spare_active(struct mddev *mddev) struct md_rdev *rdev = conf->mirrors[i].rdev; struct md_rdev *repl = conf->mirrors[conf->raid_disks + i].rdev; if (repl + && !test_bit(Candidate, &repl->flags) && repl->recovery_offset == MaxSector && !test_bit(Faulty, &repl->flags) && !test_and_set_bit(In_sync, &repl->flags)) { diff --git a/include/uapi/linux/raid/md_p.h b/include/uapi/linux/raid/md_p.h index 643489d33e68..2ae6131e69a5 100644 --- a/include/uapi/linux/raid/md_p.h +++ b/include/uapi/linux/raid/md_p.h @@ -78,6 +78,12 @@ #define MD_DISK_ACTIVE 1 /* disk is running or spare disk */ #define MD_DISK_SYNC 2 /* disk is in sync with the raid set */ #define MD_DISK_REMOVED 3 /* disk is in sync with the raid set */ +#define MD_DISK_CLUSTER_ADD 4 /* Initiate a disk add across the cluster + * For clustered enviroments only. + */ +#define MD_DISK_CANDIDATE 5 /* disk is added as spare (local) until confirmed + * For clustered enviroments only. + */ #define MD_DISK_WRITEMOSTLY 9 /* disk is "write-mostly" is RAID1 config. * read requests will only be sent here in diff --git a/include/uapi/linux/raid/md_u.h b/include/uapi/linux/raid/md_u.h index 74e7c60c4716..1cb8aa6850b5 100644 --- a/include/uapi/linux/raid/md_u.h +++ b/include/uapi/linux/raid/md_u.h @@ -62,6 +62,7 @@ #define STOP_ARRAY _IO (MD_MAJOR, 0x32) #define STOP_ARRAY_RO _IO (MD_MAJOR, 0x33) #define RESTART_ARRAY_RW _IO (MD_MAJOR, 0x34) +#define CLUSTERED_DISK_NACK _IO (MD_MAJOR, 0x35) /* 63 partitions with the alternate major number (mdp) */ #define MdpMinorShift 6 -- cgit v1.2.3 From 56a215d66b1eee870a6b90a8c245dfc3e503a137 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 6 Jan 2015 20:56:05 +0100 Subject: ARM: shmobile: sh73a0 dtsi: Add missing INTCA0 clock for irqpin module This clock drives the irqpin controller modules. Before, it was assumed enabled by the bootloader or reset state. By making it available to the driver, we make sure it gets enabled when needed, and allow it to be managed by system or runtime PM. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/boot/dts/sh73a0.dtsi | 15 +++++++++++++++ include/dt-bindings/clock/sh73a0-clock.h | 3 +++ 2 files changed, 18 insertions(+) (limited to 'include') diff --git a/arch/arm/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi index 076708797ef6..08f736d52179 100644 --- a/arch/arm/boot/dts/sh73a0.dtsi +++ b/arch/arm/boot/dts/sh73a0.dtsi @@ -94,6 +94,7 @@ 0 6 IRQ_TYPE_LEVEL_HIGH 0 7 IRQ_TYPE_LEVEL_HIGH 0 8 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp5_clks SH73A0_CLK_INTCA0>; control-parent; }; @@ -114,6 +115,7 @@ 0 14 IRQ_TYPE_LEVEL_HIGH 0 15 IRQ_TYPE_LEVEL_HIGH 0 16 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp5_clks SH73A0_CLK_INTCA0>; control-parent; }; @@ -134,6 +136,7 @@ 0 22 IRQ_TYPE_LEVEL_HIGH 0 23 IRQ_TYPE_LEVEL_HIGH 0 24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp5_clks SH73A0_CLK_INTCA0>; control-parent; }; @@ -154,6 +157,7 @@ 0 30 IRQ_TYPE_LEVEL_HIGH 0 31 IRQ_TYPE_LEVEL_HIGH 0 32 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp5_clks SH73A0_CLK_INTCA0>; control-parent; }; @@ -698,5 +702,16 @@ clock-output-names = "iic3", "iic4", "keysc"; }; + mstp5_clks: mstp5_clks@e6150144 { + compatible = "renesas,sh73a0-mstp-clocks", "renesas,cpg-mstp-clocks"; + reg = <0xe6150144 4>, <0xe615003c 4>; + clocks = <&cpg_clocks SH73A0_CLK_HP>; + #clock-cells = <1>; + clock-indices = < + SH73A0_CLK_INTCA0 + >; + clock-output-names = + "intca0"; + }; }; }; diff --git a/include/dt-bindings/clock/sh73a0-clock.h b/include/dt-bindings/clock/sh73a0-clock.h index 1dd3eb2b7d90..53369568c24c 100644 --- a/include/dt-bindings/clock/sh73a0-clock.h +++ b/include/dt-bindings/clock/sh73a0-clock.h @@ -76,4 +76,7 @@ #define SH73A0_CLK_IIC4 10 #define SH73A0_CLK_KEYSC 3 +/* MSTP5 */ +#define SH73A0_CLK_INTCA0 8 + #endif -- cgit v1.2.3 From 41650f406cdc4a420d5c08e1b407f6420323a04b Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 6 Jan 2015 00:33:25 +0300 Subject: ARM: shmobile: r8a7790: add CAN clocks The R-Car CAN controllers can derive the CAN bus clock not only from their peripheral clock input (clkp1) but also from the other internal clock (clkp2) and external clock fed on CAN_CLK pin. Describe those clocks in the device tree, along with the USB_EXTAL clock from which clkp2 is derived. Signed-off-by: Sergei Shtylyov Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7790.dtsi | 22 ++++++++++++++++++++-- include/dt-bindings/clock/r8a7790-clock.h | 1 + 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 24de994443e1..e872854b4ba9 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -838,16 +838,34 @@ clock-output-names = "audio_clk_c"; }; + /* External USB clock - can be overridden by the board */ + usb_extal_clk: usb_extal_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + clock-output-names = "usb_extal"; + }; + + /* External CAN clock */ + can_clk: can_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; + clock-output-names = "can_clk"; + status = "disabled"; + }; + /* Special CPG clocks */ cpg_clocks: cpg_clocks@e6150000 { compatible = "renesas,r8a7790-cpg-clocks", "renesas,rcar-gen2-cpg-clocks"; reg = <0 0xe6150000 0 0x1000>; - clocks = <&extal_clk>; + clocks = <&extal_clk &usb_extal_clk>; #clock-cells = <1>; clock-output-names = "main", "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1", - "z"; + "z", "rcan"; }; /* Variable factor clocks */ diff --git a/include/dt-bindings/clock/r8a7790-clock.h b/include/dt-bindings/clock/r8a7790-clock.h index 91940271cf83..ffa8c11be68a 100644 --- a/include/dt-bindings/clock/r8a7790-clock.h +++ b/include/dt-bindings/clock/r8a7790-clock.h @@ -21,6 +21,7 @@ #define R8A7790_CLK_SD0 7 #define R8A7790_CLK_SD1 8 #define R8A7790_CLK_Z 9 +#define R8A7790_CLK_RCAN 10 /* MSTP0 */ #define R8A7790_CLK_MSIOF0 0 -- cgit v1.2.3 From b324252cc18d52d5752942a8574c22229153c58f Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 6 Jan 2015 01:24:08 +0300 Subject: ARM: shmobile: r8a7791: add CAN clocks The R-Car CAN controllers can derive the CAN bus clock not only from their peripheral clock input (clkp1) but also from the other internal clock (clkp2) and external clock fed on CAN_CLK pin. Describe those clocks in the device tree, along with the USB_EXTAL clock from which clkp2 is derived. Signed-off-by: Sergei Shtylyov Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791.dtsi | 23 +++++++++++++++++++++-- include/dt-bindings/clock/r8a7791-clock.h | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index afba8af1a5e4..1ebffef5b908 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -862,15 +862,34 @@ status = "disabled"; }; + /* External USB clock - can be overridden by the board */ + usb_extal_clk: usb_extal_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <48000000>; + clock-output-names = "usb_extal"; + }; + + /* External CAN clock */ + can_clk: can_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; + clock-output-names = "can_clk"; + status = "disabled"; + }; + /* Special CPG clocks */ cpg_clocks: cpg_clocks@e6150000 { compatible = "renesas,r8a7791-cpg-clocks", "renesas,rcar-gen2-cpg-clocks"; reg = <0 0xe6150000 0 0x1000>; - clocks = <&extal_clk>; + clocks = <&extal_clk &usb_extal_clk>; #clock-cells = <1>; clock-output-names = "main", "pll0", "pll1", "pll3", - "lb", "qspi", "sdh", "sd0", "z"; + "lb", "qspi", "sdh", "sd0", "z", + "rcan"; }; /* Variable factor clocks */ diff --git a/include/dt-bindings/clock/r8a7791-clock.h b/include/dt-bindings/clock/r8a7791-clock.h index f096f3f6c16a..a45a36307895 100644 --- a/include/dt-bindings/clock/r8a7791-clock.h +++ b/include/dt-bindings/clock/r8a7791-clock.h @@ -20,6 +20,7 @@ #define R8A7791_CLK_SDH 6 #define R8A7791_CLK_SD0 7 #define R8A7791_CLK_Z 8 +#define R8A7791_CLK_RCAN 9 /* MSTP0 */ #define R8A7791_CLK_MSIOF0 0 -- cgit v1.2.3 From ae65a8ae4c25c7ea01204c9d033cd47da3000cf8 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 30 Dec 2014 23:20:34 +0300 Subject: ARM: shmobile: r8a7791: add ADSP clocks Add the ADSP clocks to the CPG and MSTP5 nodes of the R8A7791 device tree. Based on the original patch by Konstantin Kozhevnikov . Signed-off-by: Sergei Shtylyov Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7791.dtsi | 11 +++++++---- include/dt-bindings/clock/r8a7791-clock.h | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index ff49b95df0ec..1e593a2b55fa 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -909,7 +909,7 @@ #clock-cells = <1>; clock-output-names = "main", "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "z", - "rcan"; + "rcan", "adsp"; }; /* Variable factor clocks */ @@ -1164,13 +1164,16 @@ mstp5_clks: mstp5_clks@e6150144 { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150144 0 4>, <0 0xe615003c 0 4>; - clocks = <&hp_clk>, <&hp_clk>, <&extal_clk>, <&p_clk>; + clocks = <&hp_clk>, <&hp_clk>, <&cpg_clocks R8A7791_CLK_ADSP>, + <&extal_clk>, <&p_clk>; #clock-cells = <1>; clock-indices = < R8A7791_CLK_AUDIO_DMAC0 R8A7791_CLK_AUDIO_DMAC1 - R8A7791_CLK_THERMAL R8A7791_CLK_PWM + R8A7791_CLK_ADSP_MOD R8A7791_CLK_THERMAL + R8A7791_CLK_PWM >; - clock-output-names = "audmac0", "audmac1", "thermal", "pwm"; + clock-output-names = "audmac0", "audmac1", "adsp_mod", + "thermal", "pwm"; }; mstp7_clks: mstp7_clks@e615014c { compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; diff --git a/include/dt-bindings/clock/r8a7791-clock.h b/include/dt-bindings/clock/r8a7791-clock.h index a45a36307895..8fc5dc8faeea 100644 --- a/include/dt-bindings/clock/r8a7791-clock.h +++ b/include/dt-bindings/clock/r8a7791-clock.h @@ -21,6 +21,7 @@ #define R8A7791_CLK_SD0 7 #define R8A7791_CLK_Z 8 #define R8A7791_CLK_RCAN 9 +#define R8A7791_CLK_ADSP 10 /* MSTP0 */ #define R8A7791_CLK_MSIOF0 0 @@ -72,6 +73,7 @@ /* MSTP5 */ #define R8A7791_CLK_AUDIO_DMAC1 1 #define R8A7791_CLK_AUDIO_DMAC0 2 +#define R8A7791_CLK_ADSP_MOD 6 #define R8A7791_CLK_THERMAL 22 #define R8A7791_CLK_PWM 23 -- cgit v1.2.3 From 3453ca9e4f51a0e6865d303f4e428cb6f630594f Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 30 Dec 2014 23:21:45 +0300 Subject: ARM: shmobile: r8a7790: add ADSP clocks Add the ADSP clocks to the CPG and MSTP5 nodes of the R8A7790 device tree. Based on the original patch by Konstantin Kozhevnikov . Signed-off-by: Sergei Shtylyov Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/boot/dts/r8a7790.dtsi | 11 +++++++---- include/dt-bindings/clock/r8a7790-clock.h | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index cd7fc05f5e99..c6c0a0c8f1be 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -885,7 +885,7 @@ #clock-cells = <1>; clock-output-names = "main", "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1", - "z", "rcan"; + "z", "rcan", "adsp"; }; /* Variable factor clocks */ @@ -1159,13 +1159,16 @@ mstp5_clks: mstp5_clks@e6150144 { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150144 0 4>, <0 0xe615003c 0 4>; - clocks = <&hp_clk>, <&hp_clk>, <&extal_clk>, <&p_clk>; + clocks = <&hp_clk>, <&hp_clk>, <&cpg_clocks R8A7790_CLK_ADSP>, + <&extal_clk>, <&p_clk>; #clock-cells = <1>; clock-indices = < R8A7790_CLK_AUDIO_DMAC0 R8A7790_CLK_AUDIO_DMAC1 - R8A7790_CLK_THERMAL R8A7790_CLK_PWM + R8A7790_CLK_ADSP_MOD R8A7790_CLK_THERMAL + R8A7790_CLK_PWM >; - clock-output-names = "audmac0", "audmac1", "thermal", "pwm"; + clock-output-names = "audmac0", "audmac1", "adsp_mod", + "thermal", "pwm"; }; mstp7_clks: mstp7_clks@e615014c { compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; diff --git a/include/dt-bindings/clock/r8a7790-clock.h b/include/dt-bindings/clock/r8a7790-clock.h index ffa8c11be68a..3f2c6b198d4a 100644 --- a/include/dt-bindings/clock/r8a7790-clock.h +++ b/include/dt-bindings/clock/r8a7790-clock.h @@ -22,6 +22,7 @@ #define R8A7790_CLK_SD1 8 #define R8A7790_CLK_Z 9 #define R8A7790_CLK_RCAN 10 +#define R8A7790_CLK_ADSP 11 /* MSTP0 */ #define R8A7790_CLK_MSIOF0 0 @@ -81,6 +82,7 @@ /* MSTP5 */ #define R8A7790_CLK_AUDIO_DMAC1 1 #define R8A7790_CLK_AUDIO_DMAC0 2 +#define R8A7790_CLK_ADSP_MOD 6 #define R8A7790_CLK_THERMAL 22 #define R8A7790_CLK_PWM 23 -- cgit v1.2.3 From bdba0101c7e90e60481018005654227bdfd67aec Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Tue, 20 Jan 2015 13:51:38 +0100 Subject: ARM: shmobile: r8a73a4: Add CPG register bits header Signed-off-by: Ulrich Hecht Acked-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- include/dt-bindings/clock/r8a73a4-clock.h | 62 +++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 include/dt-bindings/clock/r8a73a4-clock.h (limited to 'include') diff --git a/include/dt-bindings/clock/r8a73a4-clock.h b/include/dt-bindings/clock/r8a73a4-clock.h new file mode 100644 index 000000000000..9a4b4c9ca44a --- /dev/null +++ b/include/dt-bindings/clock/r8a73a4-clock.h @@ -0,0 +1,62 @@ +/* + * Copyright 2014 Ulrich Hecht + * + * 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. + */ + +#ifndef __DT_BINDINGS_CLOCK_R8A73A4_H__ +#define __DT_BINDINGS_CLOCK_R8A73A4_H__ + +/* CPG */ +#define R8A73A4_CLK_MAIN 0 +#define R8A73A4_CLK_PLL0 1 +#define R8A73A4_CLK_PLL1 2 +#define R8A73A4_CLK_PLL2 3 +#define R8A73A4_CLK_PLL2S 4 +#define R8A73A4_CLK_PLL2H 5 +#define R8A73A4_CLK_Z 6 +#define R8A73A4_CLK_Z2 7 +#define R8A73A4_CLK_I 8 +#define R8A73A4_CLK_M3 9 +#define R8A73A4_CLK_B 10 +#define R8A73A4_CLK_M1 11 +#define R8A73A4_CLK_M2 12 +#define R8A73A4_CLK_ZX 13 +#define R8A73A4_CLK_ZS 14 +#define R8A73A4_CLK_HP 15 + +/* MSTP2 */ +#define R8A73A4_CLK_DMAC 18 +#define R8A73A4_CLK_SCIFB3 17 +#define R8A73A4_CLK_SCIFB2 16 +#define R8A73A4_CLK_SCIFB1 7 +#define R8A73A4_CLK_SCIFB0 6 +#define R8A73A4_CLK_SCIFA0 4 +#define R8A73A4_CLK_SCIFA1 3 + +/* MSTP3 */ +#define R8A73A4_CLK_CMT1 29 +#define R8A73A4_CLK_IIC1 23 +#define R8A73A4_CLK_IIC0 18 +#define R8A73A4_CLK_IIC7 17 +#define R8A73A4_CLK_IIC6 16 +#define R8A73A4_CLK_MMCIF0 15 +#define R8A73A4_CLK_SDHI0 14 +#define R8A73A4_CLK_SDHI1 13 +#define R8A73A4_CLK_SDHI2 12 +#define R8A73A4_CLK_MMCIF1 5 +#define R8A73A4_CLK_IIC2 0 + +/* MSTP4 */ +#define R8A73A4_CLK_IIC3 11 +#define R8A73A4_CLK_IIC4 10 +#define R8A73A4_CLK_IIC5 9 + +/* MSTP5 */ +#define R8A73A4_CLK_THERMAL 22 +#define R8A73A4_CLK_IIC8 15 + +#endif /* __DT_BINDINGS_CLOCK_R8A73A4_H__ */ -- cgit v1.2.3 From 83054671d28db9f1dbac1d3d1bf3b50b128e06ba Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Mon, 16 Feb 2015 17:58:46 +0100 Subject: ARM: shmobile: r8a7778: add CPG register bits header Enumerates CPG driver custom clocks and MSTP clock enable bits. Signed-off-by: Ulrich Hecht Acked-by: Laurent Pinchart Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- include/dt-bindings/clock/r8a7778-clock.h | 71 +++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 include/dt-bindings/clock/r8a7778-clock.h (limited to 'include') diff --git a/include/dt-bindings/clock/r8a7778-clock.h b/include/dt-bindings/clock/r8a7778-clock.h new file mode 100644 index 000000000000..f6b07c5399de --- /dev/null +++ b/include/dt-bindings/clock/r8a7778-clock.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2014 Ulrich Hecht + * + * 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. + */ + +#ifndef __DT_BINDINGS_CLOCK_R8A7778_H__ +#define __DT_BINDINGS_CLOCK_R8A7778_H__ + +/* CPG */ +#define R8A7778_CLK_PLLA 0 +#define R8A7778_CLK_PLLB 1 +#define R8A7778_CLK_B 2 +#define R8A7778_CLK_OUT 3 +#define R8A7778_CLK_P 4 +#define R8A7778_CLK_S 5 +#define R8A7778_CLK_S1 6 + +/* MSTP0 */ +#define R8A7778_CLK_I2C0 30 +#define R8A7778_CLK_I2C1 29 +#define R8A7778_CLK_I2C2 28 +#define R8A7778_CLK_I2C3 27 +#define R8A7778_CLK_SCIF0 26 +#define R8A7778_CLK_SCIF1 25 +#define R8A7778_CLK_SCIF2 24 +#define R8A7778_CLK_SCIF3 23 +#define R8A7778_CLK_SCIF4 22 +#define R8A7778_CLK_SCIF5 21 +#define R8A7778_CLK_TMU0 16 +#define R8A7778_CLK_TMU1 15 +#define R8A7778_CLK_TMU2 14 +#define R8A7778_CLK_SSI0 12 +#define R8A7778_CLK_SSI1 11 +#define R8A7778_CLK_SSI2 10 +#define R8A7778_CLK_SSI3 9 +#define R8A7778_CLK_SRU 8 +#define R8A7778_CLK_HSPI 7 + +/* MSTP1 */ +#define R8A7778_CLK_ETHER 14 +#define R8A7778_CLK_VIN0 10 +#define R8A7778_CLK_VIN1 9 +#define R8A7778_CLK_USB 0 + +/* MSTP3 */ +#define R8A7778_CLK_MMC 31 +#define R8A7778_CLK_SDHI0 23 +#define R8A7778_CLK_SDHI1 22 +#define R8A7778_CLK_SDHI2 21 +#define R8A7778_CLK_SSI4 11 +#define R8A7778_CLK_SSI5 10 +#define R8A7778_CLK_SSI6 9 +#define R8A7778_CLK_SSI7 8 +#define R8A7778_CLK_SSI8 7 + +/* MSTP5 */ +#define R8A7778_CLK_SRU_SRC0 31 +#define R8A7778_CLK_SRU_SRC1 30 +#define R8A7778_CLK_SRU_SRC2 29 +#define R8A7778_CLK_SRU_SRC3 28 +#define R8A7778_CLK_SRU_SRC4 27 +#define R8A7778_CLK_SRU_SRC5 26 +#define R8A7778_CLK_SRU_SRC6 25 +#define R8A7778_CLK_SRU_SRC7 24 +#define R8A7778_CLK_SRU_SRC8 23 + +#endif /* __DT_BINDINGS_CLOCK_R8A7778_H__ */ -- cgit v1.2.3 From 1af434a92871af93d97ce28e35497532a4167a0c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 22 Feb 2015 12:24:19 +0100 Subject: drm/atomic-helper: Rename commmit_post/pre_planes These names only make sense because of backwards compatability with the order used by the crtc helper library. There's not really any real requirement in the ordering here. So rename them to something more descriptive and update the kerneldoc a bit. Motivated in a discussion with Laurent about how to restore plane state for dpms for drivers with runtime pm. v2: Squash in fixup from Stephen Rothwell to fix a conflict with tegra. Cc: Laurent Pinchart Reviewed-by: Rob Clark Acked-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 40 +++++++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_atomic.c | 4 ++-- drivers/gpu/drm/msm/msm_atomic.c | 4 ++-- drivers/gpu/drm/tegra/drm.c | 4 ++-- include/drm/drm_atomic_helper.h | 6 +++--- 5 files changed, 34 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 65b9adf5777c..9c528bbcd8d2 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -768,34 +768,44 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) } /** - * drm_atomic_helper_commit_pre_planes - modeset commit before plane updates + * drm_atomic_helper_commit_modeset_disables - modeset commit to disable outputs * @dev: DRM device * @old_state: atomic state object with old state structures * - * This function commits the modeset changes that need to be committed before - * updating planes. It shuts down all the outputs that need to be shut down and + * This function shuts down all the outputs that need to be shut down and * prepares them (if required) with the new mode. + * + * For compatability with legacy crtc helpers this should be called before + * drm_atomic_helper_commit_planes(), which is what the default commit function + * does. But drivers with different needs can group the modeset commits together + * and do the plane commits at the end. This is useful for drivers doing runtime + * PM since planes updates then only happen when the CRTC is actually enabled. */ -void drm_atomic_helper_commit_pre_planes(struct drm_device *dev, - struct drm_atomic_state *old_state) +void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev, + struct drm_atomic_state *old_state) { disable_outputs(dev, old_state); set_routing_links(dev, old_state); crtc_set_mode(dev, old_state); } -EXPORT_SYMBOL(drm_atomic_helper_commit_pre_planes); +EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables); /** - * drm_atomic_helper_commit_post_planes - modeset commit after plane updates + * drm_atomic_helper_commit_modeset_enables - modeset commit to enable outputs * @dev: DRM device * @old_state: atomic state object with old state structures * - * This function commits the modeset changes that need to be committed after - * updating planes: It enables all the outputs with the new configuration which - * had to be turned off for the update. + * This function enables all the outputs with the new configuration which had to + * be turned off for the update. + * + * For compatability with legacy crtc helpers this should be called after + * drm_atomic_helper_commit_planes(), which is what the default commit function + * does. But drivers with different needs can group the modeset commits together + * and do the plane commits at the end. This is useful for drivers doing runtime + * PM since planes updates then only happen when the CRTC is actually enabled. */ -void drm_atomic_helper_commit_post_planes(struct drm_device *dev, - struct drm_atomic_state *old_state) +void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, + struct drm_atomic_state *old_state) { int ncrtcs = old_state->dev->mode_config.num_crtc; int i; @@ -861,7 +871,7 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, encoder->bridge->funcs->enable(encoder->bridge); } } -EXPORT_SYMBOL(drm_atomic_helper_commit_post_planes); +EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables); static void wait_for_fences(struct drm_device *dev, struct drm_atomic_state *state) @@ -1030,11 +1040,11 @@ int drm_atomic_helper_commit(struct drm_device *dev, wait_for_fences(dev, state); - drm_atomic_helper_commit_pre_planes(dev, state); + drm_atomic_helper_commit_modeset_disables(dev, state); drm_atomic_helper_commit_planes(dev, state); - drm_atomic_helper_commit_post_planes(dev, state); + drm_atomic_helper_commit_modeset_enables(dev, state); drm_atomic_helper_wait_for_vblanks(dev, state); diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 19a9dd5408f3..011b8960fd75 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -134,9 +134,9 @@ int intel_atomic_commit(struct drm_device *dev, * FIXME: The proper sequence here will eventually be: * * drm_atomic_helper_swap_state(dev, state) - * drm_atomic_helper_commit_pre_planes(dev, state); + * drm_atomic_helper_commit_modeset_disables(dev, state); * drm_atomic_helper_commit_planes(dev, state); - * drm_atomic_helper_commit_post_planes(dev, state); + * drm_atomic_helper_commit_modeset_enables(dev, state); * drm_atomic_helper_wait_for_vblanks(dev, state); * drm_atomic_helper_cleanup_planes(dev, state); * drm_atomic_state_free(state); diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 871aa2108dc6..7c412292a0ff 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -96,11 +96,11 @@ static void complete_commit(struct msm_commit *c) kms->funcs->prepare_commit(kms, state); - drm_atomic_helper_commit_pre_planes(dev, state); + drm_atomic_helper_commit_modeset_disables(dev, state); drm_atomic_helper_commit_planes(dev, state); - drm_atomic_helper_commit_post_planes(dev, state); + drm_atomic_helper_commit_modeset_enables(dev, state); /* NOTE: _wait_for_vblanks() only waits for vblank on * enabled CRTCs. So we end up faulting when disabling diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 7dd328d77996..5f1880766110 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -55,9 +55,9 @@ static void tegra_atomic_complete(struct tegra_drm *tegra, * current layout. */ - drm_atomic_helper_commit_pre_planes(drm, state); + drm_atomic_helper_commit_modeset_disables(drm, state); drm_atomic_helper_commit_planes(drm, state); - drm_atomic_helper_commit_post_planes(drm, state); + drm_atomic_helper_commit_modeset_enables(drm, state); drm_atomic_helper_wait_for_vblanks(drm, state); diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 8039d54a7441..829280b56874 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -43,9 +43,9 @@ int drm_atomic_helper_commit(struct drm_device *dev, void drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, struct drm_atomic_state *old_state); -void drm_atomic_helper_commit_pre_planes(struct drm_device *dev, - struct drm_atomic_state *state); -void drm_atomic_helper_commit_post_planes(struct drm_device *dev, +void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev, + struct drm_atomic_state *state); +void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, struct drm_atomic_state *old_state); int drm_atomic_helper_prepare_planes(struct drm_device *dev, -- cgit v1.2.3 From c982bd90f58681d00363538167477e60e2c8f731 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 22 Feb 2015 12:24:20 +0100 Subject: drm/atomic-helpers: make mode_set hooks optional With runtime PM the hw might still be off while doing the ->mode_set callbacks - runtime PM get/put should only happen in the enable/disable hooks to properly support DPMS. Which essentially makes these callbacks useless for drivers support runtime PM, so make them optional. Again motivated by discussions with Laurent. Cc: Laurent Pinchart Acked-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 5 +++-- include/drm/drm_crtc_helper.h | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 9c528bbcd8d2..28aa87510551 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -723,7 +723,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) funcs = crtc->helper_private; - if (crtc->state->enable) { + if (crtc->state->enable && funcs->mode_set_nofb) { DRM_DEBUG_ATOMIC("modeset on [CRTC:%d]\n", crtc->base.id); @@ -759,7 +759,8 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) * Each encoder has at most one connector (since we always steal * it away), so we won't call call mode_set hooks twice. */ - funcs->mode_set(encoder, mode, adjusted_mode); + if (funcs->mode_set) + funcs->mode_set(encoder, mode, adjusted_mode); if (encoder->bridge && encoder->bridge->funcs->mode_set) encoder->bridge->funcs->mode_set(encoder->bridge, diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index c250a22b39ab..92d5135b55d2 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -89,6 +89,7 @@ struct drm_crtc_helper_funcs { int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *old_fb); + /* Actually set the mode for atomic helpers, optional */ void (*mode_set_nofb)(struct drm_crtc *crtc); /* Move the crtc on the current fb to the given position *optional* */ @@ -119,7 +120,7 @@ struct drm_crtc_helper_funcs { * @mode_fixup: try to fixup proposed mode for this connector * @prepare: part of the disable sequence, called before the CRTC modeset * @commit: called after the CRTC modeset - * @mode_set: set this mode + * @mode_set: set this mode, optional for atomic helpers * @get_crtc: return CRTC that the encoder is currently attached to * @detect: connection status detection * @disable: disable encoder when not in use (overrides DPMS off) -- cgit v1.2.3 From e045d20bef41707dbba676e58624b54f9f39e172 Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Thu, 19 Feb 2015 13:16:44 +0530 Subject: drm: Adding edp1.4 specific dpcd macros Adding dpcd macros related to edp1.4 and link rates v2: Added DP_SUPPORTED_LINK_RATES macros Signed-off-by: Sonika Jindal Reviewed-by: Todd Previte Signed-off-by: Daniel Vetter --- include/drm/drm_dp_helper.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include') diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 7e25030a6aa2..d4803224028f 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -92,6 +92,9 @@ # define DP_MSA_TIMING_PAR_IGNORED (1 << 6) /* eDP */ # define DP_OUI_SUPPORT (1 << 7) +#define DP_SUPPORTED_LINK_RATES 0x010 /*eDP 1.4*/ +#define DP_MAX_SUPPORTED_RATES 0x8 + #define DP_I2C_SPEED_CAP 0x00c /* DPI */ # define DP_I2C_SPEED_1K 0x01 # define DP_I2C_SPEED_5K 0x02 @@ -101,6 +104,7 @@ # define DP_I2C_SPEED_1M 0x20 #define DP_EDP_CONFIGURATION_CAP 0x00d /* XXX 1.2? */ +# define DP_DPCD_DISPLAY_CONTROL_CAPABLE (1 << 3) /* edp v1.2 or higher */ #define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* XXX 1.2? */ /* Multiple stream transport */ @@ -221,6 +225,8 @@ # define DP_UP_REQ_EN (1 << 1) # define DP_UPSTREAM_IS_SRC (1 << 2) +#define DP_LINK_RATE_SET 0x115 + #define DP_PSR_EN_CFG 0x170 /* XXX 1.2? */ # define DP_PSR_ENABLE (1 << 0) # define DP_PSR_MAIN_LINK_ACTIVE (1 << 1) @@ -332,6 +338,8 @@ # define DP_SET_POWER_D3 0x2 # define DP_SET_POWER_MASK 0x3 +#define DP_EDP_DPCD_REV 0x700 + #define DP_SIDEBAND_MSG_DOWN_REQ_BASE 0x1000 /* 1.2 MST */ #define DP_SIDEBAND_MSG_UP_REP_BASE 0x1200 /* 1.2 MST */ #define DP_SIDEBAND_MSG_DOWN_REP_BASE 0x1400 /* 1.2 MST */ -- cgit v1.2.3 From 7a16360d56f6846da5a7c8cb50b14e3464ad133a Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 2 Oct 2014 17:58:48 +0000 Subject: OMAPDSS: DISPC: remove OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES DISPC can drive data lines either on rising or falling pixel clock edge, which can be configured by the user. Sync lines can also be driven on rising or falling pixel clock edge, but additionally the HW can be configured to drive the sync lines on opposite clock edge from the data lines. This opposite edge setting does not make any sense, as the same effect can be achieved by just setting the sync lines to be driven on the other edge compared to the data lines. It feels like some kind of backward compatibility option, even if all DSS versions seem to have the same implementation. To simplify the code and configuration of the signals, and to make the dispc timings more compatible with what is used on other platforms, let's just remove the whole opposite-edge support. The drivers that used OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES setting are changed so that they use the opposite setting from the data edge. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_connector.c | 2 +- drivers/video/fbdev/omap2/displays-new/connector-dvi.c | 2 +- .../video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c | 2 +- .../video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c | 2 +- drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c | 2 +- drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c | 2 +- drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c | 2 +- drivers/video/fbdev/omap2/dss/dispc.c | 10 +++------- drivers/video/fbdev/omap2/dss/display.c | 4 +++- drivers/video/fbdev/omap2/dss/dsi.c | 2 +- drivers/video/fbdev/omap2/dss/rfbi.c | 2 +- drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 4 ++-- include/video/omapdss.h | 1 - 13 files changed, 17 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index a94b11f7859d..2c2173bc3f00 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -102,7 +102,7 @@ void copy_timings_drm_to_omap(struct omap_video_timings *timings, timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH; - timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE; } static enum drm_connector_status omap_connector_detect( diff --git a/drivers/video/fbdev/omap2/displays-new/connector-dvi.c b/drivers/video/fbdev/omap2/displays-new/connector-dvi.c index 0cdc97413020..a8ce920fa797 100644 --- a/drivers/video/fbdev/omap2/displays-new/connector-dvi.c +++ b/drivers/video/fbdev/omap2/displays-new/connector-dvi.c @@ -37,7 +37,7 @@ static const struct omap_video_timings dvic_default_timings = { .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, .de_level = OMAPDSS_SIG_ACTIVE_HIGH, - .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, }; struct panel_drv_data { diff --git a/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c b/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c index 27d4fcfa1824..9974a37a11af 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c @@ -37,7 +37,7 @@ static struct omap_video_timings lb035q02_timings = { .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, .de_level = OMAPDSS_SIG_ACTIVE_HIGH, - .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, }; struct panel_drv_data { diff --git a/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c b/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c index 18b19b6e1ac2..eae263702964 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c @@ -54,7 +54,7 @@ static const struct omap_video_timings sharp_ls_timings = { .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, .de_level = OMAPDSS_SIG_ACTIVE_HIGH, - .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, }; #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) diff --git a/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c index 337ccc5c0f5e..90cbc4c3406c 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c @@ -108,7 +108,7 @@ static const struct omap_video_timings acx565akm_panel_timings = { .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, .de_level = OMAPDSS_SIG_ACTIVE_HIGH, - .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, }; #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) diff --git a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c index fbba0b8ca871..9edc51133c59 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c @@ -58,7 +58,7 @@ static struct omap_video_timings td028ttec1_panel_timings = { .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, .de_level = OMAPDSS_SIG_ACTIVE_HIGH, - .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, }; #define JBT_COMMAND 0x000 diff --git a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c index 5aba76bca25a..79e4a029aab9 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c @@ -91,7 +91,7 @@ static const struct omap_video_timings tpo_td043_timings = { .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, .de_level = OMAPDSS_SIG_ACTIVE_HIGH, - .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, }; #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/video/fbdev/omap2/dss/dispc.c index a19a1d4b2d19..11bd780fcdfa 100644 --- a/drivers/video/fbdev/omap2/dss/dispc.c +++ b/drivers/video/fbdev/omap2/dss/dispc.c @@ -2934,22 +2934,18 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, case OMAPDSS_DRIVE_SIG_FALLING_EDGE: ipc = true; break; - case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES: default: BUG(); } + /* always use the 'rf' setting */ + onoff = true; + switch (sync_pclk_edge) { - case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES: - onoff = false; - rf = false; - break; case OMAPDSS_DRIVE_SIG_FALLING_EDGE: - onoff = true; rf = false; break; case OMAPDSS_DRIVE_SIG_RISING_EDGE: - onoff = true; rf = true; break; default: diff --git a/drivers/video/fbdev/omap2/dss/display.c b/drivers/video/fbdev/omap2/dss/display.c index 2412a0dd0c13..a6fd2d35ad60 100644 --- a/drivers/video/fbdev/omap2/dss/display.c +++ b/drivers/video/fbdev/omap2/dss/display.c @@ -295,7 +295,9 @@ void videomode_to_omap_video_timings(const struct videomode *vm, OMAPDSS_DRIVE_SIG_RISING_EDGE : OMAPDSS_DRIVE_SIG_FALLING_EDGE; - ovt->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + ovt->sync_pclk_edge = vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ? + OMAPDSS_DRIVE_SIG_FALLING_EDGE : + OMAPDSS_DRIVE_SIG_RISING_EDGE; } EXPORT_SYMBOL(videomode_to_omap_video_timings); diff --git a/drivers/video/fbdev/omap2/dss/dsi.c b/drivers/video/fbdev/omap2/dss/dsi.c index 5081f6fb1737..28b0bc11669d 100644 --- a/drivers/video/fbdev/omap2/dss/dsi.c +++ b/drivers/video/fbdev/omap2/dss/dsi.c @@ -4137,7 +4137,7 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; - dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE; dss_mgr_set_timings(mgr, &dsi->timings); diff --git a/drivers/video/fbdev/omap2/dss/rfbi.c b/drivers/video/fbdev/omap2/dss/rfbi.c index 28e694b11ff9..065effca9236 100644 --- a/drivers/video/fbdev/omap2/dss/rfbi.c +++ b/drivers/video/fbdev/omap2/dss/rfbi.c @@ -869,7 +869,7 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; - rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE; dss_mgr_set_timings(mgr, &rfbi.timings); } diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c index 22f07f88bc40..4f0cbb54d4db 100644 --- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c @@ -2073,7 +2073,7 @@ static int omapfb_mode_to_timings(const char *mode_str, } else { timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH; - timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE; } timings->pixelclock = PICOS2KHZ(var->pixclock) * 1000; @@ -2223,7 +2223,7 @@ static void fb_videomode_to_omap_timings(struct fb_videomode *m, } else { t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; t->de_level = OMAPDSS_SIG_ACTIVE_HIGH; - t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE; } t->x_res = m->xres; diff --git a/include/video/omapdss.h b/include/video/omapdss.h index 60de61fea8e3..7414e4a97508 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h @@ -134,7 +134,6 @@ enum omap_dss_signal_level { }; enum omap_dss_signal_edge { - OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, OMAPDSS_DRIVE_SIG_RISING_EDGE, OMAPDSS_DRIVE_SIG_FALLING_EDGE, }; -- cgit v1.2.3 From 7ad582be12728ea76b11ce4f4c2f1202d11bf13c Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 2 Oct 2014 17:58:50 +0000 Subject: OMAPDSS: change signal_level & signal_edge enum values At the moment the enum values for ACTIVE_HIGH and RISING_EDGE are 0, and ACTIVE_LOW and FALLING_EDGE are 1, to match the values programmed to HW. The previous patch removed this dependency. Swap the enum values the other way around. This doesn't change the behavior in any way, but makes it easier to debug as value of '1' means HIGH or RISING. Signed-off-by: Tomi Valkeinen --- include/video/omapdss.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/video/omapdss.h b/include/video/omapdss.h index 7414e4a97508..45a230190720 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h @@ -129,13 +129,13 @@ enum omap_rfbi_te_mode { }; enum omap_dss_signal_level { - OMAPDSS_SIG_ACTIVE_HIGH = 0, - OMAPDSS_SIG_ACTIVE_LOW = 1, + OMAPDSS_SIG_ACTIVE_LOW, + OMAPDSS_SIG_ACTIVE_HIGH, }; enum omap_dss_signal_edge { - OMAPDSS_DRIVE_SIG_RISING_EDGE, OMAPDSS_DRIVE_SIG_FALLING_EDGE, + OMAPDSS_DRIVE_SIG_RISING_EDGE, }; enum omap_dss_venc_type { -- cgit v1.2.3 From 7e182f78988404717e27aed5a9d4150631b323f4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 25 Feb 2015 12:05:13 -0300 Subject: [media] media.h: mark alsa struct in media_entity_desc as TODO The alsa struct in struct media_entity_desc is now marked as deprecated. However, the alsa struct should remain as it is since it cannot be replaced by a simple major/minor device node description. The alsa struct was designed to be used as an alsa card description so V4L2 drivers could use this to expose the alsa card that they create to carry the captured audio. Such a card is not just a PCM device, but also needs to contain the alsa subdevice information, and it may map to multiple devices, e.g. a PCM and a mixer device, such as the au0828 usb stick creates. This is exactly as intended and this cannot and should not be replaced by a simple major/minor. However, whether this information is in the right form for an ALSA device such that it can handle udev renaming rules as well is another matter. So mark this alsa struct as TODO and document the problems involved. Updated the documentation as well to reflect this and to add the 'major' and 'minor' field documentation. Updated the documentation to clearly state that struct dev is to be used for (sub-)devices that create a single device node. Other devices need their own structure here. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../DocBook/media/v4l/media-ioc-enum-entities.xml | 16 ++++++++++++- include/uapi/linux/media.h | 26 +++++++++++++++++----- 2 files changed, 36 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml index cbf307f21a63..5872f8bbf774 100644 --- a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml +++ b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml @@ -145,7 +145,21 @@ struct dev - Valid for (sub-)devices that create devnodes. + Valid for (sub-)devices that create a single device node. + + + + + __u32 + major + Device node major number. + + + + + __u32 + minor + Device node minor number. diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index 52cc2a6b19b7..4e816be3de39 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -89,6 +89,27 @@ struct media_entity_desc { __u32 minor; } dev; +#if 1 + /* + * TODO: this shouldn't have been added without + * actual drivers that use this. When the first real driver + * appears that sets this information, special attention + * should be given whether this information is 1) enough, and + * 2) can deal with udev rules that rename devices. The struct + * dev would not be sufficient for this since that does not + * contain the subdevice information. In addition, struct dev + * can only refer to a single device, and not to multiple (e.g. + * pcm and mixer devices). + * + * So for now mark this as a to do. + */ + struct { + __u32 card; + __u32 device; + __u32 subdevice; + } alsa; +#endif + #if 1 /* * DEPRECATED: previous node specifications. Kept just to @@ -106,11 +127,6 @@ struct media_entity_desc { __u32 major; __u32 minor; } fb; - struct { - __u32 card; - __u32 device; - __u32 subdevice; - } alsa; int dvb; #endif -- cgit v1.2.3 From 1b84f2a4cd4a6f517a313261f6f7c8caae5696c6 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 2 Feb 2015 12:26:22 +0100 Subject: mfd: cros_ec: Use fixed size arrays to transfer data with the EC The struct cros_ec_command will be used as an ioctl() argument for the API to control the ChromeOS EC from user-space. So the data structure has to be 64-bit safe to make it compatible between 32 and 64 avoiding the need for a compat ioctl interface. Since pointers are self-aligned to different byte boundaries, use fixed size arrays instead of pointers for transferring ingoing and outgoing data with the Embedded Controller. Also, re-arrange struct members by decreasing alignment requirements to reduce the needing padding size. Signed-off-by: Javier Martinez Canillas Acked-by: Lee Jones Tested-by: Gwendal Grignou Reviewed-by: Gwendal Grignou Signed-off-by: Olof Johansson --- drivers/i2c/busses/i2c-cros-ec-tunnel.c | 51 +++++++-------------------------- drivers/input/keyboard/cros_ec_keyb.c | 13 +++++---- drivers/mfd/cros_ec.c | 15 +++++----- include/linux/mfd/cros_ec.h | 8 +++--- 4 files changed, 29 insertions(+), 58 deletions(-) (limited to 'include') diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c index 875c22ae5400..fa8dedd8c3a2 100644 --- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c @@ -182,72 +182,41 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[], const u16 bus_num = bus->remote_bus; int request_len; int response_len; - u8 *request = NULL; - u8 *response = NULL; int result; - struct cros_ec_command msg; + struct cros_ec_command msg = { }; request_len = ec_i2c_count_message(i2c_msgs, num); if (request_len < 0) { dev_warn(dev, "Error constructing message %d\n", request_len); - result = request_len; - goto exit; + return request_len; } + response_len = ec_i2c_count_response(i2c_msgs, num); if (response_len < 0) { /* Unexpected; no errors should come when NULL response */ dev_warn(dev, "Error preparing response %d\n", response_len); - result = response_len; - goto exit; - } - - if (request_len <= ARRAY_SIZE(bus->request_buf)) { - request = bus->request_buf; - } else { - request = kzalloc(request_len, GFP_KERNEL); - if (request == NULL) { - result = -ENOMEM; - goto exit; - } - } - if (response_len <= ARRAY_SIZE(bus->response_buf)) { - response = bus->response_buf; - } else { - response = kzalloc(response_len, GFP_KERNEL); - if (response == NULL) { - result = -ENOMEM; - goto exit; - } + return response_len; } - result = ec_i2c_construct_message(request, i2c_msgs, num, bus_num); + result = ec_i2c_construct_message(msg.outdata, i2c_msgs, num, bus_num); if (result) - goto exit; + return result; msg.version = 0; msg.command = EC_CMD_I2C_PASSTHRU; - msg.outdata = request; msg.outsize = request_len; - msg.indata = response; msg.insize = response_len; result = cros_ec_cmd_xfer(bus->ec, &msg); if (result < 0) - goto exit; + return result; - result = ec_i2c_parse_response(response, i2c_msgs, &num); + result = ec_i2c_parse_response(msg.indata, i2c_msgs, &num); if (result < 0) - goto exit; + return result; /* Indicate success by saying how many messages were sent */ - result = num; -exit: - if (request != bus->request_buf) - kfree(request); - if (response != bus->response_buf) - kfree(response); - - return result; + return num; } static u32 ec_i2c_functionality(struct i2c_adapter *adap) diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index ffa989f2c785..769f8f7f62b7 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -148,16 +148,19 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) { + int ret; struct cros_ec_command msg = { - .version = 0, .command = EC_CMD_MKBP_STATE, - .outdata = NULL, - .outsize = 0, - .indata = kb_state, .insize = ckdev->cols, }; - return cros_ec_cmd_xfer(ckdev->ec, &msg); + ret = cros_ec_cmd_xfer(ckdev->ec, &msg); + if (ret < 0) + return ret; + + memcpy(kb_state, msg.indata, ckdev->cols); + + return 0; } static irqreturn_t cros_ec_keyb_irq(int irq, void *data) diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index fc0c81ef04ff..c872e1b0eaf8 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -74,15 +74,11 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, ret = ec_dev->cmd_xfer(ec_dev, msg); if (msg->result == EC_RES_IN_PROGRESS) { int i; - struct cros_ec_command status_msg; - struct ec_response_get_comms_status status; + struct cros_ec_command status_msg = { }; + struct ec_response_get_comms_status *status; - status_msg.version = 0; status_msg.command = EC_CMD_GET_COMMS_STATUS; - status_msg.outdata = NULL; - status_msg.outsize = 0; - status_msg.indata = (uint8_t *)&status; - status_msg.insize = sizeof(status); + status_msg.insize = sizeof(*status); /* * Query the EC's status until it's no longer busy or @@ -98,7 +94,10 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, msg->result = status_msg.result; if (status_msg.result != EC_RES_SUCCESS) break; - if (!(status.flags & EC_COMMS_STATUS_PROCESSING)) + + status = (struct ec_response_get_comms_status *) + status_msg.indata; + if (!(status->flags & EC_COMMS_STATUS_PROCESSING)) break; } } diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h index 0e166b92f5b4..71675b14b5ca 100644 --- a/include/linux/mfd/cros_ec.h +++ b/include/linux/mfd/cros_ec.h @@ -38,20 +38,20 @@ enum { /* * @version: Command version number (often 0) * @command: Command to send (EC_CMD_...) - * @outdata: Outgoing data to EC * @outsize: Outgoing length in bytes - * @indata: Where to put the incoming data from EC * @insize: Max number of bytes to accept from EC * @result: EC's response to the command (separate from communication failure) + * @outdata: Outgoing data to EC + * @indata: Where to put the incoming data from EC */ struct cros_ec_command { uint32_t version; uint32_t command; - uint8_t *outdata; uint32_t outsize; - uint8_t *indata; uint32_t insize; uint32_t result; + uint8_t outdata[EC_PROTO2_MAX_PARAM_SIZE]; + uint8_t indata[EC_PROTO2_MAX_PARAM_SIZE]; }; /** -- cgit v1.2.3 From 05c11ac4e0712def44cccbff82ad980d9e1d1b80 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 2 Feb 2015 12:26:23 +0100 Subject: mfd: cros_ec: Add char dev and virtual dev pointers The ChromeOS Embedded Controller has to be accessed by applications. A virtual character device is used as an interface with user-space. Extend the struct cros_ec_device with the fields needed by the driver of this virtual character device. Signed-off-by: Javier Martinez Canillas Acked-by: Lee Jones Tested-by: Gwendal Grignou Reviewed-by: Gwendal Grignou Signed-off-by: Olof Johansson --- include/linux/mfd/cros_ec.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h index 71675b14b5ca..324a34683971 100644 --- a/include/linux/mfd/cros_ec.h +++ b/include/linux/mfd/cros_ec.h @@ -16,6 +16,7 @@ #ifndef __LINUX_MFD_CROS_EC_H #define __LINUX_MFD_CROS_EC_H +#include #include #include #include @@ -59,9 +60,17 @@ struct cros_ec_command { * * @ec_name: name of EC device (e.g. 'chromeos-ec') * @phys_name: name of physical comms layer (e.g. 'i2c-4') - * @dev: Device pointer + * @dev: Device pointer for physical comms device + * @vdev: Device pointer for virtual comms device + * @cdev: Character device structure for virtual comms device * @was_wake_device: true if this device was set to wake the system from * sleep at the last suspend + * @cmd_readmem: direct read of the EC memory-mapped region, if supported + * @offset is within EC_LPC_ADDR_MEMMAP region. + * @bytes: number of bytes to read. zero means "read a string" (including + * the trailing '\0'). At most only EC_MEMMAP_SIZE bytes can be read. + * Caller must ensure that the buffer is large enough for the result when + * reading a string. * * @priv: Private data * @irq: Interrupt to use @@ -90,8 +99,12 @@ struct cros_ec_device { const char *ec_name; const char *phys_name; struct device *dev; + struct device *vdev; + struct cdev cdev; bool was_wake_device; struct class *cros_class; + int (*cmd_readmem)(struct cros_ec_device *ec, unsigned int offset, + unsigned int bytes, void *dest); /* These are used to implement the platform-specific interface */ void *priv; -- cgit v1.2.3 From 6232c51cb370919b116e0aea38d12aa33aae2fa9 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Thu, 26 Feb 2015 17:42:07 +0100 Subject: ARM: shmobile: r8a7778: common clock framework CPG driver Driver for the r8a7778's clocks that depend on the mode bits. Signed-off-by: Ulrich Hecht Acked-by: Laurent Pinchart Acked-by: Michael Turquette Signed-off-by: Simon Horman --- .../bindings/clock/renesas,r8a7778-cpg-clocks.txt | 25 ++++ drivers/clk/shmobile/Makefile | 1 + drivers/clk/shmobile/clk-r8a7778.c | 143 +++++++++++++++++++++ include/linux/clk/shmobile.h | 1 + 4 files changed, 170 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/renesas,r8a7778-cpg-clocks.txt create mode 100644 drivers/clk/shmobile/clk-r8a7778.c (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/renesas,r8a7778-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,r8a7778-cpg-clocks.txt new file mode 100644 index 000000000000..2f3747fdcf1c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,r8a7778-cpg-clocks.txt @@ -0,0 +1,25 @@ +* Renesas R8A7778 Clock Pulse Generator (CPG) + +The CPG generates core clocks for the R8A7778. It includes two PLLs and +several fixed ratio dividers + +Required Properties: + + - compatible: Must be "renesas,r8a7778-cpg-clocks" + - reg: Base address and length of the memory resource used by the CPG + - #clock-cells: Must be 1 + - clock-output-names: The names of the clocks. Supported clocks are + "plla", "pllb", "b", "out", "p", "s", and "s1". + + +Example +------- + + cpg_clocks: cpg_clocks@ffc80000 { + compatible = "renesas,r8a7778-cpg-clocks"; + reg = <0xffc80000 0x80>; + #clock-cells = <1>; + clocks = <&extal_clk>; + clock-output-names = "plla", "pllb", "b", + "out", "p", "s", "s1"; + }; diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile index 0689d7fb2666..97c71c885e4f 100644 --- a/drivers/clk/shmobile/Makefile +++ b/drivers/clk/shmobile/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o +obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o diff --git a/drivers/clk/shmobile/clk-r8a7778.c b/drivers/clk/shmobile/clk-r8a7778.c new file mode 100644 index 000000000000..cb33b57274bf --- /dev/null +++ b/drivers/clk/shmobile/clk-r8a7778.c @@ -0,0 +1,143 @@ +/* + * r8a7778 Core CPG Clocks + * + * Copyright (C) 2014 Ulrich Hecht + * + * 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; version 2 of the License. + */ + +#include +#include +#include +#include + +struct r8a7778_cpg { + struct clk_onecell_data data; + spinlock_t lock; + void __iomem *reg; +}; + +/* PLL multipliers per bits 11, 12, and 18 of MODEMR */ +struct { + unsigned long plla_mult; + unsigned long pllb_mult; +} r8a7778_rates[] __initdata = { + [0] = { 21, 21 }, + [1] = { 24, 24 }, + [2] = { 28, 28 }, + [3] = { 32, 32 }, + [5] = { 24, 21 }, + [6] = { 28, 21 }, + [7] = { 32, 24 }, +}; + +/* Clock dividers per bits 1 and 2 of MODEMR */ +struct { + const char *name; + unsigned int div[4]; +} r8a7778_divs[6] __initdata = { + { "b", { 12, 12, 16, 18 } }, + { "out", { 12, 12, 16, 18 } }, + { "p", { 16, 12, 16, 12 } }, + { "s", { 4, 3, 4, 3 } }, + { "s1", { 8, 6, 8, 6 } }, +}; + +static u32 cpg_mode_rates __initdata; +static u32 cpg_mode_divs __initdata; + +static struct clk * __init +r8a7778_cpg_register_clock(struct device_node *np, struct r8a7778_cpg *cpg, + const char *name) +{ + if (!strcmp(name, "plla")) { + return clk_register_fixed_factor(NULL, "plla", + of_clk_get_parent_name(np, 0), 0, + r8a7778_rates[cpg_mode_rates].plla_mult, 1); + } else if (!strcmp(name, "pllb")) { + return clk_register_fixed_factor(NULL, "pllb", + of_clk_get_parent_name(np, 0), 0, + r8a7778_rates[cpg_mode_rates].pllb_mult, 1); + } else { + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(r8a7778_divs); i++) { + if (!strcmp(name, r8a7778_divs[i].name)) { + return clk_register_fixed_factor(NULL, + r8a7778_divs[i].name, + "plla", 0, 1, + r8a7778_divs[i].div[cpg_mode_divs]); + } + } + } + + return ERR_PTR(-EINVAL); +} + + +static void __init r8a7778_cpg_clocks_init(struct device_node *np) +{ + struct r8a7778_cpg *cpg; + struct clk **clks; + unsigned int i; + int num_clks; + + num_clks = of_property_count_strings(np, "clock-output-names"); + if (num_clks < 0) { + pr_err("%s: failed to count clocks\n", __func__); + return; + } + + cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); + clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL); + if (cpg == NULL || clks == NULL) { + /* We're leaking memory on purpose, there's no point in cleaning + * up as the system won't boot anyway. + */ + return; + } + + spin_lock_init(&cpg->lock); + + cpg->data.clks = clks; + cpg->data.clk_num = num_clks; + + cpg->reg = of_iomap(np, 0); + if (WARN_ON(cpg->reg == NULL)) + return; + + for (i = 0; i < num_clks; ++i) { + const char *name; + struct clk *clk; + + of_property_read_string_index(np, "clock-output-names", i, + &name); + + clk = r8a7778_cpg_register_clock(np, cpg, name); + if (IS_ERR(clk)) + pr_err("%s: failed to register %s %s clock (%ld)\n", + __func__, np->name, name, PTR_ERR(clk)); + else + cpg->data.clks[i] = clk; + } + + of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); +} + +CLK_OF_DECLARE(r8a7778_cpg_clks, "renesas,r8a7778-cpg-clocks", + r8a7778_cpg_clocks_init); + +void __init r8a7778_clocks_init(u32 mode) +{ + BUG_ON(!(mode & BIT(19))); + + cpg_mode_rates = (!!(mode & BIT(18)) << 2) | + (!!(mode & BIT(12)) << 1) | + (!!(mode & BIT(11))); + cpg_mode_divs = (!!(mode & BIT(2)) << 1) | + (!!(mode & BIT(1))); + + of_clk_init(NULL); +} diff --git a/include/linux/clk/shmobile.h b/include/linux/clk/shmobile.h index 9f8a14041dd5..63a8159c4e64 100644 --- a/include/linux/clk/shmobile.h +++ b/include/linux/clk/shmobile.h @@ -16,6 +16,7 @@ #include +void r8a7778_clocks_init(u32 mode); void r8a7779_clocks_init(u32 mode); void rcar_gen2_clocks_init(u32 mode); -- cgit v1.2.3 From b5ff6e1637b683d5996ae11ac29afe406c0bee90 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 27 Feb 2015 11:15:17 +0000 Subject: drm/i915/skl: Add new displayable tiling formats Starting with SKL display engine can scan out Y, and newly introduced Yf tiling formats so add the latter to the frame buffer modifier space. v2: Definitions moved to drm_fourcc.h. v3: Try to document the format better. Signed-off-by: Tvrtko Ursulin Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- include/uapi/drm/drm_fourcc.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'include') diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 4837c3d2319a..b35418b20dcf 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -195,4 +195,19 @@ */ #define I915_FORMAT_MOD_Y_TILED fourcc_mod_code(INTEL, 2) +/* + * Intel Yf-tiling layout + * + * This is a tiled layout using 4Kb tiles in row-major layout. + * Within the tile pixels are laid out in 16 256 byte units / sub-tiles which + * are arranged in four groups (two wide, two high) with column-major layout. + * Each group therefore consits out of four 256 byte units, which are also laid + * out as 2x2 column-major. + * 256 byte units are made out of four 64 byte blocks of pixels, producing + * either a square block or a 2:1 unit. + * 64 byte blocks of pixels contain four pixel rows of 16 bytes, where the width + * in pixel depends on the pixel depth. + */ +#define I915_FORMAT_MOD_Yf_TILED fourcc_mod_code(INTEL, 3) + #endif /* DRM_FOURCC_H */ -- cgit v1.2.3 From 9e39dc1e563e8d390bae42ee80e1e665c18b7de2 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Fri, 13 Feb 2015 03:46:07 -0500 Subject: Documentation: Add "@" in front of private structure members. Even "private" structure members need a leading "@" in their kernel-doc; otherwise, they will be treated as new section names in the resulting manual. Signed-off-by: Robert P. J. Day Acked-by: Randy Dunlap Acked-By: Sebastian Reichel Signed-off-by: Jonathan Corbet --- include/linux/hsi/hsi.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/hsi/hsi.h b/include/linux/hsi/hsi.h index 3ec06300d535..5dd60c2e120f 100644 --- a/include/linux/hsi/hsi.h +++ b/include/linux/hsi/hsi.h @@ -135,9 +135,9 @@ static inline int hsi_register_board_info(struct hsi_board_info const *info, * @device: Driver model representation of the device * @tx_cfg: HSI TX configuration * @rx_cfg: HSI RX configuration - * e_handler: Callback for handling port events (RX Wake High/Low) - * pclaimed: Keeps tracks if the clients claimed its associated HSI port - * nb: Notifier block for port events + * @e_handler: Callback for handling port events (RX Wake High/Low) + * @pclaimed: Keeps tracks if the clients claimed its associated HSI port + * @nb: Notifier block for port events */ struct hsi_client { struct device device; -- cgit v1.2.3 From bc63b6f634d91a0b2a7f3ba4f266e55fec369de3 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Fri, 27 Feb 2015 11:25:52 -0800 Subject: Drivers: hv: vmbus: rename channel work queues All channel work queues are named 'hv_vmbus_ctl', this makes them indistinguishable in ps output and makes it hard to link to the corresponding vmbus device. Rename them to hv_vmbus_ctl/N and make vmbus device names match, e.g. now vmbus_1 device is served by hv_vmbus_ctl/1 work queue. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 5 ++++- drivers/hv/vmbus_drv.c | 6 ++---- include/linux/hyperv.h | 3 +++ 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 3736f71bdec5..ba4b25f0b213 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -139,19 +139,22 @@ EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp); */ static struct vmbus_channel *alloc_channel(void) { + static atomic_t chan_num = ATOMIC_INIT(0); struct vmbus_channel *channel; channel = kzalloc(sizeof(*channel), GFP_ATOMIC); if (!channel) return NULL; + channel->id = atomic_inc_return(&chan_num); spin_lock_init(&channel->inbound_lock); spin_lock_init(&channel->lock); INIT_LIST_HEAD(&channel->sc_list); INIT_LIST_HEAD(&channel->percpu_list); - channel->controlwq = create_workqueue("hv_vmbus_ctl"); + channel->controlwq = alloc_workqueue("hv_vmbus_ctl/%d", WQ_MEM_RECLAIM, + 1, channel->id); if (!channel->controlwq) { kfree(channel); return NULL; diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 3b18a665ef4c..e334ccc70582 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -875,10 +875,8 @@ int vmbus_device_register(struct hv_device *child_device_obj) { int ret = 0; - static atomic_t device_num = ATOMIC_INIT(0); - - dev_set_name(&child_device_obj->device, "vmbus_0_%d", - atomic_inc_return(&device_num)); + dev_set_name(&child_device_obj->device, "vmbus_%d", + child_device_obj->channel->id); child_device_obj->device.bus = &hv_bus; child_device_obj->device.parent = &hv_acpi_dev->dev; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 5a2ba674795e..26a32b771ee5 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -646,6 +646,9 @@ struct hv_input_signal_event_buffer { }; struct vmbus_channel { + /* Unique channel id */ + int id; + struct list_head listentry; struct hv_device *device_obj; -- cgit v1.2.3 From 04653a009a63d6a91c60a5449ea97e3ed5e1dc29 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 27 Feb 2015 11:26:05 -0800 Subject: Drivers: hv: vmbus: Add support for the NetworkDirect GUID NetworkDirect is a service that supports guest RDMA. Define the GUID for this service. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 2 ++ include/linux/hyperv.h | 10 ++++++++++ 2 files changed, 12 insertions(+) (limited to 'include') diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 6be93f09f976..0ba6b5c303e6 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -413,6 +413,8 @@ static const struct hv_vmbus_device_id hp_devs[] = { { HV_SCSI_GUID, }, /* Network */ { HV_NIC_GUID, }, + /* NetworkDirect Guest RDMA */ + { HV_ND_GUID, }, }; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 26a32b771ee5..7d976ac01fac 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1109,6 +1109,16 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver); 0x9A, 0xE7, 0x6B, 0x17, 0x49, 0x77, 0xC1, 0x92 \ } +/* + * NetworkDirect. This is the guest RDMA service. + * {8c2eaf3d-32a7-4b09-ab99-bd1f1c86b501} + */ +#define HV_ND_GUID \ + .guid = { \ + 0x3d, 0xaf, 0x2e, 0x8c, 0xa7, 0x32, 0x09, 0x4b, \ + 0xab, 0x99, 0xbd, 0x1f, 0x1c, 0x86, 0xb5, 0x01 \ + } + /* * Common header for Hyper-V ICs */ -- cgit v1.2.3 From ed6cfcc5fdf2ebca320b6f74c836e555e18216e1 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Sat, 28 Feb 2015 11:18:17 -0800 Subject: Drivers: hv: vmbus: Introduce a function to remove a rescinded offer In response to a rescind message, we need to remove the channel and the corresponding device. Cleanup this code path by factoring out the code to remove a channel. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 9 +++++++++ drivers/hv/channel_mgmt.c | 49 +++++++++++++++++++++++++++++------------------ drivers/hv/vmbus_drv.c | 11 ++++++++++- include/linux/hyperv.h | 1 + 4 files changed, 50 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index bf0cf8f3bcaf..9b79aca7e565 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -501,6 +501,15 @@ static int vmbus_close_internal(struct vmbus_channel *channel) put_cpu(); } + /* + * If the channel has been rescinded; process device removal. + */ + if (channel->rescind) { + hv_process_channel_removal(channel, + channel->offermsg.child_relid); + return 0; + } + /* Send a closing message */ msg = &channel->close_msg.msg; diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 0ba6b5c303e6..b93389124ec4 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -207,33 +207,21 @@ static void percpu_channel_deq(void *arg) list_del(&channel->percpu_list); } -/* - * vmbus_process_rescind_offer - - * Rescind the offer by initiating a device removal - */ -static void vmbus_process_rescind_offer(struct work_struct *work) + +void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) { - struct vmbus_channel *channel = container_of(work, - struct vmbus_channel, - work); + struct vmbus_channel_relid_released msg; unsigned long flags; struct vmbus_channel *primary_channel; - struct vmbus_channel_relid_released msg; - struct device *dev; - - if (channel->device_obj) { - dev = get_device(&channel->device_obj->device); - if (dev) { - vmbus_device_unregister(channel->device_obj); - put_device(dev); - } - } memset(&msg, 0, sizeof(struct vmbus_channel_relid_released)); - msg.child_relid = channel->offermsg.child_relid; + msg.child_relid = relid; msg.header.msgtype = CHANNELMSG_RELID_RELEASED; vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released)); + if (channel == NULL) + return; + if (channel->target_cpu != get_cpu()) { put_cpu(); smp_call_function_single(channel->target_cpu, @@ -256,6 +244,29 @@ static void vmbus_process_rescind_offer(struct work_struct *work) free_channel(channel); } +/* + * vmbus_process_rescind_offer - + * Rescind the offer by initiating a device removal + */ +static void vmbus_process_rescind_offer(struct work_struct *work) +{ + struct vmbus_channel *channel = container_of(work, + struct vmbus_channel, + work); + struct device *dev; + + if (channel->device_obj) { + dev = get_device(&channel->device_obj->device); + if (dev) { + vmbus_device_unregister(channel->device_obj); + put_device(dev); + } + } else { + hv_process_channel_removal(channel, + channel->offermsg.child_relid); + } +} + void vmbus_free_channels(void) { struct vmbus_channel *channel; diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index a12666d075ea..2b7b51d264f1 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -510,14 +510,23 @@ static int vmbus_remove(struct device *child_device) { struct hv_driver *drv; struct hv_device *dev = device_to_hv_device(child_device); + u32 relid = dev->channel->offermsg.child_relid; if (child_device->driver) { drv = drv_to_hv_drv(child_device->driver); if (drv->remove) drv->remove(dev); - else + else { + hv_process_channel_removal(dev->channel, relid); pr_err("remove not set for driver %s\n", dev_name(child_device)); + } + } else { + /* + * We don't have a driver for this device; deal with the + * rescind message by removing the channel. + */ + hv_process_channel_removal(dev->channel, relid); } return 0; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 7d976ac01fac..dd92a854c700 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1226,6 +1226,7 @@ void hv_kvp_onchannelcallback(void *); int hv_vss_init(struct hv_util_service *); void hv_vss_deinit(void); void hv_vss_onchannelcallback(void *); +void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid); extern struct resource hyperv_mmio; -- cgit v1.2.3 From a13e8bbe851a96a0e78c2bd599bc34082fa697cd Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Sat, 28 Feb 2015 11:39:02 -0800 Subject: Drivers: hv: vmbus: Use a round-robin algorithm for picking the outgoing channel The current algorithm for picking an outgoing channel was not distributing the load well. Implement a simple round-robin scheme to ensure good distribution of the outgoing traffic. Signed-off-by: K. Y. Srinivasan Reviewed-by: Long Li Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 30 +++++++++++++++--------------- include/linux/hyperv.h | 3 +++ 2 files changed, 18 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index b1e5a5fdaf7f..611789139f9b 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -350,6 +350,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) } newchannel->state = CHANNEL_OPEN_STATE; + channel->num_sc++; if (channel->sc_creation_callback != NULL) /* * We need to invoke the sub-channel creation @@ -862,9 +863,8 @@ cleanup: /* * Retrieve the (sub) channel on which to send an outgoing request. - * When a primary channel has multiple sub-channels, we choose a - * channel whose VCPU binding is closest to the VCPU on which - * this call is being made. + * When a primary channel has multiple sub-channels, we try to + * distribute the load equally amongst all available channels. */ struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary) { @@ -872,11 +872,19 @@ struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary) int cur_cpu; struct vmbus_channel *cur_channel; struct vmbus_channel *outgoing_channel = primary; - int cpu_distance, new_cpu_distance; + int next_channel; + int i = 1; if (list_empty(&primary->sc_list)) return outgoing_channel; + next_channel = primary->next_oc++; + + if (next_channel > (primary->num_sc)) { + primary->next_oc = 0; + return outgoing_channel; + } + cur_cpu = hv_context.vp_index[get_cpu()]; put_cpu(); list_for_each_safe(cur, tmp, &primary->sc_list) { @@ -887,18 +895,10 @@ struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary) if (cur_channel->target_vp == cur_cpu) return cur_channel; - cpu_distance = ((outgoing_channel->target_vp > cur_cpu) ? - (outgoing_channel->target_vp - cur_cpu) : - (cur_cpu - outgoing_channel->target_vp)); - - new_cpu_distance = ((cur_channel->target_vp > cur_cpu) ? - (cur_channel->target_vp - cur_cpu) : - (cur_cpu - cur_channel->target_vp)); - - if (cpu_distance < new_cpu_distance) - continue; + if (i == next_channel) + return cur_channel; - outgoing_channel = cur_channel; + i++; } return outgoing_channel; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index dd92a854c700..1ca582457076 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -761,6 +761,9 @@ struct vmbus_channel { * link up channels based on their CPU affinity. */ struct list_head percpu_list; + + int num_sc; + int next_oc; }; static inline void set_channel_read_state(struct vmbus_channel *c, bool state) -- cgit v1.2.3 From 87e93d61708fe2c44875d1ecdb174aad070dbd08 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Sat, 28 Feb 2015 11:39:03 -0800 Subject: Drivers: hv: vmbus: Suport an API to send pagebuffers with additional control Implement an API for sending pagebuffers that gives more control to the client in terms of setting the vmbus flags as well as deciding when to notify the host. This will be useful for enabling batch processing. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 33 +++++++++++++++++++++++++++------ include/linux/hyperv.h | 9 +++++++++ 2 files changed, 36 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 9b79aca7e565..f060d1f7bc99 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -636,13 +636,18 @@ int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer, EXPORT_SYMBOL(vmbus_sendpacket); /* - * vmbus_sendpacket_pagebuffer - Send a range of single-page buffer - * packets using a GPADL Direct packet type. + * vmbus_sendpacket_pagebuffer_ctl - Send a range of single-page buffer + * packets using a GPADL Direct packet type. This interface allows you + * to control notifying the host. This will be useful for sending + * batched data. Also the sender can control the send flags + * explicitly. */ -int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, +int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel, struct hv_page_buffer pagebuffers[], u32 pagecount, void *buffer, u32 bufferlen, - u64 requestid) + u64 requestid, + u32 flags, + bool kick_q) { int ret; int i; @@ -670,7 +675,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, /* Setup the descriptor */ desc.type = VM_PKT_DATA_USING_GPA_DIRECT; - desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; + desc.flags = flags; desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */ desc.length8 = (u16)(packetlen_aligned >> 3); desc.transactionid = requestid; @@ -691,11 +696,27 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal); - if (ret == 0 && signal) + if ((ret == 0) && kick_q && signal) vmbus_setevent(channel); return ret; } + +/* + * vmbus_sendpacket_pagebuffer - Send a range of single-page buffer + * packets using a GPADL Direct packet type. + */ +int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, + struct hv_page_buffer pagebuffers[], + u32 pagecount, void *buffer, u32 bufferlen, + u64 requestid) +{ + u32 flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; + return vmbus_sendpacket_pagebuffer_ctl(channel, pagebuffers, pagecount, + buffer, bufferlen, requestid, + flags, true); + +} EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer); /* diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 1ca582457076..86e1a7a46af3 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -874,6 +874,15 @@ extern int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, u32 bufferlen, u64 requestid); +extern int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel, + struct hv_page_buffer pagebuffers[], + u32 pagecount, + void *buffer, + u32 bufferlen, + u64 requestid, + u32 flags, + bool kick_q); + extern int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel, struct hv_multipage_buffer *mpb, void *buffer, -- cgit v1.2.3 From e9395e3f8952110bda60b54ad03ec52c6e9c7dbd Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Sat, 28 Feb 2015 11:39:04 -0800 Subject: Drivers: hv: vmbus: Suport an API to send packet with additional control Implement an API that gives additional control on the what VMBUS flags will be set as well as if the host needs to be signalled. This API will be useful for clients that want to batch up requests to the host. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 43 ++++++++++++++++++++++++++----------------- include/linux/hyperv.h | 8 ++++++++ 2 files changed, 34 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index f060d1f7bc99..da53180f5eb4 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -584,23 +584,9 @@ void vmbus_close(struct vmbus_channel *channel) } EXPORT_SYMBOL_GPL(vmbus_close); -/** - * vmbus_sendpacket() - Send the specified buffer on the given channel - * @channel: Pointer to vmbus_channel structure. - * @buffer: Pointer to the buffer you want to receive the data into. - * @bufferlen: Maximum size of what the the buffer will hold - * @requestid: Identifier of the request - * @type: Type of packet that is being send e.g. negotiate, time - * packet etc. - * - * Sends data in @buffer directly to hyper-v via the vmbus - * This will send the data unparsed to hyper-v. - * - * Mainly used by Hyper-V drivers. - */ -int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer, +int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer, u32 bufferlen, u64 requestid, - enum vmbus_packet_type type, u32 flags) + enum vmbus_packet_type type, u32 flags, bool kick_q) { struct vmpacket_descriptor desc; u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen; @@ -628,11 +614,34 @@ int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer, ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal); - if (ret == 0 && signal) + if ((ret == 0) && kick_q && signal) vmbus_setevent(channel); return ret; } +EXPORT_SYMBOL(vmbus_sendpacket_ctl); + +/** + * vmbus_sendpacket() - Send the specified buffer on the given channel + * @channel: Pointer to vmbus_channel structure. + * @buffer: Pointer to the buffer you want to receive the data into. + * @bufferlen: Maximum size of what the the buffer will hold + * @requestid: Identifier of the request + * @type: Type of packet that is being send e.g. negotiate, time + * packet etc. + * + * Sends data in @buffer directly to hyper-v via the vmbus + * This will send the data unparsed to hyper-v. + * + * Mainly used by Hyper-V drivers. + */ +int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer, + u32 bufferlen, u64 requestid, + enum vmbus_packet_type type, u32 flags) +{ + return vmbus_sendpacket_ctl(channel, buffer, bufferlen, requestid, + type, flags, true); +} EXPORT_SYMBOL(vmbus_sendpacket); /* diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 86e1a7a46af3..80e444bfc9dc 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -867,6 +867,14 @@ extern int vmbus_sendpacket(struct vmbus_channel *channel, enum vmbus_packet_type type, u32 flags); +extern int vmbus_sendpacket_ctl(struct vmbus_channel *channel, + void *buffer, + u32 bufferLen, + u64 requestid, + enum vmbus_packet_type type, + u32 flags, + bool kick_q); + extern int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, struct hv_page_buffer pagebuffers[], u32 pagecount, -- cgit v1.2.3 From 5f80e19081e233698c8ea77ed2dd84a66f49fc54 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Thu, 12 Feb 2015 14:01:25 +0800 Subject: ARM: imx6q: Add GPR3 MIPI muxing control register field shift bits definition This patch adds a macro to define the GPR3 MIPI muxing control register field shift bits. Signed-off-by: Liu Ying Signed-off-by: Shawn Guo --- include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h index c877cad61a13..d16f4c82c568 100644 --- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h +++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h @@ -207,6 +207,7 @@ #define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI1 (0x1 << 6) #define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI0 (0x2 << 6) #define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI1 (0x3 << 6) +#define IMX6Q_GPR3_MIPI_MUX_CTL_SHIFT 4 #define IMX6Q_GPR3_MIPI_MUX_CTL_MASK (0x3 << 4) #define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI0 (0x0 << 4) #define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI1 (0x1 << 4) -- cgit v1.2.3 From 8f21d8d42802a68daef5a34daca8b61df96ff8c6 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Thu, 12 Feb 2015 14:01:26 +0800 Subject: ARM: imx6q: clk: Add the video_27m clock This patch supports the video_27m clock which is a fixed factor clock of the pll3_pfd1_540m clock. Signed-off-by: Liu Ying Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-imx6q.c | 1 + include/dt-bindings/clock/imx6qdl-clock.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index d04a430607b8..8335bfc14a58 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -246,6 +246,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); clk[IMX6QDL_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2); clk[IMX6QDL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8); + clk[IMX6QDL_CLK_VIDEO_27M] = imx_clk_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20); if (cpu_is_imx6dl()) { clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1); clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1); diff --git a/include/dt-bindings/clock/imx6qdl-clock.h b/include/dt-bindings/clock/imx6qdl-clock.h index b690cdba163b..25625bf3927b 100644 --- a/include/dt-bindings/clock/imx6qdl-clock.h +++ b/include/dt-bindings/clock/imx6qdl-clock.h @@ -248,6 +248,7 @@ #define IMX6QDL_PLL6_BYPASS 235 #define IMX6QDL_PLL7_BYPASS 236 #define IMX6QDL_CLK_GPT_3M 237 -#define IMX6QDL_CLK_END 238 +#define IMX6QDL_CLK_VIDEO_27M 238 +#define IMX6QDL_CLK_END 239 #endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */ -- cgit v1.2.3 From 5ccc248cc53708337a2bfe4ea380c20948e8bbed Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Thu, 12 Feb 2015 14:01:29 +0800 Subject: ARM: imx6q: clk: Add support for mipi_core_cfg clock as a shared clock gate The CG8 field of the CCM CCGR3 register is named as 'mipi_core_cfg' clock, according to the i.MX6q/sdl reference manuals. This clock is actually the gate for several clocks, including the hsi_tx_sel clock's output and the video_27m clock's output. The MIPI DSI host controller embedded in the i.MX6q/sdl SoCs uses the video_27m clock to generate PLL reference clock and MIPI core configuration clock. In order to gate/ungate the two MIPI DSI host controller relevant clocks, this patch adds the mipi_core_cfg clock as a shared clock gate. Suggested-by: Philipp Zabel Signed-off-by: Liu Ying Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-imx6q.c | 1 + include/dt-bindings/clock/imx6qdl-clock.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index 6843ea9707c1..e59e2c6943fd 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -418,6 +418,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_LDB_DI1] = imx_clk_gate2("ldb_di1", "ldb_di1_podf", base + 0x74, 14); clk[IMX6QDL_CLK_IPU2_DI1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", base + 0x74, 10); clk[IMX6QDL_CLK_HSI_TX] = imx_clk_gate2_shared("hsi_tx", "hsi_tx_podf", base + 0x74, 16, &share_count_mipi_core_cfg); + clk[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg); if (cpu_is_imx6dl()) /* * The multiplexer and divider of the imx6q clock gpu2d get diff --git a/include/dt-bindings/clock/imx6qdl-clock.h b/include/dt-bindings/clock/imx6qdl-clock.h index 25625bf3927b..dbc828c23a17 100644 --- a/include/dt-bindings/clock/imx6qdl-clock.h +++ b/include/dt-bindings/clock/imx6qdl-clock.h @@ -249,6 +249,7 @@ #define IMX6QDL_PLL7_BYPASS 236 #define IMX6QDL_CLK_GPT_3M 237 #define IMX6QDL_CLK_VIDEO_27M 238 -#define IMX6QDL_CLK_END 239 +#define IMX6QDL_CLK_MIPI_CORE_CFG 239 +#define IMX6QDL_CLK_END 240 #endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */ -- cgit v1.2.3 From e654df7a1a4843429b5d1d6ee40cac9ecef75304 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Thu, 12 Feb 2015 14:01:30 +0800 Subject: ARM: imx6q: clk: Add support for mipi_ipg clock as a shared clock gate The CG8 field of the CCM CCGR3 register is the 'mipi_core_cfg' gate clock, according to the i.MX6q/sdl reference manuals. This clock is actually the gate for several clocks, including the ipg clock's output. The MIPI DSI host controller embedded in the i.MX6q/sdl SoCs takes the ipg clock as the pclk - the APB clock signal . In order to gate/ungate the ipg clock, this patch adds a new shared clock gate named as "mipi_ipg". Signed-off-by: Liu Ying Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-imx6q.c | 1 + include/dt-bindings/clock/imx6qdl-clock.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index e59e2c6943fd..469a150bf98f 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -419,6 +419,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_IPU2_DI1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", base + 0x74, 10); clk[IMX6QDL_CLK_HSI_TX] = imx_clk_gate2_shared("hsi_tx", "hsi_tx_podf", base + 0x74, 16, &share_count_mipi_core_cfg); clk[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg); + clk[IMX6QDL_CLK_MIPI_IPG] = imx_clk_gate2_shared("mipi_ipg", "ipg", base + 0x74, 16, &share_count_mipi_core_cfg); if (cpu_is_imx6dl()) /* * The multiplexer and divider of the imx6q clock gpu2d get diff --git a/include/dt-bindings/clock/imx6qdl-clock.h b/include/dt-bindings/clock/imx6qdl-clock.h index dbc828c23a17..8780868458a0 100644 --- a/include/dt-bindings/clock/imx6qdl-clock.h +++ b/include/dt-bindings/clock/imx6qdl-clock.h @@ -250,6 +250,7 @@ #define IMX6QDL_CLK_GPT_3M 237 #define IMX6QDL_CLK_VIDEO_27M 238 #define IMX6QDL_CLK_MIPI_CORE_CFG 239 -#define IMX6QDL_CLK_END 240 +#define IMX6QDL_CLK_MIPI_IPG 240 +#define IMX6QDL_CLK_END 241 #endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */ -- cgit v1.2.3 From 559addc25b00ff3a40eff03a0b3873c2b6d726f8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 4 Feb 2015 06:07:30 -0300 Subject: [media] fixp-arith: replace sin/cos table by a better precision one The cos table used at fixp-arith.h has only 8 bits of precision. That causes problems if it is reused on other drivers. As some media drivers require a higher precision sin/cos implementation, replace the current implementation by one that will provide 32 bits precision. The values generated by the new implementation matches the 32 bit precision of glibc's sin for an angle measured in integer degrees. It also provides support for fractional angles via linear interpolation. On experimental calculus, when used a table with a 0.001 degree angle, the maximum error for sin is 0.000038, which is likely good enough for practical purposes. There are some logic there that seems to be specific to the usage inside ff-memless.c. Move those logic to there, as they're not needed elsewhere. Cc: Hans de Goede Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Prashant Laddha Signed-off-by: Hans Verkuil Acked-by: Dmitry Torokhov Signed-off-by: Mauro Carvalho Chehab --- drivers/input/ff-memless.c | 18 ++++- drivers/media/usb/gspca/ov534.c | 11 +-- include/linux/fixp-arith.h | 145 +++++++++++++++++++++++++++++----------- 3 files changed, 125 insertions(+), 49 deletions(-) (limited to 'include') diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c index 74c0d8c6002a..fcc6c3368182 100644 --- a/drivers/input/ff-memless.c +++ b/drivers/input/ff-memless.c @@ -237,6 +237,18 @@ static u16 ml_calculate_direction(u16 direction, u16 force, (force + new_force)) << 1; } +#define FRAC_N 8 +static inline s16 fixp_new16(s16 a) +{ + return ((s32)a) >> (16 - FRAC_N); +} + +static inline s16 fixp_mult(s16 a, s16 b) +{ + a = ((s32)a * 0x100) / 0x7fff; + return ((s32)(a * b)) >> FRAC_N; +} + /* * Combine two effects and apply gain. */ @@ -247,7 +259,7 @@ static void ml_combine_effects(struct ff_effect *effect, struct ff_effect *new = state->effect; unsigned int strong, weak, i; int x, y; - fixp_t level; + s16 level; switch (new->type) { case FF_CONSTANT: @@ -255,8 +267,8 @@ static void ml_combine_effects(struct ff_effect *effect, level = fixp_new16(apply_envelope(state, new->u.constant.level, &new->u.constant.envelope)); - x = fixp_mult(fixp_sin(i), level) * gain / 0xffff; - y = fixp_mult(-fixp_cos(i), level) * gain / 0xffff; + x = fixp_mult(fixp_sin16(i), level) * gain / 0xffff; + y = fixp_mult(-fixp_cos16(i), level) * gain / 0xffff; /* * here we abuse ff_ramp to hold x and y of constant force * If in future any driver wants something else than x and y diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index a9c866d6d82d..146071b8e116 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -816,21 +816,16 @@ static void sethue(struct gspca_dev *gspca_dev, s32 val) s16 huesin; s16 huecos; - /* fixp_sin and fixp_cos accept only positive values, while - * our val is between -90 and 90 - */ - val += 360; - /* According to the datasheet the registers expect HUESIN and * HUECOS to be the result of the trigonometric functions, * scaled by 0x80. * - * The 0x100 here represents the maximun absolute value + * The 0x7fff here represents the maximum absolute value * returned byt fixp_sin and fixp_cos, so the scaling will * consider the result like in the interval [-1.0, 1.0]. */ - huesin = fixp_sin(val) * 0x80 / 0x100; - huecos = fixp_cos(val) * 0x80 / 0x100; + huesin = fixp_sin16(val) * 0x80 / 0x7fff; + huecos = fixp_cos16(val) * 0x80 / 0x7fff; if (huesin < 0) { sccb_reg_write(gspca_dev, 0xab, diff --git a/include/linux/fixp-arith.h b/include/linux/fixp-arith.h index 3089d7382325..d4686fe1cac7 100644 --- a/include/linux/fixp-arith.h +++ b/include/linux/fixp-arith.h @@ -1,6 +1,8 @@ #ifndef _FIXP_ARITH_H #define _FIXP_ARITH_H +#include + /* * Simplistic fixed-point arithmetics. * Hmm, I'm probably duplicating some code :( @@ -29,59 +31,126 @@ #include -/* The type representing fixed-point values */ -typedef s16 fixp_t; +static const s32 sin_table[] = { + 0x00000000, 0x023be165, 0x04779632, 0x06b2f1d2, 0x08edc7b6, 0x0b27eb5c, + 0x0d61304d, 0x0f996a26, 0x11d06c96, 0x14060b67, 0x163a1a7d, 0x186c6ddd, + 0x1a9cd9ac, 0x1ccb3236, 0x1ef74bf2, 0x2120fb82, 0x234815ba, 0x256c6f9e, + 0x278dde6e, 0x29ac379f, 0x2bc750e8, 0x2ddf003f, 0x2ff31bdd, 0x32037a44, + 0x340ff241, 0x36185aee, 0x381c8bb5, 0x3a1c5c56, 0x3c17a4e7, 0x3e0e3ddb, + 0x3fffffff, 0x41ecc483, 0x43d464fa, 0x45b6bb5d, 0x4793a20f, 0x496af3e1, + 0x4b3c8c11, 0x4d084650, 0x4ecdfec6, 0x508d9210, 0x5246dd48, 0x53f9be04, + 0x55a6125a, 0x574bb8e5, 0x58ea90c2, 0x5a827999, 0x5c135399, 0x5d9cff82, + 0x5f1f5ea0, 0x609a52d1, 0x620dbe8a, 0x637984d3, 0x64dd894f, 0x6639b039, + 0x678dde6d, 0x68d9f963, 0x6a1de735, 0x6b598ea1, 0x6c8cd70a, 0x6db7a879, + 0x6ed9eba0, 0x6ff389de, 0x71046d3c, 0x720c8074, 0x730baeec, 0x7401e4bf, + 0x74ef0ebb, 0x75d31a5f, 0x76adf5e5, 0x777f903b, 0x7847d908, 0x7906c0af, + 0x79bc384c, 0x7a6831b8, 0x7b0a9f8c, 0x7ba3751c, 0x7c32a67c, 0x7cb82884, + 0x7d33f0c8, 0x7da5f5a3, 0x7e0e2e31, 0x7e6c924f, 0x7ec11aa3, 0x7f0bc095, + 0x7f4c7e52, 0x7f834ecf, 0x7fb02dc4, 0x7fd317b3, 0x7fec09e1, 0x7ffb025e, + 0x7fffffff +}; -#define FRAC_N 8 -#define FRAC_MASK ((1< 180) { + negative = true; + degrees -= 180; + } + if (degrees > 90) + degrees = 180 - degrees; + ret = sin_table[degrees]; -/* a: 123 -> 123.0 */ -static inline fixp_t fixp_new(s16 a) -{ - return a< -1.0 - 0x8000 -> 1.0 - 0x0000 -> 0.0 -*/ -static inline fixp_t fixp_new16(s16 a) +/** + * fixp_sin32() returns the sin of an angle in degrees + * + * @degrees: angle, in degrees. The angle can be positive or negative + * + * The returned value ranges from -0x7fffffff to +0x7fffffff. + */ +static inline s32 fixp_sin32(int degrees) { - return ((s32)a)>>(16-FRAC_N); + degrees = (degrees % 360 + 360) % 360; + + return __fixp_sin32(degrees); } -static inline fixp_t fixp_cos(unsigned int degrees) +/* cos(x) = sin(x + 90 degrees) */ +#define fixp_cos32(v) fixp_sin32((v) + 90) + +/* + * 16 bits variants + * + * The returned value ranges from -0x7fff to 0x7fff + */ + +#define fixp_sin16(v) (fixp_sin32(v) >> 16) +#define fixp_cos16(v) (fixp_cos32(v) >> 16) + +/** + * fixp_sin32_rad() - calculates the sin of an angle in radians + * + * @radians: angle, in radians + * @twopi: value to be used for 2*pi + * + * Provides a variant for the cases where just 360 + * values is not enough. This function uses linear + * interpolation to a wider range of values given by + * twopi var. + * + * Experimental tests gave a maximum difference of + * 0.000038 between the value calculated by sin() and + * the one produced by this function, when twopi is + * equal to 360000. That seems to be enough precision + * for practical purposes. + * + * Please notice that two high numbers for twopi could cause + * overflows, so the routine will not allow values of twopi + * bigger than 1^18. + */ +static inline s32 fixp_sin32_rad(u32 radians, u32 twopi) { - int quadrant = (degrees / 90) & 3; - unsigned int i = degrees % 90; + int degrees; + s32 v1, v2, dx, dy; + s64 tmp; - if (quadrant == 1 || quadrant == 3) - i = 90 - i; + /* + * Avoid too large values for twopi, as we don't want overflows. + */ + BUG_ON(twopi > 1 << 18); - i >>= 1; + degrees = (radians * 360) / twopi; + tmp = radians - (degrees * twopi) / 360; - return (quadrant == 1 || quadrant == 2)? -cos_table[i] : cos_table[i]; -} + degrees = (degrees % 360 + 360) % 360; + v1 = __fixp_sin32(degrees); -static inline fixp_t fixp_sin(unsigned int degrees) -{ - return -fixp_cos(degrees + 90); -} + v2 = fixp_sin32(degrees + 1); -static inline fixp_t fixp_mult(fixp_t a, fixp_t b) -{ - return ((s32)(a*b))>>FRAC_N; + dx = twopi / 360; + dy = v2 - v1; + + tmp *= dy; + + return v1 + div_s64(tmp, dx); } +/* cos(x) = sin(x + pi/2 radians) */ + +#define fixp_cos32_rad(rad, twopi) \ + fixp_sin32_rad(rad + twopi / 4, twopi) + #endif -- cgit v1.2.3 From b44b2e06ae463327334235bf160e804632b9b37c Mon Sep 17 00:00:00 2001 From: Pablo Anton Date: Tue, 3 Feb 2015 14:13:18 -0300 Subject: [media] media: i2c: ADV7604: Rename adv7604 prefixes It is confusing which parts of the driver are adv7604 specific, adv7611 specific or common for both. This patch renames any adv7604 prefixes (both for functions and defines) to adv76xx whenever they are common. Signed-off-by: Pablo Anton Signed-off-by: Jean-Michel Hautbois [hans.verkuil@cisco.com: rebased and renamed ADV76xx_fsc to ADV76XX_FSC] [hans.verkuil@cisco.com: kept the existing adv7604 driver name] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 898 ++++++++++++++++++++++---------------------- include/media/adv7604.h | 83 ++-- 2 files changed, 491 insertions(+), 490 deletions(-) (limited to 'include') diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 8d455b766cc2..2def57f4e1e2 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -53,41 +53,41 @@ MODULE_AUTHOR("Mats Randgaard "); MODULE_LICENSE("GPL"); /* ADV7604 system clock frequency */ -#define ADV7604_fsc (28636360) +#define ADV76XX_FSC (28636360) -#define ADV7604_RGB_OUT (1 << 1) +#define ADV76XX_RGB_OUT (1 << 1) -#define ADV7604_OP_FORMAT_SEL_8BIT (0 << 0) +#define ADV76XX_OP_FORMAT_SEL_8BIT (0 << 0) #define ADV7604_OP_FORMAT_SEL_10BIT (1 << 0) -#define ADV7604_OP_FORMAT_SEL_12BIT (2 << 0) +#define ADV76XX_OP_FORMAT_SEL_12BIT (2 << 0) -#define ADV7604_OP_MODE_SEL_SDR_422 (0 << 5) +#define ADV76XX_OP_MODE_SEL_SDR_422 (0 << 5) #define ADV7604_OP_MODE_SEL_DDR_422 (1 << 5) -#define ADV7604_OP_MODE_SEL_SDR_444 (2 << 5) +#define ADV76XX_OP_MODE_SEL_SDR_444 (2 << 5) #define ADV7604_OP_MODE_SEL_DDR_444 (3 << 5) -#define ADV7604_OP_MODE_SEL_SDR_422_2X (4 << 5) +#define ADV76XX_OP_MODE_SEL_SDR_422_2X (4 << 5) #define ADV7604_OP_MODE_SEL_ADI_CM (5 << 5) -#define ADV7604_OP_CH_SEL_GBR (0 << 5) -#define ADV7604_OP_CH_SEL_GRB (1 << 5) -#define ADV7604_OP_CH_SEL_BGR (2 << 5) -#define ADV7604_OP_CH_SEL_RGB (3 << 5) -#define ADV7604_OP_CH_SEL_BRG (4 << 5) -#define ADV7604_OP_CH_SEL_RBG (5 << 5) +#define ADV76XX_OP_CH_SEL_GBR (0 << 5) +#define ADV76XX_OP_CH_SEL_GRB (1 << 5) +#define ADV76XX_OP_CH_SEL_BGR (2 << 5) +#define ADV76XX_OP_CH_SEL_RGB (3 << 5) +#define ADV76XX_OP_CH_SEL_BRG (4 << 5) +#define ADV76XX_OP_CH_SEL_RBG (5 << 5) -#define ADV7604_OP_SWAP_CB_CR (1 << 0) +#define ADV76XX_OP_SWAP_CB_CR (1 << 0) -enum adv7604_type { +enum adv76xx_type { ADV7604, ADV7611, }; -struct adv7604_reg_seq { +struct adv76xx_reg_seq { unsigned int reg; u8 val; }; -struct adv7604_format_info { +struct adv76xx_format_info { u32 code; u8 op_ch_sel; bool rgb_out; @@ -95,8 +95,8 @@ struct adv7604_format_info { u8 op_format_sel; }; -struct adv7604_chip_info { - enum adv7604_type type; +struct adv76xx_chip_info { + enum adv76xx_type type; bool has_afe; unsigned int max_port; @@ -111,7 +111,7 @@ struct adv7604_chip_info { unsigned int fmt_change_digital_mask; unsigned int cp_csc; - const struct adv7604_format_info *formats; + const struct adv76xx_format_info *formats; unsigned int nformats; void (*set_termination)(struct v4l2_subdev *sd, bool enable); @@ -120,7 +120,7 @@ struct adv7604_chip_info { unsigned int (*read_cable_det)(struct v4l2_subdev *sd); /* 0 = AFE, 1 = HDMI */ - const struct adv7604_reg_seq *recommended_settings[2]; + const struct adv76xx_reg_seq *recommended_settings[2]; unsigned int num_recommended_settings[2]; unsigned long page_mask; @@ -134,22 +134,22 @@ struct adv7604_chip_info { ********************************************************************** */ -struct adv7604_state { - const struct adv7604_chip_info *info; - struct adv7604_platform_data pdata; +struct adv76xx_state { + const struct adv76xx_chip_info *info; + struct adv76xx_platform_data pdata; struct gpio_desc *hpd_gpio[4]; struct v4l2_subdev sd; - struct media_pad pads[ADV7604_PAD_MAX]; + struct media_pad pads[ADV76XX_PAD_MAX]; unsigned int source_pad; struct v4l2_ctrl_handler hdl; - enum adv7604_pad selected_input; + enum adv76xx_pad selected_input; struct v4l2_dv_timings timings; - const struct adv7604_format_info *format; + const struct adv76xx_format_info *format; struct { u8 edid[256]; @@ -164,7 +164,7 @@ struct adv7604_state { bool restart_stdi_once; /* i2c clients */ - struct i2c_client *i2c_clients[ADV7604_PAGE_MAX]; + struct i2c_client *i2c_clients[ADV76XX_PAGE_MAX]; /* controls */ struct v4l2_ctrl *detect_tx_5v_ctrl; @@ -174,13 +174,13 @@ struct adv7604_state { struct v4l2_ctrl *rgb_quantization_range_ctrl; }; -static bool adv7604_has_afe(struct adv7604_state *state) +static bool adv76xx_has_afe(struct adv76xx_state *state) { return state->info->has_afe; } /* Supported CEA and DMT timings */ -static const struct v4l2_dv_timings adv7604_timings[] = { +static const struct v4l2_dv_timings adv76xx_timings[] = { V4L2_DV_BT_CEA_720X480P59_94, V4L2_DV_BT_CEA_720X576P50, V4L2_DV_BT_CEA_1280X720P24, @@ -244,14 +244,14 @@ static const struct v4l2_dv_timings adv7604_timings[] = { { }, }; -struct adv7604_video_standards { +struct adv76xx_video_standards { struct v4l2_dv_timings timings; u8 vid_std; u8 v_freq; }; /* sorted by number of lines */ -static const struct adv7604_video_standards adv7604_prim_mode_comp[] = { +static const struct adv76xx_video_standards adv7604_prim_mode_comp[] = { /* { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, TODO flickering */ { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, { V4L2_DV_BT_CEA_1280X720P50, 0x19, 0x01 }, @@ -266,7 +266,7 @@ static const struct adv7604_video_standards adv7604_prim_mode_comp[] = { }; /* sorted by number of lines */ -static const struct adv7604_video_standards adv7604_prim_mode_gr[] = { +static const struct adv76xx_video_standards adv7604_prim_mode_gr[] = { { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, @@ -294,7 +294,7 @@ static const struct adv7604_video_standards adv7604_prim_mode_gr[] = { }; /* sorted by number of lines */ -static const struct adv7604_video_standards adv7604_prim_mode_hdmi_comp[] = { +static const struct adv76xx_video_standards adv76xx_prim_mode_hdmi_comp[] = { { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, { V4L2_DV_BT_CEA_1280X720P50, 0x13, 0x01 }, @@ -308,7 +308,7 @@ static const struct adv7604_video_standards adv7604_prim_mode_hdmi_comp[] = { }; /* sorted by number of lines */ -static const struct adv7604_video_standards adv7604_prim_mode_hdmi_gr[] = { +static const struct adv76xx_video_standards adv76xx_prim_mode_hdmi_gr[] = { { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, @@ -329,9 +329,9 @@ static const struct adv7604_video_standards adv7604_prim_mode_hdmi_gr[] = { /* ----------------------------------------------------------------------- */ -static inline struct adv7604_state *to_state(struct v4l2_subdev *sd) +static inline struct adv76xx_state *to_state(struct v4l2_subdev *sd) { - return container_of(sd, struct adv7604_state, sd); + return container_of(sd, struct adv76xx_state, sd); } static inline unsigned htotal(const struct v4l2_bt_timings *t) @@ -361,15 +361,15 @@ static s32 adv_smbus_read_byte_data_check(struct i2c_client *client, return -EIO; } -static s32 adv_smbus_read_byte_data(struct adv7604_state *state, - enum adv7604_page page, u8 command) +static s32 adv_smbus_read_byte_data(struct adv76xx_state *state, + enum adv76xx_page page, u8 command) { return adv_smbus_read_byte_data_check(state->i2c_clients[page], command, true); } -static s32 adv_smbus_write_byte_data(struct adv7604_state *state, - enum adv7604_page page, u8 command, +static s32 adv_smbus_write_byte_data(struct adv76xx_state *state, + enum adv76xx_page page, u8 command, u8 value) { struct i2c_client *client = state->i2c_clients[page]; @@ -392,8 +392,8 @@ static s32 adv_smbus_write_byte_data(struct adv7604_state *state, return err; } -static s32 adv_smbus_write_i2c_block_data(struct adv7604_state *state, - enum adv7604_page page, u8 command, +static s32 adv_smbus_write_i2c_block_data(struct adv76xx_state *state, + enum adv76xx_page page, u8 command, unsigned length, const u8 *values) { struct i2c_client *client = state->i2c_clients[page]; @@ -412,16 +412,16 @@ static s32 adv_smbus_write_i2c_block_data(struct adv7604_state *state, static inline int io_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_IO, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_IO, reg); } static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_IO, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_IO, reg, val); } static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -431,73 +431,73 @@ static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 v static inline int avlink_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); return adv_smbus_read_byte_data(state, ADV7604_PAGE_AVLINK, reg); } static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); return adv_smbus_write_byte_data(state, ADV7604_PAGE_AVLINK, reg, val); } static inline int cec_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_CEC, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CEC, reg); } static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_CEC, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CEC, reg, val); } static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_INFOFRAME, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_INFOFRAME, reg); } static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_INFOFRAME, + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_INFOFRAME, reg, val); } static inline int afe_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_AFE, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_AFE, reg); } static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_AFE, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_AFE, reg, val); } static inline int rep_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_REP, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_REP, reg); } static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_REP, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_REP, reg, val); } static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -507,34 +507,34 @@ static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 static inline int edid_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_EDID, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_EDID, reg); } static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_EDID, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_EDID, reg, val); } static inline int edid_write_block(struct v4l2_subdev *sd, unsigned len, const u8 *val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); int err = 0; int i; v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) - err = adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_EDID, + err = adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_EDID, i, I2C_SMBUS_BLOCK_MAX, val + i); return err; } -static void adv7604_set_hpd(struct adv7604_state *state, unsigned int hpd) +static void adv76xx_set_hpd(struct adv76xx_state *state, unsigned int hpd) { unsigned int i; @@ -545,26 +545,26 @@ static void adv7604_set_hpd(struct adv7604_state *state, unsigned int hpd) gpiod_set_value_cansleep(state->hpd_gpio[i], hpd & BIT(i)); } - v4l2_subdev_notify(&state->sd, ADV7604_HOTPLUG, &hpd); + v4l2_subdev_notify(&state->sd, ADV76XX_HOTPLUG, &hpd); } -static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) +static void adv76xx_delayed_work_enable_hotplug(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); - struct adv7604_state *state = container_of(dwork, struct adv7604_state, + struct adv76xx_state *state = container_of(dwork, struct adv76xx_state, delayed_work_enable_hotplug); struct v4l2_subdev *sd = &state->sd; v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__); - adv7604_set_hpd(state, state->edid.present); + adv76xx_set_hpd(state, state->edid.present); } static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_HDMI, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_HDMI, reg); } static u16 hdmi_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) @@ -574,9 +574,9 @@ static u16 hdmi_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_HDMI, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_HDMI, reg, val); } static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -586,16 +586,16 @@ static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_TEST, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_TEST, reg, val); } static inline int cp_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_CP, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CP, reg); } static u16 cp_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) @@ -605,9 +605,9 @@ static u16 cp_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_CP, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CP, reg, val); } static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -617,25 +617,25 @@ static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 v static inline int vdp_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); return adv_smbus_read_byte_data(state, ADV7604_PAGE_VDP, reg); } static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); return adv_smbus_write_byte_data(state, ADV7604_PAGE_VDP, reg, val); } -#define ADV7604_REG(page, offset) (((page) << 8) | (offset)) -#define ADV7604_REG_SEQ_TERM 0xffff +#define ADV76XX_REG(page, offset) (((page) << 8) | (offset)) +#define ADV76XX_REG_SEQ_TERM 0xffff #ifdef CONFIG_VIDEO_ADV_DEBUG -static int adv7604_read_reg(struct v4l2_subdev *sd, unsigned int reg) +static int adv76xx_read_reg(struct v4l2_subdev *sd, unsigned int reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); unsigned int page = reg >> 8; if (!(BIT(page) & state->info->page_mask)) @@ -647,9 +647,9 @@ static int adv7604_read_reg(struct v4l2_subdev *sd, unsigned int reg) } #endif -static int adv7604_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val) +static int adv76xx_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); unsigned int page = reg >> 8; if (!(BIT(page) & state->info->page_mask)) @@ -660,91 +660,91 @@ static int adv7604_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val) return adv_smbus_write_byte_data(state, page, reg, val); } -static void adv7604_write_reg_seq(struct v4l2_subdev *sd, - const struct adv7604_reg_seq *reg_seq) +static void adv76xx_write_reg_seq(struct v4l2_subdev *sd, + const struct adv76xx_reg_seq *reg_seq) { unsigned int i; - for (i = 0; reg_seq[i].reg != ADV7604_REG_SEQ_TERM; i++) - adv7604_write_reg(sd, reg_seq[i].reg, reg_seq[i].val); + for (i = 0; reg_seq[i].reg != ADV76XX_REG_SEQ_TERM; i++) + adv76xx_write_reg(sd, reg_seq[i].reg, reg_seq[i].val); } /* ----------------------------------------------------------------------------- * Format helpers */ -static const struct adv7604_format_info adv7604_formats[] = { - { MEDIA_BUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false, - ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YUYV10_2X10, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT }, - { MEDIA_BUS_FMT_YVYU10_2X10, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT }, - { MEDIA_BUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_UYVY10_1X20, ADV7604_OP_CH_SEL_RBG, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, - { MEDIA_BUS_FMT_VYUY10_1X20, ADV7604_OP_CH_SEL_RBG, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, - { MEDIA_BUS_FMT_YUYV10_1X20, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, - { MEDIA_BUS_FMT_YVYU10_1X20, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, - { MEDIA_BUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, +static const struct adv76xx_format_info adv7604_formats[] = { + { MEDIA_BUS_FMT_RGB888_1X24, ADV76XX_OP_CH_SEL_RGB, true, false, + ADV76XX_OP_MODE_SEL_SDR_444 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_2X8, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_2X8, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV10_2X10, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_YVYU10_2X10, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_YUYV12_2X12, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YVYU12_2X12, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_UYVY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_VYUY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_1X16, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_1X16, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_UYVY10_1X20, ADV76XX_OP_CH_SEL_RBG, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_VYUY10_1X20, ADV76XX_OP_CH_SEL_RBG, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_YUYV10_1X20, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_YVYU10_1X20, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_UYVY12_1X24, ADV76XX_OP_CH_SEL_RBG, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_VYUY12_1X24, ADV76XX_OP_CH_SEL_RBG, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YUYV12_1X24, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YVYU12_1X24, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, }; -static const struct adv7604_format_info adv7611_formats[] = { - { MEDIA_BUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false, - ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, +static const struct adv76xx_format_info adv7611_formats[] = { + { MEDIA_BUS_FMT_RGB888_1X24, ADV76XX_OP_CH_SEL_RGB, true, false, + ADV76XX_OP_MODE_SEL_SDR_444 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_2X8, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_2X8, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV12_2X12, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YVYU12_2X12, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_UYVY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_VYUY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_1X16, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_1X16, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_UYVY12_1X24, ADV76XX_OP_CH_SEL_RBG, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_VYUY12_1X24, ADV76XX_OP_CH_SEL_RBG, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YUYV12_1X24, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YVYU12_1X24, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, }; -static const struct adv7604_format_info * -adv7604_format_info(struct adv7604_state *state, u32 code) +static const struct adv76xx_format_info * +adv76xx_format_info(struct adv76xx_state *state, u32 code) { unsigned int i; @@ -760,7 +760,7 @@ adv7604_format_info(struct adv7604_state *state, u32 code) static inline bool is_analog_input(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); return state->selected_input == ADV7604_PAD_VGA_RGB || state->selected_input == ADV7604_PAD_VGA_COMP; @@ -768,9 +768,9 @@ static inline bool is_analog_input(struct v4l2_subdev *sd) static inline bool is_digital_input(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return state->selected_input == ADV7604_PAD_HDMI_PORT_A || + return state->selected_input == ADV76XX_PAD_HDMI_PORT_A || state->selected_input == ADV7604_PAD_HDMI_PORT_B || state->selected_input == ADV7604_PAD_HDMI_PORT_C || state->selected_input == ADV7604_PAD_HDMI_PORT_D; @@ -779,7 +779,7 @@ static inline bool is_digital_input(struct v4l2_subdev *sd) /* ----------------------------------------------------------------------- */ #ifdef CONFIG_VIDEO_ADV_DEBUG -static void adv7604_inv_register(struct v4l2_subdev *sd) +static void adv76xx_inv_register(struct v4l2_subdev *sd) { v4l2_info(sd, "0x000-0x0ff: IO Map\n"); v4l2_info(sd, "0x100-0x1ff: AVLink Map\n"); @@ -796,15 +796,15 @@ static void adv7604_inv_register(struct v4l2_subdev *sd) v4l2_info(sd, "0xc00-0xcff: VDP Map\n"); } -static int adv7604_g_register(struct v4l2_subdev *sd, +static int adv76xx_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { int ret; - ret = adv7604_read_reg(sd, reg->reg); + ret = adv76xx_read_reg(sd, reg->reg); if (ret < 0) { v4l2_info(sd, "Register %03llx not supported\n", reg->reg); - adv7604_inv_register(sd); + adv76xx_inv_register(sd); return ret; } @@ -814,15 +814,15 @@ static int adv7604_g_register(struct v4l2_subdev *sd, return 0; } -static int adv7604_s_register(struct v4l2_subdev *sd, +static int adv76xx_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { int ret; - ret = adv7604_write_reg(sd, reg->reg, reg->val); + ret = adv76xx_write_reg(sd, reg->reg, reg->val); if (ret < 0) { v4l2_info(sd, "Register %03llx not supported\n", reg->reg); - adv7604_inv_register(sd); + adv76xx_inv_register(sd); return ret; } @@ -847,10 +847,10 @@ static unsigned int adv7611_read_cable_det(struct v4l2_subdev *sd) return value & 1; } -static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) +static int adv76xx_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, info->read_cable_det(sd)); @@ -858,7 +858,7 @@ static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, u8 prim_mode, - const struct adv7604_video_standards *predef_vid_timings, + const struct adv76xx_video_standards *predef_vid_timings, const struct v4l2_dv_timings *timings) { int i; @@ -879,12 +879,12 @@ static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, static int configure_predefined_video_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); int err; v4l2_dbg(1, debug, sd, "%s", __func__); - if (adv7604_has_afe(state)) { + if (adv76xx_has_afe(state)) { /* reset to default values */ io_write(sd, 0x16, 0x43); io_write(sd, 0x17, 0x5a); @@ -910,10 +910,10 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd, 0x02, adv7604_prim_mode_gr, timings); } else if (is_digital_input(sd)) { err = find_and_set_predefined_video_timings(sd, - 0x05, adv7604_prim_mode_hdmi_comp, timings); + 0x05, adv76xx_prim_mode_hdmi_comp, timings); if (err) err = find_and_set_predefined_video_timings(sd, - 0x06, adv7604_prim_mode_hdmi_gr, timings); + 0x06, adv76xx_prim_mode_hdmi_gr, timings); } else { v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", __func__, state->selected_input); @@ -927,7 +927,7 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd, static void configure_custom_video_timings(struct v4l2_subdev *sd, const struct v4l2_bt_timings *bt) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); u32 width = htotal(bt); u32 height = vtotal(bt); u16 cp_start_sav = bt->hsync + bt->hbackporch - 4; @@ -935,7 +935,7 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, u16 cp_start_vbi = height - bt->vfrontporch; u16 cp_end_vbi = bt->vsync + bt->vbackporch; u16 ch1_fr_ll = (((u32)bt->pixelclock / 100) > 0) ? - ((width * (ADV7604_fsc / 100)) / ((u32)bt->pixelclock / 100)) : 0; + ((width * (ADV76XX_FSC / 100)) / ((u32)bt->pixelclock / 100)) : 0; const u8 pll[2] = { 0xc0 | ((width >> 8) & 0x1f), width & 0xff @@ -953,7 +953,7 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ /* IO-map reg. 0x16 and 0x17 should be written in sequence */ - if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_IO, + if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_IO, 0x16, 2, pll)) v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); @@ -984,9 +984,9 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, cp_write(sd, 0xac, (height & 0x0f) << 4); } -static void adv7604_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c) +static void adv76xx_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); u8 offset_buf[4]; if (auto_offset) { @@ -1005,14 +1005,14 @@ static void adv7604_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 off offset_buf[3] = offset_c & 0x0ff; /* Registers must be written in this order with no i2c access in between */ - if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_CP, + if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_CP, 0x77, 4, offset_buf)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__); } -static void adv7604_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c) +static void adv76xx_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); u8 gain_buf[4]; u8 gain_man = 1; u8 agc_mode_man = 1; @@ -1035,14 +1035,14 @@ static void adv7604_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, gain_buf[3] = ((gain_c & 0x0ff)); /* Registers must be written in this order with no i2c access in between */ - if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_CP, + if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_CP, 0x73, 4, gain_buf)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__); } static void set_rgb_quantization_range(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); bool rgb_output = io_read(sd, 0x02) & 0x02; bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; @@ -1050,8 +1050,8 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) __func__, state->rgb_quantization_range, rgb_output, hdmi_signal); - adv7604_set_gain(sd, true, 0x0, 0x0, 0x0); - adv7604_set_offset(sd, true, 0x0, 0x0, 0x0); + adv76xx_set_gain(sd, true, 0x0, 0x0, 0x0); + adv76xx_set_offset(sd, true, 0x0, 0x0, 0x0); switch (state->rgb_quantization_range) { case V4L2_DV_RGB_RANGE_AUTO: @@ -1087,10 +1087,10 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) io_write_clr_set(sd, 0x02, 0xf0, 0x10); if (is_digital_input(sd) && rgb_output) { - adv7604_set_offset(sd, false, 0x40, 0x40, 0x40); + adv76xx_set_offset(sd, false, 0x40, 0x40, 0x40); } else { - adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0); - adv7604_set_offset(sd, false, 0x70, 0x70, 0x70); + adv76xx_set_gain(sd, false, 0xe0, 0xe0, 0xe0); + adv76xx_set_offset(sd, false, 0x70, 0x70, 0x70); } } break; @@ -1120,21 +1120,21 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) /* Adjust gain/offset for DVI-D signals only */ if (rgb_output) { - adv7604_set_offset(sd, false, 0x40, 0x40, 0x40); + adv76xx_set_offset(sd, false, 0x40, 0x40, 0x40); } else { - adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0); - adv7604_set_offset(sd, false, 0x70, 0x70, 0x70); + adv76xx_set_gain(sd, false, 0xe0, 0xe0, 0xe0); + adv76xx_set_offset(sd, false, 0x70, 0x70, 0x70); } break; } } -static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) +static int adv76xx_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = - &container_of(ctrl->handler, struct adv7604_state, hdl)->sd; + &container_of(ctrl->handler, struct adv76xx_state, hdl)->sd; - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: @@ -1154,7 +1154,7 @@ static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) set_rgb_quantization_range(sd); return 0; case V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE: - if (!adv7604_has_afe(state)) + if (!adv76xx_has_afe(state)) return -EINVAL; /* Set the analog sampling phase. This is needed to find the best sampling phase for analog video: an application or @@ -1186,15 +1186,15 @@ static inline bool no_power(struct v4l2_subdev *sd) static inline bool no_signal_tmds(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); return !(io_read(sd, 0x6a) & (0x10 >> state->selected_input)); } static inline bool no_lock_tmds(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; return (io_read(sd, 0x6a) & info->tdms_lock_mask) != info->tdms_lock_mask; } @@ -1206,13 +1206,13 @@ static inline bool is_hdmi(struct v4l2_subdev *sd) static inline bool no_lock_sspd(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); /* * Chips without a AFE don't expose registers for the SSPD, so just assume * that we have a lock. */ - if (adv7604_has_afe(state)) + if (adv76xx_has_afe(state)) return false; /* TODO channel 2 */ @@ -1244,9 +1244,9 @@ static inline bool no_signal(struct v4l2_subdev *sd) static inline bool no_lock_cp(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - if (!adv7604_has_afe(state)) + if (!adv76xx_has_afe(state)) return false; /* CP has detected a non standard number of lines on the incoming @@ -1259,7 +1259,7 @@ static inline bool in_free_run(struct v4l2_subdev *sd) return cp_read(sd, 0xff) & 0x10; } -static int adv7604_g_input_status(struct v4l2_subdev *sd, u32 *status) +static int adv76xx_g_input_status(struct v4l2_subdev *sd, u32 *status) { *status = 0; *status |= no_power(sd) ? V4L2_IN_ST_NO_POWER : 0; @@ -1285,22 +1285,22 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, struct stdi_readback *stdi, struct v4l2_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); - u32 hfreq = (ADV7604_fsc * 8) / stdi->bl; + struct adv76xx_state *state = to_state(sd); + u32 hfreq = (ADV76XX_FSC * 8) / stdi->bl; u32 pix_clk; int i; - for (i = 0; adv7604_timings[i].bt.height; i++) { - if (vtotal(&adv7604_timings[i].bt) != stdi->lcf + 1) + for (i = 0; adv76xx_timings[i].bt.height; i++) { + if (vtotal(&adv76xx_timings[i].bt) != stdi->lcf + 1) continue; - if (adv7604_timings[i].bt.vsync != stdi->lcvs) + if (adv76xx_timings[i].bt.vsync != stdi->lcvs) continue; - pix_clk = hfreq * htotal(&adv7604_timings[i].bt); + pix_clk = hfreq * htotal(&adv76xx_timings[i].bt); - if ((pix_clk < adv7604_timings[i].bt.pixelclock + 1000000) && - (pix_clk > adv7604_timings[i].bt.pixelclock - 1000000)) { - *timings = adv7604_timings[i]; + if ((pix_clk < adv76xx_timings[i].bt.pixelclock + 1000000) && + (pix_clk > adv76xx_timings[i].bt.pixelclock - 1000000)) { + *timings = adv76xx_timings[i]; return 0; } } @@ -1326,8 +1326,8 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; u8 polarity; if (no_lock_stdi(sd) || no_lock_sspd(sd)) { @@ -1341,7 +1341,7 @@ static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi) stdi->lcvs = cp_read(sd, 0xb3) >> 3; stdi->interlaced = io_read(sd, 0x12) & 0x10; - if (adv7604_has_afe(state)) { + if (adv76xx_has_afe(state)) { /* read SSPD */ polarity = cp_read(sd, 0xb5); if ((polarity & 0x03) == 0x01) { @@ -1380,26 +1380,26 @@ static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi) return 0; } -static int adv7604_enum_dv_timings(struct v4l2_subdev *sd, +static int adv76xx_enum_dv_timings(struct v4l2_subdev *sd, struct v4l2_enum_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - if (timings->index >= ARRAY_SIZE(adv7604_timings) - 1) + if (timings->index >= ARRAY_SIZE(adv76xx_timings) - 1) return -EINVAL; if (timings->pad >= state->source_pad) return -EINVAL; memset(timings->reserved, 0, sizeof(timings->reserved)); - timings->timings = adv7604_timings[timings->index]; + timings->timings = adv76xx_timings[timings->index]; return 0; } -static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, +static int adv76xx_dv_timings_cap(struct v4l2_subdev *sd, struct v4l2_dv_timings_cap *cap) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); if (cap->pad >= state->source_pad) return -EINVAL; @@ -1410,7 +1410,7 @@ static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, cap->bt.min_pixelclock = 25000000; switch (cap->pad) { - case ADV7604_PAD_HDMI_PORT_A: + case ADV76XX_PAD_HDMI_PORT_A: case ADV7604_PAD_HDMI_PORT_B: case ADV7604_PAD_HDMI_PORT_C: case ADV7604_PAD_HDMI_PORT_D: @@ -1431,16 +1431,16 @@ static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, } /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings - if the format is listed in adv7604_timings[] */ -static void adv7604_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, + if the format is listed in adv76xx_timings[] */ +static void adv76xx_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { int i; - for (i = 0; adv7604_timings[i].bt.width; i++) { - if (v4l2_match_dv_timings(timings, &adv7604_timings[i], + for (i = 0; adv76xx_timings[i].bt.width; i++) { + if (v4l2_match_dv_timings(timings, &adv76xx_timings[i], is_digital_input(sd) ? 250000 : 1000000)) { - *timings = adv7604_timings[i]; + *timings = adv76xx_timings[i]; break; } } @@ -1478,11 +1478,11 @@ static unsigned int adv7611_read_hdmi_pixelclock(struct v4l2_subdev *sd) return ((a << 1) | (b >> 7)) * 1000000 + (b & 0x7f) * 1000000 / 128; } -static int adv7604_query_dv_timings(struct v4l2_subdev *sd, +static int adv76xx_query_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; struct v4l2_bt_timings *bt = &timings->bt; struct stdi_readback stdi; @@ -1526,7 +1526,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, bt->il_vsync = hdmi_read16(sd, 0x30, 0x1fff) / 2; bt->il_vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2; } - adv7604_fill_optional_dv_timings_fields(sd, timings); + adv76xx_fill_optional_dv_timings_fields(sd, timings); } else { /* find format * Since LCVS values are inaccurate [REF_03, p. 275-276], @@ -1583,16 +1583,16 @@ found: } if (debug > 1) - v4l2_print_dv_timings(sd->name, "adv7604_query_dv_timings: ", + v4l2_print_dv_timings(sd->name, "adv76xx_query_dv_timings: ", timings, true); return 0; } -static int adv7604_s_dv_timings(struct v4l2_subdev *sd, +static int adv76xx_s_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); struct v4l2_bt_timings *bt; int err; @@ -1613,7 +1613,7 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, return -ERANGE; } - adv7604_fill_optional_dv_timings_fields(sd, timings); + adv76xx_fill_optional_dv_timings_fields(sd, timings); state->timings = *timings; @@ -1630,15 +1630,15 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, set_rgb_quantization_range(sd); if (debug > 1) - v4l2_print_dv_timings(sd->name, "adv7604_s_dv_timings: ", + v4l2_print_dv_timings(sd->name, "adv76xx_s_dv_timings: ", timings, true); return 0; } -static int adv7604_g_dv_timings(struct v4l2_subdev *sd, +static int adv76xx_g_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); *timings = state->timings; return 0; @@ -1656,7 +1656,7 @@ static void adv7611_set_termination(struct v4l2_subdev *sd, bool enable) static void enable_input(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); if (is_analog_input(sd)) { io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ @@ -1673,7 +1673,7 @@ static void enable_input(struct v4l2_subdev *sd) static void disable_input(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); hdmi_write_clr_set(sd, 0x1a, 0x10, 0x10); /* Mute audio */ msleep(16); /* 512 samples with >= 32 kHz sample rate [REF_03, c. 7.16.10] */ @@ -1683,11 +1683,11 @@ static void disable_input(struct v4l2_subdev *sd) static void select_input(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; if (is_analog_input(sd)) { - adv7604_write_reg_seq(sd, info->recommended_settings[0]); + adv76xx_write_reg_seq(sd, info->recommended_settings[0]); afe_write(sd, 0x00, 0x08); /* power up ADC */ afe_write(sd, 0x01, 0x06); /* power up Analog Front End */ @@ -1695,9 +1695,9 @@ static void select_input(struct v4l2_subdev *sd) } else if (is_digital_input(sd)) { hdmi_write(sd, 0x00, state->selected_input & 0x03); - adv7604_write_reg_seq(sd, info->recommended_settings[1]); + adv76xx_write_reg_seq(sd, info->recommended_settings[1]); - if (adv7604_has_afe(state)) { + if (adv76xx_has_afe(state)) { afe_write(sd, 0x00, 0xff); /* power down ADC */ afe_write(sd, 0x01, 0xfe); /* power down Analog Front End */ afe_write(sd, 0xc8, 0x40); /* phase control */ @@ -1712,10 +1712,10 @@ static void select_input(struct v4l2_subdev *sd) } } -static int adv7604_s_routing(struct v4l2_subdev *sd, +static int adv76xx_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, u32 config) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); v4l2_dbg(2, debug, sd, "%s: input %d, selected input %d", __func__, input, state->selected_input); @@ -1737,11 +1737,11 @@ static int adv7604_s_routing(struct v4l2_subdev *sd, return 0; } -static int adv7604_enum_mbus_code(struct v4l2_subdev *sd, +static int adv76xx_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_mbus_code_enum *code) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); if (code->index >= state->info->nformats) return -EINVAL; @@ -1751,7 +1751,7 @@ static int adv7604_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static void adv7604_fill_format(struct adv7604_state *state, +static void adv76xx_fill_format(struct adv76xx_state *state, struct v4l2_mbus_framefmt *format) { memset(format, 0, sizeof(*format)); @@ -1772,7 +1772,7 @@ static void adv7604_fill_format(struct adv7604_state *state, * * The following table gives the op_ch_value from the format component order * (expressed as op_ch_sel value in column) and the bus reordering (expressed as - * adv7604_bus_order value in row). + * adv76xx_bus_order value in row). * * | GBR(0) GRB(1) BGR(2) RGB(3) BRG(4) RBG(5) * ----------+------------------------------------------------- @@ -1783,11 +1783,11 @@ static void adv7604_fill_format(struct adv7604_state *state, * BRG (ROR) | BRG RBG GRB GBR RGB BGR * GBR (ROL) | RGB BGR RBG BRG GBR GRB */ -static unsigned int adv7604_op_ch_sel(struct adv7604_state *state) +static unsigned int adv76xx_op_ch_sel(struct adv76xx_state *state) { #define _SEL(a,b,c,d,e,f) { \ - ADV7604_OP_CH_SEL_##a, ADV7604_OP_CH_SEL_##b, ADV7604_OP_CH_SEL_##c, \ - ADV7604_OP_CH_SEL_##d, ADV7604_OP_CH_SEL_##e, ADV7604_OP_CH_SEL_##f } + ADV76XX_OP_CH_SEL_##a, ADV76XX_OP_CH_SEL_##b, ADV76XX_OP_CH_SEL_##c, \ + ADV76XX_OP_CH_SEL_##d, ADV76XX_OP_CH_SEL_##e, ADV76XX_OP_CH_SEL_##f } #define _BUS(x) [ADV7604_BUS_ORDER_##x] static const unsigned int op_ch_sel[6][6] = { @@ -1802,28 +1802,28 @@ static unsigned int adv7604_op_ch_sel(struct adv7604_state *state) return op_ch_sel[state->pdata.bus_order][state->format->op_ch_sel >> 5]; } -static void adv7604_setup_format(struct adv7604_state *state) +static void adv76xx_setup_format(struct adv76xx_state *state) { struct v4l2_subdev *sd = &state->sd; io_write_clr_set(sd, 0x02, 0x02, - state->format->rgb_out ? ADV7604_RGB_OUT : 0); + state->format->rgb_out ? ADV76XX_RGB_OUT : 0); io_write(sd, 0x03, state->format->op_format_sel | state->pdata.op_format_mode_sel); - io_write_clr_set(sd, 0x04, 0xe0, adv7604_op_ch_sel(state)); + io_write_clr_set(sd, 0x04, 0xe0, adv76xx_op_ch_sel(state)); io_write_clr_set(sd, 0x05, 0x01, - state->format->swap_cb_cr ? ADV7604_OP_SWAP_CB_CR : 0); + state->format->swap_cb_cr ? ADV76XX_OP_SWAP_CB_CR : 0); } -static int adv7604_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int adv76xx_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_format *format) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); if (format->pad != state->source_pad) return -EINVAL; - adv7604_fill_format(state, &format->format); + adv76xx_fill_format(state, &format->format); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; @@ -1837,20 +1837,20 @@ static int adv7604_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } -static int adv7604_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int adv76xx_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_format *format) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_format_info *info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_format_info *info; if (format->pad != state->source_pad) return -EINVAL; - info = adv7604_format_info(state, format->format.code); + info = adv76xx_format_info(state, format->format.code); if (info == NULL) - info = adv7604_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); + info = adv76xx_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); - adv7604_fill_format(state, &format->format); + adv76xx_fill_format(state, &format->format); format->format.code = info->code; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { @@ -1860,16 +1860,16 @@ static int adv7604_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, fmt->code = format->format.code; } else { state->format = info; - adv7604_setup_format(state); + adv76xx_setup_format(state); } return 0; } -static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) +static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; const u8 irq_reg_0x43 = io_read(sd, 0x43); const u8 irq_reg_0x6b = io_read(sd, 0x6b); const u8 irq_reg_0x70 = io_read(sd, 0x70); @@ -1897,7 +1897,7 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) "%s: fmt_change = 0x%x, fmt_change_digital = 0x%x\n", __func__, fmt_change, fmt_change_digital); - v4l2_subdev_notify(sd, ADV7604_FMT_CHANGE, NULL); + v4l2_subdev_notify(sd, ADV76XX_FMT_CHANGE, NULL); if (handled) *handled = true; @@ -1916,22 +1916,22 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) if (tx_5v) { v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v); io_write(sd, 0x71, tx_5v); - adv7604_s_detect_tx_5v_ctrl(sd); + adv76xx_s_detect_tx_5v_ctrl(sd); if (handled) *handled = true; } return 0; } -static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +static int adv76xx_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); u8 *data = NULL; memset(edid->reserved, 0, sizeof(edid->reserved)); switch (edid->pad) { - case ADV7604_PAD_HDMI_PORT_A: + case ADV76XX_PAD_HDMI_PORT_A: case ADV7604_PAD_HDMI_PORT_B: case ADV7604_PAD_HDMI_PORT_C: case ADV7604_PAD_HDMI_PORT_D: @@ -1989,10 +1989,10 @@ static int get_edid_spa_location(const u8 *edid) return -1; } -static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; int spa_loc; int err; int i; @@ -2006,7 +2006,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) if (edid->blocks == 0) { /* Disable hotplug and I2C access to EDID RAM from DDC port */ state->edid.present &= ~(1 << edid->pad); - adv7604_set_hpd(state, state->edid.present); + adv76xx_set_hpd(state, state->edid.present); rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, state->edid.present); /* Fall back to a 16:9 aspect ratio */ @@ -2030,7 +2030,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) /* Disable hotplug and I2C access to EDID RAM from DDC port */ cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); - adv7604_set_hpd(state, 0); + adv76xx_set_hpd(state, 0); rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, 0x00); spa_loc = get_edid_spa_location(edid->edid); @@ -2038,7 +2038,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) spa_loc = 0xc0; /* Default value [REF_02, p. 116] */ switch (edid->pad) { - case ADV7604_PAD_HDMI_PORT_A: + case ADV76XX_PAD_HDMI_PORT_A: state->spa_port_a[0] = edid->edid[spa_loc]; state->spa_port_a[1] = edid->edid[spa_loc + 1]; break; @@ -2081,7 +2081,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) return err; } - /* adv7604 calculates the checksums and enables I2C access to internal + /* adv76xx calculates the checksums and enables I2C access to internal EDID RAM from DDC port. */ rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, state->edid.present); @@ -2145,10 +2145,10 @@ static void print_avi_infoframe(struct v4l2_subdev *sd) buf[8], buf[9], buf[10], buf[11], buf[12], buf[13]); } -static int adv7604_log_status(struct v4l2_subdev *sd) +static int adv76xx_log_status(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; struct v4l2_dv_timings timings; struct stdi_readback stdi; u8 reg_io_0x02 = io_read(sd, 0x02); @@ -2220,7 +2220,7 @@ static int adv7604_log_status(struct v4l2_subdev *sd) stdi.lcf, stdi.bl, stdi.lcvs, stdi.interlaced ? "interlaced" : "progressive", stdi.hs_pol, stdi.vs_pol); - if (adv7604_query_dv_timings(sd, &timings)) + if (adv76xx_query_dv_timings(sd, &timings)) v4l2_info(sd, "No video detected\n"); else v4l2_print_dv_timings(sd->name, "Detected format: ", @@ -2286,47 +2286,47 @@ static int adv7604_log_status(struct v4l2_subdev *sd) /* ----------------------------------------------------------------------- */ -static const struct v4l2_ctrl_ops adv7604_ctrl_ops = { - .s_ctrl = adv7604_s_ctrl, +static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = { + .s_ctrl = adv76xx_s_ctrl, }; -static const struct v4l2_subdev_core_ops adv7604_core_ops = { - .log_status = adv7604_log_status, - .interrupt_service_routine = adv7604_isr, +static const struct v4l2_subdev_core_ops adv76xx_core_ops = { + .log_status = adv76xx_log_status, + .interrupt_service_routine = adv76xx_isr, #ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = adv7604_g_register, - .s_register = adv7604_s_register, + .g_register = adv76xx_g_register, + .s_register = adv76xx_s_register, #endif }; -static const struct v4l2_subdev_video_ops adv7604_video_ops = { - .s_routing = adv7604_s_routing, - .g_input_status = adv7604_g_input_status, - .s_dv_timings = adv7604_s_dv_timings, - .g_dv_timings = adv7604_g_dv_timings, - .query_dv_timings = adv7604_query_dv_timings, +static const struct v4l2_subdev_video_ops adv76xx_video_ops = { + .s_routing = adv76xx_s_routing, + .g_input_status = adv76xx_g_input_status, + .s_dv_timings = adv76xx_s_dv_timings, + .g_dv_timings = adv76xx_g_dv_timings, + .query_dv_timings = adv76xx_query_dv_timings, }; -static const struct v4l2_subdev_pad_ops adv7604_pad_ops = { - .enum_mbus_code = adv7604_enum_mbus_code, - .get_fmt = adv7604_get_format, - .set_fmt = adv7604_set_format, - .get_edid = adv7604_get_edid, - .set_edid = adv7604_set_edid, - .dv_timings_cap = adv7604_dv_timings_cap, - .enum_dv_timings = adv7604_enum_dv_timings, +static const struct v4l2_subdev_pad_ops adv76xx_pad_ops = { + .enum_mbus_code = adv76xx_enum_mbus_code, + .get_fmt = adv76xx_get_format, + .set_fmt = adv76xx_set_format, + .get_edid = adv76xx_get_edid, + .set_edid = adv76xx_set_edid, + .dv_timings_cap = adv76xx_dv_timings_cap, + .enum_dv_timings = adv76xx_enum_dv_timings, }; -static const struct v4l2_subdev_ops adv7604_ops = { - .core = &adv7604_core_ops, - .video = &adv7604_video_ops, - .pad = &adv7604_pad_ops, +static const struct v4l2_subdev_ops adv76xx_ops = { + .core = &adv76xx_core_ops, + .video = &adv76xx_video_ops, + .pad = &adv76xx_pad_ops, }; /* -------------------------- custom ctrls ---------------------------------- */ static const struct v4l2_ctrl_config adv7604_ctrl_analog_sampling_phase = { - .ops = &adv7604_ctrl_ops, + .ops = &adv76xx_ctrl_ops, .id = V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE, .name = "Analog Sampling Phase", .type = V4L2_CTRL_TYPE_INTEGER, @@ -2336,8 +2336,8 @@ static const struct v4l2_ctrl_config adv7604_ctrl_analog_sampling_phase = { .def = 0, }; -static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color_manual = { - .ops = &adv7604_ctrl_ops, +static const struct v4l2_ctrl_config adv76xx_ctrl_free_run_color_manual = { + .ops = &adv76xx_ctrl_ops, .id = V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL, .name = "Free Running Color, Manual", .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -2347,8 +2347,8 @@ static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color_manual = { .def = false, }; -static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color = { - .ops = &adv7604_ctrl_ops, +static const struct v4l2_ctrl_config adv76xx_ctrl_free_run_color = { + .ops = &adv76xx_ctrl_ops, .id = V4L2_CID_ADV_RX_FREE_RUN_COLOR, .name = "Free Running Color", .type = V4L2_CTRL_TYPE_INTEGER, @@ -2360,11 +2360,11 @@ static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color = { /* ----------------------------------------------------------------------- */ -static int adv7604_core_init(struct v4l2_subdev *sd) +static int adv76xx_core_init(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; - struct adv7604_platform_data *pdata = &state->pdata; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; + struct adv76xx_platform_data *pdata = &state->pdata; hdmi_write(sd, 0x48, (pdata->disable_pwrdnb ? 0x80 : 0) | @@ -2392,7 +2392,7 @@ static int adv7604_core_init(struct v4l2_subdev *sd) io_write_clr_set(sd, 0x05, 0x0e, pdata->blank_data << 3 | pdata->insert_av_codes << 2 | pdata->replicate_av_codes << 1); - adv7604_setup_format(state); + adv76xx_setup_format(state); cp_write(sd, 0x69, 0x30); /* Enable CP CSC */ @@ -2422,7 +2422,7 @@ static int adv7604_core_init(struct v4l2_subdev *sd) /* TODO from platform data */ afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ - if (adv7604_has_afe(state)) { + if (adv76xx_has_afe(state)) { afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */ io_write_clr_set(sd, 0x30, 1 << 4, pdata->output_bus_lsb_to_msb << 4); } @@ -2447,7 +2447,7 @@ static void adv7611_setup_irqs(struct v4l2_subdev *sd) io_write(sd, 0x41, 0xd0); /* STDI irq for any change, disable INT2 */ } -static void adv7604_unregister_clients(struct adv7604_state *state) +static void adv76xx_unregister_clients(struct adv76xx_state *state) { unsigned int i; @@ -2457,7 +2457,7 @@ static void adv7604_unregister_clients(struct adv7604_state *state) } } -static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd, +static struct i2c_client *adv76xx_dummy_client(struct v4l2_subdev *sd, u8 addr, u8 io_reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -2467,74 +2467,74 @@ static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd, return i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1); } -static const struct adv7604_reg_seq adv7604_recommended_settings_afe[] = { +static const struct adv76xx_reg_seq adv7604_recommended_settings_afe[] = { /* reset ADI recommended settings for HDMI: */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3d), 0x00 }, /* DDC bus active pull-up control */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3e), 0x74 }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0x74 }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x63 }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x93), 0x88 }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x94), 0x2e }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x96), 0x00 }, /* enable automatic EQ changing */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x3d), 0x00 }, /* DDC bus active pull-up control */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x3e), 0x74 }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x57), 0x74 }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x58), 0x63 }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x93), 0x88 }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x94), 0x2e }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x96), 0x00 }, /* enable automatic EQ changing */ /* set ADI recommended settings for digitizer */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */ - { ADV7604_REG(ADV7604_PAGE_AFE, 0x12), 0x7b }, /* ADC noise shaping filter controls */ - { ADV7604_REG(ADV7604_PAGE_AFE, 0x0c), 0x1f }, /* CP core gain controls */ - { ADV7604_REG(ADV7604_PAGE_CP, 0x3e), 0x04 }, /* CP core pre-gain control */ - { ADV7604_REG(ADV7604_PAGE_CP, 0xc3), 0x39 }, /* CP coast control. Graphics mode */ - { ADV7604_REG(ADV7604_PAGE_CP, 0x40), 0x5c }, /* CP core pre-gain control. Graphics mode */ + { ADV76XX_REG(ADV76XX_PAGE_AFE, 0x12), 0x7b }, /* ADC noise shaping filter controls */ + { ADV76XX_REG(ADV76XX_PAGE_AFE, 0x0c), 0x1f }, /* CP core gain controls */ + { ADV76XX_REG(ADV76XX_PAGE_CP, 0x3e), 0x04 }, /* CP core pre-gain control */ + { ADV76XX_REG(ADV76XX_PAGE_CP, 0xc3), 0x39 }, /* CP coast control. Graphics mode */ + { ADV76XX_REG(ADV76XX_PAGE_CP, 0x40), 0x5c }, /* CP core pre-gain control. Graphics mode */ - { ADV7604_REG_SEQ_TERM, 0 }, + { ADV76XX_REG_SEQ_TERM, 0 }, }; -static const struct adv7604_reg_seq adv7604_recommended_settings_hdmi[] = { +static const struct adv76xx_reg_seq adv7604_recommended_settings_hdmi[] = { /* set ADI recommended settings for HDMI: */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x84 }, /* HDMI filter optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3d), 0x10 }, /* DDC bus active pull-up control */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3e), 0x39 }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0xb6 }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x03 }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x93), 0x8b }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x94), 0x2d }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x96), 0x01 }, /* enable automatic EQ changing */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x0d), 0x84 }, /* HDMI filter optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x3d), 0x10 }, /* DDC bus active pull-up control */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x3e), 0x39 }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x57), 0xb6 }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x58), 0x03 }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x93), 0x8b }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x94), 0x2d }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x96), 0x01 }, /* enable automatic EQ changing */ /* reset ADI recommended settings for digitizer */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */ - { ADV7604_REG(ADV7604_PAGE_AFE, 0x12), 0xfb }, /* ADC noise shaping filter controls */ - { ADV7604_REG(ADV7604_PAGE_AFE, 0x0c), 0x0d }, /* CP core gain controls */ + { ADV76XX_REG(ADV76XX_PAGE_AFE, 0x12), 0xfb }, /* ADC noise shaping filter controls */ + { ADV76XX_REG(ADV76XX_PAGE_AFE, 0x0c), 0x0d }, /* CP core gain controls */ - { ADV7604_REG_SEQ_TERM, 0 }, + { ADV76XX_REG_SEQ_TERM, 0 }, }; -static const struct adv7604_reg_seq adv7611_recommended_settings_hdmi[] = { +static const struct adv76xx_reg_seq adv7611_recommended_settings_hdmi[] = { /* ADV7611 Register Settings Recommendations Rev 1.5, May 2014 */ - { ADV7604_REG(ADV7604_PAGE_CP, 0x6c), 0x00 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x9b), 0x03 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x6f), 0x08 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x85), 0x1f }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x87), 0x70 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0xda }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x01 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x03), 0x98 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4c), 0x44 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x04 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x1e }, - - { ADV7604_REG_SEQ_TERM, 0 }, + { ADV76XX_REG(ADV76XX_PAGE_CP, 0x6c), 0x00 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x9b), 0x03 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x6f), 0x08 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x85), 0x1f }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x87), 0x70 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x57), 0xda }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x58), 0x01 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x03), 0x98 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x4c), 0x44 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8d), 0x04 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8e), 0x1e }, + + { ADV76XX_REG_SEQ_TERM, 0 }, }; -static const struct adv7604_chip_info adv7604_chip_info[] = { +static const struct adv76xx_chip_info adv76xx_chip_info[] = { [ADV7604] = { .type = ADV7604, .has_afe = true, @@ -2561,18 +2561,18 @@ static const struct adv7604_chip_info adv7604_chip_info[] = { [0] = ARRAY_SIZE(adv7604_recommended_settings_afe), [1] = ARRAY_SIZE(adv7604_recommended_settings_hdmi), }, - .page_mask = BIT(ADV7604_PAGE_IO) | BIT(ADV7604_PAGE_AVLINK) | - BIT(ADV7604_PAGE_CEC) | BIT(ADV7604_PAGE_INFOFRAME) | + .page_mask = BIT(ADV76XX_PAGE_IO) | BIT(ADV7604_PAGE_AVLINK) | + BIT(ADV76XX_PAGE_CEC) | BIT(ADV76XX_PAGE_INFOFRAME) | BIT(ADV7604_PAGE_ESDP) | BIT(ADV7604_PAGE_DPP) | - BIT(ADV7604_PAGE_AFE) | BIT(ADV7604_PAGE_REP) | - BIT(ADV7604_PAGE_EDID) | BIT(ADV7604_PAGE_HDMI) | - BIT(ADV7604_PAGE_TEST) | BIT(ADV7604_PAGE_CP) | + BIT(ADV76XX_PAGE_AFE) | BIT(ADV76XX_PAGE_REP) | + BIT(ADV76XX_PAGE_EDID) | BIT(ADV76XX_PAGE_HDMI) | + BIT(ADV76XX_PAGE_TEST) | BIT(ADV76XX_PAGE_CP) | BIT(ADV7604_PAGE_VDP), }, [ADV7611] = { .type = ADV7611, .has_afe = false, - .max_port = ADV7604_PAD_HDMI_PORT_A, + .max_port = ADV76XX_PAD_HDMI_PORT_A, .num_dv_ports = 1, .edid_enable_reg = 0x74, .edid_status_reg = 0x76, @@ -2593,34 +2593,34 @@ static const struct adv7604_chip_info adv7604_chip_info[] = { .num_recommended_settings = { [1] = ARRAY_SIZE(adv7611_recommended_settings_hdmi), }, - .page_mask = BIT(ADV7604_PAGE_IO) | BIT(ADV7604_PAGE_CEC) | - BIT(ADV7604_PAGE_INFOFRAME) | BIT(ADV7604_PAGE_AFE) | - BIT(ADV7604_PAGE_REP) | BIT(ADV7604_PAGE_EDID) | - BIT(ADV7604_PAGE_HDMI) | BIT(ADV7604_PAGE_CP), + .page_mask = BIT(ADV76XX_PAGE_IO) | BIT(ADV76XX_PAGE_CEC) | + BIT(ADV76XX_PAGE_INFOFRAME) | BIT(ADV76XX_PAGE_AFE) | + BIT(ADV76XX_PAGE_REP) | BIT(ADV76XX_PAGE_EDID) | + BIT(ADV76XX_PAGE_HDMI) | BIT(ADV76XX_PAGE_CP), }, }; -static struct i2c_device_id adv7604_i2c_id[] = { - { "adv7604", (kernel_ulong_t)&adv7604_chip_info[ADV7604] }, - { "adv7611", (kernel_ulong_t)&adv7604_chip_info[ADV7611] }, +static struct i2c_device_id adv76xx_i2c_id[] = { + { "adv7604", (kernel_ulong_t)&adv76xx_chip_info[ADV7604] }, + { "adv7611", (kernel_ulong_t)&adv76xx_chip_info[ADV7611] }, { } }; -MODULE_DEVICE_TABLE(i2c, adv7604_i2c_id); +MODULE_DEVICE_TABLE(i2c, adv76xx_i2c_id); -static struct of_device_id adv7604_of_id[] __maybe_unused = { - { .compatible = "adi,adv7611", .data = &adv7604_chip_info[ADV7611] }, +static struct of_device_id adv76xx_of_id[] __maybe_unused = { + { .compatible = "adi,adv7611", .data = &adv76xx_chip_info[ADV7611] }, { } }; -MODULE_DEVICE_TABLE(of, adv7604_of_id); +MODULE_DEVICE_TABLE(of, adv76xx_of_id); -static int adv7604_parse_dt(struct adv7604_state *state) +static int adv76xx_parse_dt(struct adv76xx_state *state) { struct v4l2_of_endpoint bus_cfg; struct device_node *endpoint; struct device_node *np; unsigned int flags; - np = state->i2c_clients[ADV7604_PAGE_IO]->dev.of_node; + np = state->i2c_clients[ADV76XX_PAGE_IO]->dev.of_node; /* Parse the endpoint. */ endpoint = of_graph_get_next_endpoint(np, NULL); @@ -2647,20 +2647,20 @@ static int adv7604_parse_dt(struct adv7604_state *state) } /* Disable the interrupt for now as no DT-based board uses it. */ - state->pdata.int1_config = ADV7604_INT1_CONFIG_DISABLED; + state->pdata.int1_config = ADV76XX_INT1_CONFIG_DISABLED; /* Use the default I2C addresses. */ state->pdata.i2c_addresses[ADV7604_PAGE_AVLINK] = 0x42; - state->pdata.i2c_addresses[ADV7604_PAGE_CEC] = 0x40; - state->pdata.i2c_addresses[ADV7604_PAGE_INFOFRAME] = 0x3e; + state->pdata.i2c_addresses[ADV76XX_PAGE_CEC] = 0x40; + state->pdata.i2c_addresses[ADV76XX_PAGE_INFOFRAME] = 0x3e; state->pdata.i2c_addresses[ADV7604_PAGE_ESDP] = 0x38; state->pdata.i2c_addresses[ADV7604_PAGE_DPP] = 0x3c; - state->pdata.i2c_addresses[ADV7604_PAGE_AFE] = 0x26; - state->pdata.i2c_addresses[ADV7604_PAGE_REP] = 0x32; - state->pdata.i2c_addresses[ADV7604_PAGE_EDID] = 0x36; - state->pdata.i2c_addresses[ADV7604_PAGE_HDMI] = 0x34; - state->pdata.i2c_addresses[ADV7604_PAGE_TEST] = 0x30; - state->pdata.i2c_addresses[ADV7604_PAGE_CP] = 0x22; + state->pdata.i2c_addresses[ADV76XX_PAGE_AFE] = 0x26; + state->pdata.i2c_addresses[ADV76XX_PAGE_REP] = 0x32; + state->pdata.i2c_addresses[ADV76XX_PAGE_EDID] = 0x36; + state->pdata.i2c_addresses[ADV76XX_PAGE_HDMI] = 0x34; + state->pdata.i2c_addresses[ADV76XX_PAGE_TEST] = 0x30; + state->pdata.i2c_addresses[ADV76XX_PAGE_CP] = 0x22; state->pdata.i2c_addresses[ADV7604_PAGE_VDP] = 0x24; /* Hardcode the remaining platform data fields. */ @@ -2675,12 +2675,12 @@ static int adv7604_parse_dt(struct adv7604_state *state) return 0; } -static int adv7604_probe(struct i2c_client *client, +static int adv76xx_probe(struct i2c_client *client, const struct i2c_device_id *id) { static const struct v4l2_dv_timings cea640x480 = V4L2_DV_BT_CEA_640X480P59_94; - struct adv7604_state *state; + struct adv76xx_state *state; struct v4l2_ctrl_handler *hdl; struct v4l2_subdev *sd; unsigned int i; @@ -2690,16 +2690,16 @@ static int adv7604_probe(struct i2c_client *client, /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - v4l_dbg(1, debug, client, "detecting adv7604 client on address 0x%x\n", + v4l_dbg(1, debug, client, "detecting adv76xx client on address 0x%x\n", client->addr << 1); state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); if (!state) { - v4l_err(client, "Could not allocate adv7604_state memory!\n"); + v4l_err(client, "Could not allocate adv76xx_state memory!\n"); return -ENOMEM; } - state->i2c_clients[ADV7604_PAGE_IO] = client; + state->i2c_clients[ADV76XX_PAGE_IO] = client; /* initialize variables */ state->restart_stdi_once = true; @@ -2708,18 +2708,18 @@ static int adv7604_probe(struct i2c_client *client, if (IS_ENABLED(CONFIG_OF) && client->dev.of_node) { const struct of_device_id *oid; - oid = of_match_node(adv7604_of_id, client->dev.of_node); + oid = of_match_node(adv76xx_of_id, client->dev.of_node); state->info = oid->data; - err = adv7604_parse_dt(state); + err = adv76xx_parse_dt(state); if (err < 0) { v4l_err(client, "DT parsing error\n"); return err; } } else if (client->dev.platform_data) { - struct adv7604_platform_data *pdata = client->dev.platform_data; + struct adv76xx_platform_data *pdata = client->dev.platform_data; - state->info = (const struct adv7604_chip_info *)id->driver_data; + state->info = (const struct adv76xx_chip_info *)id->driver_data; state->pdata = *pdata; } else { v4l_err(client, "No platform data!\n"); @@ -2739,10 +2739,10 @@ static int adv7604_probe(struct i2c_client *client, } state->timings = cea640x480; - state->format = adv7604_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); + state->format = adv76xx_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &adv7604_ops); + v4l2_i2c_subdev_init(sd, client, &adv76xx_ops); snprintf(sd->name, sizeof(sd->name), "%s %d-%04x", id->name, i2c_adapter_id(client->adapter), client->addr); @@ -2772,15 +2772,15 @@ static int adv7604_probe(struct i2c_client *client, /* control handlers */ hdl = &state->hdl; - v4l2_ctrl_handler_init(hdl, adv7604_has_afe(state) ? 9 : 8); + v4l2_ctrl_handler_init(hdl, adv76xx_has_afe(state) ? 9 : 8); - v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops, + v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops, V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); - v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops, + v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops, V4L2_CID_CONTRAST, 0, 255, 1, 128); - v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops, + v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops, V4L2_CID_SATURATION, 0, 255, 1, 128); - v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops, + v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops, V4L2_CID_HUE, 0, 128, 1, 0); /* private controls */ @@ -2788,18 +2788,18 @@ static int adv7604_probe(struct i2c_client *client, V4L2_CID_DV_RX_POWER_PRESENT, 0, (1 << state->info->num_dv_ports) - 1, 0, 0); state->rgb_quantization_range_ctrl = - v4l2_ctrl_new_std_menu(hdl, &adv7604_ctrl_ops, + v4l2_ctrl_new_std_menu(hdl, &adv76xx_ctrl_ops, V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, 0, V4L2_DV_RGB_RANGE_AUTO); /* custom controls */ - if (adv7604_has_afe(state)) + if (adv76xx_has_afe(state)) state->analog_sampling_phase_ctrl = v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_analog_sampling_phase, NULL); state->free_run_color_manual_ctrl = - v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_free_run_color_manual, NULL); + v4l2_ctrl_new_custom(hdl, &adv76xx_ctrl_free_run_color_manual, NULL); state->free_run_color_ctrl = - v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_free_run_color, NULL); + v4l2_ctrl_new_custom(hdl, &adv76xx_ctrl_free_run_color, NULL); sd->ctrl_handler = hdl; if (hdl->error) { @@ -2808,22 +2808,22 @@ static int adv7604_probe(struct i2c_client *client, } state->detect_tx_5v_ctrl->is_private = true; state->rgb_quantization_range_ctrl->is_private = true; - if (adv7604_has_afe(state)) + if (adv76xx_has_afe(state)) state->analog_sampling_phase_ctrl->is_private = true; state->free_run_color_manual_ctrl->is_private = true; state->free_run_color_ctrl->is_private = true; - if (adv7604_s_detect_tx_5v_ctrl(sd)) { + if (adv76xx_s_detect_tx_5v_ctrl(sd)) { err = -ENODEV; goto err_hdl; } - for (i = 1; i < ADV7604_PAGE_MAX; ++i) { + for (i = 1; i < ADV76XX_PAGE_MAX; ++i) { if (!(BIT(i) & state->info->page_mask)) continue; state->i2c_clients[i] = - adv7604_dummy_client(sd, state->pdata.i2c_addresses[i], + adv76xx_dummy_client(sd, state->pdata.i2c_addresses[i], 0xf2 + i); if (state->i2c_clients[i] == NULL) { err = -ENOMEM; @@ -2841,7 +2841,7 @@ static int adv7604_probe(struct i2c_client *client, } INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, - adv7604_delayed_work_enable_hotplug); + adv76xx_delayed_work_enable_hotplug); state->source_pad = state->info->num_dv_ports + (state->info->has_afe ? 2 : 0); @@ -2854,7 +2854,7 @@ static int adv7604_probe(struct i2c_client *client, if (err) goto err_work_queues; - err = adv7604_core_init(sd); + err = adv76xx_core_init(sd); if (err) goto err_entity; v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, @@ -2872,7 +2872,7 @@ err_work_queues: cancel_delayed_work(&state->delayed_work_enable_hotplug); destroy_workqueue(state->work_queues); err_i2c: - adv7604_unregister_clients(state); + adv76xx_unregister_clients(state); err_hdl: v4l2_ctrl_handler_free(hdl); return err; @@ -2880,32 +2880,32 @@ err_hdl: /* ----------------------------------------------------------------------- */ -static int adv7604_remove(struct i2c_client *client) +static int adv76xx_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); cancel_delayed_work(&state->delayed_work_enable_hotplug); destroy_workqueue(state->work_queues); v4l2_async_unregister_subdev(sd); v4l2_device_unregister_subdev(sd); media_entity_cleanup(&sd->entity); - adv7604_unregister_clients(to_state(sd)); + adv76xx_unregister_clients(to_state(sd)); v4l2_ctrl_handler_free(sd->ctrl_handler); return 0; } /* ----------------------------------------------------------------------- */ -static struct i2c_driver adv7604_driver = { +static struct i2c_driver adv76xx_driver = { .driver = { .owner = THIS_MODULE, .name = "adv7604", - .of_match_table = of_match_ptr(adv7604_of_id), + .of_match_table = of_match_ptr(adv76xx_of_id), }, - .probe = adv7604_probe, - .remove = adv7604_remove, - .id_table = adv7604_i2c_id, + .probe = adv76xx_probe, + .remove = adv76xx_remove, + .id_table = adv76xx_i2c_id, }; -module_i2c_driver(adv7604_driver); +module_i2c_driver(adv76xx_driver); diff --git a/include/media/adv7604.h b/include/media/adv7604.h index aa1c4477722d..9ecf353160c1 100644 --- a/include/media/adv7604.h +++ b/include/media/adv7604.h @@ -47,16 +47,16 @@ enum adv7604_bus_order { }; /* Input Color Space (IO register 0x02, [7:4]) */ -enum adv7604_inp_color_space { - ADV7604_INP_COLOR_SPACE_LIM_RGB = 0, - ADV7604_INP_COLOR_SPACE_FULL_RGB = 1, - ADV7604_INP_COLOR_SPACE_LIM_YCbCr_601 = 2, - ADV7604_INP_COLOR_SPACE_LIM_YCbCr_709 = 3, - ADV7604_INP_COLOR_SPACE_XVYCC_601 = 4, - ADV7604_INP_COLOR_SPACE_XVYCC_709 = 5, - ADV7604_INP_COLOR_SPACE_FULL_YCbCr_601 = 6, - ADV7604_INP_COLOR_SPACE_FULL_YCbCr_709 = 7, - ADV7604_INP_COLOR_SPACE_AUTO = 0xf, +enum adv76xx_inp_color_space { + ADV76XX_INP_COLOR_SPACE_LIM_RGB = 0, + ADV76XX_INP_COLOR_SPACE_FULL_RGB = 1, + ADV76XX_INP_COLOR_SPACE_LIM_YCbCr_601 = 2, + ADV76XX_INP_COLOR_SPACE_LIM_YCbCr_709 = 3, + ADV76XX_INP_COLOR_SPACE_XVYCC_601 = 4, + ADV76XX_INP_COLOR_SPACE_XVYCC_709 = 5, + ADV76XX_INP_COLOR_SPACE_FULL_YCbCr_601 = 6, + ADV76XX_INP_COLOR_SPACE_FULL_YCbCr_709 = 7, + ADV76XX_INP_COLOR_SPACE_AUTO = 0xf, }; /* Select output format (IO register 0x03, [4:2]) */ @@ -66,38 +66,39 @@ enum adv7604_op_format_mode_sel { ADV7604_OP_FORMAT_MODE2 = 0x08, }; -enum adv7604_drive_strength { - ADV7604_DR_STR_MEDIUM_LOW = 1, - ADV7604_DR_STR_MEDIUM_HIGH = 2, - ADV7604_DR_STR_HIGH = 3, +enum adv76xx_drive_strength { + ADV76XX_DR_STR_MEDIUM_LOW = 1, + ADV76XX_DR_STR_MEDIUM_HIGH = 2, + ADV76XX_DR_STR_HIGH = 3, }; -enum adv7604_int1_config { - ADV7604_INT1_CONFIG_OPEN_DRAIN, - ADV7604_INT1_CONFIG_ACTIVE_LOW, - ADV7604_INT1_CONFIG_ACTIVE_HIGH, - ADV7604_INT1_CONFIG_DISABLED, +/* INT1 Configuration (IO register 0x40, [1:0]) */ +enum adv76xx_int1_config { + ADV76XX_INT1_CONFIG_OPEN_DRAIN, + ADV76XX_INT1_CONFIG_ACTIVE_LOW, + ADV76XX_INT1_CONFIG_ACTIVE_HIGH, + ADV76XX_INT1_CONFIG_DISABLED, }; -enum adv7604_page { - ADV7604_PAGE_IO, +enum adv76xx_page { + ADV76XX_PAGE_IO, ADV7604_PAGE_AVLINK, - ADV7604_PAGE_CEC, - ADV7604_PAGE_INFOFRAME, + ADV76XX_PAGE_CEC, + ADV76XX_PAGE_INFOFRAME, ADV7604_PAGE_ESDP, ADV7604_PAGE_DPP, - ADV7604_PAGE_AFE, - ADV7604_PAGE_REP, - ADV7604_PAGE_EDID, - ADV7604_PAGE_HDMI, - ADV7604_PAGE_TEST, - ADV7604_PAGE_CP, + ADV76XX_PAGE_AFE, + ADV76XX_PAGE_REP, + ADV76XX_PAGE_EDID, + ADV76XX_PAGE_HDMI, + ADV76XX_PAGE_TEST, + ADV76XX_PAGE_CP, ADV7604_PAGE_VDP, - ADV7604_PAGE_MAX, + ADV76XX_PAGE_MAX, }; /* Platform dependent definition */ -struct adv7604_platform_data { +struct adv76xx_platform_data { /* DIS_PWRDNB: 1 if the PWRDNB pin is unused and unconnected */ unsigned disable_pwrdnb:1; @@ -116,7 +117,7 @@ struct adv7604_platform_data { enum adv7604_op_format_mode_sel op_format_mode_sel; /* Configuration of the INT1 pin */ - enum adv7604_int1_config int1_config; + enum adv76xx_int1_config int1_config; /* IO register 0x02 */ unsigned alt_gamma:1; @@ -134,9 +135,9 @@ struct adv7604_platform_data { unsigned inv_llc_pol:1; /* IO register 0x14 */ - enum adv7604_drive_strength dr_str_data; - enum adv7604_drive_strength dr_str_clk; - enum adv7604_drive_strength dr_str_sync; + enum adv76xx_drive_strength dr_str_data; + enum adv76xx_drive_strength dr_str_clk; + enum adv76xx_drive_strength dr_str_sync; /* IO register 0x30 */ unsigned output_bus_lsb_to_msb:1; @@ -145,11 +146,11 @@ struct adv7604_platform_data { unsigned hdmi_free_run_mode; /* i2c addresses: 0 == use default */ - u8 i2c_addresses[ADV7604_PAGE_MAX]; + u8 i2c_addresses[ADV76XX_PAGE_MAX]; }; -enum adv7604_pad { - ADV7604_PAD_HDMI_PORT_A = 0, +enum adv76xx_pad { + ADV76XX_PAD_HDMI_PORT_A = 0, ADV7604_PAD_HDMI_PORT_B = 1, ADV7604_PAD_HDMI_PORT_C = 2, ADV7604_PAD_HDMI_PORT_D = 3, @@ -158,7 +159,7 @@ enum adv7604_pad { /* The source pad is either 1 (ADV7611) or 6 (ADV7604) */ ADV7604_PAD_SOURCE = 6, ADV7611_PAD_SOURCE = 1, - ADV7604_PAD_MAX = 7, + ADV76XX_PAD_MAX = 7, }; #define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE (V4L2_CID_DV_CLASS_BASE + 0x1000) @@ -166,7 +167,7 @@ enum adv7604_pad { #define V4L2_CID_ADV_RX_FREE_RUN_COLOR (V4L2_CID_DV_CLASS_BASE + 0x1002) /* notify events */ -#define ADV7604_HOTPLUG 1 -#define ADV7604_FMT_CHANGE 2 +#define ADV76XX_HOTPLUG 1 +#define ADV76XX_FMT_CHANGE 2 #endif -- cgit v1.2.3 From 5cf6f7f327c95f09be859889be39e78950516556 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 17 Feb 2015 05:44:09 -0300 Subject: [media] v4l2-core: remove the old .ioctl BKL replacement To keep V4L2 drivers that did not yet convert to unlocked_ioctl happy, the v4l2 core had a .ioctl file operation that took a V4L2 lock. The last drivers are now converted to unlocked_ioctl, so all this old code can now be removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dev.c | 28 ---------------------------- drivers/media/v4l2-core/v4l2-device.c | 1 - include/media/v4l2-dev.h | 1 - include/media/v4l2-device.h | 2 -- 4 files changed, 32 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index d89d5cb465d9..9f4538ce09c2 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -357,34 +357,6 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); if (lock) mutex_unlock(lock); - } else if (vdev->fops->ioctl) { - /* This code path is a replacement for the BKL. It is a major - * hack but it will have to do for those drivers that are not - * yet converted to use unlocked_ioctl. - * - * All drivers implement struct v4l2_device, so we use the - * lock defined there to serialize the ioctls. - * - * However, if the driver sleeps, then it blocks all ioctls - * since the lock is still held. This is very common for - * VIDIOC_DQBUF since that normally waits for a frame to arrive. - * As a result any other ioctl calls will proceed very, very - * slowly since each call will have to wait for the VIDIOC_QBUF - * to finish. Things that should take 0.01s may now take 10-20 - * seconds. - * - * The workaround is to *not* take the lock for VIDIOC_DQBUF. - * This actually works OK for videobuf-based drivers, since - * videobuf will take its own internal lock. - */ - struct mutex *m = &vdev->v4l2_dev->ioctl_lock; - - if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m)) - return -ERESTARTSYS; - if (video_is_registered(vdev)) - ret = vdev->fops->ioctl(filp, cmd, arg); - if (cmd != VIDIOC_DQBUF) - mutex_unlock(m); } else ret = -ENOTTY; diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index 204cc67c84e8..5b0a30b9252b 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -37,7 +37,6 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) INIT_LIST_HEAD(&v4l2_dev->subdevs); spin_lock_init(&v4l2_dev->lock); - mutex_init(&v4l2_dev->ioctl_lock); v4l2_prio_init(&v4l2_dev->prio); kref_init(&v4l2_dev->ref); get_device(dev); diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 3e4fddfc840c..acbcd2f5fe7f 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -65,7 +65,6 @@ struct v4l2_file_operations { ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); unsigned int (*poll) (struct file *, struct poll_table_struct *); - long (*ioctl) (struct file *, unsigned int, unsigned long); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); #ifdef CONFIG_COMPAT long (*compat_ioctl32) (struct file *, unsigned int, unsigned long); diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index ffb69da3ce9e..9c581578783f 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -58,8 +58,6 @@ struct v4l2_device { struct v4l2_ctrl_handler *ctrl_handler; /* Device's priority state */ struct v4l2_prio_state prio; - /* BKL replacement mutex. Temporary solution only. */ - struct mutex ioctl_lock; /* Keep track of the references to this struct. */ struct kref ref; /* Release function that is called when the ref count goes to 0. */ -- cgit v1.2.3 From 2438e78a48643d41defd4b90da19d17b9c3e65f3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 3 Feb 2015 10:46:56 -0300 Subject: [media] v4l2-core: drop g/s_priority ops The handling of VIDIOC_G/S_PRIORITY is now entirely done by the V4L2 core, so we can drop the g/s_priority ioctl ops. We do have to make sure though that when S_PRIORITY is called we check that the driver used struct v4l2_fh. This check can be removed once all drivers are converted to that structure. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dev.c | 7 +++---- drivers/media/v4l2-core/v4l2-ioctl.c | 6 ++---- include/media/v4l2-ioctl.h | 6 ------ 3 files changed, 5 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 9f4538ce09c2..e2b8b3ed6ef3 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -532,10 +532,9 @@ static void determine_valid_ioctls(struct video_device *vdev) /* vfl_type and vfl_dir independent ioctls */ SET_VALID_IOCTL(ops, VIDIOC_QUERYCAP, vidioc_querycap); - if (ops->vidioc_g_priority) - set_bit(_IOC_NR(VIDIOC_G_PRIORITY), valid_ioctls); - if (ops->vidioc_s_priority) - set_bit(_IOC_NR(VIDIOC_S_PRIORITY), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_G_PRIORITY), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_S_PRIORITY), valid_ioctls); + /* Note: the control handler can also be passed through the filehandle, and that can't be tested here. If the bit for these control ioctls is set, then the ioctl is valid. But if it is 0, then it can still diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index b08407225db1..09ad8ddfaaf9 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1046,8 +1046,6 @@ static int v4l_g_priority(const struct v4l2_ioctl_ops *ops, struct video_device *vfd; u32 *p = arg; - if (ops->vidioc_g_priority) - return ops->vidioc_g_priority(file, fh, arg); vfd = video_devdata(file); *p = v4l2_prio_max(vfd->prio); return 0; @@ -1060,9 +1058,9 @@ static int v4l_s_priority(const struct v4l2_ioctl_ops *ops, struct v4l2_fh *vfh; u32 *p = arg; - if (ops->vidioc_s_priority) - return ops->vidioc_s_priority(file, fh, *p); vfd = video_devdata(file); + if (!test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) + return -ENOTTY; vfh = file->private_data; return v4l2_prio_change(vfd->prio, &vfh->prio, *p); } diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 8537983b9b22..8fbbd76d78e8 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -23,12 +23,6 @@ struct v4l2_ioctl_ops { /* VIDIOC_QUERYCAP handler */ int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap); - /* Priority handling */ - int (*vidioc_g_priority) (struct file *file, void *fh, - enum v4l2_priority *p); - int (*vidioc_s_priority) (struct file *file, void *fh, - enum v4l2_priority p); - /* VIDIOC_ENUM_FMT handlers */ int (*vidioc_enum_fmt_vid_cap) (struct file *file, void *fh, struct v4l2_fmtdesc *f); -- cgit v1.2.3 From 4d0b0bd4385f0ce8d3b430f9667c5e2ca1de10af Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 5 Feb 2015 17:47:25 +0800 Subject: f2fs: simplfy a field name in struct f2fs_extent,extent_info Rename a filed name from 'blk_addr' to 'blk' in struct {f2fs_extent,extent_info} as annotation of this field descripts its meaning well to us. By this way, we can avoid long statement in code of following patches. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 13 ++++++------- fs/f2fs/f2fs.h | 6 +++--- include/linux/f2fs_fs.h | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 0811d6509fce..64f9049a9f25 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -268,7 +268,7 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs, start_fofs = fi->ext.fofs; end_fofs = fi->ext.fofs + fi->ext.len - 1; - start_blkaddr = fi->ext.blk_addr; + start_blkaddr = fi->ext.blk; if (pgofs >= start_fofs && pgofs <= end_fofs) { unsigned int blkbits = inode->i_sb->s_blocksize_bits; @@ -313,8 +313,8 @@ void update_extent_cache(struct dnode_of_data *dn) start_fofs = fi->ext.fofs; end_fofs = fi->ext.fofs + fi->ext.len - 1; - start_blkaddr = fi->ext.blk_addr; - end_blkaddr = fi->ext.blk_addr + fi->ext.len - 1; + start_blkaddr = fi->ext.blk; + end_blkaddr = fi->ext.blk + fi->ext.len - 1; /* Drop and initialize the matched extent */ if (fi->ext.len == 1 && fofs == start_fofs) @@ -324,7 +324,7 @@ void update_extent_cache(struct dnode_of_data *dn) if (fi->ext.len == 0) { if (dn->data_blkaddr != NULL_ADDR) { fi->ext.fofs = fofs; - fi->ext.blk_addr = dn->data_blkaddr; + fi->ext.blk = dn->data_blkaddr; fi->ext.len = 1; } goto end_update; @@ -333,7 +333,7 @@ void update_extent_cache(struct dnode_of_data *dn) /* Front merge */ if (fofs == start_fofs - 1 && dn->data_blkaddr == start_blkaddr - 1) { fi->ext.fofs--; - fi->ext.blk_addr--; + fi->ext.blk--; fi->ext.len++; goto end_update; } @@ -351,8 +351,7 @@ void update_extent_cache(struct dnode_of_data *dn) fi->ext.len = fofs - start_fofs; } else { fi->ext.fofs = fofs + 1; - fi->ext.blk_addr = start_blkaddr + - fofs - start_fofs + 1; + fi->ext.blk = start_blkaddr + fofs - start_fofs + 1; fi->ext.len -= fofs - start_fofs + 1; } } else { diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index c3caa3cb5beb..5d2e52e31fac 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -278,7 +278,7 @@ enum { struct extent_info { unsigned int fofs; /* start offset in a file */ - u32 blk_addr; /* start block address of the extent */ + u32 blk; /* start block address of the extent */ unsigned int len; /* length of the extent */ }; @@ -320,7 +320,7 @@ static inline void get_extent_info(struct extent_info *ext, struct f2fs_extent i_ext) { ext->fofs = le32_to_cpu(i_ext.fofs); - ext->blk_addr = le32_to_cpu(i_ext.blk_addr); + ext->blk = le32_to_cpu(i_ext.blk); ext->len = le32_to_cpu(i_ext.len); } @@ -328,7 +328,7 @@ static inline void set_raw_extent(struct extent_info *ext, struct f2fs_extent *i_ext) { i_ext->fofs = cpu_to_le32(ext->fofs); - i_ext->blk_addr = cpu_to_le32(ext->blk_addr); + i_ext->blk = cpu_to_le32(ext->blk); i_ext->len = cpu_to_le32(ext->len); } diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index a23556c32703..502f28cfb78e 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -153,7 +153,7 @@ struct f2fs_orphan_block { */ struct f2fs_extent { __le32 fofs; /* start file offset of the extent */ - __le32 blk_addr; /* start block address of the extent */ + __le32 blk; /* start block address of the extent */ __le32 len; /* lengh of the extent */ } __packed; -- cgit v1.2.3 From 1ec4610c522cc51219cc022ef120a928828fa934 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 5 Feb 2015 17:59:59 +0800 Subject: f2fs: add trace for rb-tree extent cache ops This patch adds trace for lookup/update/shrink/destroy ops in rb-tree extent cache. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 16 +++++- include/trace/events/f2fs.h | 134 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index acdc0767f77c..d7ff4ca5be18 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -533,6 +533,8 @@ static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs, if (is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT)) return false; + trace_f2fs_lookup_extent_tree_start(inode, pgofs); + down_read(&sbi->extent_tree_lock); et = radix_tree_lookup(&sbi->extent_tree_root, inode->i_ino); if (!et) { @@ -555,6 +557,8 @@ static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs, stat_inc_total_hit(sbi->sb); read_unlock(&et->lock); + trace_f2fs_lookup_extent_tree_end(inode, pgofs, en); + atomic_dec(&et->refcount); return en ? true : false; } @@ -573,6 +577,8 @@ static void f2fs_update_extent_tree(struct inode *inode, pgoff_t fofs, if (is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT)) return; + trace_f2fs_update_extent_tree(inode, fofs, blkaddr); + down_write(&sbi->extent_tree_lock); et = radix_tree_lookup(&sbi->extent_tree_root, ino); if (!et) { @@ -665,6 +671,7 @@ void f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) struct radix_tree_iter iter; void **slot; unsigned int found; + unsigned int node_cnt = 0, tree_cnt = 0; if (!test_opt(sbi, EXTENT_CACHE)) return; @@ -691,7 +698,7 @@ void f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) atomic_inc(&et->refcount); write_lock(&et->lock); - __free_extent_tree(sbi, et, false); + node_cnt += __free_extent_tree(sbi, et, false); write_unlock(&et->lock); atomic_dec(&et->refcount); } @@ -707,15 +714,19 @@ void f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) radix_tree_delete(&sbi->extent_tree_root, et->ino); kmem_cache_free(extent_tree_slab, et); sbi->total_ext_tree--; + tree_cnt++; } } up_write(&sbi->extent_tree_lock); + + trace_f2fs_shrink_extent_tree(sbi, node_cnt, tree_cnt); } void f2fs_destroy_extent_tree(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct extent_tree *et; + unsigned int node_cnt = 0; if (!test_opt(sbi, EXTENT_CACHE)) return; @@ -731,7 +742,7 @@ void f2fs_destroy_extent_tree(struct inode *inode) /* free all extent info belong to this extent tree */ write_lock(&et->lock); - __free_extent_tree(sbi, et, true); + node_cnt = __free_extent_tree(sbi, et, true); write_unlock(&et->lock); atomic_dec(&et->refcount); @@ -749,6 +760,7 @@ void f2fs_destroy_extent_tree(struct inode *inode) sbi->total_ext_tree--; up_write(&sbi->extent_tree_lock); out: + trace_f2fs_destroy_extent_tree(inode, node_cnt); return; } diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 5422dbfaf97d..09a56dc75f8d 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -1011,6 +1011,140 @@ TRACE_EVENT(f2fs_issue_flush, __entry->nobarrier ? "skip (nobarrier)" : "issue", __entry->flush_merge ? " with flush_merge" : "") ); + +TRACE_EVENT(f2fs_lookup_extent_tree_start, + + TP_PROTO(struct inode *inode, unsigned int pgofs), + + TP_ARGS(inode, pgofs), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(unsigned int, pgofs) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->pgofs = pgofs; + ), + + TP_printk("dev = (%d,%d), ino = %lu, pgofs = %u", + show_dev_ino(__entry), + __entry->pgofs) +); + +TRACE_EVENT_CONDITION(f2fs_lookup_extent_tree_end, + + TP_PROTO(struct inode *inode, unsigned int pgofs, + struct extent_node *en), + + TP_ARGS(inode, pgofs, en), + + TP_CONDITION(en), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(unsigned int, pgofs) + __field(unsigned int, fofs) + __field(u32, blk) + __field(unsigned int, len) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->pgofs = pgofs; + __entry->fofs = en->ei.fofs; + __entry->blk = en->ei.blk; + __entry->len = en->ei.len; + ), + + TP_printk("dev = (%d,%d), ino = %lu, pgofs = %u, " + "ext_info(fofs: %u, blk: %u, len: %u)", + show_dev_ino(__entry), + __entry->pgofs, + __entry->fofs, + __entry->blk, + __entry->len) +); + +TRACE_EVENT(f2fs_update_extent_tree, + + TP_PROTO(struct inode *inode, unsigned int pgofs, block_t blkaddr), + + TP_ARGS(inode, pgofs, blkaddr), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(unsigned int, pgofs) + __field(u32, blk) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->pgofs = pgofs; + __entry->blk = blkaddr; + ), + + TP_printk("dev = (%d,%d), ino = %lu, pgofs = %u, blkaddr = %u", + show_dev_ino(__entry), + __entry->pgofs, + __entry->blk) +); + +TRACE_EVENT(f2fs_shrink_extent_tree, + + TP_PROTO(struct f2fs_sb_info *sbi, unsigned int node_cnt, + unsigned int tree_cnt), + + TP_ARGS(sbi, node_cnt, tree_cnt), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(unsigned int, node_cnt) + __field(unsigned int, tree_cnt) + ), + + TP_fast_assign( + __entry->dev = sbi->sb->s_dev; + __entry->node_cnt = node_cnt; + __entry->tree_cnt = tree_cnt; + ), + + TP_printk("dev = (%d,%d), shrunk: node_cnt = %u, tree_cnt = %u", + show_dev(__entry), + __entry->node_cnt, + __entry->tree_cnt) +); + +TRACE_EVENT(f2fs_destroy_extent_tree, + + TP_PROTO(struct inode *inode, unsigned int node_cnt), + + TP_ARGS(inode, node_cnt), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(unsigned int, node_cnt) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->node_cnt = node_cnt; + ), + + TP_printk("dev = (%d,%d), ino = %lu, destroyed: node_cnt = %u", + show_dev_ino(__entry), + __entry->node_cnt) +); + #endif /* _TRACE_F2FS_H */ /* This part must be outside protection */ -- cgit v1.2.3 From 112bdfaa525fd5993e17885861342893f15290b0 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 16 Feb 2015 15:41:02 +0000 Subject: extcon: arizona: Deobfuscate arizona_extcon_do_magic arizona_extcon_do_magic does not lend a lot of clarity to the purpose of the function, and as all the registers used are described in the datasheet there is no need to obfuscate the code. This patch renames the function to arizona_extcon_hp_clamp, as it controls clamping on the headphone output. Signed-off-by: Charles Keepax Acked-by: Lee Jones Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 36 ++++++++++++++++++++---------------- include/linux/mfd/arizona/core.h | 2 +- sound/soc/codecs/arizona.c | 4 ++-- 3 files changed, 23 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 63f01c42aed4..95cf7f875bb3 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -136,18 +136,22 @@ static const char *arizona_cable[] = { static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info); -static void arizona_extcon_do_magic(struct arizona_extcon_info *info, - unsigned int magic) +static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, + bool clamp) { struct arizona *arizona = info->arizona; + unsigned int val = 0; int ret; + if (clamp) + val = ARIZONA_RMV_SHRT_HP1L; + mutex_lock(&arizona->dapm->card->dapm_mutex); - arizona->hpdet_magic = magic; + arizona->hpdet_clamp = clamp; - /* Keep the HP output stages disabled while doing the magic */ - if (magic) { + /* Keep the HP output stages disabled while doing the clamp */ + if (clamp) { ret = regmap_update_bits(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT1L_ENA | @@ -158,20 +162,20 @@ static void arizona_extcon_do_magic(struct arizona_extcon_info *info, ret); } - ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, - magic); + ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L, + ARIZONA_RMV_SHRT_HP1L, val); if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", + dev_warn(arizona->dev, "Failed to do clamp: %d\n", ret); - ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, - magic); + ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R, + ARIZONA_RMV_SHRT_HP1R, val); if (ret != 0) - dev_warn(arizona->dev, "Failed to do magic: %d\n", + dev_warn(arizona->dev, "Failed to do clamp: %d\n", ret); - /* Restore the desired state while not doing the magic */ - if (!magic) { + /* Restore the desired state while not doing the clamp */ + if (!clamp) { ret = regmap_update_bits(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT1L_ENA | @@ -603,7 +607,7 @@ done: ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL, 0); - arizona_extcon_do_magic(info, 0); + arizona_extcon_hp_clamp(info, false); if (id_gpio) gpio_set_value_cansleep(id_gpio, 0); @@ -648,7 +652,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) if (info->mic) arizona_stop_mic(info); - arizona_extcon_do_magic(info, 0x4000); + arizona_extcon_hp_clamp(info, true); ret = regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, @@ -699,7 +703,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) info->hpdet_active = true; - arizona_extcon_do_magic(info, 0x4000); + arizona_extcon_hp_clamp(info, true); ret = regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h index 910e3aa1e965..4863548faff7 100644 --- a/include/linux/mfd/arizona/core.h +++ b/include/linux/mfd/arizona/core.h @@ -126,7 +126,7 @@ struct arizona { struct regmap_irq_chip_data *aod_irq_chip; struct regmap_irq_chip_data *irq_chip; - bool hpdet_magic; + bool hpdet_clamp; unsigned int hp_ena; struct mutex clk_lock; diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 29202610dd0d..fb58c7ee3780 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -840,8 +840,8 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w, priv->arizona->hp_ena &= ~mask; priv->arizona->hp_ena |= val; - /* Force off if HPDET magic is active */ - if (priv->arizona->hpdet_magic) + /* Force off if HPDET clamp is active */ + if (priv->arizona->hpdet_clamp) val = 0; regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, -- cgit v1.2.3 From e921eea8e7d4457f424bc3f821cb836e35b91f88 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 3 Mar 2015 12:05:00 +0100 Subject: dmaengine: Remove memset leftovers Commit 48a9db462d99 ("drivers/dma: remove unused support for MEMSET operations") removed support for the memset operation in dmaengine, but left the fill_aligned field that was supposed to set the buffer alignment for the memset operations. Remove that field too. Signed-off-by: Maxime Ripard Signed-off-by: Vinod Koul --- include/linux/dmaengine.h | 8 -------- 1 file changed, 8 deletions(-) (limited to 'include') diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index b6997a0cb528..db0104b0da4d 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -574,7 +574,6 @@ struct dma_tx_state { * @copy_align: alignment shift for memcpy operations * @xor_align: alignment shift for xor operations * @pq_align: alignment shift for pq operations - * @fill_align: alignment shift for memset operations * @dev_id: unique device ID * @dev: struct device reference for dma mapping api * @src_addr_widths: bit mask of src addr widths the device supports @@ -625,7 +624,6 @@ struct dma_device { u8 copy_align; u8 xor_align; u8 pq_align; - u8 fill_align; #define DMA_HAS_PQ_CONTINUE (1 << 15) int dev_id; @@ -826,12 +824,6 @@ static inline bool is_dma_pq_aligned(struct dma_device *dev, size_t off1, return dmaengine_check_align(dev->pq_align, off1, off2, len); } -static inline bool is_dma_fill_aligned(struct dma_device *dev, size_t off1, - size_t off2, size_t len) -{ - return dmaengine_check_align(dev->fill_align, off1, off2, len); -} - static inline void dma_set_maxpq(struct dma_device *dma, int maxpq, int has_pq_continue) { -- cgit v1.2.3 From 1feb57a245a4910b03202a814ffc51a900bd4aca Mon Sep 17 00:00:00 2001 From: Olliver Schinagl Date: Wed, 21 Jan 2015 22:33:46 +0100 Subject: gpio: add parameter to allow the use named gpios The gpio binding document says that new code should always use named gpios. Patch 40b73183 added support to parse a list of gpios from child nodes, but does not make it possible to use named gpios. This patch adds the con_id property and implements it is done in gpiolib.c, where the old-style of using unnamed gpios still works. Signed-off-by: Olliver Schinagl Acked-by: Bryan Wu Acked-by: Dmitry Torokhov Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/devres.c | 18 +++++++++++++++++- drivers/input/keyboard/gpio_keys_polled.c | 2 +- drivers/leds/leds-gpio.c | 2 +- include/linux/gpio/consumer.h | 1 + 4 files changed, 20 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 13dbd3dfc33a..12c2082f968e 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -111,23 +111,39 @@ EXPORT_SYMBOL(__devm_gpiod_get_index); /** * devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node * @dev: GPIO consumer + * @con_id: function within the GPIO consumer * @child: firmware node (child of @dev) * * GPIO descriptors returned from this function are automatically disposed on * driver detach. */ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, + const char *con_id, struct fwnode_handle *child) { + static const char const *suffixes[] = { "gpios", "gpio" }; + char prop_name[32]; /* 32 is max size of property name */ struct gpio_desc **dr; struct gpio_desc *desc; + unsigned int i; dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *), GFP_KERNEL); if (!dr) return ERR_PTR(-ENOMEM); - desc = fwnode_get_named_gpiod(child, "gpios"); + for (i = 0; i < ARRAY_SIZE(suffixes); i++) { + if (con_id) + snprintf(prop_name, sizeof(prop_name), "%s-%s", + con_id, suffixes[i]); + else + snprintf(prop_name, sizeof(prop_name), "%s", + suffixes[i]); + + desc = fwnode_get_named_gpiod(child, prop_name); + if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER)) + break; + } if (IS_ERR(desc)) { devres_free(dr); return desc; diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 90df4df58b07..097d7216d98e 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -125,7 +125,7 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device_for_each_child_node(dev, child) { struct gpio_desc *desc; - desc = devm_get_gpiod_from_child(dev, child); + desc = devm_get_gpiod_from_child(dev, NULL, child); if (IS_ERR(desc)) { error = PTR_ERR(desc); if (error != -EPROBE_DEFER) diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index d26af0a79a90..15eb3f86f670 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -184,7 +184,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) struct gpio_led led = {}; const char *state = NULL; - led.gpiod = devm_get_gpiod_from_child(dev, child); + led.gpiod = devm_get_gpiod_from_child(dev, NULL, child); if (IS_ERR(led.gpiod)) { fwnode_handle_put(child); ret = PTR_ERR(led.gpiod); diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 45afc2dee560..ed20759229eb 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -110,6 +110,7 @@ struct fwnode_handle; struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, const char *propname); struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, + const char *con_id, struct fwnode_handle *child); #else /* CONFIG_GPIOLIB */ -- cgit v1.2.3 From d136dfeec84bfe3e4238bacd23f21e161268deac Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 3 Mar 2015 14:22:31 +0000 Subject: drm: Pass in new and old plane state to prepare_fb and cleanup_fb Use cases like rotation require these hooks to have some context so they know how to prepare and cleanup the frame buffer correctly. For i915 specifically, object backing pages need to be mapped differently for different rotation modes and the driver needs to know which mapping to instantiate and which to tear down when transitioning between them. v2: Made passed in states const. (Daniel Vetter) [airlied: add mdp5 and atmel fixups] Signed-off-by: Tvrtko Ursulin Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Reviewed-by: Rob Clark Signed-off-by: Dave Airlie --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 3 ++- drivers/gpu/drm/drm_atomic_helper.c | 13 ++++++++----- drivers/gpu/drm/drm_plane_helper.c | 5 +++-- drivers/gpu/drm/i915/intel_display.c | 6 ++++-- drivers/gpu/drm/i915/intel_drv.h | 6 ++++-- drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c | 6 ++++-- drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 6 ++++-- drivers/gpu/drm/tegra/dc.c | 6 ++++-- include/drm/drm_plane_helper.h | 6 ++++-- 9 files changed, 37 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index dbf97d999d40..be9fa8220499 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -712,7 +712,8 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, } static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p, - struct drm_framebuffer *fb) + struct drm_framebuffer *fb, + const struct drm_plane_state *new_state) { struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 28aa87510551..7715c40d4e74 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1116,6 +1116,7 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev, for (i = 0; i < nplanes; i++) { struct drm_plane_helper_funcs *funcs; struct drm_plane *plane = state->planes[i]; + struct drm_plane_state *plane_state = state->plane_states[i]; struct drm_framebuffer *fb; if (!plane) @@ -1123,10 +1124,10 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev, funcs = plane->helper_private; - fb = state->plane_states[i]->fb; + fb = plane_state->fb; if (fb && funcs->prepare_fb) { - ret = funcs->prepare_fb(plane, fb); + ret = funcs->prepare_fb(plane, fb, plane_state); if (ret) goto fail; } @@ -1138,6 +1139,7 @@ fail: for (i--; i >= 0; i--) { struct drm_plane_helper_funcs *funcs; struct drm_plane *plane = state->planes[i]; + struct drm_plane_state *plane_state = state->plane_states[i]; struct drm_framebuffer *fb; if (!plane) @@ -1148,7 +1150,7 @@ fail: fb = state->plane_states[i]->fb; if (fb && funcs->cleanup_fb) - funcs->cleanup_fb(plane, fb); + funcs->cleanup_fb(plane, fb, plane_state); } @@ -1254,6 +1256,7 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev, for (i = 0; i < nplanes; i++) { struct drm_plane_helper_funcs *funcs; struct drm_plane *plane = old_state->planes[i]; + struct drm_plane_state *plane_state = old_state->plane_states[i]; struct drm_framebuffer *old_fb; if (!plane) @@ -1261,10 +1264,10 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev, funcs = plane->helper_private; - old_fb = old_state->plane_states[i]->fb; + old_fb = plane_state->fb; if (old_fb && funcs->cleanup_fb) - funcs->cleanup_fb(plane, old_fb); + funcs->cleanup_fb(plane, old_fb, plane_state); } } EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes); diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 5ba5792bfdba..813a06627eb3 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -437,7 +437,8 @@ int drm_plane_helper_commit(struct drm_plane *plane, if (plane_funcs->prepare_fb && plane_state->fb && plane_state->fb != old_fb) { - ret = plane_funcs->prepare_fb(plane, plane_state->fb); + ret = plane_funcs->prepare_fb(plane, plane_state->fb, + plane_state); if (ret) goto out; } @@ -487,7 +488,7 @@ int drm_plane_helper_commit(struct drm_plane *plane, } if (plane_funcs->cleanup_fb && old_fb) - plane_funcs->cleanup_fb(plane, old_fb); + plane_funcs->cleanup_fb(plane, old_fb, plane_state); out: if (plane_state) { if (plane->funcs->atomic_destroy_state) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3b0fe9f1f3c9..c234af0379fc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11776,7 +11776,8 @@ static void intel_shared_dpll_init(struct drm_device *dev) */ int intel_prepare_plane_fb(struct drm_plane *plane, - struct drm_framebuffer *fb) + struct drm_framebuffer *fb, + const struct drm_plane_state *new_state) { struct drm_device *dev = plane->dev; struct intel_plane *intel_plane = to_intel_plane(plane); @@ -11830,7 +11831,8 @@ intel_prepare_plane_fb(struct drm_plane *plane, */ void intel_cleanup_plane_fb(struct drm_plane *plane, - struct drm_framebuffer *fb) + struct drm_framebuffer *fb, + const struct drm_plane_state *old_state) { struct drm_device *dev = plane->dev; struct drm_i915_gem_object *obj = intel_fb_obj(fb); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1de8e20474d7..58d11a8066d4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -943,9 +943,11 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe); void intel_finish_page_flip_plane(struct drm_device *dev, int plane); void intel_check_page_flip(struct drm_device *dev, int pipe); int intel_prepare_plane_fb(struct drm_plane *plane, - struct drm_framebuffer *fb); + struct drm_framebuffer *fb, + const struct drm_plane_state *new_state); void intel_cleanup_plane_fb(struct drm_plane *plane, - struct drm_framebuffer *fb); + struct drm_framebuffer *fb, + const struct drm_plane_state *old_state); int intel_plane_atomic_get_property(struct drm_plane *plane, const struct drm_plane_state *state, struct drm_property *property, diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c index cde25009203a..dbc068988377 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c @@ -83,7 +83,8 @@ static const struct drm_plane_funcs mdp4_plane_funcs = { }; static int mdp4_plane_prepare_fb(struct drm_plane *plane, - struct drm_framebuffer *fb) + struct drm_framebuffer *fb, + const struct drm_plane_state *new_state) { struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); struct mdp4_kms *mdp4_kms = get_kms(plane); @@ -93,7 +94,8 @@ static int mdp4_plane_prepare_fb(struct drm_plane *plane, } static void mdp4_plane_cleanup_fb(struct drm_plane *plane, - struct drm_framebuffer *fb) + struct drm_framebuffer *fb, + const struct drm_plane_state *old_state) { struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); struct mdp4_kms *mdp4_kms = get_kms(plane); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 05cf9ab2a876..6bd48e246283 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -156,7 +156,8 @@ static const struct drm_plane_funcs mdp5_plane_funcs = { }; static int mdp5_plane_prepare_fb(struct drm_plane *plane, - struct drm_framebuffer *fb) + struct drm_framebuffer *fb, + const struct drm_plane_state *new_state) { struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); struct mdp5_kms *mdp5_kms = get_kms(plane); @@ -166,7 +167,8 @@ static int mdp5_plane_prepare_fb(struct drm_plane *plane, } static void mdp5_plane_cleanup_fb(struct drm_plane *plane, - struct drm_framebuffer *fb) + struct drm_framebuffer *fb, + const struct drm_plane_state *old_state) { struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); struct mdp5_kms *mdp5_kms = get_kms(plane); diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 3aaa84ae2681..bc3e85186b88 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -472,13 +472,15 @@ static const struct drm_plane_funcs tegra_primary_plane_funcs = { }; static int tegra_plane_prepare_fb(struct drm_plane *plane, - struct drm_framebuffer *fb) + struct drm_framebuffer *fb, + const struct drm_plane_state *new_state) { return 0; } static void tegra_plane_cleanup_fb(struct drm_plane *plane, - struct drm_framebuffer *fb) + struct drm_framebuffer *fb, + const struct drm_plane_state *old_fb) { } diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index 31c11d36fae6..72ddab02ebd9 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -59,9 +59,11 @@ extern int drm_crtc_init(struct drm_device *dev, */ struct drm_plane_helper_funcs { int (*prepare_fb)(struct drm_plane *plane, - struct drm_framebuffer *fb); + struct drm_framebuffer *fb, + const struct drm_plane_state *new_state); void (*cleanup_fb)(struct drm_plane *plane, - struct drm_framebuffer *fb); + struct drm_framebuffer *fb, + const struct drm_plane_state *old_state); int (*atomic_check)(struct drm_plane *plane, struct drm_plane_state *state); -- cgit v1.2.3 From 9941a383df98193aa9a9b3662af7c1fcbc3070ee Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 5 Mar 2015 10:49:19 +1030 Subject: CPU_MASK_ALL/CPU_MASK_NONE: remove from deprecated region. They're used to initialize various static fields, though static cpumasks should generally be avoided. Signed-off-by: Rusty Russell --- include/linux/cpumask.h | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 086549a665e2..dc037ae6f4f2 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -768,7 +768,7 @@ static inline const struct cpumask *get_cpu_mask(unsigned int cpu) #if NR_CPUS <= BITS_PER_LONG #define CPU_BITS_ALL \ { \ - [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \ + [BITS_TO_LONGS(NR_CPUS)-1] = BITMAP_LAST_WORD_MASK(NR_CPUS) \ } #else /* NR_CPUS > BITS_PER_LONG */ @@ -776,7 +776,7 @@ static inline const struct cpumask *get_cpu_mask(unsigned int cpu) #define CPU_BITS_ALL \ { \ [0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL, \ - [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \ + [BITS_TO_LONGS(NR_CPUS)-1] = BITMAP_LAST_WORD_MASK(NR_CPUS) \ } #endif /* NR_CPUS > BITS_PER_LONG */ @@ -797,38 +797,31 @@ cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask) nr_cpu_ids); } -/* - * - * From here down, all obsolete. Use cpumask_ variants! - * - */ -#ifndef CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS -#define cpumask_of_cpu(cpu) (*get_cpu_mask(cpu)) - -#define CPU_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(NR_CPUS) - #if NR_CPUS <= BITS_PER_LONG - #define CPU_MASK_ALL \ (cpumask_t) { { \ - [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \ + [BITS_TO_LONGS(NR_CPUS)-1] = BITMAP_LAST_WORD_MASK(NR_CPUS) \ } } - #else - #define CPU_MASK_ALL \ (cpumask_t) { { \ [0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL, \ - [BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \ + [BITS_TO_LONGS(NR_CPUS)-1] = BITMAP_LAST_WORD_MASK(NR_CPUS) \ } } - -#endif +#endif /* NR_CPUS > BITS_PER_LONG */ #define CPU_MASK_NONE \ (cpumask_t) { { \ [0 ... BITS_TO_LONGS(NR_CPUS)-1] = 0UL \ } } +/* + * + * From here down, all obsolete. Use cpumask_ variants! + * + */ +#ifndef CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS + #define CPU_MASK_CPU0 \ (cpumask_t) { { \ [0] = 1UL \ -- cgit v1.2.3 From 668585273246f67b0cdafa30dd2da2047a2e1290 Mon Sep 17 00:00:00 2001 From: Rojhalat Ibrahim Date: Wed, 11 Feb 2015 17:27:58 +0100 Subject: gpiolib: add gpiod_get_array and gpiod_put_array functions Introduce new functions for conveniently obtaining and disposing of an entire array of GPIOs with one function call. ACPI parts tested by Mika Westerberg, DT parts tested by Rojhalat Ibrahim. Change log: v5: move the ACPI functions to gpiolib-acpi.c v4: - use shorter names for members of struct gpio_descs - rename lut_gpio_count to platform_gpio_count for clarity - add check for successful memory allocation - use ERR_CAST() v3: - rebase on current linux-gpio devel branch - fix ACPI GPIO counting - allow for zero-sized arrays - make the flags argument mandatory for the new functions - clarify documentation v2: change interface Suggested-by: Alexandre Courbot Signed-off-by: Rojhalat Ibrahim Reviewed-by: Alexandre Courbot Reviewed-by: Mika Westerberg Tested-by: Mika Westerberg Tested-by: Rojhalat Ibrahim Signed-off-by: Linus Walleij --- Documentation/gpio/consumer.txt | 33 ++++++++- drivers/gpio/gpiolib-acpi.c | 84 +++++++++++++++++++++++ drivers/gpio/gpiolib.c | 145 ++++++++++++++++++++++++++++++++++++++++ drivers/gpio/gpiolib.h | 7 ++ include/linux/gpio/consumer.h | 46 +++++++++++++ 5 files changed, 312 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index d85fbae451ea..2924f2ffcd91 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -58,7 +58,6 @@ pattern where a GPIO is optional, the gpiod_get_optional() and gpiod_get_index_optional() functions can be used. These functions return NULL instead of -ENOENT if no GPIO has been assigned to the requested function: - struct gpio_desc *gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags) @@ -68,6 +67,27 @@ instead of -ENOENT if no GPIO has been assigned to the requested function: unsigned int index, enum gpiod_flags flags) +For a function using multiple GPIOs all of those can be obtained with one call: + + struct gpio_descs *gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags) + +This function returns a struct gpio_descs which contains an array of +descriptors: + + struct gpio_descs { + unsigned int ndescs; + struct gpio_desc *desc[]; + } + +The following function returns NULL instead of -ENOENT if no GPIOs have been +assigned to the requested function: + + struct gpio_descs *gpiod_get_array_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags) + Device-managed variants of these functions are also defined: struct gpio_desc *devm_gpiod_get(struct device *dev, const char *con_id, @@ -91,8 +111,15 @@ A GPIO descriptor can be disposed of using the gpiod_put() function: void gpiod_put(struct gpio_desc *desc) -It is strictly forbidden to use a descriptor after calling this function. The -device-managed variant is, unsurprisingly: +For an array of GPIOs this function can be used: + + void gpiod_put_array(struct gpio_descs *descs) + +It is strictly forbidden to use a descriptor after calling these functions. +It is also not allowed to individually release descriptors (using gpiod_put()) +from an array acquired with gpiod_get_array(). + +The device-managed variant is, unsurprisingly: void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index c0929d938ced..c4919966453d 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -712,3 +712,87 @@ void acpi_gpiochip_remove(struct gpio_chip *chip) acpi_detach_data(handle, acpi_gpio_chip_dh); kfree(acpi_gpio); } + +static unsigned int acpi_gpio_package_count(const union acpi_object *obj) +{ + const union acpi_object *element = obj->package.elements; + const union acpi_object *end = element + obj->package.count; + unsigned int count = 0; + + while (element < end) { + if (element->type == ACPI_TYPE_LOCAL_REFERENCE) + count++; + + element++; + } + return count; +} + +static int acpi_find_gpio_count(struct acpi_resource *ares, void *data) +{ + unsigned int *count = data; + + if (ares->type == ACPI_RESOURCE_TYPE_GPIO) + *count += ares->data.gpio.pin_table_length; + + return 1; +} + +/** + * acpi_gpio_count - return the number of GPIOs associated with a + * device / function or -ENOENT if no GPIO has been + * assigned to the requested function. + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + */ +int acpi_gpio_count(struct device *dev, const char *con_id) +{ + struct acpi_device *adev = ACPI_COMPANION(dev); + const union acpi_object *obj; + const struct acpi_gpio_mapping *gm; + int count = -ENOENT; + int ret; + char propname[32]; + unsigned int i; + + /* Try first from _DSD */ + for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { + if (con_id && strcmp(con_id, "gpios")) + snprintf(propname, sizeof(propname), "%s-%s", + con_id, gpio_suffixes[i]); + else + snprintf(propname, sizeof(propname), "%s", + gpio_suffixes[i]); + + ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY, + &obj); + if (ret == 0) { + if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) + count = 1; + else if (obj->type == ACPI_TYPE_PACKAGE) + count = acpi_gpio_package_count(obj); + } else if (adev->driver_gpios) { + for (gm = adev->driver_gpios; gm->name; gm++) + if (strcmp(propname, gm->name) == 0) { + count = gm->size; + break; + } + } + if (count >= 0) + break; + } + + /* Then from plain _CRS GPIOs */ + if (count < 0) { + struct list_head resource_list; + unsigned int crs_count = 0; + + INIT_LIST_HEAD(&resource_list); + acpi_dev_get_resources(adev, &resource_list, + acpi_find_gpio_count, &crs_count); + acpi_dev_free_resource_list(&resource_list); + if (crs_count > 0) + count = crs_count; + } + return count; +} diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2f8296c021e5..3d5b85a7dcdf 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1806,6 +1806,70 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, return desc; } +static int dt_gpio_count(struct device *dev, const char *con_id) +{ + int ret; + char propname[32]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { + if (con_id) + snprintf(propname, sizeof(propname), "%s-%s", + con_id, gpio_suffixes[i]); + else + snprintf(propname, sizeof(propname), "%s", + gpio_suffixes[i]); + + ret = of_gpio_named_count(dev->of_node, propname); + if (ret >= 0) + break; + } + return ret; +} + +static int platform_gpio_count(struct device *dev, const char *con_id) +{ + struct gpiod_lookup_table *table; + struct gpiod_lookup *p; + unsigned int count = 0; + + table = gpiod_find_lookup_table(dev); + if (!table) + return -ENOENT; + + for (p = &table->table[0]; p->chip_label; p++) { + if ((con_id && p->con_id && !strcmp(con_id, p->con_id)) || + (!con_id && !p->con_id)) + count++; + } + if (!count) + return -ENOENT; + + return count; +} + +/** + * gpiod_count - return the number of GPIOs associated with a device / function + * or -ENOENT if no GPIO has been assigned to the requested function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + */ +int gpiod_count(struct device *dev, const char *con_id) +{ + int count = -ENOENT; + + if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) + count = dt_gpio_count(dev, con_id); + else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev)) + count = acpi_gpio_count(dev, con_id); + + if (count < 0) + count = platform_gpio_count(dev, con_id); + + return count; +} +EXPORT_SYMBOL_GPL(gpiod_count); + /** * gpiod_get - obtain a GPIO for a given GPIO function * @dev: GPIO consumer, can be NULL for system-global GPIOs @@ -2089,6 +2153,72 @@ static void gpiochip_free_hogs(struct gpio_chip *chip) } } +/** + * gpiod_get_array - obtain multiple GPIOs from a multi-index GPIO function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * This function acquires all the GPIOs defined under a given function. + * + * Return a struct gpio_descs containing an array of descriptors, -ENOENT if + * no GPIO has been assigned to the requested function, or another IS_ERR() + * code if an error occurred while trying to acquire the GPIOs. + */ +struct gpio_descs *__must_check gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + struct gpio_desc *desc; + struct gpio_descs *descs; + int count; + + count = gpiod_count(dev, con_id); + if (count < 0) + return ERR_PTR(count); + + descs = kzalloc(sizeof(*descs) + sizeof(descs->desc[0]) * count, + GFP_KERNEL); + if (!descs) + return ERR_PTR(-ENOMEM); + + for (descs->ndescs = 0; descs->ndescs < count; ) { + desc = gpiod_get_index(dev, con_id, descs->ndescs, flags); + if (IS_ERR(desc)) { + gpiod_put_array(descs); + return ERR_CAST(desc); + } + descs->desc[descs->ndescs] = desc; + descs->ndescs++; + } + return descs; +} +EXPORT_SYMBOL_GPL(gpiod_get_array); + +/** + * gpiod_get_array_optional - obtain multiple GPIOs from a multi-index GPIO + * function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * This is equivalent to gpiod_get_array(), except that when no GPIO was + * assigned to the requested function it will return NULL. + */ +struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + struct gpio_descs *descs; + + descs = gpiod_get_array(dev, con_id, flags); + if (IS_ERR(descs) && (PTR_ERR(descs) == -ENOENT)) + return NULL; + + return descs; +} +EXPORT_SYMBOL_GPL(gpiod_get_array_optional); + /** * gpiod_put - dispose of a GPIO descriptor * @desc: GPIO descriptor to dispose of @@ -2101,6 +2231,21 @@ void gpiod_put(struct gpio_desc *desc) } EXPORT_SYMBOL_GPL(gpiod_put); +/** + * gpiod_put_array - dispose of multiple GPIO descriptors + * @descs: struct gpio_descs containing an array of descriptors + */ +void gpiod_put_array(struct gpio_descs *descs) +{ + unsigned int i; + + for (i = 0; i < descs->ndescs; i++) + gpiod_put(descs->desc[i]); + + kfree(descs); +} +EXPORT_SYMBOL_GPL(gpiod_put_array); + #ifdef CONFIG_DEBUG_FS static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 205dd12659c0..54bc5ec91398 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -40,6 +40,8 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname, int index, struct acpi_gpio_info *info); + +int acpi_gpio_count(struct device *dev, const char *con_id); #else static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { } @@ -56,6 +58,11 @@ acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname, { return ERR_PTR(-ENOSYS); } + +static inline int acpi_gpio_count(struct device *dev, const char *con_id) +{ + return -ENODEV; +} #endif struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index ed20759229eb..33eb52fd0932 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -16,6 +16,15 @@ struct device; */ struct gpio_desc; +/** + * Struct containing an array of descriptors that can be obtained using + * gpiod_get_array(). + */ +struct gpio_descs { + unsigned int ndescs; + struct gpio_desc *desc[]; +}; + #define GPIOD_FLAGS_BIT_DIR_SET BIT(0) #define GPIOD_FLAGS_BIT_DIR_OUT BIT(1) #define GPIOD_FLAGS_BIT_DIR_VAL BIT(2) @@ -34,6 +43,9 @@ enum gpiod_flags { #ifdef CONFIG_GPIOLIB +/* Return the number of GPIOs associated with a device / function */ +int gpiod_count(struct device *dev, const char *con_id); + /* Acquire and dispose GPIOs */ struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id, @@ -49,7 +61,14 @@ struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags); +struct gpio_descs *__must_check gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags); void gpiod_put(struct gpio_desc *desc); +void gpiod_put_array(struct gpio_descs *descs); struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev, const char *con_id, @@ -114,6 +133,11 @@ struct gpio_desc *devm_get_gpiod_from_child(struct device *dev, struct fwnode_handle *child); #else /* CONFIG_GPIOLIB */ +static inline int gpiod_count(struct device *dev, const char *con_id) +{ + return 0; +} + static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags) @@ -143,6 +167,20 @@ __gpiod_get_index_optional(struct device *dev, const char *con_id, return ERR_PTR(-ENOSYS); } +static inline struct gpio_descs *__must_check +gpiod_get_array(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_descs *__must_check +gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + static inline void gpiod_put(struct gpio_desc *desc) { might_sleep(); @@ -151,6 +189,14 @@ static inline void gpiod_put(struct gpio_desc *desc) WARN_ON(1); } +static inline void gpiod_put_array(struct gpio_descs *descs) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(1); +} + static inline struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev, const char *con_id, -- cgit v1.2.3 From 331758eef83620eef3f21289f0f44aba094d0503 Mon Sep 17 00:00:00 2001 From: Rojhalat Ibrahim Date: Wed, 11 Feb 2015 17:28:02 +0100 Subject: gpiolib: add devm_gpiod_get_array and devm_gpiod_put_array functions Add device managed variants of gpiod_get_array() / gpiod_put_array() functions for conveniently obtaining and disposing of an entire array of GPIOs with one function call. Signed-off-by: Rojhalat Ibrahim Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- Documentation/gpio/consumer.txt | 14 ++++++- drivers/gpio/devres.c | 89 +++++++++++++++++++++++++++++++++++++++++ include/linux/gpio/consumer.h | 30 ++++++++++++++ 3 files changed, 131 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index 2924f2ffcd91..d29a9725c9e5 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -102,11 +102,19 @@ Device-managed variants of these functions are also defined: const char *con_id, enum gpiod_flags flags) - struct gpio_desc * devm_gpiod_get_index_optional(struct device *dev, + struct gpio_desc *devm_gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags) + struct gpio_descs *devm_gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags) + + struct gpio_descs *devm_gpiod_get_array_optional(struct device *dev, + const char *con_id, + enum gpiod_flags flags) + A GPIO descriptor can be disposed of using the gpiod_put() function: void gpiod_put(struct gpio_desc *desc) @@ -119,10 +127,12 @@ It is strictly forbidden to use a descriptor after calling these functions. It is also not allowed to individually release descriptors (using gpiod_put()) from an array acquired with gpiod_get_array(). -The device-managed variant is, unsurprisingly: +The device-managed variants are, unsurprisingly: void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) + void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs) + Using GPIOs =========== diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 12c2082f968e..ec24da2418b3 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -35,6 +35,20 @@ static int devm_gpiod_match(struct device *dev, void *res, void *data) return *this == *gpio; } +static void devm_gpiod_release_array(struct device *dev, void *res) +{ + struct gpio_descs **descs = res; + + gpiod_put_array(*descs); +} + +static int devm_gpiod_match_array(struct device *dev, void *res, void *data) +{ + struct gpio_descs **this = res, **gpios = data; + + return *this == *gpios; +} + /** * devm_gpiod_get - Resource-managed gpiod_get() * @dev: GPIO consumer @@ -185,6 +199,66 @@ struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *de } EXPORT_SYMBOL(__devm_gpiod_get_index_optional); +/** + * devm_gpiod_get_array - Resource-managed gpiod_get_array() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * Managed gpiod_get_array(). GPIO descriptors returned from this function are + * automatically disposed on driver detach. See gpiod_get_array() for detailed + * information about behavior and return values. + */ +struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags) +{ + struct gpio_descs **dr; + struct gpio_descs *descs; + + dr = devres_alloc(devm_gpiod_release_array, + sizeof(struct gpio_descs *), GFP_KERNEL); + if (!dr) + return ERR_PTR(-ENOMEM); + + descs = gpiod_get_array(dev, con_id, flags); + if (IS_ERR(descs)) { + devres_free(dr); + return descs; + } + + *dr = descs; + devres_add(dev, dr); + + return descs; +} +EXPORT_SYMBOL(devm_gpiod_get_array); + +/** + * devm_gpiod_get_array_optional - Resource-managed gpiod_get_array_optional() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * @flags: optional GPIO initialization flags + * + * Managed gpiod_get_array_optional(). GPIO descriptors returned from this + * function are automatically disposed on driver detach. + * See gpiod_get_array_optional() for detailed information about behavior and + * return values. + */ +struct gpio_descs *__must_check +devm_gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + struct gpio_descs *descs; + + descs = devm_gpiod_get_array(dev, con_id, flags); + if (IS_ERR(descs) && (PTR_ERR(descs) == -ENOENT)) + return NULL; + + return descs; +} +EXPORT_SYMBOL(devm_gpiod_get_array_optional); + /** * devm_gpiod_put - Resource-managed gpiod_put() * @desc: GPIO descriptor to dispose of @@ -200,6 +274,21 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) } EXPORT_SYMBOL(devm_gpiod_put); +/** + * devm_gpiod_put_array - Resource-managed gpiod_put_array() + * @descs: GPIO descriptor array to dispose of + * + * Dispose of an array of GPIO descriptors obtained with devm_gpiod_get_array(). + * Normally this function will not be called as the GPIOs will be disposed of + * by the resource management code. + */ +void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs) +{ + WARN_ON(devres_release(dev, devm_gpiod_release_array, + devm_gpiod_match_array, &descs)); +} +EXPORT_SYMBOL(devm_gpiod_put_array); + diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 33eb52fd0932..3a7c9ffd5ab9 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -83,7 +83,14 @@ struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev, struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags); +struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev, + const char *con_id, + enum gpiod_flags flags); +struct gpio_descs *__must_check +devm_gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags); void devm_gpiod_put(struct device *dev, struct gpio_desc *desc); +void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs); int gpiod_get_direction(struct gpio_desc *desc); int gpiod_direction_input(struct gpio_desc *desc); @@ -228,6 +235,20 @@ __devm_gpiod_get_index_optional(struct device *dev, const char *con_id, return ERR_PTR(-ENOSYS); } +static inline struct gpio_descs *__must_check +devm_gpiod_get_array(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct gpio_descs *__must_check +devm_gpiod_get_array_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) +{ + return ERR_PTR(-ENOSYS); +} + static inline void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) { might_sleep(); @@ -236,6 +257,15 @@ static inline void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) WARN_ON(1); } +static inline void devm_gpiod_put_array(struct device *dev, + struct gpio_descs *descs) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(1); +} + static inline int gpiod_get_direction(const struct gpio_desc *desc) { -- cgit v1.2.3 From 68c062eaa87b7b85b65f20f25c54524437715a95 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 5 Mar 2015 11:42:43 +0100 Subject: dmaengine: Remove net_dma leftovers Commit 7bce d397 510a ("net_dma: simple removal") removed the net_dma support entirely but left some functions and prototypes in the dmaengine header. Remove them. Signed-off-by: Maxime Ripard Signed-off-by: Vinod Koul --- include/linux/dmaengine.h | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'include') diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index db0104b0da4d..f5cc5d4f1ad5 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -1108,27 +1108,4 @@ static inline struct dma_chan return __dma_request_channel(mask, fn, fn_param); } - -/* --- Helper iov-locking functions --- */ - -struct dma_page_list { - char __user *base_address; - int nr_pages; - struct page **pages; -}; - -struct dma_pinned_list { - int nr_iovecs; - struct dma_page_list page_list[0]; -}; - -struct dma_pinned_list *dma_pin_iovec_pages(struct iovec *iov, size_t len); -void dma_unpin_iovec_pages(struct dma_pinned_list* pinned_list); - -dma_cookie_t dma_memcpy_to_iovec(struct dma_chan *chan, struct iovec *iov, - struct dma_pinned_list *pinned_list, unsigned char *kdata, size_t len); -dma_cookie_t dma_memcpy_pg_to_iovec(struct dma_chan *chan, struct iovec *iov, - struct dma_pinned_list *pinned_list, struct page *page, - unsigned int offset, size_t len); - #endif /* DMAENGINE_H */ -- cgit v1.2.3 From bfde98bd762346639f0a5a557e02c4828dd6273b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 5 Mar 2015 11:48:50 +0100 Subject: dmaengine: Remove net_dma_find_channel Since commit 7bced397510a ("net_dma: simple removal") removed the net_dma support entirely, net_dma_find_channel has no users left. Remove the function entirely. Signed-off-by: Maxime Ripard Signed-off-by: Vinod Koul --- drivers/dma/dmaengine.c | 14 -------------- include/linux/dmaengine.h | 1 - 2 files changed, 15 deletions(-) (limited to 'include') diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index f15712f2fec6..344b0ac6d985 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -355,20 +355,6 @@ struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type) } EXPORT_SYMBOL(dma_find_channel); -/* - * net_dma_find_channel - find a channel for net_dma - * net_dma has alignment requirements - */ -struct dma_chan *net_dma_find_channel(void) -{ - struct dma_chan *chan = dma_find_channel(DMA_MEMCPY); - if (chan && !is_dma_copy_aligned(chan->device, 1, 1, 1)) - return NULL; - - return chan; -} -EXPORT_SYMBOL(net_dma_find_channel); - /** * dma_issue_pending_all - flush all pending operations across all channels */ diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index f5cc5d4f1ad5..2bff9abc162a 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -1090,7 +1090,6 @@ void dma_async_device_unregister(struct dma_device *device); void dma_run_dependencies(struct dma_async_tx_descriptor *tx); struct dma_chan *dma_get_slave_channel(struct dma_chan *chan); struct dma_chan *dma_get_any_slave_channel(struct dma_device *device); -struct dma_chan *net_dma_find_channel(void); #define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y) #define dma_request_slave_channel_compat(mask, x, y, dev, name) \ __dma_request_slave_channel_compat(&(mask), x, y, dev, name) -- cgit v1.2.3 From f33c9d655893d8632460696bbbdee737cb315711 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 24 Feb 2015 02:06:43 +0000 Subject: mmc: tmio: mmc: tmio: tmio_mmc_data has .chan_priv_?x dma_request_slave_channel_compat() in tmio_mmc_dma needs .chan_priv_tx/.chan_priv_rx. But these are copied from sh_mobile_sdhi only, and sh_mobile_sdhi_info is now almost same as tmio_mmc_data except .chan_priv_?x. sh_mobile_sdhi_info can be replaced to tmio_mmc_data, but it is used from ${LINUX}/arch/arm/mach-shmobile, ${LINUX}/arch/sh. So, this patch adds .chan_priv_?x into tmio_mmc_data as 1st step, and sh_mobile_sdhi driver has dummy operation for now. It will be replaced/removed together with platform data replace. Signed-off-by: Kuninori Morimoto Acked-by: Arnd Bergmann Acked-by: Ulf Hansson Acked-by: Lee Jones Signed-off-by: Vinod Koul --- drivers/mmc/host/sh_mobile_sdhi.c | 44 ++++++++++++++++++++++++--------------- drivers/mmc/host/tmio_mmc.h | 2 -- drivers/mmc/host/tmio_mmc_dma.c | 6 +++--- include/linux/mfd/tmio.h | 2 ++ 4 files changed, 32 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 11991f5f3fef..3137e292270e 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -201,6 +201,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) of_match_device(sh_mobile_sdhi_of_match, &pdev->dev); struct sh_mobile_sdhi *priv; struct tmio_mmc_data *mmc_data; + struct tmio_mmc_data *mmd = pdev->dev.platform_data; struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; struct tmio_mmc_host *host; struct resource *res; @@ -245,28 +246,37 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) else host->bus_shift = 0; - mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; - if (p) { - mmc_data->flags = p->tmio_flags; - mmc_data->ocr_mask = p->tmio_ocr_mask; - mmc_data->capabilities |= p->tmio_caps; - mmc_data->capabilities2 |= p->tmio_caps2; - mmc_data->cd_gpio = p->cd_gpio; - - if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) { - /* - * Yes, we have to provide slave IDs twice to TMIO: - * once as a filter parameter and once for channel - * configuration as an explicit slave ID - */ - dma_priv->chan_priv_tx = (void *)p->dma_slave_tx; - dma_priv->chan_priv_rx = (void *)p->dma_slave_rx; - } + if (mmd) { + /* + * FIXME + * + * sh_mobile_sdhi_info will be replaced to tmio_mmc_data soon. + * But, sh_mobile_sdhi_info is used under + * ${LINUX}/arch/arm/mach-shmobile/ + * ${LINUX}/arch/sh/ + * To separate large patch into "tmio_mmc_data has .chan_priv_?x" + * and "replace sh_mobile_sdhi_info in tmio_mmc_data", + * here has dummy method. + * These should be removed. + */ + struct tmio_mmc_data m; + + mmd = &m; + m.flags = p->tmio_flags; + m.ocr_mask = p->tmio_ocr_mask; + m.capabilities = p->tmio_caps; + m.capabilities2 = p->tmio_caps2; + m.cd_gpio = p->cd_gpio; + m.chan_priv_tx = (void *)p->dma_slave_tx; + m.chan_priv_rx = (void *)p->dma_slave_rx; + + *mmc_data = *mmd; } dma_priv->filter = shdma_chan_filter; dma_priv->enable = sh_mobile_sdhi_enable_dma; mmc_data->alignment_shift = 1; /* 2-byte alignment */ + mmc_data->capabilities |= MMC_CAP_MMC_HIGHSPEED; /* * All SDHI blocks support 2-byte and larger block sizes in 4-bit diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 1aea5c67af94..4a597f5a53e2 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -43,8 +43,6 @@ struct tmio_mmc_data; struct tmio_mmc_host; struct tmio_mmc_dma { - void *chan_priv_tx; - void *chan_priv_rx; enum dma_slave_buswidth dma_buswidth; bool (*filter)(struct dma_chan *chan, void *arg); void (*enable)(struct tmio_mmc_host *host, bool enable); diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c index 8dbd785366a6..e4b05dbb9ca8 100644 --- a/drivers/mmc/host/tmio_mmc_dma.c +++ b/drivers/mmc/host/tmio_mmc_dma.c @@ -261,7 +261,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat { /* We can only either use DMA for both Tx and Rx or not use it at all */ if (!host->dma || (!host->pdev->dev.of_node && - (!host->dma->chan_priv_tx || !host->dma->chan_priv_rx))) + (!pdata->chan_priv_tx || !pdata->chan_priv_rx))) return; if (!host->chan_tx && !host->chan_rx) { @@ -278,7 +278,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat dma_cap_set(DMA_SLAVE, mask); host->chan_tx = dma_request_slave_channel_compat(mask, - host->dma->filter, host->dma->chan_priv_tx, + host->dma->filter, pdata->chan_priv_tx, &host->pdev->dev, "tx"); dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, host->chan_tx); @@ -297,7 +297,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat goto ecfgtx; host->chan_rx = dma_request_slave_channel_compat(mask, - host->dma->filter, host->dma->chan_priv_rx, + host->dma->filter, pdata->chan_priv_rx, &host->pdev->dev, "rx"); dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, host->chan_rx); diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index 605812820e48..24b86d538e88 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -111,6 +111,8 @@ struct dma_chan; * data for the MMC controller */ struct tmio_mmc_data { + void *chan_priv_tx; + void *chan_priv_rx; unsigned int hclk; unsigned long capabilities; unsigned long capabilities2; -- cgit v1.2.3 From 84f11d5b1f2abc0e22895b7e12e037f0ec03caeb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 24 Feb 2015 02:07:07 +0000 Subject: mmc: sh_mobile_sdhi: remove sh_mobile_sdhi_info Current sh_mobile_sdhi's platform data is set via sh_mobile_sdhi_info and it is just copied to tmio_mmc_data. Now, tmio mmc platform data is specified via tmio_mmc_data. This patch replace sh_mobile_sdhi_info to tmio_mmc_data struct sh_mobile_sdhi_info { -> struct tmio_mmc_data { int dma_slave_tx; -> void *chan_priv_tx; int dma_slave_rx; -> void *chan_priv_rx; unsigned long tmio_flags; -> unsigned long flags; unsigned long tmio_caps; -> unsigned long capabilities; unsigned long tmio_caps2; -> unsigned long capabilities2; u32 tmio_ocr_mask; -> u32 ocr_mask; unsigned int cd_gpio; -> unsigned int cd_gpio; }; unsigned int hclk; void (*set_pwr)(...); void (*set_clk_div)(...); }; Signed-off-by: Kuninori Morimoto Acked-by: Arnd Bergmann Acked-by: Ulf Hansson Signed-off-by: Vinod Koul --- arch/arm/mach-shmobile/board-armadillo800eva.c | 20 +++++++++--------- arch/arm/mach-shmobile/board-bockw.c | 14 ++++++------- arch/arm/mach-shmobile/board-kzm9g.c | 20 +++++++++--------- arch/arm/mach-shmobile/board-marzen.c | 10 ++++----- arch/sh/boards/board-sh7757lcr.c | 9 +++++---- arch/sh/boards/mach-ap325rxa/setup.c | 9 +++++---- arch/sh/boards/mach-ecovec24/setup.c | 20 +++++++++--------- arch/sh/boards/mach-kfr2r09/setup.c | 10 ++++----- arch/sh/boards/mach-migor/setup.c | 9 +++++---- arch/sh/boards/mach-se/7724/setup.c | 17 ++++++++-------- drivers/mmc/host/sh_mobile_sdhi.c | 28 ++------------------------ include/linux/mmc/sh_mobile_sdhi.h | 10 --------- 12 files changed, 73 insertions(+), 103 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index 6d949f1c850b..7eac84687cb4 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -754,12 +754,12 @@ static struct platform_device vcc_sdhi1 = { }; /* SDHI0 */ -static struct sh_mobile_sdhi_info sdhi0_info = { - .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX, - .dma_slave_rx = SHDMA_SLAVE_SDHI0_RX, - .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | +static struct tmio_mmc_data sdhi0_info = { + .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI0_TX, + .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI0_RX, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD, - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_USE_GPIO_CD, + .flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_USE_GPIO_CD, .cd_gpio = 167, }; @@ -796,12 +796,12 @@ static struct platform_device sdhi0_device = { }; /* SDHI1 */ -static struct sh_mobile_sdhi_info sdhi1_info = { - .dma_slave_tx = SHDMA_SLAVE_SDHI1_TX, - .dma_slave_rx = SHDMA_SLAVE_SDHI1_RX, - .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | +static struct tmio_mmc_data sdhi1_info = { + .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI1_TX, + .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI1_RX, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD, - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_USE_GPIO_CD, + .flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_USE_GPIO_CD, /* Port72 cannot generate IRQs, will be used in polling mode. */ .cd_gpio = 72, }; diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c index f27b5a833bf0..25558d1f417f 100644 --- a/arch/arm/mach-shmobile/board-bockw.c +++ b/arch/arm/mach-shmobile/board-bockw.c @@ -201,12 +201,12 @@ static struct rcar_phy_platform_data usb_phy_platform_data __initdata = /* SDHI */ -static struct sh_mobile_sdhi_info sdhi0_info __initdata = { - .dma_slave_tx = HPBDMA_SLAVE_SDHI0_TX, - .dma_slave_rx = HPBDMA_SLAVE_SDHI0_RX, - .tmio_caps = MMC_CAP_SD_HIGHSPEED, - .tmio_ocr_mask = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34, - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, +static struct tmio_mmc_data sdhi0_info __initdata = { + .chan_priv_tx = (void *)HPBDMA_SLAVE_SDHI0_TX, + .chan_priv_rx = (void *)HPBDMA_SLAVE_SDHI0_RX, + .capabilities = MMC_CAP_SD_HIGHSPEED, + .ocr_mask = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34, + .flags = TMIO_MMC_HAS_IDLE_WAIT, }; static struct resource sdhi0_resources[] __initdata = { @@ -683,7 +683,7 @@ static void __init bockw_init(void) platform_device_register_resndata( NULL, "sh_mobile_sdhi", 0, sdhi0_resources, ARRAY_SIZE(sdhi0_resources), - &sdhi0_info, sizeof(struct sh_mobile_sdhi_info)); + &sdhi0_info, sizeof(struct tmio_mmc_data)); } /* for Audio */ diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c index 7c9b63bdde9f..260d8319fd82 100644 --- a/arch/arm/mach-shmobile/board-kzm9g.c +++ b/arch/arm/mach-shmobile/board-kzm9g.c @@ -442,11 +442,11 @@ static struct platform_device vcc_sdhi2 = { }; /* SDHI */ -static struct sh_mobile_sdhi_info sdhi0_info = { - .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX, - .dma_slave_rx = SHDMA_SLAVE_SDHI0_RX, - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, - .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | +static struct tmio_mmc_data sdhi0_info = { + .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI0_TX, + .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI0_RX, + .flags = TMIO_MMC_HAS_IDLE_WAIT, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD, }; @@ -484,13 +484,13 @@ static struct platform_device sdhi0_device = { }; /* Micro SD */ -static struct sh_mobile_sdhi_info sdhi2_info = { - .dma_slave_tx = SHDMA_SLAVE_SDHI2_TX, - .dma_slave_rx = SHDMA_SLAVE_SDHI2_RX, - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | +static struct tmio_mmc_data sdhi2_info = { + .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI2_TX, + .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI2_RX, + .flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_USE_GPIO_CD | TMIO_MMC_WRPROTECT_DISABLE, - .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_POWER_OFF_CARD, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_POWER_OFF_CARD, .cd_gpio = 13, }; diff --git a/arch/arm/mach-shmobile/board-marzen.c b/arch/arm/mach-shmobile/board-marzen.c index 598f704f76ae..51db288f192a 100644 --- a/arch/arm/mach-shmobile/board-marzen.c +++ b/arch/arm/mach-shmobile/board-marzen.c @@ -122,11 +122,11 @@ static struct resource sdhi0_resources[] = { }, }; -static struct sh_mobile_sdhi_info sdhi0_platform_data = { - .dma_slave_tx = HPBDMA_SLAVE_SDHI0_TX, - .dma_slave_rx = HPBDMA_SLAVE_SDHI0_RX, - .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT, - .tmio_caps = MMC_CAP_SD_HIGHSPEED, +static struct tmio_mmc_data sdhi0_platform_data = { + .chan_priv_tx = (void *)HPBDMA_SLAVE_SDHI0_TX, + .chan_priv_rx = (void *)HPBDMA_SLAVE_SDHI0_RX, + .flags = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT, + .capabilities = MMC_CAP_SD_HIGHSPEED, }; static struct platform_device sdhi0_device = { diff --git a/arch/sh/boards/board-sh7757lcr.c b/arch/sh/boards/board-sh7757lcr.c index 669df51a82e3..324599bfad14 100644 --- a/arch/sh/boards/board-sh7757lcr.c +++ b/arch/sh/boards/board-sh7757lcr.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -243,10 +244,10 @@ static struct platform_device sh_mmcif_device = { }; /* SDHI0 */ -static struct sh_mobile_sdhi_info sdhi_info = { - .dma_slave_tx = SHDMA_SLAVE_SDHI_TX, - .dma_slave_rx = SHDMA_SLAVE_SDHI_RX, - .tmio_caps = MMC_CAP_SD_HIGHSPEED, +static struct tmio_mmc_data sdhi_info = { + .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI_TX, + .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI_RX, + .capabilities = MMC_CAP_SD_HIGHSPEED, }; static struct resource sdhi_resources[] = { diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index d4b01d4cc102..cbd2a9f02a91 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -447,8 +448,8 @@ static struct resource sdhi0_cn3_resources[] = { }, }; -static struct sh_mobile_sdhi_info sdhi0_cn3_data = { - .tmio_caps = MMC_CAP_SDIO_IRQ, +static struct tmio_mmc_data sdhi0_cn3_data = { + .capabilities = MMC_CAP_SDIO_IRQ, }; static struct platform_device sdhi0_cn3_device = { @@ -474,8 +475,8 @@ static struct resource sdhi1_cn7_resources[] = { }, }; -static struct sh_mobile_sdhi_info sdhi1_cn7_data = { - .tmio_caps = MMC_CAP_SDIO_IRQ, +static struct tmio_mmc_data sdhi1_cn7_data = { + .capabilities = MMC_CAP_SDIO_IRQ, }; static struct platform_device sdhi1_cn7_device = { diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 0d3049244cd3..d531791f06ff 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -601,12 +601,12 @@ static struct platform_device sdhi0_power = { }, }; -static struct sh_mobile_sdhi_info sdhi0_info = { - .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX, - .dma_slave_rx = SHDMA_SLAVE_SDHI0_RX, - .tmio_caps = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD | +static struct tmio_mmc_data sdhi0_info = { + .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI0_TX, + .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI0_RX, + .capabilities = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD | MMC_CAP_NEEDS_POLL, - .tmio_flags = TMIO_MMC_USE_GPIO_CD, + .flags = TMIO_MMC_USE_GPIO_CD, .cd_gpio = GPIO_PTY7, }; @@ -635,12 +635,12 @@ static struct platform_device sdhi0_device = { #if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE) /* SDHI1 */ -static struct sh_mobile_sdhi_info sdhi1_info = { - .dma_slave_tx = SHDMA_SLAVE_SDHI1_TX, - .dma_slave_rx = SHDMA_SLAVE_SDHI1_RX, - .tmio_caps = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD | +static struct tmio_mmc_data sdhi1_info = { + .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI1_TX, + .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI1_RX, + .capabilities = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD | MMC_CAP_NEEDS_POLL, - .tmio_flags = TMIO_MMC_USE_GPIO_CD, + .flags = TMIO_MMC_USE_GPIO_CD, .cd_gpio = GPIO_PTW7, }; diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 1df4398f8375..7d997cec09c5 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c @@ -373,11 +373,11 @@ static struct resource kfr2r09_sh_sdhi0_resources[] = { }, }; -static struct sh_mobile_sdhi_info sh7724_sdhi0_data = { - .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX, - .dma_slave_rx = SHDMA_SLAVE_SDHI0_RX, - .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE, - .tmio_caps = MMC_CAP_SDIO_IRQ, +static struct tmio_mmc_data sh7724_sdhi0_data = { + .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI0_TX, + .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI0_RX, + .flags = TMIO_MMC_WRPROTECT_DISABLE, + .capabilities = MMC_CAP_SDIO_IRQ, }; static struct platform_device kfr2r09_sh_sdhi0_device = { diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 8b73194ed2ce..29b7c0dcfc51 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -408,10 +409,10 @@ static struct resource sdhi_cn9_resources[] = { }, }; -static struct sh_mobile_sdhi_info sh7724_sdhi_data = { - .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX, - .dma_slave_rx = SHDMA_SLAVE_SDHI0_RX, - .tmio_caps = MMC_CAP_SDIO_IRQ, +static struct tmio_mmc_data sh7724_sdhi_data = { + .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI0_TX, + .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI0_RX, + .capabilities = MMC_CAP_SDIO_IRQ, }; static struct platform_device sdhi_cn9_device = { diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 1162bc6945a3..4f6635a075f2 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -468,10 +469,10 @@ static struct resource sdhi0_cn7_resources[] = { }, }; -static struct sh_mobile_sdhi_info sh7724_sdhi0_data = { - .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX, - .dma_slave_rx = SHDMA_SLAVE_SDHI0_RX, - .tmio_caps = MMC_CAP_SDIO_IRQ, +static struct tmio_mmc_data sh7724_sdhi0_data = { + .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI0_TX, + .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI0_RX, + .capabilities = MMC_CAP_SDIO_IRQ, }; static struct platform_device sdhi0_cn7_device = { @@ -497,10 +498,10 @@ static struct resource sdhi1_cn8_resources[] = { }, }; -static struct sh_mobile_sdhi_info sh7724_sdhi1_data = { - .dma_slave_tx = SHDMA_SLAVE_SDHI1_TX, - .dma_slave_rx = SHDMA_SLAVE_SDHI1_RX, - .tmio_caps = MMC_CAP_SDIO_IRQ, +static struct tmio_mmc_data sh7724_sdhi1_data = { + .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI1_TX, + .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI1_RX, + .capabilities = MMC_CAP_SDIO_IRQ, }; static struct platform_device sdhi1_cn8_device = { diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 3137e292270e..354f4f335ed5 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -202,7 +202,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) struct sh_mobile_sdhi *priv; struct tmio_mmc_data *mmc_data; struct tmio_mmc_data *mmd = pdev->dev.platform_data; - struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; struct tmio_mmc_host *host; struct resource *res; int irq, ret, i = 0; @@ -246,32 +245,9 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) else host->bus_shift = 0; - if (mmd) { - /* - * FIXME - * - * sh_mobile_sdhi_info will be replaced to tmio_mmc_data soon. - * But, sh_mobile_sdhi_info is used under - * ${LINUX}/arch/arm/mach-shmobile/ - * ${LINUX}/arch/sh/ - * To separate large patch into "tmio_mmc_data has .chan_priv_?x" - * and "replace sh_mobile_sdhi_info in tmio_mmc_data", - * here has dummy method. - * These should be removed. - */ - struct tmio_mmc_data m; - - mmd = &m; - m.flags = p->tmio_flags; - m.ocr_mask = p->tmio_ocr_mask; - m.capabilities = p->tmio_caps; - m.capabilities2 = p->tmio_caps2; - m.cd_gpio = p->cd_gpio; - m.chan_priv_tx = (void *)p->dma_slave_tx; - m.chan_priv_rx = (void *)p->dma_slave_rx; - + if (mmd) *mmc_data = *mmd; - } + dma_priv->filter = shdma_chan_filter; dma_priv->enable = sh_mobile_sdhi_enable_dma; diff --git a/include/linux/mmc/sh_mobile_sdhi.h b/include/linux/mmc/sh_mobile_sdhi.h index da77e5e2041d..95d6f0314a7d 100644 --- a/include/linux/mmc/sh_mobile_sdhi.h +++ b/include/linux/mmc/sh_mobile_sdhi.h @@ -7,14 +7,4 @@ #define SH_MOBILE_SDHI_IRQ_SDCARD "sdcard" #define SH_MOBILE_SDHI_IRQ_SDIO "sdio" -struct sh_mobile_sdhi_info { - int dma_slave_tx; - int dma_slave_rx; - unsigned long tmio_flags; - unsigned long tmio_caps; - unsigned long tmio_caps2; - u32 tmio_ocr_mask; /* available MMC voltages */ - unsigned int cd_gpio; -}; - #endif /* LINUX_MMC_SH_MOBILE_SDHI_H */ -- cgit v1.2.3 From 2e67690137f3a7bac660edd548f8846709c55381 Mon Sep 17 00:00:00 2001 From: Robert ABEL Date: Fri, 27 Feb 2015 16:56:53 +0100 Subject: ARM OMAP2+ GPMC: calculate GPMCFCLKDIVIDER based on WAITMONITORINGTIME The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles, even though the access is defined as asynchronous, and no GPMC_CLK clock is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider for the GPMC clock, so it must be programmed to define the correct WAITMONITORINGTIME delay. Calculate GPMCFCLKDIVIDER independent of gpmc,sync-clk-ps in DT for pure asynchronous accesses, i.e. both read and write asynchronous. Signed-off-by: Robert ABEL Acked-by: Tony Lindgren Signed-off-by: Roger Quadros --- arch/arm/mach-omap2/gpmc-nand.c | 18 ++++---- arch/arm/mach-omap2/gpmc-onenand.c | 4 +- arch/arm/mach-omap2/usb-tusb6010.c | 4 +- drivers/memory/omap-gpmc.c | 86 ++++++++++++++++++++++++++++++++++---- include/linux/omap-gpmc.h | 3 +- 5 files changed, 95 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index d5951b17b736..72918c4973ea 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -96,14 +96,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, gpmc_nand_res[1].start = gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE); gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT); - if (gpmc_t) { - err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t); - if (err < 0) { - pr_err("omap2-gpmc: Unable to set gpmc timings: %d\n", err); - return err; - } - } - memset(&s, 0, sizeof(struct gpmc_settings)); if (gpmc_nand_data->of_node) gpmc_read_settings_dt(gpmc_nand_data->of_node, &s); @@ -111,6 +103,16 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, gpmc_set_legacy(gpmc_nand_data, &s); s.device_nand = true; + + if (gpmc_t) { + err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t, &s); + if (err < 0) { + pr_err("omap2-gpmc: Unable to set gpmc timings: %d\n", + err); + return err; + } + } + err = gpmc_cs_program_settings(gpmc_nand_data->cs, &s); if (err < 0) goto out_free_cs; diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index 53d197e0c1f3..f899e77ff5e6 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -293,7 +293,7 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base) if (ret < 0) return ret; - ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t); + ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t, &onenand_async); if (ret < 0) return ret; @@ -331,7 +331,7 @@ static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr) if (ret < 0) return ret; - ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t); + ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t, &onenand_sync); if (ret < 0) return ret; diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c index 8333400898fb..e554d9e66a1c 100644 --- a/arch/arm/mach-omap2/usb-tusb6010.c +++ b/arch/arm/mach-omap2/usb-tusb6010.c @@ -71,7 +71,7 @@ static int tusb_set_async_mode(unsigned sysclk_ps) gpmc_calc_timings(&t, &tusb_async, &dev_t); - return gpmc_cs_set_timings(async_cs, &t); + return gpmc_cs_set_timings(async_cs, &t, &tusb_async); } static int tusb_set_sync_mode(unsigned sysclk_ps) @@ -98,7 +98,7 @@ static int tusb_set_sync_mode(unsigned sysclk_ps) gpmc_calc_timings(&t, &tusb_sync, &dev_t); - return gpmc_cs_set_timings(sync_cs, &t); + return gpmc_cs_set_timings(sync_cs, &t, &tusb_sync); } /* tusb driver calls this when it changes the chip's clocking */ diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index 5c36ff397b73..768bab233196 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -138,7 +138,9 @@ #define GPMC_CONFIG1_PAGE_LEN(val) ((val & 3) << 23) #define GPMC_CONFIG1_WAIT_READ_MON (1 << 22) #define GPMC_CONFIG1_WAIT_WRITE_MON (1 << 21) -#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18) +#define GPMC_CONFIG1_WAIT_MON_TIME(val) ((val & 3) << 18) +/** WAITMONITORINGTIME Max Ticks */ +#define GPMC_CONFIG1_WAITMONITORINGTIME_MAX 2 #define GPMC_CONFIG1_WAIT_PIN_SEL(val) ((val & 3) << 16) #define GPMC_CONFIG1_DEVICESIZE(val) ((val & 3) << 12) #define GPMC_CONFIG1_DEVICESIZE_16 GPMC_CONFIG1_DEVICESIZE(1) @@ -525,13 +527,48 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, t->field, #field) < 0) \ return -1 +/** + * gpmc_calc_waitmonitoring_divider - calculate proper GPMCFCLKDIVIDER based on WAITMONITORINGTIME + * WAITMONITORINGTIME will be _at least_ as long as desired, i.e. + * read --> don't sample bus too early + * write --> data is longer on bus + * + * Formula: + * gpmc_clk_div + 1 = ceil(ceil(waitmonitoringtime_ns / gpmc_fclk_ns) + * / waitmonitoring_ticks) + * WAITMONITORINGTIME resulting in 0 or 1 tick with div = 1 are caught by + * div <= 0 check. + * + * @wait_monitoring: WAITMONITORINGTIME in ns. + * @return: -1 on failure to scale, else proper divider > 0. + */ +static int gpmc_calc_waitmonitoring_divider(unsigned int wait_monitoring) +{ + + int div = gpmc_ns_to_ticks(wait_monitoring); + + div += GPMC_CONFIG1_WAITMONITORINGTIME_MAX - 1; + div /= GPMC_CONFIG1_WAITMONITORINGTIME_MAX; + + if (div > 4) + return -1; + if (div <= 0) + div = 1; + + return div; + +} + +/** + * gpmc_calc_divider - calculate GPMC_FCLK divider for sync_clk GPMC_CLK period. + * @sync_clk: GPMC_CLK period in ps. + * @return: Returns at least 1 if GPMC_FCLK can be divided to GPMC_CLK. + * Else, returns -1. + */ int gpmc_calc_divider(unsigned int sync_clk) { - int div; - u32 l; + int div = gpmc_ps_to_ticks(sync_clk); - l = sync_clk + (gpmc_get_fclk_period() - 1); - div = l / gpmc_get_fclk_period(); if (div > 4) return -1; if (div <= 0) @@ -540,7 +577,15 @@ int gpmc_calc_divider(unsigned int sync_clk) return div; } -int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) +/** + * gpmc_cs_set_timings - program timing parameters for Chip Select Region. + * @cs: Chip Select Region. + * @t: GPMC timing parameters. + * @s: GPMC timing settings. + * @return: 0 on success, -1 on error. + */ +int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t, + const struct gpmc_settings *s) { int div; u32 l; @@ -550,6 +595,33 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) if (div < 0) return div; + /* + * See if we need to change the divider for waitmonitoringtime. + * + * Calculate GPMCFCLKDIVIDER independent of gpmc,sync-clk-ps in DT for + * pure asynchronous accesses, i.e. both read and write asynchronous. + * However, only do so if WAITMONITORINGTIME is actually used, i.e. + * either WAITREADMONITORING or WAITWRITEMONITORING is set. + * + * This statement must not change div to scale async WAITMONITORINGTIME + * to protect mixed synchronous and asynchronous accesses. + * + * We raise an error later if WAITMONITORINGTIME does not fit. + */ + if (!s->sync_read && !s->sync_write && + (s->wait_on_read || s->wait_on_write) + ) { + + div = gpmc_calc_waitmonitoring_divider(t->wait_monitoring); + if (div < 0) { + pr_err("%s: waitmonitoringtime %3d ns too large for greatest gpmcfclkdivider.\n", + __func__, + t->wait_monitoring + ); + return -1; + } + } + GPMC_SET_ONE(GPMC_CS_CONFIG2, 0, 3, cs_on); GPMC_SET_ONE(GPMC_CS_CONFIG2, 8, 12, cs_rd_off); GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off); @@ -1810,7 +1882,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, if (ret < 0) goto err; - ret = gpmc_cs_set_timings(cs, &gpmc_t); + ret = gpmc_cs_set_timings(cs, &gpmc_t, &gpmc_s); if (ret) { dev_err(&pdev->dev, "failed to set gpmc timings for: %s\n", child->name); diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h index c2080eebbb47..7dee00143afd 100644 --- a/include/linux/omap-gpmc.h +++ b/include/linux/omap-gpmc.h @@ -163,7 +163,8 @@ extern unsigned int gpmc_ticks_to_ns(unsigned int ticks); extern void gpmc_cs_write_reg(int cs, int idx, u32 val); extern int gpmc_calc_divider(unsigned int sync_clk); -extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t); +extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t, + const struct gpmc_settings *s); extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p); extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base); extern void gpmc_cs_free(int cs); -- cgit v1.2.3 From 2b49e0c56741fca538176f66ed3c8d16ce4fccd8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 23 Feb 2015 16:24:42 +0200 Subject: dmaengine: append hsu DMA driver The HSU DMA is developed to support High Speed UART controllers found in particular on Intel MID platforms such as Intel Medfield. The existing implementation is tighten to the drivers/tty/serial/mfd.c driver and has a lot of disadvantages. Besides that we would like to get rid of the old HS UART driver in regarding to extending the 8250 which supports generic DMAEngine API. That's why the current driver has been developed. Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/dma/Kconfig | 2 + drivers/dma/Makefile | 1 + drivers/dma/hsu/Kconfig | 14 + drivers/dma/hsu/Makefile | 5 + drivers/dma/hsu/hsu.c | 504 ++++++++++++++++++++++++++++++++++ drivers/dma/hsu/hsu.h | 118 ++++++++ drivers/dma/hsu/pci.c | 123 +++++++++ include/linux/dma/hsu.h | 48 ++++ include/linux/platform_data/dma-hsu.h | 25 ++ 9 files changed, 840 insertions(+) create mode 100644 drivers/dma/hsu/Kconfig create mode 100644 drivers/dma/hsu/Makefile create mode 100644 drivers/dma/hsu/hsu.c create mode 100644 drivers/dma/hsu/hsu.h create mode 100644 drivers/dma/hsu/pci.c create mode 100644 include/linux/dma/hsu.h create mode 100644 include/linux/platform_data/dma-hsu.h (limited to 'include') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index a874b6ec6650..074ffad334a7 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -125,6 +125,8 @@ config FSL_DMA EloPlus is on mpc85xx and mpc86xx and Pxxx parts, and the Elo3 is on some Txxx and Bxxx parts. +source "drivers/dma/hsu/Kconfig" + config MPC512X_DMA tristate "Freescale MPC512x built-in DMA engine support" depends on PPC_MPC512x || PPC_MPC831x diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index f915f61ec574..bf4485800c60 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_DMATEST) += dmatest.o obj-$(CONFIG_INTEL_IOATDMA) += ioat/ obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o obj-$(CONFIG_FSL_DMA) += fsldma.o +obj-$(CONFIG_HSU_DMA) += hsu/ obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ obj-$(CONFIG_MV_XOR) += mv_xor.o diff --git a/drivers/dma/hsu/Kconfig b/drivers/dma/hsu/Kconfig new file mode 100644 index 000000000000..7e98eff7440e --- /dev/null +++ b/drivers/dma/hsu/Kconfig @@ -0,0 +1,14 @@ +# DMA engine configuration for hsu +config HSU_DMA + tristate "High Speed UART DMA support" + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + +config HSU_DMA_PCI + tristate "High Speed UART DMA PCI driver" + depends on PCI + select HSU_DMA + help + Support the High Speed UART DMA on the platfroms that + enumerate it as a PCI device. For example, Intel Medfield + has integrated this HSU DMA controller. diff --git a/drivers/dma/hsu/Makefile b/drivers/dma/hsu/Makefile new file mode 100644 index 000000000000..b8f9af032ef1 --- /dev/null +++ b/drivers/dma/hsu/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_HSU_DMA) += hsu_dma.o +hsu_dma-objs := hsu.o + +obj-$(CONFIG_HSU_DMA_PCI) += hsu_dma_pci.o +hsu_dma_pci-objs := pci.o diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c new file mode 100644 index 000000000000..683ba9b62795 --- /dev/null +++ b/drivers/dma/hsu/hsu.c @@ -0,0 +1,504 @@ +/* + * Core driver for the High Speed UART DMA + * + * Copyright (C) 2015 Intel Corporation + * Author: Andy Shevchenko + * + * Partially based on the bits found in drivers/tty/serial/mfd.c. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * DMA channel allocation: + * 1. Even number chans are used for DMA Read (UART TX), odd chans for DMA + * Write (UART RX). + * 2. 0/1 channel are assigned to port 0, 2/3 chan to port 1, 4/5 chan to + * port 3, and so on. + */ + +#include +#include +#include +#include +#include +#include + +#include "hsu.h" + +#define HSU_DMA_BUSWIDTHS \ + BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \ + BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_8_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_16_BYTES) + +static inline void hsu_chan_disable(struct hsu_dma_chan *hsuc) +{ + hsu_chan_writel(hsuc, HSU_CH_CR, 0); +} + +static inline void hsu_chan_enable(struct hsu_dma_chan *hsuc) +{ + u32 cr = HSU_CH_CR_CHA; + + if (hsuc->direction == DMA_MEM_TO_DEV) + cr &= ~HSU_CH_CR_CHD; + else if (hsuc->direction == DMA_DEV_TO_MEM) + cr |= HSU_CH_CR_CHD; + + hsu_chan_writel(hsuc, HSU_CH_CR, cr); +} + +static void hsu_dma_chan_start(struct hsu_dma_chan *hsuc) +{ + struct dma_slave_config *config = &hsuc->config; + struct hsu_dma_desc *desc = hsuc->desc; + u32 bsr, mtsr; + u32 dcr = HSU_CH_DCR_CHSOE | HSU_CH_DCR_CHEI; + unsigned int i, count; + + if (hsuc->direction == DMA_MEM_TO_DEV) { + bsr = config->dst_maxburst; + mtsr = config->dst_addr_width; + } else if (hsuc->direction == DMA_DEV_TO_MEM) { + bsr = config->src_maxburst; + mtsr = config->src_addr_width; + } else { + /* Not supported direction */ + return; + } + + hsu_chan_disable(hsuc); + + hsu_chan_writel(hsuc, HSU_CH_DCR, 0); + hsu_chan_writel(hsuc, HSU_CH_BSR, bsr); + hsu_chan_writel(hsuc, HSU_CH_MTSR, mtsr); + + /* Set descriptors */ + count = (desc->nents - desc->active) % HSU_DMA_CHAN_NR_DESC; + for (i = 0; i < count; i++) { + hsu_chan_writel(hsuc, HSU_CH_DxSAR(i), desc->sg[i].addr); + hsu_chan_writel(hsuc, HSU_CH_DxTSR(i), desc->sg[i].len); + + /* Prepare value for DCR */ + dcr |= HSU_CH_DCR_DESCA(i); + dcr |= HSU_CH_DCR_CHTOI(i); /* timeout bit, see HSU Errata 1 */ + + desc->active++; + } + /* Only for the last descriptor in the chain */ + dcr |= HSU_CH_DCR_CHSOD(count - 1); + dcr |= HSU_CH_DCR_CHDI(count - 1); + + hsu_chan_writel(hsuc, HSU_CH_DCR, dcr); + + hsu_chan_enable(hsuc); +} + +static void hsu_dma_stop_channel(struct hsu_dma_chan *hsuc) +{ + unsigned long flags; + + spin_lock_irqsave(&hsuc->lock, flags); + hsu_chan_disable(hsuc); + hsu_chan_writel(hsuc, HSU_CH_DCR, 0); + spin_unlock_irqrestore(&hsuc->lock, flags); +} + +static void hsu_dma_start_channel(struct hsu_dma_chan *hsuc) +{ + unsigned long flags; + + spin_lock_irqsave(&hsuc->lock, flags); + hsu_dma_chan_start(hsuc); + spin_unlock_irqrestore(&hsuc->lock, flags); +} + +static void hsu_dma_start_transfer(struct hsu_dma_chan *hsuc) +{ + struct virt_dma_desc *vdesc; + + /* Get the next descriptor */ + vdesc = vchan_next_desc(&hsuc->vchan); + if (!vdesc) { + hsuc->desc = NULL; + return; + } + + list_del(&vdesc->node); + hsuc->desc = to_hsu_dma_desc(vdesc); + + /* Start the channel with a new descriptor */ + hsu_dma_start_channel(hsuc); +} + +static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc) +{ + unsigned long flags; + u32 sr; + + spin_lock_irqsave(&hsuc->lock, flags); + sr = hsu_chan_readl(hsuc, HSU_CH_SR); + spin_unlock_irqrestore(&hsuc->lock, flags); + + return sr; +} + +irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) +{ + struct hsu_dma_chan *hsuc; + struct hsu_dma_desc *desc; + unsigned long flags; + u32 sr; + + /* Sanity check */ + if (nr >= chip->pdata->nr_channels) + return IRQ_NONE; + + hsuc = &chip->hsu->chan[nr]; + + /* + * No matter what situation, need read clear the IRQ status + * There is a bug, see Errata 5, HSD 2900918 + */ + sr = hsu_dma_chan_get_sr(hsuc); + if (!sr) + return IRQ_NONE; + + /* Timeout IRQ, need wait some time, see Errata 2 */ + if (hsuc->direction == DMA_DEV_TO_MEM && (sr & HSU_CH_SR_DESCTO_ANY)) + udelay(2); + + sr &= ~HSU_CH_SR_DESCTO_ANY; + if (!sr) + return IRQ_HANDLED; + + spin_lock_irqsave(&hsuc->vchan.lock, flags); + desc = hsuc->desc; + if (desc) { + if (sr & HSU_CH_SR_CHE) { + desc->status = DMA_ERROR; + } else if (desc->active < desc->nents) { + hsu_dma_start_channel(hsuc); + } else { + vchan_cookie_complete(&desc->vdesc); + desc->status = DMA_COMPLETE; + hsu_dma_start_transfer(hsuc); + } + } + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(hsu_dma_irq); + +static struct hsu_dma_desc *hsu_dma_alloc_desc(unsigned int nents) +{ + struct hsu_dma_desc *desc; + + desc = kzalloc(sizeof(*desc), GFP_ATOMIC); + if (!desc) + return NULL; + + desc->sg = kcalloc(nents, sizeof(*desc->sg), GFP_ATOMIC); + if (!desc->sg) { + kfree(desc); + return NULL; + } + + return desc; +} + +static void hsu_dma_desc_free(struct virt_dma_desc *vdesc) +{ + struct hsu_dma_desc *desc = to_hsu_dma_desc(vdesc); + + kfree(desc->sg); + kfree(desc); +} + +static struct dma_async_tx_descriptor *hsu_dma_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, enum dma_transfer_direction direction, + unsigned long flags, void *context) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + struct hsu_dma_desc *desc; + struct scatterlist *sg; + unsigned int i; + + desc = hsu_dma_alloc_desc(sg_len); + if (!desc) + return NULL; + + for_each_sg(sgl, sg, sg_len, i) { + desc->sg[i].addr = sg_dma_address(sg); + desc->sg[i].len = sg_dma_len(sg); + } + + desc->nents = sg_len; + desc->direction = direction; + desc->active = 0; + desc->status = DMA_IN_PROGRESS; + + return vchan_tx_prep(&hsuc->vchan, &desc->vdesc, flags); +} + +static void hsu_dma_issue_pending(struct dma_chan *chan) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&hsuc->vchan.lock, flags); + if (vchan_issue_pending(&hsuc->vchan) && !hsuc->desc) + hsu_dma_start_transfer(hsuc); + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); +} + +static size_t hsu_dma_desc_size(struct hsu_dma_desc *desc) +{ + size_t bytes = 0; + unsigned int i; + + for (i = desc->active; i < desc->nents; i++) + bytes += desc->sg[i].len; + + return bytes; +} + +static size_t hsu_dma_active_desc_size(struct hsu_dma_chan *hsuc) +{ + struct hsu_dma_desc *desc = hsuc->desc; + size_t bytes = hsu_dma_desc_size(desc); + int i; + unsigned long flags; + + spin_lock_irqsave(&hsuc->lock, flags); + i = desc->active % HSU_DMA_CHAN_NR_DESC; + do { + bytes += hsu_chan_readl(hsuc, HSU_CH_DxTSR(i)); + } while (--i >= 0); + spin_unlock_irqrestore(&hsuc->lock, flags); + + return bytes; +} + +static enum dma_status hsu_dma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *state) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + struct virt_dma_desc *vdesc; + enum dma_status status; + size_t bytes; + unsigned long flags; + + status = dma_cookie_status(chan, cookie, state); + if (status == DMA_COMPLETE) + return status; + + spin_lock_irqsave(&hsuc->vchan.lock, flags); + vdesc = vchan_find_desc(&hsuc->vchan, cookie); + if (hsuc->desc && cookie == hsuc->desc->vdesc.tx.cookie) { + bytes = hsu_dma_active_desc_size(hsuc); + dma_set_residue(state, bytes); + status = hsuc->desc->status; + } else if (vdesc) { + bytes = hsu_dma_desc_size(to_hsu_dma_desc(vdesc)); + dma_set_residue(state, bytes); + } + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); + + return status; +} + +static int hsu_dma_slave_config(struct dma_chan *chan, + struct dma_slave_config *config) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + + /* Check if chan will be configured for slave transfers */ + if (!is_slave_direction(config->direction)) + return -EINVAL; + + memcpy(&hsuc->config, config, sizeof(hsuc->config)); + + return 0; +} + +static void hsu_dma_chan_deactivate(struct hsu_dma_chan *hsuc) +{ + unsigned long flags; + + spin_lock_irqsave(&hsuc->lock, flags); + hsu_chan_disable(hsuc); + spin_unlock_irqrestore(&hsuc->lock, flags); +} + +static void hsu_dma_chan_activate(struct hsu_dma_chan *hsuc) +{ + unsigned long flags; + + spin_lock_irqsave(&hsuc->lock, flags); + hsu_chan_enable(hsuc); + spin_unlock_irqrestore(&hsuc->lock, flags); +} + +static int hsu_dma_pause(struct dma_chan *chan) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&hsuc->vchan.lock, flags); + if (hsuc->desc && hsuc->desc->status == DMA_IN_PROGRESS) { + hsu_dma_chan_deactivate(hsuc); + hsuc->desc->status = DMA_PAUSED; + } + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); + + return 0; +} + +static int hsu_dma_resume(struct dma_chan *chan) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&hsuc->vchan.lock, flags); + if (hsuc->desc && hsuc->desc->status == DMA_PAUSED) { + hsuc->desc->status = DMA_IN_PROGRESS; + hsu_dma_chan_activate(hsuc); + } + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); + + return 0; +} + +static int hsu_dma_terminate_all(struct dma_chan *chan) +{ + struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); + unsigned long flags; + LIST_HEAD(head); + + spin_lock_irqsave(&hsuc->vchan.lock, flags); + + hsu_dma_stop_channel(hsuc); + hsuc->desc = NULL; + + vchan_get_all_descriptors(&hsuc->vchan, &head); + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); + vchan_dma_desc_free_list(&hsuc->vchan, &head); + + return 0; +} + +static int hsu_dma_alloc_chan_resources(struct dma_chan *chan) +{ + return 0; +} + +static void hsu_dma_free_chan_resources(struct dma_chan *chan) +{ + vchan_free_chan_resources(to_virt_chan(chan)); +} + +int hsu_dma_probe(struct hsu_dma_chip *chip) +{ + struct hsu_dma *hsu; + struct hsu_dma_platform_data *pdata = chip->pdata; + void __iomem *addr = chip->regs + chip->offset; + unsigned short i; + int ret; + + hsu = devm_kzalloc(chip->dev, sizeof(*hsu), GFP_KERNEL); + if (!hsu) + return -ENOMEM; + + chip->hsu = hsu; + + if (!pdata) { + pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + chip->pdata = pdata; + + /* Guess nr_channels from the IO space length */ + pdata->nr_channels = (chip->length - chip->offset) / + HSU_DMA_CHAN_LENGTH; + } + + hsu->chan = devm_kcalloc(chip->dev, pdata->nr_channels, + sizeof(*hsu->chan), GFP_KERNEL); + if (!hsu->chan) + return -ENOMEM; + + INIT_LIST_HEAD(&hsu->dma.channels); + for (i = 0; i < pdata->nr_channels; i++) { + struct hsu_dma_chan *hsuc = &hsu->chan[i]; + + hsuc->vchan.desc_free = hsu_dma_desc_free; + vchan_init(&hsuc->vchan, &hsu->dma); + + hsuc->direction = (i & 0x1) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; + hsuc->reg = addr + i * HSU_DMA_CHAN_LENGTH; + + spin_lock_init(&hsuc->lock); + } + + dma_cap_set(DMA_SLAVE, hsu->dma.cap_mask); + dma_cap_set(DMA_PRIVATE, hsu->dma.cap_mask); + + hsu->dma.device_alloc_chan_resources = hsu_dma_alloc_chan_resources; + hsu->dma.device_free_chan_resources = hsu_dma_free_chan_resources; + + hsu->dma.device_prep_slave_sg = hsu_dma_prep_slave_sg; + + hsu->dma.device_issue_pending = hsu_dma_issue_pending; + hsu->dma.device_tx_status = hsu_dma_tx_status; + + hsu->dma.device_config = hsu_dma_slave_config; + hsu->dma.device_pause = hsu_dma_pause; + hsu->dma.device_resume = hsu_dma_resume; + hsu->dma.device_terminate_all = hsu_dma_terminate_all; + + hsu->dma.src_addr_widths = HSU_DMA_BUSWIDTHS; + hsu->dma.dst_addr_widths = HSU_DMA_BUSWIDTHS; + hsu->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + hsu->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + + hsu->dma.dev = chip->dev; + + ret = dma_async_device_register(&hsu->dma); + if (ret) + return ret; + + dev_info(chip->dev, "Found HSU DMA, %d channels\n", pdata->nr_channels); + return 0; +} +EXPORT_SYMBOL_GPL(hsu_dma_probe); + +int hsu_dma_remove(struct hsu_dma_chip *chip) +{ + struct hsu_dma *hsu = chip->hsu; + unsigned short i; + + dma_async_device_unregister(&hsu->dma); + + for (i = 0; i < chip->pdata->nr_channels; i++) { + struct hsu_dma_chan *hsuc = &hsu->chan[i]; + + tasklet_kill(&hsuc->vchan.task); + } + + return 0; +} +EXPORT_SYMBOL_GPL(hsu_dma_remove); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("High Speed UART DMA core driver"); +MODULE_AUTHOR("Andy Shevchenko "); diff --git a/drivers/dma/hsu/hsu.h b/drivers/dma/hsu/hsu.h new file mode 100644 index 000000000000..0275233cf550 --- /dev/null +++ b/drivers/dma/hsu/hsu.h @@ -0,0 +1,118 @@ +/* + * Driver for the High Speed UART DMA + * + * Copyright (C) 2015 Intel Corporation + * + * Partially based on the bits found in drivers/tty/serial/mfd.c. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DMA_HSU_H__ +#define __DMA_HSU_H__ + +#include +#include + +#include "../virt-dma.h" + +#define HSU_CH_SR 0x00 /* channel status */ +#define HSU_CH_CR 0x04 /* channel control */ +#define HSU_CH_DCR 0x08 /* descriptor control */ +#define HSU_CH_BSR 0x10 /* FIFO buffer size */ +#define HSU_CH_MTSR 0x14 /* minimum transfer size */ +#define HSU_CH_DxSAR(x) (0x20 + 8 * (x)) /* desc start addr */ +#define HSU_CH_DxTSR(x) (0x24 + 8 * (x)) /* desc transfer size */ +#define HSU_CH_D0SAR 0x20 /* desc 0 start addr */ +#define HSU_CH_D0TSR 0x24 /* desc 0 transfer size */ +#define HSU_CH_D1SAR 0x28 +#define HSU_CH_D1TSR 0x2c +#define HSU_CH_D2SAR 0x30 +#define HSU_CH_D2TSR 0x34 +#define HSU_CH_D3SAR 0x38 +#define HSU_CH_D3TSR 0x3c + +#define HSU_DMA_CHAN_NR_DESC 4 +#define HSU_DMA_CHAN_LENGTH 0x40 + +/* Bits in HSU_CH_SR */ +#define HSU_CH_SR_DESCTO(x) BIT(8 + (x)) +#define HSU_CH_SR_DESCTO_ANY (BIT(11) | BIT(10) | BIT(9) | BIT(8)) +#define HSU_CH_SR_CHE BIT(15) + +/* Bits in HSU_CH_CR */ +#define HSU_CH_CR_CHA BIT(0) +#define HSU_CH_CR_CHD BIT(1) + +/* Bits in HSU_CH_DCR */ +#define HSU_CH_DCR_DESCA(x) BIT(0 + (x)) +#define HSU_CH_DCR_CHSOD(x) BIT(8 + (x)) +#define HSU_CH_DCR_CHSOTO BIT(14) +#define HSU_CH_DCR_CHSOE BIT(15) +#define HSU_CH_DCR_CHDI(x) BIT(16 + (x)) +#define HSU_CH_DCR_CHEI BIT(23) +#define HSU_CH_DCR_CHTOI(x) BIT(24 + (x)) + +struct hsu_dma_sg { + dma_addr_t addr; + unsigned int len; +}; + +struct hsu_dma_desc { + struct virt_dma_desc vdesc; + enum dma_transfer_direction direction; + struct hsu_dma_sg *sg; + unsigned int nents; + unsigned int active; + enum dma_status status; +}; + +static inline struct hsu_dma_desc *to_hsu_dma_desc(struct virt_dma_desc *vdesc) +{ + return container_of(vdesc, struct hsu_dma_desc, vdesc); +} + +struct hsu_dma_chan { + struct virt_dma_chan vchan; + + void __iomem *reg; + spinlock_t lock; + + /* hardware configuration */ + enum dma_transfer_direction direction; + struct dma_slave_config config; + + struct hsu_dma_desc *desc; +}; + +static inline struct hsu_dma_chan *to_hsu_dma_chan(struct dma_chan *chan) +{ + return container_of(chan, struct hsu_dma_chan, vchan.chan); +} + +static inline u32 hsu_chan_readl(struct hsu_dma_chan *hsuc, int offset) +{ + return readl(hsuc->reg + offset); +} + +static inline void hsu_chan_writel(struct hsu_dma_chan *hsuc, int offset, + u32 value) +{ + writel(value, hsuc->reg + offset); +} + +struct hsu_dma { + struct dma_device dma; + + /* channels */ + struct hsu_dma_chan *chan; +}; + +static inline struct hsu_dma *to_hsu_dma(struct dma_device *ddev) +{ + return container_of(ddev, struct hsu_dma, dma); +} + +#endif /* __DMA_HSU_H__ */ diff --git a/drivers/dma/hsu/pci.c b/drivers/dma/hsu/pci.c new file mode 100644 index 000000000000..563b4685d766 --- /dev/null +++ b/drivers/dma/hsu/pci.c @@ -0,0 +1,123 @@ +/* + * PCI driver for the High Speed UART DMA + * + * Copyright (C) 2015 Intel Corporation + * Author: Andy Shevchenko + * + * Partially based on the bits found in drivers/tty/serial/mfd.c. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "hsu.h" + +#define HSU_PCI_DMASR 0x00 +#define HSU_PCI_DMAISR 0x04 + +#define HSU_PCI_CHAN_OFFSET 0x100 + +static irqreturn_t hsu_pci_irq(int irq, void *dev) +{ + struct hsu_dma_chip *chip = dev; + u32 dmaisr; + unsigned short i; + irqreturn_t ret = IRQ_NONE; + + dmaisr = readl(chip->regs + HSU_PCI_DMAISR); + for (i = 0; i < chip->pdata->nr_channels; i++) { + if (dmaisr & 0x1) + ret |= hsu_dma_irq(chip, i); + dmaisr >>= 1; + } + + return ret; +} + +static int hsu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct hsu_dma_chip *chip; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); + if (ret) { + dev_err(&pdev->dev, "I/O memory remapping failed\n"); + return ret; + } + + pci_set_master(pdev); + pci_try_set_mwi(pdev); + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->dev = &pdev->dev; + chip->regs = pcim_iomap_table(pdev)[0]; + chip->length = pci_resource_len(pdev, 0); + chip->offset = HSU_PCI_CHAN_OFFSET; + chip->irq = pdev->irq; + + pci_enable_msi(pdev); + + ret = hsu_dma_probe(chip); + if (ret) + return ret; + + ret = request_irq(chip->irq, hsu_pci_irq, 0, "hsu_dma_pci", chip); + if (ret) + goto err_register_irq; + + pci_set_drvdata(pdev, chip); + + return 0; + +err_register_irq: + hsu_dma_remove(chip); + return ret; +} + +static void hsu_pci_remove(struct pci_dev *pdev) +{ + struct hsu_dma_chip *chip = pci_get_drvdata(pdev); + + free_irq(chip->irq, chip); + hsu_dma_remove(chip); +} + +static const struct pci_device_id hsu_pci_id_table[] = { + { PCI_VDEVICE(INTEL, 0x081e), 0 }, + { } +}; +MODULE_DEVICE_TABLE(pci, hsu_pci_id_table); + +static struct pci_driver hsu_pci_driver = { + .name = "hsu_dma_pci", + .id_table = hsu_pci_id_table, + .probe = hsu_pci_probe, + .remove = hsu_pci_remove, +}; + +module_pci_driver(hsu_pci_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("High Speed UART DMA PCI driver"); +MODULE_AUTHOR("Andy Shevchenko "); diff --git a/include/linux/dma/hsu.h b/include/linux/dma/hsu.h new file mode 100644 index 000000000000..234393a6997b --- /dev/null +++ b/include/linux/dma/hsu.h @@ -0,0 +1,48 @@ +/* + * Driver for the High Speed UART DMA + * + * Copyright (C) 2015 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _DMA_HSU_H +#define _DMA_HSU_H + +#include +#include + +#include + +struct hsu_dma; + +/** + * struct hsu_dma_chip - representation of HSU DMA hardware + * @dev: struct device of the DMA controller + * @irq: irq line + * @regs: memory mapped I/O space + * @length: I/O space length + * @offset: offset of the I/O space where registers are located + * @hsu: struct hsu_dma that is filed by ->probe() + * @pdata: platform data for the DMA controller if provided + */ +struct hsu_dma_chip { + struct device *dev; + int irq; + void __iomem *regs; + unsigned int length; + unsigned int offset; + struct hsu_dma *hsu; + struct hsu_dma_platform_data *pdata; +}; + +/* Export to the internal users */ +irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr); + +/* Export to the platform drivers */ +int hsu_dma_probe(struct hsu_dma_chip *chip); +int hsu_dma_remove(struct hsu_dma_chip *chip); + +#endif /* _DMA_HSU_H */ diff --git a/include/linux/platform_data/dma-hsu.h b/include/linux/platform_data/dma-hsu.h new file mode 100644 index 000000000000..8a1f6a4920b2 --- /dev/null +++ b/include/linux/platform_data/dma-hsu.h @@ -0,0 +1,25 @@ +/* + * Driver for the High Speed UART DMA + * + * Copyright (C) 2015 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _PLATFORM_DATA_DMA_HSU_H +#define _PLATFORM_DATA_DMA_HSU_H + +#include + +struct hsu_dma_slave { + struct device *dma_dev; + int chan_id; +}; + +struct hsu_dma_platform_data { + unsigned short nr_channels; +}; + +#endif /* _PLATFORM_DATA_DMA_HSU_H */ -- cgit v1.2.3 From 1bd187de536494a27925902b9653e9ef0ace4774 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 23 Feb 2015 16:24:44 +0200 Subject: x86, intel-mid: remove Intel MID specific serial support Since we have a native 8250 driver carrying the Intel MID serial devices the specific support is not needed anymore. This patch removes it for Intel MID. Note that the console device name is changed from ttyMFDx to ttySx. Signed-off-by: Andy Shevchenko Acked-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/Kconfig.debug | 4 - arch/x86/include/asm/intel-mid.h | 3 - arch/x86/kernel/early_printk.c | 6 - arch/x86/platform/intel-mid/Makefile | 1 - .../platform/intel-mid/early_printk_intel_mid.c | 112 -- drivers/tty/serial/Kconfig | 10 - drivers/tty/serial/Makefile | 1 - drivers/tty/serial/mfd.c | 1505 -------------------- include/linux/serial_mfd.h | 47 - include/uapi/linux/serial_reg.h | 19 - 10 files changed, 1708 deletions(-) delete mode 100644 arch/x86/platform/intel-mid/early_printk_intel_mid.c delete mode 100644 drivers/tty/serial/mfd.c delete mode 100644 include/linux/serial_mfd.h (limited to 'include') diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 20028da8ae18..72484a645f05 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -43,10 +43,6 @@ config EARLY_PRINTK with klogd/syslogd or the X server. You should normally N here, unless you want to debug such a crash. -config EARLY_PRINTK_INTEL_MID - bool "Early printk for Intel MID platform support" - depends on EARLY_PRINTK && X86_INTEL_MID - config EARLY_PRINTK_DBGP bool "Early printk via EHCI debug port" depends on EARLY_PRINTK && PCI diff --git a/arch/x86/include/asm/intel-mid.h b/arch/x86/include/asm/intel-mid.h index 705d35708a50..7c5af123bdbd 100644 --- a/arch/x86/include/asm/intel-mid.h +++ b/arch/x86/include/asm/intel-mid.h @@ -136,9 +136,6 @@ extern enum intel_mid_timer_options intel_mid_timer_options; #define SFI_MTMR_MAX_NUM 8 #define SFI_MRTC_MAX 8 -extern struct console early_hsu_console; -extern void hsu_early_console_init(const char *); - extern void intel_scu_devices_create(void); extern void intel_scu_devices_destroy(void); diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c index a62536a1be88..f85e3fb50f28 100644 --- a/arch/x86/kernel/early_printk.c +++ b/arch/x86/kernel/early_printk.c @@ -375,12 +375,6 @@ static int __init setup_early_printk(char *buf) if (!strncmp(buf, "xen", 3)) early_console_register(&xenboot_console, keep); #endif -#ifdef CONFIG_EARLY_PRINTK_INTEL_MID - if (!strncmp(buf, "hsu", 3)) { - hsu_early_console_init(buf + 3); - early_console_register(&early_hsu_console, keep); - } -#endif #ifdef CONFIG_EARLY_PRINTK_EFI if (!strncmp(buf, "efi", 3)) early_console_register(&early_efi_console, keep); diff --git a/arch/x86/platform/intel-mid/Makefile b/arch/x86/platform/intel-mid/Makefile index 0a8ee703b9fa..0ce1b1913673 100644 --- a/arch/x86/platform/intel-mid/Makefile +++ b/arch/x86/platform/intel-mid/Makefile @@ -1,5 +1,4 @@ obj-$(CONFIG_X86_INTEL_MID) += intel-mid.o intel_mid_vrtc.o mfld.o mrfl.o -obj-$(CONFIG_EARLY_PRINTK_INTEL_MID) += early_printk_intel_mid.o # SFI specific code ifdef CONFIG_X86_INTEL_MID diff --git a/arch/x86/platform/intel-mid/early_printk_intel_mid.c b/arch/x86/platform/intel-mid/early_printk_intel_mid.c deleted file mode 100644 index 4e720829ab90..000000000000 --- a/arch/x86/platform/intel-mid/early_printk_intel_mid.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * early_printk_intel_mid.c - early consoles for Intel MID platforms - * - * Copyright (c) 2008-2010, Intel Corporation - * - * 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; version 2 - * of the License. - */ - -/* - * This file implements early console named hsu. - * hsu is based on a High Speed UART device which only exists in the Medfield - * platform - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* - * Following is the early console based on Medfield HSU (High - * Speed UART) device. - */ -#define HSU_PORT_BASE 0xffa28080 - -static void __iomem *phsu; - -void hsu_early_console_init(const char *s) -{ - unsigned long paddr, port = 0; - u8 lcr; - - /* - * Select the early HSU console port if specified by user in the - * kernel command line. - */ - if (*s && !kstrtoul(s, 10, &port)) - port = clamp_val(port, 0, 2); - - paddr = HSU_PORT_BASE + port * 0x80; - phsu = (void __iomem *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, paddr); - - /* Disable FIFO */ - writeb(0x0, phsu + UART_FCR); - - /* Set to default 115200 bps, 8n1 */ - lcr = readb(phsu + UART_LCR); - writeb((0x80 | lcr), phsu + UART_LCR); - writeb(0x18, phsu + UART_DLL); - writeb(lcr, phsu + UART_LCR); - writel(0x3600, phsu + UART_MUL*4); - - writeb(0x8, phsu + UART_MCR); - writeb(0x7, phsu + UART_FCR); - writeb(0x3, phsu + UART_LCR); - - /* Clear IRQ status */ - readb(phsu + UART_LSR); - readb(phsu + UART_RX); - readb(phsu + UART_IIR); - readb(phsu + UART_MSR); - - /* Enable FIFO */ - writeb(0x7, phsu + UART_FCR); -} - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -static void early_hsu_putc(char ch) -{ - unsigned int timeout = 10000; /* 10ms */ - u8 status; - - while (--timeout) { - status = readb(phsu + UART_LSR); - if (status & BOTH_EMPTY) - break; - udelay(1); - } - - /* Only write the char when there was no timeout */ - if (timeout) - writeb(ch, phsu + UART_TX); -} - -static void early_hsu_write(struct console *con, const char *str, unsigned n) -{ - int i; - - for (i = 0; i < n && *str; i++) { - if (*str == '\n') - early_hsu_putc('\r'); - early_hsu_putc(*str); - str++; - } -} - -struct console early_hsu_console = { - .name = "earlyhsu", - .write = early_hsu_write, - .flags = CON_PRINTBUFFER, - .index = -1, -}; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 60c368a5dbf1..c9dbc626038d 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -483,16 +483,6 @@ config SERIAL_SA1100_CONSOLE your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) -config SERIAL_MFD_HSU - tristate "Medfield High Speed UART support" - depends on PCI - select SERIAL_CORE - -config SERIAL_MFD_HSU_CONSOLE - bool "Medfield HSU serial console support" - depends on SERIAL_MFD_HSU=y - select SERIAL_CORE_CONSOLE - config SERIAL_BFIN tristate "Blackfin serial port support" depends on BLACKFIN diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 599be4b05a26..f42b4f9845df 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -78,7 +78,6 @@ obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o -obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c deleted file mode 100644 index 8fe4501d7565..000000000000 --- a/drivers/tty/serial/mfd.c +++ /dev/null @@ -1,1505 +0,0 @@ -/* - * mfd.c: driver for High Speed UART device of Intel Medfield platform - * - * Refer pxa.c, 8250.c and some other drivers in drivers/serial/ - * - * (C) Copyright 2010 Intel Corporation - * - * 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; version 2 - * of the License. - */ - -/* Notes: - * 1. DMA channel allocation: 0/1 channel are assigned to port 0, - * 2/3 chan to port 1, 4/5 chan to port 3. Even number chans - * are used for RX, odd chans for TX - * - * 2. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always - * asserted, only when the HW is reset the DDCD and DDSR will - * be triggered - */ - -#if defined(CONFIG_SERIAL_MFD_HSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define HSU_DMA_BUF_SIZE 2048 - -#define chan_readl(chan, offset) readl(chan->reg + offset) -#define chan_writel(chan, offset, val) writel(val, chan->reg + offset) - -#define mfd_readl(obj, offset) readl(obj->reg + offset) -#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) - -static int hsu_dma_enable; -module_param(hsu_dma_enable, int, 0); -MODULE_PARM_DESC(hsu_dma_enable, - "It is a bitmap to set working mode, if bit[x] is 1, then port[x] will work in DMA mode, otherwise in PIO mode."); - -struct hsu_dma_buffer { - u8 *buf; - dma_addr_t dma_addr; - u32 dma_size; - u32 ofs; -}; - -struct hsu_dma_chan { - u32 id; - enum dma_data_direction dirt; - struct uart_hsu_port *uport; - void __iomem *reg; -}; - -struct uart_hsu_port { - struct uart_port port; - unsigned char ier; - unsigned char lcr; - unsigned char mcr; - unsigned int lsr_break_flag; - char name[12]; - int index; - struct device *dev; - - struct hsu_dma_chan *txc; - struct hsu_dma_chan *rxc; - struct hsu_dma_buffer txbuf; - struct hsu_dma_buffer rxbuf; - int use_dma; /* flag for DMA/PIO */ - int running; - int dma_tx_on; -}; - -/* Top level data structure of HSU */ -struct hsu_port { - void __iomem *reg; - unsigned long paddr; - unsigned long iolen; - u32 irq; - - struct uart_hsu_port port[3]; - struct hsu_dma_chan chans[10]; - - struct dentry *debugfs; -}; - -static inline unsigned int serial_in(struct uart_hsu_port *up, int offset) -{ - unsigned int val; - - if (offset > UART_MSR) { - offset <<= 2; - val = readl(up->port.membase + offset); - } else - val = (unsigned int)readb(up->port.membase + offset); - - return val; -} - -static inline void serial_out(struct uart_hsu_port *up, int offset, int value) -{ - if (offset > UART_MSR) { - offset <<= 2; - writel(value, up->port.membase + offset); - } else { - unsigned char val = value & 0xff; - writeb(val, up->port.membase + offset); - } -} - -#ifdef CONFIG_DEBUG_FS - -#define HSU_REGS_BUFSIZE 1024 - - -static ssize_t port_show_regs(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct uart_hsu_port *up = file->private_data; - char *buf; - u32 len = 0; - ssize_t ret; - - buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); - if (!buf) - return 0; - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MFD HSU port[%d] regs:\n", up->index); - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "=================================\n"); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "IER: \t\t0x%08x\n", serial_in(up, UART_IER)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "PS: \t\t0x%08x\n", serial_in(up, UART_PS)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV)); - - if (len > HSU_REGS_BUFSIZE) - len = HSU_REGS_BUFSIZE; - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return ret; -} - -static ssize_t dma_show_regs(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct hsu_dma_chan *chan = file->private_data; - char *buf; - u32 len = 0; - ssize_t ret; - - buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); - if (!buf) - return 0; - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MFD HSU DMA channel [%d] regs:\n", chan->id); - - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "=================================\n"); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR)); - len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, - "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR)); - - if (len > HSU_REGS_BUFSIZE) - len = HSU_REGS_BUFSIZE; - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return ret; -} - -static const struct file_operations port_regs_ops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = port_show_regs, - .llseek = default_llseek, -}; - -static const struct file_operations dma_regs_ops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = dma_show_regs, - .llseek = default_llseek, -}; - -static int hsu_debugfs_init(struct hsu_port *hsu) -{ - int i; - char name[32]; - - hsu->debugfs = debugfs_create_dir("hsu", NULL); - if (!hsu->debugfs) - return -ENOMEM; - - for (i = 0; i < 3; i++) { - snprintf(name, sizeof(name), "port_%d_regs", i); - debugfs_create_file(name, S_IFREG | S_IRUGO, - hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops); - } - - for (i = 0; i < 6; i++) { - snprintf(name, sizeof(name), "dma_chan_%d_regs", i); - debugfs_create_file(name, S_IFREG | S_IRUGO, - hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops); - } - - return 0; -} - -static void hsu_debugfs_remove(struct hsu_port *hsu) -{ - if (hsu->debugfs) - debugfs_remove_recursive(hsu->debugfs); -} - -#else -static inline int hsu_debugfs_init(struct hsu_port *hsu) -{ - return 0; -} - -static inline void hsu_debugfs_remove(struct hsu_port *hsu) -{ -} -#endif /* CONFIG_DEBUG_FS */ - -static void serial_hsu_enable_ms(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - - up->ier |= UART_IER_MSI; - serial_out(up, UART_IER, up->ier); -} - -static void hsu_dma_tx(struct uart_hsu_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - struct hsu_dma_buffer *dbuf = &up->txbuf; - int count; - - /* test_and_set_bit may be better, but anyway it's in lock protected mode */ - if (up->dma_tx_on) - return; - - /* Update the circ buf info */ - xmit->tail += dbuf->ofs; - xmit->tail &= UART_XMIT_SIZE - 1; - - up->port.icount.tx += dbuf->ofs; - dbuf->ofs = 0; - - /* Disable the channel */ - chan_writel(up->txc, HSU_CH_CR, 0x0); - - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) { - dma_sync_single_for_device(up->port.dev, - dbuf->dma_addr, - dbuf->dma_size, - DMA_TO_DEVICE); - - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - dbuf->ofs = count; - - /* Reprogram the channel */ - chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail); - chan_writel(up->txc, HSU_CH_D0TSR, count); - - /* Reenable the channel */ - chan_writel(up->txc, HSU_CH_DCR, 0x1 - | (0x1 << 8) - | (0x1 << 16) - | (0x1 << 24)); - up->dma_tx_on = 1; - chan_writel(up->txc, HSU_CH_CR, 0x1); - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); -} - -/* The buffer is already cache coherent */ -static void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, - struct hsu_dma_buffer *dbuf) -{ - dbuf->ofs = 0; - - chan_writel(rxc, HSU_CH_BSR, 32); - chan_writel(rxc, HSU_CH_MOTSR, 4); - - chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr); - chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size); - chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8) - | (0x1 << 16) - | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ - ); - chan_writel(rxc, HSU_CH_CR, 0x3); -} - -/* Protected by spin_lock_irqsave(port->lock) */ -static void serial_hsu_start_tx(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - - if (up->use_dma) { - hsu_dma_tx(up); - } else if (!(up->ier & UART_IER_THRI)) { - up->ier |= UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -} - -static void serial_hsu_stop_tx(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - struct hsu_dma_chan *txc = up->txc; - - if (up->use_dma) - chan_writel(txc, HSU_CH_CR, 0x0); - else if (up->ier & UART_IER_THRI) { - up->ier &= ~UART_IER_THRI; - serial_out(up, UART_IER, up->ier); - } -} - -/* This is always called in spinlock protected mode, so - * modify timeout timer is safe here */ -static void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts, - unsigned long *flags) -{ - struct hsu_dma_buffer *dbuf = &up->rxbuf; - struct hsu_dma_chan *chan = up->rxc; - struct uart_port *port = &up->port; - struct tty_port *tport = &port->state->port; - int count; - - /* - * First need to know how many is already transferred, - * then check if its a timeout DMA irq, and return - * the trail bytes out, push them up and reenable the - * channel - */ - - /* Timeout IRQ, need wait some time, see Errata 2 */ - if (int_sts & 0xf00) - udelay(2); - - /* Stop the channel */ - chan_writel(chan, HSU_CH_CR, 0x0); - - count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; - if (!count) { - /* Restart the channel before we leave */ - chan_writel(chan, HSU_CH_CR, 0x3); - return; - } - - dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, - dbuf->dma_size, DMA_FROM_DEVICE); - - /* - * Head will only wrap around when we recycle - * the DMA buffer, and when that happens, we - * explicitly set tail to 0. So head will - * always be greater than tail. - */ - tty_insert_flip_string(tport, dbuf->buf, count); - port->icount.rx += count; - - dma_sync_single_for_device(up->port.dev, dbuf->dma_addr, - dbuf->dma_size, DMA_FROM_DEVICE); - - /* Reprogram the channel */ - chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr); - chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size); - chan_writel(chan, HSU_CH_DCR, 0x1 - | (0x1 << 8) - | (0x1 << 16) - | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ - ); - spin_unlock_irqrestore(&up->port.lock, *flags); - tty_flip_buffer_push(tport); - spin_lock_irqsave(&up->port.lock, *flags); - - chan_writel(chan, HSU_CH_CR, 0x3); - -} - -static void serial_hsu_stop_rx(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - struct hsu_dma_chan *chan = up->rxc; - - if (up->use_dma) - chan_writel(chan, HSU_CH_CR, 0x2); - else { - up->ier &= ~UART_IER_RLSI; - up->port.read_status_mask &= ~UART_LSR_DR; - serial_out(up, UART_IER, up->ier); - } -} - -static inline void receive_chars(struct uart_hsu_port *up, int *status, - unsigned long *flags) -{ - unsigned int ch, flag; - unsigned int max_count = 256; - - do { - ch = serial_in(up, UART_RX); - flag = TTY_NORMAL; - up->port.icount.rx++; - - if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE))) { - - dev_warn(up->dev, "We really rush into ERR/BI case" - "status = 0x%02x", *status); - /* For statistics only */ - if (*status & UART_LSR_BI) { - *status &= ~(UART_LSR_FE | UART_LSR_PE); - up->port.icount.brk++; - /* - * We do the SysRQ and SAK checking - * here because otherwise the break - * may get masked by ignore_status_mask - * or read_status_mask. - */ - if (uart_handle_break(&up->port)) - goto ignore_char; - } else if (*status & UART_LSR_PE) - up->port.icount.parity++; - else if (*status & UART_LSR_FE) - up->port.icount.frame++; - if (*status & UART_LSR_OE) - up->port.icount.overrun++; - - /* Mask off conditions which should be ignored. */ - *status &= up->port.read_status_mask; - -#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE - if (up->port.cons && - up->port.cons->index == up->port.line) { - /* Recover the break flag from console xmit */ - *status |= up->lsr_break_flag; - up->lsr_break_flag = 0; - } -#endif - if (*status & UART_LSR_BI) { - flag = TTY_BREAK; - } else if (*status & UART_LSR_PE) - flag = TTY_PARITY; - else if (*status & UART_LSR_FE) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(&up->port, ch)) - goto ignore_char; - - uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); - ignore_char: - *status = serial_in(up, UART_LSR); - } while ((*status & UART_LSR_DR) && max_count--); - - spin_unlock_irqrestore(&up->port.lock, *flags); - tty_flip_buffer_push(&up->port.state->port); - spin_lock_irqsave(&up->port.lock, *flags); -} - -static void transmit_chars(struct uart_hsu_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - int count; - - if (up->port.x_char) { - serial_out(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_hsu_stop_tx(&up->port); - return; - } - - /* The IRQ is for TX FIFO half-empty */ - count = up->port.fifosize / 2; - - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - if (uart_circ_empty(xmit)) - serial_hsu_stop_tx(&up->port); -} - -static inline void check_modem_status(struct uart_hsu_port *up) -{ - int status; - - status = serial_in(up, UART_MSR); - - if ((status & UART_MSR_ANY_DELTA) == 0) - return; - - if (status & UART_MSR_TERI) - up->port.icount.rng++; - if (status & UART_MSR_DDSR) - up->port.icount.dsr++; - /* We may only get DDCD when HW init and reset */ - if (status & UART_MSR_DDCD) - uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); - /* Will start/stop_tx accordingly */ - if (status & UART_MSR_DCTS) - uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - - wake_up_interruptible(&up->port.state->port.delta_msr_wait); -} - -/* - * This handles the interrupt from one port. - */ -static irqreturn_t port_irq(int irq, void *dev_id) -{ - struct uart_hsu_port *up = dev_id; - unsigned int iir, lsr; - unsigned long flags; - - if (unlikely(!up->running)) - return IRQ_NONE; - - spin_lock_irqsave(&up->port.lock, flags); - if (up->use_dma) { - lsr = serial_in(up, UART_LSR); - if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE))) - dev_warn(up->dev, - "Got lsr irq while using DMA, lsr = 0x%2x\n", - lsr); - check_modem_status(up); - spin_unlock_irqrestore(&up->port.lock, flags); - return IRQ_HANDLED; - } - - iir = serial_in(up, UART_IIR); - if (iir & UART_IIR_NO_INT) { - spin_unlock_irqrestore(&up->port.lock, flags); - return IRQ_NONE; - } - - lsr = serial_in(up, UART_LSR); - if (lsr & UART_LSR_DR) - receive_chars(up, &lsr, &flags); - check_modem_status(up); - - /* lsr will be renewed during the receive_chars */ - if (lsr & UART_LSR_THRE) - transmit_chars(up); - - spin_unlock_irqrestore(&up->port.lock, flags); - return IRQ_HANDLED; -} - -static inline void dma_chan_irq(struct hsu_dma_chan *chan) -{ - struct uart_hsu_port *up = chan->uport; - unsigned long flags; - u32 int_sts; - - spin_lock_irqsave(&up->port.lock, flags); - - if (!up->use_dma || !up->running) - goto exit; - - /* - * No matter what situation, need read clear the IRQ status - * There is a bug, see Errata 5, HSD 2900918 - */ - int_sts = chan_readl(chan, HSU_CH_SR); - - /* Rx channel */ - if (chan->dirt == DMA_FROM_DEVICE) - hsu_dma_rx(up, int_sts, &flags); - - /* Tx channel */ - if (chan->dirt == DMA_TO_DEVICE) { - chan_writel(chan, HSU_CH_CR, 0x0); - up->dma_tx_on = 0; - hsu_dma_tx(up); - } - -exit: - spin_unlock_irqrestore(&up->port.lock, flags); - return; -} - -static irqreturn_t dma_irq(int irq, void *dev_id) -{ - struct hsu_port *hsu = dev_id; - u32 int_sts, i; - - int_sts = mfd_readl(hsu, HSU_GBL_DMAISR); - - /* Currently we only have 6 channels may be used */ - for (i = 0; i < 6; i++) { - if (int_sts & 0x1) - dma_chan_irq(&hsu->chans[i]); - int_sts >>= 1; - } - - return IRQ_HANDLED; -} - -static unsigned int serial_hsu_tx_empty(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - unsigned int ret; - - spin_lock_irqsave(&up->port.lock, flags); - ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; - spin_unlock_irqrestore(&up->port.lock, flags); - - return ret; -} - -static unsigned int serial_hsu_get_mctrl(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned char status; - unsigned int ret; - - status = serial_in(up, UART_MSR); - - ret = 0; - if (status & UART_MSR_DCD) - ret |= TIOCM_CAR; - if (status & UART_MSR_RI) - ret |= TIOCM_RNG; - if (status & UART_MSR_DSR) - ret |= TIOCM_DSR; - if (status & UART_MSR_CTS) - ret |= TIOCM_CTS; - return ret; -} - -static void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned char mcr = 0; - - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - mcr |= up->mcr; - - serial_out(up, UART_MCR, mcr); -} - -static void serial_hsu_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - if (break_state == -1) - up->lcr |= UART_LCR_SBC; - else - up->lcr &= ~UART_LCR_SBC; - serial_out(up, UART_LCR, up->lcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -/* - * What special to do: - * 1. chose the 64B fifo mode - * 2. start dma or pio depends on configuration - * 3. we only allocate dma memory when needed - */ -static int serial_hsu_startup(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - - pm_runtime_get_sync(up->dev); - - /* - * Clear the FIFO buffers and disable them. - * (they will be reenabled in set_termios()) - */ - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(up, UART_FCR, 0); - - /* Clear the interrupt registers. */ - (void) serial_in(up, UART_LSR); - (void) serial_in(up, UART_RX); - (void) serial_in(up, UART_IIR); - (void) serial_in(up, UART_MSR); - - /* Now, initialize the UART, default is 8n1 */ - serial_out(up, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irqsave(&up->port.lock, flags); - - up->port.mctrl |= TIOCM_OUT2; - serial_hsu_set_mctrl(&up->port, up->port.mctrl); - - /* - * Finally, enable interrupts. Note: Modem status interrupts - * are set via set_termios(), which will be occurring imminently - * anyway, so we don't enable them here. - */ - if (!up->use_dma) - up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE; - else - up->ier = 0; - serial_out(up, UART_IER, up->ier); - - spin_unlock_irqrestore(&up->port.lock, flags); - - /* DMA init */ - if (up->use_dma) { - struct hsu_dma_buffer *dbuf; - struct circ_buf *xmit = &port->state->xmit; - - up->dma_tx_on = 0; - - /* First allocate the RX buffer */ - dbuf = &up->rxbuf; - dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL); - if (!dbuf->buf) { - up->use_dma = 0; - goto exit; - } - dbuf->dma_addr = dma_map_single(port->dev, - dbuf->buf, - HSU_DMA_BUF_SIZE, - DMA_FROM_DEVICE); - dbuf->dma_size = HSU_DMA_BUF_SIZE; - - /* Start the RX channel right now */ - hsu_dma_start_rx_chan(up->rxc, dbuf); - - /* Next init the TX DMA */ - dbuf = &up->txbuf; - dbuf->buf = xmit->buf; - dbuf->dma_addr = dma_map_single(port->dev, - dbuf->buf, - UART_XMIT_SIZE, - DMA_TO_DEVICE); - dbuf->dma_size = UART_XMIT_SIZE; - - /* This should not be changed all around */ - chan_writel(up->txc, HSU_CH_BSR, 32); - chan_writel(up->txc, HSU_CH_MOTSR, 4); - dbuf->ofs = 0; - } - -exit: - /* And clear the interrupt registers again for luck. */ - (void) serial_in(up, UART_LSR); - (void) serial_in(up, UART_RX); - (void) serial_in(up, UART_IIR); - (void) serial_in(up, UART_MSR); - - up->running = 1; - return 0; -} - -static void serial_hsu_shutdown(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned long flags; - - /* Disable interrupts from this port */ - up->ier = 0; - serial_out(up, UART_IER, 0); - up->running = 0; - - spin_lock_irqsave(&up->port.lock, flags); - up->port.mctrl &= ~TIOCM_OUT2; - serial_hsu_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); - - /* Disable break condition and FIFOs */ - serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT); - serial_out(up, UART_FCR, 0); - - pm_runtime_put(up->dev); -} - -static void -serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - unsigned char cval, fcr = 0; - unsigned long flags; - unsigned int baud, quot; - u32 ps, mul; - - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } - - /* CMSPAR isn't supported by this driver */ - termios->c_cflag &= ~CMSPAR; - - if (termios->c_cflag & CSTOPB) - cval |= UART_LCR_STOP; - if (termios->c_cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(termios->c_cflag & PARODD)) - cval |= UART_LCR_EPAR; - - /* - * The base clk is 50Mhz, and the baud rate come from: - * baud = 50M * MUL / (DIV * PS * DLAB) - * - * For those basic low baud rate we can get the direct - * scalar from 2746800, like 115200 = 2746800/24. For those - * higher baud rate, we handle them case by case, mainly by - * adjusting the MUL/PS registers, and DIV register is kept - * as default value 0x3d09 to make things simple - */ - baud = uart_get_baud_rate(port, termios, old, 0, 4000000); - - quot = 1; - ps = 0x10; - mul = 0x3600; - switch (baud) { - case 3500000: - mul = 0x3345; - ps = 0xC; - break; - case 1843200: - mul = 0x2400; - break; - case 3000000: - case 2500000: - case 2000000: - case 1500000: - case 1000000: - case 500000: - /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */ - mul = baud / 500000 * 0x9C4; - break; - default: - /* Use uart_get_divisor to get quot for other baud rates */ - quot = 0; - } - - if (!quot) - quot = uart_get_divisor(port, baud); - - if ((up->port.uartclk / quot) < (2400 * 16)) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B; - else if ((up->port.uartclk / quot) < (230400 * 16)) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B; - else - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B; - - fcr |= UART_FCR_HSU_64B_FIFO; - - /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. - */ - spin_lock_irqsave(&up->port.lock, flags); - - /* Update the per-port timeout */ - uart_update_timeout(port, termios->c_cflag, baud); - - up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (termios->c_iflag & INPCK) - up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - up->port.read_status_mask |= UART_LSR_BI; - - /* Characters to ignore */ - up->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (termios->c_iflag & IGNBRK) { - up->port.ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - up->port.ignore_status_mask |= UART_LSR_OE; - } - - /* Ignore all characters if CREAD is not set */ - if ((termios->c_cflag & CREAD) == 0) - up->port.ignore_status_mask |= UART_LSR_DR; - - /* - * CTS flow control flag and modem status interrupts, disable - * MSI by default - */ - up->ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->ier |= UART_IER_MSI; - - serial_out(up, UART_IER, up->ier); - - if (termios->c_cflag & CRTSCTS) - up->mcr |= UART_MCR_AFE | UART_MCR_RTS; - else - up->mcr &= ~UART_MCR_AFE; - - serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ - serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ - serial_out(up, UART_LCR, cval); /* reset DLAB */ - serial_out(up, UART_MUL, mul); /* set MUL */ - serial_out(up, UART_PS, ps); /* set PS */ - up->lcr = cval; /* Save LCR */ - serial_hsu_set_mctrl(&up->port, up->port.mctrl); - serial_out(up, UART_FCR, fcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -static void -serial_hsu_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ -} - -static void serial_hsu_release_port(struct uart_port *port) -{ -} - -static int serial_hsu_request_port(struct uart_port *port) -{ - return 0; -} - -static void serial_hsu_config_port(struct uart_port *port, int flags) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - up->port.type = PORT_MFD; -} - -static int -serial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - /* We don't want the core code to modify any port params */ - return -EINVAL; -} - -static const char * -serial_hsu_type(struct uart_port *port) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - return up->name; -} - -/* Mainly for uart console use */ -static struct uart_hsu_port *serial_hsu_ports[3]; -static struct uart_driver serial_hsu_reg; - -#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -/* Wait for transmitter & holding register to empty */ -static inline void wait_for_xmitr(struct uart_hsu_port *up) -{ - unsigned int status, tmout = 1000; - - /* Wait up to 1ms for the character to be sent. */ - do { - status = serial_in(up, UART_LSR); - - if (status & UART_LSR_BI) - up->lsr_break_flag = UART_LSR_BI; - - if (--tmout == 0) - break; - udelay(1); - } while (!(status & BOTH_EMPTY)); - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - tmout = 1000000; - while (--tmout && - ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) - udelay(1); - } -} - -static void serial_hsu_console_putchar(struct uart_port *port, int ch) -{ - struct uart_hsu_port *up = - container_of(port, struct uart_hsu_port, port); - - wait_for_xmitr(up); - serial_out(up, UART_TX, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - */ -static void -serial_hsu_console_write(struct console *co, const char *s, unsigned int count) -{ - struct uart_hsu_port *up = serial_hsu_ports[co->index]; - unsigned long flags; - unsigned int ier; - int locked = 1; - - touch_nmi_watchdog(); - - local_irq_save(flags); - if (up->port.sysrq) - locked = 0; - else if (oops_in_progress) { - locked = spin_trylock(&up->port.lock); - } else - spin_lock(&up->port.lock); - - /* First save the IER then disable the interrupts */ - ier = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); - - uart_console_write(&up->port, s, count, serial_hsu_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up); - serial_out(up, UART_IER, ier); - - if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); -} - -static struct console serial_hsu_console; - -static int __init -serial_hsu_console_setup(struct console *co, char *options) -{ - struct uart_hsu_port *up; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (co->index == -1 || co->index >= serial_hsu_reg.nr) - co->index = 0; - up = serial_hsu_ports[co->index]; - if (!up) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(&up->port, co, baud, parity, bits, flow); -} - -static struct console serial_hsu_console = { - .name = "ttyMFD", - .write = serial_hsu_console_write, - .device = uart_console_device, - .setup = serial_hsu_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &serial_hsu_reg, -}; - -#define SERIAL_HSU_CONSOLE (&serial_hsu_console) -#else -#define SERIAL_HSU_CONSOLE NULL -#endif - -static struct uart_ops serial_hsu_pops = { - .tx_empty = serial_hsu_tx_empty, - .set_mctrl = serial_hsu_set_mctrl, - .get_mctrl = serial_hsu_get_mctrl, - .stop_tx = serial_hsu_stop_tx, - .start_tx = serial_hsu_start_tx, - .stop_rx = serial_hsu_stop_rx, - .enable_ms = serial_hsu_enable_ms, - .break_ctl = serial_hsu_break_ctl, - .startup = serial_hsu_startup, - .shutdown = serial_hsu_shutdown, - .set_termios = serial_hsu_set_termios, - .pm = serial_hsu_pm, - .type = serial_hsu_type, - .release_port = serial_hsu_release_port, - .request_port = serial_hsu_request_port, - .config_port = serial_hsu_config_port, - .verify_port = serial_hsu_verify_port, -}; - -static struct uart_driver serial_hsu_reg = { - .owner = THIS_MODULE, - .driver_name = "MFD serial", - .dev_name = "ttyMFD", - .major = TTY_MAJOR, - .minor = 128, - .nr = 3, - .cons = SERIAL_HSU_CONSOLE, -}; - -#ifdef CONFIG_PM -static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state) -{ - void *priv = pci_get_drvdata(pdev); - struct uart_hsu_port *up; - - /* Make sure this is not the internal dma controller */ - if (priv && (pdev->device != 0x081E)) { - up = priv; - uart_suspend_port(&serial_hsu_reg, &up->port); - } - - pci_save_state(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; -} - -static int serial_hsu_resume(struct pci_dev *pdev) -{ - void *priv = pci_get_drvdata(pdev); - struct uart_hsu_port *up; - int ret; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - ret = pci_enable_device(pdev); - if (ret) - dev_warn(&pdev->dev, - "HSU: can't re-enable device, try to continue\n"); - - if (priv && (pdev->device != 0x081E)) { - up = priv; - uart_resume_port(&serial_hsu_reg, &up->port); - } - return 0; -} - -static int serial_hsu_runtime_idle(struct device *dev) -{ - pm_schedule_suspend(dev, 500); - return -EBUSY; -} - -static int serial_hsu_runtime_suspend(struct device *dev) -{ - return 0; -} - -static int serial_hsu_runtime_resume(struct device *dev) -{ - return 0; -} -#else -#define serial_hsu_suspend NULL -#define serial_hsu_resume NULL -#define serial_hsu_runtime_idle NULL -#define serial_hsu_runtime_suspend NULL -#define serial_hsu_runtime_resume NULL -#endif - -static const struct dev_pm_ops serial_hsu_pm_ops = { - .runtime_suspend = serial_hsu_runtime_suspend, - .runtime_resume = serial_hsu_runtime_resume, - .runtime_idle = serial_hsu_runtime_idle, -}; - -/* temp global pointer before we settle down on using one or four PCI dev */ -static struct hsu_port *phsu; - -static int serial_hsu_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct uart_hsu_port *uport; - int index, ret; - - printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n", - pdev->vendor, pdev->device); - - switch (pdev->device) { - case 0x081B: - index = 0; - break; - case 0x081C: - index = 1; - break; - case 0x081D: - index = 2; - break; - case 0x081E: - /* internal DMA controller */ - index = 3; - break; - default: - dev_err(&pdev->dev, "HSU: out of index!"); - return -ENODEV; - } - - ret = pci_enable_device(pdev); - if (ret) - return ret; - - if (index == 3) { - /* DMA controller */ - ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu); - if (ret) { - dev_err(&pdev->dev, "can not get IRQ\n"); - goto err_disable; - } - pci_set_drvdata(pdev, phsu); - } else { - /* UART port 0~2 */ - uport = &phsu->port[index]; - uport->port.irq = pdev->irq; - uport->port.dev = &pdev->dev; - uport->dev = &pdev->dev; - - ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport); - if (ret) { - dev_err(&pdev->dev, "can not get IRQ\n"); - goto err_disable; - } - uart_add_one_port(&serial_hsu_reg, &uport->port); - - pci_set_drvdata(pdev, uport); - } - - pm_runtime_put_noidle(&pdev->dev); - pm_runtime_allow(&pdev->dev); - - return 0; - -err_disable: - pci_disable_device(pdev); - return ret; -} - -static void hsu_global_init(void) -{ - struct hsu_port *hsu; - struct uart_hsu_port *uport; - struct hsu_dma_chan *dchan; - int i, ret; - - hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL); - if (!hsu) - return; - - /* Get basic io resource and map it */ - hsu->paddr = 0xffa28000; - hsu->iolen = 0x1000; - - if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global"))) - pr_warn("HSU: error in request mem region\n"); - - hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen); - if (!hsu->reg) { - pr_err("HSU: error in ioremap\n"); - ret = -ENOMEM; - goto err_free_region; - } - - /* Initialise the 3 UART ports */ - uport = hsu->port; - for (i = 0; i < 3; i++) { - uport->port.type = PORT_MFD; - uport->port.iotype = UPIO_MEM; - uport->port.mapbase = (resource_size_t)hsu->paddr - + HSU_PORT_REG_OFFSET - + i * HSU_PORT_REG_LENGTH; - uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET - + i * HSU_PORT_REG_LENGTH; - - sprintf(uport->name, "hsu_port%d", i); - uport->port.fifosize = 64; - uport->port.ops = &serial_hsu_pops; - uport->port.line = i; - uport->port.flags = UPF_IOREMAP; - /* set the scalable maxim support rate to 2746800 bps */ - uport->port.uartclk = 115200 * 24 * 16; - - uport->running = 0; - uport->txc = &hsu->chans[i * 2]; - uport->rxc = &hsu->chans[i * 2 + 1]; - - serial_hsu_ports[i] = uport; - uport->index = i; - - if (hsu_dma_enable & (1<use_dma = 1; - else - uport->use_dma = 0; - - uport++; - } - - /* Initialise 6 dma channels */ - dchan = hsu->chans; - for (i = 0; i < 6; i++) { - dchan->id = i; - dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - dchan->uport = &hsu->port[i/2]; - dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET + - i * HSU_DMA_CHANS_REG_LENGTH; - - dchan++; - } - - phsu = hsu; - hsu_debugfs_init(hsu); - return; - -err_free_region: - release_mem_region(hsu->paddr, hsu->iolen); - kfree(hsu); - return; -} - -static void serial_hsu_remove(struct pci_dev *pdev) -{ - void *priv = pci_get_drvdata(pdev); - struct uart_hsu_port *up; - - if (!priv) - return; - - pm_runtime_forbid(&pdev->dev); - pm_runtime_get_noresume(&pdev->dev); - - /* For port 0/1/2, priv is the address of uart_hsu_port */ - if (pdev->device != 0x081E) { - up = priv; - uart_remove_one_port(&serial_hsu_reg, &up->port); - } - - free_irq(pdev->irq, priv); - pci_disable_device(pdev); -} - -/* First 3 are UART ports, and the 4th is the DMA */ -static const struct pci_device_id pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081E) }, - {}, -}; - -static struct pci_driver hsu_pci_driver = { - .name = "HSU serial", - .id_table = pci_ids, - .probe = serial_hsu_probe, - .remove = serial_hsu_remove, - .suspend = serial_hsu_suspend, - .resume = serial_hsu_resume, - .driver = { - .pm = &serial_hsu_pm_ops, - }, -}; - -static int __init hsu_pci_init(void) -{ - int ret; - - hsu_global_init(); - - ret = uart_register_driver(&serial_hsu_reg); - if (ret) - return ret; - - return pci_register_driver(&hsu_pci_driver); -} - -static void __exit hsu_pci_exit(void) -{ - pci_unregister_driver(&hsu_pci_driver); - uart_unregister_driver(&serial_hsu_reg); - - hsu_debugfs_remove(phsu); - - kfree(phsu); -} - -module_init(hsu_pci_init); -module_exit(hsu_pci_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DEVICE_TABLE(pci, pci_ids); diff --git a/include/linux/serial_mfd.h b/include/linux/serial_mfd.h deleted file mode 100644 index 2b071e0b034d..000000000000 --- a/include/linux/serial_mfd.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef _SERIAL_MFD_H_ -#define _SERIAL_MFD_H_ - -/* HW register offset definition */ -#define UART_FOR 0x08 -#define UART_PS 0x0C -#define UART_MUL 0x0D -#define UART_DIV 0x0E - -#define HSU_GBL_IEN 0x0 -#define HSU_GBL_IST 0x4 - -#define HSU_GBL_INT_BIT_PORT0 0x0 -#define HSU_GBL_INT_BIT_PORT1 0x1 -#define HSU_GBL_INT_BIT_PORT2 0x2 -#define HSU_GBL_INT_BIT_IRI 0x3 -#define HSU_GBL_INT_BIT_HDLC 0x4 -#define HSU_GBL_INT_BIT_DMA 0x5 - -#define HSU_GBL_ISR 0x8 -#define HSU_GBL_DMASR 0x400 -#define HSU_GBL_DMAISR 0x404 - -#define HSU_PORT_REG_OFFSET 0x80 -#define HSU_PORT0_REG_OFFSET 0x80 -#define HSU_PORT1_REG_OFFSET 0x100 -#define HSU_PORT2_REG_OFFSET 0x180 -#define HSU_PORT_REG_LENGTH 0x80 - -#define HSU_DMA_CHANS_REG_OFFSET 0x500 -#define HSU_DMA_CHANS_REG_LENGTH 0x40 - -#define HSU_CH_SR 0x0 /* channel status reg */ -#define HSU_CH_CR 0x4 /* control reg */ -#define HSU_CH_DCR 0x8 /* descriptor control reg */ -#define HSU_CH_BSR 0x10 /* max fifo buffer size reg */ -#define HSU_CH_MOTSR 0x14 /* minimum ocp transfer size */ -#define HSU_CH_D0SAR 0x20 /* desc 0 start addr */ -#define HSU_CH_D0TSR 0x24 /* desc 0 transfer size */ -#define HSU_CH_D1SAR 0x28 -#define HSU_CH_D1TSR 0x2C -#define HSU_CH_D2SAR 0x30 -#define HSU_CH_D2TSR 0x34 -#define HSU_CH_D3SAR 0x38 -#define HSU_CH_D3TSR 0x3C - -#endif diff --git a/include/uapi/linux/serial_reg.h b/include/uapi/linux/serial_reg.h index 00adb01fa5f3..e9b4cb0cd7ed 100644 --- a/include/uapi/linux/serial_reg.h +++ b/include/uapi/linux/serial_reg.h @@ -241,25 +241,6 @@ #define UART_FCR_PXAR16 0x80 /* receive FIFO threshold = 16 */ #define UART_FCR_PXAR32 0xc0 /* receive FIFO threshold = 32 */ -/* - * Intel MID on-chip HSU (High Speed UART) defined bits - */ -#define UART_FCR_HSU_64_1B 0x00 /* receive FIFO treshold = 1 */ -#define UART_FCR_HSU_64_16B 0x40 /* receive FIFO treshold = 16 */ -#define UART_FCR_HSU_64_32B 0x80 /* receive FIFO treshold = 32 */ -#define UART_FCR_HSU_64_56B 0xc0 /* receive FIFO treshold = 56 */ - -#define UART_FCR_HSU_16_1B 0x00 /* receive FIFO treshold = 1 */ -#define UART_FCR_HSU_16_4B 0x40 /* receive FIFO treshold = 4 */ -#define UART_FCR_HSU_16_8B 0x80 /* receive FIFO treshold = 8 */ -#define UART_FCR_HSU_16_14B 0xc0 /* receive FIFO treshold = 14 */ - -#define UART_FCR_HSU_64B_FIFO 0x20 /* chose 64 bytes FIFO */ -#define UART_FCR_HSU_16B_FIFO 0x00 /* chose 16 bytes FIFO */ - -#define UART_FCR_HALF_EMPT_TXI 0x00 /* trigger TX_EMPT IRQ for half empty */ -#define UART_FCR_FULL_EMPT_TXI 0x08 /* trigger TX_EMPT IRQ for full empty */ - /* * These register definitions are for the 16C950 */ -- cgit v1.2.3 From afe9cbb1a6adf6da5fa6d4747d102b95b4bb52c1 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 24 Feb 2015 11:17:10 +0100 Subject: serial: imx: drop support for IRDA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for IRDA was added in 2009 in commit v2.6.31-rc1~399^2~2. There are no in-tree users. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 157 ++----------------------------- include/linux/platform_data/serial-imx.h | 5 - 2 files changed, 9 insertions(+), 153 deletions(-) (limited to 'include') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index cbbb47385877..6dc1d2781b86 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -6,9 +6,6 @@ * Author: Sascha Hauer * Copyright (C) 2004 Pengutronix * - * Author: Fabian Godehardt (added IrDA support for iMX) - * Copyright (C) 2009 emlix GmbH - * * 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 @@ -201,7 +198,6 @@ struct imx_port { unsigned int old_status; unsigned int have_rtscts:1; unsigned int dte_mode:1; - unsigned int use_irda:1; unsigned int irda_inv_rx:1; unsigned int irda_inv_tx:1; unsigned short trcv_delay; /* transceiver delay */ @@ -228,12 +224,6 @@ struct imx_port_ucrs { unsigned int ucr3; }; -#ifdef CONFIG_IRDA -#define USE_IRDA(sport) ((sport)->use_irda) -#else -#define USE_IRDA(sport) (0) -#endif - static struct imx_uart_data imx_uart_devdata[] = { [IMX1_UART] = { .uts_reg = IMX1_UTS, @@ -368,48 +358,6 @@ static void imx_stop_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - if (USE_IRDA(sport)) { - /* half duplex - wait for end of transmission */ - int n = 256; - while ((--n > 0) && - !(readl(sport->port.membase + USR2) & USR2_TXDC)) { - udelay(5); - barrier(); - } - /* - * irda transceiver - wait a bit more to avoid - * cutoff, hardware dependent - */ - udelay(sport->trcv_delay); - - /* - * half duplex - reactivate receive mode, - * flush receive pipe echo crap - */ - if (readl(sport->port.membase + USR2) & USR2_TXDC) { - temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN); - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR4); - temp &= ~(UCR4_TCEN); - writel(temp, sport->port.membase + UCR4); - - while (readl(sport->port.membase + URXD0) & - URXD_CHARRDY) - barrier(); - - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RRDYEN; - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR4); - temp |= UCR4_DREN; - writel(temp, sport->port.membase + UCR4); - } - return; - } - /* * We are maybe in the SMP context, so if the DMA TX thread is running * on other cpu, we have to wait for it to finish. @@ -612,32 +560,11 @@ static void imx_start_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - if (USE_IRDA(sport)) { - /* half duplex in IrDA mode; have to disable receive mode */ - temp = readl(sport->port.membase + UCR4); - temp &= ~(UCR4_DREN); - writel(temp, sport->port.membase + UCR4); - - temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_RRDYEN); - writel(temp, sport->port.membase + UCR1); - } - if (!sport->dma_is_enabled) { temp = readl(sport->port.membase + UCR1); writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); } - if (USE_IRDA(sport)) { - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_TRDYEN; - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR4); - temp |= UCR4_TCEN; - writel(temp, sport->port.membase + UCR4); - } - if (sport->dma_is_enabled) { if (sport->port.x_char) { /* We have X-char to send, so enable TX IRQ and @@ -1148,9 +1075,6 @@ static int imx_startup(struct uart_port *port) */ temp = readl(sport->port.membase + UCR4); - if (USE_IRDA(sport)) - temp |= UCR4_IRSC; - /* set the trigger level for CTS */ temp &= ~(UCR4_CTSTL_MASK << UCR4_CTSTL_SHF); temp |= CTSTL << UCR4_CTSTL_SHF; @@ -1186,11 +1110,6 @@ static int imx_startup(struct uart_port *port) temp = readl(sport->port.membase + UCR1); temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; - if (USE_IRDA(sport)) { - temp |= UCR1_IREN; - temp &= ~(UCR1_RTSDEN); - } - writel(temp, sport->port.membase + UCR1); temp = readl(sport->port.membase + UCR4); @@ -1209,38 +1128,12 @@ static int imx_startup(struct uart_port *port) writel(temp, sport->port.membase + UCR3); } - if (USE_IRDA(sport)) { - temp = readl(sport->port.membase + UCR4); - if (sport->irda_inv_rx) - temp |= UCR4_INVR; - else - temp &= ~(UCR4_INVR); - writel(temp | UCR4_DREN, sport->port.membase + UCR4); - - temp = readl(sport->port.membase + UCR3); - if (sport->irda_inv_tx) - temp |= UCR3_INVT; - else - temp &= ~(UCR3_INVT); - writel(temp, sport->port.membase + UCR3); - } - /* * Enable modem status interrupts */ imx_enable_ms(&sport->port); spin_unlock_irqrestore(&sport->port.lock, flags); - if (USE_IRDA(sport)) { - struct imxuart_platform_data *pdata; - pdata = dev_get_platdata(sport->port.dev); - sport->irda_inv_rx = pdata->irda_inv_rx; - sport->irda_inv_tx = pdata->irda_inv_tx; - sport->trcv_delay = pdata->transceiver_delay; - if (pdata->irda_enable) - pdata->irda_enable(1); - } - return 0; } @@ -1276,13 +1169,6 @@ static void imx_shutdown(struct uart_port *port) writel(temp, sport->port.membase + UCR2); spin_unlock_irqrestore(&sport->port.lock, flags); - if (USE_IRDA(sport)) { - struct imxuart_platform_data *pdata; - pdata = dev_get_platdata(sport->port.dev); - if (pdata->irda_enable) - pdata->irda_enable(0); - } - /* * Stop our timer. */ @@ -1295,8 +1181,6 @@ static void imx_shutdown(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); temp = readl(sport->port.membase + UCR1); temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); - if (USE_IRDA(sport)) - temp &= ~(UCR1_IREN); writel(temp, sport->port.membase + UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1450,24 +1334,16 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.membase + UCR2); old_txrxen &= (UCR2_TXEN | UCR2_RXEN); - if (USE_IRDA(sport)) { - /* - * use maximum available submodule frequency to - * avoid missing short pulses due to low sampling rate - */ + /* custom-baudrate handling */ + div = sport->port.uartclk / (baud * 16); + if (baud == 38400 && quot != div) + baud = sport->port.uartclk / (quot * 16); + + div = sport->port.uartclk / (baud * 16); + if (div > 7) + div = 7; + if (!div) div = 1; - } else { - /* custom-baudrate handling */ - div = sport->port.uartclk / (baud * 16); - if (baud == 38400 && quot != div) - baud = sport->port.uartclk / (quot * 16); - - div = sport->port.uartclk / (baud * 16); - if (div > 7) - div = 7; - if (!div) - div = 1; - } rational_best_approximation(16 * div * baud, sport->port.uartclk, 1 << 16, 1 << 16, &num, &denom); @@ -1906,9 +1782,6 @@ static int serial_imx_probe_dt(struct imx_port *sport, if (of_get_property(np, "fsl,uart-has-rtscts", NULL)) sport->have_rtscts = 1; - if (of_get_property(np, "fsl,irda-mode", NULL)) - sport->use_irda = 1; - if (of_get_property(np, "fsl,dte-mode", NULL)) sport->dte_mode = 1; @@ -1937,9 +1810,6 @@ static void serial_imx_probe_pdata(struct imx_port *sport, if (pdata->flags & IMXUART_HAVE_RTSCTS) sport->have_rtscts = 1; - - if (pdata->flags & IMXUART_IRDA) - sport->use_irda = 1; } static int serial_imx_probe(struct platform_device *pdev) @@ -2012,15 +1882,6 @@ static int serial_imx_probe(struct platform_device *pdev) dev_name(&pdev->dev), sport); if (ret) return ret; - - /* do not use RTS IRQ on IrDA */ - if (!USE_IRDA(sport)) { - ret = devm_request_irq(&pdev->dev, rtsirq, - imx_rtsint, 0, - dev_name(&pdev->dev), sport); - if (ret) - return ret; - } } else { ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0, dev_name(&pdev->dev), sport); diff --git a/include/linux/platform_data/serial-imx.h b/include/linux/platform_data/serial-imx.h index 3cc2e3c40914..a938eba2f18e 100644 --- a/include/linux/platform_data/serial-imx.h +++ b/include/linux/platform_data/serial-imx.h @@ -20,14 +20,9 @@ #define ASMARM_ARCH_UART_H #define IMXUART_HAVE_RTSCTS (1<<0) -#define IMXUART_IRDA (1<<1) struct imxuart_platform_data { unsigned int flags; - void (*irda_enable)(int enable); - unsigned int irda_inv_rx:1; - unsigned int irda_inv_tx:1; - unsigned short transceiver_delay; }; #endif -- cgit v1.2.3 From 73abaf87f01be6fa6da3c0aa9c138a1b6b281068 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 1 Mar 2015 11:05:46 -0500 Subject: serial: earlycon: Refactor parse_options into serial core Prepare to support console-defined matching; refactor the command line parameter string processing from parse_options() into a new core function, uart_parse_earlycon(), which decodes command line parameters of the form: earlycon=,io|mmio|mmio32,, console=,io|mmio|mmio32,, earlycon=,0x, console=,0x, Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/earlycon.c | 39 ++++++++++++---------------------- drivers/tty/serial/serial_core.c | 46 ++++++++++++++++++++++++++++++++++++++++ include/linux/serial_core.h | 2 ++ 3 files changed, 61 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 64fe25a4285c..58d6bcdaf31c 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -54,44 +54,31 @@ static void __iomem * __init earlycon_map(unsigned long paddr, size_t size) return base; } -static int __init parse_options(struct earlycon_device *device, - char *options) +static int __init parse_options(struct earlycon_device *device, char *options) { struct uart_port *port = &device->port; - int mmio, mmio32, length; + int length; unsigned long addr; - if (!options) - return -ENODEV; + if (uart_parse_earlycon(options, &port->iotype, &addr, &options)) + return -EINVAL; - mmio = !strncmp(options, "mmio,", 5); - mmio32 = !strncmp(options, "mmio32,", 7); - if (mmio || mmio32) { - port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32); - options += mmio ? 5 : 7; - addr = simple_strtoul(options, NULL, 0); + switch (port->iotype) { + case UPIO_MEM32: + port->regshift = 2; /* fall-through */ + case UPIO_MEM: port->mapbase = addr; - if (mmio32) - port->regshift = 2; - } else if (!strncmp(options, "io,", 3)) { - port->iotype = UPIO_PORT; - options += 3; - addr = simple_strtoul(options, NULL, 0); + break; + case UPIO_PORT: port->iobase = addr; - mmio = 0; - } else if (!strncmp(options, "0x", 2)) { - port->iotype = UPIO_MEM; - addr = simple_strtoul(options, NULL, 0); - port->mapbase = addr; - } else { + break; + default: return -EINVAL; } port->uartclk = BASE_BAUD * 16; - options = strchr(options, ','); if (options) { - options++; device->baud = simple_strtoul(options, NULL, 0); length = min(strcspn(options, " ") + 1, (size_t)(sizeof(device->options))); @@ -100,7 +87,7 @@ static int __init parse_options(struct earlycon_device *device, if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32) pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n", - mmio32 ? "32" : "", + (port->iotype == UPIO_MEM32) ? "32" : "", (unsigned long long)port->mapbase, device->options); else diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 63d29473c703..8379e3fa0162 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1808,6 +1808,52 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) return ports + idx; } +/** + * uart_parse_earlycon - Parse earlycon options + * @p: ptr to 2nd field (ie., just beyond ',') + * @iotype: ptr for decoded iotype (out) + * @addr: ptr for decoded mapbase/iobase (out) + * @options: ptr for field; NULL if not present (out) + * + * Decodes earlycon kernel command line parameters of the form + * earlycon=,io|mmio|mmio32,, + * console=,io|mmio|mmio32,, + * + * The optional form + * earlycon=,0x, + * console=,0x, + * is also accepted; the returned @iotype will be UPIO_MEM. + * + * Returns 0 on success or -EINVAL on failure + */ +int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr, + char **options) +{ + if (strncmp(p, "mmio,", 5) == 0) { + *iotype = UPIO_MEM; + p += 5; + } else if (strncmp(p, "mmio32,", 7) == 0) { + *iotype = UPIO_MEM32; + p += 7; + } else if (strncmp(p, "io,", 3) == 0) { + *iotype = UPIO_PORT; + p += 3; + } else if (strncmp(p, "0x", 2) == 0) { + *iotype = UPIO_MEM; + } else { + return -EINVAL; + } + + *addr = simple_strtoul(p, NULL, 0); + p = strchr(p, ','); + if (p) + p++; + + *options = p; + return 0; +} +EXPORT_SYMBOL_GPL(uart_parse_earlycon); + /** * uart_parse_options - Parse serial port baud/parity/bits/flow control. * @options: pointer to option string diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index baf3e1d08416..cc5c506f07dd 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -354,6 +354,8 @@ early_param("earlycon", name ## _setup_earlycon); struct uart_port *uart_get_console(struct uart_port *ports, int nr, struct console *c); +int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr, + char **options); void uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow); int uart_set_options(struct uart_port *port, struct console *co, int baud, -- cgit v1.2.3 From f8e471f9eb9068bf5ac8c6a04da74329a442f75a Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 6 Mar 2015 20:34:32 -0800 Subject: target: Add target_show_dynamic_sessions attribute helper This patch adds a new helper function that can be used by fabric driver TPG attributes for dumping the list of active sessions with a dynamically generated se_node_acl. (generate_node_acl=1). It prints one se_node_acl->initiatorname per line, up to PAGE_SIZE which is due to the current limitiation of single page attribute output within sysfs and configfs code. Note that if a session is referencing a explicit NodeACL, the InitiatorName will not appear within dynamic_sessions output. Reported-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 24 ++++++++++++++++++++++++ include/target/target_core_fabric.h | 1 + include/target/target_core_fabric_configfs.h | 5 +++++ 3 files changed, 30 insertions(+) (limited to 'include') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 0adc0f650213..e06c136ff839 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -404,6 +404,30 @@ void target_put_session(struct se_session *se_sess) } EXPORT_SYMBOL(target_put_session); +ssize_t target_show_dynamic_sessions(struct se_portal_group *se_tpg, char *page) +{ + struct se_session *se_sess; + ssize_t len = 0; + + spin_lock_bh(&se_tpg->session_lock); + list_for_each_entry(se_sess, &se_tpg->tpg_sess_list, sess_list) { + if (!se_sess->se_node_acl) + continue; + if (!se_sess->se_node_acl->dynamic_node_acl) + continue; + if (strlen(se_sess->se_node_acl->initiatorname) + 1 + len > PAGE_SIZE) + break; + + len += snprintf(page + len, PAGE_SIZE - len, "%s\n", + se_sess->se_node_acl->initiatorname); + len += 1; /* Include NULL terminator */ + } + spin_unlock_bh(&se_tpg->session_lock); + + return len; +} +EXPORT_SYMBOL(target_show_dynamic_sessions); + static void target_complete_nacl(struct kref *kref) { struct se_node_acl *nacl = container_of(kref, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 22a4e98eec80..2f4a2505db4c 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -95,6 +95,7 @@ void transport_register_session(struct se_portal_group *, struct se_node_acl *, struct se_session *, void *); void target_get_session(struct se_session *); void target_put_session(struct se_session *); +ssize_t target_show_dynamic_sessions(struct se_portal_group *, char *); void transport_free_session(struct se_session *); void target_put_nacl(struct se_node_acl *); void transport_deregister_session_configfs(struct se_session *); diff --git a/include/target/target_core_fabric_configfs.h b/include/target/target_core_fabric_configfs.h index b32a14905cfa..7a0649c09e79 100644 --- a/include/target/target_core_fabric_configfs.h +++ b/include/target/target_core_fabric_configfs.h @@ -90,6 +90,11 @@ static struct target_fabric_tpg_attribute _fabric##_tpg_##_name = \ _fabric##_tpg_store_##_name); +#define TF_TPG_BASE_ATTR_RO(_fabric, _name) \ +static struct target_fabric_tpg_attribute _fabric##_tpg_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + _fabric##_tpg_show_##_name); + CONFIGFS_EATTR_STRUCT(target_fabric_wwn, target_fabric_configfs); #define TF_WWN_ATTR(_fabric, _name, _mode) \ static struct target_fabric_wwn_attribute _fabric##_wwn_##_name = \ -- cgit v1.2.3 From 2f0f267ea0720ec6adbe9cf7386450425fac8258 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 5 Mar 2015 10:49:19 +1030 Subject: cpumask: remove deprecated functions. Using these functions with offstack cpus is unsafe. They use all NR_CPUS bits, unstead of nr_cpumask_bits. In particular, lustre (in staging) used cpus_ and that caused a bug. Reported-by: Oleg Drokin Signed-off-by: Rusty Russell --- include/linux/cpumask.h | 151 ------------------------------------------------ lib/Kconfig | 4 -- 2 files changed, 155 deletions(-) (limited to 'include') diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index dc037ae6f4f2..646fadee5caf 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -815,155 +815,4 @@ cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask) [0 ... BITS_TO_LONGS(NR_CPUS)-1] = 0UL \ } } -/* - * - * From here down, all obsolete. Use cpumask_ variants! - * - */ -#ifndef CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS - -#define CPU_MASK_CPU0 \ -(cpumask_t) { { \ - [0] = 1UL \ -} } - -#if NR_CPUS == 1 -#define first_cpu(src) ({ (void)(src); 0; }) -#define next_cpu(n, src) ({ (void)(src); 1; }) -#define any_online_cpu(mask) 0 -#define for_each_cpu_mask(cpu, mask) \ - for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask) -#else /* NR_CPUS > 1 */ -int __first_cpu(const cpumask_t *srcp); -int __next_cpu(int n, const cpumask_t *srcp); - -#define first_cpu(src) __first_cpu(&(src)) -#define next_cpu(n, src) __next_cpu((n), &(src)) -#define any_online_cpu(mask) cpumask_any_and(&mask, cpu_online_mask) -#define for_each_cpu_mask(cpu, mask) \ - for ((cpu) = -1; \ - (cpu) = next_cpu((cpu), (mask)), \ - (cpu) < NR_CPUS; ) -#endif /* SMP */ - -#if NR_CPUS <= 64 - -#define for_each_cpu_mask_nr(cpu, mask) for_each_cpu_mask(cpu, mask) - -#else /* NR_CPUS > 64 */ - -int __next_cpu_nr(int n, const cpumask_t *srcp); -#define for_each_cpu_mask_nr(cpu, mask) \ - for ((cpu) = -1; \ - (cpu) = __next_cpu_nr((cpu), &(mask)), \ - (cpu) < nr_cpu_ids; ) - -#endif /* NR_CPUS > 64 */ - -#define cpus_addr(src) ((src).bits) - -#define cpu_set(cpu, dst) __cpu_set((cpu), &(dst)) -static inline void __cpu_set(int cpu, volatile cpumask_t *dstp) -{ - set_bit(cpu, dstp->bits); -} - -#define cpu_clear(cpu, dst) __cpu_clear((cpu), &(dst)) -static inline void __cpu_clear(int cpu, volatile cpumask_t *dstp) -{ - clear_bit(cpu, dstp->bits); -} - -#define cpus_setall(dst) __cpus_setall(&(dst), NR_CPUS) -static inline void __cpus_setall(cpumask_t *dstp, unsigned int nbits) -{ - bitmap_fill(dstp->bits, nbits); -} - -#define cpus_clear(dst) __cpus_clear(&(dst), NR_CPUS) -static inline void __cpus_clear(cpumask_t *dstp, unsigned int nbits) -{ - bitmap_zero(dstp->bits, nbits); -} - -/* No static inline type checking - see Subtlety (1) above. */ -#define cpu_isset(cpu, cpumask) test_bit((cpu), (cpumask).bits) - -#define cpu_test_and_set(cpu, cpumask) __cpu_test_and_set((cpu), &(cpumask)) -static inline int __cpu_test_and_set(int cpu, cpumask_t *addr) -{ - return test_and_set_bit(cpu, addr->bits); -} - -#define cpus_and(dst, src1, src2) __cpus_and(&(dst), &(src1), &(src2), NR_CPUS) -static inline int __cpus_and(cpumask_t *dstp, const cpumask_t *src1p, - const cpumask_t *src2p, unsigned int nbits) -{ - return bitmap_and(dstp->bits, src1p->bits, src2p->bits, nbits); -} - -#define cpus_or(dst, src1, src2) __cpus_or(&(dst), &(src1), &(src2), NR_CPUS) -static inline void __cpus_or(cpumask_t *dstp, const cpumask_t *src1p, - const cpumask_t *src2p, unsigned int nbits) -{ - bitmap_or(dstp->bits, src1p->bits, src2p->bits, nbits); -} - -#define cpus_xor(dst, src1, src2) __cpus_xor(&(dst), &(src1), &(src2), NR_CPUS) -static inline void __cpus_xor(cpumask_t *dstp, const cpumask_t *src1p, - const cpumask_t *src2p, unsigned int nbits) -{ - bitmap_xor(dstp->bits, src1p->bits, src2p->bits, nbits); -} - -#define cpus_andnot(dst, src1, src2) \ - __cpus_andnot(&(dst), &(src1), &(src2), NR_CPUS) -static inline int __cpus_andnot(cpumask_t *dstp, const cpumask_t *src1p, - const cpumask_t *src2p, unsigned int nbits) -{ - return bitmap_andnot(dstp->bits, src1p->bits, src2p->bits, nbits); -} - -#define cpus_equal(src1, src2) __cpus_equal(&(src1), &(src2), NR_CPUS) -static inline int __cpus_equal(const cpumask_t *src1p, - const cpumask_t *src2p, unsigned int nbits) -{ - return bitmap_equal(src1p->bits, src2p->bits, nbits); -} - -#define cpus_intersects(src1, src2) __cpus_intersects(&(src1), &(src2), NR_CPUS) -static inline int __cpus_intersects(const cpumask_t *src1p, - const cpumask_t *src2p, unsigned int nbits) -{ - return bitmap_intersects(src1p->bits, src2p->bits, nbits); -} - -#define cpus_subset(src1, src2) __cpus_subset(&(src1), &(src2), NR_CPUS) -static inline int __cpus_subset(const cpumask_t *src1p, - const cpumask_t *src2p, unsigned int nbits) -{ - return bitmap_subset(src1p->bits, src2p->bits, nbits); -} - -#define cpus_empty(src) __cpus_empty(&(src), NR_CPUS) -static inline int __cpus_empty(const cpumask_t *srcp, unsigned int nbits) -{ - return bitmap_empty(srcp->bits, nbits); -} - -#define cpus_weight(cpumask) __cpus_weight(&(cpumask), NR_CPUS) -static inline int __cpus_weight(const cpumask_t *srcp, unsigned int nbits) -{ - return bitmap_weight(srcp->bits, nbits); -} - -#define cpus_shift_left(dst, src, n) \ - __cpus_shift_left(&(dst), &(src), (n), NR_CPUS) -static inline void __cpus_shift_left(cpumask_t *dstp, - const cpumask_t *srcp, int n, int nbits) -{ - bitmap_shift_left(dstp->bits, srcp->bits, n, nbits); -} -#endif /* !CONFIG_DISABLE_OBSOLETE_CPUMASK_FUNCTIONS */ - #endif /* __LINUX_CPUMASK_H */ diff --git a/lib/Kconfig b/lib/Kconfig index 87da53bb1fef..47d262b3251e 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -397,10 +397,6 @@ config CPUMASK_OFFSTACK them on the stack. This is a bit more expensive, but avoids stack overflow. -config DISABLE_OBSOLETE_CPUMASK_FUNCTIONS - bool "Disable obsolete cpumask functions" if DEBUG_PER_CPU_MAPS - depends on BROKEN - config CPU_RMAP bool depends on SMP -- cgit v1.2.3 From cdfdef75e795fb5ab76c66f3329e509f3ab8b9b5 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 5 Mar 2015 10:49:19 +1030 Subject: cpumask: only allocate nr_cpumask_bits. Now we'll find out the hard way if anyone has CPUMASK_OFFSTACK and is returning these or assigning them. Signed-off-by: Rusty Russell --- include/linux/cpumask.h | 5 ++--- lib/cpumask.c | 7 ------- 2 files changed, 2 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 646fadee5caf..4ad2d3c8e21f 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -11,6 +11,7 @@ #include #include +/* Don't assign or return these: may not be this big! */ typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t; /** @@ -609,9 +610,7 @@ static inline int cpulist_parse(const char *buf, struct cpumask *dstp) */ static inline size_t cpumask_size(void) { - /* FIXME: Once all cpumask assignments are eliminated, this - * can be nr_cpumask_bits */ - return BITS_TO_LONGS(NR_CPUS) * sizeof(long); + return BITS_TO_LONGS(nr_cpumask_bits) * sizeof(long); } /* diff --git a/lib/cpumask.c b/lib/cpumask.c index b6513a9f2892..ba379d12bb57 100644 --- a/lib/cpumask.c +++ b/lib/cpumask.c @@ -89,13 +89,6 @@ bool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node) dump_stack(); } #endif - /* FIXME: Bandaid to save us from old primitives which go to NR_CPUS. */ - if (*mask) { - unsigned char *ptr = (unsigned char *)cpumask_bits(*mask); - unsigned int tail; - tail = BITS_TO_LONGS(NR_CPUS - nr_cpumask_bits) * sizeof(long); - memset(ptr + cpumask_size() - tail, 0, tail); - } return *mask != NULL; } -- cgit v1.2.3 From bd5da992b96bc018c3e64ffc5ac15cbe301f6440 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 25 Feb 2015 14:46:51 +0200 Subject: drm/dp: indentation and ordering cleanups Keep the DPCD macros ordered by address, and make indentation conform to the rest of the file. commit e045d20bef41707dbba676e58624b54f9f39e172 Author: Sonika Jindal Date: Thu Feb 19 13:16:44 2015 +0530 drm: Adding edp1.4 specific dpcd macros Signed-off-by: Jani Nikula Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter --- include/drm/drm_dp_helper.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index d4803224028f..98fefe45d158 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -92,9 +92,6 @@ # define DP_MSA_TIMING_PAR_IGNORED (1 << 6) /* eDP */ # define DP_OUI_SUPPORT (1 << 7) -#define DP_SUPPORTED_LINK_RATES 0x010 /*eDP 1.4*/ -#define DP_MAX_SUPPORTED_RATES 0x8 - #define DP_I2C_SPEED_CAP 0x00c /* DPI */ # define DP_I2C_SPEED_1K 0x01 # define DP_I2C_SPEED_5K 0x02 @@ -105,8 +102,12 @@ #define DP_EDP_CONFIGURATION_CAP 0x00d /* XXX 1.2? */ # define DP_DPCD_DISPLAY_CONTROL_CAPABLE (1 << 3) /* edp v1.2 or higher */ + #define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* XXX 1.2? */ +#define DP_SUPPORTED_LINK_RATES 0x010 /* eDP 1.4 */ +# define DP_MAX_SUPPORTED_RATES 8 /* 16-bit little-endian */ + /* Multiple stream transport */ #define DP_FAUX_CAP 0x020 /* 1.2 */ # define DP_FAUX_CAP_1 (1 << 0) @@ -225,7 +226,7 @@ # define DP_UP_REQ_EN (1 << 1) # define DP_UPSTREAM_IS_SRC (1 << 2) -#define DP_LINK_RATE_SET 0x115 +#define DP_LINK_RATE_SET 0x115 /* eDP 1.4 */ #define DP_PSR_EN_CFG 0x170 /* XXX 1.2? */ # define DP_PSR_ENABLE (1 << 0) @@ -338,7 +339,7 @@ # define DP_SET_POWER_D3 0x2 # define DP_SET_POWER_MASK 0x3 -#define DP_EDP_DPCD_REV 0x700 +#define DP_EDP_DPCD_REV 0x700 /* eDP 1.2 */ #define DP_SIDEBAND_MSG_DOWN_REQ_BASE 0x1000 /* 1.2 MST */ #define DP_SIDEBAND_MSG_UP_REP_BASE 0x1200 /* 1.2 MST */ -- cgit v1.2.3 From 0e71244c1bb873f0e3be3b79d3436d7ef2601029 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 25 Feb 2015 14:46:53 +0200 Subject: drm/dp: add DPCD definitions from eDP 1.2 Mostly display control related DPCD addresses. Signed-off-by: Jani Nikula Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter --- include/drm/drm_dp_helper.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'include') diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 98fefe45d158..a3ecaa06c9db 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -341,6 +341,38 @@ #define DP_EDP_DPCD_REV 0x700 /* eDP 1.2 */ +#define DP_EDP_GENERAL_CAP_1 0x701 + +#define DP_EDP_BACKLIGHT_ADJUSTMENT_CAP 0x702 + +#define DP_EDP_GENERAL_CAP_2 0x703 + +#define DP_EDP_DISPLAY_CONTROL_REGISTER 0x720 + +#define DP_EDP_BACKLIGHT_MODE_SET_REGISTER 0x721 + +#define DP_EDP_BACKLIGHT_BRIGHTNESS_MSB 0x722 +#define DP_EDP_BACKLIGHT_BRIGHTNESS_LSB 0x723 + +#define DP_EDP_PWMGEN_BIT_COUNT 0x724 +#define DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN 0x725 +#define DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX 0x726 + +#define DP_EDP_BACKLIGHT_CONTROL_STATUS 0x727 + +#define DP_EDP_BACKLIGHT_FREQ_SET 0x728 + +#define DP_EDP_BACKLIGHT_FREQ_CAP_MIN_MSB 0x72a +#define DP_EDP_BACKLIGHT_FREQ_CAP_MIN_MID 0x72b +#define DP_EDP_BACKLIGHT_FREQ_CAP_MIN_LSB 0x72c + +#define DP_EDP_BACKLIGHT_FREQ_CAP_MAX_MSB 0x72d +#define DP_EDP_BACKLIGHT_FREQ_CAP_MAX_MID 0x72e +#define DP_EDP_BACKLIGHT_FREQ_CAP_MAX_LSB 0x72f + +#define DP_EDP_DBC_MINIMUM_BRIGHTNESS_SET 0x732 +#define DP_EDP_DBC_MAXIMUM_BRIGHTNESS_SET 0x733 + #define DP_SIDEBAND_MSG_DOWN_REQ_BASE 0x1000 /* 1.2 MST */ #define DP_SIDEBAND_MSG_UP_REP_BASE 0x1200 /* 1.2 MST */ #define DP_SIDEBAND_MSG_DOWN_REP_BASE 0x1400 /* 1.2 MST */ -- cgit v1.2.3 From 9474675afa9fe9d1145df0acb9fc15b6ad56a9f9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 27 Feb 2015 13:10:38 +0200 Subject: drm/dp: add DPCD definitions from DP 1.1 and 1.2a Add a number of DPCD definitions from DP 1.1 and 1.2a. v2: drop wrong DP version reference, rename DP training set macros (Sonika). Reviewed-by: Sonika Jindal Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- include/drm/drm_dp_helper.h | 93 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index a3ecaa06c9db..319d5edfb3b5 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -92,6 +92,15 @@ # define DP_MSA_TIMING_PAR_IGNORED (1 << 6) /* eDP */ # define DP_OUI_SUPPORT (1 << 7) +#define DP_RECEIVE_PORT_0_CAP_0 0x008 +# define DP_LOCAL_EDID_PRESENT (1 << 1) +# define DP_ASSOCIATED_TO_PRECEDING_PORT (1 << 2) + +#define DP_RECEIVE_PORT_0_BUFFER_SIZE 0x009 + +#define DP_RECEIVE_PORT_1_CAP_0 0x00a +#define DP_RECEIVE_PORT_1_BUFFER_SIZE 0x00b + #define DP_I2C_SPEED_CAP 0x00c /* DPI */ # define DP_I2C_SPEED_1K 0x01 # define DP_I2C_SPEED_5K 0x02 @@ -101,10 +110,16 @@ # define DP_I2C_SPEED_1M 0x20 #define DP_EDP_CONFIGURATION_CAP 0x00d /* XXX 1.2? */ +# define DP_ALTERNATE_SCRAMBLER_RESET_CAP (1 << 0) +# define DP_FRAMING_CHANGE_CAP (1 << 1) # define DP_DPCD_DISPLAY_CONTROL_CAPABLE (1 << 3) /* edp v1.2 or higher */ #define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* XXX 1.2? */ +#define DP_ADAPTER_CAP 0x00f /* 1.2 */ +# define DP_FORCE_LOAD_SENSE_CAP (1 << 0) +# define DP_ALTERNATE_I2C_PATTERN_CAP (1 << 1) + #define DP_SUPPORTED_LINK_RATES 0x010 /* eDP 1.4 */ # define DP_MAX_SUPPORTED_RATES 8 /* 16-bit little-endian */ @@ -115,6 +130,44 @@ #define DP_MSTM_CAP 0x021 /* 1.2 */ # define DP_MST_CAP (1 << 0) +#define DP_NUMBER_OF_AUDIO_ENDPOINTS 0x022 /* 1.2 */ + +/* AV_SYNC_DATA_BLOCK 1.2 */ +#define DP_AV_GRANULARITY 0x023 +# define DP_AG_FACTOR_MASK (0xf << 0) +# define DP_AG_FACTOR_3MS (0 << 0) +# define DP_AG_FACTOR_2MS (1 << 0) +# define DP_AG_FACTOR_1MS (2 << 0) +# define DP_AG_FACTOR_500US (3 << 0) +# define DP_AG_FACTOR_200US (4 << 0) +# define DP_AG_FACTOR_100US (5 << 0) +# define DP_AG_FACTOR_10US (6 << 0) +# define DP_AG_FACTOR_1US (7 << 0) +# define DP_VG_FACTOR_MASK (0xf << 4) +# define DP_VG_FACTOR_3MS (0 << 4) +# define DP_VG_FACTOR_2MS (1 << 4) +# define DP_VG_FACTOR_1MS (2 << 4) +# define DP_VG_FACTOR_500US (3 << 4) +# define DP_VG_FACTOR_200US (4 << 4) +# define DP_VG_FACTOR_100US (5 << 4) + +#define DP_AUD_DEC_LAT0 0x024 +#define DP_AUD_DEC_LAT1 0x025 + +#define DP_AUD_PP_LAT0 0x026 +#define DP_AUD_PP_LAT1 0x027 + +#define DP_VID_INTER_LAT 0x028 + +#define DP_VID_PROG_LAT 0x029 + +#define DP_REP_LAT 0x02a + +#define DP_AUD_DEL_INS0 0x02b +#define DP_AUD_DEL_INS1 0x02c +#define DP_AUD_DEL_INS2 0x02d +/* End of AV_SYNC_DATA_BLOCK */ + #define DP_GUID 0x030 /* 1.2 */ #define DP_PSR_SUPPORT 0x070 /* XXX 1.2? */ @@ -173,11 +226,12 @@ # define DP_TRAINING_PATTERN_3 3 /* 1.2 */ # define DP_TRAINING_PATTERN_MASK 0x3 -# define DP_LINK_QUAL_PATTERN_DISABLE (0 << 2) -# define DP_LINK_QUAL_PATTERN_D10_2 (1 << 2) -# define DP_LINK_QUAL_PATTERN_ERROR_RATE (2 << 2) -# define DP_LINK_QUAL_PATTERN_PRBS7 (3 << 2) -# define DP_LINK_QUAL_PATTERN_MASK (3 << 2) +/* DPCD 1.1 only. For DPCD >= 1.2 see per-lane DP_LINK_QUAL_LANEn_SET */ +# define DP_LINK_QUAL_PATTERN_11_DISABLE (0 << 2) +# define DP_LINK_QUAL_PATTERN_11_D10_2 (1 << 2) +# define DP_LINK_QUAL_PATTERN_11_ERROR_RATE (2 << 2) +# define DP_LINK_QUAL_PATTERN_11_PRBS7 (3 << 2) +# define DP_LINK_QUAL_PATTERN_11_MASK (3 << 2) # define DP_RECOVERED_CLOCK_OUT_EN (1 << 4) # define DP_LINK_SCRAMBLING_DISABLE (1 << 5) @@ -220,14 +274,43 @@ /* bitmask as for DP_I2C_SPEED_CAP */ #define DP_EDP_CONFIGURATION_SET 0x10a /* XXX 1.2? */ +# define DP_ALTERNATE_SCRAMBLER_RESET_ENABLE (1 << 0) +# define DP_FRAMING_CHANGE_ENABLE (1 << 1) +# define DP_PANEL_SELF_TEST_ENABLE (1 << 7) + +#define DP_LINK_QUAL_LANE0_SET 0x10b /* DPCD >= 1.2 */ +#define DP_LINK_QUAL_LANE1_SET 0x10c +#define DP_LINK_QUAL_LANE2_SET 0x10d +#define DP_LINK_QUAL_LANE3_SET 0x10e +# define DP_LINK_QUAL_PATTERN_DISABLE 0 +# define DP_LINK_QUAL_PATTERN_D10_2 1 +# define DP_LINK_QUAL_PATTERN_ERROR_RATE 2 +# define DP_LINK_QUAL_PATTERN_PRBS7 3 +# define DP_LINK_QUAL_PATTERN_80BIT_CUSTOM 4 +# define DP_LINK_QUAL_PATTERN_HBR2_EYE 5 +# define DP_LINK_QUAL_PATTERN_MASK 7 + +#define DP_TRAINING_LANE0_1_SET2 0x10f +#define DP_TRAINING_LANE2_3_SET2 0x110 +# define DP_LANE02_POST_CURSOR2_SET_MASK (3 << 0) +# define DP_LANE02_MAX_POST_CURSOR2_REACHED (1 << 2) +# define DP_LANE13_POST_CURSOR2_SET_MASK (3 << 4) +# define DP_LANE13_MAX_POST_CURSOR2_REACHED (1 << 6) #define DP_MSTM_CTRL 0x111 /* 1.2 */ # define DP_MST_EN (1 << 0) # define DP_UP_REQ_EN (1 << 1) # define DP_UPSTREAM_IS_SRC (1 << 2) +#define DP_AUDIO_DELAY0 0x112 /* 1.2 */ +#define DP_AUDIO_DELAY1 0x113 +#define DP_AUDIO_DELAY2 0x114 + #define DP_LINK_RATE_SET 0x115 /* eDP 1.4 */ +#define DP_UPSTREAM_DEVICE_DP_PWR_NEED 0x118 /* 1.2 */ +# define DP_PWR_NOT_NEEDED (1 << 0) + #define DP_PSR_EN_CFG 0x170 /* XXX 1.2? */ # define DP_PSR_ENABLE (1 << 0) # define DP_PSR_MAIN_LINK_ACTIVE (1 << 1) -- cgit v1.2.3 From 6b1e3f615482f308ae74af13fae6c1d9191d2906 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 27 Feb 2015 13:11:14 +0200 Subject: drm/dp: add DPCD definitions from eDP 1.4 Add a number of DPCD definitions from eDP 1.4. v2: s/DP_ALPM_LOCK_TIMEOUT_ERROR_STATUS/DP_ALPM_LOCK_TIMEOUT_ERROR/ (Sonika) Signed-off-by: Jani Nikula Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter --- include/drm/drm_dp_helper.h | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'include') diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 319d5edfb3b5..c5fdc2d3ca97 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -168,10 +168,18 @@ #define DP_AUD_DEL_INS2 0x02d /* End of AV_SYNC_DATA_BLOCK */ +#define DP_RECEIVER_ALPM_CAP 0x02e /* eDP 1.4 */ +# define DP_ALPM_CAP (1 << 0) + +#define DP_SINK_DEVICE_AUX_FRAME_SYNC_CAP 0x02f /* eDP 1.4 */ +# define DP_AUX_FRAME_SYNC_CAP (1 << 0) + #define DP_GUID 0x030 /* 1.2 */ #define DP_PSR_SUPPORT 0x070 /* XXX 1.2? */ # define DP_PSR_IS_SUPPORTED 1 +# define DP_PSR2_IS_SUPPORTED 2 /* eDP 1.4 */ + #define DP_PSR_CAPS 0x071 /* XXX 1.2? */ # define DP_PSR_NO_TRAIN_ON_EXIT 1 # define DP_PSR_SETUP_TIME_330 (0 << 1) @@ -211,6 +219,7 @@ /* link configuration */ #define DP_LINK_BW_SET 0x100 +# define DP_LINK_RATE_TABLE 0x00 /* eDP 1.4 */ # define DP_LINK_BW_1_62 0x06 # define DP_LINK_BW_2_7 0x0a # define DP_LINK_BW_5_4 0x14 /* 1.2 */ @@ -307,15 +316,30 @@ #define DP_AUDIO_DELAY2 0x114 #define DP_LINK_RATE_SET 0x115 /* eDP 1.4 */ +# define DP_LINK_RATE_SET_SHIFT 0 +# define DP_LINK_RATE_SET_MASK (7 << 0) + +#define DP_RECEIVER_ALPM_CONFIG 0x116 /* eDP 1.4 */ +# define DP_ALPM_ENABLE (1 << 0) +# define DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE (1 << 1) + +#define DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF 0x117 /* eDP 1.4 */ +# define DP_AUX_FRAME_SYNC_ENABLE (1 << 0) +# define DP_IRQ_HPD_ENABLE (1 << 1) #define DP_UPSTREAM_DEVICE_DP_PWR_NEED 0x118 /* 1.2 */ # define DP_PWR_NOT_NEEDED (1 << 0) +#define DP_AUX_FRAME_SYNC_VALUE 0x15c /* eDP 1.4 */ +# define DP_AUX_FRAME_SYNC_VALID (1 << 0) + #define DP_PSR_EN_CFG 0x170 /* XXX 1.2? */ # define DP_PSR_ENABLE (1 << 0) # define DP_PSR_MAIN_LINK_ACTIVE (1 << 1) # define DP_PSR_CRC_VERIFICATION (1 << 2) # define DP_PSR_FRAME_CAPTURE (1 << 3) +# define DP_PSR_SELECTIVE_UPDATE (1 << 4) +# define DP_PSR_IRQ_HPD_WITH_CRC_ERRORS (1 << 5) #define DP_ADAPTER_CTRL 0x1a0 # define DP_ADAPTER_CTRL_FORCE_LOAD_SENSE (1 << 0) @@ -423,6 +447,10 @@ # define DP_SET_POWER_MASK 0x3 #define DP_EDP_DPCD_REV 0x700 /* eDP 1.2 */ +# define DP_EDP_11 0x00 +# define DP_EDP_12 0x01 +# define DP_EDP_13 0x02 +# define DP_EDP_14 0x03 #define DP_EDP_GENERAL_CAP_1 0x701 @@ -430,6 +458,8 @@ #define DP_EDP_GENERAL_CAP_2 0x703 +#define DP_EDP_GENERAL_CAP_3 0x704 /* eDP 1.4 */ + #define DP_EDP_DISPLAY_CONTROL_REGISTER 0x720 #define DP_EDP_BACKLIGHT_MODE_SET_REGISTER 0x721 @@ -456,6 +486,9 @@ #define DP_EDP_DBC_MINIMUM_BRIGHTNESS_SET 0x732 #define DP_EDP_DBC_MAXIMUM_BRIGHTNESS_SET 0x733 +#define DP_EDP_REGIONAL_BACKLIGHT_BASE 0x740 /* eDP 1.4 */ +#define DP_EDP_REGIONAL_BACKLIGHT_0 0x741 /* eDP 1.4 */ + #define DP_SIDEBAND_MSG_DOWN_REQ_BASE 0x1000 /* 1.2 MST */ #define DP_SIDEBAND_MSG_UP_REP_BASE 0x1200 /* 1.2 MST */ #define DP_SIDEBAND_MSG_DOWN_REP_BASE 0x1400 /* 1.2 MST */ @@ -474,6 +507,7 @@ #define DP_PSR_ERROR_STATUS 0x2006 /* XXX 1.2? */ # define DP_PSR_LINK_CRC_ERROR (1 << 0) # define DP_PSR_RFB_STORAGE_ERROR (1 << 1) +# define DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR (1 << 2) /* eDP 1.4 */ #define DP_PSR_ESI 0x2007 /* XXX 1.2? */ # define DP_PSR_CAPS_CHANGE (1 << 0) @@ -487,6 +521,9 @@ # define DP_PSR_SINK_INTERNAL_ERROR 7 # define DP_PSR_SINK_STATE_MASK 0x07 +#define DP_RECEIVER_ALPM_STATUS 0x200b /* eDP 1.4 */ +# define DP_ALPM_LOCK_TIMEOUT_ERROR (1 << 0) + /* DP 1.2 Sideband message defines */ /* peer device type - DP 1.2a Table 2-92 */ #define DP_PEER_DEVICE_NONE 0x0 -- cgit v1.2.3 From ead8610d42105a3d01f755522f11b96c60dc648f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 5 Mar 2015 02:25:43 +0200 Subject: drm: Share plane pixel format check code between legacy and atomic Both the legacy and atomic helpers need to check whether a plane supports a given pixel format. The code is currently duplicated, share it. Signed-off-by: Laurent Pinchart [danvet: Slightly extend the docbook.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 10 ++++------ drivers/gpu/drm/drm_crtc.c | 29 +++++++++++++++++++++++------ include/drm/drm_crtc.h | 2 ++ 3 files changed, 29 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 7ca54cb6b15b..a6caaae40b9e 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -475,7 +475,7 @@ static int drm_atomic_plane_check(struct drm_plane *plane, struct drm_plane_state *state) { unsigned int fb_width, fb_height; - unsigned int i; + int ret; /* either *both* CRTC and FB must be set, or neither */ if (WARN_ON(state->crtc && !state->fb)) { @@ -497,13 +497,11 @@ static int drm_atomic_plane_check(struct drm_plane *plane, } /* Check whether this plane supports the fb pixel format. */ - for (i = 0; i < plane->format_count; i++) - if (state->fb->pixel_format == plane->format_types[i]) - break; - if (i == plane->format_count) { + ret = drm_plane_check_pixel_format(plane, state->fb->pixel_format); + if (ret) { DRM_DEBUG_ATOMIC("Invalid pixel format %s\n", drm_get_format_name(state->fb->pixel_format)); - return -EINVAL; + return ret; } /* Give drivers some help against integer overflows */ diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index c83e4db0adf7..447db50e6838 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2408,6 +2408,27 @@ int drm_mode_getplane(struct drm_device *dev, void *data, return 0; } +/** + * drm_plane_check_pixel_format - Check if the plane supports the pixel format + * @plane: plane to check for format support + * @format: the pixel format + * + * Returns: + * Zero of @plane has @format in its list of supported pixel formats, -EINVAL + * otherwise. + */ +int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) +{ + unsigned int i; + + for (i = 0; i < plane->format_count; i++) { + if (format == plane->format_types[i]) + return 0; + } + + return -EINVAL; +} + /* * setplane_internal - setplane handler for internal callers * @@ -2428,7 +2449,6 @@ static int __setplane_internal(struct drm_plane *plane, { int ret = 0; unsigned int fb_width, fb_height; - unsigned int i; /* No fb means shut it down */ if (!fb) { @@ -2451,13 +2471,10 @@ static int __setplane_internal(struct drm_plane *plane, } /* Check whether this plane supports the fb pixel format. */ - for (i = 0; i < plane->format_count; i++) - if (fb->pixel_format == plane->format_types[i]) - break; - if (i == plane->format_count) { + ret = drm_plane_check_pixel_format(plane, fb->pixel_format); + if (ret) { DRM_DEBUG_KMS("Invalid pixel format %s\n", drm_get_format_name(fb->pixel_format)); - ret = -EINVAL; goto out; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index b1465d6fbe94..da83d39e37d4 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1263,6 +1263,8 @@ extern int drm_plane_init(struct drm_device *dev, extern void drm_plane_cleanup(struct drm_plane *plane); extern unsigned int drm_plane_index(struct drm_plane *plane); extern void drm_plane_force_disable(struct drm_plane *plane); +extern int drm_plane_check_pixel_format(const struct drm_plane *plane, + u32 format); extern void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, int *hdisplay, int *vdisplay); extern int drm_crtc_check_viewport(const struct drm_crtc *crtc, -- cgit v1.2.3 From 3461b30b3e171e16498f3d7bc59ab703aec475c8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 5 Mar 2015 10:32:44 +0100 Subject: drm/plane-helper: unexport drm_primary_helper_create_plane We shouldn't tempt driver writers into using this since it uses a default format list which is likely wrong. And when that's done we can simplify the code a bit, too. Noticed while reviewing a patch from Laurent. Cc: Laurent Pinchart Cc: Matt Roper Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_plane_helper.c | 26 ++++---------------------- include/drm/drm_plane_helper.h | 4 ---- 2 files changed, 4 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 813a06627eb3..8e56783265e1 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -344,20 +344,7 @@ const struct drm_plane_funcs drm_primary_helper_funcs = { }; EXPORT_SYMBOL(drm_primary_helper_funcs); -/** - * drm_primary_helper_create_plane() - Create a generic primary plane - * @dev: drm device - * @formats: pixel formats supported, or NULL for a default safe list - * @num_formats: size of @formats; ignored if @formats is NULL - * - * Allocates and initializes a primary plane that can be used with the primary - * plane helpers. Drivers that wish to use driver-specific plane structures or - * provide custom handler functions may perform their own allocation and - * initialization rather than calling this function. - */ -struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, - const uint32_t *formats, - int num_formats) +static struct drm_plane *create_primary_plane(struct drm_device *dev) { struct drm_plane *primary; int ret; @@ -368,15 +355,11 @@ struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, return NULL; } - if (formats == NULL) { - formats = safe_modeset_formats; - num_formats = ARRAY_SIZE(safe_modeset_formats); - } - /* possible_crtc's will be filled in later by crtc_init */ ret = drm_universal_plane_init(dev, primary, 0, &drm_primary_helper_funcs, - formats, num_formats, + safe_modeset_formats, + ARRAY_SIZE(safe_modeset_formats), DRM_PLANE_TYPE_PRIMARY); if (ret) { kfree(primary); @@ -385,7 +368,6 @@ struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, return primary; } -EXPORT_SYMBOL(drm_primary_helper_create_plane); /** * drm_crtc_init - Legacy CRTC initialization function @@ -404,7 +386,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, { struct drm_plane *primary; - primary = drm_primary_helper_create_plane(dev, NULL, 0); + primary = create_primary_plane(dev); return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs); } EXPORT_SYMBOL(drm_crtc_init); diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index 72ddab02ebd9..e48157a5a59c 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -100,10 +100,6 @@ extern int drm_primary_helper_update(struct drm_plane *plane, extern int drm_primary_helper_disable(struct drm_plane *plane); extern void drm_primary_helper_destroy(struct drm_plane *plane); extern const struct drm_plane_funcs drm_primary_helper_funcs; -extern struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, - const uint32_t *formats, - int num_formats); - int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, -- cgit v1.2.3 From 7eb5f302bbe78b88da8b2008c502c1975e75db05 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 9 Mar 2015 10:41:07 +0200 Subject: drm: Check in setcrtc if the primary plane supports the fb pixel format Drivers implementing the universal planes API report the list of supported pixel formats for the primary plane. Make sure the fb passed to the setcrtc ioctl is compatible. Drivers not implementing the universal planes API will have no format reported for the primary plane, skip the check in that case. Signed-off-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 17 +++++++++++++++++ drivers/gpu/drm/drm_plane_helper.c | 5 +++++ include/drm/drm_crtc.h | 2 ++ 3 files changed, 24 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 447db50e6838..5785336695ca 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2798,6 +2798,23 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + /* + * Check whether the primary plane supports the fb pixel format. + * Drivers not implementing the universal planes API use a + * default formats list provided by the DRM core which doesn't + * match real hardware capabilities. Skip the check in that + * case. + */ + if (!crtc->primary->format_default) { + ret = drm_plane_check_pixel_format(crtc->primary, + fb->pixel_format); + if (ret) { + DRM_DEBUG_KMS("Invalid pixel format %s\n", + drm_get_format_name(fb->pixel_format)); + goto out; + } + } + ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, mode, fb); if (ret) diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 8e56783265e1..b62b03635050 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -353,6 +353,11 @@ static struct drm_plane *create_primary_plane(struct drm_device *dev) if (primary == NULL) { DRM_DEBUG_KMS("Failed to allocate primary plane\n"); return NULL; + /* + * Remove the format_default field from drm_plane when dropping + * this helper. + */ + primary->format_default = true; } /* possible_crtc's will be filled in later by crtc_init */ diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index da83d39e37d4..adc9ea5acf02 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -830,6 +830,7 @@ enum drm_plane_type { * @possible_crtcs: pipes this plane can be bound to * @format_types: array of formats supported by this plane * @format_count: number of formats supported + * @format_default: driver hasn't supplied supported formats for the plane * @crtc: currently bound CRTC * @fb: currently bound fb * @old_fb: Temporary tracking of the old fb while a modeset is ongoing. Used by @@ -850,6 +851,7 @@ struct drm_plane { uint32_t possible_crtcs; uint32_t *format_types; uint32_t format_count; + bool format_default; struct drm_crtc *crtc; struct drm_framebuffer *fb; -- cgit v1.2.3 From 916f743da3546c28a2f350d197e3bea95d97ba15 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 26 Feb 2015 15:49:09 -0600 Subject: firmware: qcom: scm: Move the scm driver to drivers/firmware Architectural changes in the ARM Linux kernel tree mandate the eventual removal of the mach-* directories. Move the scm driver to drivers/firmware and the scm header to include/linux to support that removal. Signed-off-by: Kumar Gala --- MAINTAINERS | 1 + arch/arm/Kconfig | 2 + arch/arm/mach-qcom/Kconfig | 3 - arch/arm/mach-qcom/Makefile | 3 - arch/arm/mach-qcom/platsmp.c | 2 +- arch/arm/mach-qcom/scm.c | 344 ------------------------------------------- arch/arm/mach-qcom/scm.h | 29 ---- drivers/firmware/Kconfig | 4 + drivers/firmware/Makefile | 2 + drivers/firmware/qcom_scm.c | 344 +++++++++++++++++++++++++++++++++++++++++++ include/linux/qcom_scm.h | 29 ++++ 11 files changed, 383 insertions(+), 380 deletions(-) delete mode 100644 arch/arm/mach-qcom/scm.c delete mode 100644 arch/arm/mach-qcom/scm.h create mode 100644 drivers/firmware/qcom_scm.c create mode 100644 include/linux/qcom_scm.h (limited to 'include') diff --git a/MAINTAINERS b/MAINTAINERS index ddc5a8cf9a8a..beb8aa4840e4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1317,6 +1317,7 @@ L: linux-soc@vger.kernel.org S: Maintained F: arch/arm/mach-qcom/ F: drivers/soc/qcom/ +F: drivers/firmware/qcom_scm.c T: git git://git.kernel.org/pub/scm/linux/kernel/git/galak/linux-qcom.git ARM/RADISYS ENP2611 MACHINE SUPPORT diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9f1f09a2bc9b..7ffd1518d2aa 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2160,6 +2160,8 @@ source "net/Kconfig" source "drivers/Kconfig" +source "drivers/firmware/Kconfig" + source "fs/Kconfig" source "arch/arm/Kconfig.debug" diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index 48003ea652b9..2256cd1e25d1 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -22,7 +22,4 @@ config ARCH_MSM8974 bool "Enable support for MSM8974" select HAVE_ARM_ARCH_TIMER -config QCOM_SCM - bool - endif diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile index 10b684140aa1..e324375fa919 100644 --- a/arch/arm/mach-qcom/Makefile +++ b/arch/arm/mach-qcom/Makefile @@ -1,5 +1,2 @@ obj-y := board.o obj-$(CONFIG_SMP) += platsmp.o -obj-$(CONFIG_QCOM_SCM) += scm.o - -CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c index 596e6237dc7e..4b67e56911d3 100644 --- a/arch/arm/mach-qcom/platsmp.c +++ b/arch/arm/mach-qcom/platsmp.c @@ -17,10 +17,10 @@ #include #include #include +#include #include -#include "scm.h" #define VDD_SC1_ARRAY_CLAMP_GFS_CTL 0x35a0 #define SCSS_CPU1CORE_RESET 0x2d80 diff --git a/arch/arm/mach-qcom/scm.c b/arch/arm/mach-qcom/scm.c deleted file mode 100644 index 3e0e334374de..000000000000 --- a/arch/arm/mach-qcom/scm.c +++ /dev/null @@ -1,344 +0,0 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "scm.h" - -#define QCOM_SCM_ENOMEM -5 -#define QCOM_SCM_EOPNOTSUPP -4 -#define QCOM_SCM_EINVAL_ADDR -3 -#define QCOM_SCM_EINVAL_ARG -2 -#define QCOM_SCM_ERROR -1 -#define QCOM_SCM_INTERRUPTED 1 - -static DEFINE_MUTEX(qcom_scm_lock); - -/** - * struct qcom_scm_command - one SCM command buffer - * @len: total available memory for command and response - * @buf_offset: start of command buffer - * @resp_hdr_offset: start of response buffer - * @id: command to be executed - * @buf: buffer returned from qcom_scm_get_command_buffer() - * - * An SCM command is laid out in memory as follows: - * - * ------------------- <--- struct qcom_scm_command - * | command header | - * ------------------- <--- qcom_scm_get_command_buffer() - * | command buffer | - * ------------------- <--- struct qcom_scm_response and - * | response header | qcom_scm_command_to_response() - * ------------------- <--- qcom_scm_get_response_buffer() - * | response buffer | - * ------------------- - * - * There can be arbitrary padding between the headers and buffers so - * you should always use the appropriate qcom_scm_get_*_buffer() routines - * to access the buffers in a safe manner. - */ -struct qcom_scm_command { - __le32 len; - __le32 buf_offset; - __le32 resp_hdr_offset; - __le32 id; - __le32 buf[0]; -}; - -/** - * struct qcom_scm_response - one SCM response buffer - * @len: total available memory for response - * @buf_offset: start of response data relative to start of qcom_scm_response - * @is_complete: indicates if the command has finished processing - */ -struct qcom_scm_response { - __le32 len; - __le32 buf_offset; - __le32 is_complete; -}; - -/** - * alloc_qcom_scm_command() - Allocate an SCM command - * @cmd_size: size of the command buffer - * @resp_size: size of the response buffer - * - * Allocate an SCM command, including enough room for the command - * and response headers as well as the command and response buffers. - * - * Returns a valid &qcom_scm_command on success or %NULL if the allocation fails. - */ -static struct qcom_scm_command *alloc_qcom_scm_command(size_t cmd_size, size_t resp_size) -{ - struct qcom_scm_command *cmd; - size_t len = sizeof(*cmd) + sizeof(struct qcom_scm_response) + cmd_size + - resp_size; - u32 offset; - - cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL); - if (cmd) { - cmd->len = cpu_to_le32(len); - offset = offsetof(struct qcom_scm_command, buf); - cmd->buf_offset = cpu_to_le32(offset); - cmd->resp_hdr_offset = cpu_to_le32(offset + cmd_size); - } - return cmd; -} - -/** - * free_qcom_scm_command() - Free an SCM command - * @cmd: command to free - * - * Free an SCM command. - */ -static inline void free_qcom_scm_command(struct qcom_scm_command *cmd) -{ - kfree(cmd); -} - -/** - * qcom_scm_command_to_response() - Get a pointer to a qcom_scm_response - * @cmd: command - * - * Returns a pointer to a response for a command. - */ -static inline struct qcom_scm_response *qcom_scm_command_to_response( - const struct qcom_scm_command *cmd) -{ - return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset); -} - -/** - * qcom_scm_get_command_buffer() - Get a pointer to a command buffer - * @cmd: command - * - * Returns a pointer to the command buffer of a command. - */ -static inline void *qcom_scm_get_command_buffer(const struct qcom_scm_command *cmd) -{ - return (void *)cmd->buf; -} - -/** - * qcom_scm_get_response_buffer() - Get a pointer to a response buffer - * @rsp: response - * - * Returns a pointer to a response buffer of a response. - */ -static inline void *qcom_scm_get_response_buffer(const struct qcom_scm_response *rsp) -{ - return (void *)rsp + le32_to_cpu(rsp->buf_offset); -} - -static int qcom_scm_remap_error(int err) -{ - pr_err("qcom_scm_call failed with error code %d\n", err); - switch (err) { - case QCOM_SCM_ERROR: - return -EIO; - case QCOM_SCM_EINVAL_ADDR: - case QCOM_SCM_EINVAL_ARG: - return -EINVAL; - case QCOM_SCM_EOPNOTSUPP: - return -EOPNOTSUPP; - case QCOM_SCM_ENOMEM: - return -ENOMEM; - } - return -EINVAL; -} - -static u32 smc(u32 cmd_addr) -{ - int context_id; - register u32 r0 asm("r0") = 1; - register u32 r1 asm("r1") = (u32)&context_id; - register u32 r2 asm("r2") = cmd_addr; - do { - asm volatile( - __asmeq("%0", "r0") - __asmeq("%1", "r0") - __asmeq("%2", "r1") - __asmeq("%3", "r2") -#ifdef REQUIRES_SEC - ".arch_extension sec\n" -#endif - "smc #0 @ switch to secure world\n" - : "=r" (r0) - : "r" (r0), "r" (r1), "r" (r2) - : "r3"); - } while (r0 == QCOM_SCM_INTERRUPTED); - - return r0; -} - -static int __qcom_scm_call(const struct qcom_scm_command *cmd) -{ - int ret; - u32 cmd_addr = virt_to_phys(cmd); - - /* - * Flush the command buffer so that the secure world sees - * the correct data. - */ - __cpuc_flush_dcache_area((void *)cmd, cmd->len); - outer_flush_range(cmd_addr, cmd_addr + cmd->len); - - ret = smc(cmd_addr); - if (ret < 0) - ret = qcom_scm_remap_error(ret); - - return ret; -} - -static void qcom_scm_inv_range(unsigned long start, unsigned long end) -{ - u32 cacheline_size, ctr; - - asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr)); - cacheline_size = 4 << ((ctr >> 16) & 0xf); - - start = round_down(start, cacheline_size); - end = round_up(end, cacheline_size); - outer_inv_range(start, end); - while (start < end) { - asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start) - : "memory"); - start += cacheline_size; - } - dsb(); - isb(); -} - -/** - * qcom_scm_call() - Send an SCM command - * @svc_id: service identifier - * @cmd_id: command identifier - * @cmd_buf: command buffer - * @cmd_len: length of the command buffer - * @resp_buf: response buffer - * @resp_len: length of the response buffer - * - * Sends a command to the SCM and waits for the command to finish processing. - * - * A note on cache maintenance: - * Note that any buffers that are expected to be accessed by the secure world - * must be flushed before invoking qcom_scm_call and invalidated in the cache - * immediately after qcom_scm_call returns. Cache maintenance on the command - * and response buffers is taken care of by qcom_scm_call; however, callers are - * responsible for any other cached buffers passed over to the secure world. - */ -static int qcom_scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, - size_t cmd_len, void *resp_buf, size_t resp_len) -{ - int ret; - struct qcom_scm_command *cmd; - struct qcom_scm_response *rsp; - unsigned long start, end; - - cmd = alloc_qcom_scm_command(cmd_len, resp_len); - if (!cmd) - return -ENOMEM; - - cmd->id = cpu_to_le32((svc_id << 10) | cmd_id); - if (cmd_buf) - memcpy(qcom_scm_get_command_buffer(cmd), cmd_buf, cmd_len); - - mutex_lock(&qcom_scm_lock); - ret = __qcom_scm_call(cmd); - mutex_unlock(&qcom_scm_lock); - if (ret) - goto out; - - rsp = qcom_scm_command_to_response(cmd); - start = (unsigned long)rsp; - - do { - qcom_scm_inv_range(start, start + sizeof(*rsp)); - } while (!rsp->is_complete); - - end = (unsigned long)qcom_scm_get_response_buffer(rsp) + resp_len; - qcom_scm_inv_range(start, end); - - if (resp_buf) - memcpy(resp_buf, qcom_scm_get_response_buffer(rsp), resp_len); -out: - free_qcom_scm_command(cmd); - return ret; -} - -u32 qcom_scm_get_version(void) -{ - int context_id; - static u32 version = -1; - register u32 r0 asm("r0"); - register u32 r1 asm("r1"); - - if (version != -1) - return version; - - mutex_lock(&qcom_scm_lock); - - r0 = 0x1 << 8; - r1 = (u32)&context_id; - do { - asm volatile( - __asmeq("%0", "r0") - __asmeq("%1", "r1") - __asmeq("%2", "r0") - __asmeq("%3", "r1") -#ifdef REQUIRES_SEC - ".arch_extension sec\n" -#endif - "smc #0 @ switch to secure world\n" - : "=r" (r0), "=r" (r1) - : "r" (r0), "r" (r1) - : "r2", "r3"); - } while (r0 == QCOM_SCM_INTERRUPTED); - - version = r1; - mutex_unlock(&qcom_scm_lock); - - return version; -} -EXPORT_SYMBOL(qcom_scm_get_version); - -#define QCOM_SCM_SVC_BOOT 0x1 -#define QCOM_SCM_BOOT_ADDR 0x1 -/* - * Set the cold/warm boot address for one of the CPU cores. - */ -int qcom_scm_set_boot_addr(u32 addr, int flags) -{ - struct { - __le32 flags; - __le32 addr; - } cmd; - - cmd.addr = cpu_to_le32(addr); - cmd.flags = cpu_to_le32(flags); - return qcom_scm_call(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR, - &cmd, sizeof(cmd), NULL, 0); -} -EXPORT_SYMBOL(qcom_scm_set_boot_addr); diff --git a/arch/arm/mach-qcom/scm.h b/arch/arm/mach-qcom/scm.h deleted file mode 100644 index 6bb84cffb396..000000000000 --- a/arch/arm/mach-qcom/scm.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef __QCOM_SCM_H -#define __QCOM_SCM_H - -#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01 -#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08 -#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20 -#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04 -#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02 -#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10 -#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40 - -extern int qcom_scm_set_boot_addr(u32 addr, int flags); - -#define QCOM_SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) - -extern u32 qcom_scm_get_version(void); - -#endif diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 41983883cef4..6517132e5d8b 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -132,6 +132,10 @@ config ISCSI_IBFT detect iSCSI boot parameters dynamically during system boot, say Y. Otherwise, say N. +config QCOM_SCM + bool + depends on ARM || ARM64 + source "drivers/firmware/google/Kconfig" source "drivers/firmware/efi/Kconfig" diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 5373dc5b6011..3fdd3912709a 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -11,6 +11,8 @@ obj-$(CONFIG_DMIID) += dmi-id.o obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o +obj-$(CONFIG_QCOM_SCM) += qcom_scm.o +CFLAGS_qcom_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ obj-$(CONFIG_EFI) += efi/ diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c new file mode 100644 index 000000000000..6e7a72bdb176 --- /dev/null +++ b/drivers/firmware/qcom_scm.c @@ -0,0 +1,344 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#define QCOM_SCM_ENOMEM -5 +#define QCOM_SCM_EOPNOTSUPP -4 +#define QCOM_SCM_EINVAL_ADDR -3 +#define QCOM_SCM_EINVAL_ARG -2 +#define QCOM_SCM_ERROR -1 +#define QCOM_SCM_INTERRUPTED 1 + +static DEFINE_MUTEX(qcom_scm_lock); + +/** + * struct qcom_scm_command - one SCM command buffer + * @len: total available memory for command and response + * @buf_offset: start of command buffer + * @resp_hdr_offset: start of response buffer + * @id: command to be executed + * @buf: buffer returned from qcom_scm_get_command_buffer() + * + * An SCM command is laid out in memory as follows: + * + * ------------------- <--- struct qcom_scm_command + * | command header | + * ------------------- <--- qcom_scm_get_command_buffer() + * | command buffer | + * ------------------- <--- struct qcom_scm_response and + * | response header | qcom_scm_command_to_response() + * ------------------- <--- qcom_scm_get_response_buffer() + * | response buffer | + * ------------------- + * + * There can be arbitrary padding between the headers and buffers so + * you should always use the appropriate qcom_scm_get_*_buffer() routines + * to access the buffers in a safe manner. + */ +struct qcom_scm_command { + __le32 len; + __le32 buf_offset; + __le32 resp_hdr_offset; + __le32 id; + __le32 buf[0]; +}; + +/** + * struct qcom_scm_response - one SCM response buffer + * @len: total available memory for response + * @buf_offset: start of response data relative to start of qcom_scm_response + * @is_complete: indicates if the command has finished processing + */ +struct qcom_scm_response { + __le32 len; + __le32 buf_offset; + __le32 is_complete; +}; + +/** + * alloc_qcom_scm_command() - Allocate an SCM command + * @cmd_size: size of the command buffer + * @resp_size: size of the response buffer + * + * Allocate an SCM command, including enough room for the command + * and response headers as well as the command and response buffers. + * + * Returns a valid &qcom_scm_command on success or %NULL if the allocation fails. + */ +static struct qcom_scm_command *alloc_qcom_scm_command(size_t cmd_size, size_t resp_size) +{ + struct qcom_scm_command *cmd; + size_t len = sizeof(*cmd) + sizeof(struct qcom_scm_response) + cmd_size + + resp_size; + u32 offset; + + cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL); + if (cmd) { + cmd->len = cpu_to_le32(len); + offset = offsetof(struct qcom_scm_command, buf); + cmd->buf_offset = cpu_to_le32(offset); + cmd->resp_hdr_offset = cpu_to_le32(offset + cmd_size); + } + return cmd; +} + +/** + * free_qcom_scm_command() - Free an SCM command + * @cmd: command to free + * + * Free an SCM command. + */ +static inline void free_qcom_scm_command(struct qcom_scm_command *cmd) +{ + kfree(cmd); +} + +/** + * qcom_scm_command_to_response() - Get a pointer to a qcom_scm_response + * @cmd: command + * + * Returns a pointer to a response for a command. + */ +static inline struct qcom_scm_response *qcom_scm_command_to_response( + const struct qcom_scm_command *cmd) +{ + return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset); +} + +/** + * qcom_scm_get_command_buffer() - Get a pointer to a command buffer + * @cmd: command + * + * Returns a pointer to the command buffer of a command. + */ +static inline void *qcom_scm_get_command_buffer(const struct qcom_scm_command *cmd) +{ + return (void *)cmd->buf; +} + +/** + * qcom_scm_get_response_buffer() - Get a pointer to a response buffer + * @rsp: response + * + * Returns a pointer to a response buffer of a response. + */ +static inline void *qcom_scm_get_response_buffer(const struct qcom_scm_response *rsp) +{ + return (void *)rsp + le32_to_cpu(rsp->buf_offset); +} + +static int qcom_scm_remap_error(int err) +{ + pr_err("qcom_scm_call failed with error code %d\n", err); + switch (err) { + case QCOM_SCM_ERROR: + return -EIO; + case QCOM_SCM_EINVAL_ADDR: + case QCOM_SCM_EINVAL_ARG: + return -EINVAL; + case QCOM_SCM_EOPNOTSUPP: + return -EOPNOTSUPP; + case QCOM_SCM_ENOMEM: + return -ENOMEM; + } + return -EINVAL; +} + +static u32 smc(u32 cmd_addr) +{ + int context_id; + register u32 r0 asm("r0") = 1; + register u32 r1 asm("r1") = (u32)&context_id; + register u32 r2 asm("r2") = cmd_addr; + do { + asm volatile( + __asmeq("%0", "r0") + __asmeq("%1", "r0") + __asmeq("%2", "r1") + __asmeq("%3", "r2") +#ifdef REQUIRES_SEC + ".arch_extension sec\n" +#endif + "smc #0 @ switch to secure world\n" + : "=r" (r0) + : "r" (r0), "r" (r1), "r" (r2) + : "r3"); + } while (r0 == QCOM_SCM_INTERRUPTED); + + return r0; +} + +static int __qcom_scm_call(const struct qcom_scm_command *cmd) +{ + int ret; + u32 cmd_addr = virt_to_phys(cmd); + + /* + * Flush the command buffer so that the secure world sees + * the correct data. + */ + __cpuc_flush_dcache_area((void *)cmd, cmd->len); + outer_flush_range(cmd_addr, cmd_addr + cmd->len); + + ret = smc(cmd_addr); + if (ret < 0) + ret = qcom_scm_remap_error(ret); + + return ret; +} + +static void qcom_scm_inv_range(unsigned long start, unsigned long end) +{ + u32 cacheline_size, ctr; + + asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr)); + cacheline_size = 4 << ((ctr >> 16) & 0xf); + + start = round_down(start, cacheline_size); + end = round_up(end, cacheline_size); + outer_inv_range(start, end); + while (start < end) { + asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start) + : "memory"); + start += cacheline_size; + } + dsb(); + isb(); +} + +/** + * qcom_scm_call() - Send an SCM command + * @svc_id: service identifier + * @cmd_id: command identifier + * @cmd_buf: command buffer + * @cmd_len: length of the command buffer + * @resp_buf: response buffer + * @resp_len: length of the response buffer + * + * Sends a command to the SCM and waits for the command to finish processing. + * + * A note on cache maintenance: + * Note that any buffers that are expected to be accessed by the secure world + * must be flushed before invoking qcom_scm_call and invalidated in the cache + * immediately after qcom_scm_call returns. Cache maintenance on the command + * and response buffers is taken care of by qcom_scm_call; however, callers are + * responsible for any other cached buffers passed over to the secure world. + */ +static int qcom_scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, + size_t cmd_len, void *resp_buf, size_t resp_len) +{ + int ret; + struct qcom_scm_command *cmd; + struct qcom_scm_response *rsp; + unsigned long start, end; + + cmd = alloc_qcom_scm_command(cmd_len, resp_len); + if (!cmd) + return -ENOMEM; + + cmd->id = cpu_to_le32((svc_id << 10) | cmd_id); + if (cmd_buf) + memcpy(qcom_scm_get_command_buffer(cmd), cmd_buf, cmd_len); + + mutex_lock(&qcom_scm_lock); + ret = __qcom_scm_call(cmd); + mutex_unlock(&qcom_scm_lock); + if (ret) + goto out; + + rsp = qcom_scm_command_to_response(cmd); + start = (unsigned long)rsp; + + do { + qcom_scm_inv_range(start, start + sizeof(*rsp)); + } while (!rsp->is_complete); + + end = (unsigned long)qcom_scm_get_response_buffer(rsp) + resp_len; + qcom_scm_inv_range(start, end); + + if (resp_buf) + memcpy(resp_buf, qcom_scm_get_response_buffer(rsp), resp_len); +out: + free_qcom_scm_command(cmd); + return ret; +} + +u32 qcom_scm_get_version(void) +{ + int context_id; + static u32 version = -1; + register u32 r0 asm("r0"); + register u32 r1 asm("r1"); + + if (version != -1) + return version; + + mutex_lock(&qcom_scm_lock); + + r0 = 0x1 << 8; + r1 = (u32)&context_id; + do { + asm volatile( + __asmeq("%0", "r0") + __asmeq("%1", "r1") + __asmeq("%2", "r0") + __asmeq("%3", "r1") +#ifdef REQUIRES_SEC + ".arch_extension sec\n" +#endif + "smc #0 @ switch to secure world\n" + : "=r" (r0), "=r" (r1) + : "r" (r0), "r" (r1) + : "r2", "r3"); + } while (r0 == QCOM_SCM_INTERRUPTED); + + version = r1; + mutex_unlock(&qcom_scm_lock); + + return version; +} +EXPORT_SYMBOL(qcom_scm_get_version); + +#define QCOM_SCM_SVC_BOOT 0x1 +#define QCOM_SCM_BOOT_ADDR 0x1 +/* + * Set the cold/warm boot address for one of the CPU cores. + */ +int qcom_scm_set_boot_addr(u32 addr, int flags) +{ + struct { + __le32 flags; + __le32 addr; + } cmd; + + cmd.addr = cpu_to_le32(addr); + cmd.flags = cpu_to_le32(flags); + return qcom_scm_call(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR, + &cmd, sizeof(cmd), NULL, 0); +} +EXPORT_SYMBOL(qcom_scm_set_boot_addr); diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h new file mode 100644 index 000000000000..6bb84cffb396 --- /dev/null +++ b/include/linux/qcom_scm.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __QCOM_SCM_H +#define __QCOM_SCM_H + +#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01 +#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08 +#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20 +#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04 +#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02 +#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10 +#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40 + +extern int qcom_scm_set_boot_addr(u32 addr, int flags); + +#define QCOM_SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) + +extern u32 qcom_scm_get_version(void); + +#endif -- cgit v1.2.3 From a353e4a06f24235138d483a2625726a5fc472949 Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Mon, 2 Mar 2015 16:30:28 -0700 Subject: firmware: qcom: scm: Clean cold boot entry to export only the API We dont need to export the SCM specific cold boot flags to the platform code. Export only a function to set the cold boot address. Signed-off-by: Lina Iyer Signed-off-by: Kumar Gala --- arch/arm/mach-qcom/platsmp.c | 21 +++------------------ drivers/firmware/qcom_scm.c | 41 +++++++++++++++++++++++++++++++++++++++-- include/linux/qcom_scm.h | 5 +---- 3 files changed, 43 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c index 4b67e56911d3..5cde63a64b34 100644 --- a/arch/arm/mach-qcom/platsmp.c +++ b/arch/arm/mach-qcom/platsmp.c @@ -319,25 +319,10 @@ static int kpssv2_boot_secondary(unsigned int cpu, struct task_struct *idle) static void __init qcom_smp_prepare_cpus(unsigned int max_cpus) { - int cpu, map; - unsigned int flags = 0; - static const int cold_boot_flags[] = { - 0, - QCOM_SCM_FLAG_COLDBOOT_CPU1, - QCOM_SCM_FLAG_COLDBOOT_CPU2, - QCOM_SCM_FLAG_COLDBOOT_CPU3, - }; - - for_each_present_cpu(cpu) { - map = cpu_logical_map(cpu); - if (WARN_ON(map >= ARRAY_SIZE(cold_boot_flags))) { - set_cpu_present(cpu, false); - continue; - } - flags |= cold_boot_flags[map]; - } + int cpu; - if (qcom_scm_set_boot_addr(virt_to_phys(secondary_startup_arm), flags)) { + if (qcom_scm_set_cold_boot_addr(secondary_startup_arm, + cpu_present_mask)) { for_each_present_cpu(cpu) { if (cpu == smp_processor_id()) continue; diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 6e7a72bdb176..c953cc38918f 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -34,6 +34,11 @@ #define QCOM_SCM_ERROR -1 #define QCOM_SCM_INTERRUPTED 1 +#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00 +#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01 +#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08 +#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20 + static DEFINE_MUTEX(qcom_scm_lock); /** @@ -329,7 +334,7 @@ EXPORT_SYMBOL(qcom_scm_get_version); /* * Set the cold/warm boot address for one of the CPU cores. */ -int qcom_scm_set_boot_addr(u32 addr, int flags) +static int qcom_scm_set_boot_addr(u32 addr, int flags) { struct { __le32 flags; @@ -341,4 +346,36 @@ int qcom_scm_set_boot_addr(u32 addr, int flags) return qcom_scm_call(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_ADDR, &cmd, sizeof(cmd), NULL, 0); } -EXPORT_SYMBOL(qcom_scm_set_boot_addr); + +/** + * qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus + * @entry: Entry point function for the cpus + * @cpus: The cpumask of cpus that will use the entry point + * + * Set the cold boot address of the cpus. Any cpu outside the supported + * range would be removed from the cpu present mask. + */ +int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) +{ + int flags = 0; + int cpu; + int scm_cb_flags[] = { + QCOM_SCM_FLAG_COLDBOOT_CPU0, + QCOM_SCM_FLAG_COLDBOOT_CPU1, + QCOM_SCM_FLAG_COLDBOOT_CPU2, + QCOM_SCM_FLAG_COLDBOOT_CPU3, + }; + + if (!cpus || (cpus && cpumask_empty(cpus))) + return -EINVAL; + + for_each_cpu(cpu, cpus) { + if (cpu < ARRAY_SIZE(scm_cb_flags)) + flags |= scm_cb_flags[cpu]; + else + set_cpu_present(cpu, false); + } + + return qcom_scm_set_boot_addr(virt_to_phys(entry), flags); +} +EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr); diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 6bb84cffb396..68a1d8801c6f 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -12,15 +12,12 @@ #ifndef __QCOM_SCM_H #define __QCOM_SCM_H -#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01 -#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08 -#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20 #define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04 #define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02 #define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10 #define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40 -extern int qcom_scm_set_boot_addr(u32 addr, int flags); +extern int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus); #define QCOM_SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) -- cgit v1.2.3 From 2ce76a6ad32fa076a2bb5561e859c97fceec8bb1 Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Mon, 2 Mar 2015 16:30:29 -0700 Subject: firmware: qcom: scm: Add qcom_scm_set_warm_boot_addr function A core can be powered down for cpuidle or when it is hotplugged off. In either case, the warmboot return address would be different. Allow setting the warmboot address for a specific cpu, optimize and write to the firmware, if the address is different than the previously set address. Export qcom_scm_set_warm_boot_addr function move the warm boot flags to implementation. Signed-off-by: Lina Iyer Signed-off-by: Kumar Gala --- drivers/firmware/qcom_scm.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/qcom_scm.h | 7 ++---- 2 files changed, 58 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index c953cc38918f..4d8ede4807ac 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -1,4 +1,5 @@ /* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -39,6 +40,23 @@ #define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08 #define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20 +#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04 +#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02 +#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10 +#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40 + +struct qcom_scm_entry { + int flag; + void *entry; +}; + +static struct qcom_scm_entry qcom_scm_wb[] = { + { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 }, + { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 }, + { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 }, + { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 }, +}; + static DEFINE_MUTEX(qcom_scm_lock); /** @@ -379,3 +397,41 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) return qcom_scm_set_boot_addr(virt_to_phys(entry), flags); } EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr); + +/** + * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus + * @entry: Entry point function for the cpus + * @cpus: The cpumask of cpus that will use the entry point + * + * Set the Linux entry point for the SCM to transfer control to when coming + * out of a power down. CPU power down may be executed on cpuidle or hotplug. + */ +int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) +{ + int ret; + int flags = 0; + int cpu; + + /* + * Reassign only if we are switching from hotplug entry point + * to cpuidle entry point or vice versa. + */ + for_each_cpu(cpu, cpus) { + if (entry == qcom_scm_wb[cpu].entry) + continue; + flags |= qcom_scm_wb[cpu].flag; + } + + /* No change in entry function */ + if (!flags) + return 0; + + ret = qcom_scm_set_boot_addr(virt_to_phys(entry), flags); + if (!ret) { + for_each_cpu(cpu, cpus) + qcom_scm_wb[cpu].entry = entry; + } + + return ret; +} +EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 68a1d8801c6f..95ef72a47b0f 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -1,4 +1,5 @@ /* Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,12 +13,8 @@ #ifndef __QCOM_SCM_H #define __QCOM_SCM_H -#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04 -#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02 -#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10 -#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40 - extern int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus); +extern int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus); #define QCOM_SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) -- cgit v1.2.3 From 767b0235dd476596c0d4154839ae6880bec71b3c Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Mon, 2 Mar 2015 16:30:30 -0700 Subject: firmware: qcom: scm: Support cpu power down through SCM Support powering down the calling cpu, by trapping into SCM. This termination function triggers the ARM cpu to execute WFI instruction, causing the power controller to safely power the cpu down. Caches may be flushed before powering down the cpu. If cache controller is set to turn off when the cpu is powered down, then the flags argument indicates to the secure mode to flush its cache lines before executing WFI.The warm boot reset address for the cpu should be set before the calling into this function for the cpu to resume. The original code for the qcom_scm_call_atomic1() comes from a patch by Stephen Boyd [1]. The function scm_call_atomic1() has been cherry picked and renamed to match the convention used in this file. Since there are no users of scm_call_atomic2(), the function is not included. [1]. https://lkml.org/lkml/2014/8/4/765 Signed-off-by: Stephen Boyd Signed-off-by: Lina Iyer Signed-off-by: Kumar Gala --- drivers/firmware/qcom_scm.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/qcom_scm.h | 7 +++++- 2 files changed, 63 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 4d8ede4807ac..994b50fd997c 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -311,6 +311,45 @@ out: return ret; } +#define SCM_CLASS_REGISTER (0x2 << 8) +#define SCM_MASK_IRQS BIT(5) +#define SCM_ATOMIC(svc, cmd, n) (((((svc) << 10)|((cmd) & 0x3ff)) << 12) | \ + SCM_CLASS_REGISTER | \ + SCM_MASK_IRQS | \ + (n & 0xf)) + +/** + * qcom_scm_call_atomic1() - Send an atomic SCM command with one argument + * @svc_id: service identifier + * @cmd_id: command identifier + * @arg1: first argument + * + * This shall only be used with commands that are guaranteed to be + * uninterruptable, atomic and SMP safe. + */ +static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1) +{ + int context_id; + + register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 1); + register u32 r1 asm("r1") = (u32)&context_id; + register u32 r2 asm("r2") = arg1; + + asm volatile( + __asmeq("%0", "r0") + __asmeq("%1", "r0") + __asmeq("%2", "r1") + __asmeq("%3", "r2") +#ifdef REQUIRES_SEC + ".arch_extension sec\n" +#endif + "smc #0 @ switch to secure world\n" + : "=r" (r0) + : "r" (r0), "r" (r1), "r" (r2) + : "r3"); + return r0; +} + u32 qcom_scm_get_version(void) { int context_id; @@ -435,3 +474,21 @@ int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) return ret; } EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); + +#define QCOM_SCM_CMD_TERMINATE_PC 0x2 +#define QCOM_SCM_FLUSH_FLAG_MASK 0x3 + +/** + * qcom_scm_cpu_power_down() - Power down the cpu + * @flags - Flags to flush cache + * + * This is an end point to power down cpu. If there was a pending interrupt, + * the control would return from this function, otherwise, the cpu jumps to the + * warm boot entry point set for this cpu upon reset. + */ +void qcom_scm_cpu_power_down(u32 flags) +{ + qcom_scm_call_atomic1(QCOM_SCM_SVC_BOOT, QCOM_SCM_CMD_TERMINATE_PC, + flags & QCOM_SCM_FLUSH_FLAG_MASK); +} +EXPORT_SYMBOL(qcom_scm_cpu_power_down); diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 95ef72a47b0f..d7a974d5f57c 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. * Copyright (C) 2015 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify @@ -16,6 +16,11 @@ extern int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus); extern int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus); +#define QCOM_SCM_CPU_PWR_DOWN_L2_ON 0x0 +#define QCOM_SCM_CPU_PWR_DOWN_L2_OFF 0x1 + +extern void qcom_scm_cpu_power_down(u32 flags); + #define QCOM_SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) extern u32 qcom_scm_get_version(void); -- cgit v1.2.3 From 1d002fa720738bcd0bddb9178e9ea0773288e1dd Mon Sep 17 00:00:00 2001 From: Simon Farnsworth Date: Tue, 10 Feb 2015 18:38:08 +0000 Subject: drm/dp: Use large transactions for I2C over AUX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Older DisplayPort to DVI-D Dual Link adapters designed by Bizlink have bugs in their I2C over AUX implementation (fixed in newer revisions). They work fine with Windows, but fail with Linux. It turns out that they cannot keep an I2C transaction open unless the previous read was 16 bytes; shorter reads can only be followed by a zero byte transfer ending the I2C transaction. Copy Windows's behaviour, and read 16 bytes at a time. If we get a short reply, assume that there's a hardware bottleneck, and shrink our read size to match. For this purpose, use the algorithm in the DisplayPort 1.2 spec, in the hopes that it'll be closest to what Windows does. Also provide an unsafe module parameter for testing smaller transfer sizes, in case there are sinks out there that cannot work with Windows. Note also that despite the previous comment in drm_dp_i2c_xfer, this speeds up native DP EDID reads; Ville Syrjälä found the following changes in his testing: Device under test: old -> with this patch DP->DVI (OUI 001cf8): 40ms -> 35ms DP->VGA (OUI 0022b9): 45ms -> 38ms Zotac DP->2xHDMI: 25ms -> 4ms Asus PB278 monitor: 22ms -> 3ms A back of the envelope calculation shows that peak theoretical transfer rate for 1 byte reads is around 60 kbit/s; with 16 byte reads, this increases to around 500 kbit/s, which explains the increase in speed. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=55228 Tested-by: Aidan Marks (v3) Signed-off-by: Simon Farnsworth Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_dp_helper.c | 76 +++++++++++++++++++++++++++++++---------- include/drm/drm_dp_helper.h | 5 +++ 2 files changed, 63 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index f1283878ff6d..d5368ea56a0f 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -427,11 +427,13 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter) * retrying the transaction as appropriate. It is assumed that the * aux->transfer function does not modify anything in the msg other than the * reply field. + * + * Returns bytes transferred on success, or a negative error code on failure. */ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { unsigned int retry; - int err; + int ret; /* * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device @@ -440,14 +442,14 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) */ for (retry = 0; retry < 7; retry++) { mutex_lock(&aux->hw_mutex); - err = aux->transfer(aux, msg); + ret = aux->transfer(aux, msg); mutex_unlock(&aux->hw_mutex); - if (err < 0) { - if (err == -EBUSY) + if (ret < 0) { + if (ret == -EBUSY) continue; - DRM_DEBUG_KMS("transaction failed: %d\n", err); - return err; + DRM_DEBUG_KMS("transaction failed: %d\n", ret); + return ret; } @@ -488,9 +490,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) * Both native ACK and I2C ACK replies received. We * can assume the transfer was successful. */ - if (err < msg->size) - return -EPROTO; - return 0; + return ret; case DP_AUX_I2C_REPLY_NACK: DRM_DEBUG_KMS("I2C nack\n"); @@ -513,14 +513,55 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) return -EREMOTEIO; } +/* + * Keep retrying drm_dp_i2c_do_msg until all data has been transferred. + * + * Returns an error code on failure, or a recommended transfer size on success. + */ +static int drm_dp_i2c_drain_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *orig_msg) +{ + int err, ret = orig_msg->size; + struct drm_dp_aux_msg msg = *orig_msg; + + while (msg.size > 0) { + err = drm_dp_i2c_do_msg(aux, &msg); + if (err <= 0) + return err == 0 ? -EPROTO : err; + + if (err < msg.size && err < ret) { + DRM_DEBUG_KMS("Partial I2C reply: requested %zu bytes got %d bytes\n", + msg.size, err); + ret = err; + } + + msg.size -= err; + msg.buffer += err; + } + + return ret; +} + +/* + * Bizlink designed DP->DVI-D Dual Link adapters require the I2C over AUX + * packets to be as large as possible. If not, the I2C transactions never + * succeed. Hence the default is maximum. + */ +static int dp_aux_i2c_transfer_size __read_mostly = DP_AUX_MAX_PAYLOAD_BYTES; +module_param_unsafe(dp_aux_i2c_transfer_size, int, 0644); +MODULE_PARM_DESC(dp_aux_i2c_transfer_size, + "Number of bytes to transfer in a single I2C over DP AUX CH message, (1-16, default 16)"); + static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) { struct drm_dp_aux *aux = adapter->algo_data; unsigned int i, j; + unsigned transfer_size; struct drm_dp_aux_msg msg; int err = 0; + dp_aux_i2c_transfer_size = clamp(dp_aux_i2c_transfer_size, 1, DP_AUX_MAX_PAYLOAD_BYTES); + memset(&msg, 0, sizeof(msg)); for (i = 0; i < num; i++) { @@ -538,20 +579,19 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, err = drm_dp_i2c_do_msg(aux, &msg); if (err < 0) break; - /* - * Many hardware implementations support FIFOs larger than a - * single byte, but it has been empirically determined that - * transferring data in larger chunks can actually lead to - * decreased performance. Therefore each message is simply - * transferred byte-by-byte. + /* We want each transaction to be as large as possible, but + * we'll go to smaller sizes if the hardware gives us a + * short reply. */ - for (j = 0; j < msgs[i].len; j++) { + transfer_size = dp_aux_i2c_transfer_size; + for (j = 0; j < msgs[i].len; j += msg.size) { msg.buffer = msgs[i].buf + j; - msg.size = 1; + msg.size = min(transfer_size, msgs[i].len - j); - err = drm_dp_i2c_do_msg(aux, &msg); + err = drm_dp_i2c_drain_msg(aux, &msg); if (err < 0) break; + transfer_size = err; } if (err < 0) break; diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index c5fdc2d3ca97..523f04c90dea 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -42,6 +42,8 @@ * 1.2 formally includes both eDP and DPI definitions. */ +#define DP_AUX_MAX_PAYLOAD_BYTES 16 + #define DP_AUX_I2C_WRITE 0x0 #define DP_AUX_I2C_READ 0x1 #define DP_AUX_I2C_STATUS 0x2 @@ -680,6 +682,9 @@ struct drm_dp_aux_msg { * transactions. The drm_dp_aux_register_i2c_bus() function registers an * I2C adapter that can be passed to drm_probe_ddc(). Upon removal, drivers * should call drm_dp_aux_unregister_i2c_bus() to remove the I2C adapter. + * The I2C adapter uses long transfers by default; if a partial response is + * received, the adapter will drop down to the size given by the partial + * response for this transaction only. * * Note that the aux helper code assumes that the .transfer() function * only modifies the reply field of the drm_dp_aux_msg structure. The -- cgit v1.2.3 From b7b5ee593118f9dc884fc21237f51b9f599cc432 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 11 Mar 2015 10:23:08 -0400 Subject: drm/fb: document drm_fb_helper_surface_size There has been some confusion about this struct. Lack of documentation probably didn't help. Signed-off-by: Rob Clark Reviewed-by: Alex Deucher Acked-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- include/drm/drm_fb_helper.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'include') diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 21b944c456f6..0dfd94def593 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -44,6 +44,25 @@ struct drm_fb_helper_crtc { int x, y; }; +/** + * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size + * @fb_width: fbdev width + * @fb_height: fbdev height + * @surface_width: scanout buffer width + * @surface_height: scanout buffer height + * @surface_bpp: scanout buffer bpp + * @surface_depth: scanout buffer depth + * + * Note that the scanout surface width/height may be larger than the fbdev + * width/height. In case of multiple displays, the scanout surface is sized + * according to the largest width/height (so it is large enough for all CRTCs + * to scanout). But the fbdev width/height is sized to the minimum width/ + * height of all the displays. This ensures that fbcon fits on the smallest + * of the attached displays. + * + * So what is passed to drm_fb_helper_fill_var() should be fb_width/fb_height, + * rather than the surface size. + */ struct drm_fb_helper_surface_size { u32 fb_width; u32 fb_height; -- cgit v1.2.3 From 08855fae10f088d83527bdf108199d3e35be503b Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 11 Mar 2015 10:23:09 -0400 Subject: drm/atomic: minor kerneldoc typo fix Signed-off-by: Rob Clark Reviewed-by: Alex Deucher Acked-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- include/drm/drm_crtc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index adc9ea5acf02..7b5c661b37d8 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -915,7 +915,7 @@ struct drm_bridge { }; /** - * struct struct drm_atomic_state - the global state object for atomic updates + * struct drm_atomic_state - the global state object for atomic updates * @dev: parent DRM device * @allow_modeset: allow full modeset * @legacy_cursor_update: hint to enforce legacy cursor ioctl semantics -- cgit v1.2.3 From d09957fbb4d0b059b3176b510540df69048ad170 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 10 Mar 2015 17:48:37 +0100 Subject: mtd: cfi: reduce stack size The cfi_staa_write_buffers function uses a large amount of kernel stack whenever CONFIG_MTD_MAP_BANK_WIDTH_32 is set, and that results in a warning on ARM allmodconfig builds: drivers/mtd/chips/cfi_cmdset_0020.c: In function 'cfi_staa_write_buffers': drivers/mtd/chips/cfi_cmdset_0020.c:651:1: warning: the frame size of 1208 bytes is larger than 1024 bytes [-Wframe-larger-than=] It turns out that this is largely a result of a suboptimal implementation of map_word_andequal(). Replacing this function with a straightforward one reduces the stack size in this function by exactly 200 bytes, shrinks the .text segment for this file from 27648 bytes to 26608 bytes, and makes the warning go away. Signed-off-by: Arnd Bergmann Signed-off-by: Brian Norris --- include/linux/mtd/map.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index 5f487d776411..a872157a0700 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -314,7 +314,17 @@ static inline map_word map_word_or(struct map_info *map, map_word val1, map_word return r; } -#define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b)) +static inline int map_word_andequal(struct map_info *map, map_word val1, map_word val2, map_word val3) +{ + int i; + + for (i = 0; i < map_words(map); i++) { + if ((val1.x[i] & val2.x[i]) != val3.x[i]) + return 0; + } + + return 1; +} static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2) { -- cgit v1.2.3 From 7234bea69de200e2060d099685c4c674b556edc0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 10 Mar 2015 17:51:55 +0100 Subject: mtd: clean up whitespace in linux/mtd/map.h As the only comments I got for the "mtd: cfi: reduce stack size" patch were about whitespace changes, it appears necessary to fix up the rest of the file as well, which contains the exact same mistakes. Signed-off-by: Arnd Bergmann Signed-off-by: Brian Norris --- include/linux/mtd/map.h | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index a872157a0700..29975c73a953 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -77,7 +77,7 @@ /* ensure we never evaluate anything shorted than an unsigned long * to zero, and ensure we'll never miss the end of an comparison (bjd) */ -#define map_calc_words(map) ((map_bankwidth(map) + (sizeof(unsigned long)-1))/ sizeof(unsigned long)) +#define map_calc_words(map) ((map_bankwidth(map) + (sizeof(unsigned long)-1)) / sizeof(unsigned long)) #ifdef CONFIG_MTD_MAP_BANK_WIDTH_8 # ifdef map_bankwidth @@ -181,7 +181,7 @@ static inline int map_bankwidth_supported(int w) } } -#define MAX_MAP_LONGS ( ((MAX_MAP_BANKWIDTH*8) + BITS_PER_LONG - 1) / BITS_PER_LONG ) +#define MAX_MAP_LONGS (((MAX_MAP_BANKWIDTH * 8) + BITS_PER_LONG - 1) / BITS_PER_LONG) typedef union { unsigned long x[MAX_MAP_LONGS]; @@ -264,20 +264,22 @@ void unregister_mtd_chip_driver(struct mtd_chip_driver *); struct mtd_info *do_map_probe(const char *name, struct map_info *map); void map_destroy(struct mtd_info *mtd); -#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0) -#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0) +#define ENABLE_VPP(map) do { if (map->set_vpp) map->set_vpp(map, 1); } while (0) +#define DISABLE_VPP(map) do { if (map->set_vpp) map->set_vpp(map, 0); } while (0) #define INVALIDATE_CACHED_RANGE(map, from, size) \ - do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0) + do { if (map->inval_cache) map->inval_cache(map, from, size); } while (0) static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2) { int i; - for (i=0; ivirt + ofs); #endif else if (map_bankwidth_is_large(map)) - memcpy_fromio(r.x, map->virt+ofs, map->bankwidth); + memcpy_fromio(r.x, map->virt + ofs, map->bankwidth); else BUG(); -- cgit v1.2.3 From 315491e5d6ee66838a18a8ca0c14e6ffb376e48c Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Fri, 9 Jan 2015 15:21:58 -0600 Subject: remoteproc: add IOMMU hardware capability flag The remoteproc framework currently relies on iommu_present() on the bus the device is on, to perform MMU management. However, this logic doesn't scale for multi-arch, especially for processors that do not have an IOMMU. Replace this logic instead by using a h/w capability flag for the presence of IOMMU in the rproc structure. This issue is seen on OMAP platforms when trying to add a remoteproc driver for a small Cortex M3 called the WkupM3 used for suspend / resume management on TI AM335/AM437x SoCs. This processor does not have an MMU. Same is the case with another processor subsystem PRU-ICSS on AM335/AM437x. All these are platform devices, and the current iommu_present check will not scale for the same kernel image to support OMAP4/OMAP5 and AM335/AM437x. The existing platform implementation drivers - OMAP remoteproc, STE Modem remoteproc and DA8xx remoteproc, are updated as well to properly configure the newly added rproc field. Cc: Robert Tivy Cc: Linus Walleij Signed-off-by: Suman Anna [small change in the commit title and in a single comment] Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/da8xx_remoteproc.c | 1 + drivers/remoteproc/omap_remoteproc.c | 2 ++ drivers/remoteproc/remoteproc_core.c | 15 ++------------- drivers/remoteproc/ste_modem_rproc.c | 1 + include/linux/remoteproc.h | 2 ++ 5 files changed, 8 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index 89fd057e5f1d..f8d6a0661c14 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -224,6 +224,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev) drproc = rproc->priv; drproc->rproc = rproc; + rproc->has_iommu = false; platform_set_drvdata(pdev, rproc); diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c index e85f30370760..b74368a91235 100644 --- a/drivers/remoteproc/omap_remoteproc.c +++ b/drivers/remoteproc/omap_remoteproc.c @@ -202,6 +202,8 @@ static int omap_rproc_probe(struct platform_device *pdev) oproc = rproc->priv; oproc->rproc = rproc; + /* All existing OMAP IPU and DSP processors have an MMU */ + rproc->has_iommu = true; platform_set_drvdata(pdev, rproc); diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 3cd85a638afa..11cdb119e4f3 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -94,19 +94,8 @@ static int rproc_enable_iommu(struct rproc *rproc) struct device *dev = rproc->dev.parent; int ret; - /* - * We currently use iommu_present() to decide if an IOMMU - * setup is needed. - * - * This works for simple cases, but will easily fail with - * platforms that do have an IOMMU, but not for this specific - * rproc. - * - * This will be easily solved by introducing hw capabilities - * that will be set by the remoteproc driver. - */ - if (!iommu_present(dev->bus)) { - dev_dbg(dev, "iommu not found\n"); + if (!rproc->has_iommu) { + dev_dbg(dev, "iommu not present\n"); return 0; } diff --git a/drivers/remoteproc/ste_modem_rproc.c b/drivers/remoteproc/ste_modem_rproc.c index 16b7b7bd805b..dd193f35a1ff 100644 --- a/drivers/remoteproc/ste_modem_rproc.c +++ b/drivers/remoteproc/ste_modem_rproc.c @@ -289,6 +289,7 @@ static int sproc_probe(struct platform_device *pdev) sproc = rproc->priv; sproc->mdev = mdev; sproc->rproc = rproc; + rproc->has_iommu = false; mdev->drv_data = sproc; /* Provide callback functions to modem device */ diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 9e7e745dac55..78b8a9b9d40a 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -404,6 +404,7 @@ enum rproc_crash_type { * @table_ptr: pointer to the resource table in effect * @cached_table: copy of the resource table * @table_csum: checksum of the resource table + * @has_iommu: flag to indicate if remote processor is behind an MMU */ struct rproc { struct klist_node node; @@ -435,6 +436,7 @@ struct rproc { struct resource_table *table_ptr; struct resource_table *cached_table; u32 table_csum; + bool has_iommu; }; /* we currently support only two vrings per rvdev */ -- cgit v1.2.3 From dfc202ead3123988793ac1160849676000b77ee4 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 2 Feb 2015 14:37:41 -0800 Subject: clk: Add tracepoints for hardware operations It's useful to have tracepoints around operations that change the hardware state so that we can debug clock hardware performance and operations. Four basic types of events are supported: on/off events for enable, disable, prepare, unprepare that only record an event and a clock name, rate changing events for clk_set_{min_,max_}rate{_range}(), phase changing events for clk_set_phase() and parent changing events for clk_set_parent(). Cc: Steven Rostedt Signed-off-by: Stephen Boyd Signed-off-by: Michael Turquette --- drivers/clk/clk.c | 56 ++++++++++--- include/trace/events/clk.h | 198 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+), 10 deletions(-) create mode 100644 include/trace/events/clk.h (limited to 'include') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 0b3f39c03785..42064cec2364 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -77,6 +77,9 @@ struct clk_core { struct kref ref; }; +#define CREATE_TRACE_POINTS +#include + struct clk { struct clk_core *core; const char *dev_id; @@ -492,10 +495,12 @@ static void clk_unprepare_unused_subtree(struct clk_core *clk) return; if (clk_core_is_prepared(clk)) { + trace_clk_unprepare(clk); if (clk->ops->unprepare_unused) clk->ops->unprepare_unused(clk->hw); else if (clk->ops->unprepare) clk->ops->unprepare(clk->hw); + trace_clk_unprepare_complete(clk); } } @@ -524,10 +529,12 @@ static void clk_disable_unused_subtree(struct clk_core *clk) * back to .disable */ if (clk_core_is_enabled(clk)) { + trace_clk_disable(clk); if (clk->ops->disable_unused) clk->ops->disable_unused(clk->hw); else if (clk->ops->disable) clk->ops->disable(clk->hw); + trace_clk_disable_complete(clk); } unlock_out: @@ -907,9 +914,12 @@ static void clk_core_unprepare(struct clk_core *clk) WARN_ON(clk->enable_count > 0); + trace_clk_unprepare(clk); + if (clk->ops->unprepare) clk->ops->unprepare(clk->hw); + trace_clk_unprepare_complete(clk); clk_core_unprepare(clk->parent); } @@ -947,12 +957,16 @@ static int clk_core_prepare(struct clk_core *clk) if (ret) return ret; - if (clk->ops->prepare) { + trace_clk_prepare(clk); + + if (clk->ops->prepare) ret = clk->ops->prepare(clk->hw); - if (ret) { - clk_core_unprepare(clk->parent); - return ret; - } + + trace_clk_prepare_complete(clk); + + if (ret) { + clk_core_unprepare(clk->parent); + return ret; } } @@ -999,9 +1013,13 @@ static void clk_core_disable(struct clk_core *clk) if (--clk->enable_count > 0) return; + trace_clk_disable(clk); + if (clk->ops->disable) clk->ops->disable(clk->hw); + trace_clk_disable_complete(clk); + clk_core_disable(clk->parent); } @@ -1054,12 +1072,16 @@ static int clk_core_enable(struct clk_core *clk) if (ret) return ret; - if (clk->ops->enable) { + trace_clk_enable(clk); + + if (clk->ops->enable) ret = clk->ops->enable(clk->hw); - if (ret) { - clk_core_disable(clk->parent); - return ret; - } + + trace_clk_enable_complete(clk); + + if (ret) { + clk_core_disable(clk->parent); + return ret; } } @@ -1490,10 +1512,14 @@ static int __clk_set_parent(struct clk_core *clk, struct clk_core *parent, old_parent = __clk_set_parent_before(clk, parent); + trace_clk_set_parent(clk, parent); + /* change clock input source */ if (parent && clk->ops->set_parent) ret = clk->ops->set_parent(clk->hw, p_index); + trace_clk_set_parent_complete(clk, parent); + if (ret) { flags = clk_enable_lock(); clk_reparent(clk, old_parent); @@ -1719,6 +1745,7 @@ static void clk_change_rate(struct clk_core *clk) if (clk->new_parent && clk->new_parent != clk->parent) { old_parent = __clk_set_parent_before(clk, clk->new_parent); + trace_clk_set_parent(clk, clk->new_parent); if (clk->ops->set_rate_and_parent) { skip_set_rate = true; @@ -1729,12 +1756,17 @@ static void clk_change_rate(struct clk_core *clk) clk->ops->set_parent(clk->hw, clk->new_parent_index); } + trace_clk_set_parent_complete(clk, clk->new_parent); __clk_set_parent_after(clk, clk->new_parent, old_parent); } + trace_clk_set_rate(clk, clk->new_rate); + if (!skip_set_rate && clk->ops->set_rate) clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate); + trace_clk_set_rate_complete(clk, clk->new_rate); + clk->rate = clk_recalc(clk, best_parent_rate); if (clk->notifier_count && old_rate != clk->rate) @@ -2135,9 +2167,13 @@ int clk_set_phase(struct clk *clk, int degrees) clk_prepare_lock(); + trace_clk_set_phase(clk->core, degrees); + if (clk->core->ops->set_phase) ret = clk->core->ops->set_phase(clk->core->hw, degrees); + trace_clk_set_phase_complete(clk->core, degrees); + if (!ret) clk->core->phase = degrees; diff --git a/include/trace/events/clk.h b/include/trace/events/clk.h new file mode 100644 index 000000000000..758607226bfd --- /dev/null +++ b/include/trace/events/clk.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM clk + +#if !defined(_TRACE_CLK_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_CLK_H + +#include + +struct clk_core; + +DECLARE_EVENT_CLASS(clk, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core), + + TP_STRUCT__entry( + __string( name, core->name ) + ), + + TP_fast_assign( + __assign_str(name, core->name); + ), + + TP_printk("%s", __get_str(name)) +); + +DEFINE_EVENT(clk, clk_enable, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_enable_complete, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_disable, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_disable_complete, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_prepare, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_prepare_complete, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_unprepare, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_unprepare_complete, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DECLARE_EVENT_CLASS(clk_rate, + + TP_PROTO(struct clk_core *core, unsigned long rate), + + TP_ARGS(core, rate), + + TP_STRUCT__entry( + __string( name, core->name ) + __field(unsigned long, rate ) + ), + + TP_fast_assign( + __assign_str(name, core->name); + __entry->rate = rate; + ), + + TP_printk("%s %lu", __get_str(name), (unsigned long)__entry->rate) +); + +DEFINE_EVENT(clk_rate, clk_set_rate, + + TP_PROTO(struct clk_core *core, unsigned long rate), + + TP_ARGS(core, rate) +); + +DEFINE_EVENT(clk_rate, clk_set_rate_complete, + + TP_PROTO(struct clk_core *core, unsigned long rate), + + TP_ARGS(core, rate) +); + +DECLARE_EVENT_CLASS(clk_parent, + + TP_PROTO(struct clk_core *core, struct clk_core *parent), + + TP_ARGS(core, parent), + + TP_STRUCT__entry( + __string( name, core->name ) + __string( pname, parent->name ) + ), + + TP_fast_assign( + __assign_str(name, core->name); + __assign_str(pname, parent->name); + ), + + TP_printk("%s %s", __get_str(name), __get_str(pname)) +); + +DEFINE_EVENT(clk_parent, clk_set_parent, + + TP_PROTO(struct clk_core *core, struct clk_core *parent), + + TP_ARGS(core, parent) +); + +DEFINE_EVENT(clk_parent, clk_set_parent_complete, + + TP_PROTO(struct clk_core *core, struct clk_core *parent), + + TP_ARGS(core, parent) +); + +DECLARE_EVENT_CLASS(clk_phase, + + TP_PROTO(struct clk_core *core, int phase), + + TP_ARGS(core, phase), + + TP_STRUCT__entry( + __string( name, core->name ) + __field( int, phase ) + ), + + TP_fast_assign( + __assign_str(name, core->name); + __entry->phase = phase; + ), + + TP_printk("%s %d", __get_str(name), (int)__entry->phase) +); + +DEFINE_EVENT(clk_phase, clk_set_phase, + + TP_PROTO(struct clk_core *core, int phase), + + TP_ARGS(core, phase) +); + +DEFINE_EVENT(clk_phase, clk_set_phase_complete, + + TP_PROTO(struct clk_core *core, int phase), + + TP_ARGS(core, phase) +); + +#endif /* _TRACE_CLK_H */ + +/* This part must be outside protection */ +#include -- cgit v1.2.3 From 1aa15f4e00c9be2c7e4c3bd36886ed65d25cc075 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 12 Mar 2015 13:07:26 +0100 Subject: mfd: syscon: Add atmel system timer registers definition AT91RM920 has a memory range reserved for timer and watchdog configuration. Expose those registers so that drivers can make use of the system timer syscon declared in at91 DTs. Signed-off-by: Alexandre Belloni Acked-by: Lee Jones Signed-off-by: Nicolas Ferre --- include/linux/mfd/syscon/atmel-st.h | 49 +++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 include/linux/mfd/syscon/atmel-st.h (limited to 'include') diff --git a/include/linux/mfd/syscon/atmel-st.h b/include/linux/mfd/syscon/atmel-st.h new file mode 100644 index 000000000000..8acf1ec1fa32 --- /dev/null +++ b/include/linux/mfd/syscon/atmel-st.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) SAN People + * + * System Timer (ST) - System peripherals registers. + * Based on AT91RM9200 datasheet revision E. + * + * 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. + */ + +#ifndef _LINUX_MFD_SYSCON_ATMEL_ST_H +#define _LINUX_MFD_SYSCON_ATMEL_ST_H + +#include + +#define AT91_ST_CR 0x00 /* Control Register */ +#define AT91_ST_WDRST BIT(0) /* Watchdog Timer Restart */ + +#define AT91_ST_PIMR 0x04 /* Period Interval Mode Register */ +#define AT91_ST_PIV 0xffff /* Period Interval Value */ + +#define AT91_ST_WDMR 0x08 /* Watchdog Mode Register */ +#define AT91_ST_WDV 0xffff /* Watchdog Counter Value */ +#define AT91_ST_RSTEN BIT(16) /* Reset Enable */ +#define AT91_ST_EXTEN BIT(17) /* External Signal Assertion Enable */ + +#define AT91_ST_RTMR 0x0c /* Real-time Mode Register */ +#define AT91_ST_RTPRES 0xffff /* Real-time Prescalar Value */ + +#define AT91_ST_SR 0x10 /* Status Register */ +#define AT91_ST_PITS BIT(0) /* Period Interval Timer Status */ +#define AT91_ST_WDOVF BIT(1) /* Watchdog Overflow */ +#define AT91_ST_RTTINC BIT(2) /* Real-time Timer Increment */ +#define AT91_ST_ALMS BIT(3) /* Alarm Status */ + +#define AT91_ST_IER 0x14 /* Interrupt Enable Register */ +#define AT91_ST_IDR 0x18 /* Interrupt Disable Register */ +#define AT91_ST_IMR 0x1c /* Interrupt Mask Register */ + +#define AT91_ST_RTAR 0x20 /* Real-time Alarm Register */ +#define AT91_ST_ALMV 0xfffff /* Alarm Value */ + +#define AT91_ST_CRTR 0x24 /* Current Real-time Register */ +#define AT91_ST_CRTV 0xfffff /* Current Real-Time Value */ + +#endif /* _LINUX_MFD_SYSCON_ATMEL_ST_H */ -- cgit v1.2.3 From 3b62286d0ef785815994e2558e8cfb686597b0cd Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 16 Mar 2015 09:37:24 +0200 Subject: dmaengine: Remove FSF mailing addresses Free Software Foundation mailing address has been moved in the past and some of the addresses here are outdated. Remove them from file headers since the COPYING file in the kernel sources includes it. Signed-off-by: Jarkko Nikula Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 4 ---- drivers/dma/dma-jz4740.c | 4 ---- drivers/dma/dmaengine.c | 4 ---- drivers/dma/intel_mid_dma.c | 4 ---- drivers/dma/intel_mid_dma_regs.h | 4 ---- drivers/dma/ioat/dca.c | 4 ---- drivers/dma/ioat/dma.c | 4 ---- drivers/dma/ioat/dma.h | 4 ---- drivers/dma/ioat/dma_v2.c | 4 ---- drivers/dma/ioat/dma_v2.h | 4 ---- drivers/dma/ioat/dma_v3.c | 4 ---- drivers/dma/ioat/hw.h | 4 ---- drivers/dma/ioat/pci.c | 4 ---- drivers/dma/ioat/registers.h | 4 ---- drivers/dma/iop-adma.c | 4 ---- drivers/dma/mpc512x_dma.c | 4 ---- drivers/dma/mv_xor.c | 4 ---- drivers/dma/mv_xor.h | 4 ---- drivers/dma/ppc4xx/adma.c | 4 ---- include/linux/dmaengine.h | 4 ---- 20 files changed, 80 deletions(-) (limited to 'include') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 4a5fd245014e..171e768888c0 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -15,10 +15,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * * The full GNU General Public License is in this distribution in the file * called COPYING. * diff --git a/drivers/dma/dma-jz4740.c b/drivers/dma/dma-jz4740.c index f6a4c4270dcd..248a6ee1775b 100644 --- a/drivers/dma/dma-jz4740.c +++ b/drivers/dma/dma-jz4740.c @@ -7,10 +7,6 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * */ #include diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 344b0ac6d985..24967c89f5d4 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * * The full GNU General Public License is included in this distribution in the * file called COPYING. */ diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 5aaead9b56f7..c17e18b909b6 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c @@ -15,10 +15,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h index 17b42192ea58..ebdd567dac1e 100644 --- a/drivers/dma/intel_mid_dma_regs.h +++ b/drivers/dma/intel_mid_dma_regs.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * diff --git a/drivers/dma/ioat/dca.c b/drivers/dma/ioat/dca.c index 3b55bb8d969a..ea1e107ae884 100644 --- a/drivers/dma/ioat/dca.c +++ b/drivers/dma/ioat/dca.c @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * The full GNU General Public License is included in this distribution in * the file called "COPYING". * diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 940c1502a8b5..ee0aa9f4ccfa 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * The full GNU General Public License is included in this distribution in * the file called "COPYING". * diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h index d63f68b1aa35..30f5c7eede16 100644 --- a/drivers/dma/ioat/dma.h +++ b/drivers/dma/ioat/dma.h @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * * The full GNU General Public License is included in this distribution in the * file called COPYING. */ diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c index 695483e6be32..69c7dfcad023 100644 --- a/drivers/dma/ioat/dma_v2.c +++ b/drivers/dma/ioat/dma_v2.c @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * The full GNU General Public License is included in this distribution in * the file called "COPYING". * diff --git a/drivers/dma/ioat/dma_v2.h b/drivers/dma/ioat/dma_v2.h index 470292767e68..bf24ebe874b0 100644 --- a/drivers/dma/ioat/dma_v2.h +++ b/drivers/dma/ioat/dma_v2.h @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * * The full GNU General Public License is included in this distribution in the * file called COPYING. */ diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index 77a6dcf25b98..3d19a3187a77 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c @@ -15,10 +15,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * The full GNU General Public License is included in this distribution in * the file called "COPYING". * diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h index 02177ecf09f8..a3e731edce57 100644 --- a/drivers/dma/ioat/hw.h +++ b/drivers/dma/ioat/hw.h @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * * The full GNU General Public License is included in this distribution in the * file called COPYING. */ diff --git a/drivers/dma/ioat/pci.c b/drivers/dma/ioat/pci.c index 5501eb072d69..76f0dc688a19 100644 --- a/drivers/dma/ioat/pci.c +++ b/drivers/dma/ioat/pci.c @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * The full GNU General Public License is included in this distribution in * the file called "COPYING". * diff --git a/drivers/dma/ioat/registers.h b/drivers/dma/ioat/registers.h index 2f1cfa0f1f47..909352f74c89 100644 --- a/drivers/dma/ioat/registers.h +++ b/drivers/dma/ioat/registers.h @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * * The full GNU General Public License is included in this distribution in the * file called COPYING. */ diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 263d9f6a207e..998826854fdd 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * */ /* diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 57d2457545f3..c66a82ea2559 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -21,10 +21,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * * The full GNU General Public License is included in this distribution in the * file called COPYING. */ diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index b03e8137b918..5ef567ee335b 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -10,10 +10,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #include diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h index 78edc7e44569..91958dba39a2 100644 --- a/drivers/dma/mv_xor.h +++ b/drivers/dma/mv_xor.h @@ -9,10 +9,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef MV_XOR_H diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index fa764a39cd36..9217f893b0d1 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c @@ -16,10 +16,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * * The full GNU General Public License is included in this distribution in the * file called COPYING. */ diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 2bff9abc162a..ad419757241f 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -11,10 +11,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * * The full GNU General Public License is included in this distribution in the * file called COPYING. */ -- cgit v1.2.3 From 34644524bce91883d5051a7eaf3ec5464ed149bf Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Fri, 6 Feb 2015 19:15:27 +0530 Subject: lib: devres: add a helper function for ioremap_wc Implement a resource managed writecombine ioremap function. Signed-off-by: Abhilash Kesavan Acked-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-model/devres.txt | 1 + include/linux/io.h | 2 ++ lib/devres.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+) (limited to 'include') diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 6d1e8eeb5990..7fe7fd263aba 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -276,6 +276,7 @@ IOMAP devm_ioport_unmap() devm_ioremap() devm_ioremap_nocache() + devm_ioremap_wc() devm_ioremap_resource() : checks resource, requests memory region, ioremaps devm_iounmap() pcim_iomap() diff --git a/include/linux/io.h b/include/linux/io.h index fa02e55e5a2e..42b33f03d1df 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -64,6 +64,8 @@ void __iomem *devm_ioremap(struct device *dev, resource_size_t offset, resource_size_t size); void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset, resource_size_t size); +void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset, + resource_size_t size); void devm_iounmap(struct device *dev, void __iomem *addr); int check_signature(const volatile void __iomem *io_addr, const unsigned char *signature, int length); diff --git a/lib/devres.c b/lib/devres.c index 0f1dd2e9d2c1..fbe2aac522e6 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -71,6 +71,34 @@ void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset, } EXPORT_SYMBOL(devm_ioremap_nocache); +/** + * devm_ioremap_wc - Managed ioremap_wc() + * @dev: Generic device to remap IO address for + * @offset: BUS offset to map + * @size: Size of map + * + * Managed ioremap_wc(). Map is automatically unmapped on driver detach. + */ +void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset, + resource_size_t size) +{ + void __iomem **ptr, *addr; + + ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return NULL; + + addr = ioremap_wc(offset, size); + if (addr) { + *ptr = addr; + devres_add(dev, ptr); + } else + devres_free(ptr); + + return addr; +} +EXPORT_SYMBOL(devm_ioremap_wc); + /** * devm_iounmap - Managed iounmap() * @dev: Generic device to unmap for -- cgit v1.2.3 From 937abe88aea3161cd3a563e577fc9cf4522c7aad Mon Sep 17 00:00:00 2001 From: Kedareswara rao Appana Date: Mon, 2 Mar 2015 23:24:24 +0530 Subject: dmaengine: xilinx-dma: move header file to common location This patch moves the xilinx_dma.h header file to the include/linux/dma. Signed-off-by: Kedareswara rao Appana Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_vdma.c | 2 +- include/linux/amba/xilinx_dma.h | 47 ---------------------------------------- include/linux/dma/xilinx_dma.h | 47 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 48 deletions(-) delete mode 100644 include/linux/amba/xilinx_dma.h create mode 100644 include/linux/dma/xilinx_dma.h (limited to 'include') diff --git a/drivers/dma/xilinx/xilinx_vdma.c b/drivers/dma/xilinx/xilinx_vdma.c index bdd2a5dd7220..d8434d465885 100644 --- a/drivers/dma/xilinx/xilinx_vdma.c +++ b/drivers/dma/xilinx/xilinx_vdma.c @@ -22,9 +22,9 @@ * (at your option) any later version. */ -#include #include #include +#include #include #include #include diff --git a/include/linux/amba/xilinx_dma.h b/include/linux/amba/xilinx_dma.h deleted file mode 100644 index 34b98f276ed0..000000000000 --- a/include/linux/amba/xilinx_dma.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Xilinx DMA Engine drivers support header file - * - * Copyright (C) 2010-2014 Xilinx, Inc. All rights reserved. - * - * This 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. - */ - -#ifndef __DMA_XILINX_DMA_H -#define __DMA_XILINX_DMA_H - -#include -#include - -/** - * struct xilinx_vdma_config - VDMA Configuration structure - * @frm_dly: Frame delay - * @gen_lock: Whether in gen-lock mode - * @master: Master that it syncs to - * @frm_cnt_en: Enable frame count enable - * @park: Whether wants to park - * @park_frm: Frame to park on - * @coalesc: Interrupt coalescing threshold - * @delay: Delay counter - * @reset: Reset Channel - * @ext_fsync: External Frame Sync source - */ -struct xilinx_vdma_config { - int frm_dly; - int gen_lock; - int master; - int frm_cnt_en; - int park; - int park_frm; - int coalesc; - int delay; - int reset; - int ext_fsync; -}; - -int xilinx_vdma_channel_set_config(struct dma_chan *dchan, - struct xilinx_vdma_config *cfg); - -#endif diff --git a/include/linux/dma/xilinx_dma.h b/include/linux/dma/xilinx_dma.h new file mode 100644 index 000000000000..34b98f276ed0 --- /dev/null +++ b/include/linux/dma/xilinx_dma.h @@ -0,0 +1,47 @@ +/* + * Xilinx DMA Engine drivers support header file + * + * Copyright (C) 2010-2014 Xilinx, Inc. All rights reserved. + * + * This 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. + */ + +#ifndef __DMA_XILINX_DMA_H +#define __DMA_XILINX_DMA_H + +#include +#include + +/** + * struct xilinx_vdma_config - VDMA Configuration structure + * @frm_dly: Frame delay + * @gen_lock: Whether in gen-lock mode + * @master: Master that it syncs to + * @frm_cnt_en: Enable frame count enable + * @park: Whether wants to park + * @park_frm: Frame to park on + * @coalesc: Interrupt coalescing threshold + * @delay: Delay counter + * @reset: Reset Channel + * @ext_fsync: External Frame Sync source + */ +struct xilinx_vdma_config { + int frm_dly; + int gen_lock; + int master; + int frm_cnt_en; + int park; + int park_frm; + int coalesc; + int delay; + int reset; + int ext_fsync; +}; + +int xilinx_vdma_channel_set_config(struct dma_chan *dchan, + struct xilinx_vdma_config *cfg); + +#endif -- cgit v1.2.3 From 27cd44618b92fc8c6889e4628407791e45422bac Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Wed, 4 Mar 2015 14:41:16 +0000 Subject: drm/i915: Add I915_PARAM_REVISION Adds a parameter which can be used with DRM_I915_GETPARAM to query the GPU revision. The intention is to use this in Mesa to implement the WaDisableSIMD16On3SrcInstr workaround on Skylake but only for revision 2. Signed-off-by: Neil Roberts Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 +++ include/uapi/drm/i915_drm.h | 1 + 2 files changed, 4 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 053e1788f578..3b64c526b6b9 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -68,6 +68,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_CHIPSET_ID: value = dev->pdev->device; break; + case I915_PARAM_REVISION: + value = dev->pdev->revision; + break; case I915_PARAM_HAS_GEM: value = 1; break; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 6eed16b92a24..b768f3b21eaa 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -347,6 +347,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_COHERENT_PHYS_GTT 29 #define I915_PARAM_MMAP_VERSION 30 #define I915_PARAM_HAS_BSD2 31 +#define I915_PARAM_REVISION 32 typedef struct drm_i915_getparam { int param; -- cgit v1.2.3 From 8c4f83fb1e8bf317e894f62d17a63c32b7a6b75e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Mar 2015 08:26:23 +0100 Subject: drm/fourcc: 64 #defines need ULL postfix I have no idea about the exact rules, but this angered Dave's 32bit rhel gcc. Reported-by: Dave Airlie Signed-off-by: Daniel Vetter --- include/uapi/drm/drm_fourcc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index e6efac23c7ea..07735822a28f 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -151,7 +151,7 @@ /* add more to the end as needed */ #define fourcc_mod_code(vendor, val) \ - ((((u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | (val & 0x00ffffffffffffffL)) + ((((u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | (val & 0x00ffffffffffffffULL)) /* * Format Modifier tokens: -- cgit v1.2.3 From 44e5e28bf64fcd7c4d3f933cb4c7f69d8aa11781 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 Feb 2015 14:34:05 +0200 Subject: drm/i915: remove indirection in the PCI ID macros Spell all the PCI IDs out to be able to quickly grep for the IDs. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Damien Lespiau [danvet: Add GT1/2 to comments to not loose that distinction.] Signed-off-by: Daniel Vetter --- include/drm/i915_pciids.h | 49 ++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index f2e47fd56751..613372375ada 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -208,40 +208,41 @@ #define INTEL_VLV_D_IDS(info) \ INTEL_VGA_DEVICE(0x0155, info) -#define _INTEL_BDW_M(gt, id, info) \ - INTEL_VGA_DEVICE((((gt) - 1) << 4) | (id), info) -#define _INTEL_BDW_D(gt, id, info) \ - INTEL_VGA_DEVICE((((gt) - 1) << 4) | (id), info) - -#define _INTEL_BDW_M_IDS(gt, info) \ - _INTEL_BDW_M(gt, 0x1602, info), /* Halo */ \ - _INTEL_BDW_M(gt, 0x1606, info), /* ULT */ \ - _INTEL_BDW_M(gt, 0x160B, info), /* ULT */ \ - _INTEL_BDW_M(gt, 0x160E, info) /* ULX */ - -#define _INTEL_BDW_D_IDS(gt, info) \ - _INTEL_BDW_D(gt, 0x160A, info), /* Server */ \ - _INTEL_BDW_D(gt, 0x160D, info) /* Workstation */ - -#define INTEL_BDW_GT12M_IDS(info) \ - _INTEL_BDW_M_IDS(1, info), \ - _INTEL_BDW_M_IDS(2, info) +#define INTEL_BDW_GT12M_IDS(info) \ + INTEL_VGA_DEVICE(0x1602, info), /* GT1 ULT */ \ + INTEL_VGA_DEVICE(0x1606, info), /* GT1 ULT */ \ + INTEL_VGA_DEVICE(0x160B, info), /* GT1 Iris */ \ + INTEL_VGA_DEVICE(0x160E, info), /* GT1 ULX */ \ + INTEL_VGA_DEVICE(0x1612, info), /* GT2 Halo */ \ + INTEL_VGA_DEVICE(0x1616, info), /* GT2 ULT */ \ + INTEL_VGA_DEVICE(0x161B, info), /* GT2 ULT */ \ + INTEL_VGA_DEVICE(0x161E, info) /* GT2 ULX */ #define INTEL_BDW_GT12D_IDS(info) \ - _INTEL_BDW_D_IDS(1, info), \ - _INTEL_BDW_D_IDS(2, info) + INTEL_VGA_DEVICE(0x160A, info), /* GT1 Server */ \ + INTEL_VGA_DEVICE(0x160D, info), /* GT1 Workstation */ \ + INTEL_VGA_DEVICE(0x161A, info), /* GT2 Server */ \ + INTEL_VGA_DEVICE(0x161D, info) /* GT2 Workstation */ #define INTEL_BDW_GT3M_IDS(info) \ - _INTEL_BDW_M_IDS(3, info) + INTEL_VGA_DEVICE(0x1622, info), /* ULT */ \ + INTEL_VGA_DEVICE(0x1626, info), /* ULT */ \ + INTEL_VGA_DEVICE(0x162B, info), /* Iris */ \ + INTEL_VGA_DEVICE(0x162E, info) /* ULX */ #define INTEL_BDW_GT3D_IDS(info) \ - _INTEL_BDW_D_IDS(3, info) + INTEL_VGA_DEVICE(0x162A, info), /* Server */ \ + INTEL_VGA_DEVICE(0x162D, info) /* Workstation */ #define INTEL_BDW_RSVDM_IDS(info) \ - _INTEL_BDW_M_IDS(4, info) + INTEL_VGA_DEVICE(0x1632, info), /* ULT */ \ + INTEL_VGA_DEVICE(0x1636, info), /* ULT */ \ + INTEL_VGA_DEVICE(0x163B, info), /* Iris */ \ + INTEL_VGA_DEVICE(0x163E, info) /* ULX */ #define INTEL_BDW_RSVDD_IDS(info) \ - _INTEL_BDW_D_IDS(4, info) + INTEL_VGA_DEVICE(0x163A, info), /* Server */ \ + INTEL_VGA_DEVICE(0x163D, info) /* Workstation */ #define INTEL_BDW_M_IDS(info) \ INTEL_BDW_GT12M_IDS(info), \ -- cgit v1.2.3 From a1559ffefb2a80eabbee65d7cc04e828d4fd557d Mon Sep 17 00:00:00 2001 From: Jeff McGee Date: Mon, 9 Mar 2015 16:06:54 -0700 Subject: drm/i915: Export total subslice and EU counts Setup new I915_GETPARAM ioctl entries for subslice total and EU total. Userspace drivers need these values when constructing GPGPU commands. This kernel query method is intended to replace the PCI ID-based tables that userspace drivers currently maintain. The kernel driver can employ fuse register reads as needed to ensure the most accurate determination of GT config attributes. This first became important with Cherryview in which the config could differ between devices with the same PCI ID. The kernel detection of these values is device-specific and not included in this patch. Because zero is not a valid value for any of these parameters, a value of zero is interpreted as unknown for the device. Userspace drivers should continue to maintain ID-based tables for older devices not supported by the new query method. v2: Increment our I915_GETPARAM indices to fit after REVISION which was merged ahead of us. For: VIZ-4636 Signed-off-by: Jeff McGee Tested-by: Zhigang Gong Acked-by: Zhigang Gong Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 10 ++++++++++ include/uapi/drm/i915_drm.h | 2 ++ 2 files changed, 12 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 8e914303b831..d49ed68f041e 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -153,6 +153,16 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_MMAP_VERSION: value = 1; break; + case I915_PARAM_SUBSLICE_TOTAL: + value = INTEL_INFO(dev)->subslice_total; + if (!value) + return -ENODEV; + break; + case I915_PARAM_EU_TOTAL: + value = INTEL_INFO(dev)->eu_total; + if (!value) + return -ENODEV; + break; default: DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index b768f3b21eaa..8d1be9073380 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -348,6 +348,8 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_MMAP_VERSION 30 #define I915_PARAM_HAS_BSD2 31 #define I915_PARAM_REVISION 32 +#define I915_PARAM_SUBSLICE_TOTAL 33 +#define I915_PARAM_EU_TOTAL 34 typedef struct drm_i915_getparam { int param; -- cgit v1.2.3 From a572460be9cfb423c60275943f7921003b8cd372 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 11 Mar 2015 12:30:58 -0300 Subject: dmaengine: imx-sdma: Add support for version 3 firmware Currently when version 3.1 of the mx6q SDMA firmware is used we get: [ 0.392169] imx-sdma 20ec000.sdma: unknown firmware version [ 0.399281] imx-sdma 20ec000.sdma: initialized Add support for it. Based on a patch from Shengjiu Wang from the internal FSL kernel. Signed-off-by: Fabio Estevam Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 4 ++++ include/linux/platform_data/dma-imx-sdma.h | 3 +++ 2 files changed, 7 insertions(+) (limited to 'include') diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 18c0a131e4e4..eb10109c55ad 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1256,6 +1256,7 @@ static void sdma_issue_pending(struct dma_chan *chan) #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34 #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38 +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3 41 static void sdma_add_scripts(struct sdma_engine *sdma, const struct sdma_script_start_addrs *addr) @@ -1302,6 +1303,9 @@ static void sdma_load_firmware(const struct firmware *fw, void *context) case 2: sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2; break; + case 3: + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3; + break; default: dev_err(sdma->dev, "unknown firmware version\n"); goto err_firmware; diff --git a/include/linux/platform_data/dma-imx-sdma.h b/include/linux/platform_data/dma-imx-sdma.h index eabac4e2fc99..2d08816720f6 100644 --- a/include/linux/platform_data/dma-imx-sdma.h +++ b/include/linux/platform_data/dma-imx-sdma.h @@ -48,6 +48,9 @@ struct sdma_script_start_addrs { s32 ssish_2_mcu_addr; s32 hdmi_dma_addr; /* End of v2 array */ + s32 zcanfd_2_mcu_addr; + s32 zqspi_2_mcu_addr; + /* End of v3 array */ }; /** -- cgit v1.2.3 From 964cb341882f920a1a1043864178f22def3193e4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 18 Mar 2015 01:56:17 +0100 Subject: gpio: move pincontrol calls to These functions do not belong in since the split into separate GPIO headers under . Move them to as is apropriate. Acked-by: Alexandre Courbot Signed-off-by: Linus Walleij --- include/asm-generic/gpio.h | 48 --------------------------------------------- include/linux/gpio/driver.h | 48 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 48 deletions(-) (limited to 'include') diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 383ade1a211b..9bb0d11729c9 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -5,7 +5,6 @@ #include #include #include -#include #ifdef CONFIG_GPIOLIB @@ -139,53 +138,6 @@ static inline void gpio_unexport(unsigned gpio) gpiod_unexport(gpio_to_desc(gpio)); } -#ifdef CONFIG_PINCTRL - -/** - * struct gpio_pin_range - pin range controlled by a gpio chip - * @head: list for maintaining set of pin ranges, used internally - * @pctldev: pinctrl device which handles corresponding pins - * @range: actual range of pins controlled by a gpio controller - */ - -struct gpio_pin_range { - struct list_head node; - struct pinctrl_dev *pctldev; - struct pinctrl_gpio_range range; -}; - -int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int gpio_offset, unsigned int pin_offset, - unsigned int npins); -int gpiochip_add_pingroup_range(struct gpio_chip *chip, - struct pinctrl_dev *pctldev, - unsigned int gpio_offset, const char *pin_group); -void gpiochip_remove_pin_ranges(struct gpio_chip *chip); - -#else - -static inline int -gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int gpio_offset, unsigned int pin_offset, - unsigned int npins) -{ - return 0; -} -static inline int -gpiochip_add_pingroup_range(struct gpio_chip *chip, - struct pinctrl_dev *pctldev, - unsigned int gpio_offset, const char *pin_group) -{ - return 0; -} - -static inline void -gpiochip_remove_pin_ranges(struct gpio_chip *chip) -{ -} - -#endif /* CONFIG_PINCTRL */ - #else /* !CONFIG_GPIOLIB */ static inline bool gpio_is_valid(int number) diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index c497c62889d1..f1b36593ec9f 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -6,6 +6,7 @@ #include #include #include +#include struct device; struct gpio_desc; @@ -173,6 +174,53 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, #endif /* CONFIG_GPIOLIB_IRQCHIP */ +#ifdef CONFIG_PINCTRL + +/** + * struct gpio_pin_range - pin range controlled by a gpio chip + * @head: list for maintaining set of pin ranges, used internally + * @pctldev: pinctrl device which handles corresponding pins + * @range: actual range of pins controlled by a gpio controller + */ + +struct gpio_pin_range { + struct list_head node; + struct pinctrl_dev *pctldev; + struct pinctrl_gpio_range range; +}; + +int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int gpio_offset, unsigned int pin_offset, + unsigned int npins); +int gpiochip_add_pingroup_range(struct gpio_chip *chip, + struct pinctrl_dev *pctldev, + unsigned int gpio_offset, const char *pin_group); +void gpiochip_remove_pin_ranges(struct gpio_chip *chip); + +#else + +static inline int +gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int gpio_offset, unsigned int pin_offset, + unsigned int npins) +{ + return 0; +} +static inline int +gpiochip_add_pingroup_range(struct gpio_chip *chip, + struct pinctrl_dev *pctldev, + unsigned int gpio_offset, const char *pin_group) +{ + return 0; +} + +static inline void +gpiochip_remove_pin_ranges(struct gpio_chip *chip) +{ +} + +#endif /* CONFIG_PINCTRL */ + struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum, const char *label); void gpiochip_free_own_desc(struct gpio_desc *desc); -- cgit v1.2.3 From d6d2a1882a79c1a5425d6f82b2fc7b934916f893 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 30 Sep 2014 10:04:40 -0400 Subject: drm/radeon: add INFO query for GPU temperature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Useful for profiling. Tested-by: Marek Olšák Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_kms.c | 7 +++++++ include/uapi/drm/radeon_drm.h | 1 + 2 files changed, 8 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 686411e4e4f6..7904887c6cc7 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -547,6 +547,13 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file else *value = 1; break; + case RADEON_INFO_CURRENT_GPU_TEMP: + /* get temperature in millidegrees C */ + if (rdev->asic->pm.get_temperature) + *value = radeon_get_temperature(rdev); + else + *value = 0; + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->request); return -EINVAL; diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h index 50d0fb41a3bf..66b1131bb296 100644 --- a/include/uapi/drm/radeon_drm.h +++ b/include/uapi/drm/radeon_drm.h @@ -1034,6 +1034,7 @@ struct drm_radeon_cs { #define RADEON_INFO_VRAM_USAGE 0x1e #define RADEON_INFO_GTT_USAGE 0x1f #define RADEON_INFO_ACTIVE_CU_COUNT 0x20 +#define RADEON_INFO_CURRENT_GPU_TEMP 0x21 struct drm_radeon_info { uint32_t request; -- cgit v1.2.3 From 5c363a860398e2a09e5cff7f4654cf82ed8485e1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 30 Sep 2014 11:33:30 -0400 Subject: drm/radeon: add INFO query for current sclk/mclk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow the UMDs to query the current sclk/mclk for profiling, etc. Tested-by: Marek Olšák Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_kms.c | 14 ++++++++++++++ include/uapi/drm/radeon_drm.h | 2 ++ 2 files changed, 16 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 7904887c6cc7..cf7e54e9b0d1 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -554,6 +554,20 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file else *value = 0; break; + case RADEON_INFO_CURRENT_GPU_SCLK: + /* get sclk in Mhz */ + if (rdev->pm.dpm_enabled) + *value = radeon_dpm_get_current_sclk(rdev) / 100; + else + *value = rdev->pm.current_sclk / 100; + break; + case RADEON_INFO_CURRENT_GPU_MCLK: + /* get mclk in Mhz */ + if (rdev->pm.dpm_enabled) + *value = radeon_dpm_get_current_mclk(rdev) / 100; + else + *value = rdev->pm.current_mclk / 100; + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->request); return -EINVAL; diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h index 66b1131bb296..de7ee21efea2 100644 --- a/include/uapi/drm/radeon_drm.h +++ b/include/uapi/drm/radeon_drm.h @@ -1035,6 +1035,8 @@ struct drm_radeon_cs { #define RADEON_INFO_GTT_USAGE 0x1f #define RADEON_INFO_ACTIVE_CU_COUNT 0x20 #define RADEON_INFO_CURRENT_GPU_TEMP 0x21 +#define RADEON_INFO_CURRENT_GPU_SCLK 0x22 +#define RADEON_INFO_CURRENT_GPU_MCLK 0x23 struct drm_radeon_info { uint32_t request; -- cgit v1.2.3 From 4535cb9cefbc736b47bc1e7f8628065aba5ca0d7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 1 Oct 2014 11:26:50 -0400 Subject: drm/radeon: add support for read reg query from radeon info ioctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows us to query certain registers from userspace for profiling and harvest configuration. E.g., it can be used by the GALLIUM_HUD for profiling the status of various gfx blocks. Tested-by: Marek Olšák Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_kms.c | 8 ++++++++ include/uapi/drm/radeon_drm.h | 1 + 2 files changed, 9 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index cf7e54e9b0d1..7b2a7335cc5d 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -568,6 +568,14 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file else *value = rdev->pm.current_mclk / 100; break; + case RADEON_INFO_READ_REG: + if (copy_from_user(value, value_ptr, sizeof(uint32_t))) { + DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__); + return -EFAULT; + } + if (radeon_get_allowed_info_register(rdev, *value, value)) + return -EINVAL; + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->request); return -EINVAL; diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h index de7ee21efea2..871e73f99a4d 100644 --- a/include/uapi/drm/radeon_drm.h +++ b/include/uapi/drm/radeon_drm.h @@ -1037,6 +1037,7 @@ struct drm_radeon_cs { #define RADEON_INFO_CURRENT_GPU_TEMP 0x21 #define RADEON_INFO_CURRENT_GPU_SCLK 0x22 #define RADEON_INFO_CURRENT_GPU_MCLK 0x23 +#define RADEON_INFO_READ_REG 0x24 struct drm_radeon_info { uint32_t request; -- cgit v1.2.3 From 87f5942d1f7bc320a0ec70ac4a8a3396024c7091 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 24 Feb 2015 09:23:55 +1000 Subject: drm/dp_mst: add a function to retrieve vcpi slots radeon requires this to get the slots for later filling out a table on every transition. Signed-off-by: Dave Airlie Signed-off-by: Alex Deucher --- drivers/gpu/drm/drm_dp_mst_topology.c | 13 +++++++++++++ include/drm/drm_dp_mst_helper.h | 2 ++ 2 files changed, 15 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 9a5b68717ec8..0d15e6e30732 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2319,6 +2319,19 @@ out: } EXPORT_SYMBOL(drm_dp_mst_allocate_vcpi); +int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) +{ + int slots = 0; + port = drm_dp_get_validated_port_ref(mgr, port); + if (!port) + return slots; + + slots = port->vcpi.num_slots; + drm_dp_put_port(port); + return slots; +} +EXPORT_SYMBOL(drm_dp_mst_get_vcpi_slots); + /** * drm_dp_mst_reset_vcpi_slots() - Reset number of slots to 0 for VCPI * @mgr: manager for this port diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 00c1da927245..a2507817be41 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -486,6 +486,8 @@ int drm_dp_calc_pbn_mode(int clock, int bpp); bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn, int *slots); +int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); + void drm_dp_mst_reset_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); -- cgit v1.2.3 From 7eec52db361a6ae6fbbd86c2299718586866b664 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 19 Mar 2015 01:50:22 +0200 Subject: Documentation: DT: Add bindings for omap3isp Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Signed-off-by: Tony Lindgren --- .../devicetree/bindings/media/ti,omap3isp.txt | 71 ++++++++++++++++++++++ MAINTAINERS | 1 + include/dt-bindings/media/omap3-isp.h | 22 +++++++ 3 files changed, 94 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/ti,omap3isp.txt create mode 100644 include/dt-bindings/media/omap3-isp.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/media/ti,omap3isp.txt b/Documentation/devicetree/bindings/media/ti,omap3isp.txt new file mode 100644 index 000000000000..ac23de855641 --- /dev/null +++ b/Documentation/devicetree/bindings/media/ti,omap3isp.txt @@ -0,0 +1,71 @@ +OMAP 3 ISP Device Tree bindings +=============================== + +The DT definitions can be found in include/dt-bindings/media/omap3-isp.h. + +Required properties +=================== + +compatible : must contain "ti,omap3-isp" + +reg : the two registers sets (physical address and length) for the + ISP. The first set contains the core ISP registers up to + the end of the SBL block. The second set contains the + CSI PHYs and receivers registers. +interrupts : the ISP interrupt specifier +iommus : phandle and IOMMU specifier for the IOMMU that serves the ISP +syscon : the phandle and register offset to the Complex I/O or CSI-PHY + register +ti,phy-type : 0 -- OMAP3ISP_PHY_TYPE_COMPLEX_IO (e.g. 3430) + 1 -- OMAP3ISP_PHY_TYPE_CSIPHY (e.g. 3630) +#clock-cells : Must be 1 --- the ISP provides two external clocks, + cam_xclka and cam_xclkb, at indices 0 and 1, + respectively. Please find more information on common + clock bindings in ../clock/clock-bindings.txt. + +Port nodes (optional) +--------------------- + +More documentation on these bindings is available in +video-interfaces.txt in the same directory. + +reg : The interface: + 0 - parallel (CCDC) + 1 - CSIPHY1 -- CSI2C / CCP2B on 3630; + CSI1 -- CSIb on 3430 + 2 - CSIPHY2 -- CSI2A / CCP2B on 3630; + CSI2 -- CSIa on 3430 + +Optional properties +=================== + +vdd-csiphy1-supply : voltage supply of the CSI-2 PHY 1 +vdd-csiphy2-supply : voltage supply of the CSI-2 PHY 2 + +Endpoint nodes +-------------- + +lane-polarities : lane polarity (required on CSI-2) + 0 -- not inverted; 1 -- inverted +data-lanes : an array of data lanes from 1 to 3. The length can + be either 1 or 2. (required on CSI-2) +clock-lanes : the clock lane (from 1 to 3). (required on CSI-2) + + +Example +======= + + isp@480bc000 { + compatible = "ti,omap3-isp"; + reg = <0x480bc000 0x12fc + 0x480bd800 0x0600>; + interrupts = <24>; + iommus = <&mmu_isp>; + syscon = <&scm_conf 0x2f0>; + ti,phy-type = ; + #clock-cells = <1>; + ports { + #address-cells = <1>; + #size-cells = <0>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index eaf999638a65..6a271a6ff903 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7077,6 +7077,7 @@ OMAP IMAGING SUBSYSTEM (OMAP3 ISP and OMAP4 ISS) M: Laurent Pinchart L: linux-media@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/media/ti,omap3isp.txt F: drivers/media/platform/omap3isp/ F: drivers/staging/media/omap4iss/ diff --git a/include/dt-bindings/media/omap3-isp.h b/include/dt-bindings/media/omap3-isp.h new file mode 100644 index 000000000000..b18c60e468c7 --- /dev/null +++ b/include/dt-bindings/media/omap3-isp.h @@ -0,0 +1,22 @@ +/* + * include/dt-bindings/media/omap3-isp.h + * + * Copyright (C) 2015 Sakari Ailus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef __DT_BINDINGS_OMAP3_ISP_H__ +#define __DT_BINDINGS_OMAP3_ISP_H__ + +#define OMAP3ISP_PHY_TYPE_COMPLEX_IO 0 +#define OMAP3ISP_PHY_TYPE_CSIPHY 1 + +#endif /* __DT_BINDINGS_OMAP3_ISP_H__ */ -- cgit v1.2.3 From 6f921fab5844941f7605b7f1a265f5fc7fe969a7 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 18 Mar 2015 18:38:25 +0200 Subject: wlcore: set irq_trigger in board files instead of hiding behind a quirk The platform_quirk element in the platform data was used to change the way the IRQ is triggered. When set, the EDGE_IRQ quirk would change the irqflags used and treat edge trigger differently from the rest. Instead of hiding this irq flag setting behind the quirk, have the board files set the irq_trigger explicitly. This will allow us to use standard irq DT definitions later on. Signed-off-by: Luciano Coelho [Eliad - rebase, add irq_trigger field and pass it, update board file changes] Signed-off-by: Eliad Peller Tested-by: Nikita Kiryanov Acked-by: Kalle Valo Acked-by: Sekhar Nori Signed-off-by: Tony Lindgren --- arch/arm/mach-davinci/board-da850-evm.c | 2 +- arch/arm/mach-omap2/pdata-quirks.c | 1 + drivers/net/wireless/ti/wlcore/debugfs.c | 2 +- drivers/net/wireless/ti/wlcore/main.c | 27 ++++++++++++++++----------- drivers/net/wireless/ti/wlcore/sdio.c | 2 +- drivers/net/wireless/ti/wlcore/wlcore.h | 5 ++--- include/linux/wl12xx.h | 5 +---- 7 files changed, 23 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 6b5a97da9fe3..916589ca8d44 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -1385,8 +1385,8 @@ static const short da850_wl12xx_pins[] __initconst = { static struct wl12xx_platform_data da850_wl12xx_wlan_data __initdata = { .irq = -1, + .irq_trigger = IRQ_TYPE_EDGE_RISING, .board_ref_clock = WL12XX_REFCLOCK_38, - .platform_quirks = WL12XX_PLATFORM_QUIRK_EDGE_IRQ, }; static __init int da850_wl12xx_init(void) diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index e642b079e9f3..e86fb0d55c59 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -48,6 +48,7 @@ static void __init __used legacy_init_wl12xx(unsigned ref_clock, wl12xx.board_ref_clock = ref_clock; wl12xx.board_tcxo_clock = tcxo_clock; wl12xx.irq = gpio_to_irq(gpio); + wl12xx.irq_trigger = IRQ_TYPE_LEVEL_HIGH; res = wl12xx_set_platform_data(&wl12xx); if (res) { diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index 68f3bf229b5a..eb43f94a1597 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c @@ -502,7 +502,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_HEX(irq); /* TODO: ref_clock and tcxo_clock were moved to wl12xx priv */ DRIVER_STATE_PRINT_HEX(hw_pg_ver); - DRIVER_STATE_PRINT_HEX(platform_quirks); + DRIVER_STATE_PRINT_HEX(irq_flags); DRIVER_STATE_PRINT_HEX(chip.id); DRIVER_STATE_PRINT_STR(chip.fw_ver_str); DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 1e136993580f..67518f692cfc 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "wlcore.h" #include "debug.h" @@ -538,7 +539,7 @@ static int wlcore_irq_locked(struct wl1271 *wl) * In case edge triggered interrupt must be used, we cannot iterate * more than once without introducing race conditions with the hardirq. */ - if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) + if (wl->irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) loopcount = 1; wl1271_debug(DEBUG_IRQ, "IRQ work"); @@ -6249,7 +6250,6 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size, wl->ap_ps_map = 0; wl->ap_fw_ps_map = 0; wl->quirks = 0; - wl->platform_quirks = 0; wl->system_hlid = WL12XX_SYSTEM_HLID; wl->active_sta_count = 0; wl->active_link_count = 0; @@ -6391,7 +6391,8 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) struct platform_device *pdev = wl->pdev; struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); struct wl12xx_platform_data *pdata = pdev_data->pdata; - unsigned long irqflags; + struct resource *res; + int ret; irq_handler_t hardirq_fn = NULL; @@ -6418,19 +6419,23 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) /* adjust some runtime configuration parameters */ wlcore_adjust_conf(wl); - wl->irq = platform_get_irq(pdev, 0); - wl->platform_quirks = pdata->platform_quirks; + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + wl1271_error("Could not get IRQ resource"); + goto out_free_nvs; + } + + wl->irq = res->start; + wl->irq_flags = res->flags & IRQF_TRIGGER_MASK; wl->if_ops = pdev_data->if_ops; - if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) { - irqflags = IRQF_TRIGGER_RISING; + if (wl->irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) hardirq_fn = wlcore_hardirq; - } else { - irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; - } + else + wl->irq_flags |= IRQF_ONESHOT; ret = request_threaded_irq(wl->irq, hardirq_fn, wlcore_irq, - irqflags, pdev->name, wl); + wl->irq_flags, pdev->name, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); goto out_free_nvs; diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index d3dd7bfdf3f1..2bce00afea1f 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -287,7 +287,7 @@ static int wl1271_probe(struct sdio_func *func, memset(res, 0x00, sizeof(res)); res[0].start = pdev_data.pdata->irq; - res[0].flags = IORESOURCE_IRQ; + res[0].flags = IORESOURCE_IRQ | pdev_data.pdata->irq_trigger; res[0].name = "irq"; ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res)); diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index d599c869e6e8..7f363fa566a3 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -197,6 +197,8 @@ struct wl1271 { int irq; + int irq_flags; + spinlock_t wl_lock; enum wlcore_state state; @@ -404,9 +406,6 @@ struct wl1271 { /* Quirks of specific hardware revisions */ unsigned int quirks; - /* Platform limitations */ - unsigned int platform_quirks; - /* number of currently active RX BA sessions */ int ba_rx_session_count; diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h index a9c723be1acf..3876b67dbcbc 100644 --- a/include/linux/wl12xx.h +++ b/include/linux/wl12xx.h @@ -57,15 +57,12 @@ struct wl1251_platform_data { struct wl12xx_platform_data { int irq; + u32 irq_trigger; int board_ref_clock; int board_tcxo_clock; - unsigned long platform_quirks; bool pwr_in_suspend; }; -/* Platform does not support level trigger interrupts */ -#define WL12XX_PLATFORM_QUIRK_EDGE_IRQ BIT(0) - #ifdef CONFIG_WILINK_PLATFORM_DATA int wl12xx_set_platform_data(const struct wl12xx_platform_data *data); -- cgit v1.2.3 From f7234138f14c2296c5eb6b8224abe00b507faf3f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 4 Mar 2015 01:47:54 -0800 Subject: [media] v4l2-subdev: replace v4l2_subdev_fh by v4l2_subdev_pad_config If a subdevice pad op is called from a bridge driver, then there is no v4l2_subdev_fh struct that can be passed to the subdevice. This made it hard to use such subdevs from a bridge driver. This patch replaces the v4l2_subdev_fh pointer by a v4l2_subdev_pad_config pointer in the pad ops. This allows bridge drivers to use the various try_ pad ops by creating a v4l2_subdev_pad_config struct and passing it along to the pad op. The v4l2_subdev_get_try_* macros had to be changed because of this, so I also took the opportunity to use the full name of the v4l2_subdev_get_try_* functions in the __V4L2_SUBDEV_MK_GET_TRY macro arguments: if you now do 'git grep v4l2_subdev_get_try_format' you will actually find the header where it is defined. One remark regarding the drivers/staging/media/davinci_vpfe patches: the *_init_formats() functions assumed that fh could be NULL. However, that's not true for this driver, it's always set. This is almost certainly a copy and paste from the omap3isp driver. I've updated the code to reflect the fact that fh is never NULL. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Acked-by: Laurent Pinchart Acked-by: Sakari Ailus Acked-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 10 +-- drivers/media/i2c/adv7511.c | 16 +++-- drivers/media/i2c/adv7604.c | 12 ++-- drivers/media/i2c/m5mols/m5mols_core.c | 16 ++--- drivers/media/i2c/mt9m032.c | 34 ++++----- drivers/media/i2c/mt9p031.c | 36 +++++----- drivers/media/i2c/mt9t001.c | 36 +++++----- drivers/media/i2c/mt9v032.c | 36 +++++----- drivers/media/i2c/noon010pc30.c | 17 ++--- drivers/media/i2c/ov9650.c | 16 ++--- drivers/media/i2c/s5c73m3/s5c73m3-core.c | 51 +++++++------- drivers/media/i2c/s5k4ecgx.c | 16 ++--- drivers/media/i2c/s5k5baf.c | 38 +++++----- drivers/media/i2c/s5k6a3.c | 18 ++--- drivers/media/i2c/s5k6aa.c | 34 ++++----- drivers/media/i2c/smiapp/smiapp-core.c | 80 ++++++++++----------- drivers/media/i2c/tvp514x.c | 12 ++-- drivers/media/i2c/tvp7002.c | 14 ++-- drivers/media/platform/exynos4-is/fimc-capture.c | 22 +++--- drivers/media/platform/exynos4-is/fimc-isp.c | 28 ++++---- drivers/media/platform/exynos4-is/fimc-lite.c | 33 ++++----- drivers/media/platform/exynos4-is/mipi-csis.c | 16 ++--- drivers/media/platform/omap3isp/ispccdc.c | 82 +++++++++++----------- drivers/media/platform/omap3isp/ispccp2.c | 44 ++++++------ drivers/media/platform/omap3isp/ispcsi2.c | 40 +++++------ drivers/media/platform/omap3isp/isppreview.c | 70 +++++++++--------- drivers/media/platform/omap3isp/ispresizer.c | 78 ++++++++++---------- drivers/media/platform/s3c-camif/camif-capture.c | 18 ++--- drivers/media/platform/vsp1/vsp1_bru.c | 40 +++++------ drivers/media/platform/vsp1/vsp1_entity.c | 16 ++--- drivers/media/platform/vsp1/vsp1_entity.h | 4 +- drivers/media/platform/vsp1/vsp1_hsit.c | 16 ++--- drivers/media/platform/vsp1/vsp1_lif.c | 18 ++--- drivers/media/platform/vsp1/vsp1_lut.c | 18 ++--- drivers/media/platform/vsp1/vsp1_rwpf.c | 36 +++++----- drivers/media/platform/vsp1/vsp1_rwpf.h | 12 ++-- drivers/media/platform/vsp1/vsp1_sru.c | 26 +++---- drivers/media/platform/vsp1/vsp1_uds.c | 26 +++---- drivers/media/v4l2-core/v4l2-subdev.c | 18 ++--- drivers/staging/media/davinci_vpfe/dm365_ipipe.c | 49 +++++++------ drivers/staging/media/davinci_vpfe/dm365_ipipeif.c | 47 ++++++------- drivers/staging/media/davinci_vpfe/dm365_isif.c | 79 ++++++++++----------- drivers/staging/media/davinci_vpfe/dm365_resizer.c | 57 ++++++++------- drivers/staging/media/omap4iss/iss_csi2.c | 40 +++++------ drivers/staging/media/omap4iss/iss_ipipe.c | 42 +++++------ drivers/staging/media/omap4iss/iss_ipipeif.c | 48 ++++++------- drivers/staging/media/omap4iss/iss_resizer.c | 42 +++++------ include/media/v4l2-subdev.h | 53 ++++++++------ 48 files changed, 813 insertions(+), 797 deletions(-) (limited to 'include') diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index b75878c27c2a..a493c0b0b5fe 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -582,7 +582,7 @@ static void adv7180_exit_controls(struct adv7180_state *state) } static int adv7180_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index != 0) @@ -645,13 +645,13 @@ static int adv7180_set_field_mode(struct adv7180_state *state) } static int adv7180_get_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct adv7180_state *state = to_state(sd); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - format->format = *v4l2_subdev_get_try_format(fh, 0); + format->format = *v4l2_subdev_get_try_format(sd, cfg, 0); } else { adv7180_mbus_fmt(sd, &format->format); format->format.field = state->field; @@ -661,7 +661,7 @@ static int adv7180_get_pad_format(struct v4l2_subdev *sd, } static int adv7180_set_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct adv7180_state *state = to_state(sd); @@ -686,7 +686,7 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd, adv7180_set_power(state, true); } } else { - framefmt = v4l2_subdev_get_try_format(fh, 0); + framefmt = v4l2_subdev_get_try_format(sd, cfg, 0); *framefmt = format->format; } diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index 81736aaf0f31..03ea62f9c074 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c @@ -810,7 +810,7 @@ static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) } static int adv7511_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->pad != 0) @@ -842,8 +842,9 @@ static void adv7511_fill_format(struct adv7511_state *state, format->field = V4L2_FIELD_NONE; } -static int adv7511_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *format) +static int adv7511_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct adv7511_state *state = get_adv7511_state(sd); @@ -855,7 +856,7 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(fh, format->pad); + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); format->format.code = fmt->code; format->format.colorspace = fmt->colorspace; format->format.ycbcr_enc = fmt->ycbcr_enc; @@ -870,8 +871,9 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } -static int adv7511_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *format) +static int adv7511_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct adv7511_state *state = get_adv7511_state(sd); /* @@ -905,7 +907,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(fh, format->pad); + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); fmt->code = format->format.code; fmt->colorspace = format->format.colorspace; fmt->ycbcr_enc = format->format.ycbcr_enc; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index aaab9c9cebee..1e58537c3ea3 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1734,7 +1734,7 @@ static int adv76xx_s_routing(struct v4l2_subdev *sd, } static int adv76xx_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct adv76xx_state *state = to_state(sd); @@ -1811,7 +1811,8 @@ static void adv76xx_setup_format(struct adv76xx_state *state) state->format->swap_cb_cr ? ADV76XX_OP_SWAP_CB_CR : 0); } -static int adv76xx_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int adv76xx_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct adv76xx_state *state = to_state(sd); @@ -1824,7 +1825,7 @@ static int adv76xx_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(fh, format->pad); + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); format->format.code = fmt->code; } else { format->format.code = state->format->code; @@ -1833,7 +1834,8 @@ static int adv76xx_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } -static int adv76xx_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int adv76xx_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct adv76xx_state *state = to_state(sd); @@ -1852,7 +1854,7 @@ static int adv76xx_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(fh, format->pad); + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); fmt->code = format->format.code; } else { state->format = info; diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c index 6ed16e569bbf..6404c0d93e7a 100644 --- a/drivers/media/i2c/m5mols/m5mols_core.c +++ b/drivers/media/i2c/m5mols/m5mols_core.c @@ -531,17 +531,17 @@ static int __find_resolution(struct v4l2_subdev *sd, } static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which, enum m5mols_restype type) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; + return cfg ? v4l2_subdev_get_try_format(&info->sd, cfg, 0) : NULL; return &info->ffmt[type]; } -static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct m5mols_info *info = to_m5mols(sd); @@ -550,7 +550,7 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, mutex_lock(&info->lock); - format = __find_format(info, fh, fmt->which, info->res_type); + format = __find_format(info, cfg, fmt->which, info->res_type); if (format) fmt->format = *format; else @@ -560,7 +560,7 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return ret; } -static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct m5mols_info *info = to_m5mols(sd); @@ -574,7 +574,7 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (ret < 0) return ret; - sfmt = __find_format(info, fh, fmt->which, type); + sfmt = __find_format(info, cfg, fmt->which, type); if (!sfmt) return 0; @@ -640,7 +640,7 @@ static int m5mols_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad, static int m5mols_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (!code || code->index >= SIZE_DEFAULT_FFMT) @@ -895,7 +895,7 @@ static const struct v4l2_subdev_core_ops m5mols_core_ops = { */ static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0); *format = m5mols_default_ffmt[0]; return 0; diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c index 76431223f0ff..c7747bd0cabb 100644 --- a/drivers/media/i2c/mt9m032.c +++ b/drivers/media/i2c/mt9m032.c @@ -317,7 +317,7 @@ static int mt9m032_setup_pll(struct mt9m032 *sensor) */ static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index != 0) @@ -328,7 +328,7 @@ static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev, } static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { if (fse->index != 0 || fse->code != MEDIA_BUS_FMT_Y8_1X8) @@ -345,18 +345,18 @@ static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev, /** * __mt9m032_get_pad_crop() - get crop rect * @sensor: pointer to the sensor struct - * @fh: file handle for getting the try crop rect from + * @cfg: v4l2_subdev_pad_config for getting the try crop rect from * @which: select try or active crop rect * * Returns a pointer the current active or fh relative try crop rect */ static struct v4l2_rect * -__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, +__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(fh, 0); + return v4l2_subdev_get_try_crop(&sensor->subdev, cfg, 0); case V4L2_SUBDEV_FORMAT_ACTIVE: return &sensor->crop; default: @@ -367,18 +367,18 @@ __mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, /** * __mt9m032_get_pad_format() - get format * @sensor: pointer to the sensor struct - * @fh: file handle for getting the try format from + * @cfg: v4l2_subdev_pad_config for getting the try format from * @which: select try or active format * * Returns a pointer the current active or fh relative try format */ static struct v4l2_mbus_framefmt * -__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, +__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(fh, 0); + return v4l2_subdev_get_try_format(&sensor->subdev, cfg, 0); case V4L2_SUBDEV_FORMAT_ACTIVE: return &sensor->format; default: @@ -387,20 +387,20 @@ __mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, } static int mt9m032_get_pad_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct mt9m032 *sensor = to_mt9m032(subdev); mutex_lock(&sensor->lock); - fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which); + fmt->format = *__mt9m032_get_pad_format(sensor, cfg, fmt->which); mutex_unlock(&sensor->lock); return 0; } static int mt9m032_set_pad_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct mt9m032 *sensor = to_mt9m032(subdev); @@ -414,7 +414,7 @@ static int mt9m032_set_pad_format(struct v4l2_subdev *subdev, } /* Scaling is not supported, the format is thus fixed. */ - fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which); + fmt->format = *__mt9m032_get_pad_format(sensor, cfg, fmt->which); ret = 0; done: @@ -423,7 +423,7 @@ done: } static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9m032 *sensor = to_mt9m032(subdev); @@ -432,14 +432,14 @@ static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev, return -EINVAL; mutex_lock(&sensor->lock); - sel->r = *__mt9m032_get_pad_crop(sensor, fh, sel->which); + sel->r = *__mt9m032_get_pad_crop(sensor, cfg, sel->which); mutex_unlock(&sensor->lock); return 0; } static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9m032 *sensor = to_mt9m032(subdev); @@ -475,13 +475,13 @@ static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9m032_get_pad_crop(sensor, fh, sel->which); + __crop = __mt9m032_get_pad_crop(sensor, cfg, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - format = __mt9m032_get_pad_format(sensor, fh, sel->which); + format = __mt9m032_get_pad_format(sensor, cfg, sel->which); format->width = rect.width; format->height = rect.height; } diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index e3acae9a2ec3..c56a58b47c78 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -474,7 +474,7 @@ static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable) } static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); @@ -487,7 +487,7 @@ static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev, } static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); @@ -505,12 +505,12 @@ static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev, } static struct v4l2_mbus_framefmt * -__mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh, +__mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config *cfg, unsigned int pad, u32 which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&mt9p031->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9p031->format; default: @@ -519,12 +519,12 @@ __mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh, } static struct v4l2_rect * -__mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh, +__mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config *cfg, unsigned int pad, u32 which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(fh, pad); + return v4l2_subdev_get_try_crop(&mt9p031->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9p031->crop; default: @@ -533,18 +533,18 @@ __mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh, } static int mt9p031_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); - fmt->format = *__mt9p031_get_pad_format(mt9p031, fh, fmt->pad, + fmt->format = *__mt9p031_get_pad_format(mt9p031, cfg, fmt->pad, fmt->which); return 0; } static int mt9p031_set_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); @@ -555,7 +555,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev, unsigned int hratio; unsigned int vratio; - __crop = __mt9p031_get_pad_crop(mt9p031, fh, format->pad, + __crop = __mt9p031_get_pad_crop(mt9p031, cfg, format->pad, format->which); /* Clamp the width and height to avoid dividing by zero. */ @@ -571,7 +571,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev, hratio = DIV_ROUND_CLOSEST(__crop->width, width); vratio = DIV_ROUND_CLOSEST(__crop->height, height); - __format = __mt9p031_get_pad_format(mt9p031, fh, format->pad, + __format = __mt9p031_get_pad_format(mt9p031, cfg, format->pad, format->which); __format->width = __crop->width / hratio; __format->height = __crop->height / vratio; @@ -582,7 +582,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev, } static int mt9p031_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); @@ -590,12 +590,12 @@ static int mt9p031_get_selection(struct v4l2_subdev *subdev, if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - sel->r = *__mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which); + sel->r = *__mt9p031_get_pad_crop(mt9p031, cfg, sel->pad, sel->which); return 0; } static int mt9p031_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); @@ -625,13 +625,13 @@ static int mt9p031_set_selection(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9P031_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which); + __crop = __mt9p031_get_pad_crop(mt9p031, cfg, sel->pad, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - __format = __mt9p031_get_pad_format(mt9p031, fh, sel->pad, + __format = __mt9p031_get_pad_format(mt9p031, cfg, sel->pad, sel->which); __format->width = rect.width; __format->height = rect.height; @@ -946,13 +946,13 @@ static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - crop = v4l2_subdev_get_try_crop(fh, 0); + crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0); crop->left = MT9P031_COLUMN_START_DEF; crop->top = MT9P031_ROW_START_DEF; crop->width = MT9P031_WINDOW_WIDTH_DEF; crop->height = MT9P031_WINDOW_HEIGHT_DEF; - format = v4l2_subdev_get_try_format(fh, 0); + format = v4l2_subdev_get_try_format(subdev, fh->pad, 0); if (mt9p031->model == MT9P031_MODEL_MONOCHROME) format->code = MEDIA_BUS_FMT_Y12_1X12; diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c index f6ca636b538d..8ae99f7f254c 100644 --- a/drivers/media/i2c/mt9t001.c +++ b/drivers/media/i2c/mt9t001.c @@ -244,12 +244,12 @@ static int __mt9t001_set_power(struct mt9t001 *mt9t001, bool on) */ static struct v4l2_mbus_framefmt * -__mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh, +__mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&mt9t001->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9t001->format; default: @@ -258,12 +258,12 @@ __mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh, } static struct v4l2_rect * -__mt9t001_get_pad_crop(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh, +__mt9t001_get_pad_crop(struct mt9t001 *mt9t001, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(fh, pad); + return v4l2_subdev_get_try_crop(&mt9t001->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9t001->crop; default: @@ -327,7 +327,7 @@ static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable) } static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index > 0) @@ -338,7 +338,7 @@ static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev, } static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) @@ -353,18 +353,18 @@ static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev, } static int mt9t001_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct mt9t001 *mt9t001 = to_mt9t001(subdev); - format->format = *__mt9t001_get_pad_format(mt9t001, fh, format->pad, + format->format = *__mt9t001_get_pad_format(mt9t001, cfg, format->pad, format->which); return 0; } static int mt9t001_set_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct mt9t001 *mt9t001 = to_mt9t001(subdev); @@ -375,7 +375,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev, unsigned int hratio; unsigned int vratio; - __crop = __mt9t001_get_pad_crop(mt9t001, fh, format->pad, + __crop = __mt9t001_get_pad_crop(mt9t001, cfg, format->pad, format->which); /* Clamp the width and height to avoid dividing by zero. */ @@ -391,7 +391,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev, hratio = DIV_ROUND_CLOSEST(__crop->width, width); vratio = DIV_ROUND_CLOSEST(__crop->height, height); - __format = __mt9t001_get_pad_format(mt9t001, fh, format->pad, + __format = __mt9t001_get_pad_format(mt9t001, cfg, format->pad, format->which); __format->width = __crop->width / hratio; __format->height = __crop->height / vratio; @@ -402,7 +402,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev, } static int mt9t001_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9t001 *mt9t001 = to_mt9t001(subdev); @@ -410,12 +410,12 @@ static int mt9t001_get_selection(struct v4l2_subdev *subdev, if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - sel->r = *__mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which); + sel->r = *__mt9t001_get_pad_crop(mt9t001, cfg, sel->pad, sel->which); return 0; } static int mt9t001_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9t001 *mt9t001 = to_mt9t001(subdev); @@ -447,13 +447,13 @@ static int mt9t001_set_selection(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9T001_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which); + __crop = __mt9t001_get_pad_crop(mt9t001, cfg, sel->pad, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - __format = __mt9t001_get_pad_format(mt9t001, fh, sel->pad, + __format = __mt9t001_get_pad_format(mt9t001, cfg, sel->pad, sel->which); __format->width = rect.width; __format->height = rect.height; @@ -790,13 +790,13 @@ static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - crop = v4l2_subdev_get_try_crop(fh, 0); + crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0); crop->left = MT9T001_COLUMN_START_DEF; crop->top = MT9T001_ROW_START_DEF; crop->width = MT9T001_WINDOW_WIDTH_DEF + 1; crop->height = MT9T001_WINDOW_HEIGHT_DEF + 1; - format = v4l2_subdev_get_try_format(fh, 0); + format = v4l2_subdev_get_try_format(subdev, fh->pad, 0); format->code = MEDIA_BUS_FMT_SGRBG10_1X10; format->width = MT9T001_WINDOW_WIDTH_DEF + 1; format->height = MT9T001_WINDOW_HEIGHT_DEF + 1; diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 3267c183104b..3793d317772b 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -371,12 +371,12 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on) */ static struct v4l2_mbus_framefmt * -__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh, +__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&mt9v032->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9v032->format; default: @@ -385,12 +385,12 @@ __mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh, } static struct v4l2_rect * -__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh, +__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(fh, pad); + return v4l2_subdev_get_try_crop(&mt9v032->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9v032->crop; default: @@ -448,7 +448,7 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable) } static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index > 0) @@ -459,7 +459,7 @@ static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev, } static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { if (fse->index >= 3 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) @@ -474,12 +474,12 @@ static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev, } static int mt9v032_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct mt9v032 *mt9v032 = to_mt9v032(subdev); - format->format = *__mt9v032_get_pad_format(mt9v032, fh, format->pad, + format->format = *__mt9v032_get_pad_format(mt9v032, cfg, format->pad, format->which); return 0; } @@ -509,7 +509,7 @@ static unsigned int mt9v032_calc_ratio(unsigned int input, unsigned int output) } static int mt9v032_set_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct mt9v032 *mt9v032 = to_mt9v032(subdev); @@ -520,7 +520,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev, unsigned int hratio; unsigned int vratio; - __crop = __mt9v032_get_pad_crop(mt9v032, fh, format->pad, + __crop = __mt9v032_get_pad_crop(mt9v032, cfg, format->pad, format->which); /* Clamp the width and height to avoid dividing by zero. */ @@ -536,7 +536,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev, hratio = mt9v032_calc_ratio(__crop->width, width); vratio = mt9v032_calc_ratio(__crop->height, height); - __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad, + __format = __mt9v032_get_pad_format(mt9v032, cfg, format->pad, format->which); __format->width = __crop->width / hratio; __format->height = __crop->height / vratio; @@ -553,7 +553,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev, } static int mt9v032_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9v032 *mt9v032 = to_mt9v032(subdev); @@ -561,12 +561,12 @@ static int mt9v032_get_selection(struct v4l2_subdev *subdev, if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - sel->r = *__mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which); + sel->r = *__mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which); return 0; } static int mt9v032_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9v032 *mt9v032 = to_mt9v032(subdev); @@ -598,13 +598,13 @@ static int mt9v032_set_selection(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which); + __crop = __mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - __format = __mt9v032_get_pad_format(mt9v032, fh, sel->pad, + __format = __mt9v032_get_pad_format(mt9v032, cfg, sel->pad, sel->which); __format->width = rect.width; __format->height = rect.height; @@ -810,13 +810,13 @@ static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - crop = v4l2_subdev_get_try_crop(fh, 0); + crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0); crop->left = MT9V032_COLUMN_START_DEF; crop->top = MT9V032_ROW_START_DEF; crop->width = MT9V032_WINDOW_WIDTH_DEF; crop->height = MT9V032_WINDOW_HEIGHT_DEF; - format = v4l2_subdev_get_try_format(fh, 0); + format = v4l2_subdev_get_try_format(subdev, fh->pad, 0); if (mt9v032->model->color) format->code = MEDIA_BUS_FMT_SGRBG10_1X10; diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c index 00c7b26f4823..f197b6cbd407 100644 --- a/drivers/media/i2c/noon010pc30.c +++ b/drivers/media/i2c/noon010pc30.c @@ -492,7 +492,7 @@ unlock: } static int noon010_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(noon010_formats)) @@ -502,15 +502,16 @@ static int noon010_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int noon010_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int noon010_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct noon010_info *info = to_noon010(sd); struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - if (fh) { - mf = v4l2_subdev_get_try_format(fh, 0); + if (cfg) { + mf = v4l2_subdev_get_try_format(sd, cfg, 0); fmt->format = *mf; } return 0; @@ -542,7 +543,7 @@ static const struct noon010_format *noon010_try_fmt(struct v4l2_subdev *sd, return &noon010_formats[i]; } -static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct noon010_info *info = to_noon010(sd); @@ -557,8 +558,8 @@ static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, fmt->format.field = V4L2_FIELD_NONE; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - if (fh) { - mf = v4l2_subdev_get_try_format(fh, 0); + if (cfg) { + mf = v4l2_subdev_get_try_format(sd, cfg, 0); *mf = fmt->format; } return 0; @@ -640,7 +641,7 @@ static int noon010_log_status(struct v4l2_subdev *sd) static int noon010_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0); mf->width = noon010_sizes[0].width; mf->height = noon010_sizes[0].height; diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 2246bd5436ad..2bc473385c91 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -1067,7 +1067,7 @@ static void ov965x_get_default_format(struct v4l2_mbus_framefmt *mf) } static int ov965x_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(ov965x_formats)) @@ -1078,7 +1078,7 @@ static int ov965x_enum_mbus_code(struct v4l2_subdev *sd, } static int ov965x_enum_frame_sizes(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { int i = ARRAY_SIZE(ov965x_formats); @@ -1164,14 +1164,14 @@ static int ov965x_s_frame_interval(struct v4l2_subdev *sd, return ret; } -static int ov965x_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ov965x_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct ov965x *ov965x = to_ov965x(sd); struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, 0); + mf = v4l2_subdev_get_try_format(sd, cfg, 0); fmt->format = *mf; return 0; } @@ -1208,7 +1208,7 @@ static void __ov965x_try_frame_size(struct v4l2_mbus_framefmt *mf, *size = match; } -static int ov965x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ov965x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { unsigned int index = ARRAY_SIZE(ov965x_formats); @@ -1230,8 +1230,8 @@ static int ov965x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, mutex_lock(&ov965x->lock); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - if (fh != NULL) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + if (cfg != NULL) { + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; } } else { @@ -1361,7 +1361,7 @@ static int ov965x_s_stream(struct v4l2_subdev *sd, int on) */ static int ov965x_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0); ov965x_get_default_format(mf); return 0; diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index ee0f57e01b56..257a335c0ece 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -824,10 +824,11 @@ static const struct s5c73m3_frame_size *s5c73m3_find_frame_size( } static void s5c73m3_oif_try_format(struct s5c73m3 *state, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt, const struct s5c73m3_frame_size **fs) { + struct v4l2_subdev *sd = &state->sensor_sd; u32 code; switch (fmt->pad) { @@ -850,7 +851,7 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state, *fs = state->oif_pix_size[RES_ISP]; else *fs = s5c73m3_find_frame_size( - v4l2_subdev_get_try_format(fh, + v4l2_subdev_get_try_format(sd, cfg, OIF_ISP_PAD), RES_ISP); break; @@ -860,7 +861,7 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state, } static void s5c73m3_try_format(struct s5c73m3 *state, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt, const struct s5c73m3_frame_size **fs) { @@ -952,7 +953,7 @@ static int s5c73m3_oif_s_frame_interval(struct v4l2_subdev *sd, } static int s5c73m3_oif_enum_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_interval_enum *fie) { struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); @@ -990,7 +991,7 @@ static int s5c73m3_oif_get_pad_code(int pad, int index) } static int s5c73m3_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); @@ -998,7 +999,7 @@ static int s5c73m3_get_fmt(struct v4l2_subdev *sd, u32 code; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad); + fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); return 0; } @@ -1024,7 +1025,7 @@ static int s5c73m3_get_fmt(struct v4l2_subdev *sd, } static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); @@ -1032,7 +1033,7 @@ static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd, u32 code; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad); + fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); return 0; } @@ -1062,7 +1063,7 @@ static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd, } static int s5c73m3_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { const struct s5c73m3_frame_size *frame_size = NULL; @@ -1072,10 +1073,10 @@ static int s5c73m3_set_fmt(struct v4l2_subdev *sd, mutex_lock(&state->lock); - s5c73m3_try_format(state, fh, fmt, &frame_size); + s5c73m3_try_format(state, cfg, fmt, &frame_size); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; } else { switch (fmt->pad) { @@ -1101,7 +1102,7 @@ static int s5c73m3_set_fmt(struct v4l2_subdev *sd, } static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { const struct s5c73m3_frame_size *frame_size = NULL; @@ -1111,13 +1112,13 @@ static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd, mutex_lock(&state->lock); - s5c73m3_oif_try_format(state, fh, fmt, &frame_size); + s5c73m3_oif_try_format(state, cfg, fmt, &frame_size); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; if (fmt->pad == OIF_ISP_PAD) { - mf = v4l2_subdev_get_try_format(fh, OIF_SOURCE_PAD); + mf = v4l2_subdev_get_try_format(sd, cfg, OIF_SOURCE_PAD); mf->width = fmt->format.width; mf->height = fmt->format.height; } @@ -1189,7 +1190,7 @@ static int s5c73m3_oif_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad, } static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const int codes[] = { @@ -1205,7 +1206,7 @@ static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd, } static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { int ret; @@ -1220,7 +1221,7 @@ static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd, } static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { int idx; @@ -1247,7 +1248,7 @@ static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd, } static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { int idx; @@ -1260,7 +1261,7 @@ static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd, case S5C73M3_JPEG_FMT: case S5C73M3_ISP_FMT: { struct v4l2_mbus_framefmt *mf = - v4l2_subdev_get_try_format(fh, OIF_ISP_PAD); + v4l2_subdev_get_try_format(sd, cfg, OIF_ISP_PAD); fse->max_width = fse->min_width = mf->width; fse->max_height = fse->min_height = mf->height; @@ -1306,11 +1307,11 @@ static int s5c73m3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(fh, S5C73M3_ISP_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, S5C73M3_ISP_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], S5C73M3_ISP_FMT); - mf = v4l2_subdev_get_try_format(fh, S5C73M3_JPEG_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, S5C73M3_JPEG_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1], S5C73M3_JPEG_FMT); @@ -1321,15 +1322,15 @@ static int s5c73m3_oif_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(fh, OIF_ISP_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_ISP_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], S5C73M3_ISP_FMT); - mf = v4l2_subdev_get_try_format(fh, OIF_JPEG_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_JPEG_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1], S5C73M3_JPEG_FMT); - mf = v4l2_subdev_get_try_format(fh, OIF_SOURCE_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_SOURCE_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], S5C73M3_ISP_FMT); return 0; diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c index 70071314789e..97084237275d 100644 --- a/drivers/media/i2c/s5k4ecgx.c +++ b/drivers/media/i2c/s5k4ecgx.c @@ -531,7 +531,7 @@ static int s5k4ecgx_try_frame_size(struct v4l2_mbus_framefmt *mf, } static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(s5k4ecgx_formats)) @@ -541,15 +541,15 @@ static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5k4ecgx *priv = to_s5k4ecgx(sd); struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - if (fh) { - mf = v4l2_subdev_get_try_format(fh, 0); + if (cfg) { + mf = v4l2_subdev_get_try_format(sd, cfg, 0); fmt->format = *mf; } return 0; @@ -581,7 +581,7 @@ static const struct s5k4ecgx_pixfmt *s5k4ecgx_try_fmt(struct v4l2_subdev *sd, return &s5k4ecgx_formats[i]; } -static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5k4ecgx *priv = to_s5k4ecgx(sd); @@ -596,8 +596,8 @@ static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, fmt->format.field = V4L2_FIELD_NONE; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - if (fh) { - mf = v4l2_subdev_get_try_format(fh, 0); + if (cfg) { + mf = v4l2_subdev_get_try_format(sd, cfg, 0); *mf = fmt->format; } return 0; @@ -692,7 +692,7 @@ static int s5k4ecgx_registered(struct v4l2_subdev *sd) */ static int s5k4ecgx_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0); mf->width = s5k4ecgx_prev_sizes[0].size.width; mf->height = s5k4ecgx_prev_sizes[0].size.height; diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index a3d7d0391302..96e7a4834130 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -1182,7 +1182,7 @@ static int s5k5baf_s_frame_interval(struct v4l2_subdev *sd, * V4L2 subdev pad level and video operations */ static int s5k5baf_enum_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_interval_enum *fie) { if (fie->index > S5K5BAF_MAX_FR_TIME - S5K5BAF_MIN_FR_TIME || @@ -1201,7 +1201,7 @@ static int s5k5baf_enum_frame_interval(struct v4l2_subdev *sd, } static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->pad == PAD_CIS) { @@ -1219,7 +1219,7 @@ static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd, } static int s5k5baf_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { int i; @@ -1276,7 +1276,7 @@ static int s5k5baf_try_isp_format(struct v4l2_mbus_framefmt *mf) return pixfmt; } -static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5k5baf *state = to_s5k5baf(sd); @@ -1284,7 +1284,7 @@ static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); fmt->format = *mf; return 0; } @@ -1306,7 +1306,7 @@ static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } -static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *mf = &fmt->format; @@ -1317,7 +1317,7 @@ static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, mf->field = V4L2_FIELD_NONE; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(fh, fmt->pad) = *mf; + *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = *mf; return 0; } @@ -1369,7 +1369,7 @@ static int s5k5baf_is_bound_target(u32 target) } static int s5k5baf_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { static enum selection_rect rtype; @@ -1389,9 +1389,9 @@ static int s5k5baf_get_selection(struct v4l2_subdev *sd, if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { if (rtype == R_COMPOSE) - sel->r = *v4l2_subdev_get_try_compose(fh, sel->pad); + sel->r = *v4l2_subdev_get_try_compose(sd, cfg, sel->pad); else - sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad); + sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad); return 0; } @@ -1460,7 +1460,7 @@ static bool s5k5baf_cmp_rect(const struct v4l2_rect *r1, } static int s5k5baf_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { static enum selection_rect rtype; @@ -1481,9 +1481,9 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd, if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { rects = (struct v4l2_rect * []) { &s5k5baf_cis_rect, - v4l2_subdev_get_try_crop(fh, PAD_CIS), - v4l2_subdev_get_try_compose(fh, PAD_CIS), - v4l2_subdev_get_try_crop(fh, PAD_OUT) + v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS), + v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS), + v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT) }; s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r); return 0; @@ -1701,22 +1701,22 @@ static int s5k5baf_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(fh, PAD_CIS); + mf = v4l2_subdev_get_try_format(sd, fh->pad, PAD_CIS); s5k5baf_try_cis_format(mf); if (s5k5baf_is_cis_subdev(sd)) return 0; - mf = v4l2_subdev_get_try_format(fh, PAD_OUT); + mf = v4l2_subdev_get_try_format(sd, fh->pad, PAD_OUT); mf->colorspace = s5k5baf_formats[0].colorspace; mf->code = s5k5baf_formats[0].code; mf->width = s5k5baf_cis_rect.width; mf->height = s5k5baf_cis_rect.height; mf->field = V4L2_FIELD_NONE; - *v4l2_subdev_get_try_crop(fh, PAD_CIS) = s5k5baf_cis_rect; - *v4l2_subdev_get_try_compose(fh, PAD_CIS) = s5k5baf_cis_rect; - *v4l2_subdev_get_try_crop(fh, PAD_OUT) = s5k5baf_cis_rect; + *v4l2_subdev_get_try_crop(sd, fh->pad, PAD_CIS) = s5k5baf_cis_rect; + *v4l2_subdev_get_try_compose(sd, fh->pad, PAD_CIS) = s5k5baf_cis_rect; + *v4l2_subdev_get_try_crop(sd, fh->pad, PAD_OUT) = s5k5baf_cis_rect; return 0; } diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index 91b841a1b850..bc389d5e42ae 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c @@ -99,7 +99,7 @@ static const struct v4l2_mbus_framefmt *find_sensor_format( } static int s5k6a3_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(s5k6a3_formats)) @@ -123,17 +123,17 @@ static void s5k6a3_try_format(struct v4l2_mbus_framefmt *mf) } static struct v4l2_mbus_framefmt *__s5k6a3_get_format( - struct s5k6a3 *sensor, struct v4l2_subdev_fh *fh, + struct s5k6a3 *sensor, struct v4l2_subdev_pad_config *cfg, u32 pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL; + return cfg ? v4l2_subdev_get_try_format(&sensor->subdev, cfg, pad) : NULL; return &sensor->format; } static int s5k6a3_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5k6a3 *sensor = sd_to_s5k6a3(sd); @@ -141,7 +141,7 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd, s5k6a3_try_format(&fmt->format); - mf = __s5k6a3_get_format(sensor, fh, fmt->pad, fmt->which); + mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which); if (mf) { mutex_lock(&sensor->lock); if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) @@ -152,13 +152,13 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd, } static int s5k6a3_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) { struct s5k6a3 *sensor = sd_to_s5k6a3(sd); struct v4l2_mbus_framefmt *mf; - mf = __s5k6a3_get_format(sensor, fh, fmt->pad, fmt->which); + mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which); mutex_lock(&sensor->lock); fmt->format = *mf; @@ -174,7 +174,7 @@ static struct v4l2_subdev_pad_ops s5k6a3_pad_ops = { static int s5k6a3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0); *format = s5k6a3_formats[0]; format->width = S5K6A3_DEFAULT_WIDTH; diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c index b1c583239dab..de803a11efb4 100644 --- a/drivers/media/i2c/s5k6aa.c +++ b/drivers/media/i2c/s5k6aa.c @@ -996,7 +996,7 @@ static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd, * V4L2 subdev pad level and video operations */ static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_interval_enum *fie) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); @@ -1023,7 +1023,7 @@ static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd, } static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(s5k6aa_formats)) @@ -1034,7 +1034,7 @@ static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd, } static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { int i = ARRAY_SIZE(s5k6aa_formats); @@ -1056,14 +1056,14 @@ static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd, } static struct v4l2_rect * -__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_fh *fh, +__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_ACTIVE) return &s5k6aa->ccd_rect; WARN_ON(which != V4L2_SUBDEV_FORMAT_TRY); - return v4l2_subdev_get_try_crop(fh, 0); + return v4l2_subdev_get_try_crop(&s5k6aa->sd, cfg, 0); } static void s5k6aa_try_format(struct s5k6aa *s5k6aa, @@ -1087,7 +1087,7 @@ static void s5k6aa_try_format(struct s5k6aa *s5k6aa, mf->field = V4L2_FIELD_NONE; } -static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); @@ -1096,7 +1096,7 @@ static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, memset(fmt->reserved, 0, sizeof(fmt->reserved)); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, 0); + mf = v4l2_subdev_get_try_format(sd, cfg, 0); fmt->format = *mf; return 0; } @@ -1108,7 +1108,7 @@ static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } -static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); @@ -1121,8 +1121,8 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, s5k6aa_try_format(s5k6aa, &fmt->format); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); - crop = v4l2_subdev_get_try_crop(fh, 0); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); + crop = v4l2_subdev_get_try_crop(sd, cfg, 0); } else { if (s5k6aa->streaming) { ret = -EBUSY; @@ -1162,7 +1162,7 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, } static int s5k6aa_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); @@ -1174,7 +1174,7 @@ static int s5k6aa_get_selection(struct v4l2_subdev *sd, memset(sel->reserved, 0, sizeof(sel->reserved)); mutex_lock(&s5k6aa->lock); - rect = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which); + rect = __s5k6aa_get_crop_rect(s5k6aa, cfg, sel->which); sel->r = *rect; mutex_unlock(&s5k6aa->lock); @@ -1185,7 +1185,7 @@ static int s5k6aa_get_selection(struct v4l2_subdev *sd, } static int s5k6aa_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); @@ -1197,13 +1197,13 @@ static int s5k6aa_set_selection(struct v4l2_subdev *sd, return -EINVAL; mutex_lock(&s5k6aa->lock); - crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which); + crop_r = __s5k6aa_get_crop_rect(s5k6aa, cfg, sel->which); if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { mf = &s5k6aa->preset->mbus_fmt; s5k6aa->apply_crop = 1; } else { - mf = v4l2_subdev_get_try_format(fh, 0); + mf = v4l2_subdev_get_try_format(sd, cfg, 0); } v4l_bound_align_image(&sel->r.width, mf->width, S5K6AA_WIN_WIDTH_MAX, 1, @@ -1424,8 +1424,8 @@ static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa) */ static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); - struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0); + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0); + struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0); format->colorspace = s5k6aa_formats[0].colorspace; format->code = s5k6aa_formats[0].code; diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index d47eff5d3101..c73deb0432d7 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -1557,7 +1557,7 @@ static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable) } static int smiapp_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct i2c_client *client = v4l2_get_subdevdata(subdev); @@ -1611,13 +1611,13 @@ static u32 __smiapp_get_mbus_code(struct v4l2_subdev *subdev, } static int __smiapp_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad); + fmt->format = *v4l2_subdev_get_try_format(subdev, cfg, fmt->pad); } else { struct v4l2_rect *r; @@ -1636,21 +1636,21 @@ static int __smiapp_get_format(struct v4l2_subdev *subdev, } static int smiapp_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); int rval; mutex_lock(&sensor->mutex); - rval = __smiapp_get_format(subdev, fh, fmt); + rval = __smiapp_get_format(subdev, cfg, fmt); mutex_unlock(&sensor->mutex); return rval; } static void smiapp_get_crop_compose(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_rect **crops, struct v4l2_rect **comps, int which) { @@ -1666,12 +1666,12 @@ static void smiapp_get_crop_compose(struct v4l2_subdev *subdev, } else { if (crops) { for (i = 0; i < subdev->entity.num_pads; i++) { - crops[i] = v4l2_subdev_get_try_crop(fh, i); + crops[i] = v4l2_subdev_get_try_crop(subdev, cfg, i); BUG_ON(!crops[i]); } } if (comps) { - *comps = v4l2_subdev_get_try_compose(fh, + *comps = v4l2_subdev_get_try_compose(subdev, cfg, SMIAPP_PAD_SINK); BUG_ON(!*comps); } @@ -1680,14 +1680,14 @@ static void smiapp_get_crop_compose(struct v4l2_subdev *subdev, /* Changes require propagation only on sink pad. */ static void smiapp_propagate(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, int which, + struct v4l2_subdev_pad_config *cfg, int which, int target) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); struct v4l2_rect *comp, *crops[SMIAPP_PADS]; - smiapp_get_crop_compose(subdev, fh, crops, &comp, which); + smiapp_get_crop_compose(subdev, cfg, crops, &comp, which); switch (target) { case V4L2_SEL_TGT_CROP: @@ -1730,7 +1730,7 @@ static const struct smiapp_csi_data_format } static int smiapp_set_format_source(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); @@ -1741,7 +1741,7 @@ static int smiapp_set_format_source(struct v4l2_subdev *subdev, unsigned int i; int rval; - rval = __smiapp_get_format(subdev, fh, fmt); + rval = __smiapp_get_format(subdev, cfg, fmt); if (rval) return rval; @@ -1783,7 +1783,7 @@ static int smiapp_set_format_source(struct v4l2_subdev *subdev, } static int smiapp_set_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); @@ -1795,7 +1795,7 @@ static int smiapp_set_format(struct v4l2_subdev *subdev, if (fmt->pad == ssd->source_pad) { int rval; - rval = smiapp_set_format_source(subdev, fh, fmt); + rval = smiapp_set_format_source(subdev, cfg, fmt); mutex_unlock(&sensor->mutex); @@ -1817,7 +1817,7 @@ static int smiapp_set_format(struct v4l2_subdev *subdev, sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE], sensor->limits[SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE]); - smiapp_get_crop_compose(subdev, fh, crops, NULL, fmt->which); + smiapp_get_crop_compose(subdev, cfg, crops, NULL, fmt->which); crops[ssd->sink_pad]->left = 0; crops[ssd->sink_pad]->top = 0; @@ -1825,7 +1825,7 @@ static int smiapp_set_format(struct v4l2_subdev *subdev, crops[ssd->sink_pad]->height = fmt->format.height; if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) ssd->sink_fmt = *crops[ssd->sink_pad]; - smiapp_propagate(subdev, fh, fmt->which, + smiapp_propagate(subdev, cfg, fmt->which, V4L2_SEL_TGT_CROP); mutex_unlock(&sensor->mutex); @@ -1878,7 +1878,7 @@ static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w, } static void smiapp_set_compose_binner(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel, struct v4l2_rect **crops, struct v4l2_rect *comp) @@ -1926,7 +1926,7 @@ static void smiapp_set_compose_binner(struct v4l2_subdev *subdev, * result. */ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel, struct v4l2_rect **crops, struct v4l2_rect *comp) @@ -2042,25 +2042,25 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, } /* We're only called on source pads. This function sets scaling. */ static int smiapp_set_compose(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); struct v4l2_rect *comp, *crops[SMIAPP_PADS]; - smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which); + smiapp_get_crop_compose(subdev, cfg, crops, &comp, sel->which); sel->r.top = 0; sel->r.left = 0; if (ssd == sensor->binner) - smiapp_set_compose_binner(subdev, fh, sel, crops, comp); + smiapp_set_compose_binner(subdev, cfg, sel, crops, comp); else - smiapp_set_compose_scaler(subdev, fh, sel, crops, comp); + smiapp_set_compose_scaler(subdev, cfg, sel, crops, comp); *comp = sel->r; - smiapp_propagate(subdev, fh, sel->which, + smiapp_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_COMPOSE); if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) @@ -2113,7 +2113,7 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev, } static int smiapp_set_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); @@ -2121,7 +2121,7 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev, struct v4l2_rect *src_size, *crops[SMIAPP_PADS]; struct v4l2_rect _r; - smiapp_get_crop_compose(subdev, fh, crops, NULL, sel->which); + smiapp_get_crop_compose(subdev, cfg, crops, NULL, sel->which); if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { if (sel->pad == ssd->sink_pad) @@ -2132,15 +2132,15 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev, if (sel->pad == ssd->sink_pad) { _r.left = 0; _r.top = 0; - _r.width = v4l2_subdev_get_try_format(fh, sel->pad) + _r.width = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) ->width; - _r.height = v4l2_subdev_get_try_format(fh, sel->pad) + _r.height = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) ->height; src_size = &_r; } else { src_size = v4l2_subdev_get_try_compose( - fh, ssd->sink_pad); + subdev, cfg, ssd->sink_pad); } } @@ -2158,14 +2158,14 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev, *crops[sel->pad] = sel->r; if (ssd != sensor->pixel_array && sel->pad == SMIAPP_PAD_SINK) - smiapp_propagate(subdev, fh, sel->which, + smiapp_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_CROP); return 0; } static int __smiapp_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); @@ -2178,13 +2178,13 @@ static int __smiapp_get_selection(struct v4l2_subdev *subdev, if (ret) return ret; - smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which); + smiapp_get_crop_compose(subdev, cfg, crops, &comp, sel->which); if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { sink_fmt = ssd->sink_fmt; } else { struct v4l2_mbus_framefmt *fmt = - v4l2_subdev_get_try_format(fh, ssd->sink_pad); + v4l2_subdev_get_try_format(subdev, cfg, ssd->sink_pad); sink_fmt.left = 0; sink_fmt.top = 0; @@ -2220,20 +2220,20 @@ static int __smiapp_get_selection(struct v4l2_subdev *subdev, } static int smiapp_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); int rval; mutex_lock(&sensor->mutex); - rval = __smiapp_get_selection(subdev, fh, sel); + rval = __smiapp_get_selection(subdev, cfg, sel); mutex_unlock(&sensor->mutex); return rval; } static int smiapp_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); @@ -2259,10 +2259,10 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev, switch (sel->target) { case V4L2_SEL_TGT_CROP: - ret = smiapp_set_crop(subdev, fh, sel); + ret = smiapp_set_crop(subdev, cfg, sel); break; case V4L2_SEL_TGT_COMPOSE: - ret = smiapp_set_compose(subdev, fh, sel); + ret = smiapp_set_compose(subdev, cfg, sel); break; default: ret = -EINVAL; @@ -2841,8 +2841,8 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) for (i = 0; i < ssd->npads; i++) { struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(fh, i); - struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(fh, i); + v4l2_subdev_get_try_format(sd, fh->pad, i); + struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, i); struct v4l2_rect *try_comp; try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1; @@ -2858,7 +2858,7 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) if (ssd != sensor->pixel_array) continue; - try_comp = v4l2_subdev_get_try_compose(fh, i); + try_comp = v4l2_subdev_get_try_compose(sd, fh->pad, i); *try_comp = *try_crop; } diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index c6b3dc541cc2..1c6bc306ecdc 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -923,13 +923,13 @@ static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = { /** * tvp514x_enum_mbus_code() - V4L2 decoder interface handler for enum_mbus_code * @sd: pointer to standard V4L2 sub-device structure - * @fh: file handle + * @cfg: pad configuration * @code: pointer to v4l2_subdev_mbus_code_enum structure * * Enumertaes mbus codes supported */ static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { u32 pad = code->pad; @@ -950,13 +950,13 @@ static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd, /** * tvp514x_get_pad_format() - V4L2 decoder interface handler for get pad format * @sd: pointer to standard V4L2 sub-device structure - * @fh: file handle + * @cfg: pad configuration * @format: pointer to v4l2_subdev_format structure * * Retrieves pad format which is active or tried based on requirement */ static int tvp514x_get_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct tvp514x_decoder *decoder = to_decoder(sd); @@ -979,13 +979,13 @@ static int tvp514x_get_pad_format(struct v4l2_subdev *sd, /** * tvp514x_set_pad_format() - V4L2 decoder interface handler for set pad format * @sd: pointer to standard V4L2 sub-device structure - * @fh: file handle + * @cfg: pad configuration * @format: pointer to v4l2_subdev_format structure * * Set pad format for the output pad */ static int tvp514x_set_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct tvp514x_decoder *decoder = to_decoder(sd); diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 9233194233eb..787cdfb08749 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -846,13 +846,13 @@ static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = { /* * tvp7002_enum_mbus_code() - Enum supported digital video format on pad * @sd: pointer to standard V4L2 sub-device structure - * @fh: file handle for the subdev + * @cfg: pad configuration * @code: pointer to subdev enum mbus code struct * * Enumerate supported digital video formats for pad. */ static int -tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { /* Check requested format index is within range */ @@ -867,13 +867,13 @@ tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * tvp7002_get_pad_format() - get video format on pad * @sd: pointer to standard V4L2 sub-device structure - * @fh: file handle for the subdev + * @cfg: pad configuration * @fmt: pointer to subdev format struct * * get video format for pad. */ static int -tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct tvp7002 *tvp7002 = to_tvp7002(sd); @@ -890,16 +890,16 @@ tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * tvp7002_set_pad_format() - set video format on pad * @sd: pointer to standard V4L2 sub-device structure - * @fh: file handle for the subdev + * @cfg: pad configuration * @fmt: pointer to subdev format struct * * set video format for pad. */ static int -tvp7002_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +tvp7002_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { - return tvp7002_get_pad_format(sd, fh, fmt); + return tvp7002_get_pad_format(sd, cfg, fmt); } /* V4L2 core operation handlers */ diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 8a2fd8c33d42..cfebf292e15a 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -1482,7 +1482,7 @@ void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification, } static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct fimc_fmt *fmt; @@ -1495,7 +1495,7 @@ static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd, } static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); @@ -1504,7 +1504,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); fmt->format = *mf; return 0; } @@ -1536,7 +1536,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, } static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); @@ -1559,7 +1559,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_JPEG; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; return 0; } @@ -1602,7 +1602,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, } static int fimc_subdev_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); @@ -1628,10 +1628,10 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd, return 0; case V4L2_SEL_TGT_CROP: - try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); + try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad); break; case V4L2_SEL_TGT_COMPOSE: - try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); + try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad); f = &ctx->d_frame; break; default: @@ -1657,7 +1657,7 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd, } static int fimc_subdev_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); @@ -1675,10 +1675,10 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP: - try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); + try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad); break; case V4L2_SEL_TGT_COMPOSE: - try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); + try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad); f = &ctx->d_frame; break; default: diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index 60c744915549..5d78f5716f3b 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -112,7 +112,7 @@ static const struct media_entity_operations fimc_is_subdev_media_ops = { }; static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { const struct fimc_fmt *fmt; @@ -125,14 +125,14 @@ static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd, } static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_isp *isp = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf = &fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *mf = *v4l2_subdev_get_try_format(fh, fmt->pad); + *mf = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); return 0; } @@ -162,7 +162,7 @@ static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd, } static void __isp_subdev_try_format(struct fimc_isp *isp, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *mf = &fmt->format; @@ -178,7 +178,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp, mf->code = MEDIA_BUS_FMT_SGRBG10_1X10; } else { if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - format = v4l2_subdev_get_try_format(fh, + format = v4l2_subdev_get_try_format(&isp->subdev, cfg, FIMC_ISP_SD_PAD_SINK); else format = &isp->sink_fmt; @@ -197,7 +197,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp, } static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_isp *isp = v4l2_get_subdevdata(sd); @@ -209,10 +209,10 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, __func__, fmt->pad, mf->code, mf->width, mf->height); mutex_lock(&isp->subdev_lock); - __isp_subdev_try_format(isp, fh, fmt); + __isp_subdev_try_format(isp, cfg, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; /* Propagate format to the source pads */ @@ -223,8 +223,8 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, for (pad = FIMC_ISP_SD_PAD_SRC_FIFO; pad < FIMC_ISP_SD_PADS_NUM; pad++) { format.pad = pad; - __isp_subdev_try_format(isp, fh, &format); - mf = v4l2_subdev_get_try_format(fh, pad); + __isp_subdev_try_format(isp, cfg, &format); + mf = v4l2_subdev_get_try_format(sd, cfg, pad); *mf = format.format; } } @@ -236,7 +236,7 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, isp->sink_fmt = *mf; format.pad = FIMC_ISP_SD_PAD_SRC_DMA; - __isp_subdev_try_format(isp, fh, &format); + __isp_subdev_try_format(isp, cfg, &format); isp->src_fmt = format.format; __is_set_frame_size(is, &isp->src_fmt); @@ -369,7 +369,7 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt fmt; struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SINK); + format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SINK); fmt.colorspace = V4L2_COLORSPACE_SRGB; fmt.code = fimc_isp_formats[0].mbus_code; @@ -378,12 +378,12 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd, fmt.field = V4L2_FIELD_NONE; *format = fmt; - format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SRC_FIFO); + format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SRC_FIFO); fmt.width = DEFAULT_PREVIEW_STILL_WIDTH; fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT; *format = fmt; - format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SRC_DMA); + format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SRC_DMA); *format = fmt; return 0; diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 2510f189e242..ca6261a86a5f 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -568,7 +568,7 @@ static const struct v4l2_file_operations fimc_lite_fops = { */ static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct flite_drvdata *dd = fimc->dd; @@ -592,13 +592,13 @@ static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc, struct v4l2_rect *rect; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sink_fmt = v4l2_subdev_get_try_format(fh, + sink_fmt = v4l2_subdev_get_try_format(&fimc->subdev, cfg, FLITE_SD_PAD_SINK); mf->code = sink_fmt->code; mf->colorspace = sink_fmt->colorspace; - rect = v4l2_subdev_get_try_crop(fh, + rect = v4l2_subdev_get_try_crop(&fimc->subdev, cfg, FLITE_SD_PAD_SINK); } else { mf->code = sink->fmt->mbus_code; @@ -1047,7 +1047,7 @@ static const struct media_entity_operations fimc_lite_subdev_media_ops = { }; static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { const struct fimc_fmt *fmt; @@ -1060,16 +1060,17 @@ static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd, } static struct v4l2_mbus_framefmt *__fimc_lite_subdev_get_try_fmt( - struct v4l2_subdev_fh *fh, unsigned int pad) + struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, unsigned int pad) { if (pad != FLITE_SD_PAD_SINK) pad = FLITE_SD_PAD_SOURCE_DMA; - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(sd, cfg, pad); } static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_lite *fimc = v4l2_get_subdevdata(sd); @@ -1077,7 +1078,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, struct flite_frame *f = &fimc->inp_frame; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = __fimc_lite_subdev_get_try_fmt(fh, fmt->pad); + mf = __fimc_lite_subdev_get_try_fmt(sd, cfg, fmt->pad); fmt->format = *mf; return 0; } @@ -1100,7 +1101,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, } static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_lite *fimc = v4l2_get_subdevdata(sd); @@ -1122,17 +1123,17 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, return -EBUSY; } - ffmt = fimc_lite_subdev_try_fmt(fimc, fh, fmt); + ffmt = fimc_lite_subdev_try_fmt(fimc, cfg, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *src_fmt; - mf = __fimc_lite_subdev_get_try_fmt(fh, fmt->pad); + mf = __fimc_lite_subdev_get_try_fmt(sd, cfg, fmt->pad); *mf = fmt->format; if (fmt->pad == FLITE_SD_PAD_SINK) { unsigned int pad = FLITE_SD_PAD_SOURCE_DMA; - src_fmt = __fimc_lite_subdev_get_try_fmt(fh, pad); + src_fmt = __fimc_lite_subdev_get_try_fmt(sd, cfg, pad); *src_fmt = *mf; } @@ -1160,7 +1161,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, } static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct fimc_lite *fimc = v4l2_get_subdevdata(sd); @@ -1172,7 +1173,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, return -EINVAL; if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad); + sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad); return 0; } @@ -1195,7 +1196,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, } static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct fimc_lite *fimc = v4l2_get_subdevdata(sd); @@ -1209,7 +1210,7 @@ static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd, fimc_lite_try_crop(fimc, &sel->r); if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r; + *v4l2_subdev_get_try_crop(sd, cfg, sel->pad) = sel->r; } else { unsigned long flags; spin_lock_irqsave(&fimc->slock, flags); diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 2504aa89a6f4..d74e1bec3d86 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -540,7 +540,7 @@ unlock: } static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(s5pcsis_formats)) @@ -568,23 +568,23 @@ static struct csis_pix_format const *s5pcsis_try_format( } static struct v4l2_mbus_framefmt *__s5pcsis_get_format( - struct csis_state *state, struct v4l2_subdev_fh *fh, + struct csis_state *state, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; + return cfg ? v4l2_subdev_get_try_format(&state->sd, cfg, 0) : NULL; return &state->format; } -static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct csis_state *state = sd_to_csis_state(sd); struct csis_pix_format const *csis_fmt; struct v4l2_mbus_framefmt *mf; - mf = __s5pcsis_get_format(state, fh, fmt->which); + mf = __s5pcsis_get_format(state, cfg, fmt->which); if (fmt->pad == CSIS_PAD_SOURCE) { if (mf) { @@ -605,13 +605,13 @@ static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } -static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct csis_state *state = sd_to_csis_state(sd); struct v4l2_mbus_framefmt *mf; - mf = __s5pcsis_get_format(state, fh, fmt->which); + mf = __s5pcsis_get_format(state, cfg, fmt->which); if (!mf) return -EINVAL; @@ -651,7 +651,7 @@ static int s5pcsis_log_status(struct v4l2_subdev *sd) static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0); format->colorspace = V4L2_COLORSPACE_JPEG; format->code = s5pcsis_formats[0].code; diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 587489a072d5..b0431a988d47 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -32,7 +32,7 @@ #define CCDC_MIN_HEIGHT 32 static struct v4l2_mbus_framefmt * -__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, +__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which); static const unsigned int ccdc_fmts[] = { @@ -1935,21 +1935,21 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable) } static struct v4l2_mbus_framefmt * -__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, +__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&ccdc->subdev, cfg, pad); else return &ccdc->formats[pad]; } static struct v4l2_rect * -__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, +__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(fh, CCDC_PAD_SOURCE_OF); + return v4l2_subdev_get_try_crop(&ccdc->subdev, cfg, CCDC_PAD_SOURCE_OF); else return &ccdc->crop; } @@ -1957,12 +1957,12 @@ __ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, /* * ccdc_try_format - Try video format on a pad * @ccdc: ISP CCDC device - * @fh : V4L2 subdev file handle + * @cfg : V4L2 subdev pad configuration * @pad: Pad number * @fmt: Format */ static void -ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, +ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -1998,7 +1998,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, case CCDC_PAD_SOURCE_OF: pixelcode = fmt->code; field = fmt->field; - *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); + *fmt = *__ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, which); /* In SYNC mode the bridge converts YUV formats from 2X8 to * 1X16. In BT.656 no such conversion occurs. As we don't know @@ -2023,7 +2023,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, } /* Hardcode the output size to the crop rectangle size. */ - crop = __ccdc_get_crop(ccdc, fh, which); + crop = __ccdc_get_crop(ccdc, cfg, which); fmt->width = crop->width; fmt->height = crop->height; @@ -2040,7 +2040,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, break; case CCDC_PAD_SOURCE_VP: - *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); + *fmt = *__ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, which); /* The video port interface truncates the data to 10 bits. */ info = omap3isp_video_format_info(fmt->code); @@ -2112,12 +2112,12 @@ static void ccdc_try_crop(struct isp_ccdc_device *ccdc, /* * ccdc_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg : V4L2 subdev pad configuration * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); @@ -2132,7 +2132,7 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, break; case CCDC_PAD_SOURCE_OF: - format = __ccdc_get_format(ccdc, fh, code->pad, + format = __ccdc_get_format(ccdc, cfg, code->pad, V4L2_SUBDEV_FORMAT_TRY); if (format->code == MEDIA_BUS_FMT_YUYV8_2X8 || @@ -2163,7 +2163,7 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, if (code->index != 0) return -EINVAL; - format = __ccdc_get_format(ccdc, fh, code->pad, + format = __ccdc_get_format(ccdc, cfg, code->pad, V4L2_SUBDEV_FORMAT_TRY); /* A pixel code equal to 0 means that the video port doesn't @@ -2183,7 +2183,7 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, } static int ccdc_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); @@ -2195,7 +2195,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + ccdc_try_format(ccdc, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->min_width = format.width; fse->min_height = format.height; @@ -2205,7 +2205,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + ccdc_try_format(ccdc, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->max_width = format.width; fse->max_height = format.height; @@ -2215,7 +2215,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, /* * ccdc_get_selection - Retrieve a selection rectangle on a pad * @sd: ISP CCDC V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @sel: Selection rectangle * * The only supported rectangles are the crop rectangles on the output formatter @@ -2223,7 +2223,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, * * Return 0 on success or a negative error code otherwise. */ -static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); @@ -2239,12 +2239,12 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, sel->r.width = INT_MAX; sel->r.height = INT_MAX; - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which); + format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, sel->which); ccdc_try_crop(ccdc, format, &sel->r); break; case V4L2_SEL_TGT_CROP: - sel->r = *__ccdc_get_crop(ccdc, fh, sel->which); + sel->r = *__ccdc_get_crop(ccdc, cfg, sel->which); break; default: @@ -2257,7 +2257,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ccdc_set_selection - Set a selection rectangle on a pad * @sd: ISP CCDC V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @sel: Selection rectangle * * The only supported rectangle is the actual crop rectangle on the output @@ -2265,7 +2265,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, * * Return 0 on success or a negative error code otherwise. */ -static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); @@ -2284,17 +2284,17 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, * rectangle. */ if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) { - sel->r = *__ccdc_get_crop(ccdc, fh, sel->which); + sel->r = *__ccdc_get_crop(ccdc, cfg, sel->which); return 0; } - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which); + format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, sel->which); ccdc_try_crop(ccdc, format, &sel->r); - *__ccdc_get_crop(ccdc, fh, sel->which) = sel->r; + *__ccdc_get_crop(ccdc, cfg, sel->which) = sel->r; /* Update the source format. */ - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, sel->which); - ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, sel->which); + format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, sel->which); + ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, format, sel->which); return 0; } @@ -2302,19 +2302,19 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ccdc_get_format - Retrieve the video format on a pad * @sd : ISP CCDC V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which); + format = __ccdc_get_format(ccdc, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -2325,30 +2325,30 @@ static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ccdc_set_format - Set the video format on a pad * @sd : ISP CCDC V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which); + format = __ccdc_get_format(ccdc, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - ccdc_try_format(ccdc, fh, fmt->pad, &fmt->format, fmt->which); + ccdc_try_format(ccdc, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == CCDC_PAD_SINK) { /* Reset the crop rectangle. */ - crop = __ccdc_get_crop(ccdc, fh, fmt->which); + crop = __ccdc_get_crop(ccdc, cfg, fmt->which); crop->left = 0; crop->top = 0; crop->width = fmt->format.width; @@ -2357,16 +2357,16 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, ccdc_try_crop(ccdc, &fmt->format, crop); /* Update the source formats. */ - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, + format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, fmt->which); *format = fmt->format; - ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, + ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, format, fmt->which); - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_VP, + format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_VP, fmt->which); *format = fmt->format; - ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_VP, format, + ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_VP, format, fmt->which); } @@ -2453,7 +2453,7 @@ static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - ccdc_set_format(sd, fh, &format); + ccdc_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index f4aedb37e41e..3f10c3af3a0a 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -611,17 +611,17 @@ static const unsigned int ccp2_fmts[] = { /* * __ccp2_get_format - helper function for getting ccp2 format * @ccp2 : Pointer to ISP CCP2 device - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @pad : pad number * @which : wanted subdev format * return format structure or NULL on error */ static struct v4l2_mbus_framefmt * -__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh, +__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&ccp2->subdev, cfg, pad); else return &ccp2->formats[pad]; } @@ -629,13 +629,13 @@ __ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh, /* * ccp2_try_format - Handle try format by pad subdev method * @ccp2 : Pointer to ISP CCP2 device - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @pad : pad num * @fmt : pointer to v4l2 mbus format structure * @which : wanted subdev format */ static void ccp2_try_format(struct isp_ccp2_device *ccp2, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -669,7 +669,7 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2, * When CCP2 write to memory feature will be added this * should be changed properly. */ - format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, which); + format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; break; @@ -682,12 +682,12 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2, /* * ccp2_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); @@ -702,7 +702,7 @@ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd, if (code->index != 0) return -EINVAL; - format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, + format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK, V4L2_SUBDEV_FORMAT_TRY); code->code = format->code; } @@ -711,7 +711,7 @@ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd, } static int ccp2_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); @@ -723,7 +723,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + ccp2_try_format(ccp2, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->min_width = format.width; fse->min_height = format.height; @@ -733,7 +733,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + ccp2_try_format(ccp2, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->max_width = format.width; fse->max_height = format.height; @@ -743,17 +743,17 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd, /* * ccp2_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt : pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which); + format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -764,29 +764,29 @@ static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ccp2_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt : pointer to v4l2 subdev format structure * returns zero */ -static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which); + format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - ccp2_try_format(ccp2, fh, fmt->pad, &fmt->format, fmt->which); + ccp2_try_format(ccp2, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == CCP2_PAD_SINK) { - format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SOURCE, + format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SOURCE, fmt->which); *format = fmt->format; - ccp2_try_format(ccp2, fh, CCP2_PAD_SOURCE, format, fmt->which); + ccp2_try_format(ccp2, cfg, CCP2_PAD_SOURCE, format, fmt->which); } return 0; @@ -811,7 +811,7 @@ static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - ccp2_set_format(sd, fh, &format); + ccp2_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index 09c686d96ae8..12ca63f2bf53 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -829,17 +829,17 @@ static const struct isp_video_operations csi2_ispvideo_ops = { */ static struct v4l2_mbus_framefmt * -__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, +__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad); else return &csi2->formats[pad]; } static void -csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, +csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -869,7 +869,7 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, * compression. */ pixelcode = fmt->code; - format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which); + format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); /* @@ -890,12 +890,12 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, /* * csi2_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); @@ -908,7 +908,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, code->code = csi2_input_fmts[code->index]; } else { - format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, + format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, V4L2_SUBDEV_FORMAT_TRY); switch (code->index) { case 0: @@ -932,7 +932,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, } static int csi2_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); @@ -944,7 +944,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + csi2_try_format(csi2, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->min_width = format.width; fse->min_height = format.height; @@ -954,7 +954,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + csi2_try_format(csi2, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->max_width = format.width; fse->max_height = format.height; @@ -964,17 +964,17 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, /* * csi2_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); + format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -985,29 +985,29 @@ static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * csi2_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); + format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which); + csi2_try_format(csi2, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == CSI2_PAD_SINK) { - format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE, + format = __csi2_get_format(csi2, cfg, CSI2_PAD_SOURCE, fmt->which); *format = fmt->format; - csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which); + csi2_try_format(csi2, cfg, CSI2_PAD_SOURCE, format, fmt->which); } return 0; @@ -1032,7 +1032,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - csi2_set_format(sd, fh, &format); + csi2_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index dd9eed45d853..0571c57dbae0 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -1686,21 +1686,21 @@ static int preview_set_stream(struct v4l2_subdev *sd, int enable) } static struct v4l2_mbus_framefmt * -__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, +__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&prev->subdev, cfg, pad); else return &prev->formats[pad]; } static struct v4l2_rect * -__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, +__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK); + return v4l2_subdev_get_try_crop(&prev->subdev, cfg, PREV_PAD_SINK); else return &prev->crop; } @@ -1727,7 +1727,7 @@ static const unsigned int preview_output_fmts[] = { /* * preview_try_format - Validate a format * @prev: ISP preview engine - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @pad: pad number * @fmt: format to be validated * @which: try/active format selector @@ -1736,7 +1736,7 @@ static const unsigned int preview_output_fmts[] = { * engine limits and the format and crop rectangles on other pads. */ static void preview_try_format(struct isp_prev_device *prev, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -1777,7 +1777,7 @@ static void preview_try_format(struct isp_prev_device *prev, case PREV_PAD_SOURCE: pixelcode = fmt->code; - *fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which); + *fmt = *__preview_get_format(prev, cfg, PREV_PAD_SINK, which); switch (pixelcode) { case MEDIA_BUS_FMT_YUYV8_1X16: @@ -1795,7 +1795,7 @@ static void preview_try_format(struct isp_prev_device *prev, * is not supported yet, hardcode the output size to the crop * rectangle size. */ - crop = __preview_get_crop(prev, fh, which); + crop = __preview_get_crop(prev, cfg, which); fmt->width = crop->width; fmt->height = crop->height; @@ -1864,12 +1864,12 @@ static void preview_try_crop(struct isp_prev_device *prev, /* * preview_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int preview_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { switch (code->pad) { @@ -1893,7 +1893,7 @@ static int preview_enum_mbus_code(struct v4l2_subdev *sd, } static int preview_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct isp_prev_device *prev = v4l2_get_subdevdata(sd); @@ -1905,7 +1905,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + preview_try_format(prev, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->min_width = format.width; fse->min_height = format.height; @@ -1915,7 +1915,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + preview_try_format(prev, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->max_width = format.width; fse->max_height = format.height; @@ -1925,7 +1925,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, /* * preview_get_selection - Retrieve a selection rectangle on a pad * @sd: ISP preview V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @sel: Selection rectangle * * The only supported rectangles are the crop rectangles on the sink pad. @@ -1933,7 +1933,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, * Return 0 on success or a negative error code otherwise. */ static int preview_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct isp_prev_device *prev = v4l2_get_subdevdata(sd); @@ -1949,13 +1949,13 @@ static int preview_get_selection(struct v4l2_subdev *sd, sel->r.width = INT_MAX; sel->r.height = INT_MAX; - format = __preview_get_format(prev, fh, PREV_PAD_SINK, + format = __preview_get_format(prev, cfg, PREV_PAD_SINK, sel->which); preview_try_crop(prev, format, &sel->r); break; case V4L2_SEL_TGT_CROP: - sel->r = *__preview_get_crop(prev, fh, sel->which); + sel->r = *__preview_get_crop(prev, cfg, sel->which); break; default: @@ -1968,7 +1968,7 @@ static int preview_get_selection(struct v4l2_subdev *sd, /* * preview_set_selection - Set a selection rectangle on a pad * @sd: ISP preview V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @sel: Selection rectangle * * The only supported rectangle is the actual crop rectangle on the sink pad. @@ -1976,7 +1976,7 @@ static int preview_get_selection(struct v4l2_subdev *sd, * Return 0 on success or a negative error code otherwise. */ static int preview_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct isp_prev_device *prev = v4l2_get_subdevdata(sd); @@ -1995,17 +1995,17 @@ static int preview_set_selection(struct v4l2_subdev *sd, * rectangle. */ if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) { - sel->r = *__preview_get_crop(prev, fh, sel->which); + sel->r = *__preview_get_crop(prev, cfg, sel->which); return 0; } - format = __preview_get_format(prev, fh, PREV_PAD_SINK, sel->which); + format = __preview_get_format(prev, cfg, PREV_PAD_SINK, sel->which); preview_try_crop(prev, format, &sel->r); - *__preview_get_crop(prev, fh, sel->which) = sel->r; + *__preview_get_crop(prev, cfg, sel->which) = sel->r; /* Update the source format. */ - format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, sel->which); - preview_try_format(prev, fh, PREV_PAD_SOURCE, format, sel->which); + format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE, sel->which); + preview_try_format(prev, cfg, PREV_PAD_SOURCE, format, sel->which); return 0; } @@ -2013,17 +2013,17 @@ static int preview_set_selection(struct v4l2_subdev *sd, /* * preview_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_prev_device *prev = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __preview_get_format(prev, fh, fmt->pad, fmt->which); + format = __preview_get_format(prev, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -2034,28 +2034,28 @@ static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * preview_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_prev_device *prev = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - format = __preview_get_format(prev, fh, fmt->pad, fmt->which); + format = __preview_get_format(prev, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - preview_try_format(prev, fh, fmt->pad, &fmt->format, fmt->which); + preview_try_format(prev, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == PREV_PAD_SINK) { /* Reset the crop rectangle. */ - crop = __preview_get_crop(prev, fh, fmt->which); + crop = __preview_get_crop(prev, cfg, fmt->which); crop->left = 0; crop->top = 0; crop->width = fmt->format.width; @@ -2064,9 +2064,9 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, preview_try_crop(prev, &fmt->format, crop); /* Update the source format. */ - format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, + format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE, fmt->which); - preview_try_format(prev, fh, PREV_PAD_SOURCE, format, + preview_try_format(prev, cfg, PREV_PAD_SOURCE, format, fmt->which); } @@ -2093,7 +2093,7 @@ static int preview_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - preview_set_format(sd, fh, &format); + preview_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 2b9bc4839876..3ede27bc0a45 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -112,16 +112,16 @@ static const struct isprsz_coef filter_coefs = { * __resizer_get_format - helper function for getting resizer format * @res : pointer to resizer private structure * @pad : pad number - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @which : wanted subdev format * return zero */ static struct v4l2_mbus_framefmt * -__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh, +__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&res->subdev, cfg, pad); else return &res->formats[pad]; } @@ -129,15 +129,15 @@ __resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh, /* * __resizer_get_crop - helper function for getting resizer crop rectangle * @res : pointer to resizer private structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @which : wanted subdev crop rectangle */ static struct v4l2_rect * -__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh, +__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK); + return v4l2_subdev_get_try_crop(&res->subdev, cfg, RESZ_PAD_SINK); else return &res->crop.request; } @@ -1215,7 +1215,7 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink, /* * resizer_get_selection - Retrieve a selection rectangle on a pad * @sd: ISP resizer V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @sel: Selection rectangle * * The only supported rectangles are the crop rectangles on the sink pad. @@ -1223,7 +1223,7 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink, * Return 0 on success or a negative error code otherwise. */ static int resizer_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct isp_res_device *res = v4l2_get_subdevdata(sd); @@ -1234,9 +1234,9 @@ static int resizer_get_selection(struct v4l2_subdev *sd, if (sel->pad != RESZ_PAD_SINK) return -EINVAL; - format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK, + format_sink = __resizer_get_format(res, cfg, RESZ_PAD_SINK, sel->which); - format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, + format_source = __resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which); switch (sel->target) { @@ -1251,7 +1251,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd, break; case V4L2_SEL_TGT_CROP: - sel->r = *__resizer_get_crop(res, fh, sel->which); + sel->r = *__resizer_get_crop(res, cfg, sel->which); resizer_calc_ratios(res, &sel->r, format_source, &ratio); break; @@ -1265,7 +1265,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd, /* * resizer_set_selection - Set a selection rectangle on a pad * @sd: ISP resizer V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @sel: Selection rectangle * * The only supported rectangle is the actual crop rectangle on the sink pad. @@ -1276,7 +1276,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd, * Return 0 on success or a negative error code otherwise. */ static int resizer_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct isp_res_device *res = v4l2_get_subdevdata(sd); @@ -1290,9 +1290,9 @@ static int resizer_set_selection(struct v4l2_subdev *sd, sel->pad != RESZ_PAD_SINK) return -EINVAL; - format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK, + format_sink = __resizer_get_format(res, cfg, RESZ_PAD_SINK, sel->which); - format_source = *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, + format_source = *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which); dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", @@ -1310,7 +1310,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd, * stored the mangled rectangle. */ resizer_try_crop(format_sink, &format_source, &sel->r); - *__resizer_get_crop(res, fh, sel->which) = sel->r; + *__resizer_get_crop(res, cfg, sel->which) = sel->r; resizer_calc_ratios(res, &sel->r, &format_source, &ratio); dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", @@ -1320,7 +1320,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd, format_source.width, format_source.height); if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) = + *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which) = format_source; return 0; } @@ -1331,7 +1331,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd, */ spin_lock_irqsave(&res->lock, flags); - *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) = + *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which) = format_source; res->ratio = ratio; @@ -1368,13 +1368,13 @@ static unsigned int resizer_max_in_width(struct isp_res_device *res) /* * resizer_try_format - Handle try format by pad subdev method * @res : ISP resizer device - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @pad : pad num * @fmt : pointer to v4l2 format structure * @which : wanted subdev format */ static void resizer_try_format(struct isp_res_device *res, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -1395,10 +1395,10 @@ static void resizer_try_format(struct isp_res_device *res, break; case RESZ_PAD_SOURCE: - format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which); + format = __resizer_get_format(res, cfg, RESZ_PAD_SINK, which); fmt->code = format->code; - crop = *__resizer_get_crop(res, fh, which); + crop = *__resizer_get_crop(res, cfg, which); resizer_calc_ratios(res, &crop, fmt, &ratio); break; } @@ -1410,12 +1410,12 @@ static void resizer_try_format(struct isp_res_device *res, /* * resizer_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct isp_res_device *res = v4l2_get_subdevdata(sd); @@ -1430,7 +1430,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, if (code->index != 0) return -EINVAL; - format = __resizer_get_format(res, fh, RESZ_PAD_SINK, + format = __resizer_get_format(res, cfg, RESZ_PAD_SINK, V4L2_SUBDEV_FORMAT_TRY); code->code = format->code; } @@ -1439,7 +1439,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, } static int resizer_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct isp_res_device *res = v4l2_get_subdevdata(sd); @@ -1451,7 +1451,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + resizer_try_format(res, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->min_width = format.width; fse->min_height = format.height; @@ -1461,7 +1461,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + resizer_try_format(res, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->max_width = format.width; fse->max_height = format.height; @@ -1471,17 +1471,17 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, /* * resizer_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt : pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_res_device *res = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __resizer_get_format(res, fh, fmt->pad, fmt->which); + format = __resizer_get_format(res, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -1492,37 +1492,37 @@ static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * resizer_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt : pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_res_device *res = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - format = __resizer_get_format(res, fh, fmt->pad, fmt->which); + format = __resizer_get_format(res, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which); + resizer_try_format(res, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; if (fmt->pad == RESZ_PAD_SINK) { /* reset crop rectangle */ - crop = __resizer_get_crop(res, fh, fmt->which); + crop = __resizer_get_crop(res, cfg, fmt->which); crop->left = 0; crop->top = 0; crop->width = fmt->format.width; crop->height = fmt->format.height; /* Propagate the format from sink to source */ - format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, + format = __resizer_get_format(res, cfg, RESZ_PAD_SOURCE, fmt->which); *format = fmt->format; - resizer_try_format(res, fh, RESZ_PAD_SOURCE, format, + resizer_try_format(res, cfg, RESZ_PAD_SOURCE, format, fmt->which); } @@ -1573,7 +1573,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_YUYV8_1X16; format.format.width = 4096; format.format.height = 4096; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 54479d60cc0d..f6a61b9ceff4 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -1219,7 +1219,7 @@ static const u32 camif_mbus_formats[] = { */ static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(camif_mbus_formats)) @@ -1230,14 +1230,14 @@ static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd, } static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct camif_dev *camif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf = &fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); fmt->format = *mf; return 0; } @@ -1297,7 +1297,7 @@ static void __camif_subdev_try_format(struct camif_dev *camif, } static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct camif_dev *camif = v4l2_get_subdevdata(sd); @@ -1325,7 +1325,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd, __camif_subdev_try_format(camif, mf, fmt->pad); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; mutex_unlock(&camif->lock); return 0; @@ -1364,7 +1364,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd, } static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct camif_dev *camif = v4l2_get_subdevdata(sd); @@ -1377,7 +1377,7 @@ static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd, return -EINVAL; if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad); + sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad); return 0; } @@ -1451,7 +1451,7 @@ static void __camif_try_crop(struct camif_dev *camif, struct v4l2_rect *r) } static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct camif_dev *camif = v4l2_get_subdevdata(sd); @@ -1465,7 +1465,7 @@ static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd, __camif_try_crop(camif, &sel->r); if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r; + *v4l2_subdev_get_try_crop(sd, cfg, sel->pad) = sel->r; } else { unsigned long flags; unsigned int i; diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c index 401e2b77a0b6..31ad0b634e0c 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.c +++ b/drivers/media/platform/vsp1/vsp1_bru.c @@ -183,7 +183,7 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable) */ static int bru_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { @@ -201,7 +201,7 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev, if (code->index) return -EINVAL; - format = v4l2_subdev_get_try_format(fh, BRU_PAD_SINK(0)); + format = v4l2_subdev_get_try_format(subdev, cfg, BRU_PAD_SINK(0)); code->code = format->code; } @@ -209,7 +209,7 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev, } static int bru_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { if (fse->index) @@ -228,12 +228,12 @@ static int bru_enum_frame_size(struct v4l2_subdev *subdev, } static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, u32 which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(fh, pad); + return v4l2_subdev_get_try_crop(&bru->entity.subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &bru->inputs[pad].compose; default: @@ -241,18 +241,18 @@ static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, } } -static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_bru *bru = to_bru(subdev); - fmt->format = *vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad, fmt->which); return 0; } -static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, +static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -268,7 +268,7 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, default: /* The BRU can't perform format conversion. */ - format = vsp1_entity_get_pad_format(&bru->entity, fh, + format = vsp1_entity_get_pad_format(&bru->entity, cfg, BRU_PAD_SINK(0), which); fmt->code = format->code; break; @@ -280,15 +280,15 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, fmt->colorspace = V4L2_COLORSPACE_SRGB; } -static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_bru *bru = to_bru(subdev); struct v4l2_mbus_framefmt *format; - bru_try_format(bru, fh, fmt->pad, &fmt->format, fmt->which); + bru_try_format(bru, cfg, fmt->pad, &fmt->format, fmt->which); - format = vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad, fmt->which); *format = fmt->format; @@ -296,7 +296,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, if (fmt->pad != BRU_PAD_SOURCE) { struct v4l2_rect *compose; - compose = bru_get_compose(bru, fh, fmt->pad, fmt->which); + compose = bru_get_compose(bru, cfg, fmt->pad, fmt->which); compose->left = 0; compose->top = 0; compose->width = format->width; @@ -308,7 +308,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, unsigned int i; for (i = 0; i <= BRU_PAD_SOURCE; ++i) { - format = vsp1_entity_get_pad_format(&bru->entity, fh, + format = vsp1_entity_get_pad_format(&bru->entity, cfg, i, fmt->which); format->code = fmt->format.code; } @@ -318,7 +318,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, } static int bru_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct vsp1_bru *bru = to_bru(subdev); @@ -335,7 +335,7 @@ static int bru_get_selection(struct v4l2_subdev *subdev, return 0; case V4L2_SEL_TGT_COMPOSE: - sel->r = *bru_get_compose(bru, fh, sel->pad, sel->which); + sel->r = *bru_get_compose(bru, cfg, sel->pad, sel->which); return 0; default: @@ -344,7 +344,7 @@ static int bru_get_selection(struct v4l2_subdev *subdev, } static int bru_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct vsp1_bru *bru = to_bru(subdev); @@ -360,7 +360,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev, /* The compose rectangle top left corner must be inside the output * frame. */ - format = vsp1_entity_get_pad_format(&bru->entity, fh, BRU_PAD_SOURCE, + format = vsp1_entity_get_pad_format(&bru->entity, cfg, BRU_PAD_SOURCE, sel->which); sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); @@ -368,12 +368,12 @@ static int bru_set_selection(struct v4l2_subdev *subdev, /* Scaling isn't supported, the compose rectangle size must be identical * to the sink format size. */ - format = vsp1_entity_get_pad_format(&bru->entity, fh, sel->pad, + format = vsp1_entity_get_pad_format(&bru->entity, cfg, sel->pad, sel->which); sel->r.width = format->width; sel->r.height = format->height; - compose = bru_get_compose(bru, fh, sel->pad, sel->which); + compose = bru_get_compose(bru, cfg, sel->pad, sel->which); *compose = sel->r; return 0; diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 79af71d5e270..a453bb4ddd37 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -63,12 +63,12 @@ int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming) struct v4l2_mbus_framefmt * vsp1_entity_get_pad_format(struct vsp1_entity *entity, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, u32 which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &entity->formats[pad]; default: @@ -79,14 +79,14 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity, /* * vsp1_entity_init_formats - Initialize formats on all pads * @subdev: V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * - * Initialize all pad formats with default values. If fh is not NULL, try + * Initialize all pad formats with default values. If cfg is not NULL, try * formats are initialized on the file handle. Otherwise active formats are * initialized on the device. */ void vsp1_entity_init_formats(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh) + struct v4l2_subdev_pad_config *cfg) { struct v4l2_subdev_format format; unsigned int pad; @@ -95,17 +95,17 @@ void vsp1_entity_init_formats(struct v4l2_subdev *subdev, memset(&format, 0, sizeof(format)); format.pad = pad; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY + format.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - v4l2_subdev_call(subdev, pad, set_fmt, fh, &format); + v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format); } } static int vsp1_entity_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) { - vsp1_entity_init_formats(subdev, fh); + vsp1_entity_init_formats(subdev, fh->pad); return 0; } diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index aa20aaa58208..62c768d1c6aa 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -91,10 +91,10 @@ extern const struct media_entity_operations vsp1_media_ops; struct v4l2_mbus_framefmt * vsp1_entity_get_pad_format(struct vsp1_entity *entity, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, u32 which); void vsp1_entity_init_formats(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh); + struct v4l2_subdev_pad_config *cfg); bool vsp1_entity_is_streaming(struct vsp1_entity *entity); int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming); diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index 0bc0471746c9..d226b3ff5e30 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c @@ -55,7 +55,7 @@ static int hsit_s_stream(struct v4l2_subdev *subdev, int enable) */ static int hsit_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct vsp1_hsit *hsit = to_hsit(subdev); @@ -73,12 +73,12 @@ static int hsit_enum_mbus_code(struct v4l2_subdev *subdev, } static int hsit_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, fse->pad); + format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad); if (fse->index || fse->code != format->code) return -EINVAL; @@ -102,25 +102,25 @@ static int hsit_enum_frame_size(struct v4l2_subdev *subdev, } static int hsit_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_hsit *hsit = to_hsit(subdev); - fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad, fmt->which); return 0; } static int hsit_set_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_hsit *hsit = to_hsit(subdev); struct v4l2_mbus_framefmt *format; - format = vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad, fmt->which); if (fmt->pad == HSIT_PAD_SOURCE) { @@ -143,7 +143,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev, fmt->format = *format; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&hsit->entity, fh, HSIT_PAD_SOURCE, + format = vsp1_entity_get_pad_format(&hsit->entity, cfg, HSIT_PAD_SOURCE, fmt->which); *format = fmt->format; format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32 diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index 17a6ca7dafe6..b91c925a9887 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c @@ -74,7 +74,7 @@ static int lif_s_stream(struct v4l2_subdev *subdev, int enable) */ static int lif_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { @@ -96,7 +96,7 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev, if (code->index) return -EINVAL; - format = v4l2_subdev_get_try_format(fh, LIF_PAD_SINK); + format = v4l2_subdev_get_try_format(subdev, cfg, LIF_PAD_SINK); code->code = format->code; } @@ -104,12 +104,12 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev, } static int lif_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, LIF_PAD_SINK); + format = v4l2_subdev_get_try_format(subdev, cfg, LIF_PAD_SINK); if (fse->index || fse->code != format->code) return -EINVAL; @@ -129,18 +129,18 @@ static int lif_enum_frame_size(struct v4l2_subdev *subdev, return 0; } -static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_lif *lif = to_lif(subdev); - fmt->format = *vsp1_entity_get_pad_format(&lif->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad, fmt->which); return 0; } -static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_lif *lif = to_lif(subdev); @@ -151,7 +151,7 @@ static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; - format = vsp1_entity_get_pad_format(&lif->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad, fmt->which); if (fmt->pad == LIF_PAD_SOURCE) { @@ -173,7 +173,7 @@ static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, fmt->format = *format; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&lif->entity, fh, LIF_PAD_SOURCE, + format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SOURCE, fmt->which); *format = fmt->format; diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index 6f185c3621fe..003363d9a5d8 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -82,7 +82,7 @@ static int lut_s_stream(struct v4l2_subdev *subdev, int enable) */ static int lut_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { @@ -104,7 +104,7 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev, if (code->index) return -EINVAL; - format = v4l2_subdev_get_try_format(fh, LUT_PAD_SINK); + format = v4l2_subdev_get_try_format(subdev, cfg, LUT_PAD_SINK); code->code = format->code; } @@ -112,12 +112,12 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev, } static int lut_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, fse->pad); + format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad); if (fse->index || fse->code != format->code) return -EINVAL; @@ -140,18 +140,18 @@ static int lut_enum_frame_size(struct v4l2_subdev *subdev, return 0; } -static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_lut *lut = to_lut(subdev); - fmt->format = *vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad, fmt->which); return 0; } -static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_lut *lut = to_lut(subdev); @@ -163,7 +163,7 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; - format = vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad, fmt->which); if (fmt->pad == LUT_PAD_SOURCE) { @@ -182,7 +182,7 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, fmt->format = *format; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&lut->entity, fh, LUT_PAD_SOURCE, + format = vsp1_entity_get_pad_format(&lut->entity, cfg, LUT_PAD_SOURCE, fmt->which); *format = fmt->format; diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index 1f1ba26a834a..a083d85e84b4 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c @@ -25,7 +25,7 @@ */ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { @@ -42,13 +42,13 @@ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, } int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, fse->pad); + format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad); if (fse->index || fse->code != format->code) return -EINVAL; @@ -72,11 +72,11 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, } static struct v4l2_rect * -vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_fh *fh, u32 which) +vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg, u32 which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(fh, RWPF_PAD_SINK); + return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg, RWPF_PAD_SINK); case V4L2_SUBDEV_FORMAT_ACTIVE: return &rwpf->crop; default: @@ -84,18 +84,18 @@ vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_fh *fh, u32 which) } } -int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); - fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad, fmt->which); return 0; } -int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); @@ -107,7 +107,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; - format = vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad, fmt->which); if (fmt->pad == RWPF_PAD_SOURCE) { @@ -130,14 +130,14 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, fmt->format = *format; /* Update the sink crop rectangle. */ - crop = vsp1_rwpf_get_crop(rwpf, fh, fmt->which); + crop = vsp1_rwpf_get_crop(rwpf, cfg, fmt->which); crop->left = 0; crop->top = 0; crop->width = fmt->format.width; crop->height = fmt->format.height; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE, + format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, fmt->which); *format = fmt->format; @@ -145,7 +145,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, } int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); @@ -157,11 +157,11 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, switch (sel->target) { case V4L2_SEL_TGT_CROP: - sel->r = *vsp1_rwpf_get_crop(rwpf, fh, sel->which); + sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which); break; case V4L2_SEL_TGT_CROP_BOUNDS: - format = vsp1_entity_get_pad_format(&rwpf->entity, fh, + format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK, sel->which); sel->r.left = 0; sel->r.top = 0; @@ -177,7 +177,7 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, } int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); @@ -194,7 +194,7 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, /* Make sure the crop rectangle is entirely contained in the image. The * WPF top and left offsets are limited to 255. */ - format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SINK, + format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK, sel->which); sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); @@ -207,11 +207,11 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, sel->r.height = min_t(unsigned int, sel->r.height, format->height - sel->r.top); - crop = vsp1_rwpf_get_crop(rwpf, fh, sel->which); + crop = vsp1_rwpf_get_crop(rwpf, cfg, sel->which); *crop = sel->r; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE, + format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, sel->which); format->width = crop->width; format->height = crop->height; diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 2cf1f13d3bf9..f452dce1a931 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h @@ -51,20 +51,20 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index); struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code); int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse); -int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt); -int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt); int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel); int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel); #endif /* __VSP1_RWPF_H__ */ diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index 1129494c7cfc..c51dcee228bc 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c @@ -166,7 +166,7 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable) */ static int sru_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { @@ -187,7 +187,7 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev, if (code->index) return -EINVAL; - format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK); + format = v4l2_subdev_get_try_format(subdev, cfg, SRU_PAD_SINK); code->code = format->code; } @@ -195,12 +195,12 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev, } static int sru_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK); + format = v4l2_subdev_get_try_format(subdev, cfg, SRU_PAD_SINK); if (fse->index || fse->code != format->code) return -EINVAL; @@ -226,18 +226,18 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev, return 0; } -static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_sru *sru = to_sru(subdev); - fmt->format = *vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad, fmt->which); return 0; } -static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh, +static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -258,7 +258,7 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh, case SRU_PAD_SOURCE: /* The SRU can't perform format conversion. */ - format = vsp1_entity_get_pad_format(&sru->entity, fh, + format = vsp1_entity_get_pad_format(&sru->entity, cfg, SRU_PAD_SINK, which); fmt->code = format->code; @@ -288,25 +288,25 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh, fmt->colorspace = V4L2_COLORSPACE_SRGB; } -static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_sru *sru = to_sru(subdev); struct v4l2_mbus_framefmt *format; - sru_try_format(sru, fh, fmt->pad, &fmt->format, fmt->which); + sru_try_format(sru, cfg, fmt->pad, &fmt->format, fmt->which); - format = vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad, fmt->which); *format = fmt->format; if (fmt->pad == SRU_PAD_SINK) { /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&sru->entity, fh, + format = vsp1_entity_get_pad_format(&sru->entity, cfg, SRU_PAD_SOURCE, fmt->which); *format = fmt->format; - sru_try_format(sru, fh, SRU_PAD_SOURCE, format, fmt->which); + sru_try_format(sru, cfg, SRU_PAD_SOURCE, format, fmt->which); } return 0; diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index a4afec133800..08d916d5d1ac 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c @@ -169,7 +169,7 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable) */ static int uds_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { @@ -191,7 +191,7 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev, if (code->index) return -EINVAL; - format = v4l2_subdev_get_try_format(fh, UDS_PAD_SINK); + format = v4l2_subdev_get_try_format(subdev, cfg, UDS_PAD_SINK); code->code = format->code; } @@ -199,12 +199,12 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev, } static int uds_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, UDS_PAD_SINK); + format = v4l2_subdev_get_try_format(subdev, cfg, UDS_PAD_SINK); if (fse->index || fse->code != format->code) return -EINVAL; @@ -224,18 +224,18 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev, return 0; } -static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_uds *uds = to_uds(subdev); - fmt->format = *vsp1_entity_get_pad_format(&uds->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad, fmt->which); return 0; } -static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh, +static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -256,7 +256,7 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh, case UDS_PAD_SOURCE: /* The UDS scales but can't perform format conversion. */ - format = vsp1_entity_get_pad_format(&uds->entity, fh, + format = vsp1_entity_get_pad_format(&uds->entity, cfg, UDS_PAD_SINK, which); fmt->code = format->code; @@ -271,25 +271,25 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh, fmt->colorspace = V4L2_COLORSPACE_SRGB; } -static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_uds *uds = to_uds(subdev); struct v4l2_mbus_framefmt *format; - uds_try_format(uds, fh, fmt->pad, &fmt->format, fmt->which); + uds_try_format(uds, cfg, fmt->pad, &fmt->format, fmt->which); - format = vsp1_entity_get_pad_format(&uds->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad, fmt->which); *format = fmt->format; if (fmt->pad == UDS_PAD_SINK) { /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&uds->entity, fh, + format = vsp1_entity_get_pad_format(&uds->entity, cfg, UDS_PAD_SOURCE, fmt->which); *format = fmt->format; - uds_try_format(uds, fh, UDS_PAD_SOURCE, format, fmt->which); + uds_try_format(uds, cfg, UDS_PAD_SOURCE, format, fmt->which); } return 0; diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 19a034e79be4..3c8b198a0622 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -262,7 +262,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; - return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh, format); + return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format); } case VIDIOC_SUBDEV_S_FMT: { @@ -272,7 +272,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; - return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format); + return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format); } case VIDIOC_SUBDEV_G_CROP: { @@ -289,7 +289,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) sel.target = V4L2_SEL_TGT_CROP; rval = v4l2_subdev_call( - sd, pad, get_selection, subdev_fh, &sel); + sd, pad, get_selection, subdev_fh->pad, &sel); crop->rect = sel.r; @@ -311,7 +311,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) sel.r = crop->rect; rval = v4l2_subdev_call( - sd, pad, set_selection, subdev_fh, &sel); + sd, pad, set_selection, subdev_fh->pad, &sel); crop->rect = sel.r; @@ -324,7 +324,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (code->pad >= sd->entity.num_pads) return -EINVAL; - return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh, + return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad, code); } @@ -334,7 +334,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (fse->pad >= sd->entity.num_pads) return -EINVAL; - return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh, + return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad, fse); } @@ -362,7 +362,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (fie->pad >= sd->entity.num_pads) return -EINVAL; - return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh, + return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad, fie); } @@ -374,7 +374,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) return rval; return v4l2_subdev_call( - sd, pad, get_selection, subdev_fh, sel); + sd, pad, get_selection, subdev_fh->pad, sel); } case VIDIOC_SUBDEV_S_SELECTION: { @@ -385,7 +385,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) return rval; return v4l2_subdev_call( - sd, pad, set_selection, subdev_fh, sel); + sd, pad, set_selection, subdev_fh->pad, sel); } case VIDIOC_G_EDID: { diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c index a425f71dfb97..715f1e6b8fe2 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c +++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c @@ -1414,17 +1414,17 @@ static int ipipe_set_stream(struct v4l2_subdev *sd, int enable) * __ipipe_get_format() - helper function for getting ipipe format * @ipipe: pointer to ipipe private structure. * @pad: pad number. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @which: wanted subdev format. * */ static struct v4l2_mbus_framefmt * __ipipe_get_format(struct vpfe_ipipe_device *ipipe, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&ipipe->subdev, cfg, pad); return &ipipe->formats[pad]; } @@ -1432,14 +1432,14 @@ __ipipe_get_format(struct vpfe_ipipe_device *ipipe, /* * ipipe_try_format() - Handle try format by pad subdev method * @ipipe: VPFE ipipe device. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @pad: pad num. * @fmt: pointer to v4l2 format structure. * @which : wanted subdev format */ static void ipipe_try_format(struct vpfe_ipipe_device *ipipe, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -1475,22 +1475,22 @@ ipipe_try_format(struct vpfe_ipipe_device *ipipe, /* * ipipe_set_format() - Handle set format by pads subdev method * @sd: pointer to v4l2 subdev structure - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ static int -ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipe_get_format(ipipe, fh, fmt->pad, fmt->which); + format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - ipipe_try_format(ipipe, fh, fmt->pad, &fmt->format, fmt->which); + ipipe_try_format(ipipe, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) @@ -1512,11 +1512,11 @@ ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ipipe_get_format() - Handle get format by pads subdev method. * @sd: pointer to v4l2 subdev structure. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure. */ static int -ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); @@ -1524,7 +1524,7 @@ ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) fmt->format = ipipe->formats[fmt->pad]; else - fmt->format = *(v4l2_subdev_get_try_format(fh, fmt->pad)); + fmt->format = *(v4l2_subdev_get_try_format(sd, cfg, fmt->pad)); return 0; } @@ -1532,11 +1532,11 @@ ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ipipe_enum_frame_size() - enum frame sizes on pads * @sd: pointer to v4l2 subdev structure. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @fse: pointer to v4l2_subdev_frame_size_enum structure. */ static int -ipipe_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipe_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); @@ -1548,7 +1548,7 @@ ipipe_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, format.code = fse->code; format.width = 1; format.height = 1; - ipipe_try_format(ipipe, fh, fse->pad, &format, + ipipe_try_format(ipipe, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->min_width = format.width; fse->min_height = format.height; @@ -1559,7 +1559,7 @@ ipipe_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, format.code = fse->code; format.width = -1; format.height = -1; - ipipe_try_format(ipipe, fh, fse->pad, &format, + ipipe_try_format(ipipe, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->max_width = format.width; fse->max_height = format.height; @@ -1570,11 +1570,11 @@ ipipe_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ipipe_enum_mbus_code() - enum mbus codes for pads * @sd: pointer to v4l2 subdev structure. - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_mbus_code_enum structure */ static int -ipipe_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipe_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { switch (code->pad) { @@ -1630,9 +1630,8 @@ static int ipipe_s_ctrl(struct v4l2_ctrl *ctrl) * @sd: pointer to v4l2 subdev structure. * @fh: V4L2 subdev file handle * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. + * Initialize all pad formats with default values. Try formats are initialized + * on the file handle. */ static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) @@ -1641,19 +1640,19 @@ ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) memset(&format, 0, sizeof(format)); format.pad = IPIPE_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.which = V4L2_SUBDEV_FORMAT_TRY; format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipe_set_format(sd, fh, &format); + ipipe_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = IPIPE_PAD_SOURCE; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.which = V4L2_SUBDEV_FORMAT_TRY; format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipe_set_format(sd, fh, &format); + ipipe_set_format(sd, fh->pad, &format); return 0; } diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c index 87d42e18377d..68a9bb04922a 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c +++ b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c @@ -544,12 +544,12 @@ static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable) /* * ipipeif_enum_mbus_code() - Handle pixel format enumeration * @sd: pointer to v4l2 subdev structure - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { switch (code->pad) { @@ -577,11 +577,11 @@ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, /* * ipipeif_get_format() - Handle get format by pads subdev method * @sd: pointer to v4l2 subdev structure - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure */ static int -ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); @@ -589,7 +589,7 @@ ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) fmt->format = ipipeif->formats[fmt->pad]; else - fmt->format = *(v4l2_subdev_get_try_format(fh, fmt->pad)); + fmt->format = *(v4l2_subdev_get_try_format(sd, cfg, fmt->pad)); return 0; } @@ -600,14 +600,14 @@ ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ipipeif_try_format() - Handle try format by pad subdev method * @ipipeif: VPFE ipipeif device. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @pad: pad num. * @fmt: pointer to v4l2 format structure. * @which : wanted subdev format */ static void ipipeif_try_format(struct vpfe_ipipeif_device *ipipeif, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -641,7 +641,7 @@ ipipeif_try_format(struct vpfe_ipipeif_device *ipipeif, } static int -ipipeif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipeif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); @@ -653,7 +653,7 @@ ipipeif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, format.code = fse->code; format.width = 1; format.height = 1; - ipipeif_try_format(ipipeif, fh, fse->pad, &format, + ipipeif_try_format(ipipeif, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->min_width = format.width; fse->min_height = format.height; @@ -664,7 +664,7 @@ ipipeif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, format.code = fse->code; format.width = -1; format.height = -1; - ipipeif_try_format(ipipeif, fh, fse->pad, &format, + ipipeif_try_format(ipipeif, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->max_width = format.width; fse->max_height = format.height; @@ -675,18 +675,18 @@ ipipeif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * __ipipeif_get_format() - helper function for getting ipipeif format * @ipipeif: pointer to ipipeif private structure. + * @cfg: V4L2 subdev pad config * @pad: pad number. - * @fh: V4L2 subdev file handle. * @which: wanted subdev format. * */ static struct v4l2_mbus_framefmt * __ipipeif_get_format(struct vpfe_ipipeif_device *ipipeif, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&ipipeif->subdev, cfg, pad); return &ipipeif->formats[pad]; } @@ -694,22 +694,22 @@ __ipipeif_get_format(struct vpfe_ipipeif_device *ipipeif, /* * ipipeif_set_format() - Handle set format by pads subdev method * @sd: pointer to v4l2 subdev structure - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ static int -ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipeif_get_format(ipipeif, fh, fmt->pad, fmt->which); + format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - ipipeif_try_format(ipipeif, fh, fmt->pad, &fmt->format, fmt->which); + ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) @@ -757,9 +757,8 @@ static void ipipeif_set_default_config(struct vpfe_ipipeif_device *ipipeif) * @sd: VPFE ipipeif V4L2 subdevice * @fh: V4L2 subdev file handle * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. + * Initialize all pad formats with default values. Try formats are initialized + * on the file handle. */ static int ipipeif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) @@ -769,19 +768,19 @@ ipipeif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) memset(&format, 0, sizeof(format)); format.pad = IPIPEIF_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.which = V4L2_SUBDEV_FORMAT_TRY; format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipeif_set_format(sd, fh, &format); + ipipeif_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = IPIPEIF_PAD_SOURCE; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.which = V4L2_SUBDEV_FORMAT_TRY; format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipeif_set_format(sd, fh, &format); + ipipeif_set_format(sd, fh->pad, &format); ipipeif_set_default_config(ipipeif); diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c index bcf762bc233d..02b6bdc0d771 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_isif.c +++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c @@ -278,11 +278,11 @@ isif_config_format(struct vpfe_device *vpfe_dev, unsigned int pad) /* * isif_try_format() - Try video format on a pad * @isif: VPFE isif device - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure */ static void -isif_try_format(struct vpfe_isif_device *isif, struct v4l2_subdev_fh *fh, +isif_try_format(struct vpfe_isif_device *isif, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { unsigned int width = fmt->format.width; @@ -1394,11 +1394,11 @@ static int isif_set_stream(struct v4l2_subdev *sd, int enable) * __isif_get_format() - helper function for getting isif format * @isif: pointer to isif private structure. * @pad: pad number. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @which: wanted subdev format. */ static struct v4l2_mbus_framefmt * -__isif_get_format(struct vpfe_isif_device *isif, struct v4l2_subdev_fh *fh, +__isif_get_format(struct vpfe_isif_device *isif, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) { @@ -1407,32 +1407,32 @@ __isif_get_format(struct vpfe_isif_device *isif, struct v4l2_subdev_fh *fh, fmt.pad = pad; fmt.which = which; - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&isif->subdev, cfg, pad); } return &isif->formats[pad]; } /* -* isif_set_format() - set format on pad -* @sd : VPFE ISIF device -* @fh : V4L2 subdev file handle -* @fmt : pointer to v4l2 subdev format structure -* -* Return 0 on success or -EINVAL if format or pad is invalid -*/ + * isif_set_format() - set format on pad + * @sd : VPFE ISIF device + * @cfg : V4L2 subdev pad config + * @fmt : pointer to v4l2 subdev format structure + * + * Return 0 on success or -EINVAL if format or pad is invalid + */ static int -isif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +isif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); struct vpfe_device *vpfe_dev = to_vpfe_device(isif); struct v4l2_mbus_framefmt *format; - format = __isif_get_format(isif, fh, fmt->pad, fmt->which); + format = __isif_get_format(isif, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - isif_try_format(isif, fh, fmt); + isif_try_format(isif, cfg, fmt); memcpy(format, &fmt->format, sizeof(*format)); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) @@ -1447,20 +1447,20 @@ isif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * isif_get_format() - Retrieve the video format on a pad * @sd: VPFE ISIF V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ static int -isif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +isif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __isif_get_format(vpfe_isif, fh, fmt->pad, fmt->which); + format = __isif_get_format(vpfe_isif, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -1472,11 +1472,11 @@ isif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * isif_enum_frame_size() - enum frame sizes on pads * @sd: VPFE isif V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_frame_size_enum structure */ static int -isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); @@ -1490,7 +1490,7 @@ isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, format.format.width = 1; format.format.height = 1; format.which = V4L2_SUBDEV_FORMAT_TRY; - isif_try_format(isif, fh, &format); + isif_try_format(isif, cfg, &format); fse->min_width = format.format.width; fse->min_height = format.format.height; @@ -1502,7 +1502,7 @@ isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, format.format.width = -1; format.format.height = -1; format.which = V4L2_SUBDEV_FORMAT_TRY; - isif_try_format(isif, fh, &format); + isif_try_format(isif, cfg, &format); fse->max_width = format.format.width; fse->max_height = format.format.height; @@ -1512,11 +1512,11 @@ isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * isif_enum_mbus_code() - enum mbus codes for pads * @sd: VPFE isif V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_mbus_code_enum structure */ static int -isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { switch (code->pad) { @@ -1537,14 +1537,14 @@ isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * isif_pad_set_selection() - set crop rectangle on pad * @sd: VPFE isif V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_mbus_code_enum structure * * Return 0 on success, -EINVAL if pad is invalid */ static int isif_pad_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); @@ -1554,7 +1554,7 @@ isif_pad_set_selection(struct v4l2_subdev *sd, if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - format = __isif_get_format(vpfe_isif, fh, sel->pad, sel->which); + format = __isif_get_format(vpfe_isif, cfg, sel->pad, sel->which); if (format == NULL) return -EINVAL; @@ -1577,7 +1577,7 @@ isif_pad_set_selection(struct v4l2_subdev *sd, } else { struct v4l2_rect *rect; - rect = v4l2_subdev_get_try_crop(fh, ISIF_PAD_SINK); + rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK); memcpy(rect, &vpfe_isif->crop, sizeof(*rect)); } return 0; @@ -1586,14 +1586,14 @@ isif_pad_set_selection(struct v4l2_subdev *sd, /* * isif_pad_get_selection() - get crop rectangle on pad * @sd: VPFE isif V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_mbus_code_enum structure * * Return 0 on success, -EINVAL if pad is invalid */ static int isif_pad_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); @@ -1605,7 +1605,7 @@ isif_pad_get_selection(struct v4l2_subdev *sd, if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_rect *rect; - rect = v4l2_subdev_get_try_crop(fh, ISIF_PAD_SINK); + rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK); memcpy(&sel->r, rect, sizeof(*rect)); } else { sel->r = vpfe_isif->crop; @@ -1619,9 +1619,8 @@ isif_pad_get_selection(struct v4l2_subdev *sd, * @sd: VPFE isif V4L2 subdevice * @fh: V4L2 subdev file handle * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. + * Initialize all pad formats with default values. Try formats are initialized + * on the file handle. */ static int isif_init_formats(struct v4l2_subdev *sd, @@ -1632,27 +1631,27 @@ isif_init_formats(struct v4l2_subdev *sd, memset(&format, 0, sizeof(format)); format.pad = ISIF_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.which = V4L2_SUBDEV_FORMAT_TRY; format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; format.format.width = MAX_WIDTH; format.format.height = MAX_HEIGHT; - isif_set_format(sd, fh, &format); + isif_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = ISIF_PAD_SOURCE; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.which = V4L2_SUBDEV_FORMAT_TRY; format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; format.format.width = MAX_WIDTH; format.format.height = MAX_HEIGHT; - isif_set_format(sd, fh, &format); + isif_set_format(sd, fh->pad, &format); memset(&sel, 0, sizeof(sel)); sel.pad = ISIF_PAD_SINK; - sel.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + sel.which = V4L2_SUBDEV_FORMAT_TRY; sel.target = V4L2_SEL_TGT_CROP; sel.r.width = MAX_WIDTH; sel.r.height = MAX_HEIGHT; - isif_pad_set_selection(sd, fh, &sel); + isif_pad_set_selection(sd, fh->pad, &sel); return 0; } diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c index 75e70e14b724..acd9cb56f0f3 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c +++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.c @@ -1289,19 +1289,19 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable) /* * __resizer_get_format() - helper function for getting resizer format * @sd: pointer to subdev. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @pad: pad number. * @which: wanted subdev format. * Retun wanted mbus frame format. */ static struct v4l2_mbus_framefmt * -__resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +__resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(sd, cfg, pad); if (&resizer->crop_resizer.subdev == sd) return &resizer->crop_resizer.formats[pad]; if (&resizer->resizer_a.subdev == sd) @@ -1314,13 +1314,13 @@ __resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * resizer_try_format() - Handle try format by pad subdev method * @sd: pointer to subdev. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @pad: pad num. * @fmt: pointer to v4l2 format structure. * @which: wanted subdev format. */ static void -resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -1388,21 +1388,21 @@ resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * resizer_set_format() - Handle set format by pads subdev method * @sd: pointer to v4l2 subdev structure - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __resizer_get_format(sd, fh, fmt->pad, fmt->which); + format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - resizer_try_format(sd, fh, fmt->pad, &fmt->format, fmt->which); + resizer_try_format(sd, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) @@ -1448,16 +1448,16 @@ static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * resizer_get_format() - Retrieve the video format on a pad * @sd: pointer to v4l2 subdev structure. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *format; - format = __resizer_get_format(sd, fh, fmt->pad, fmt->which); + format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -1469,11 +1469,11 @@ static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * resizer_enum_frame_size() - enum frame sizes on pads * @sd: Pointer to subdevice. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_frame_size_enum structure. */ static int resizer_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct v4l2_mbus_framefmt format; @@ -1484,7 +1484,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - resizer_try_format(sd, fh, fse->pad, &format, + resizer_try_format(sd, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->min_width = format.width; fse->min_height = format.height; @@ -1495,7 +1495,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - resizer_try_format(sd, fh, fse->pad, &format, + resizer_try_format(sd, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->max_width = format.width; fse->max_height = format.height; @@ -1506,11 +1506,11 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, /* * resizer_enum_mbus_code() - enum mbus codes for pads * @sd: Pointer to subdevice. - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_mbus_code_enum structure */ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->pad == RESIZER_PAD_SINK) { @@ -1533,14 +1533,13 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, * @sd: Pointer to subdevice. * @fh: V4L2 subdev file handle. * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. + * Initialize all pad formats with default values. Try formats are + * initialized on the file handle. */ static int resizer_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - __u32 which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + __u32 which = V4L2_SUBDEV_FORMAT_TRY; struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); struct v4l2_subdev_format format; @@ -1551,7 +1550,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; format.format.width = MAX_IN_WIDTH; format.format.height = MAX_IN_HEIGHT; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = RESIZER_CROP_PAD_SOURCE; @@ -1559,7 +1558,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; format.format.width = MAX_IN_WIDTH; format.format.height = MAX_IN_WIDTH; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = RESIZER_CROP_PAD_SOURCE2; @@ -1567,7 +1566,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; format.format.width = MAX_IN_WIDTH; format.format.height = MAX_IN_WIDTH; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); } else if (&resizer->resizer_a.subdev == sd) { memset(&format, 0, sizeof(format)); format.pad = RESIZER_PAD_SINK; @@ -1575,7 +1574,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; format.format.width = MAX_IN_WIDTH; format.format.height = MAX_IN_HEIGHT; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = RESIZER_PAD_SOURCE; @@ -1583,7 +1582,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); } else if (&resizer->resizer_b.subdev == sd) { memset(&format, 0, sizeof(format)); format.pad = RESIZER_PAD_SINK; @@ -1591,7 +1590,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; format.format.width = MAX_IN_WIDTH; format.format.height = MAX_IN_HEIGHT; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = RESIZER_PAD_SOURCE; @@ -1599,7 +1598,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; format.format.width = IPIPE_MAX_OUTPUT_WIDTH_B; format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_B; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); } return 0; diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c index 2d96fb3eca53..e404ad4fd987 100644 --- a/drivers/staging/media/omap4iss/iss_csi2.c +++ b/drivers/staging/media/omap4iss/iss_csi2.c @@ -828,17 +828,17 @@ static const struct iss_video_operations csi2_issvideo_ops = { */ static struct v4l2_mbus_framefmt * -__csi2_get_format(struct iss_csi2_device *csi2, struct v4l2_subdev_fh *fh, +__csi2_get_format(struct iss_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad); return &csi2->formats[pad]; } static void -csi2_try_format(struct iss_csi2_device *csi2, struct v4l2_subdev_fh *fh, +csi2_try_format(struct iss_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -868,7 +868,7 @@ csi2_try_format(struct iss_csi2_device *csi2, struct v4l2_subdev_fh *fh, * compression. */ pixelcode = fmt->code; - format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which); + format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); /* @@ -889,12 +889,12 @@ csi2_try_format(struct iss_csi2_device *csi2, struct v4l2_subdev_fh *fh, /* * csi2_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg : V4L2 subdev pad config * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); @@ -907,7 +907,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, code->code = csi2_input_fmts[code->index]; } else { - format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, + format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, V4L2_SUBDEV_FORMAT_TRY); switch (code->index) { case 0: @@ -931,7 +931,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, } static int csi2_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); @@ -943,7 +943,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + csi2_try_format(csi2, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->min_width = format.width; fse->min_height = format.height; @@ -953,7 +953,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + csi2_try_format(csi2, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->max_width = format.width; fse->max_height = format.height; @@ -963,17 +963,17 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, /* * csi2_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); + format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -984,29 +984,29 @@ static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * csi2_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); + format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which); + csi2_try_format(csi2, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == CSI2_PAD_SINK) { - format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE, + format = __csi2_get_format(csi2, cfg, CSI2_PAD_SOURCE, fmt->which); *format = fmt->format; - csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which); + csi2_try_format(csi2, cfg, CSI2_PAD_SOURCE, format, fmt->which); } return 0; @@ -1048,7 +1048,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - csi2_set_format(sd, fh, &format); + csi2_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/staging/media/omap4iss/iss_ipipe.c b/drivers/staging/media/omap4iss/iss_ipipe.c index a1a46ef8319b..fc319822a33e 100644 --- a/drivers/staging/media/omap4iss/iss_ipipe.c +++ b/drivers/staging/media/omap4iss/iss_ipipe.c @@ -24,7 +24,7 @@ #include "iss_ipipe.h" static struct v4l2_mbus_framefmt * -__ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh, +__ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which); static const unsigned int ipipe_fmts[] = { @@ -176,11 +176,11 @@ static int ipipe_set_stream(struct v4l2_subdev *sd, int enable) } static struct v4l2_mbus_framefmt * -__ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh, +__ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&ipipe->subdev, cfg, pad); return &ipipe->formats[pad]; } @@ -188,12 +188,12 @@ __ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh, /* * ipipe_try_format - Try video format on a pad * @ipipe: ISS IPIPE device - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @pad: Pad number * @fmt: Format */ static void -ipipe_try_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh, +ipipe_try_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -220,7 +220,7 @@ ipipe_try_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh, break; case IPIPE_PAD_SOURCE_VP: - format = __ipipe_get_format(ipipe, fh, IPIPE_PAD_SINK, which); + format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; @@ -236,12 +236,12 @@ ipipe_try_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh, /* * ipipe_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg : V4L2 subdev pad config * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int ipipe_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { switch (code->pad) { @@ -268,7 +268,7 @@ static int ipipe_enum_mbus_code(struct v4l2_subdev *sd, } static int ipipe_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); @@ -280,7 +280,7 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - ipipe_try_format(ipipe, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + ipipe_try_format(ipipe, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->min_width = format.width; fse->min_height = format.height; @@ -290,7 +290,7 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - ipipe_try_format(ipipe, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + ipipe_try_format(ipipe, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->max_width = format.width; fse->max_height = format.height; @@ -300,19 +300,19 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd, /* * ipipe_get_format - Retrieve the video format on a pad * @sd : ISP IPIPE V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipe_get_format(ipipe, fh, fmt->pad, fmt->which); + format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -323,31 +323,31 @@ static int ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ipipe_set_format - Set the video format on a pad * @sd : ISP IPIPE V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipe_get_format(ipipe, fh, fmt->pad, fmt->which); + format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - ipipe_try_format(ipipe, fh, fmt->pad, &fmt->format, fmt->which); + ipipe_try_format(ipipe, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == IPIPE_PAD_SINK) { - format = __ipipe_get_format(ipipe, fh, IPIPE_PAD_SOURCE_VP, + format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP, fmt->which); *format = fmt->format; - ipipe_try_format(ipipe, fh, IPIPE_PAD_SOURCE_VP, format, + ipipe_try_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP, format, fmt->which); } @@ -388,7 +388,7 @@ static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - ipipe_set_format(sd, fh, &format); + ipipe_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c index 3943fae699ee..948edcca8704 100644 --- a/drivers/staging/media/omap4iss/iss_ipipeif.c +++ b/drivers/staging/media/omap4iss/iss_ipipeif.c @@ -361,24 +361,24 @@ static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable) static struct v4l2_mbus_framefmt * __ipipeif_get_format(struct iss_ipipeif_device *ipipeif, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&ipipeif->subdev, cfg, pad); return &ipipeif->formats[pad]; } /* * ipipeif_try_format - Try video format on a pad * @ipipeif: ISS IPIPEIF device - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @pad: Pad number * @fmt: Format */ static void ipipeif_try_format(struct iss_ipipeif_device *ipipeif, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -407,7 +407,7 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif, break; case IPIPEIF_PAD_SOURCE_ISIF_SF: - format = __ipipeif_get_format(ipipeif, fh, IPIPEIF_PAD_SINK, + format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); @@ -422,7 +422,7 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif, break; case IPIPEIF_PAD_SOURCE_VP: - format = __ipipeif_get_format(ipipeif, fh, IPIPEIF_PAD_SINK, + format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); @@ -441,12 +441,12 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif, /* * ipipeif_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg : V4L2 subdev pad config * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); @@ -466,7 +466,7 @@ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, if (code->index != 0) return -EINVAL; - format = __ipipeif_get_format(ipipeif, fh, IPIPEIF_PAD_SINK, + format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, V4L2_SUBDEV_FORMAT_TRY); code->code = format->code; @@ -480,7 +480,7 @@ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, } static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); @@ -492,7 +492,7 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - ipipeif_try_format(ipipeif, fh, fse->pad, &format, + ipipeif_try_format(ipipeif, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->min_width = format.width; fse->min_height = format.height; @@ -503,7 +503,7 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - ipipeif_try_format(ipipeif, fh, fse->pad, &format, + ipipeif_try_format(ipipeif, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->max_width = format.width; fse->max_height = format.height; @@ -514,19 +514,19 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, /* * ipipeif_get_format - Retrieve the video format on a pad * @sd : ISP IPIPEIF V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipeif_get_format(ipipeif, fh, fmt->pad, fmt->which); + format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -537,39 +537,39 @@ static int ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ipipeif_set_format - Set the video format on a pad * @sd : ISP IPIPEIF V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipeif_get_format(ipipeif, fh, fmt->pad, fmt->which); + format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - ipipeif_try_format(ipipeif, fh, fmt->pad, &fmt->format, fmt->which); + ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == IPIPEIF_PAD_SINK) { - format = __ipipeif_get_format(ipipeif, fh, + format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_ISIF_SF, fmt->which); *format = fmt->format; - ipipeif_try_format(ipipeif, fh, IPIPEIF_PAD_SOURCE_ISIF_SF, + ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_ISIF_SF, format, fmt->which); - format = __ipipeif_get_format(ipipeif, fh, + format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_VP, fmt->which); *format = fmt->format; - ipipeif_try_format(ipipeif, fh, IPIPEIF_PAD_SOURCE_VP, format, + ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_VP, format, fmt->which); } @@ -612,7 +612,7 @@ static int ipipeif_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - ipipeif_set_format(sd, fh, &format); + ipipeif_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c index 3ab972818f1b..f9b0aac91e9d 100644 --- a/drivers/staging/media/omap4iss/iss_resizer.c +++ b/drivers/staging/media/omap4iss/iss_resizer.c @@ -420,24 +420,24 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable) static struct v4l2_mbus_framefmt * __resizer_get_format(struct iss_resizer_device *resizer, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&resizer->subdev, cfg, pad); return &resizer->formats[pad]; } /* * resizer_try_format - Try video format on a pad * @resizer: ISS RESIZER device - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @pad: Pad number * @fmt: Format */ static void resizer_try_format(struct iss_resizer_device *resizer, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -465,7 +465,7 @@ resizer_try_format(struct iss_resizer_device *resizer, case RESIZER_PAD_SOURCE_MEM: pixelcode = fmt->code; - format = __resizer_get_format(resizer, fh, RESIZER_PAD_SINK, + format = __resizer_get_format(resizer, cfg, RESIZER_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); @@ -492,12 +492,12 @@ resizer_try_format(struct iss_resizer_device *resizer, /* * resizer_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); @@ -512,7 +512,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, break; case RESIZER_PAD_SOURCE_MEM: - format = __resizer_get_format(resizer, fh, RESIZER_PAD_SINK, + format = __resizer_get_format(resizer, cfg, RESIZER_PAD_SINK, V4L2_SUBDEV_FORMAT_TRY); if (code->index == 0) { @@ -542,7 +542,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, } static int resizer_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); @@ -554,7 +554,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - resizer_try_format(resizer, fh, fse->pad, &format, + resizer_try_format(resizer, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->min_width = format.width; fse->min_height = format.height; @@ -565,7 +565,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - resizer_try_format(resizer, fh, fse->pad, &format, + resizer_try_format(resizer, cfg, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); fse->max_width = format.width; fse->max_height = format.height; @@ -576,19 +576,19 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, /* * resizer_get_format - Retrieve the video format on a pad * @sd : ISP RESIZER V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __resizer_get_format(resizer, fh, fmt->pad, fmt->which); + format = __resizer_get_format(resizer, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -599,32 +599,32 @@ static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * resizer_set_format - Set the video format on a pad * @sd : ISP RESIZER V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __resizer_get_format(resizer, fh, fmt->pad, fmt->which); + format = __resizer_get_format(resizer, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - resizer_try_format(resizer, fh, fmt->pad, &fmt->format, fmt->which); + resizer_try_format(resizer, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == RESIZER_PAD_SINK) { - format = __resizer_get_format(resizer, fh, + format = __resizer_get_format(resizer, cfg, RESIZER_PAD_SOURCE_MEM, fmt->which); *format = fmt->format; - resizer_try_format(resizer, fh, RESIZER_PAD_SOURCE_MEM, format, + resizer_try_format(resizer, cfg, RESIZER_PAD_SOURCE_MEM, format, fmt->which); } @@ -667,7 +667,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_UYVY8_1X16; format.format.width = 4096; format.format.height = 4096; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 5beeb8744fd1..d9404df80482 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -482,6 +482,18 @@ struct v4l2_subdev_ir_ops { struct v4l2_subdev_ir_parameters *params); }; +/* + * Used for storing subdev pad information. This structure only needs + * to be passed to the pad op if the 'which' field of the main argument + * is set to V4L2_SUBDEV_FORMAT_TRY. For V4L2_SUBDEV_FORMAT_ACTIVE it is + * safe to pass NULL. + */ +struct v4l2_subdev_pad_config { + struct v4l2_mbus_framefmt try_fmt; + struct v4l2_rect try_crop; + struct v4l2_rect try_compose; +}; + /** * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations * @get_frame_desc: get the current low level media bus frame parameters. @@ -489,21 +501,26 @@ struct v4l2_subdev_ir_ops { * may be adjusted by the subdev driver to device capabilities. */ struct v4l2_subdev_pad_ops { - int (*enum_mbus_code)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + int (*enum_mbus_code)(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code); int (*enum_frame_size)(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse); int (*enum_frame_interval)(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_interval_enum *fie); - int (*get_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + int (*get_fmt)(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format); - int (*set_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + int (*set_fmt)(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format); - int (*get_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + int (*get_selection)(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel); - int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + int (*set_selection)(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel); int (*get_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid); int (*set_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid); @@ -625,11 +642,7 @@ struct v4l2_subdev { struct v4l2_subdev_fh { struct v4l2_fh vfh; #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) - struct { - struct v4l2_mbus_framefmt try_fmt; - struct v4l2_rect try_crop; - struct v4l2_rect try_compose; - } *pad; + struct v4l2_subdev_pad_config *pad; #endif }; @@ -639,17 +652,17 @@ struct v4l2_subdev_fh { #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) #define __V4L2_SUBDEV_MK_GET_TRY(rtype, fun_name, field_name) \ static inline struct rtype * \ - v4l2_subdev_get_try_##fun_name(struct v4l2_subdev_fh *fh, \ - unsigned int pad) \ + fun_name(struct v4l2_subdev *sd, \ + struct v4l2_subdev_pad_config *cfg, \ + unsigned int pad) \ { \ - BUG_ON(pad >= vdev_to_v4l2_subdev( \ - fh->vfh.vdev)->entity.num_pads); \ - return &fh->pad[pad].field_name; \ + BUG_ON(pad >= sd->entity.num_pads); \ + return &cfg[pad].field_name; \ } -__V4L2_SUBDEV_MK_GET_TRY(v4l2_mbus_framefmt, format, try_fmt) -__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, crop, try_crop) -__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, compose, try_compose) +__V4L2_SUBDEV_MK_GET_TRY(v4l2_mbus_framefmt, v4l2_subdev_get_try_format, try_fmt) +__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, v4l2_subdev_get_try_crop, try_crop) +__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, v4l2_subdev_get_try_compose, try_compose) #endif extern const struct v4l2_file_operations v4l2_subdev_fops; -- cgit v1.2.3 From e1c47e732cbb4211d15ae0c4465dc4ceefcaa398 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 4 Mar 2015 01:47:55 -0800 Subject: [media] v4l2-subdev.h: add 'which' field for the enum structs While all other pad ops allow you to select whether to use the 'try' or the 'active' formats, the enum ops didn't have that option and always used 'try'. However, this will fail if a simple (e.g. PCI) bridge driver wants to use the enum pad op of a subdev that's also used in a complex platform driver like the omap3. Such a bridge driver generally wants to enum formats based on the active format. So add a new 'which' field to these structs. Note that V4L2_SUBDEV_FORMAT_TRY is 0, so the default remains TRY (applications need to set reserved to 0). Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Acked-by: Laurent Pinchart Acked-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/v4l2-subdev.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h index e0a7e3da498a..dbce2b554e02 100644 --- a/include/uapi/linux/v4l2-subdev.h +++ b/include/uapi/linux/v4l2-subdev.h @@ -69,12 +69,14 @@ struct v4l2_subdev_crop { * @pad: pad number, as reported by the media API * @index: format index during enumeration * @code: format code (MEDIA_BUS_FMT_ definitions) + * @which: format type (from enum v4l2_subdev_format_whence) */ struct v4l2_subdev_mbus_code_enum { __u32 pad; __u32 index; __u32 code; - __u32 reserved[9]; + __u32 which; + __u32 reserved[8]; }; /** @@ -82,6 +84,7 @@ struct v4l2_subdev_mbus_code_enum { * @pad: pad number, as reported by the media API * @index: format index during enumeration * @code: format code (MEDIA_BUS_FMT_ definitions) + * @which: format type (from enum v4l2_subdev_format_whence) */ struct v4l2_subdev_frame_size_enum { __u32 index; @@ -91,7 +94,8 @@ struct v4l2_subdev_frame_size_enum { __u32 max_width; __u32 min_height; __u32 max_height; - __u32 reserved[9]; + __u32 which; + __u32 reserved[8]; }; /** @@ -113,6 +117,7 @@ struct v4l2_subdev_frame_interval { * @width: frame width in pixels * @height: frame height in pixels * @interval: frame interval in seconds + * @which: format type (from enum v4l2_subdev_format_whence) */ struct v4l2_subdev_frame_interval_enum { __u32 index; @@ -121,7 +126,8 @@ struct v4l2_subdev_frame_interval_enum { __u32 width; __u32 height; struct v4l2_fract interval; - __u32 reserved[9]; + __u32 which; + __u32 reserved[8]; }; /** -- cgit v1.2.3 From 8a56b6b5fd6ff92b7e27d870b803b11b751660c2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 4 Mar 2015 01:48:01 -0800 Subject: [media] v4l2-subdev: remove enum_framesizes/intervals The video and pad ops are duplicates, so get rid of the more limited video op. The whole point of the subdev API is to allow reuse of subdev drivers by bridge drivers. Having duplicate ops makes that much harder. We should never have allowed duplicate ops in the first place. A lesson for the future. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-subdev.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index d9404df80482..2f0a345a7fed 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -332,8 +332,6 @@ struct v4l2_subdev_video_ops { struct v4l2_subdev_frame_interval *interval); int (*s_frame_interval)(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval); - int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize); - int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival); int (*s_dv_timings)(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings); int (*g_dv_timings)(struct v4l2_subdev *sd, -- cgit v1.2.3 From a5408ec6057e40d56b1c04608f07d21c5163ced0 Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Wed, 18 Mar 2015 16:08:21 +0200 Subject: dt-bindings: Add #defines for MSM8916 clocks and resets Add clocks/resets defines for the global clock controller found on Qualcomm MSM8916 SoCs. Signed-off-by: Georgi Djakov Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/qcom,gcc.txt | 1 + include/dt-bindings/clock/qcom,gcc-msm8916.h | 156 +++++++++++++++++++++ include/dt-bindings/reset/qcom,gcc-msm8916.h | 108 ++++++++++++++ 3 files changed, 265 insertions(+) create mode 100644 include/dt-bindings/clock/qcom,gcc-msm8916.h create mode 100644 include/dt-bindings/reset/qcom,gcc-msm8916.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index aba3d254e037..54c23f34f194 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -8,6 +8,7 @@ Required properties : "qcom,gcc-apq8084" "qcom,gcc-ipq8064" "qcom,gcc-msm8660" + "qcom,gcc-msm8916" "qcom,gcc-msm8960" "qcom,gcc-msm8974" "qcom,gcc-msm8974pro" diff --git a/include/dt-bindings/clock/qcom,gcc-msm8916.h b/include/dt-bindings/clock/qcom,gcc-msm8916.h new file mode 100644 index 000000000000..e430f644dd6c --- /dev/null +++ b/include/dt-bindings/clock/qcom,gcc-msm8916.h @@ -0,0 +1,156 @@ +/* + * Copyright 2015 Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_CLK_MSM_GCC_8916_H +#define _DT_BINDINGS_CLK_MSM_GCC_8916_H + +#define GPLL0 0 +#define GPLL0_VOTE 1 +#define BIMC_PLL 2 +#define BIMC_PLL_VOTE 3 +#define GPLL1 4 +#define GPLL1_VOTE 5 +#define GPLL2 6 +#define GPLL2_VOTE 7 +#define PCNOC_BFDCD_CLK_SRC 8 +#define SYSTEM_NOC_BFDCD_CLK_SRC 9 +#define CAMSS_AHB_CLK_SRC 10 +#define APSS_AHB_CLK_SRC 11 +#define CSI0_CLK_SRC 12 +#define CSI1_CLK_SRC 13 +#define GFX3D_CLK_SRC 14 +#define VFE0_CLK_SRC 15 +#define BLSP1_QUP1_I2C_APPS_CLK_SRC 16 +#define BLSP1_QUP1_SPI_APPS_CLK_SRC 17 +#define BLSP1_QUP2_I2C_APPS_CLK_SRC 18 +#define BLSP1_QUP2_SPI_APPS_CLK_SRC 19 +#define BLSP1_QUP3_I2C_APPS_CLK_SRC 20 +#define BLSP1_QUP3_SPI_APPS_CLK_SRC 21 +#define BLSP1_QUP4_I2C_APPS_CLK_SRC 22 +#define BLSP1_QUP4_SPI_APPS_CLK_SRC 23 +#define BLSP1_QUP5_I2C_APPS_CLK_SRC 24 +#define BLSP1_QUP5_SPI_APPS_CLK_SRC 25 +#define BLSP1_QUP6_I2C_APPS_CLK_SRC 26 +#define BLSP1_QUP6_SPI_APPS_CLK_SRC 27 +#define BLSP1_UART1_APPS_CLK_SRC 28 +#define BLSP1_UART2_APPS_CLK_SRC 29 +#define CCI_CLK_SRC 30 +#define CAMSS_GP0_CLK_SRC 31 +#define CAMSS_GP1_CLK_SRC 32 +#define JPEG0_CLK_SRC 33 +#define MCLK0_CLK_SRC 34 +#define MCLK1_CLK_SRC 35 +#define CSI0PHYTIMER_CLK_SRC 36 +#define CSI1PHYTIMER_CLK_SRC 37 +#define CPP_CLK_SRC 38 +#define CRYPTO_CLK_SRC 39 +#define GP1_CLK_SRC 40 +#define GP2_CLK_SRC 41 +#define GP3_CLK_SRC 42 +#define BYTE0_CLK_SRC 43 +#define ESC0_CLK_SRC 44 +#define MDP_CLK_SRC 45 +#define PCLK0_CLK_SRC 46 +#define VSYNC_CLK_SRC 47 +#define PDM2_CLK_SRC 48 +#define SDCC1_APPS_CLK_SRC 49 +#define SDCC2_APPS_CLK_SRC 50 +#define APSS_TCU_CLK_SRC 51 +#define USB_HS_SYSTEM_CLK_SRC 52 +#define VCODEC0_CLK_SRC 53 +#define GCC_BLSP1_AHB_CLK 54 +#define GCC_BLSP1_SLEEP_CLK 55 +#define GCC_BLSP1_QUP1_I2C_APPS_CLK 56 +#define GCC_BLSP1_QUP1_SPI_APPS_CLK 57 +#define GCC_BLSP1_QUP2_I2C_APPS_CLK 58 +#define GCC_BLSP1_QUP2_SPI_APPS_CLK 59 +#define GCC_BLSP1_QUP3_I2C_APPS_CLK 60 +#define GCC_BLSP1_QUP3_SPI_APPS_CLK 61 +#define GCC_BLSP1_QUP4_I2C_APPS_CLK 62 +#define GCC_BLSP1_QUP4_SPI_APPS_CLK 63 +#define GCC_BLSP1_QUP5_I2C_APPS_CLK 64 +#define GCC_BLSP1_QUP5_SPI_APPS_CLK 65 +#define GCC_BLSP1_QUP6_I2C_APPS_CLK 66 +#define GCC_BLSP1_QUP6_SPI_APPS_CLK 67 +#define GCC_BLSP1_UART1_APPS_CLK 68 +#define GCC_BLSP1_UART2_APPS_CLK 69 +#define GCC_BOOT_ROM_AHB_CLK 70 +#define GCC_CAMSS_CCI_AHB_CLK 71 +#define GCC_CAMSS_CCI_CLK 72 +#define GCC_CAMSS_CSI0_AHB_CLK 73 +#define GCC_CAMSS_CSI0_CLK 74 +#define GCC_CAMSS_CSI0PHY_CLK 75 +#define GCC_CAMSS_CSI0PIX_CLK 76 +#define GCC_CAMSS_CSI0RDI_CLK 77 +#define GCC_CAMSS_CSI1_AHB_CLK 78 +#define GCC_CAMSS_CSI1_CLK 79 +#define GCC_CAMSS_CSI1PHY_CLK 80 +#define GCC_CAMSS_CSI1PIX_CLK 81 +#define GCC_CAMSS_CSI1RDI_CLK 82 +#define GCC_CAMSS_CSI_VFE0_CLK 83 +#define GCC_CAMSS_GP0_CLK 84 +#define GCC_CAMSS_GP1_CLK 85 +#define GCC_CAMSS_ISPIF_AHB_CLK 86 +#define GCC_CAMSS_JPEG0_CLK 87 +#define GCC_CAMSS_JPEG_AHB_CLK 88 +#define GCC_CAMSS_JPEG_AXI_CLK 89 +#define GCC_CAMSS_MCLK0_CLK 90 +#define GCC_CAMSS_MCLK1_CLK 91 +#define GCC_CAMSS_MICRO_AHB_CLK 92 +#define GCC_CAMSS_CSI0PHYTIMER_CLK 93 +#define GCC_CAMSS_CSI1PHYTIMER_CLK 94 +#define GCC_CAMSS_AHB_CLK 95 +#define GCC_CAMSS_TOP_AHB_CLK 96 +#define GCC_CAMSS_CPP_AHB_CLK 97 +#define GCC_CAMSS_CPP_CLK 98 +#define GCC_CAMSS_VFE0_CLK 99 +#define GCC_CAMSS_VFE_AHB_CLK 100 +#define GCC_CAMSS_VFE_AXI_CLK 101 +#define GCC_CRYPTO_AHB_CLK 102 +#define GCC_CRYPTO_AXI_CLK 103 +#define GCC_CRYPTO_CLK 104 +#define GCC_OXILI_GMEM_CLK 105 +#define GCC_GP1_CLK 106 +#define GCC_GP2_CLK 107 +#define GCC_GP3_CLK 108 +#define GCC_MDSS_AHB_CLK 109 +#define GCC_MDSS_AXI_CLK 110 +#define GCC_MDSS_BYTE0_CLK 111 +#define GCC_MDSS_ESC0_CLK 112 +#define GCC_MDSS_MDP_CLK 113 +#define GCC_MDSS_PCLK0_CLK 114 +#define GCC_MDSS_VSYNC_CLK 115 +#define GCC_MSS_CFG_AHB_CLK 116 +#define GCC_OXILI_AHB_CLK 117 +#define GCC_OXILI_GFX3D_CLK 118 +#define GCC_PDM2_CLK 119 +#define GCC_PDM_AHB_CLK 120 +#define GCC_PRNG_AHB_CLK 121 +#define GCC_SDCC1_AHB_CLK 122 +#define GCC_SDCC1_APPS_CLK 123 +#define GCC_SDCC2_AHB_CLK 124 +#define GCC_SDCC2_APPS_CLK 125 +#define GCC_GTCU_AHB_CLK 126 +#define GCC_JPEG_TBU_CLK 127 +#define GCC_MDP_TBU_CLK 128 +#define GCC_SMMU_CFG_CLK 129 +#define GCC_VENUS_TBU_CLK 130 +#define GCC_VFE_TBU_CLK 131 +#define GCC_USB2A_PHY_SLEEP_CLK 132 +#define GCC_USB_HS_AHB_CLK 133 +#define GCC_USB_HS_SYSTEM_CLK 134 +#define GCC_VENUS0_AHB_CLK 135 +#define GCC_VENUS0_AXI_CLK 136 +#define GCC_VENUS0_VCODEC0_CLK 137 + +#endif diff --git a/include/dt-bindings/reset/qcom,gcc-msm8916.h b/include/dt-bindings/reset/qcom,gcc-msm8916.h new file mode 100644 index 000000000000..3d90410f09c7 --- /dev/null +++ b/include/dt-bindings/reset/qcom,gcc-msm8916.h @@ -0,0 +1,108 @@ +/* + * Copyright 2015 Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_RESET_MSM_GCC_8916_H +#define _DT_BINDINGS_RESET_MSM_GCC_8916_H + +#define GCC_BLSP1_BCR 0 +#define GCC_BLSP1_QUP1_BCR 1 +#define GCC_BLSP1_UART1_BCR 2 +#define GCC_BLSP1_QUP2_BCR 3 +#define GCC_BLSP1_UART2_BCR 4 +#define GCC_BLSP1_QUP3_BCR 5 +#define GCC_BLSP1_QUP4_BCR 6 +#define GCC_BLSP1_QUP5_BCR 7 +#define GCC_BLSP1_QUP6_BCR 8 +#define GCC_IMEM_BCR 9 +#define GCC_SMMU_BCR 10 +#define GCC_APSS_TCU_BCR 11 +#define GCC_SMMU_XPU_BCR 12 +#define GCC_PCNOC_TBU_BCR 13 +#define GCC_PRNG_BCR 14 +#define GCC_BOOT_ROM_BCR 15 +#define GCC_CRYPTO_BCR 16 +#define GCC_SEC_CTRL_BCR 17 +#define GCC_AUDIO_CORE_BCR 18 +#define GCC_ULT_AUDIO_BCR 19 +#define GCC_DEHR_BCR 20 +#define GCC_SYSTEM_NOC_BCR 21 +#define GCC_PCNOC_BCR 22 +#define GCC_TCSR_BCR 23 +#define GCC_QDSS_BCR 24 +#define GCC_DCD_BCR 25 +#define GCC_MSG_RAM_BCR 26 +#define GCC_MPM_BCR 27 +#define GCC_SPMI_BCR 28 +#define GCC_SPDM_BCR 29 +#define GCC_MM_SPDM_BCR 30 +#define GCC_BIMC_BCR 31 +#define GCC_RBCPR_BCR 32 +#define GCC_TLMM_BCR 33 +#define GCC_USB_HS_BCR 34 +#define GCC_USB2A_PHY_BCR 35 +#define GCC_SDCC1_BCR 36 +#define GCC_SDCC2_BCR 37 +#define GCC_PDM_BCR 38 +#define GCC_SNOC_BUS_TIMEOUT0_BCR 39 +#define GCC_PCNOC_BUS_TIMEOUT0_BCR 40 +#define GCC_PCNOC_BUS_TIMEOUT1_BCR 41 +#define GCC_PCNOC_BUS_TIMEOUT2_BCR 42 +#define GCC_PCNOC_BUS_TIMEOUT3_BCR 43 +#define GCC_PCNOC_BUS_TIMEOUT4_BCR 44 +#define GCC_PCNOC_BUS_TIMEOUT5_BCR 45 +#define GCC_PCNOC_BUS_TIMEOUT6_BCR 46 +#define GCC_PCNOC_BUS_TIMEOUT7_BCR 47 +#define GCC_PCNOC_BUS_TIMEOUT8_BCR 48 +#define GCC_PCNOC_BUS_TIMEOUT9_BCR 49 +#define GCC_MMSS_BCR 50 +#define GCC_VENUS0_BCR 51 +#define GCC_MDSS_BCR 52 +#define GCC_CAMSS_PHY0_BCR 53 +#define GCC_CAMSS_CSI0_BCR 54 +#define GCC_CAMSS_CSI0PHY_BCR 55 +#define GCC_CAMSS_CSI0RDI_BCR 56 +#define GCC_CAMSS_CSI0PIX_BCR 57 +#define GCC_CAMSS_PHY1_BCR 58 +#define GCC_CAMSS_CSI1_BCR 59 +#define GCC_CAMSS_CSI1PHY_BCR 60 +#define GCC_CAMSS_CSI1RDI_BCR 61 +#define GCC_CAMSS_CSI1PIX_BCR 62 +#define GCC_CAMSS_ISPIF_BCR 63 +#define GCC_CAMSS_CCI_BCR 64 +#define GCC_CAMSS_MCLK0_BCR 65 +#define GCC_CAMSS_MCLK1_BCR 66 +#define GCC_CAMSS_GP0_BCR 67 +#define GCC_CAMSS_GP1_BCR 68 +#define GCC_CAMSS_TOP_BCR 69 +#define GCC_CAMSS_MICRO_BCR 70 +#define GCC_CAMSS_JPEG_BCR 71 +#define GCC_CAMSS_VFE_BCR 72 +#define GCC_CAMSS_CSI_VFE0_BCR 73 +#define GCC_OXILI_BCR 74 +#define GCC_GMEM_BCR 75 +#define GCC_CAMSS_AHB_BCR 76 +#define GCC_MDP_TBU_BCR 77 +#define GCC_GFX_TBU_BCR 78 +#define GCC_GFX_TCU_BCR 79 +#define GCC_MSS_TBU_AXI_BCR 80 +#define GCC_MSS_TBU_GSS_AXI_BCR 81 +#define GCC_MSS_TBU_Q6_AXI_BCR 82 +#define GCC_GTCU_AHB_BCR 83 +#define GCC_SMMU_CFG_BCR 84 +#define GCC_VFE_TBU_BCR 85 +#define GCC_VENUS_TBU_BCR 86 +#define GCC_JPEG_TBU_BCR 87 +#define GCC_PRONTO_TBU_BCR 88 +#define GCC_SMMU_CATS_BCR 89 + +#endif -- cgit v1.2.3 From 2f921b5bb0511fb698681d8ef35c48be7a9116bf Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 24 Mar 2015 11:51:39 +1030 Subject: lguest: suppress interrupts for single insn, not range. The last patch reduced our interrupt-suppression region to one address, so simplify the code somewhat. Also, remove the obsolete undefined instruction ranges and the comment which refers to lguest_guest.S instead of head_32.S. Signed-off-by: Rusty Russell --- arch/x86/include/asm/lguest.h | 7 ++----- arch/x86/lguest/boot.c | 3 +-- arch/x86/lguest/head_32.S | 15 ++++++--------- drivers/lguest/hypercalls.c | 5 ++--- drivers/lguest/interrupts_and_traps.c | 8 ++++---- drivers/lguest/lg.h | 2 +- include/linux/lguest.h | 4 ++-- 7 files changed, 18 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/arch/x86/include/asm/lguest.h b/arch/x86/include/asm/lguest.h index e2d4a4afa8c3..3bbc07a57a31 100644 --- a/arch/x86/include/asm/lguest.h +++ b/arch/x86/include/asm/lguest.h @@ -20,13 +20,10 @@ extern unsigned long switcher_addr; /* Found in switcher.S */ extern unsigned long default_idt_entries[]; -/* Declarations for definitions in lguest_guest.S */ -extern char lguest_noirq_start[], lguest_noirq_end[]; +/* Declarations for definitions in arch/x86/lguest/head_32.S */ +extern char lguest_noirq_iret[]; extern const char lgstart_cli[], lgend_cli[]; -extern const char lgstart_sti[], lgend_sti[]; -extern const char lgstart_popf[], lgend_popf[]; extern const char lgstart_pushf[], lgend_pushf[]; -extern const char lgstart_iret[], lgend_iret[]; extern void lguest_iret(void); extern void lguest_init(void); diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 543510a2f9e0..13616d708389 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -87,8 +87,7 @@ struct lguest_data lguest_data = { .hcall_status = { [0 ... LHCALL_RING_SIZE-1] = 0xFF }, - .noirq_start = (u32)lguest_noirq_start, - .noirq_end = (u32)lguest_noirq_end, + .noirq_iret = (u32)lguest_noirq_iret, .kernel_address = PAGE_OFFSET, .blocked_interrupts = { 1 }, /* Block timer interrupts */ .syscall_vec = SYSCALL_VECTOR, diff --git a/arch/x86/lguest/head_32.S b/arch/x86/lguest/head_32.S index 81678bf0fcb7..d5ae63f5ec5d 100644 --- a/arch/x86/lguest/head_32.S +++ b/arch/x86/lguest/head_32.S @@ -133,9 +133,8 @@ ENTRY(lg_restore_fl) ret /*:*/ -/* These demark the EIP range where host should never deliver interrupts. */ -.global lguest_noirq_start -.global lguest_noirq_end +/* These demark the EIP where host should never deliver interrupts. */ +.global lguest_noirq_iret /*M:004 * When the Host reflects a trap or injects an interrupt into the Guest, it @@ -174,12 +173,11 @@ ENTRY(lg_restore_fl) * * The second is harder: copying eflags to lguest_data.irq_enabled will turn * interrupts on before we're finished, so we could be interrupted before we - * return to userspace or wherever. Our solution to this is to surround the - * code with lguest_noirq_start: and lguest_noirq_end: labels. We tell the + * return to userspace or wherever. Our solution to this is to tell the * Host that it is *never* to interrupt us there, even if interrupts seem to be * enabled. (It's not necessary to protect pop instruction, since - * data gets updated only after it completes, so we end up surrounding - * just one instruction, iret). + * data gets updated only after it completes, so we only need to protect + * one instruction, iret). */ ENTRY(lguest_iret) pushl 2*4(%esp) @@ -190,6 +188,5 @@ ENTRY(lguest_iret) * prefix makes sure we use the stack segment, which is still valid. */ popl %ss:lguest_data+LGUEST_DATA_irq_enabled -lguest_noirq_start: +lguest_noirq_iret: iret -lguest_noirq_end: diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c index 1219af493c0f..19a32280731d 100644 --- a/drivers/lguest/hypercalls.c +++ b/drivers/lguest/hypercalls.c @@ -211,10 +211,9 @@ static void initialize(struct lg_cpu *cpu) /* * The Guest tells us where we're not to deliver interrupts by putting - * the range of addresses into "struct lguest_data". + * the instruction address into "struct lguest_data". */ - if (get_user(cpu->lg->noirq_start, &cpu->lg->lguest_data->noirq_start) - || get_user(cpu->lg->noirq_end, &cpu->lg->lguest_data->noirq_end)) + if (get_user(cpu->lg->noirq_iret, &cpu->lg->lguest_data->noirq_iret)) kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data); /* diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index 70dfcdc29f1f..6d4c072b61e1 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c @@ -204,8 +204,7 @@ void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more) * They may be in the middle of an iret, where they asked us never to * deliver interrupts. */ - if (cpu->regs->eip >= cpu->lg->noirq_start && - (cpu->regs->eip < cpu->lg->noirq_end)) + if (cpu->regs->eip == cpu->lg->noirq_iret) return; /* If they're halted, interrupts restart them. */ @@ -395,8 +394,9 @@ static bool direct_trap(unsigned int num) * The Guest has the ability to turn its interrupt gates into trap gates, * if it is careful. The Host will let trap gates can go directly to the * Guest, but the Guest needs the interrupts atomically disabled for an - * interrupt gate. It can do this by pointing the trap gate at instructions - * within noirq_start and noirq_end, where it can safely disable interrupts. + * interrupt gate. The Host could provide a mechanism to register more + * "no-interrupt" regions, and the Guest could point the trap gate at + * instructions within that region, where it can safely disable interrupts. */ /*M:006 diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index 307e8b39e7d1..ac8ad0461e80 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h @@ -102,7 +102,7 @@ struct lguest { struct pgdir pgdirs[4]; - unsigned long noirq_start, noirq_end; + unsigned long noirq_iret; unsigned int stack_pages; u32 tsc_khz; diff --git a/include/linux/lguest.h b/include/linux/lguest.h index 9962c6bb1311..6db19f35f7c5 100644 --- a/include/linux/lguest.h +++ b/include/linux/lguest.h @@ -61,8 +61,8 @@ struct lguest_data { u32 tsc_khz; /* Fields initialized by the Guest at boot: */ - /* Instruction range to suppress interrupts even if enabled */ - unsigned long noirq_start, noirq_end; + /* Instruction to suppress interrupts even if enabled */ + unsigned long noirq_iret; /* Address above which page tables are all identical. */ unsigned long kernel_address; /* The vector to try to use for system calls (0x40 or 0x80). */ -- cgit v1.2.3 From 6321fd6b6f0942e986b297e8192febfc860b83b3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 30 Jan 2015 12:36:12 +0100 Subject: drm: Remove unused DRM_MODE_OBJECT_BRIDGE With bridges now moving to a separate registry they are no longer DRM objects, hence this define is no longer needed. Signed-off-by: Thierry Reding --- include/drm/drm_crtc.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 920e21a8f3fd..f924b81d48ff 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -53,7 +53,6 @@ struct fence; #define DRM_MODE_OBJECT_FB 0xfbfbfbfb #define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb #define DRM_MODE_OBJECT_PLANE 0xeeeeeeee -#define DRM_MODE_OBJECT_BRIDGE 0xbdbdbdbd #define DRM_MODE_OBJECT_ANY 0 struct drm_mode_object { -- cgit v1.2.3 From 44486b48b066330e0ed0a66478cc49f5975ec6c1 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 18 Mar 2015 18:38:26 +0200 Subject: wl12xx: use frequency instead of enumerations for pdata clocks Instead of defining an enumeration with the FW specific values for the different clock rates, use the actual frequency instead. Also add a boolean to specify whether the clock is XTAL or not. Change all board files to reflect this. Signed-off-by: Luciano Coelho [Eliad - small fixes, update board file changes] Signed-off-by: Eliad Peller Tested-by: Nikita Kiryanov Acked-by: Kalle Valo Acked-by: Sekhar Nori Signed-off-by: Tony Lindgren --- arch/arm/mach-davinci/board-da850-evm.c | 3 +- arch/arm/mach-omap2/pdata-quirks.c | 29 ++++++++-------- drivers/net/wireless/ti/wl12xx/main.c | 60 ++++++++++++++++++++++++++++++--- drivers/net/wireless/ti/wl12xx/wl12xx.h | 28 +++++++++++++++ include/linux/wl12xx.h | 27 ++------------- 5 files changed, 103 insertions(+), 44 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 916589ca8d44..853b941b710e 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -1386,7 +1386,8 @@ static const short da850_wl12xx_pins[] __initconst = { static struct wl12xx_platform_data da850_wl12xx_wlan_data __initdata = { .irq = -1, .irq_trigger = IRQ_TYPE_EDGE_RISING, - .board_ref_clock = WL12XX_REFCLOCK_38, + .ref_clock_freq = 38400000, + .ref_clock_xtal = false, }; static __init int da850_wl12xx_init(void) diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index e86fb0d55c59..cebdf8d0dc08 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -39,14 +39,14 @@ static struct twl4030_gpio_platform_data twl_gpio_auxdata; static struct wl12xx_platform_data wl12xx __initdata; -static void __init __used legacy_init_wl12xx(unsigned ref_clock, - unsigned tcxo_clock, +static void __init __used legacy_init_wl12xx(u32 ref_clock_freq, + u32 tcxo_clock_freq, int gpio) { int res; - wl12xx.board_ref_clock = ref_clock; - wl12xx.board_tcxo_clock = tcxo_clock; + wl12xx.ref_clock_freq = ref_clock_freq; + wl12xx.tcxo_clock_freq = tcxo_clock_freq; wl12xx.irq = gpio_to_irq(gpio); wl12xx.irq_trigger = IRQ_TYPE_LEVEL_HIGH; @@ -57,8 +57,8 @@ static void __init __used legacy_init_wl12xx(unsigned ref_clock, } } #else -static inline void legacy_init_wl12xx(unsigned ref_clock, - unsigned tcxo_clock, +static inline void legacy_init_wl12xx(u32 ref_clock_freq, + u32 tcxo_clock_freq, int gpio) { } @@ -130,7 +130,7 @@ static void __init omap3_sbc_t3730_twl_init(void) static void __init omap3_sbc_t3730_legacy_init(void) { omap3_sbc_t3x_usb_hub_init(167, "sb-t35 usb hub"); - legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 136); + legacy_init_wl12xx(38400000, 0, 136); } static void __init omap3_sbc_t3530_legacy_init(void) @@ -175,12 +175,12 @@ static void __init omap3_igep0030_rev_g_legacy_init(void) static void __init omap3_evm_legacy_init(void) { hsmmc2_internal_input_clk(); - legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 149); + legacy_init_wl12xx(38400000, 0, 149); } static void __init omap3_zoom_legacy_init(void) { - legacy_init_wl12xx(WL12XX_REFCLOCK_26, 0, 162); + legacy_init_wl12xx(26000000, 0, 162); } static void am35xx_enable_emac_int(void) @@ -247,7 +247,7 @@ static void __init omap3_sbc_t3517_legacy_init(void) am35xx_emac_reset(); hsmmc2_internal_input_clk(); omap3_sbc_t3517_wifi_init(); - legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 145); + legacy_init_wl12xx(38400000, 0, 145); } static void __init am3517_evm_legacy_init(void) @@ -292,18 +292,17 @@ static void __init omap3_tao3530_legacy_init(void) #ifdef CONFIG_ARCH_OMAP4 static void __init omap4_sdp_legacy_init(void) { - legacy_init_wl12xx(WL12XX_REFCLOCK_26, - WL12XX_TCXOCLOCK_26, 53); + legacy_init_wl12xx(26000000, 26000000, 53); } static void __init omap4_panda_legacy_init(void) { - legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 53); + legacy_init_wl12xx(38400000, 0, 53); } static void __init var_som_om44_legacy_init(void) { - legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 41); + legacy_init_wl12xx(38400000, 0, 41); } #endif @@ -318,7 +317,7 @@ static struct iommu_platform_data omap4_iommu_pdata = { #ifdef CONFIG_SOC_AM33XX static void __init am335x_evmsk_legacy_init(void) { - legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 31); + legacy_init_wl12xx(38400000, 0, 31); } #endif diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index 144d1f8ba473..b3f751f1e08f 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -1770,6 +1770,40 @@ wl12xx_iface_combinations[] = { }, }; +static const struct wl12xx_clock wl12xx_refclock_table[] = { + { 19200000, false, WL12XX_REFCLOCK_19 }, + { 26000000, false, WL12XX_REFCLOCK_26 }, + { 26000000, true, WL12XX_REFCLOCK_26_XTAL }, + { 38400000, false, WL12XX_REFCLOCK_38 }, + { 38400000, true, WL12XX_REFCLOCK_38_XTAL }, + { 52000000, false, WL12XX_REFCLOCK_52 }, + { 0, false, 0 } +}; + +static const struct wl12xx_clock wl12xx_tcxoclock_table[] = { + { 16368000, true, WL12XX_TCXOCLOCK_16_368 }, + { 16800000, true, WL12XX_TCXOCLOCK_16_8 }, + { 19200000, true, WL12XX_TCXOCLOCK_19_2 }, + { 26000000, true, WL12XX_TCXOCLOCK_26 }, + { 32736000, true, WL12XX_TCXOCLOCK_32_736 }, + { 33600000, true, WL12XX_TCXOCLOCK_33_6 }, + { 38400000, true, WL12XX_TCXOCLOCK_38_4 }, + { 52000000, true, WL12XX_TCXOCLOCK_52 }, + { 0, false, 0 } +}; + +static int wl12xx_get_clock_idx(const struct wl12xx_clock *table, + u32 freq, bool xtal) +{ + int i; + + for (i = 0; table[i].freq != 0; i++) + if ((table[i].freq == freq) && (table[i].xtal == xtal)) + return table[i].hw_idx; + + return -EINVAL; +} + static int wl12xx_setup(struct wl1271 *wl) { struct wl12xx_priv *priv = wl->priv; @@ -1799,7 +1833,17 @@ static int wl12xx_setup(struct wl1271 *wl) wl12xx_conf_init(wl); if (!fref_param) { - priv->ref_clock = pdata->board_ref_clock; + priv->ref_clock = wl12xx_get_clock_idx(wl12xx_refclock_table, + pdata->ref_clock_freq, + pdata->ref_clock_xtal); + if (priv->ref_clock < 0) { + wl1271_error("Invalid ref_clock frequency (%d Hz, %s)", + pdata->ref_clock_freq, + pdata->ref_clock_xtal ? + "XTAL" : "not XTAL"); + + return priv->ref_clock; + } } else { if (!strcmp(fref_param, "19.2")) priv->ref_clock = WL12XX_REFCLOCK_19; @@ -1817,9 +1861,17 @@ static int wl12xx_setup(struct wl1271 *wl) wl1271_error("Invalid fref parameter %s", fref_param); } - if (!tcxo_param) { - priv->tcxo_clock = pdata->board_tcxo_clock; - } else { + if (!tcxo_param && pdata->tcxo_clock_freq) { + priv->tcxo_clock = wl12xx_get_clock_idx(wl12xx_tcxoclock_table, + pdata->tcxo_clock_freq, + true); + if (priv->tcxo_clock < 0) { + wl1271_error("Invalid tcxo_clock frequency (%d Hz)", + pdata->tcxo_clock_freq); + + return priv->tcxo_clock; + } + } else if (tcxo_param) { if (!strcmp(tcxo_param, "19.2")) priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2; else if (!strcmp(tcxo_param, "26")) diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h index 75c92658bfea..5952e99ace1b 100644 --- a/drivers/net/wireless/ti/wl12xx/wl12xx.h +++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h @@ -82,6 +82,34 @@ struct wl12xx_priv { struct wl127x_rx_mem_pool_addr *rx_mem_addr; }; +/* Reference clock values */ +enum { + WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ + WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ + WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ + WL12XX_REFCLOCK_52 = 3, /* 52 MHz */ + WL12XX_REFCLOCK_38_XTAL = 4, /* 38.4 MHz, XTAL */ + WL12XX_REFCLOCK_26_XTAL = 5, /* 26 MHz, XTAL */ +}; + +/* TCXO clock values */ +enum { + WL12XX_TCXOCLOCK_19_2 = 0, /* 19.2MHz */ + WL12XX_TCXOCLOCK_26 = 1, /* 26 MHz */ + WL12XX_TCXOCLOCK_38_4 = 2, /* 38.4MHz */ + WL12XX_TCXOCLOCK_52 = 3, /* 52 MHz */ + WL12XX_TCXOCLOCK_16_368 = 4, /* 16.368 MHz */ + WL12XX_TCXOCLOCK_32_736 = 5, /* 32.736 MHz */ + WL12XX_TCXOCLOCK_16_8 = 6, /* 16.8 MHz */ + WL12XX_TCXOCLOCK_33_6 = 7, /* 33.6 MHz */ +}; + +struct wl12xx_clock { + u32 freq; + bool xtal; + u8 hw_idx; +}; + struct wl12xx_fw_packet_counters { /* Cumulative counter of released packets per AC */ u8 tx_released_pkts[NUM_TX_QUEUES]; diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h index 3876b67dbcbc..eea1e6dac4be 100644 --- a/include/linux/wl12xx.h +++ b/include/linux/wl12xx.h @@ -26,28 +26,6 @@ #include -/* Reference clock values */ -enum { - WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ - WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ - WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ - WL12XX_REFCLOCK_52 = 3, /* 52 MHz */ - WL12XX_REFCLOCK_38_XTAL = 4, /* 38.4 MHz, XTAL */ - WL12XX_REFCLOCK_26_XTAL = 5, /* 26 MHz, XTAL */ -}; - -/* TCXO clock values */ -enum { - WL12XX_TCXOCLOCK_19_2 = 0, /* 19.2MHz */ - WL12XX_TCXOCLOCK_26 = 1, /* 26 MHz */ - WL12XX_TCXOCLOCK_38_4 = 2, /* 38.4MHz */ - WL12XX_TCXOCLOCK_52 = 3, /* 52 MHz */ - WL12XX_TCXOCLOCK_16_368 = 4, /* 16.368 MHz */ - WL12XX_TCXOCLOCK_32_736 = 5, /* 32.736 MHz */ - WL12XX_TCXOCLOCK_16_8 = 6, /* 16.8 MHz */ - WL12XX_TCXOCLOCK_33_6 = 7, /* 33.6 MHz */ -}; - struct wl1251_platform_data { int power_gpio; /* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */ @@ -58,8 +36,9 @@ struct wl1251_platform_data { struct wl12xx_platform_data { int irq; u32 irq_trigger; - int board_ref_clock; - int board_tcxo_clock; + bool ref_clock_xtal; /* specify whether the clock is XTAL or not */ + u32 ref_clock_freq; /* in Hertz */ + u32 tcxo_clock_freq; /* in Hertz, tcxo is always XTAL */ bool pwr_in_suspend; }; -- cgit v1.2.3 From 83c3a7d4ac7fdc29a64bf9a5467a36b4c72a1eed Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 18 Mar 2015 18:38:30 +0200 Subject: wlcore: remove wl12xx_platform_data Now that we have wlcore device-tree bindings in place (for both wl12xx and wl18xx), remove the legacy wl12xx_platform_data struct, and move its members into the platform device data (that is passed to wlcore) Davinci 850 is the only platform that still set the platform data in the legacy way (and doesn't have DT bindings), so remove the relevant code/Kconfig option from the board file (as suggested by Sekhar Nori) Since no one currently uses wlcore_spi, simply remove its platform data support (DT bindings will have to be added if someone actually needs it) Signed-off-by: Luciano Coelho Signed-off-by: Eliad Peller Tested-by: Nikita Kiryanov Acked-by: Kalle Valo Acked-by: Sekhar Nori Signed-off-by: Tony Lindgren --- arch/arm/mach-davinci/Kconfig | 11 --- arch/arm/mach-davinci/board-da850-evm.c | 113 ------------------------- drivers/net/wireless/ti/wilink_platform_data.c | 25 ------ drivers/net/wireless/ti/wl12xx/main.c | 19 ++--- drivers/net/wireless/ti/wlcore/boot.c | 1 - drivers/net/wireless/ti/wlcore/main.c | 4 +- drivers/net/wireless/ti/wlcore/sdio.c | 76 +++++------------ drivers/net/wireless/ti/wlcore/spi.c | 6 +- drivers/net/wireless/ti/wlcore/wlcore_i.h | 6 +- include/linux/wl12xx.h | 25 ------ 10 files changed, 35 insertions(+), 251 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index cd30f6f5f2ff..dd8f5312b2c0 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -200,17 +200,6 @@ config DA850_UI_SD_VIDEO_PORT endchoice -config DA850_WL12XX - bool "AM18x wl1271 daughter board" - depends on MACH_DAVINCI_DA850_EVM - help - The wl1271 daughter card for AM18x EVMs is a combo wireless - connectivity add-on card, based on the LS Research TiWi module with - Texas Instruments' wl1271 solution. - Say Y if you want to use a wl1271 expansion card connected to the - AM18x EVM. - - config MACH_MITYOMAPL138 bool "Critical Link MityDSP-L138/MityARM-1808 SoM" depends on ARCH_DAVINCI_DA850 diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 853b941b710e..1ed545cc2b83 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -60,9 +59,6 @@ #define DA850_MMCSD_CD_PIN GPIO_TO_PIN(4, 0) #define DA850_MMCSD_WP_PIN GPIO_TO_PIN(4, 1) -#define DA850_WLAN_EN GPIO_TO_PIN(6, 9) -#define DA850_WLAN_IRQ GPIO_TO_PIN(6, 10) - #define DA850_MII_MDIO_CLKEN_PIN GPIO_TO_PIN(2, 6) static struct mtd_partition da850evm_spiflash_part[] = { @@ -1343,110 +1339,6 @@ static __init void da850_vpif_init(void) static __init void da850_vpif_init(void) {} #endif -#ifdef CONFIG_DA850_WL12XX - -static void wl12xx_set_power(int index, bool power_on) -{ - static bool power_state; - - pr_debug("Powering %s wl12xx", power_on ? "on" : "off"); - - if (power_on == power_state) - return; - power_state = power_on; - - if (power_on) { - /* Power up sequence required for wl127x devices */ - gpio_set_value(DA850_WLAN_EN, 1); - usleep_range(15000, 15000); - gpio_set_value(DA850_WLAN_EN, 0); - usleep_range(1000, 1000); - gpio_set_value(DA850_WLAN_EN, 1); - msleep(70); - } else { - gpio_set_value(DA850_WLAN_EN, 0); - } -} - -static struct davinci_mmc_config da850_wl12xx_mmc_config = { - .set_power = wl12xx_set_power, - .wires = 4, - .max_freq = 25000000, - .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_NONREMOVABLE | - MMC_CAP_POWER_OFF_CARD, -}; - -static const short da850_wl12xx_pins[] __initconst = { - DA850_MMCSD1_DAT_0, DA850_MMCSD1_DAT_1, DA850_MMCSD1_DAT_2, - DA850_MMCSD1_DAT_3, DA850_MMCSD1_CLK, DA850_MMCSD1_CMD, - DA850_GPIO6_9, DA850_GPIO6_10, - -1 -}; - -static struct wl12xx_platform_data da850_wl12xx_wlan_data __initdata = { - .irq = -1, - .irq_trigger = IRQ_TYPE_EDGE_RISING, - .ref_clock_freq = 38400000, - .ref_clock_xtal = false, -}; - -static __init int da850_wl12xx_init(void) -{ - int ret; - - ret = davinci_cfg_reg_list(da850_wl12xx_pins); - if (ret) { - pr_err("wl12xx/mmc mux setup failed: %d\n", ret); - goto exit; - } - - ret = da850_register_mmcsd1(&da850_wl12xx_mmc_config); - if (ret) { - pr_err("wl12xx/mmc registration failed: %d\n", ret); - goto exit; - } - - ret = gpio_request_one(DA850_WLAN_EN, GPIOF_OUT_INIT_LOW, "wl12xx_en"); - if (ret) { - pr_err("Could not request wl12xx enable gpio: %d\n", ret); - goto exit; - } - - ret = gpio_request_one(DA850_WLAN_IRQ, GPIOF_IN, "wl12xx_irq"); - if (ret) { - pr_err("Could not request wl12xx irq gpio: %d\n", ret); - goto free_wlan_en; - } - - da850_wl12xx_wlan_data.irq = gpio_to_irq(DA850_WLAN_IRQ); - - ret = wl12xx_set_platform_data(&da850_wl12xx_wlan_data); - if (ret) { - pr_err("Could not set wl12xx data: %d\n", ret); - goto free_wlan_irq; - } - - return 0; - -free_wlan_irq: - gpio_free(DA850_WLAN_IRQ); - -free_wlan_en: - gpio_free(DA850_WLAN_EN); - -exit: - return ret; -} - -#else /* CONFIG_DA850_WL12XX */ - -static __init int da850_wl12xx_init(void) -{ - return 0; -} - -#endif /* CONFIG_DA850_WL12XX */ - #define DA850EVM_SATA_REFCLKPN_RATE (100 * 1000 * 1000) static __init void da850_evm_init(void) @@ -1503,11 +1395,6 @@ static __init void da850_evm_init(void) if (ret) pr_warn("%s: MMCSD0 registration failed: %d\n", __func__, ret); - - ret = da850_wl12xx_init(); - if (ret) - pr_warn("%s: WL12xx initialization failed: %d\n", - __func__, ret); } davinci_serial_init(da8xx_serial_device); diff --git a/drivers/net/wireless/ti/wilink_platform_data.c b/drivers/net/wireless/ti/wilink_platform_data.c index a92bd3e89796..ea0e359bdb43 100644 --- a/drivers/net/wireless/ti/wilink_platform_data.c +++ b/drivers/net/wireless/ti/wilink_platform_data.c @@ -23,31 +23,6 @@ #include #include -static struct wl12xx_platform_data *wl12xx_platform_data; - -int __init wl12xx_set_platform_data(const struct wl12xx_platform_data *data) -{ - if (wl12xx_platform_data) - return -EBUSY; - if (!data) - return -EINVAL; - - wl12xx_platform_data = kmemdup(data, sizeof(*data), GFP_KERNEL); - if (!wl12xx_platform_data) - return -ENOMEM; - - return 0; -} - -struct wl12xx_platform_data *wl12xx_get_platform_data(void) -{ - if (!wl12xx_platform_data) - return ERR_PTR(-ENODEV); - - return wl12xx_platform_data; -} -EXPORT_SYMBOL(wl12xx_get_platform_data); - static struct wl1251_platform_data *wl1251_platform_data; int __init wl1251_set_platform_data(const struct wl1251_platform_data *data) diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index b3f751f1e08f..af0fe2e17151 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -24,8 +24,6 @@ #include -#include - #include "../wlcore/wlcore.h" #include "../wlcore/debug.h" #include "../wlcore/io.h" @@ -1808,7 +1806,6 @@ static int wl12xx_setup(struct wl1271 *wl) { struct wl12xx_priv *priv = wl->priv; struct wlcore_platdev_data *pdev_data = dev_get_platdata(&wl->pdev->dev); - struct wl12xx_platform_data *pdata = pdev_data->pdata; BUILD_BUG_ON(WL12XX_MAX_LINKS > WLCORE_MAX_LINKS); BUILD_BUG_ON(WL12XX_MAX_AP_STATIONS > WL12XX_MAX_LINKS); @@ -1834,12 +1831,12 @@ static int wl12xx_setup(struct wl1271 *wl) if (!fref_param) { priv->ref_clock = wl12xx_get_clock_idx(wl12xx_refclock_table, - pdata->ref_clock_freq, - pdata->ref_clock_xtal); + pdev_data->ref_clock_freq, + pdev_data->ref_clock_xtal); if (priv->ref_clock < 0) { wl1271_error("Invalid ref_clock frequency (%d Hz, %s)", - pdata->ref_clock_freq, - pdata->ref_clock_xtal ? + pdev_data->ref_clock_freq, + pdev_data->ref_clock_xtal ? "XTAL" : "not XTAL"); return priv->ref_clock; @@ -1861,13 +1858,13 @@ static int wl12xx_setup(struct wl1271 *wl) wl1271_error("Invalid fref parameter %s", fref_param); } - if (!tcxo_param && pdata->tcxo_clock_freq) { + if (!tcxo_param && pdev_data->tcxo_clock_freq) { priv->tcxo_clock = wl12xx_get_clock_idx(wl12xx_tcxoclock_table, - pdata->tcxo_clock_freq, - true); + pdev_data->tcxo_clock_freq, + true); if (priv->tcxo_clock < 0) { wl1271_error("Invalid tcxo_clock frequency (%d Hz)", - pdata->tcxo_clock_freq); + pdev_data->tcxo_clock_freq); return priv->tcxo_clock; } diff --git a/drivers/net/wireless/ti/wlcore/boot.c b/drivers/net/wireless/ti/wlcore/boot.c index 77752b03f189..19b7ec7b69c2 100644 --- a/drivers/net/wireless/ti/wlcore/boot.c +++ b/drivers/net/wireless/ti/wlcore/boot.c @@ -22,7 +22,6 @@ */ #include -#include #include #include "debug.h" diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 67518f692cfc..0be807951afe 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -6390,7 +6389,6 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) struct wl1271 *wl = context; struct platform_device *pdev = wl->pdev; struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); - struct wl12xx_platform_data *pdata = pdev_data->pdata; struct resource *res; int ret; @@ -6446,7 +6444,7 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context) if (!ret) { wl->irq_wake_enabled = true; device_init_wakeup(wl->dev, 1); - if (pdata->pwr_in_suspend) + if (pdev_data->pwr_in_suspend) wl->hw->wiphy->wowlan = &wlcore_wowlan_support; } #endif diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index b55dc0ede513..ea7e07abca4e 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -231,67 +230,37 @@ static const struct of_device_id wlcore_sdio_of_match_table[] = { { } }; -static struct wl12xx_platform_data *wlcore_probe_of(struct device *dev) +static int wlcore_probe_of(struct device *dev, int *irq, + struct wlcore_platdev_data *pdev_data) { struct device_node *np = dev->of_node; - struct wl12xx_platform_data *pdata; if (!np || !of_match_node(wlcore_sdio_of_match_table, np)) - return NULL; + return -ENODATA; - pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return NULL; - - pdata->irq = irq_of_parse_and_map(np, 0); - if (!pdata->irq) { + *irq = irq_of_parse_and_map(np, 0); + if (!*irq) { dev_err(dev, "No irq in platform data\n"); - kfree(pdata); - return NULL; + kfree(pdev_data); + return -EINVAL; } - pdata->irq_trigger = - irqd_get_trigger_type(irq_get_irq_data(pdata->irq)); - /* optional clock frequency params */ of_property_read_u32(np, "ref-clock-frequency", - &pdata->ref_clock_freq); + &pdev_data->ref_clock_freq); of_property_read_u32(np, "tcxo-clock-frequency", - &pdata->tcxo_clock_freq); + &pdev_data->tcxo_clock_freq); - return pdata; + return 0; } #else -static struct wl12xx_platform_data *wlcore_probe_of(struct device *dev) +static int wlcore_probe_of(struct device *dev, int *irq, + struct wlcore_platdev_data *pdev_data) { - return NULL; + return -ENODATA; } #endif -static struct wl12xx_platform_data * -wlcore_get_platform_data(struct device *dev) -{ - struct wl12xx_platform_data *pdata; - - /* first, look for DT data */ - pdata = wlcore_probe_of(dev); - if (pdata) - return pdata; - - /* if not found - fallback to static platform data */ - pdata = wl12xx_get_platform_data(); - if (!IS_ERR(pdata)) - return kmemdup(pdata, sizeof(*pdata), GFP_KERNEL); - - dev_err(dev, "No platform data set\n"); - return NULL; -} - -static void wlcore_del_platform_data(struct wl12xx_platform_data *pdata) -{ - kfree(pdata); -} - static int wl1271_probe(struct sdio_func *func, const struct sdio_device_id *id) { @@ -300,6 +269,7 @@ static int wl1271_probe(struct sdio_func *func, struct resource res[1]; mmc_pm_flag_t mmcflags; int ret = -ENOMEM; + int irq; const char *chip_family; /* We are only able to handle the wlan function */ @@ -323,8 +293,7 @@ static int wl1271_probe(struct sdio_func *func, /* Use block mode for transferring over one block size of data */ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; - pdev_data.pdata = wlcore_get_platform_data(&func->dev); - if (!pdev_data.pdata) + if (wlcore_probe_of(&func->dev, &irq, &pdev_data)) goto out_free_glue; /* if sdio can keep power while host is suspended, enable wow */ @@ -332,7 +301,7 @@ static int wl1271_probe(struct sdio_func *func, dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags); if (mmcflags & MMC_PM_KEEP_POWER) - pdev_data.pdata->pwr_in_suspend = true; + pdev_data.pwr_in_suspend = true; sdio_set_drvdata(func, glue); @@ -354,15 +323,16 @@ static int wl1271_probe(struct sdio_func *func, if (!glue->core) { dev_err(glue->dev, "can't allocate platform_device"); ret = -ENOMEM; - goto out_free_pdata; + goto out_free_glue; } glue->core->dev.parent = &func->dev; memset(res, 0x00, sizeof(res)); - res[0].start = pdev_data.pdata->irq; - res[0].flags = IORESOURCE_IRQ | pdev_data.pdata->irq_trigger; + res[0].start = irq; + res[0].flags = IORESOURCE_IRQ | + irqd_get_trigger_type(irq_get_irq_data(irq)); res[0].name = "irq"; ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res)); @@ -388,9 +358,6 @@ static int wl1271_probe(struct sdio_func *func, out_dev_put: platform_device_put(glue->core); -out_free_pdata: - wlcore_del_platform_data(pdev_data.pdata); - out_free_glue: kfree(glue); @@ -401,14 +368,11 @@ out: static void wl1271_remove(struct sdio_func *func) { struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func); - struct wlcore_platdev_data *pdev_data = glue->core->dev.platform_data; - struct wl12xx_platform_data *pdata = pdev_data->pdata; /* Undo decrement done above in wl1271_probe */ pm_runtime_get_noresume(&func->dev); platform_device_unregister(glue->core); - wlcore_del_platform_data(pdata); kfree(glue); } diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 69601f6741d9..f1ac2839d97c 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -331,11 +331,7 @@ static int wl1271_probe(struct spi_device *spi) memset(&pdev_data, 0x00, sizeof(pdev_data)); - pdev_data.pdata = dev_get_platdata(&spi->dev); - if (!pdev_data.pdata) { - dev_err(&spi->dev, "no platform data\n"); - return -ENODEV; - } + /* TODO: add DT parsing when needed */ pdev_data.if_ops = &spi_ops; diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 3396ce5a934d..39efc6d78b10 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -201,8 +201,12 @@ struct wl1271_if_operations { }; struct wlcore_platdev_data { - struct wl12xx_platform_data *pdata; struct wl1271_if_operations *if_ops; + + bool ref_clock_xtal; /* specify whether the clock is XTAL or not */ + u32 ref_clock_freq; /* in Hertz */ + u32 tcxo_clock_freq; /* in Hertz, tcxo is always XTAL */ + bool pwr_in_suspend; }; #define MAX_NUM_KEYS 14 diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h index eea1e6dac4be..95704cd4cfab 100644 --- a/include/linux/wl12xx.h +++ b/include/linux/wl12xx.h @@ -33,39 +33,14 @@ struct wl1251_platform_data { bool use_eeprom; }; -struct wl12xx_platform_data { - int irq; - u32 irq_trigger; - bool ref_clock_xtal; /* specify whether the clock is XTAL or not */ - u32 ref_clock_freq; /* in Hertz */ - u32 tcxo_clock_freq; /* in Hertz, tcxo is always XTAL */ - bool pwr_in_suspend; -}; - #ifdef CONFIG_WILINK_PLATFORM_DATA -int wl12xx_set_platform_data(const struct wl12xx_platform_data *data); - -struct wl12xx_platform_data *wl12xx_get_platform_data(void); - int wl1251_set_platform_data(const struct wl1251_platform_data *data); struct wl1251_platform_data *wl1251_get_platform_data(void); #else -static inline -int wl12xx_set_platform_data(const struct wl12xx_platform_data *data) -{ - return -ENOSYS; -} - -static inline -struct wl12xx_platform_data *wl12xx_get_platform_data(void) -{ - return ERR_PTR(-ENODATA); -} - static inline int wl1251_set_platform_data(const struct wl1251_platform_data *data) { -- cgit v1.2.3 From dd46c787788d5bf5b974729d43e4c405814a4c7d Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 25 Mar 2015 15:07:05 +1100 Subject: fs: Add support FALLOC_FL_INSERT_RANGE for fallocate FALLOC_FL_INSERT_RANGE command is the opposite command of FALLOC_FL_COLLAPSE_RANGE that is needed for someone who wants to add some data in the middle of file. FALLOC_FL_INSERT_RANGE will create space for writing new data within a file after shifting extents to right as given length. This command also has same limitations as FALLOC_FL_COLLAPSE_RANGE in that operations need to be filesystem block boundary aligned and cannot cross the current EOF. Signed-off-by: Namjae Jeon Signed-off-by: Ashish Sangwan Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/open.c | 8 ++++++-- include/linux/falloc.h | 6 ++++++ include/uapi/linux/falloc.h | 17 +++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/fs/open.c b/fs/open.c index 33f9cbf2610b..b724cc0e0228 100644 --- a/fs/open.c +++ b/fs/open.c @@ -231,8 +231,7 @@ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) return -EINVAL; /* Return error if mode is not supported */ - if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | - FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE)) + if (mode & ~FALLOC_FL_SUPPORTED_MASK) return -EOPNOTSUPP; /* Punch hole and zero range are mutually exclusive */ @@ -250,6 +249,11 @@ int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) (mode & ~FALLOC_FL_COLLAPSE_RANGE)) return -EINVAL; + /* Insert range should only be used exclusively. */ + if ((mode & FALLOC_FL_INSERT_RANGE) && + (mode & ~FALLOC_FL_INSERT_RANGE)) + return -EINVAL; + if (!(file->f_mode & FMODE_WRITE)) return -EBADF; diff --git a/include/linux/falloc.h b/include/linux/falloc.h index 31591686ac2d..996111000a8c 100644 --- a/include/linux/falloc.h +++ b/include/linux/falloc.h @@ -21,4 +21,10 @@ struct space_resv { #define FS_IOC_RESVSP _IOW('X', 40, struct space_resv) #define FS_IOC_RESVSP64 _IOW('X', 42, struct space_resv) +#define FALLOC_FL_SUPPORTED_MASK (FALLOC_FL_KEEP_SIZE | \ + FALLOC_FL_PUNCH_HOLE | \ + FALLOC_FL_COLLAPSE_RANGE | \ + FALLOC_FL_ZERO_RANGE | \ + FALLOC_FL_INSERT_RANGE) + #endif /* _FALLOC_H_ */ diff --git a/include/uapi/linux/falloc.h b/include/uapi/linux/falloc.h index d1197ae3723c..3e445a760f14 100644 --- a/include/uapi/linux/falloc.h +++ b/include/uapi/linux/falloc.h @@ -41,4 +41,21 @@ */ #define FALLOC_FL_ZERO_RANGE 0x10 +/* + * FALLOC_FL_INSERT_RANGE is use to insert space within the file size without + * overwriting any existing data. The contents of the file beyond offset are + * shifted towards right by len bytes to create a hole. As such, this + * operation will increase the size of the file by len bytes. + * + * Different filesystems may implement different limitations on the granularity + * of the operation. Most will limit operations to filesystem block size + * boundaries, but this boundary may be larger or smaller depending on + * the filesystem and/or the configuration of the filesystem or file. + * + * Attempting to insert space using this flag at OR beyond the end of + * the file is considered an illegal operation - just use ftruncate(2) or + * fallocate(2) with mode 0 for such type of operations. + */ +#define FALLOC_FL_INSERT_RANGE 0x20 + #endif /* _UAPI_FALLOC_H_ */ -- cgit v1.2.3 From 3a3e1c88362429ca3a6ef84d232e56b197294ce0 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 23 Feb 2015 15:57:32 +0200 Subject: ARM: OMAP2+: PRCM: add support for static clock memmap indices All clock provider related drivers will now register their iomaps with a static index. This makes it easier to split up the individual drivers to their own files in subsequent patches. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/prcm-common.h | 8 ++++ arch/arm/mach-omap2/prm_common.c | 79 +++++++++++++++++++++++++-------------- include/linux/clk/ti.h | 1 + 3 files changed, 59 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h index 6163d66102a3..ee38356b3601 100644 --- a/arch/arm/mach-omap2/prcm-common.h +++ b/arch/arm/mach-omap2/prcm-common.h @@ -518,6 +518,14 @@ struct omap_prcm_irq_setup { .priority = _priority \ } +/** + * struct omap_prcm_init_data - PRCM driver init data + * @index: clock memory mapping index to be used + */ +struct omap_prcm_init_data { + int index; +}; + extern void omap_prcm_irq_cleanup(void); extern int omap_prcm_register_chain_handler( struct omap_prcm_irq_setup *irq_setup); diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index 79cee117f971..8ec52012f85d 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -633,31 +633,47 @@ int prm_unregister(struct prm_ll_data *pld) return 0; } +static struct omap_prcm_init_data prm_data = { + .index = TI_CLKM_PRM, +}; + +static struct omap_prcm_init_data cm_data = { + .index = TI_CLKM_CM, +}; + +static struct omap_prcm_init_data cm2_data = { + .index = TI_CLKM_CM2, +}; + +static struct omap_prcm_init_data scrm_data = { + .index = TI_CLKM_SCRM, +}; + static const struct of_device_id omap_prcm_dt_match_table[] = { - { .compatible = "ti,am3-prcm" }, - { .compatible = "ti,am3-scrm" }, - { .compatible = "ti,am4-prcm" }, - { .compatible = "ti,am4-scrm" }, - { .compatible = "ti,dm814-prcm" }, - { .compatible = "ti,dm814-scrm" }, - { .compatible = "ti,dm816-prcm" }, - { .compatible = "ti,dm816-scrm" }, - { .compatible = "ti,omap2-prcm" }, - { .compatible = "ti,omap2-scrm" }, - { .compatible = "ti,omap3-prm" }, - { .compatible = "ti,omap3-cm" }, - { .compatible = "ti,omap3-scrm" }, - { .compatible = "ti,omap4-cm1" }, - { .compatible = "ti,omap4-prm" }, - { .compatible = "ti,omap4-cm2" }, - { .compatible = "ti,omap4-scrm" }, - { .compatible = "ti,omap5-prm" }, - { .compatible = "ti,omap5-cm-core-aon" }, - { .compatible = "ti,omap5-scrm" }, - { .compatible = "ti,omap5-cm-core" }, - { .compatible = "ti,dra7-prm" }, - { .compatible = "ti,dra7-cm-core-aon" }, - { .compatible = "ti,dra7-cm-core" }, + { .compatible = "ti,am3-prcm", .data = &prm_data }, + { .compatible = "ti,am3-scrm", .data = &scrm_data }, + { .compatible = "ti,am4-prcm", .data = &prm_data }, + { .compatible = "ti,am4-scrm", .data = &scrm_data }, + { .compatible = "ti,dm814-prcm", .data = &prm_data }, + { .compatible = "ti,dm814-scrm", .data = &scrm_data }, + { .compatible = "ti,dm816-prcm", .data = &prm_data }, + { .compatible = "ti,dm816-scrm", .data = &scrm_data }, + { .compatible = "ti,omap2-prcm", .data = &prm_data }, + { .compatible = "ti,omap2-scrm", .data = &scrm_data }, + { .compatible = "ti,omap3-prm", .data = &prm_data }, + { .compatible = "ti,omap3-cm", .data = &cm_data }, + { .compatible = "ti,omap3-scrm", .data = &scrm_data }, + { .compatible = "ti,omap4-cm1", .data = &cm_data }, + { .compatible = "ti,omap4-prm", .data = &prm_data }, + { .compatible = "ti,omap4-cm2", .data = &cm2_data }, + { .compatible = "ti,omap4-scrm", .data = &scrm_data }, + { .compatible = "ti,omap5-prm", .data = &prm_data }, + { .compatible = "ti,omap5-cm-core-aon", .data = &cm_data }, + { .compatible = "ti,omap5-scrm", .data = &scrm_data }, + { .compatible = "ti,omap5-cm-core", .data = &cm2_data }, + { .compatible = "ti,dra7-prm", .data = &prm_data }, + { .compatible = "ti,dra7-cm-core-aon", .data = &cm_data }, + { .compatible = "ti,dra7-cm-core", .data = &cm2_data }, { } }; @@ -690,15 +706,20 @@ int __init omap_prcm_init(void) { struct device_node *np; void __iomem *mem; - int memmap_index = 0; + const struct of_device_id *match; + const struct omap_prcm_init_data *data; ti_clk_ll_ops = &omap_clk_ll_ops; - for_each_matching_node(np, omap_prcm_dt_match_table) { + for_each_matching_node_and_match(np, omap_prcm_dt_match_table, &match) { + data = match->data; + mem = of_iomap(np, 0); - clk_memmaps[memmap_index] = mem; - ti_dt_clk_init_provider(np, memmap_index); - memmap_index++; + if (!mem) + return -ENOMEM; + + clk_memmaps[data->index] = mem; + ti_dt_clk_init_provider(np, data->index); } return 0; diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 67844003493d..19895a3f48b7 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -221,6 +221,7 @@ struct ti_dt_clk { /* Static memmap indices */ enum { TI_CLKM_CM = 0, + TI_CLKM_CM2, TI_CLKM_PRM, TI_CLKM_SCRM, }; -- cgit v1.2.3 From bd735995308b553cc3c7f6a975aa284b270c7e2c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 2 Feb 2015 15:44:54 +0100 Subject: misc: Add attribute groups Add groups field to struct miscdevice for passing the attribute groups at device creation. In this way, the driver can avoid the manual call of device_create_file() after the device registration, which is basically a racy operation, in addition to the reduction of manual device_remove_file() calls. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/char/misc.c | 5 +++-- include/linux/miscdevice.h | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/char/misc.c b/drivers/char/misc.c index c892c296a4de..5bb3a2109ab7 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -207,8 +207,9 @@ int misc_register(struct miscdevice * misc) dev = MKDEV(MISC_MAJOR, misc->minor); - misc->this_device = device_create(misc_class, misc->parent, dev, - misc, "%s", misc->name); + misc->this_device = + device_create_with_groups(misc_class, misc->parent, dev, + misc, misc->groups, "%s", misc->name); if (IS_ERR(misc->this_device)) { int i = DYNAMIC_MINORS - misc->minor - 1; if (i < DYNAMIC_MINORS && i >= 0) diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index ee80dd7d9f60..819077c32690 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -52,6 +52,7 @@ #define MISC_DYNAMIC_MINOR 255 struct device; +struct attribute_group; struct miscdevice { int minor; @@ -60,6 +61,7 @@ struct miscdevice { struct list_head list; struct device *parent; struct device *this_device; + const struct attribute_group **groups; const char *nodename; umode_t mode; }; -- cgit v1.2.3 From 652261a7a86c884147930fa1e5ddd82a8a5748da Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Tue, 24 Mar 2015 14:02:38 +0000 Subject: ACPI: fix acpi_os_ioremap for arm64 The acpi_os_ioremap() function may be used to map normal RAM or IO regions. The current implementation simply uses ioremap_cache(). This will work for some architectures, but arm64 ioremap_cache() cannot be used to map IO regions which don't support caching. So for arm64, use ioremap() for non-RAM regions. CC: Rafael J Wysocki CC: Catalin Marinas Tested-by: Robert Richter Tested-by: Timur Tabi Acked-by: Robert Richter Acked-by: Rafael J. Wysocki Reviewed-by: Grant Likely Signed-off-by: Mark Salter Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/include/asm/acpi.h | 13 +++++++++++++ include/acpi/acpi_io.h | 4 ++++ 2 files changed, 17 insertions(+) (limited to 'include') diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 8b837ab59988..40e092483e96 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -12,8 +12,21 @@ #ifndef _ASM_ACPI_H #define _ASM_ACPI_H +#include + /* Basic configuration for ACPI */ #ifdef CONFIG_ACPI +/* ACPI table mapping after acpi_gbl_permanent_mmap is set */ +static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, + acpi_size size) +{ + if (!page_is_ram(phys >> PAGE_SHIFT)) + return ioremap(phys, size); + + return ioremap_cache(phys, size); +} +#define acpi_os_ioremap acpi_os_ioremap + #define acpi_strict 1 /* No out-of-spec workarounds on ARM64 */ extern int acpi_disabled; extern int acpi_noirq; diff --git a/include/acpi/acpi_io.h b/include/acpi/acpi_io.h index 444671e9c65d..dd86c5fc102d 100644 --- a/include/acpi/acpi_io.h +++ b/include/acpi/acpi_io.h @@ -3,11 +3,15 @@ #include +#include + +#ifndef acpi_os_ioremap static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size) { return ioremap_cache(phys, size); } +#endif void __iomem *__init_refok acpi_os_map_iomem(acpi_physical_address phys, acpi_size size); -- cgit v1.2.3 From 44caf2f37f009b2affa743073fa935826b6ab2fd Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 13 Feb 2015 14:25:24 +0000 Subject: iommu/vt-d: kill bogus ecap_niotlb_iunits() As far back as I can see (which right now is a draft of the v1.2 spec dating from September 2008), bits 24-31 of the Extended Capability Register have already been reserved. I have no idea why anyone ever thought there would be multiple sets of IOTLB registers, but we've never supported them and all we do is make sure we map enough MMIO space for them. Kill it dead. Those bits do actually have a different meaning now. Signed-off-by: David Woodhouse --- include/linux/intel-iommu.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index a65208a8fe18..ee24ada20428 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -115,10 +115,8 @@ static inline void dmar_writeq(void __iomem *addr, u64 val) * Extended Capability Register */ -#define ecap_niotlb_iunits(e) ((((e) >> 24) & 0xff) + 1) #define ecap_iotlb_offset(e) ((((e) >> 8) & 0x3ff) * 16) -#define ecap_max_iotlb_offset(e) \ - (ecap_iotlb_offset(e) + ecap_niotlb_iunits(e) * 16) +#define ecap_max_iotlb_offset(e) (ecap_iotlb_offset(e) + 16) #define ecap_coherent(e) ((e) & 0x1) #define ecap_qis(e) ((e) & 0x2) #define ecap_pass_through(e) ((e >> 6) & 0x1) -- cgit v1.2.3 From 4423f5e7d28c26af31df711c5c21eeacfac737b4 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 25 Mar 2015 15:43:39 +0000 Subject: iommu/vt-d: Add new extended capabilities from v2.3 VT-d specification Signed-off-by: David Woodhouse --- include/linux/intel-iommu.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'include') diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index ee24ada20428..796ef9645827 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -115,6 +115,17 @@ static inline void dmar_writeq(void __iomem *addr, u64 val) * Extended Capability Register */ +#define ecap_pss(e) ((e >> 35) & 0x1f) +#define ecap_eafs(e) ((e >> 34) & 0x1) +#define ecap_nwfs(e) ((e >> 33) & 0x1) +#define ecap_srs(e) ((e >> 31) & 0x1) +#define ecap_ers(e) ((e >> 30) & 0x1) +#define ecap_prs(e) ((e >> 29) & 0x1) +#define ecap_pasid(e) ((e >> 28) & 0x1) +#define ecap_dis(e) ((e >> 27) & 0x1) +#define ecap_nest(e) ((e >> 26) & 0x1) +#define ecap_mts(e) ((e >> 25) & 0x1) +#define ecap_ecs(e) ((e >> 24) & 0x1) #define ecap_iotlb_offset(e) ((((e) >> 8) & 0x3ff) * 16) #define ecap_max_iotlb_offset(e) (ecap_iotlb_offset(e) + 16) #define ecap_coherent(e) ((e) & 0x1) @@ -178,6 +189,9 @@ static inline void dmar_writeq(void __iomem *addr, u64 val) #define DMA_GSTS_IRES (((u32)1) << 25) #define DMA_GSTS_CFIS (((u32)1) << 23) +/* DMA_RTADDR_REG */ +#define DMA_RTADDR_RTT (((u64)1) << 11) + /* CCMD_REG */ #define DMA_CCMD_ICC (((u64)1) << 63) #define DMA_CCMD_GLOBAL_INVL (((u64)1) << 61) -- cgit v1.2.3 From 959801fef94b7ee66ea2c713229637a7e1770890 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Tue, 24 Feb 2015 14:25:00 -0500 Subject: serial: core: Add minor field to uart_port UART drivers that share ttyS namespace cannot trivially compute the ttyS index from the port->line value since the minor_start may be offset from minor 64. Further, to do so requires a pointer to the uart driver since there is no back pointer from uart_port to uart_driver. Rather than have UART drivers computing the minor value by themselves, encapsulate within the serial core at port registration time. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 1 + include/linux/serial_core.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 8379e3fa0162..a373eff44ae8 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2682,6 +2682,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) state->pm_state = UART_PM_STATE_UNDEFINED; uport->cons = drv->cons; + uport->minor = drv->tty_driver->minor_start + uport->line; /* * If this port is a console, then the spinlock is already diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index b0148e7bcbfa..980170e5a982 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -235,6 +235,7 @@ struct uart_port { const struct uart_ops *ops; unsigned int custom_divisor; unsigned int line; /* port index */ + unsigned int minor; resource_size_t mapbase; /* for ioremap */ struct device *dev; /* parent device */ unsigned char hub6; /* this should be in the 8250 driver */ -- cgit v1.2.3 From 828aef376d7a129547bc4ebb949965040177e3da Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Tue, 24 Mar 2015 14:02:46 +0000 Subject: ACPI / processor: Introduce phys_cpuid_t for CPU hardware ID CPU hardware ID (phys_id) is defined as u32 in structure acpi_processor, but phys_id is used as int in acpi processor driver, so it will lead to some inconsistence for the drivers. Furthermore, to cater for ACPI arch ports that implement 64 bits CPU ids a generic CPU physical id type is required. So introduce typedef u32 phys_cpuid_t in a common file, and introduce a macro PHYS_CPUID_INVALID as (phys_cpuid_t)(-1) if it's not defined by other archs, this will solve the inconsistence in acpi processor driver, and will prepare for the ACPI on ARM64 for the 64 bit CPU hardware ID in the following patch. CC: Rafael J Wysocki Suggested-by: Lorenzo Pieralisi Reviewed-by: Grant Likely Acked-by: Sudeep Holla Acked-by: Lorenzo Pieralisi Acked-by: Rafael J. Wysocki Signed-off-by: Catalin Marinas [hj: reworked cpu physid map return codes] Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/ia64/kernel/acpi.c | 2 +- arch/x86/kernel/acpi/boot.c | 2 +- drivers/acpi/acpi_processor.c | 7 ++++--- drivers/acpi/processor_core.c | 30 +++++++++++++++--------------- include/acpi/processor.h | 6 +++--- include/linux/acpi.h | 7 ++++++- 6 files changed, 30 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 2c4498919d3c..067ef4439fa4 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -887,7 +887,7 @@ static int _acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu) } /* wrapper to silence section mismatch warning */ -int __ref acpi_map_cpu(acpi_handle handle, int physid, int *pcpu) +int __ref acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, int *pcpu) { return _acpi_map_lsapic(handle, physid, pcpu); } diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 3d525c6124f6..e4f8582eb756 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -757,7 +757,7 @@ static int _acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu) } /* wrapper to silence section mismatch warning */ -int __ref acpi_map_cpu(acpi_handle handle, int physid, int *pcpu) +int __ref acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, int *pcpu) { return _acpi_map_lsapic(handle, physid, pcpu); } diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 1020b1b53a17..58f335ca2e75 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -170,7 +170,7 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr) acpi_status status; int ret; - if (pr->phys_id == -1) + if (pr->phys_id == PHYS_CPUID_INVALID) return -ENODEV; status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta); @@ -215,7 +215,8 @@ static int acpi_processor_get_info(struct acpi_device *device) union acpi_object object = { 0 }; struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; struct acpi_processor *pr = acpi_driver_data(device); - int phys_id, cpu_index, device_declaration = 0; + phys_cpuid_t phys_id; + int cpu_index, device_declaration = 0; acpi_status status = AE_OK; static int cpu0_initialized; unsigned long long value; @@ -263,7 +264,7 @@ static int acpi_processor_get_info(struct acpi_device *device) } phys_id = acpi_get_phys_id(pr->handle, device_declaration, pr->acpi_id); - if (phys_id < 0) + if (phys_id == PHYS_CPUID_INVALID) acpi_handle_debug(pr->handle, "failed to get CPU physical ID.\n"); pr->phys_id = phys_id; diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 7962651cdbd4..51cc29909e08 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -32,7 +32,7 @@ static struct acpi_table_madt *get_madt_table(void) } static int map_lapic_id(struct acpi_subtable_header *entry, - u32 acpi_id, int *apic_id) + u32 acpi_id, phys_cpuid_t *apic_id) { struct acpi_madt_local_apic *lapic = container_of(entry, struct acpi_madt_local_apic, header); @@ -48,7 +48,7 @@ static int map_lapic_id(struct acpi_subtable_header *entry, } static int map_x2apic_id(struct acpi_subtable_header *entry, - int device_declaration, u32 acpi_id, int *apic_id) + int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id) { struct acpi_madt_local_x2apic *apic = container_of(entry, struct acpi_madt_local_x2apic, header); @@ -65,7 +65,7 @@ static int map_x2apic_id(struct acpi_subtable_header *entry, } static int map_lsapic_id(struct acpi_subtable_header *entry, - int device_declaration, u32 acpi_id, int *apic_id) + int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id) { struct acpi_madt_local_sapic *lsapic = container_of(entry, struct acpi_madt_local_sapic, header); @@ -83,10 +83,10 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, return 0; } -static int map_madt_entry(int type, u32 acpi_id) +static phys_cpuid_t map_madt_entry(int type, u32 acpi_id) { unsigned long madt_end, entry; - int phys_id = -1; /* CPU hardware ID */ + phys_cpuid_t phys_id = PHYS_CPUID_INVALID; /* CPU hardware ID */ struct acpi_table_madt *madt; madt = get_madt_table(); @@ -117,12 +117,12 @@ static int map_madt_entry(int type, u32 acpi_id) return phys_id; } -static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id) +static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; struct acpi_subtable_header *header; - int phys_id = -1; + phys_cpuid_t phys_id = PHYS_CPUID_INVALID; if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) goto exit; @@ -149,27 +149,27 @@ exit: return phys_id; } -int acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id) +phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id) { - int phys_id; + phys_cpuid_t phys_id; phys_id = map_mat_entry(handle, type, acpi_id); - if (phys_id == -1) + if (phys_id == PHYS_CPUID_INVALID) phys_id = map_madt_entry(type, acpi_id); return phys_id; } -int acpi_map_cpuid(int phys_id, u32 acpi_id) +int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id) { #ifdef CONFIG_SMP int i; #endif - if (phys_id == -1) { + if (phys_id == PHYS_CPUID_INVALID) { /* * On UP processor, there is no _MAT or MADT table. - * So above phys_id is always set to -1. + * So above phys_id is always set to PHYS_CPUID_INVALID. * * BIOS may define multiple CPU handles even for UP processor. * For example, @@ -190,7 +190,7 @@ int acpi_map_cpuid(int phys_id, u32 acpi_id) if (nr_cpu_ids <= 1 && acpi_id == 0) return acpi_id; else - return phys_id; + return -1; } #ifdef CONFIG_SMP @@ -208,7 +208,7 @@ int acpi_map_cpuid(int phys_id, u32 acpi_id) int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) { - int phys_id; + phys_cpuid_t phys_id; phys_id = acpi_get_phys_id(handle, type, acpi_id); diff --git a/include/acpi/processor.h b/include/acpi/processor.h index b95dc32a6e6b..4188a4d3b597 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -196,7 +196,7 @@ struct acpi_processor_flags { struct acpi_processor { acpi_handle handle; u32 acpi_id; - u32 phys_id; /* CPU hardware ID such as APIC ID for x86 */ + phys_cpuid_t phys_id; /* CPU hardware ID such as APIC ID for x86 */ u32 id; /* CPU logical ID allocated by OS */ u32 pblk; int performance_platform_limit; @@ -310,8 +310,8 @@ static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit) #endif /* CONFIG_CPU_FREQ */ /* in processor_core.c */ -int acpi_get_phys_id(acpi_handle, int type, u32 acpi_id); -int acpi_map_cpuid(int phys_id, u32 acpi_id); +phys_cpuid_t acpi_get_phys_id(acpi_handle, int type, u32 acpi_id); +int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id); int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id); /* in processor_pdc.c */ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 24c7aa8b1d20..6ec33c595aea 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -146,9 +146,14 @@ void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa); int acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma); void acpi_numa_arch_fixup(void); +#ifndef PHYS_CPUID_INVALID +typedef u32 phys_cpuid_t; +#define PHYS_CPUID_INVALID (phys_cpuid_t)(-1) +#endif + #ifdef CONFIG_ACPI_HOTPLUG_CPU /* Arch dependent functions for cpu hotplug support */ -int acpi_map_cpu(acpi_handle handle, int physid, int *pcpu); +int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, int *pcpu); int acpi_unmap_cpu(int cpu); #endif /* CONFIG_ACPI_HOTPLUG_CPU */ -- cgit v1.2.3 From fbe61ec71ac975279cd47b6c299d5e33f63aac4e Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 24 Mar 2015 14:02:48 +0000 Subject: ARM64 / ACPI: Introduce ACPI_IRQ_MODEL_GIC and register device's gsi Introduce ACPI_IRQ_MODEL_GIC which is needed for ARM64 as GIC is used, and then register device's gsi with the core IRQ subsystem. acpi_register_gsi() is similar to DT based irq_of_parse_and_map(), since gsi is unique in the system, so use hwirq number directly for the mapping. We are going to implement stacked domains when GICv2m, GICv3, ITS support are added. CC: Marc Zyngier Originally-by: Amit Daniel Kachhap Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Acked-by: Rafael J. Wysocki Reviewed-by: Grant Likely Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/kernel/acpi.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/bus.c | 3 ++ include/linux/acpi.h | 1 + 3 files changed, 77 insertions(+) (limited to 'include') diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index c9203c0a1179..dec6f8aed3dc 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -75,6 +75,12 @@ static int __init dt_scan_depth1_nodes(unsigned long node, return 0; } +/* + * Since we're on ARM, the default interrupt routing model + * clearly has to be GIC. + */ +enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_GIC; + /* * __acpi_map_table() will be called before page_init(), so early_ioremap() * or early_memremap() should be called here to for ACPI table mapping. @@ -218,6 +224,73 @@ void __init acpi_init_cpus(void) pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus); } +int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) +{ + *irq = irq_find_mapping(NULL, gsi); + + return 0; +} +EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); + +/* + * success: return IRQ number (>0) + * failure: return =< 0 + */ +int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) +{ + unsigned int irq; + unsigned int irq_type; + + /* + * ACPI have no bindings to indicate SPI or PPI, so we + * use different mappings from DT in ACPI. + * + * For FDT + * PPI interrupt: in the range [0, 15]; + * SPI interrupt: in the range [0, 987]; + * + * For ACPI, GSI should be unique so using + * the hwirq directly for the mapping: + * PPI interrupt: in the range [16, 31]; + * SPI interrupt: in the range [32, 1019]; + */ + + if (trigger == ACPI_EDGE_SENSITIVE && + polarity == ACPI_ACTIVE_LOW) + irq_type = IRQ_TYPE_EDGE_FALLING; + else if (trigger == ACPI_EDGE_SENSITIVE && + polarity == ACPI_ACTIVE_HIGH) + irq_type = IRQ_TYPE_EDGE_RISING; + else if (trigger == ACPI_LEVEL_SENSITIVE && + polarity == ACPI_ACTIVE_LOW) + irq_type = IRQ_TYPE_LEVEL_LOW; + else if (trigger == ACPI_LEVEL_SENSITIVE && + polarity == ACPI_ACTIVE_HIGH) + irq_type = IRQ_TYPE_LEVEL_HIGH; + else + irq_type = IRQ_TYPE_NONE; + + /* + * Since only one GIC is supported in ACPI 5.0, we can + * create mapping refer to the default domain + */ + irq = irq_create_mapping(NULL, gsi); + if (!irq) + return irq; + + /* Set irq type if specified and different than the current one */ + if (irq_type != IRQ_TYPE_NONE && + irq_type != irq_get_trigger_type(irq)) + irq_set_irq_type(irq, irq_type); + return irq; +} +EXPORT_SYMBOL_GPL(acpi_register_gsi); + +void acpi_unregister_gsi(u32 gsi) +{ +} +EXPORT_SYMBOL_GPL(acpi_unregister_gsi); + static int __init acpi_parse_fadt(struct acpi_table_header *table) { struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table; diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 8b67bd0f6bb5..c412fdb28d34 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -448,6 +448,9 @@ static int __init acpi_bus_init_irq(void) case ACPI_IRQ_MODEL_IOSAPIC: message = "IOSAPIC"; break; + case ACPI_IRQ_MODEL_GIC: + message = "GIC"; + break; case ACPI_IRQ_MODEL_PLATFORM: message = "platform specific model"; break; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 6ec33c595aea..de4e86f89c83 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -73,6 +73,7 @@ enum acpi_irq_model_id { ACPI_IRQ_MODEL_IOAPIC, ACPI_IRQ_MODEL_IOSAPIC, ACPI_IRQ_MODEL_PLATFORM, + ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_COUNT }; -- cgit v1.2.3 From d60fc3892c4de4a25658786f941690462c5a5bab Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Tue, 24 Mar 2015 14:02:49 +0000 Subject: irqchip: Add GICv2 specific ACPI boot support ACPI kernel uses MADT table for proper GIC initialization. It needs to parse GIC related subtables, collect CPU interface and distributor addresses and call driver initialization function (which is hardware abstraction agnostic). In a similar way, FDT initialize GICv1/2. NOTE: This commit allow to initialize GICv1/2 basic functionality. While now simple GICv2 init call is used, any further GIC features require generic infrastructure for proper ACPI irqchip initialization. That mechanism and stacked irqdomains to support GICv2 MSI/virtualization extension, GICv3/4 and its ITS are considered as next steps. CC: Jason Cooper CC: Marc Zyngier CC: Thomas Gleixner Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Acked-by: Marc Zyngier Acked-by: Jason Cooper Reviewed-by: Grant Likely Signed-off-by: Tomasz Nowicki Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/include/asm/acpi.h | 2 + arch/arm64/include/asm/irq.h | 13 +++++ arch/arm64/kernel/acpi.c | 25 +++++++++ drivers/irqchip/irq-gic.c | 102 +++++++++++++++++++++++++++++++++++ drivers/irqchip/irqchip.c | 3 ++ include/linux/acpi_irq.h | 10 ++++ include/linux/irqchip/arm-gic-acpi.h | 31 +++++++++++ 7 files changed, 186 insertions(+) create mode 100644 include/linux/acpi_irq.h create mode 100644 include/linux/irqchip/arm-gic-acpi.h (limited to 'include') diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index eea0bc3b09d5..59c05d8ea4a0 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -13,6 +13,8 @@ #define _ASM_ACPI_H #include +#include + #include #include diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h index 94c53674a31d..bbb251b14746 100644 --- a/arch/arm64/include/asm/irq.h +++ b/arch/arm64/include/asm/irq.h @@ -1,6 +1,8 @@ #ifndef __ASM_IRQ_H #define __ASM_IRQ_H +#include + #include struct pt_regs; @@ -8,4 +10,15 @@ struct pt_regs; extern void migrate_irqs(void); extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); +static inline void acpi_irq_init(void) +{ + /* + * Hardcode ACPI IRQ chip initialization to GICv2 for now. + * Proper irqchip infrastructure will be implemented along with + * incoming GICv2m|GICv3|ITS bits. + */ + acpi_gic_init(); +} +#define acpi_irq_init acpi_irq_init + #endif diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index dec6f8aed3dc..6468f8898530 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -359,3 +359,28 @@ void __init acpi_boot_table_init(void) pr_err("Can't find FADT\n"); } } + +void __init acpi_gic_init(void) +{ + struct acpi_table_header *table; + acpi_status status; + acpi_size tbl_size; + int err; + + if (acpi_disabled) + return; + + status = acpi_get_table_with_size(ACPI_SIG_MADT, 0, &table, &tbl_size); + if (ACPI_FAILURE(status)) { + const char *msg = acpi_format_exception(status); + + pr_err("Failed to get MADT table, %s\n", msg); + return; + } + + err = gic_v2_acpi_init(table); + if (err) + pr_err("Failed to initialize GIC IRQ controller"); + + early_acpi_os_unmap_memory((char *)table, tbl_size); +} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 471e1cdc1933..d15a36a93c52 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -33,12 +33,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -1090,3 +1092,103 @@ IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init); IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init); #endif + +#ifdef CONFIG_ACPI +static phys_addr_t dist_phy_base, cpu_phy_base __initdata; + +static int __init +gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *processor; + phys_addr_t gic_cpu_base; + static int cpu_base_assigned; + + processor = (struct acpi_madt_generic_interrupt *)header; + + if (BAD_MADT_ENTRY(processor, end)) + return -EINVAL; + + /* + * There is no support for non-banked GICv1/2 register in ACPI spec. + * All CPU interface addresses have to be the same. + */ + gic_cpu_base = processor->base_address; + if (cpu_base_assigned && gic_cpu_base != cpu_phy_base) + return -EINVAL; + + cpu_phy_base = gic_cpu_base; + cpu_base_assigned = 1; + return 0; +} + +static int __init +gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_distributor *dist; + + dist = (struct acpi_madt_generic_distributor *)header; + + if (BAD_MADT_ENTRY(dist, end)) + return -EINVAL; + + dist_phy_base = dist->base_address; + return 0; +} + +int __init +gic_v2_acpi_init(struct acpi_table_header *table) +{ + void __iomem *cpu_base, *dist_base; + int count; + + /* Collect CPU base addresses */ + count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_cpu, table, + ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0); + if (count <= 0) { + pr_err("No valid GICC entries exist\n"); + return -EINVAL; + } + + /* + * Find distributor base address. We expect one distributor entry since + * ACPI 5.1 spec neither support multi-GIC instances nor GIC cascade. + */ + count = acpi_parse_entries(ACPI_SIG_MADT, + sizeof(struct acpi_table_madt), + gic_acpi_parse_madt_distributor, table, + ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0); + if (count <= 0) { + pr_err("No valid GICD entries exist\n"); + return -EINVAL; + } else if (count > 1) { + pr_err("More than one GICD entry detected\n"); + return -EINVAL; + } + + cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE); + if (!cpu_base) { + pr_err("Unable to map GICC registers\n"); + return -ENOMEM; + } + + dist_base = ioremap(dist_phy_base, ACPI_GICV2_DIST_MEM_SIZE); + if (!dist_base) { + pr_err("Unable to map GICD registers\n"); + iounmap(cpu_base); + return -ENOMEM; + } + + /* + * Initialize zero GIC instance (no multi-GIC support). Also, set GIC + * as default IRQ domain to allow for GSI registration and GSI to IRQ + * number translation (see acpi_register_gsi() and acpi_gsi_to_irq()). + */ + gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); + irq_set_default_host(gic_data[0].domain); + return 0; +} +#endif diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c index 0fe2f718d81c..afd1af3dfe5a 100644 --- a/drivers/irqchip/irqchip.c +++ b/drivers/irqchip/irqchip.c @@ -8,6 +8,7 @@ * warranty of any kind, whether express or implied. */ +#include #include #include #include @@ -26,4 +27,6 @@ extern struct of_device_id __irqchip_of_table[]; void __init irqchip_init(void) { of_irq_init(__irqchip_of_table); + + acpi_irq_init(); } diff --git a/include/linux/acpi_irq.h b/include/linux/acpi_irq.h new file mode 100644 index 000000000000..f10c87265855 --- /dev/null +++ b/include/linux/acpi_irq.h @@ -0,0 +1,10 @@ +#ifndef _LINUX_ACPI_IRQ_H +#define _LINUX_ACPI_IRQ_H + +#include + +#ifndef acpi_irq_init +static inline void acpi_irq_init(void) { } +#endif + +#endif /* _LINUX_ACPI_IRQ_H */ diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h new file mode 100644 index 000000000000..de3419ed3937 --- /dev/null +++ b/include/linux/irqchip/arm-gic-acpi.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014, Linaro Ltd. + * Author: Tomasz Nowicki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef ARM_GIC_ACPI_H_ +#define ARM_GIC_ACPI_H_ + +#ifdef CONFIG_ACPI + +/* + * Hard code here, we can not get memory size from MADT (but FDT does), + * Actually no need to do that, because this size can be inferred + * from GIC spec. + */ +#define ACPI_GICV2_DIST_MEM_SIZE (SZ_4K) +#define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K) + +struct acpi_table_header; + +int gic_v2_acpi_init(struct acpi_table_header *table); +void acpi_gic_init(void); +#else +static inline void acpi_gic_init(void) { } +#endif + +#endif /* ARM_GIC_ACPI_H_ */ -- cgit v1.2.3 From b09ca1ecf6d499d5a33f978c905d2fbcc79b55d9 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 24 Mar 2015 14:02:50 +0000 Subject: clocksource / arch_timer: Parse GTDT to initialize arch timer Using the information presented by GTDT (Generic Timer Description Table) to initialize the arch timer (not memory-mapped). CC: Daniel Lezcano CC: Thomas Gleixner Originally-by: Amit Daniel Kachhap Tested-by: Suravee Suthikulpanit Tested-by: Yijing Wang Tested-by: Mark Langsdorf Tested-by: Jon Masters Tested-by: Timur Tabi Tested-by: Robert Richter Acked-by: Robert Richter Acked-by: Daniel Lezcano Reviewed-by: Grant Likely Signed-off-by: Hanjun Guo Signed-off-by: Will Deacon --- arch/arm64/kernel/time.c | 7 ++ drivers/clocksource/arm_arch_timer.c | 132 ++++++++++++++++++++++++++++------- include/linux/clocksource.h | 6 ++ 3 files changed, 118 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c index 1a7125c3099b..42f9195cf2f8 100644 --- a/arch/arm64/kernel/time.c +++ b/arch/arm64/kernel/time.c @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -72,6 +73,12 @@ void __init time_init(void) tick_setup_hrtimer_broadcast(); + /* + * Since ACPI or FDT will only one be available in the system, + * we can use acpi_generic_timer_init() here safely + */ + acpi_generic_timer_init(); + arch_timer_rate = arch_timer_get_rate(); if (!arch_timer_rate) panic("Unable to initialise architected timer.\n"); diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index a3025e7ae35f..ea62fc79e1e8 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -371,8 +372,12 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np) if (arch_timer_rate) return; - /* Try to determine the frequency from the device tree or CNTFRQ */ - if (of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) { + /* + * Try to determine the frequency from the device tree or CNTFRQ, + * if ACPI is enabled, get the frequency from CNTFRQ ONLY. + */ + if (!acpi_disabled || + of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) { if (cntbase) arch_timer_rate = readl_relaxed(cntbase + CNTFRQ); else @@ -691,28 +696,8 @@ static void __init arch_timer_common_init(void) arch_timer_arch_init(); } -static void __init arch_timer_init(struct device_node *np) +static void __init arch_timer_init(void) { - int i; - - if (arch_timers_present & ARCH_CP15_TIMER) { - pr_warn("arch_timer: multiple nodes in dt, skipping\n"); - return; - } - - arch_timers_present |= ARCH_CP15_TIMER; - for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) - arch_timer_ppi[i] = irq_of_parse_and_map(np, i); - arch_timer_detect_rate(NULL, np); - - /* - * If we cannot rely on firmware initializing the timer registers then - * we should use the physical timers instead. - */ - if (IS_ENABLED(CONFIG_ARM) && - of_property_read_bool(np, "arm,cpu-registers-not-fw-configured")) - arch_timer_use_virtual = false; - /* * If HYP mode is available, we know that the physical timer * has been configured to be accessible from PL1. Use it, so @@ -731,13 +716,39 @@ static void __init arch_timer_init(struct device_node *np) } } - arch_timer_c3stop = !of_property_read_bool(np, "always-on"); - arch_timer_register(); arch_timer_common_init(); } -CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init); -CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init); + +static void __init arch_timer_of_init(struct device_node *np) +{ + int i; + + if (arch_timers_present & ARCH_CP15_TIMER) { + pr_warn("arch_timer: multiple nodes in dt, skipping\n"); + return; + } + + arch_timers_present |= ARCH_CP15_TIMER; + for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) + arch_timer_ppi[i] = irq_of_parse_and_map(np, i); + + arch_timer_detect_rate(NULL, np); + + arch_timer_c3stop = !of_property_read_bool(np, "always-on"); + + /* + * If we cannot rely on firmware initializing the timer registers then + * we should use the physical timers instead. + */ + if (IS_ENABLED(CONFIG_ARM) && + of_property_read_bool(np, "arm,cpu-registers-not-fw-configured")) + arch_timer_use_virtual = false; + + arch_timer_init(); +} +CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); +CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); static void __init arch_timer_mem_init(struct device_node *np) { @@ -804,3 +815,70 @@ static void __init arch_timer_mem_init(struct device_node *np) } CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", arch_timer_mem_init); + +#ifdef CONFIG_ACPI +static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags) +{ + int trigger, polarity; + + if (!interrupt) + return 0; + + trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE + : ACPI_LEVEL_SENSITIVE; + + polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW + : ACPI_ACTIVE_HIGH; + + return acpi_register_gsi(NULL, interrupt, trigger, polarity); +} + +/* Initialize per-processor generic timer */ +static int __init arch_timer_acpi_init(struct acpi_table_header *table) +{ + struct acpi_table_gtdt *gtdt; + + if (arch_timers_present & ARCH_CP15_TIMER) { + pr_warn("arch_timer: already initialized, skipping\n"); + return -EINVAL; + } + + gtdt = container_of(table, struct acpi_table_gtdt, header); + + arch_timers_present |= ARCH_CP15_TIMER; + + arch_timer_ppi[PHYS_SECURE_PPI] = + map_generic_timer_interrupt(gtdt->secure_el1_interrupt, + gtdt->secure_el1_flags); + + arch_timer_ppi[PHYS_NONSECURE_PPI] = + map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt, + gtdt->non_secure_el1_flags); + + arch_timer_ppi[VIRT_PPI] = + map_generic_timer_interrupt(gtdt->virtual_timer_interrupt, + gtdt->virtual_timer_flags); + + arch_timer_ppi[HYP_PPI] = + map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt, + gtdt->non_secure_el2_flags); + + /* Get the frequency from CNTFRQ */ + arch_timer_detect_rate(NULL, NULL); + + /* Always-on capability */ + arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON); + + arch_timer_init(); + return 0; +} + +/* Initialize all the generic timers presented in GTDT */ +void __init acpi_generic_timer_init(void) +{ + if (acpi_disabled) + return; + + acpi_table_parse(ACPI_SIG_GTDT, arch_timer_acpi_init); +} +#endif diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 9c78d15d33e4..2b2e1f80c519 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -244,4 +244,10 @@ extern void clocksource_of_init(void); static inline void clocksource_of_init(void) {} #endif +#ifdef CONFIG_ACPI +void acpi_generic_timer_init(void); +#else +static inline void acpi_generic_timer_init(void) { } +#endif + #endif /* _LINUX_CLOCKSOURCE_H */ -- cgit v1.2.3 From c7cef0a84912cab3c9df8949b034e4aa62982ec9 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 9 Mar 2015 16:27:12 -0400 Subject: console: Add extensible console matching Add match() method to struct console which allows the console to perform console command line matching instead of (or in addition to) default console matching (ie., by fixed name and index). The match() method returns 0 to indicate a successful match; normal console matching occurs if no match() method is defined or the match() method returns non-zero. The match() method is expected to set the console index if required. Re-implement earlycon-to-console-handoff with direct matching of "console=uart|uart8250,..." to the 8250 ttyS console. Acked-by: Rob Herring Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 64 +++++++++++++++++++++++++++--------- drivers/tty/serial/8250/8250_early.c | 23 ------------- include/linux/console.h | 3 +- include/linux/serial_8250.h | 2 -- kernel/printk/printk.c | 52 ++++++++++------------------- 5 files changed, 67 insertions(+), 77 deletions(-) (limited to 'include') diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index bd06ab790c64..924ee1e13828 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -3322,9 +3322,54 @@ static int serial8250_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -static int serial8250_console_early_setup(void) +/** + * serial8250_console_match - non-standard console matching + * @co: registering console + * @name: name from console command line + * @idx: index from console command line + * @options: ptr to option string from console command line + * + * Only attempts to match console command lines of the form: + * console=uart<>,io|mmio|mmio32,, + * console=uart<>,,options + * This form is used to register an initial earlycon boot console and + * replace it with the serial8250_console at 8250 driver init. + * + * Performs console setup for a match (as required by interface) + * + * Returns 0 if console matches; otherwise non-zero to use default matching + */ +static int serial8250_console_match(struct console *co, char *name, int idx, + char *options) { - return serial8250_find_port_for_earlycon(); + char match[] = "uart"; /* 8250-specific earlycon name */ + unsigned char iotype; + unsigned long addr; + int i; + + if (strncmp(name, match, 4) != 0) + return -ENODEV; + + if (uart_parse_earlycon(options, &iotype, &addr, &options)) + return -ENODEV; + + /* try to match the port specified on the command line */ + for (i = 0; i < nr_uarts; i++) { + struct uart_port *port = &serial8250_ports[i].port; + + if (port->iotype != iotype) + continue; + if ((iotype == UPIO_MEM || iotype == UPIO_MEM32) && + (port->mapbase != addr)) + continue; + if (iotype == UPIO_PORT && port->iobase != addr) + continue; + + co->index = i; + return serial8250_console_setup(co, options); + } + + return -ENODEV; } static struct console serial8250_console = { @@ -3332,7 +3377,7 @@ static struct console serial8250_console = { .write = serial8250_console_write, .device = uart_console_device, .setup = serial8250_console_setup, - .early_setup = serial8250_console_early_setup, + .match = serial8250_console_match, .flags = CON_PRINTBUFFER | CON_ANYTIME, .index = -1, .data = &serial8250_reg, @@ -3346,19 +3391,6 @@ static int __init serial8250_console_init(void) } console_initcall(serial8250_console_init); -int serial8250_find_port(struct uart_port *p) -{ - int line; - struct uart_port *port; - - for (line = 0; line < nr_uarts; line++) { - port = &serial8250_ports[line].port; - if (uart_match_port(p, port)) - return line; - } - return -ENODEV; -} - #define SERIAL8250_CONSOLE &serial8250_console #else #define SERIAL8250_CONSOLE NULL diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index c31a22b4f845..49bca65057e6 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -173,26 +173,3 @@ int __init setup_early_serial8250_console(char *cmdline) return setup_earlycon(cmdline, match, early_serial8250_setup); } - -int serial8250_find_port_for_earlycon(void) -{ - struct earlycon_device *device = early_device; - struct uart_port *port = device ? &device->port : NULL; - int line; - int ret; - - if (!port || (!port->membase && !port->iobase)) - return -ENODEV; - - line = serial8250_find_port(port); - if (line < 0) - return -ENODEV; - - ret = update_console_cmdline("uart", 8250, - "ttyS", line, device->options); - if (ret < 0) - ret = update_console_cmdline("uart", 0, - "ttyS", line, device->options); - - return ret; -} diff --git a/include/linux/console.h b/include/linux/console.h index 7571a16bd653..9f50fb413c11 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -123,7 +123,7 @@ struct console { struct tty_driver *(*device)(struct console *, int *); void (*unblank)(void); int (*setup)(struct console *, char *); - int (*early_setup)(void); + int (*match)(struct console *, char *name, int idx, char *options); short flags; short index; int cflag; @@ -141,7 +141,6 @@ extern int console_set_on_cmdline; extern struct console *early_console; extern int add_preferred_console(char *name, int idx, char *options); -extern int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options); extern void register_console(struct console *); extern int unregister_console(struct console *); extern struct console *console_drivers; diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index a8efa235b7c1..f26ae7fa30ae 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -118,8 +118,6 @@ void serial8250_resume_port(int line); extern int early_serial_setup(struct uart_port *port); -extern int serial8250_find_port(struct uart_port *p); -extern int serial8250_find_port_for_earlycon(void); extern unsigned int serial8250_early_in(struct uart_port *port, int offset); extern void serial8250_early_out(struct uart_port *port, int offset, int value); extern int setup_early_serial8250_console(char *cmdline); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 26f899809539..dda959221086 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2017,24 +2017,6 @@ int add_preferred_console(char *name, int idx, char *options) return __add_preferred_console(name, idx, options, NULL); } -int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options) -{ - struct console_cmdline *c; - int i; - - for (i = 0, c = console_cmdline; - i < MAX_CMDLINECONSOLES && c->name[0]; - i++, c++) - if (strcmp(c->name, name) == 0 && c->index == idx) { - strlcpy(c->name, name_new, sizeof(c->name)); - c->options = options; - c->index = idx_new; - return i; - } - /* not found */ - return -1; -} - bool console_suspend_enabled = true; EXPORT_SYMBOL(console_suspend_enabled); @@ -2436,9 +2418,6 @@ void register_console(struct console *newcon) if (preferred_console < 0 || bcon || !console_drivers) preferred_console = selected_console; - if (newcon->early_setup) - newcon->early_setup(); - /* * See if we want to use this console driver. If we * didn't select a console we take the first one @@ -2464,21 +2443,26 @@ void register_console(struct console *newcon) for (i = 0, c = console_cmdline; i < MAX_CMDLINECONSOLES && c->name[0]; i++, c++) { - BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name)); - if (strcmp(c->name, newcon->name) != 0) - continue; - if (newcon->index >= 0 && - newcon->index != c->index) - continue; - if (newcon->index < 0) - newcon->index = c->index; + if (!newcon->match || + newcon->match(newcon, c->name, c->index, c->options) != 0) { + /* default matching */ + BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name)); + if (strcmp(c->name, newcon->name) != 0) + continue; + if (newcon->index >= 0 && + newcon->index != c->index) + continue; + if (newcon->index < 0) + newcon->index = c->index; - if (_braille_register_console(newcon, c)) - return; + if (_braille_register_console(newcon, c)) + return; + + if (newcon->setup && + newcon->setup(newcon, c->options) != 0) + break; + } - if (newcon->setup && - newcon->setup(newcon, console_cmdline[i].options) != 0) - break; newcon->flags |= CON_ENABLED; if (i == selected_console) { newcon->flags |= CON_CONSDEV; -- cgit v1.2.3 From 470ca0de69feaba5df215ad804cec1859883a5ed Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 9 Mar 2015 16:27:21 -0400 Subject: serial: earlycon: Enable earlycon without command line param Earlycon matching can only be triggered if 'earlycon=...' has been specified on the kernel command line. To workaround this limitation requires tight coupling between arches and specific serial drivers in order to start an earlycon. Devicetree avoids this limitation with a link table that contains the required data to match earlycons. Mirror this approach for earlycon match by name. Re-purpose EARLYCON_DECLARE to generate a table entry which associates name with setup() function. Re-purpose setup_earlycon() to scan this table for an earlycon match, which is registered if found. Declare one "earlycon" early_param, which calls setup_earlycon(). This design allows setup_earlycon() to be called directly with a param string (as if 'earlycon=...' had been set on the command line). Re-registration (either directly or by early_param) is prevented. Acked-by: Rob Herring Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_early.c | 7 +-- drivers/tty/serial/earlycon.c | 92 ++++++++++++++++++++++++++++-------- include/asm-generic/vmlinux.lds.h | 9 ++++ include/linux/serial_core.h | 19 ++++---- 4 files changed, 94 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index b199c10689f4..d272139a5729 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -170,10 +170,5 @@ EARLYCON_DECLARE(uart, early_serial8250_setup); int __init setup_early_serial8250_console(char *cmdline) { - char match[] = "uart8250"; - - if (cmdline && cmdline[4] == ',') - match[4] = '\0'; - - return setup_earlycon(cmdline, match, early_serial8250_setup); + return setup_earlycon(cmdline); } diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 9fb76b66c545..5fdc9f3ecd64 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -10,6 +10,9 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -34,6 +37,10 @@ static struct earlycon_device early_console_dev = { .con = &early_con, }; +extern struct earlycon_id __earlycon_table[]; +static const struct earlycon_id __earlycon_table_sentinel + __used __section(__earlycon_table_end); + static const struct of_device_id __earlycon_of_table_sentinel __used __section(__earlycon_of_table_end); @@ -96,9 +103,7 @@ static int __init parse_options(struct earlycon_device *device, char *options) return 0; } - -static int __init -register_earlycon(char *buf, int (*setup)(struct earlycon_device *, const char *)) +static int __init register_earlycon(char *buf, const struct earlycon_id *match) { int err; struct uart_port *port = &early_console_dev.port; @@ -112,7 +117,7 @@ register_earlycon(char *buf, int (*setup)(struct earlycon_device *, const char * port->membase = earlycon_map(port->mapbase, 64); early_console_dev.con->data = &early_console_dev; - err = setup(&early_console_dev, buf); + err = match->setup(&early_console_dev, buf); if (err < 0) return err; if (!early_console_dev.con->write) @@ -122,27 +127,76 @@ register_earlycon(char *buf, int (*setup)(struct earlycon_device *, const char * return 0; } -int __init setup_earlycon(char *buf, const char *match, - int (*setup)(struct earlycon_device *, const char *)) +/** + * setup_earlycon - match and register earlycon console + * @buf: earlycon param string + * + * Registers the earlycon console matching the earlycon specified + * in the param string @buf. Acceptable param strings are of the form + * ,io|mmio|mmio32,, + * ,0x, + * , + * + * + * Only for the third form does the earlycon setup() method receive the + * string in the 'options' parameter; all other forms set + * the parameter to NULL. + * + * Returns 0 if an attempt to register the earlycon was made, + * otherwise negative error code + */ +int __init setup_earlycon(char *buf) { - size_t len; + const struct earlycon_id *match; - if (!buf || !match || !setup) - return 0; + if (!buf || !buf[0]) + return -EINVAL; - len = strlen(match); - if (strncmp(buf, match, len)) - return 0; + if (early_con.flags & CON_ENABLED) + return -EALREADY; - if (buf[len]) { - if (buf[len] != ',') - return 0; - buf += len + 1; - } else - buf = NULL; + for (match = __earlycon_table; match->name[0]; match++) { + size_t len = strlen(match->name); - return register_earlycon(buf, setup); + if (strncmp(buf, match->name, len)) + continue; + + if (buf[len]) { + if (buf[len] != ',') + continue; + buf += len + 1; + } else + buf = NULL; + + return register_earlycon(buf, match); + } + + return -ENOENT; +} + +/* early_param wrapper for setup_earlycon() */ +static int __init param_setup_earlycon(char *buf) +{ + int err; + + /* + * Just 'earlycon' is a valid param for devicetree earlycons; + * don't generate a warning from parse_early_params() in that case + */ + if (!buf || !buf[0]) + return 0; + + err = setup_earlycon(buf); + if (err == -ENOENT) { + pr_warn("no match for %s\n", buf); + err = 0; + } else if (err == -EALREADY) { + pr_warn("already registered\n"); + err = 0; + } + return err; } +early_param("earlycon", param_setup_earlycon); int __init of_setup_earlycon(unsigned long addr, int (*setup)(struct earlycon_device *, const char *)) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index ac78910d7416..87e5b6f8f4fc 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -150,6 +150,14 @@ #define TRACE_SYSCALLS() #endif +#ifdef CONFIG_SERIAL_EARLYCON +#define EARLYCON_TABLE() . = ALIGN(8); \ + VMLINUX_SYMBOL(__earlycon_table) = .; \ + *(__earlycon_table) \ + *(__earlycon_table_end) +#else +#define EARLYCON_TABLE() +#endif #define ___OF_TABLE(cfg, name) _OF_TABLE_##cfg(name) #define __OF_TABLE(cfg, name) ___OF_TABLE(cfg, name) @@ -503,6 +511,7 @@ CPU_METHOD_OF_TABLES() \ KERNEL_DTB() \ IRQCHIP_OF_MATCH_TABLE() \ + EARLYCON_TABLE() \ EARLYCON_OF_TABLES() #define INIT_TEXT \ diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 980170e5a982..8aeec4913a9c 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -337,18 +337,21 @@ struct earlycon_device { char options[16]; /* e.g., 115200n8 */ unsigned int baud; }; -int setup_earlycon(char *buf, const char *match, - int (*setup)(struct earlycon_device *, const char *)); +struct earlycon_id { + char name[16]; + int (*setup)(struct earlycon_device *, const char *options); +}; + +extern int setup_earlycon(char *buf); extern int of_setup_earlycon(unsigned long addr, int (*setup)(struct earlycon_device *, const char *)); -#define EARLYCON_DECLARE(name, func) \ -static int __init name ## _setup_earlycon(char *buf) \ -{ \ - return setup_earlycon(buf, __stringify(name), func); \ -} \ -early_param("earlycon", name ## _setup_earlycon); +#define EARLYCON_DECLARE(_name, func) \ + static const struct earlycon_id __earlycon_##_name \ + __used __section(__earlycon_table) \ + = { .name = __stringify(_name), \ + .setup = func } #define OF_EARLYCON_DECLARE(name, compat, fn) \ _OF_DECLARE(earlycon, name, compat, fn, void *) -- cgit v1.2.3 From df519e7bd33cf56d8a5ce357dfb94248d427b688 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 9 Mar 2015 16:27:22 -0400 Subject: serial: 8250_early: Remove setup_early_serial8250_console() setup_earlycon() will now match and register the desired earlycon from the param string (as if 'earlycon=...' had been set on the command line). Use setup_earlycon() from existing arch call sites which start an earlycon directly. Acked-by: Rob Herring Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- arch/mips/mti-malta/malta-init.c | 4 ++-- drivers/firmware/pcdp.c | 4 ++-- drivers/tty/serial/8250/8250_early.c | 5 ----- include/linux/serial_8250.h | 1 - 4 files changed, 4 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index 6849f533154f..cec3e187c48f 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -75,7 +75,7 @@ static void __init console_config(void) if ((strstr(fw_getcmdline(), "earlycon=")) == NULL) { sprintf(console_string, "uart8250,io,0x3f8,%d%c%c", baud, parity, bits); - setup_early_serial8250_console(console_string); + setup_earlycon(console_string); } if ((strstr(fw_getcmdline(), "console=")) == NULL) { diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c index a330492e06f9..75273a251603 100644 --- a/drivers/firmware/pcdp.c +++ b/drivers/firmware/pcdp.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include "pcdp.h" @@ -43,7 +43,7 @@ setup_serial_console(struct pcdp_uart *uart) } add_preferred_console("uart", 8250, &options[9]); - return setup_early_serial8250_console(options); + return setup_earlycon(options); #else return -ENODEV; #endif diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index d272139a5729..a2b4e58690ba 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -167,8 +167,3 @@ static int __init early_serial8250_setup(struct earlycon_device *device, } EARLYCON_DECLARE(uart8250, early_serial8250_setup); EARLYCON_DECLARE(uart, early_serial8250_setup); - -int __init setup_early_serial8250_console(char *cmdline) -{ - return setup_earlycon(cmdline); -} diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index f26ae7fa30ae..ca9f87beac63 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -120,7 +120,6 @@ extern int early_serial_setup(struct uart_port *port); extern unsigned int serial8250_early_in(struct uart_port *port, int offset); extern void serial8250_early_out(struct uart_port *port, int offset, int value); -extern int setup_early_serial8250_console(char *cmdline); extern void serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old); extern int serial8250_do_startup(struct uart_port *port); -- cgit v1.2.3 From 01218bf14ee60d4a2d6c667ebdbba3ae9a7a1d66 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 26 Mar 2015 09:47:55 -0700 Subject: of: Explicitly include linux/types.h in of_graph.h In current -next of_graph.h fails to build due to it relying on linux/types.h without explicitly including it: ../include/linux/of_graph.h:43:71: error: unknown type name 'u32' caused by bfe446e37c4e (of: Add of_graph_get_port_by_id function). Add an explicit inclusion to fix this. Signed-off-by: Mark Brown Acked-by: Laurent Pinchart Acked-by: Philipp Zabel Signed-off-by: Rob Herring --- include/linux/of_graph.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h index 3c1c95a39e0c..7bc92e050608 100644 --- a/include/linux/of_graph.h +++ b/include/linux/of_graph.h @@ -14,6 +14,8 @@ #ifndef __LINUX_OF_GRAPH_H #define __LINUX_OF_GRAPH_H +#include + /** * struct of_endpoint - the OF graph endpoint data structure * @port: identifier (value of reg property) of a port this endpoint belongs to -- cgit v1.2.3 From a4416cd1ac7b48988f0f41a17769d65c71ffc504 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Tue, 24 Feb 2015 14:25:07 -0500 Subject: serial: 8250: Separate legacy irq handling from core port operations Prepare for 8250 split; decouple irq setup/teardown and handler from core port operations. Introduce setup_irq() and release_irq() 8250 driver methods; the 8250 core will use these methods to install and remove irq handling for the given 8250 port. Refactor irq chain linking/unlinking from 8250 core into univ8250_setup_irq()/univ8250_release_irq() for the universal 8250 driver. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 83 +++++++++++++++++++++++-------------- include/linux/serial_8250.h | 15 +++++++ 2 files changed, 68 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 625f81c9b55e..06bb2ced2c94 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1890,6 +1890,48 @@ static void serial8250_backup_timeout(unsigned long data) jiffies + uart_poll_timeout(&up->port) + HZ / 5); } +static int univ8250_setup_irq(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + int retval = 0; + + /* + * The above check will only give an accurate result the first time + * the port is opened so this value needs to be preserved. + */ + if (up->bugs & UART_BUG_THRE) { + pr_debug("ttyS%d - using backup timer\n", serial_index(port)); + + up->timer.function = serial8250_backup_timeout; + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + + uart_poll_timeout(port) + HZ / 5); + } + + /* + * If the "interrupt" for this port doesn't correspond with any + * hardware interrupt, we use a timer-based system. The original + * driver used to do this with IRQ0. + */ + if (!port->irq) { + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); + } else + retval = serial_link_irq_chain(up); + + return retval; +} + +static void univ8250_release_irq(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + + del_timer_sync(&up->timer); + up->timer.function = serial8250_timeout; + if (port->irq) + serial_unlink_irq_chain(up); +} + static unsigned int serial8250_tx_empty(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); @@ -2194,35 +2236,12 @@ int serial8250_do_startup(struct uart_port *port) if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || up->port.flags & UPF_BUG_THRE) { up->bugs |= UART_BUG_THRE; - pr_debug("ttyS%d - using backup timer\n", - serial_index(port)); } } - /* - * The above check will only give an accurate result the first time - * the port is opened so this value needs to be preserved. - */ - if (up->bugs & UART_BUG_THRE) { - up->timer.function = serial8250_backup_timeout; - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + - uart_poll_timeout(port) + HZ / 5); - } - - /* - * If the "interrupt" for this port doesn't correspond with any - * hardware interrupt, we use a timer-based system. The original - * driver used to do this with IRQ0. - */ - if (!port->irq) { - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); - } else { - retval = serial_link_irq_chain(up); - if (retval) - goto out; - } + retval = up->ops->setup_irq(up); + if (retval) + goto out; /* * Now, initialize the UART @@ -2380,10 +2399,7 @@ void serial8250_do_shutdown(struct uart_port *port) serial_port_in(port, UART_RX); serial8250_rpm_put(up); - del_timer_sync(&up->timer); - up->timer.function = serial8250_timeout; - if (port->irq) - serial_unlink_irq_chain(up); + up->ops->release_irq(up); } EXPORT_SYMBOL_GPL(serial8250_do_shutdown); @@ -3083,6 +3099,11 @@ static struct uart_ops serial8250_pops = { #endif }; +static const struct uart_8250_ops univ8250_driver_ops = { + .setup_irq = univ8250_setup_irq, + .release_irq = univ8250_release_irq, +}; + static struct uart_8250_port serial8250_ports[UART_NR]; /** @@ -3137,6 +3158,8 @@ static void __init serial8250_isa_init_ports(void) up->timer.function = serial8250_timeout; up->cur_iotype = 0xFF; + up->ops = &univ8250_driver_ops; + /* * ALPHA_KLUDGE_MCR needs to be killed. */ diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index ca9f87beac63..50735a9ad598 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -60,6 +60,20 @@ enum { }; struct uart_8250_dma; +struct uart_8250_port; + +/** + * 8250 core driver operations + * + * @setup_irq() Setup irq handling. The universal 8250 driver links this + * port to the irq chain. Other drivers may @request_irq(). + * @release_irq() Undo irq handling. The universal 8250 driver unlinks + * the port from the irq chain. + */ +struct uart_8250_ops { + int (*setup_irq)(struct uart_8250_port *); + void (*release_irq)(struct uart_8250_port *); +}; /* * This should be used by drivers which want to register @@ -100,6 +114,7 @@ struct uart_8250_port { unsigned char msr_saved_flags; struct uart_8250_dma *dma; + const struct uart_8250_ops *ops; /* 8250 specific callbacks */ int (*dl_read)(struct uart_8250_port *); -- cgit v1.2.3 From 403753937020549e4bb0d8ef6e915f00a338a096 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Tue, 24 Feb 2015 14:25:14 -0500 Subject: serial: 8250: Decouple RSA probe Prepare for 8250 split; separate RSA probe and resource management from base port operations. Override base port operations for the config_port(), request_port() and release_port() methods to implement the optional RSA probe and resource management only in the universal/legacy 8250 driver. Introduce 'probe' flags for 8250 ports, which allows drivers higher up the driver stack to enable optional probes. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 3 - drivers/tty/serial/8250/8250_core.c | 112 ++++++++++++++++++++++++------------ include/linux/serial_8250.h | 2 + 3 files changed, 78 insertions(+), 39 deletions(-) (limited to 'include') diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 23dc9f9b9839..c43f74c53cd9 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -84,9 +84,6 @@ struct serial8250_config { #define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */ #define UART_BUG_PARITY (1 << 4) /* UART mishandles parity if FIFO enabled */ -#define PROBE_RSA (1 << 0) -#define PROBE_ANY (~0) - #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) #ifdef CONFIG_SERIAL_8250_SHARE_IRQ diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 257e373bfccd..a4ed84a4f8db 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1105,7 +1105,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) * whether or not this UART is a 16550A or not, since this will * determine whether or not we can use its FIFO features or not. */ -static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) +static void autoconfig(struct uart_8250_port *up) { unsigned char status1, scratch, scratch2, scratch3; unsigned char save_lcr, save_mcr; @@ -1228,7 +1228,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) /* * Only probe for RSA ports if we got the region. */ - if (port->type == PORT_16550A && probeflags & PROBE_RSA && + if (port->type == PORT_16550A && up->probe & UART_PROBE_RSA && __enable_rsa(up)) port->type = PORT_RSA; #endif @@ -2832,10 +2832,6 @@ static void serial8250_release_port(struct uart_port *port) struct uart_8250_port *up = up_to_u8250p(port); serial8250_release_std_resource(up); -#ifdef CONFIG_SERIAL_8250_RSA - if (port->type == PORT_RSA) - serial8250_release_rsa_resource(up); -#endif } static int serial8250_request_port(struct uart_port *port) @@ -2847,13 +2843,6 @@ static int serial8250_request_port(struct uart_port *port) return -ENODEV; ret = serial8250_request_std_resource(up); -#ifdef CONFIG_SERIAL_8250_RSA - if (ret == 0 && port->type == PORT_RSA) { - ret = serial8250_request_rsa_resource(up); - if (ret < 0) - serial8250_release_std_resource(up); - } -#endif return ret; } @@ -3001,7 +2990,6 @@ static void register_dev_spec_attr_grp(struct uart_8250_port *up) static void serial8250_config_port(struct uart_port *port, int flags) { struct uart_8250_port *up = up_to_u8250p(port); - int probeflags = 0; int ret; if (port->type == PORT_8250_CIR) @@ -3015,28 +3003,11 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (ret < 0) return; -#ifdef CONFIG_SERIAL_8250_RSA - if (port->type == PORT_RSA) { - if (serial8250_request_rsa_resource(up) == 0) - probeflags |= PROBE_RSA; - } else if (flags & UART_CONFIG_TYPE) { - int i; - - for (i = 0 ; i < probe_rsa_count; ++i) { - if (probe_rsa[i] == port->iobase) { - if (serial8250_request_rsa_resource(up) == 0) - probeflags |= PROBE_RSA; - break; - } - } - } -#endif - if (port->iotype != up->cur_iotype) set_io_from_upio(port); if (flags & UART_CONFIG_TYPE) - autoconfig(up, probeflags); + autoconfig(up); /* if access method is AU, it is a 16550 with a quirk */ if (port->type == PORT_16550A && port->iotype == UPIO_AU) @@ -3049,10 +3020,6 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) autoconfig_irq(up); -#ifdef CONFIG_SERIAL_8250_RSA - if (port->type != PORT_RSA && probeflags & PROBE_RSA) - serial8250_release_rsa_resource(up); -#endif if (port->type == PORT_UNKNOWN) serial8250_release_std_resource(up); @@ -3113,6 +3080,9 @@ static struct uart_ops serial8250_pops = { #endif }; +static const struct uart_ops *base_ops; +static struct uart_ops univ8250_port_ops; + static const struct uart_8250_ops univ8250_driver_ops = { .setup_irq = univ8250_setup_irq, .release_irq = univ8250_release_irq, @@ -3184,6 +3154,69 @@ static void serial8250_set_defaults(struct uart_8250_port *up) } } +#ifdef CONFIG_SERIAL_8250_RSA + +static void univ8250_config_port(struct uart_port *port, int flags) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + up->probe &= ~UART_PROBE_RSA; + if (port->type == PORT_RSA) { + if (serial8250_request_rsa_resource(up) == 0) + up->probe |= UART_PROBE_RSA; + } else if (flags & UART_CONFIG_TYPE) { + int i; + + for (i = 0; i < probe_rsa_count; i++) { + if (probe_rsa[i] == up->port.iobase) { + if (serial8250_request_rsa_resource(up) == 0) + up->probe |= UART_PROBE_RSA; + break; + } + } + } + + base_ops->config_port(port, flags); + + if (port->type != PORT_RSA && up->probe & UART_PROBE_RSA) + serial8250_release_rsa_resource(up); +} + +static int univ8250_request_port(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + int ret; + + ret = base_ops->request_port(port); + if (ret == 0 && port->type == PORT_RSA) { + ret = serial8250_request_rsa_resource(up); + if (ret < 0) + base_ops->release_port(port); + } + + return ret; +} + +static void univ8250_release_port(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + if (port->type == PORT_RSA) + serial8250_release_rsa_resource(up); + base_ops->release_port(port); +} + +static void univ8250_rsa_support(struct uart_ops *ops) +{ + ops->config_port = univ8250_config_port; + ops->request_port = univ8250_request_port; + ops->release_port = univ8250_release_port; +} + +#else +#define univ8250_rsa_support(x) do { } while (0) +#endif /* CONFIG_SERIAL_8250_RSA */ + static void __init serial8250_isa_init_ports(void) { struct uart_8250_port *up; @@ -3203,6 +3236,9 @@ static void __init serial8250_isa_init_ports(void) port->line = i; serial8250_init_port(up); + if (!base_ops) + base_ops = port->ops; + port->ops = &univ8250_port_ops; init_timer(&up->timer); up->timer.function = serial8250_timeout; @@ -3216,6 +3252,10 @@ static void __init serial8250_isa_init_ports(void) up->mcr_force = ALPHA_KLUDGE_MCR; } + /* chain base port ops to support Remote Supervisor Adapter */ + univ8250_port_ops = *base_ops; + univ8250_rsa_support(&univ8250_port_ops); + if (share_irqs) irqflag = IRQF_SHARED; diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 50735a9ad598..78097e7a330a 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -102,6 +102,8 @@ struct uart_8250_port { unsigned char canary; /* non-zero during system sleep * if no_console_suspend */ + unsigned char probe; +#define UART_PROBE_RSA (1 << 0) /* * Some bits in registers are cleared on a read, so they must -- cgit v1.2.3 From 0fea53e255eaa889fb6cf8e10d11fbea2921eac8 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 13 Mar 2015 11:09:36 -0700 Subject: tty: serial: Remove orphaned serial driver This driver is orphaned now that mach-msm has been removed. Delete it. Cc: Greg Kroah-Hartman Cc: David Brown Cc: Bryan Huntsman Cc: Daniel Walker Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 12 - drivers/tty/serial/Makefile | 1 - drivers/tty/serial/msm_serial_hs.c | 1874 --------------------------- include/linux/platform_data/msm_serial_hs.h | 49 - 4 files changed, 1936 deletions(-) delete mode 100644 drivers/tty/serial/msm_serial_hs.c delete mode 100644 include/linux/platform_data/msm_serial_hs.h (limited to 'include') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 04d7a96c7cf9..79ae58682adc 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1053,18 +1053,6 @@ config SERIAL_MSM_CONSOLE select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON -config SERIAL_MSM_HS - tristate "MSM UART High Speed: Serial Driver" - depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50 - select SERIAL_CORE - help - If you have a machine based on MSM family of SoCs, you - can enable its onboard high speed serial port by enabling - this option. - - Choose M here to compile it as a module. The module will be - called msm_serial_hs. - config SERIAL_VT8500 bool "VIA VT8500 on-chip serial port support" depends on ARCH_VT8500 diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index f42b4f9845df..c3ac3d930b33 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -62,7 +62,6 @@ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_MSM) += msm_serial.o -obj-$(CONFIG_SERIAL_MSM_HS) += msm_serial_hs.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c deleted file mode 100644 index 62da8534ba75..000000000000 --- a/drivers/tty/serial/msm_serial_hs.c +++ /dev/null @@ -1,1874 +0,0 @@ -/* - * MSM 7k/8k High speed uart driver - * - * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved. - * Copyright (c) 2008 Google Inc. - * Modified: Nick Pelly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * Has optional support for uart power management independent of linux - * suspend/resume: - * - * RX wakeup. - * UART wakeup can be triggered by RX activity (using a wakeup GPIO on the - * UART RX pin). This should only be used if there is not a wakeup - * GPIO on the UART CTS, and the first RX byte is known (for example, with the - * Bluetooth Texas Instruments HCILL protocol), since the first RX byte will - * always be lost. RTS will be asserted even while the UART is off in this mode - * of operation. See msm_serial_hs_platform_data.rx_wakeup_irq. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -/* HSUART Registers */ -#define UARTDM_MR1_ADDR 0x0 -#define UARTDM_MR2_ADDR 0x4 - -/* Data Mover result codes */ -#define RSLT_FIFO_CNTR_BMSK (0xE << 28) -#define RSLT_VLD BIT(1) - -/* write only register */ -#define UARTDM_CSR_ADDR 0x8 -#define UARTDM_CSR_115200 0xFF -#define UARTDM_CSR_57600 0xEE -#define UARTDM_CSR_38400 0xDD -#define UARTDM_CSR_28800 0xCC -#define UARTDM_CSR_19200 0xBB -#define UARTDM_CSR_14400 0xAA -#define UARTDM_CSR_9600 0x99 -#define UARTDM_CSR_7200 0x88 -#define UARTDM_CSR_4800 0x77 -#define UARTDM_CSR_3600 0x66 -#define UARTDM_CSR_2400 0x55 -#define UARTDM_CSR_1200 0x44 -#define UARTDM_CSR_600 0x33 -#define UARTDM_CSR_300 0x22 -#define UARTDM_CSR_150 0x11 -#define UARTDM_CSR_75 0x00 - -/* write only register */ -#define UARTDM_TF_ADDR 0x70 -#define UARTDM_TF2_ADDR 0x74 -#define UARTDM_TF3_ADDR 0x78 -#define UARTDM_TF4_ADDR 0x7C - -/* write only register */ -#define UARTDM_CR_ADDR 0x10 -#define UARTDM_IMR_ADDR 0x14 - -#define UARTDM_IPR_ADDR 0x18 -#define UARTDM_TFWR_ADDR 0x1c -#define UARTDM_RFWR_ADDR 0x20 -#define UARTDM_HCR_ADDR 0x24 -#define UARTDM_DMRX_ADDR 0x34 -#define UARTDM_IRDA_ADDR 0x38 -#define UARTDM_DMEN_ADDR 0x3c - -/* UART_DM_NO_CHARS_FOR_TX */ -#define UARTDM_NCF_TX_ADDR 0x40 - -#define UARTDM_BADR_ADDR 0x44 - -#define UARTDM_SIM_CFG_ADDR 0x80 -/* Read Only register */ -#define UARTDM_SR_ADDR 0x8 - -/* Read Only register */ -#define UARTDM_RF_ADDR 0x70 -#define UARTDM_RF2_ADDR 0x74 -#define UARTDM_RF3_ADDR 0x78 -#define UARTDM_RF4_ADDR 0x7C - -/* Read Only register */ -#define UARTDM_MISR_ADDR 0x10 - -/* Read Only register */ -#define UARTDM_ISR_ADDR 0x14 -#define UARTDM_RX_TOTAL_SNAP_ADDR 0x38 - -#define UARTDM_RXFS_ADDR 0x50 - -/* Register field Mask Mapping */ -#define UARTDM_SR_PAR_FRAME_BMSK BIT(5) -#define UARTDM_SR_OVERRUN_BMSK BIT(4) -#define UARTDM_SR_TXEMT_BMSK BIT(3) -#define UARTDM_SR_TXRDY_BMSK BIT(2) -#define UARTDM_SR_RXRDY_BMSK BIT(0) - -#define UARTDM_CR_TX_DISABLE_BMSK BIT(3) -#define UARTDM_CR_RX_DISABLE_BMSK BIT(1) -#define UARTDM_CR_TX_EN_BMSK BIT(2) -#define UARTDM_CR_RX_EN_BMSK BIT(0) - -/* UARTDM_CR channel_comman bit value (register field is bits 8:4) */ -#define RESET_RX 0x10 -#define RESET_TX 0x20 -#define RESET_ERROR_STATUS 0x30 -#define RESET_BREAK_INT 0x40 -#define START_BREAK 0x50 -#define STOP_BREAK 0x60 -#define RESET_CTS 0x70 -#define RESET_STALE_INT 0x80 -#define RFR_LOW 0xD0 -#define RFR_HIGH 0xE0 -#define CR_PROTECTION_EN 0x100 -#define STALE_EVENT_ENABLE 0x500 -#define STALE_EVENT_DISABLE 0x600 -#define FORCE_STALE_EVENT 0x400 -#define CLEAR_TX_READY 0x300 -#define RESET_TX_ERROR 0x800 -#define RESET_TX_DONE 0x810 - -#define UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK 0xffffff00 -#define UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK 0x3f -#define UARTDM_MR1_CTS_CTL_BMSK 0x40 -#define UARTDM_MR1_RX_RDY_CTL_BMSK 0x80 - -#define UARTDM_MR2_ERROR_MODE_BMSK 0x40 -#define UARTDM_MR2_BITS_PER_CHAR_BMSK 0x30 - -/* bits per character configuration */ -#define FIVE_BPC (0 << 4) -#define SIX_BPC (1 << 4) -#define SEVEN_BPC (2 << 4) -#define EIGHT_BPC (3 << 4) - -#define UARTDM_MR2_STOP_BIT_LEN_BMSK 0xc -#define STOP_BIT_ONE (1 << 2) -#define STOP_BIT_TWO (3 << 2) - -#define UARTDM_MR2_PARITY_MODE_BMSK 0x3 - -/* Parity configuration */ -#define NO_PARITY 0x0 -#define EVEN_PARITY 0x1 -#define ODD_PARITY 0x2 -#define SPACE_PARITY 0x3 - -#define UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK 0xffffff80 -#define UARTDM_IPR_STALE_LSB_BMSK 0x1f - -/* These can be used for both ISR and IMR register */ -#define UARTDM_ISR_TX_READY_BMSK BIT(7) -#define UARTDM_ISR_CURRENT_CTS_BMSK BIT(6) -#define UARTDM_ISR_DELTA_CTS_BMSK BIT(5) -#define UARTDM_ISR_RXLEV_BMSK BIT(4) -#define UARTDM_ISR_RXSTALE_BMSK BIT(3) -#define UARTDM_ISR_RXBREAK_BMSK BIT(2) -#define UARTDM_ISR_RXHUNT_BMSK BIT(1) -#define UARTDM_ISR_TXLEV_BMSK BIT(0) - -/* Field definitions for UART_DM_DMEN*/ -#define UARTDM_TX_DM_EN_BMSK 0x1 -#define UARTDM_RX_DM_EN_BMSK 0x2 - -#define UART_FIFOSIZE 64 -#define UARTCLK 7372800 - -/* Rx DMA request states */ -enum flush_reason { - FLUSH_NONE, - FLUSH_DATA_READY, - FLUSH_DATA_INVALID, /* values after this indicate invalid data */ - FLUSH_IGNORE = FLUSH_DATA_INVALID, - FLUSH_STOP, - FLUSH_SHUTDOWN, -}; - -/* UART clock states */ -enum msm_hs_clk_states_e { - MSM_HS_CLK_PORT_OFF, /* port not in use */ - MSM_HS_CLK_OFF, /* clock disabled */ - MSM_HS_CLK_REQUEST_OFF, /* disable after TX and RX flushed */ - MSM_HS_CLK_ON, /* clock enabled */ -}; - -/* Track the forced RXSTALE flush during clock off sequence. - * These states are only valid during MSM_HS_CLK_REQUEST_OFF */ -enum msm_hs_clk_req_off_state_e { - CLK_REQ_OFF_START, - CLK_REQ_OFF_RXSTALE_ISSUED, - CLK_REQ_OFF_FLUSH_ISSUED, - CLK_REQ_OFF_RXSTALE_FLUSHED, -}; - -/** - * struct msm_hs_tx - * @tx_ready_int_en: ok to dma more tx? - * @dma_in_flight: tx dma in progress - * @xfer: top level DMA command pointer structure - * @command_ptr: third level command struct pointer - * @command_ptr_ptr: second level command list struct pointer - * @mapped_cmd_ptr: DMA view of third level command struct - * @mapped_cmd_ptr_ptr: DMA view of second level command list struct - * @tx_count: number of bytes to transfer in DMA transfer - * @dma_base: DMA view of UART xmit buffer - * - * This structure describes a single Tx DMA transaction. MSM DMA - * commands have two levels of indirection. The top level command - * ptr points to a list of command ptr which in turn points to a - * single DMA 'command'. In our case each Tx transaction consists - * of a single second level pointer pointing to a 'box type' command. - */ -struct msm_hs_tx { - unsigned int tx_ready_int_en; - unsigned int dma_in_flight; - struct msm_dmov_cmd xfer; - dmov_box *command_ptr; - u32 *command_ptr_ptr; - dma_addr_t mapped_cmd_ptr; - dma_addr_t mapped_cmd_ptr_ptr; - int tx_count; - dma_addr_t dma_base; -}; - -/** - * struct msm_hs_rx - * @flush: Rx DMA request state - * @xfer: top level DMA command pointer structure - * @cmdptr_dmaaddr: DMA view of second level command structure - * @command_ptr: third level DMA command pointer structure - * @command_ptr_ptr: second level DMA command list pointer - * @mapped_cmd_ptr: DMA view of the third level command structure - * @wait: wait for DMA completion before shutdown - * @buffer: destination buffer for RX DMA - * @rbuffer: DMA view of buffer - * @pool: dma pool out of which coherent rx buffer is allocated - * @tty_work: private work-queue for tty flip buffer push task - * - * This structure describes a single Rx DMA transaction. Rx DMA - * transactions use box mode DMA commands. - */ -struct msm_hs_rx { - enum flush_reason flush; - struct msm_dmov_cmd xfer; - dma_addr_t cmdptr_dmaaddr; - dmov_box *command_ptr; - u32 *command_ptr_ptr; - dma_addr_t mapped_cmd_ptr; - wait_queue_head_t wait; - dma_addr_t rbuffer; - unsigned char *buffer; - struct dma_pool *pool; - struct work_struct tty_work; -}; - -/** - * struct msm_hs_rx_wakeup - * @irq: IRQ line to be configured as interrupt source on Rx activity - * @ignore: boolean value. 1 = ignore the wakeup interrupt - * @rx_to_inject: extra character to be inserted to Rx tty on wakeup - * @inject_rx: 1 = insert rx_to_inject. 0 = do not insert extra character - * - * This is an optional structure required for UART Rx GPIO IRQ based - * wakeup from low power state. UART wakeup can be triggered by RX activity - * (using a wakeup GPIO on the UART RX pin). This should only be used if - * there is not a wakeup GPIO on the UART CTS, and the first RX byte is - * known (eg., with the Bluetooth Texas Instruments HCILL protocol), - * since the first RX byte will always be lost. RTS will be asserted even - * while the UART is clocked off in this mode of operation. - */ -struct msm_hs_rx_wakeup { - int irq; /* < 0 indicates low power wakeup disabled */ - unsigned char ignore; - unsigned char inject_rx; - char rx_to_inject; -}; - -/** - * struct msm_hs_port - * @uport: embedded uart port structure - * @imr_reg: shadow value of UARTDM_IMR - * @clk: uart input clock handle - * @tx: Tx transaction related data structure - * @rx: Rx transaction related data structure - * @dma_tx_channel: Tx DMA command channel - * @dma_rx_channel Rx DMA command channel - * @dma_tx_crci: Tx channel rate control interface number - * @dma_rx_crci: Rx channel rate control interface number - * @clk_off_timer: Timer to poll DMA event completion before clock off - * @clk_off_delay: clk_off_timer poll interval - * @clk_state: overall clock state - * @clk_req_off_state: post flush clock states - * @rx_wakeup: optional rx_wakeup feature related data - * @exit_lpm_cb: optional callback to exit low power mode - * - * Low level serial port structure. - */ -struct msm_hs_port { - struct uart_port uport; - unsigned long imr_reg; - struct clk *clk; - struct msm_hs_tx tx; - struct msm_hs_rx rx; - - int dma_tx_channel; - int dma_rx_channel; - int dma_tx_crci; - int dma_rx_crci; - - struct hrtimer clk_off_timer; - ktime_t clk_off_delay; - enum msm_hs_clk_states_e clk_state; - enum msm_hs_clk_req_off_state_e clk_req_off_state; - - struct msm_hs_rx_wakeup rx_wakeup; - void (*exit_lpm_cb)(struct uart_port *); -}; - -#define MSM_UARTDM_BURST_SIZE 16 /* DM burst size (in bytes) */ -#define UARTDM_TX_BUF_SIZE UART_XMIT_SIZE -#define UARTDM_RX_BUF_SIZE 512 - -#define UARTDM_NR 2 - -static struct msm_hs_port q_uart_port[UARTDM_NR]; -static struct platform_driver msm_serial_hs_platform_driver; -static struct uart_driver msm_hs_driver; -static struct uart_ops msm_hs_ops; -static struct workqueue_struct *msm_hs_workqueue; - -#define UARTDM_TO_MSM(uart_port) \ - container_of((uart_port), struct msm_hs_port, uport) - -static unsigned int use_low_power_rx_wakeup(struct msm_hs_port - *msm_uport) -{ - return (msm_uport->rx_wakeup.irq >= 0); -} - -static unsigned int msm_hs_read(struct uart_port *uport, - unsigned int offset) -{ - return ioread32(uport->membase + offset); -} - -static void msm_hs_write(struct uart_port *uport, unsigned int offset, - unsigned int value) -{ - iowrite32(value, uport->membase + offset); -} - -static void msm_hs_release_port(struct uart_port *port) -{ - iounmap(port->membase); -} - -static int msm_hs_request_port(struct uart_port *port) -{ - port->membase = ioremap(port->mapbase, PAGE_SIZE); - if (unlikely(!port->membase)) - return -ENOMEM; - - /* configure the CR Protection to Enable */ - msm_hs_write(port, UARTDM_CR_ADDR, CR_PROTECTION_EN); - return 0; -} - -static int msm_hs_remove(struct platform_device *pdev) -{ - - struct msm_hs_port *msm_uport; - struct device *dev; - - if (pdev->id < 0 || pdev->id >= UARTDM_NR) { - printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id); - return -EINVAL; - } - - msm_uport = &q_uart_port[pdev->id]; - dev = msm_uport->uport.dev; - - dma_unmap_single(dev, msm_uport->rx.mapped_cmd_ptr, sizeof(dmov_box), - DMA_TO_DEVICE); - dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer, - msm_uport->rx.rbuffer); - dma_pool_destroy(msm_uport->rx.pool); - - dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32), - DMA_TO_DEVICE); - dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32), - DMA_TO_DEVICE); - dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr, sizeof(dmov_box), - DMA_TO_DEVICE); - - uart_remove_one_port(&msm_hs_driver, &msm_uport->uport); - clk_put(msm_uport->clk); - - /* Free the tx resources */ - kfree(msm_uport->tx.command_ptr); - kfree(msm_uport->tx.command_ptr_ptr); - - /* Free the rx resources */ - kfree(msm_uport->rx.command_ptr); - kfree(msm_uport->rx.command_ptr_ptr); - - iounmap(msm_uport->uport.membase); - - return 0; -} - -static int msm_hs_init_clk_locked(struct uart_port *uport) -{ - int ret; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - ret = clk_enable(msm_uport->clk); - if (ret) { - printk(KERN_ERR "Error could not turn on UART clk\n"); - return ret; - } - - /* Set up the MREG/NREG/DREG/MNDREG */ - ret = clk_set_rate(msm_uport->clk, uport->uartclk); - if (ret) { - printk(KERN_WARNING "Error setting clock rate on UART\n"); - clk_disable(msm_uport->clk); - return ret; - } - - msm_uport->clk_state = MSM_HS_CLK_ON; - return 0; -} - -/* Enable and Disable clocks (Used for power management) */ -static void msm_hs_pm(struct uart_port *uport, unsigned int state, - unsigned int oldstate) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - if (use_low_power_rx_wakeup(msm_uport) || - msm_uport->exit_lpm_cb) - return; /* ignore linux PM states, - use msm_hs_request_clock API */ - - switch (state) { - case 0: - clk_enable(msm_uport->clk); - break; - case 3: - clk_disable(msm_uport->clk); - break; - default: - dev_err(uport->dev, "msm_serial: Unknown PM state %d\n", - state); - } -} - -/* - * programs the UARTDM_CSR register with correct bit rates - * - * Interrupts should be disabled before we are called, as - * we modify Set Baud rate - * Set receive stale interrupt level, dependent on Bit Rate - * Goal is to have around 8 ms before indicate stale. - * roundup (((Bit Rate * .008) / 10) + 1 - */ -static void msm_hs_set_bps_locked(struct uart_port *uport, - unsigned int bps) -{ - unsigned long rxstale; - unsigned long data; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - switch (bps) { - case 300: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_75); - rxstale = 1; - break; - case 600: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_150); - rxstale = 1; - break; - case 1200: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_300); - rxstale = 1; - break; - case 2400: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_600); - rxstale = 1; - break; - case 4800: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_1200); - rxstale = 1; - break; - case 9600: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_2400); - rxstale = 2; - break; - case 14400: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_3600); - rxstale = 3; - break; - case 19200: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_4800); - rxstale = 4; - break; - case 28800: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_7200); - rxstale = 6; - break; - case 38400: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_9600); - rxstale = 8; - break; - case 57600: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_14400); - rxstale = 16; - break; - case 76800: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_19200); - rxstale = 16; - break; - case 115200: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_28800); - rxstale = 31; - break; - case 230400: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_57600); - rxstale = 31; - break; - case 460800: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_115200); - rxstale = 31; - break; - case 4000000: - case 3686400: - case 3200000: - case 3500000: - case 3000000: - case 2500000: - case 1500000: - case 1152000: - case 1000000: - case 921600: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_115200); - rxstale = 31; - break; - default: - msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_2400); - /* default to 9600 */ - bps = 9600; - rxstale = 2; - break; - } - if (bps > 460800) - uport->uartclk = bps * 16; - else - uport->uartclk = UARTCLK; - - if (clk_set_rate(msm_uport->clk, uport->uartclk)) { - printk(KERN_WARNING "Error setting clock rate on UART\n"); - return; - } - - data = rxstale & UARTDM_IPR_STALE_LSB_BMSK; - data |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2); - - msm_hs_write(uport, UARTDM_IPR_ADDR, data); -} - -/* - * termios : new ktermios - * oldtermios: old ktermios previous setting - * - * Configure the serial port - */ -static void msm_hs_set_termios(struct uart_port *uport, - struct ktermios *termios, - struct ktermios *oldtermios) -{ - unsigned int bps; - unsigned long data; - unsigned long flags; - unsigned int c_cflag = termios->c_cflag; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - spin_lock_irqsave(&uport->lock, flags); - clk_enable(msm_uport->clk); - - /* 300 is the minimum baud support by the driver */ - bps = uart_get_baud_rate(uport, termios, oldtermios, 200, 4000000); - - /* Temporary remapping 200 BAUD to 3.2 mbps */ - if (bps == 200) - bps = 3200000; - - msm_hs_set_bps_locked(uport, bps); - - data = msm_hs_read(uport, UARTDM_MR2_ADDR); - data &= ~UARTDM_MR2_PARITY_MODE_BMSK; - /* set parity */ - if (PARENB == (c_cflag & PARENB)) { - if (PARODD == (c_cflag & PARODD)) - data |= ODD_PARITY; - else if (CMSPAR == (c_cflag & CMSPAR)) - data |= SPACE_PARITY; - else - data |= EVEN_PARITY; - } - - /* Set bits per char */ - data &= ~UARTDM_MR2_BITS_PER_CHAR_BMSK; - - switch (c_cflag & CSIZE) { - case CS5: - data |= FIVE_BPC; - break; - case CS6: - data |= SIX_BPC; - break; - case CS7: - data |= SEVEN_BPC; - break; - default: - data |= EIGHT_BPC; - break; - } - /* stop bits */ - if (c_cflag & CSTOPB) { - data |= STOP_BIT_TWO; - } else { - /* otherwise 1 stop bit */ - data |= STOP_BIT_ONE; - } - data |= UARTDM_MR2_ERROR_MODE_BMSK; - /* write parity/bits per char/stop bit configuration */ - msm_hs_write(uport, UARTDM_MR2_ADDR, data); - - /* Configure HW flow control */ - data = msm_hs_read(uport, UARTDM_MR1_ADDR); - - data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK); - - if (c_cflag & CRTSCTS) { - data |= UARTDM_MR1_CTS_CTL_BMSK; - data |= UARTDM_MR1_RX_RDY_CTL_BMSK; - } - - msm_hs_write(uport, UARTDM_MR1_ADDR, data); - - uport->ignore_status_mask = termios->c_iflag & INPCK; - uport->ignore_status_mask |= termios->c_iflag & IGNPAR; - uport->read_status_mask = (termios->c_cflag & CREAD); - - msm_hs_write(uport, UARTDM_IMR_ADDR, 0); - - /* Set Transmit software time out */ - uart_update_timeout(uport, c_cflag, bps); - - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX); - - if (msm_uport->rx.flush == FLUSH_NONE) { - msm_uport->rx.flush = FLUSH_IGNORE; - msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1); - } - - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - clk_disable(msm_uport->clk); - spin_unlock_irqrestore(&uport->lock, flags); -} - -/* - * Standard API, Transmitter - * Any character in the transmit shift register is sent - */ -static unsigned int msm_hs_tx_empty(struct uart_port *uport) -{ - unsigned int data; - unsigned int ret = 0; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - data = msm_hs_read(uport, UARTDM_SR_ADDR); - if (data & UARTDM_SR_TXEMT_BMSK) - ret = TIOCSER_TEMT; - - clk_disable(msm_uport->clk); - - return ret; -} - -/* - * Standard API, Stop transmitter. - * Any character in the transmit shift register is sent as - * well as the current data mover transfer . - */ -static void msm_hs_stop_tx_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - msm_uport->tx.tx_ready_int_en = 0; -} - -/* - * Standard API, Stop receiver as soon as possible. - * - * Function immediately terminates the operation of the - * channel receiver and any incoming characters are lost. None - * of the receiver status bits are affected by this command and - * characters that are already in the receive FIFO there. - */ -static void msm_hs_stop_rx_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - unsigned int data; - - clk_enable(msm_uport->clk); - - /* disable dlink */ - data = msm_hs_read(uport, UARTDM_DMEN_ADDR); - data &= ~UARTDM_RX_DM_EN_BMSK; - msm_hs_write(uport, UARTDM_DMEN_ADDR, data); - - /* Disable the receiver */ - if (msm_uport->rx.flush == FLUSH_NONE) - msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1); - - if (msm_uport->rx.flush != FLUSH_SHUTDOWN) - msm_uport->rx.flush = FLUSH_STOP; - - clk_disable(msm_uport->clk); -} - -/* Transmit the next chunk of data */ -static void msm_hs_submit_tx_locked(struct uart_port *uport) -{ - int left; - int tx_count; - dma_addr_t src_addr; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - struct msm_hs_tx *tx = &msm_uport->tx; - struct circ_buf *tx_buf = &msm_uport->uport.state->xmit; - - if (uart_circ_empty(tx_buf) || uport->state->port.tty->stopped) { - msm_hs_stop_tx_locked(uport); - return; - } - - tx->dma_in_flight = 1; - - tx_count = uart_circ_chars_pending(tx_buf); - - if (UARTDM_TX_BUF_SIZE < tx_count) - tx_count = UARTDM_TX_BUF_SIZE; - - left = UART_XMIT_SIZE - tx_buf->tail; - - if (tx_count > left) - tx_count = left; - - src_addr = tx->dma_base + tx_buf->tail; - dma_sync_single_for_device(uport->dev, src_addr, tx_count, - DMA_TO_DEVICE); - - tx->command_ptr->num_rows = (((tx_count + 15) >> 4) << 16) | - ((tx_count + 15) >> 4); - tx->command_ptr->src_row_addr = src_addr; - - dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr, - sizeof(dmov_box), DMA_TO_DEVICE); - - *tx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(tx->mapped_cmd_ptr); - - dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr, - sizeof(u32), DMA_TO_DEVICE); - - /* Save tx_count to use in Callback */ - tx->tx_count = tx_count; - msm_hs_write(uport, UARTDM_NCF_TX_ADDR, tx_count); - - /* Disable the tx_ready interrupt */ - msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer); -} - -/* Start to receive the next chunk of data */ -static void msm_hs_start_rx_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT); - msm_hs_write(uport, UARTDM_DMRX_ADDR, UARTDM_RX_BUF_SIZE); - msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_ENABLE); - msm_uport->imr_reg |= UARTDM_ISR_RXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - msm_uport->rx.flush = FLUSH_NONE; - msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel, &msm_uport->rx.xfer); - - /* might have finished RX and be ready to clock off */ - hrtimer_start(&msm_uport->clk_off_timer, msm_uport->clk_off_delay, - HRTIMER_MODE_REL); -} - -/* Enable the transmitter Interrupt */ -static void msm_hs_start_tx_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - if (msm_uport->exit_lpm_cb) - msm_uport->exit_lpm_cb(uport); - - if (msm_uport->tx.tx_ready_int_en == 0) { - msm_uport->tx.tx_ready_int_en = 1; - msm_hs_submit_tx_locked(uport); - } - - clk_disable(msm_uport->clk); -} - -/* - * This routine is called when we are done with a DMA transfer - * - * This routine is registered with Data mover when we set - * up a Data Mover transfer. It is called from Data mover ISR - * when the DMA transfer is done. - */ -static void msm_hs_dmov_tx_callback(struct msm_dmov_cmd *cmd_ptr, - unsigned int result, - struct msm_dmov_errdata *err) -{ - unsigned long flags; - struct msm_hs_port *msm_uport; - - /* DMA did not finish properly */ - WARN_ON((((result & RSLT_FIFO_CNTR_BMSK) >> 28) == 1) && - !(result & RSLT_VLD)); - - msm_uport = container_of(cmd_ptr, struct msm_hs_port, tx.xfer); - - spin_lock_irqsave(&msm_uport->uport.lock, flags); - clk_enable(msm_uport->clk); - - msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK; - msm_hs_write(&msm_uport->uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - clk_disable(msm_uport->clk); - spin_unlock_irqrestore(&msm_uport->uport.lock, flags); -} - -/* - * This routine is called when we are done with a DMA transfer or the - * a flush has been sent to the data mover driver. - * - * This routine is registered with Data mover when we set up a Data Mover - * transfer. It is called from Data mover ISR when the DMA transfer is done. - */ -static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr, - unsigned int result, - struct msm_dmov_errdata *err) -{ - int retval; - int rx_count; - unsigned long status; - unsigned int error_f = 0; - unsigned long flags; - unsigned int flush; - struct tty_port *port; - struct uart_port *uport; - struct msm_hs_port *msm_uport; - - msm_uport = container_of(cmd_ptr, struct msm_hs_port, rx.xfer); - uport = &msm_uport->uport; - - spin_lock_irqsave(&uport->lock, flags); - clk_enable(msm_uport->clk); - - port = &uport->state->port; - - msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE); - - status = msm_hs_read(uport, UARTDM_SR_ADDR); - - /* overflow is not connect to data in a FIFO */ - if (unlikely((status & UARTDM_SR_OVERRUN_BMSK) && - (uport->read_status_mask & CREAD))) { - tty_insert_flip_char(port, 0, TTY_OVERRUN); - uport->icount.buf_overrun++; - error_f = 1; - } - - if (!(uport->ignore_status_mask & INPCK)) - status = status & ~(UARTDM_SR_PAR_FRAME_BMSK); - - if (unlikely(status & UARTDM_SR_PAR_FRAME_BMSK)) { - /* Can not tell difference between parity & frame error */ - uport->icount.parity++; - error_f = 1; - if (uport->ignore_status_mask & IGNPAR) - tty_insert_flip_char(port, 0, TTY_PARITY); - } - - if (error_f) - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS); - - if (msm_uport->clk_req_off_state == CLK_REQ_OFF_FLUSH_ISSUED) - msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_FLUSHED; - - flush = msm_uport->rx.flush; - if (flush == FLUSH_IGNORE) - msm_hs_start_rx_locked(uport); - if (flush == FLUSH_STOP) - msm_uport->rx.flush = FLUSH_SHUTDOWN; - if (flush >= FLUSH_DATA_INVALID) - goto out; - - rx_count = msm_hs_read(uport, UARTDM_RX_TOTAL_SNAP_ADDR); - - if (0 != (uport->read_status_mask & CREAD)) { - retval = tty_insert_flip_string(port, msm_uport->rx.buffer, - rx_count); - BUG_ON(retval != rx_count); - } - - msm_hs_start_rx_locked(uport); - -out: - clk_disable(msm_uport->clk); - - spin_unlock_irqrestore(&uport->lock, flags); - - if (flush < FLUSH_DATA_INVALID) - queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work); -} - -static void msm_hs_tty_flip_buffer_work(struct work_struct *work) -{ - struct msm_hs_port *msm_uport = - container_of(work, struct msm_hs_port, rx.tty_work); - - tty_flip_buffer_push(&msm_uport->uport.state->port); -} - -/* - * Standard API, Current states of modem control inputs - * - * Since CTS can be handled entirely by HARDWARE we always - * indicate clear to send and count on the TX FIFO to block when - * it fills up. - * - * - TIOCM_DCD - * - TIOCM_CTS - * - TIOCM_DSR - * - TIOCM_RI - * (Unsupported) DCD and DSR will return them high. RI will return low. - */ -static unsigned int msm_hs_get_mctrl_locked(struct uart_port *uport) -{ - return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; -} - -/* - * True enables UART auto RFR, which indicates we are ready for data if the RX - * buffer is not full. False disables auto RFR, and deasserts RFR to indicate - * we are not ready for data. Must be called with UART clock on. - */ -static void set_rfr_locked(struct uart_port *uport, int auto_rfr) -{ - unsigned int data; - - data = msm_hs_read(uport, UARTDM_MR1_ADDR); - - if (auto_rfr) { - /* enable auto ready-for-receiving */ - data |= UARTDM_MR1_RX_RDY_CTL_BMSK; - msm_hs_write(uport, UARTDM_MR1_ADDR, data); - } else { - /* disable auto ready-for-receiving */ - data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK; - msm_hs_write(uport, UARTDM_MR1_ADDR, data); - /* RFR is active low, set high */ - msm_hs_write(uport, UARTDM_CR_ADDR, RFR_HIGH); - } -} - -/* - * Standard API, used to set or clear RFR - */ -static void msm_hs_set_mctrl_locked(struct uart_port *uport, - unsigned int mctrl) -{ - unsigned int auto_rfr; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - auto_rfr = TIOCM_RTS & mctrl ? 1 : 0; - set_rfr_locked(uport, auto_rfr); - - clk_disable(msm_uport->clk); -} - -/* Standard API, Enable modem status (CTS) interrupt */ -static void msm_hs_enable_ms_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - /* Enable DELTA_CTS Interrupt */ - msm_uport->imr_reg |= UARTDM_ISR_DELTA_CTS_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - clk_disable(msm_uport->clk); - -} - -/* - * Standard API, Break Signal - * - * Control the transmission of a break signal. ctl eq 0 => break - * signal terminate ctl ne 0 => start break signal - */ -static void msm_hs_break_ctl(struct uart_port *uport, int ctl) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - msm_hs_write(uport, UARTDM_CR_ADDR, ctl ? START_BREAK : STOP_BREAK); - clk_disable(msm_uport->clk); -} - -static void msm_hs_config_port(struct uart_port *uport, int cfg_flags) -{ - unsigned long flags; - - spin_lock_irqsave(&uport->lock, flags); - if (cfg_flags & UART_CONFIG_TYPE) { - uport->type = PORT_MSM; - msm_hs_request_port(uport); - } - spin_unlock_irqrestore(&uport->lock, flags); -} - -/* Handle CTS changes (Called from interrupt handler) */ -static void msm_hs_handle_delta_cts_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - clk_enable(msm_uport->clk); - - /* clear interrupt */ - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS); - uport->icount.cts++; - - clk_disable(msm_uport->clk); - - /* clear the IOCTL TIOCMIWAIT if called */ - wake_up_interruptible(&uport->state->port.delta_msr_wait); -} - -/* check if the TX path is flushed, and if so clock off - * returns 0 did not clock off, need to retry (still sending final byte) - * -1 did not clock off, do not retry - * 1 if we clocked off - */ -static int msm_hs_check_clock_off_locked(struct uart_port *uport) -{ - unsigned long sr_status; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - struct circ_buf *tx_buf = &uport->state->xmit; - - /* Cancel if tx tty buffer is not empty, dma is in flight, - * or tx fifo is not empty, or rx fifo is not empty */ - if (msm_uport->clk_state != MSM_HS_CLK_REQUEST_OFF || - !uart_circ_empty(tx_buf) || msm_uport->tx.dma_in_flight || - (msm_uport->imr_reg & UARTDM_ISR_TXLEV_BMSK) || - !(msm_uport->imr_reg & UARTDM_ISR_RXLEV_BMSK)) { - return -1; - } - - /* Make sure the uart is finished with the last byte */ - sr_status = msm_hs_read(uport, UARTDM_SR_ADDR); - if (!(sr_status & UARTDM_SR_TXEMT_BMSK)) - return 0; /* retry */ - - /* Make sure forced RXSTALE flush complete */ - switch (msm_uport->clk_req_off_state) { - case CLK_REQ_OFF_START: - msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_ISSUED; - msm_hs_write(uport, UARTDM_CR_ADDR, FORCE_STALE_EVENT); - return 0; /* RXSTALE flush not complete - retry */ - case CLK_REQ_OFF_RXSTALE_ISSUED: - case CLK_REQ_OFF_FLUSH_ISSUED: - return 0; /* RXSTALE flush not complete - retry */ - case CLK_REQ_OFF_RXSTALE_FLUSHED: - break; /* continue */ - } - - if (msm_uport->rx.flush != FLUSH_SHUTDOWN) { - if (msm_uport->rx.flush == FLUSH_NONE) - msm_hs_stop_rx_locked(uport); - return 0; /* come back later to really clock off */ - } - - /* we really want to clock off */ - clk_disable(msm_uport->clk); - msm_uport->clk_state = MSM_HS_CLK_OFF; - - if (use_low_power_rx_wakeup(msm_uport)) { - msm_uport->rx_wakeup.ignore = 1; - enable_irq(msm_uport->rx_wakeup.irq); - } - return 1; -} - -static enum hrtimer_restart msm_hs_clk_off_retry(struct hrtimer *timer) -{ - unsigned long flags; - int ret = HRTIMER_NORESTART; - struct msm_hs_port *msm_uport = container_of(timer, struct msm_hs_port, - clk_off_timer); - struct uart_port *uport = &msm_uport->uport; - - spin_lock_irqsave(&uport->lock, flags); - - if (!msm_hs_check_clock_off_locked(uport)) { - hrtimer_forward_now(timer, msm_uport->clk_off_delay); - ret = HRTIMER_RESTART; - } - - spin_unlock_irqrestore(&uport->lock, flags); - - return ret; -} - -static irqreturn_t msm_hs_isr(int irq, void *dev) -{ - unsigned long flags; - unsigned long isr_status; - struct msm_hs_port *msm_uport = dev; - struct uart_port *uport = &msm_uport->uport; - struct circ_buf *tx_buf = &uport->state->xmit; - struct msm_hs_tx *tx = &msm_uport->tx; - struct msm_hs_rx *rx = &msm_uport->rx; - - spin_lock_irqsave(&uport->lock, flags); - - isr_status = msm_hs_read(uport, UARTDM_MISR_ADDR); - - /* Uart RX starting */ - if (isr_status & UARTDM_ISR_RXLEV_BMSK) { - msm_uport->imr_reg &= ~UARTDM_ISR_RXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - } - /* Stale rx interrupt */ - if (isr_status & UARTDM_ISR_RXSTALE_BMSK) { - msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT); - - if (msm_uport->clk_req_off_state == CLK_REQ_OFF_RXSTALE_ISSUED) - msm_uport->clk_req_off_state = - CLK_REQ_OFF_FLUSH_ISSUED; - if (rx->flush == FLUSH_NONE) { - rx->flush = FLUSH_DATA_READY; - msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1); - } - } - /* tx ready interrupt */ - if (isr_status & UARTDM_ISR_TX_READY_BMSK) { - /* Clear TX Ready */ - msm_hs_write(uport, UARTDM_CR_ADDR, CLEAR_TX_READY); - - if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) { - msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, - msm_uport->imr_reg); - } - - /* Complete DMA TX transactions and submit new transactions */ - tx_buf->tail = (tx_buf->tail + tx->tx_count) & ~UART_XMIT_SIZE; - - tx->dma_in_flight = 0; - - uport->icount.tx += tx->tx_count; - if (tx->tx_ready_int_en) - msm_hs_submit_tx_locked(uport); - - if (uart_circ_chars_pending(tx_buf) < WAKEUP_CHARS) - uart_write_wakeup(uport); - } - if (isr_status & UARTDM_ISR_TXLEV_BMSK) { - /* TX FIFO is empty */ - msm_uport->imr_reg &= ~UARTDM_ISR_TXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - if (!msm_hs_check_clock_off_locked(uport)) - hrtimer_start(&msm_uport->clk_off_timer, - msm_uport->clk_off_delay, - HRTIMER_MODE_REL); - } - - /* Change in CTS interrupt */ - if (isr_status & UARTDM_ISR_DELTA_CTS_BMSK) - msm_hs_handle_delta_cts_locked(uport); - - spin_unlock_irqrestore(&uport->lock, flags); - - return IRQ_HANDLED; -} - -void msm_hs_request_clock_off_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - if (msm_uport->clk_state == MSM_HS_CLK_ON) { - msm_uport->clk_state = MSM_HS_CLK_REQUEST_OFF; - msm_uport->clk_req_off_state = CLK_REQ_OFF_START; - if (!use_low_power_rx_wakeup(msm_uport)) - set_rfr_locked(uport, 0); - msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - } -} - -/** - * msm_hs_request_clock_off - request to (i.e. asynchronously) turn off uart - * clock once pending TX is flushed and Rx DMA command is terminated. - * @uport: uart_port structure for the device instance. - * - * This functions puts the device into a partially active low power mode. It - * waits to complete all pending tx transactions, flushes ongoing Rx DMA - * command and terminates UART side Rx transaction, puts UART HW in non DMA - * mode and then clocks off the device. A client calls this when no UART - * data is expected. msm_request_clock_on() must be called before any further - * UART can be sent or received. - */ -void msm_hs_request_clock_off(struct uart_port *uport) -{ - unsigned long flags; - - spin_lock_irqsave(&uport->lock, flags); - msm_hs_request_clock_off_locked(uport); - spin_unlock_irqrestore(&uport->lock, flags); -} - -void msm_hs_request_clock_on_locked(struct uart_port *uport) -{ - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - unsigned int data; - - switch (msm_uport->clk_state) { - case MSM_HS_CLK_OFF: - clk_enable(msm_uport->clk); - disable_irq_nosync(msm_uport->rx_wakeup.irq); - /* fall-through */ - case MSM_HS_CLK_REQUEST_OFF: - if (msm_uport->rx.flush == FLUSH_STOP || - msm_uport->rx.flush == FLUSH_SHUTDOWN) { - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX); - data = msm_hs_read(uport, UARTDM_DMEN_ADDR); - data |= UARTDM_RX_DM_EN_BMSK; - msm_hs_write(uport, UARTDM_DMEN_ADDR, data); - } - hrtimer_try_to_cancel(&msm_uport->clk_off_timer); - if (msm_uport->rx.flush == FLUSH_SHUTDOWN) - msm_hs_start_rx_locked(uport); - if (!use_low_power_rx_wakeup(msm_uport)) - set_rfr_locked(uport, 1); - if (msm_uport->rx.flush == FLUSH_STOP) - msm_uport->rx.flush = FLUSH_IGNORE; - msm_uport->clk_state = MSM_HS_CLK_ON; - break; - case MSM_HS_CLK_ON: - break; - case MSM_HS_CLK_PORT_OFF: - break; - } -} - -/** - * msm_hs_request_clock_on - Switch the device from partially active low - * power mode to fully active (i.e. clock on) mode. - * @uport: uart_port structure for the device. - * - * This function switches on the input clock, puts UART HW into DMA mode - * and enqueues an Rx DMA command if the device was in partially active - * mode. It has no effect if called with the device in inactive state. - */ -void msm_hs_request_clock_on(struct uart_port *uport) -{ - unsigned long flags; - - spin_lock_irqsave(&uport->lock, flags); - msm_hs_request_clock_on_locked(uport); - spin_unlock_irqrestore(&uport->lock, flags); -} - -static irqreturn_t msm_hs_rx_wakeup_isr(int irq, void *dev) -{ - unsigned int wakeup = 0; - unsigned long flags; - struct msm_hs_port *msm_uport = dev; - struct uart_port *uport = &msm_uport->uport; - - spin_lock_irqsave(&uport->lock, flags); - if (msm_uport->clk_state == MSM_HS_CLK_OFF) { - /* ignore the first irq - it is a pending irq that occurred - * before enable_irq() */ - if (msm_uport->rx_wakeup.ignore) - msm_uport->rx_wakeup.ignore = 0; - else - wakeup = 1; - } - - if (wakeup) { - /* the uart was clocked off during an rx, wake up and - * optionally inject char into tty rx */ - msm_hs_request_clock_on_locked(uport); - if (msm_uport->rx_wakeup.inject_rx) { - tty_insert_flip_char(&uport->state->port, - msm_uport->rx_wakeup.rx_to_inject, - TTY_NORMAL); - queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work); - } - } - - spin_unlock_irqrestore(&uport->lock, flags); - - return IRQ_HANDLED; -} - -static const char *msm_hs_type(struct uart_port *port) -{ - return (port->type == PORT_MSM) ? "MSM_HS_UART" : NULL; -} - -/* Called when port is opened */ -static int msm_hs_startup(struct uart_port *uport) -{ - int ret; - int rfr_level; - unsigned long flags; - unsigned int data; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - struct circ_buf *tx_buf = &uport->state->xmit; - struct msm_hs_tx *tx = &msm_uport->tx; - struct msm_hs_rx *rx = &msm_uport->rx; - - rfr_level = uport->fifosize; - if (rfr_level > 16) - rfr_level -= 16; - - tx->dma_base = dma_map_single(uport->dev, tx_buf->buf, UART_XMIT_SIZE, - DMA_TO_DEVICE); - - /* do not let tty layer execute RX in global workqueue, use a - * dedicated workqueue managed by this driver */ - uport->state->port.low_latency = 1; - - /* turn on uart clk */ - ret = msm_hs_init_clk_locked(uport); - if (unlikely(ret)) { - printk(KERN_ERR "Turning uartclk failed!\n"); - goto err_msm_hs_init_clk; - } - - /* Set auto RFR Level */ - data = msm_hs_read(uport, UARTDM_MR1_ADDR); - data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK; - data &= ~UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK; - data |= (UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK & (rfr_level << 2)); - data |= (UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK & rfr_level); - msm_hs_write(uport, UARTDM_MR1_ADDR, data); - - /* Make sure RXSTALE count is non-zero */ - data = msm_hs_read(uport, UARTDM_IPR_ADDR); - if (!data) { - data |= 0x1f & UARTDM_IPR_STALE_LSB_BMSK; - msm_hs_write(uport, UARTDM_IPR_ADDR, data); - } - - /* Enable Data Mover Mode */ - data = UARTDM_TX_DM_EN_BMSK | UARTDM_RX_DM_EN_BMSK; - msm_hs_write(uport, UARTDM_DMEN_ADDR, data); - - /* Reset TX */ - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_BREAK_INT); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT); - msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS); - msm_hs_write(uport, UARTDM_CR_ADDR, RFR_LOW); - /* Turn on Uart Receiver */ - msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_EN_BMSK); - - /* Turn on Uart Transmitter */ - msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_EN_BMSK); - - /* Initialize the tx */ - tx->tx_ready_int_en = 0; - tx->dma_in_flight = 0; - - tx->xfer.complete_func = msm_hs_dmov_tx_callback; - tx->xfer.execute_func = NULL; - - tx->command_ptr->cmd = CMD_LC | - CMD_DST_CRCI(msm_uport->dma_tx_crci) | CMD_MODE_BOX; - - tx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16) - | (MSM_UARTDM_BURST_SIZE); - - tx->command_ptr->row_offset = (MSM_UARTDM_BURST_SIZE << 16); - - tx->command_ptr->dst_row_addr = - msm_uport->uport.mapbase + UARTDM_TF_ADDR; - - - /* Turn on Uart Receive */ - rx->xfer.complete_func = msm_hs_dmov_rx_callback; - rx->xfer.execute_func = NULL; - - rx->command_ptr->cmd = CMD_LC | - CMD_SRC_CRCI(msm_uport->dma_rx_crci) | CMD_MODE_BOX; - - rx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16) - | (MSM_UARTDM_BURST_SIZE); - rx->command_ptr->row_offset = MSM_UARTDM_BURST_SIZE; - rx->command_ptr->src_row_addr = uport->mapbase + UARTDM_RF_ADDR; - - - msm_uport->imr_reg |= UARTDM_ISR_RXSTALE_BMSK; - /* Enable reading the current CTS, no harm even if CTS is ignored */ - msm_uport->imr_reg |= UARTDM_ISR_CURRENT_CTS_BMSK; - - msm_hs_write(uport, UARTDM_TFWR_ADDR, 0); /* TXLEV on empty TX fifo */ - - - ret = request_irq(uport->irq, msm_hs_isr, IRQF_TRIGGER_HIGH, - "msm_hs_uart", msm_uport); - if (unlikely(ret)) { - printk(KERN_ERR "Request msm_hs_uart IRQ failed!\n"); - goto err_request_irq; - } - if (use_low_power_rx_wakeup(msm_uport)) { - ret = request_irq(msm_uport->rx_wakeup.irq, - msm_hs_rx_wakeup_isr, - IRQF_TRIGGER_FALLING, - "msm_hs_rx_wakeup", msm_uport); - if (unlikely(ret)) { - printk(KERN_ERR "Request msm_hs_rx_wakeup IRQ failed!\n"); - free_irq(uport->irq, msm_uport); - goto err_request_irq; - } - disable_irq(msm_uport->rx_wakeup.irq); - } - - spin_lock_irqsave(&uport->lock, flags); - - msm_hs_write(uport, UARTDM_RFWR_ADDR, 0); - msm_hs_start_rx_locked(uport); - - spin_unlock_irqrestore(&uport->lock, flags); - ret = pm_runtime_set_active(uport->dev); - if (ret) - dev_err(uport->dev, "set active error:%d\n", ret); - pm_runtime_enable(uport->dev); - - return 0; - -err_request_irq: -err_msm_hs_init_clk: - dma_unmap_single(uport->dev, tx->dma_base, - UART_XMIT_SIZE, DMA_TO_DEVICE); - return ret; -} - -/* Initialize tx and rx data structures */ -static int uartdm_init_port(struct uart_port *uport) -{ - int ret = 0; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - struct msm_hs_tx *tx = &msm_uport->tx; - struct msm_hs_rx *rx = &msm_uport->rx; - - /* Allocate the command pointer. Needs to be 64 bit aligned */ - tx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA); - if (!tx->command_ptr) - return -ENOMEM; - - tx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA); - if (!tx->command_ptr_ptr) { - ret = -ENOMEM; - goto err_tx_command_ptr_ptr; - } - - tx->mapped_cmd_ptr = dma_map_single(uport->dev, tx->command_ptr, - sizeof(dmov_box), DMA_TO_DEVICE); - tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev, - tx->command_ptr_ptr, - sizeof(u32), DMA_TO_DEVICE); - tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr); - - init_waitqueue_head(&rx->wait); - - rx->pool = dma_pool_create("rx_buffer_pool", uport->dev, - UARTDM_RX_BUF_SIZE, 16, 0); - if (!rx->pool) { - pr_err("%s(): cannot allocate rx_buffer_pool", __func__); - ret = -ENOMEM; - goto err_dma_pool_create; - } - - rx->buffer = dma_pool_alloc(rx->pool, GFP_KERNEL, &rx->rbuffer); - if (!rx->buffer) { - pr_err("%s(): cannot allocate rx->buffer", __func__); - ret = -ENOMEM; - goto err_dma_pool_alloc; - } - - /* Allocate the command pointer. Needs to be 64 bit aligned */ - rx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA); - if (!rx->command_ptr) { - pr_err("%s(): cannot allocate rx->command_ptr", __func__); - ret = -ENOMEM; - goto err_rx_command_ptr; - } - - rx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA); - if (!rx->command_ptr_ptr) { - pr_err("%s(): cannot allocate rx->command_ptr_ptr", __func__); - ret = -ENOMEM; - goto err_rx_command_ptr_ptr; - } - - rx->command_ptr->num_rows = ((UARTDM_RX_BUF_SIZE >> 4) << 16) | - (UARTDM_RX_BUF_SIZE >> 4); - - rx->command_ptr->dst_row_addr = rx->rbuffer; - - rx->mapped_cmd_ptr = dma_map_single(uport->dev, rx->command_ptr, - sizeof(dmov_box), DMA_TO_DEVICE); - - *rx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(rx->mapped_cmd_ptr); - - rx->cmdptr_dmaaddr = dma_map_single(uport->dev, rx->command_ptr_ptr, - sizeof(u32), DMA_TO_DEVICE); - rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr); - - INIT_WORK(&rx->tty_work, msm_hs_tty_flip_buffer_work); - - return ret; - -err_rx_command_ptr_ptr: - kfree(rx->command_ptr); -err_rx_command_ptr: - dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer, - msm_uport->rx.rbuffer); -err_dma_pool_alloc: - dma_pool_destroy(msm_uport->rx.pool); -err_dma_pool_create: - dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr, - sizeof(u32), DMA_TO_DEVICE); - dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr, - sizeof(dmov_box), DMA_TO_DEVICE); - kfree(msm_uport->tx.command_ptr_ptr); -err_tx_command_ptr_ptr: - kfree(msm_uport->tx.command_ptr); - return ret; -} - -static int msm_hs_probe(struct platform_device *pdev) -{ - int ret; - struct uart_port *uport; - struct msm_hs_port *msm_uport; - struct resource *resource; - const struct msm_serial_hs_platform_data *pdata = - dev_get_platdata(&pdev->dev); - - if (pdev->id < 0 || pdev->id >= UARTDM_NR) { - printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id); - return -EINVAL; - } - - msm_uport = &q_uart_port[pdev->id]; - uport = &msm_uport->uport; - - uport->dev = &pdev->dev; - - resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!resource)) - return -ENXIO; - - uport->mapbase = resource->start; - uport->irq = platform_get_irq(pdev, 0); - if (unlikely(uport->irq < 0)) - return -ENXIO; - - if (unlikely(irq_set_irq_wake(uport->irq, 1))) - return -ENXIO; - - if (pdata == NULL || pdata->rx_wakeup_irq < 0) - msm_uport->rx_wakeup.irq = -1; - else { - msm_uport->rx_wakeup.irq = pdata->rx_wakeup_irq; - msm_uport->rx_wakeup.ignore = 1; - msm_uport->rx_wakeup.inject_rx = pdata->inject_rx_on_wakeup; - msm_uport->rx_wakeup.rx_to_inject = pdata->rx_to_inject; - - if (unlikely(msm_uport->rx_wakeup.irq < 0)) - return -ENXIO; - - if (unlikely(irq_set_irq_wake(msm_uport->rx_wakeup.irq, 1))) - return -ENXIO; - } - - if (pdata == NULL) - msm_uport->exit_lpm_cb = NULL; - else - msm_uport->exit_lpm_cb = pdata->exit_lpm_cb; - - resource = platform_get_resource_byname(pdev, IORESOURCE_DMA, - "uartdm_channels"); - if (unlikely(!resource)) - return -ENXIO; - - msm_uport->dma_tx_channel = resource->start; - msm_uport->dma_rx_channel = resource->end; - - resource = platform_get_resource_byname(pdev, IORESOURCE_DMA, - "uartdm_crci"); - if (unlikely(!resource)) - return -ENXIO; - - msm_uport->dma_tx_crci = resource->start; - msm_uport->dma_rx_crci = resource->end; - - uport->iotype = UPIO_MEM; - uport->fifosize = UART_FIFOSIZE; - uport->ops = &msm_hs_ops; - uport->flags = UPF_BOOT_AUTOCONF; - uport->uartclk = UARTCLK; - msm_uport->imr_reg = 0x0; - msm_uport->clk = clk_get(&pdev->dev, "uartdm_clk"); - if (IS_ERR(msm_uport->clk)) - return PTR_ERR(msm_uport->clk); - - ret = uartdm_init_port(uport); - if (unlikely(ret)) - return ret; - - msm_uport->clk_state = MSM_HS_CLK_PORT_OFF; - hrtimer_init(&msm_uport->clk_off_timer, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - msm_uport->clk_off_timer.function = msm_hs_clk_off_retry; - msm_uport->clk_off_delay = ktime_set(0, 1000000); /* 1ms */ - - uport->line = pdev->id; - return uart_add_one_port(&msm_hs_driver, uport); -} - -static int __init msm_serial_hs_init(void) -{ - int ret, i; - - /* Init all UARTS as non-configured */ - for (i = 0; i < UARTDM_NR; i++) - q_uart_port[i].uport.type = PORT_UNKNOWN; - - msm_hs_workqueue = create_singlethread_workqueue("msm_serial_hs"); - if (unlikely(!msm_hs_workqueue)) - return -ENOMEM; - - ret = uart_register_driver(&msm_hs_driver); - if (unlikely(ret)) { - printk(KERN_ERR "%s failed to load\n", __func__); - goto err_uart_register_driver; - } - - ret = platform_driver_register(&msm_serial_hs_platform_driver); - if (ret) { - printk(KERN_ERR "%s failed to load\n", __func__); - goto err_platform_driver_register; - } - - return ret; - -err_platform_driver_register: - uart_unregister_driver(&msm_hs_driver); -err_uart_register_driver: - destroy_workqueue(msm_hs_workqueue); - return ret; -} -module_init(msm_serial_hs_init); - -/* - * Called by the upper layer when port is closed. - * - Disables the port - * - Unhook the ISR - */ -static void msm_hs_shutdown(struct uart_port *uport) -{ - unsigned long flags; - struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); - - BUG_ON(msm_uport->rx.flush < FLUSH_STOP); - - spin_lock_irqsave(&uport->lock, flags); - clk_enable(msm_uport->clk); - - /* Disable the transmitter */ - msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK); - /* Disable the receiver */ - msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_DISABLE_BMSK); - - pm_runtime_disable(uport->dev); - pm_runtime_set_suspended(uport->dev); - - /* Free the interrupt */ - free_irq(uport->irq, msm_uport); - if (use_low_power_rx_wakeup(msm_uport)) - free_irq(msm_uport->rx_wakeup.irq, msm_uport); - - msm_uport->imr_reg = 0; - msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); - - wait_event(msm_uport->rx.wait, msm_uport->rx.flush == FLUSH_SHUTDOWN); - - clk_disable(msm_uport->clk); /* to balance local clk_enable() */ - if (msm_uport->clk_state != MSM_HS_CLK_OFF) - clk_disable(msm_uport->clk); /* to balance clk_state */ - msm_uport->clk_state = MSM_HS_CLK_PORT_OFF; - - dma_unmap_single(uport->dev, msm_uport->tx.dma_base, - UART_XMIT_SIZE, DMA_TO_DEVICE); - - spin_unlock_irqrestore(&uport->lock, flags); - - if (cancel_work_sync(&msm_uport->rx.tty_work)) - msm_hs_tty_flip_buffer_work(&msm_uport->rx.tty_work); -} - -static void __exit msm_serial_hs_exit(void) -{ - flush_workqueue(msm_hs_workqueue); - destroy_workqueue(msm_hs_workqueue); - platform_driver_unregister(&msm_serial_hs_platform_driver); - uart_unregister_driver(&msm_hs_driver); -} -module_exit(msm_serial_hs_exit); - -#ifdef CONFIG_PM -static int msm_hs_runtime_idle(struct device *dev) -{ - /* - * returning success from idle results in runtime suspend to be - * called - */ - return 0; -} - -static int msm_hs_runtime_resume(struct device *dev) -{ - struct platform_device *pdev = container_of(dev, struct - platform_device, dev); - struct msm_hs_port *msm_uport = &q_uart_port[pdev->id]; - - msm_hs_request_clock_on(&msm_uport->uport); - return 0; -} - -static int msm_hs_runtime_suspend(struct device *dev) -{ - struct platform_device *pdev = container_of(dev, struct - platform_device, dev); - struct msm_hs_port *msm_uport = &q_uart_port[pdev->id]; - - msm_hs_request_clock_off(&msm_uport->uport); - return 0; -} -#else -#define msm_hs_runtime_idle NULL -#define msm_hs_runtime_resume NULL -#define msm_hs_runtime_suspend NULL -#endif - -static const struct dev_pm_ops msm_hs_dev_pm_ops = { - .runtime_suspend = msm_hs_runtime_suspend, - .runtime_resume = msm_hs_runtime_resume, - .runtime_idle = msm_hs_runtime_idle, -}; - -static struct platform_driver msm_serial_hs_platform_driver = { - .probe = msm_hs_probe, - .remove = msm_hs_remove, - .driver = { - .name = "msm_serial_hs", - .pm = &msm_hs_dev_pm_ops, - }, -}; - -static struct uart_driver msm_hs_driver = { - .owner = THIS_MODULE, - .driver_name = "msm_serial_hs", - .dev_name = "ttyHS", - .nr = UARTDM_NR, - .cons = 0, -}; - -static struct uart_ops msm_hs_ops = { - .tx_empty = msm_hs_tx_empty, - .set_mctrl = msm_hs_set_mctrl_locked, - .get_mctrl = msm_hs_get_mctrl_locked, - .stop_tx = msm_hs_stop_tx_locked, - .start_tx = msm_hs_start_tx_locked, - .stop_rx = msm_hs_stop_rx_locked, - .enable_ms = msm_hs_enable_ms_locked, - .break_ctl = msm_hs_break_ctl, - .startup = msm_hs_startup, - .shutdown = msm_hs_shutdown, - .set_termios = msm_hs_set_termios, - .pm = msm_hs_pm, - .type = msm_hs_type, - .config_port = msm_hs_config_port, - .release_port = msm_hs_release_port, - .request_port = msm_hs_request_port, -}; - -MODULE_DESCRIPTION("High Speed UART Driver for the MSM chipset"); -MODULE_VERSION("1.2"); -MODULE_LICENSE("GPL v2"); diff --git a/include/linux/platform_data/msm_serial_hs.h b/include/linux/platform_data/msm_serial_hs.h deleted file mode 100644 index 98a2046f8b31..000000000000 --- a/include/linux/platform_data/msm_serial_hs.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2008 Google, Inc. - * Author: Nick Pelly - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __ASM_ARCH_MSM_SERIAL_HS_H -#define __ASM_ARCH_MSM_SERIAL_HS_H - -#include - -/* API to request the uart clock off or on for low power management - * Clients should call request_clock_off() when no uart data is expected, - * and must call request_clock_on() before any further uart data can be - * received. */ -extern void msm_hs_request_clock_off(struct uart_port *uport); -extern void msm_hs_request_clock_on(struct uart_port *uport); - -/** - * struct msm_serial_hs_platform_data - * @rx_wakeup_irq: Rx activity irq - * @rx_to_inject: extra character to be inserted to Rx tty on wakeup - * @inject_rx: 1 = insert rx_to_inject. 0 = do not insert extra character - * @exit_lpm_cb: function called before every Tx transaction - * - * This is an optional structure required for UART Rx GPIO IRQ based - * wakeup from low power state. UART wakeup can be triggered by RX activity - * (using a wakeup GPIO on the UART RX pin). This should only be used if - * there is not a wakeup GPIO on the UART CTS, and the first RX byte is - * known (eg., with the Bluetooth Texas Instruments HCILL protocol), - * since the first RX byte will always be lost. RTS will be asserted even - * while the UART is clocked off in this mode of operation. - */ -struct msm_serial_hs_platform_data { - int rx_wakeup_irq; - unsigned char inject_rx_on_wakeup; - char rx_to_inject; - void (*exit_lpm_cb)(struct uart_port *); -}; - -#endif -- cgit v1.2.3 From 88dcd2dab5c23b1c9cfc396246d8f476c872f0ca Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 26 Feb 2015 22:19:15 -0800 Subject: iscsi-target: Convert iscsi_thread_set usage to kthread.h This patch converts iscsi-target code to use modern kthread.h API callers for creating RX/TX threads for each new iscsi_conn descriptor, and releasing associated RX/TX threads during connection shutdown. This is done using iscsit_start_kthreads() -> kthread_run() to start new kthreads from within iscsi_post_login_handler(), and invoking kthread_stop() from existing iscsit_close_connection() code. Also, convert iscsit_logout_post_handler_closesession() code to use cmpxchg when determing when iscsit_cause_connection_reinstatement() needs to sleep waiting for completion. Reported-by: Sagi Grimberg Tested-by: Sagi Grimberg Cc: Slava Shwartsman Cc: # v3.10+ Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target.c | 104 +++++++++++++----------------- drivers/target/iscsi/iscsi_target_erl0.c | 13 ++-- drivers/target/iscsi/iscsi_target_login.c | 59 +++++++++++++++-- include/target/iscsi/iscsi_target_core.h | 7 ++ 4 files changed, 114 insertions(+), 69 deletions(-) (limited to 'include') diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 47af86167b49..163773fb4f84 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -537,7 +537,7 @@ static struct iscsit_transport iscsi_target_transport = { static int __init iscsi_target_init_module(void) { - int ret = 0; + int ret = 0, size; pr_debug("iSCSI-Target "ISCSIT_VERSION"\n"); @@ -546,6 +546,7 @@ static int __init iscsi_target_init_module(void) pr_err("Unable to allocate memory for iscsit_global\n"); return -1; } + spin_lock_init(&iscsit_global->ts_bitmap_lock); mutex_init(&auth_id_lock); spin_lock_init(&sess_idr_lock); idr_init(&tiqn_idr); @@ -555,15 +556,11 @@ static int __init iscsi_target_init_module(void) if (ret < 0) goto out; - ret = iscsi_thread_set_init(); - if (ret < 0) + size = BITS_TO_LONGS(ISCSIT_BITMAP_BITS) * sizeof(long); + iscsit_global->ts_bitmap = vzalloc(size); + if (!iscsit_global->ts_bitmap) { + pr_err("Unable to allocate iscsit_global->ts_bitmap\n"); goto configfs_out; - - if (iscsi_allocate_thread_sets(TARGET_THREAD_SET_COUNT) != - TARGET_THREAD_SET_COUNT) { - pr_err("iscsi_allocate_thread_sets() returned" - " unexpected value!\n"); - goto ts_out1; } lio_qr_cache = kmem_cache_create("lio_qr_cache", @@ -572,7 +569,7 @@ static int __init iscsi_target_init_module(void) if (!lio_qr_cache) { pr_err("nable to kmem_cache_create() for" " lio_qr_cache\n"); - goto ts_out2; + goto bitmap_out; } lio_dr_cache = kmem_cache_create("lio_dr_cache", @@ -617,10 +614,8 @@ dr_out: kmem_cache_destroy(lio_dr_cache); qr_out: kmem_cache_destroy(lio_qr_cache); -ts_out2: - iscsi_deallocate_thread_sets(); -ts_out1: - iscsi_thread_set_free(); +bitmap_out: + vfree(iscsit_global->ts_bitmap); configfs_out: iscsi_target_deregister_configfs(); out: @@ -630,8 +625,6 @@ out: static void __exit iscsi_target_cleanup_module(void) { - iscsi_deallocate_thread_sets(); - iscsi_thread_set_free(); iscsit_release_discovery_tpg(); iscsit_unregister_transport(&iscsi_target_transport); kmem_cache_destroy(lio_qr_cache); @@ -641,6 +634,7 @@ static void __exit iscsi_target_cleanup_module(void) iscsi_target_deregister_configfs(); + vfree(iscsit_global->ts_bitmap); kfree(iscsit_global); } @@ -3709,17 +3703,16 @@ static int iscsit_send_reject( void iscsit_thread_get_cpumask(struct iscsi_conn *conn) { - struct iscsi_thread_set *ts = conn->thread_set; int ord, cpu; /* - * thread_id is assigned from iscsit_global->ts_bitmap from - * within iscsi_thread_set.c:iscsi_allocate_thread_sets() + * bitmap_id is assigned from iscsit_global->ts_bitmap from + * within iscsit_start_kthreads() * - * Here we use thread_id to determine which CPU that this - * iSCSI connection's iscsi_thread_set will be scheduled to + * Here we use bitmap_id to determine which CPU that this + * iSCSI connection's RX/TX threads will be scheduled to * execute upon. */ - ord = ts->thread_id % cpumask_weight(cpu_online_mask); + ord = conn->bitmap_id % cpumask_weight(cpu_online_mask); for_each_online_cpu(cpu) { if (ord-- == 0) { cpumask_set_cpu(cpu, conn->conn_cpumask); @@ -3908,7 +3901,7 @@ check_rsp_state: switch (state) { case ISTATE_SEND_LOGOUTRSP: if (!iscsit_logout_post_handler(cmd, conn)) - goto restart; + return -ECONNRESET; /* fall through */ case ISTATE_SEND_STATUS: case ISTATE_SEND_ASYNCMSG: @@ -3936,8 +3929,6 @@ check_rsp_state: err: return -1; -restart: - return -EAGAIN; } static int iscsit_handle_response_queue(struct iscsi_conn *conn) @@ -3964,21 +3955,13 @@ static int iscsit_handle_response_queue(struct iscsi_conn *conn) int iscsi_target_tx_thread(void *arg) { int ret = 0; - struct iscsi_conn *conn; - struct iscsi_thread_set *ts = arg; + struct iscsi_conn *conn = arg; /* * Allow ourselves to be interrupted by SIGINT so that a * connection recovery / failure event can be triggered externally. */ allow_signal(SIGINT); -restart: - conn = iscsi_tx_thread_pre_handler(ts); - if (!conn) - goto out; - - ret = 0; - while (!kthread_should_stop()) { /* * Ensure that both TX and RX per connection kthreads @@ -3987,11 +3970,9 @@ restart: iscsit_thread_check_cpumask(conn, current, 1); wait_event_interruptible(conn->queues_wq, - !iscsit_conn_all_queues_empty(conn) || - ts->status == ISCSI_THREAD_SET_RESET); + !iscsit_conn_all_queues_empty(conn)); - if ((ts->status == ISCSI_THREAD_SET_RESET) || - signal_pending(current)) + if (signal_pending(current)) goto transport_err; get_immediate: @@ -4002,15 +3983,14 @@ get_immediate: ret = iscsit_handle_response_queue(conn); if (ret == 1) goto get_immediate; - else if (ret == -EAGAIN) - goto restart; + else if (ret == -ECONNRESET) + goto out; else if (ret < 0) goto transport_err; } transport_err: iscsit_take_action_for_connection_exit(conn); - goto restart; out: return 0; } @@ -4105,8 +4085,7 @@ int iscsi_target_rx_thread(void *arg) int ret; u8 buffer[ISCSI_HDR_LEN], opcode; u32 checksum = 0, digest = 0; - struct iscsi_conn *conn = NULL; - struct iscsi_thread_set *ts = arg; + struct iscsi_conn *conn = arg; struct kvec iov; /* * Allow ourselves to be interrupted by SIGINT so that a @@ -4114,11 +4093,6 @@ int iscsi_target_rx_thread(void *arg) */ allow_signal(SIGINT); -restart: - conn = iscsi_rx_thread_pre_handler(ts); - if (!conn) - goto out; - if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) { struct completion comp; int rc; @@ -4128,7 +4102,7 @@ restart: if (rc < 0) goto transport_err; - goto out; + goto transport_err; } while (!kthread_should_stop()) { @@ -4204,8 +4178,6 @@ transport_err: if (!signal_pending(current)) atomic_set(&conn->transport_failed, 1); iscsit_take_action_for_connection_exit(conn); - goto restart; -out: return 0; } @@ -4261,7 +4233,24 @@ int iscsit_close_connection( */ complete(&conn->conn_logout_comp); - iscsi_release_thread_set(conn); + if (!strcmp(current->comm, ISCSI_RX_THREAD_NAME)) { + if (conn->tx_thread && + cmpxchg(&conn->tx_thread_active, true, false)) { + send_sig(SIGINT, conn->tx_thread, 1); + kthread_stop(conn->tx_thread); + } + } else if (!strcmp(current->comm, ISCSI_TX_THREAD_NAME)) { + if (conn->rx_thread && + cmpxchg(&conn->rx_thread_active, true, false)) { + send_sig(SIGINT, conn->rx_thread, 1); + kthread_stop(conn->rx_thread); + } + } + + spin_lock(&iscsit_global->ts_bitmap_lock); + bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, + get_order(1)); + spin_unlock(&iscsit_global->ts_bitmap_lock); iscsit_stop_timers_for_cmds(conn); iscsit_stop_nopin_response_timer(conn); @@ -4539,15 +4528,13 @@ static void iscsit_logout_post_handler_closesession( struct iscsi_conn *conn) { struct iscsi_session *sess = conn->sess; - - iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD); - iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD); + int sleep = cmpxchg(&conn->tx_thread_active, true, false); atomic_set(&conn->conn_logout_remove, 0); complete(&conn->conn_logout_comp); iscsit_dec_conn_usage_count(conn); - iscsit_stop_session(sess, 1, 1); + iscsit_stop_session(sess, sleep, sleep); iscsit_dec_session_usage_count(sess); target_put_session(sess->se_sess); } @@ -4555,13 +4542,12 @@ static void iscsit_logout_post_handler_closesession( static void iscsit_logout_post_handler_samecid( struct iscsi_conn *conn) { - iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD); - iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD); + int sleep = cmpxchg(&conn->tx_thread_active, true, false); atomic_set(&conn->conn_logout_remove, 0); complete(&conn->conn_logout_comp); - iscsit_cause_connection_reinstatement(conn, 1); + iscsit_cause_connection_reinstatement(conn, sleep); iscsit_dec_conn_usage_count(conn); } diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index 1c197bad6132..d4e2159f53c2 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -861,7 +861,10 @@ void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *conn) } spin_unlock_bh(&conn->state_lock); - iscsi_thread_set_force_reinstatement(conn); + if (conn->tx_thread && conn->tx_thread_active) + send_sig(SIGINT, conn->tx_thread, 1); + if (conn->rx_thread && conn->rx_thread_active) + send_sig(SIGINT, conn->rx_thread, 1); sleep: wait_for_completion(&conn->conn_wait_rcfr_comp); @@ -886,10 +889,10 @@ void iscsit_cause_connection_reinstatement(struct iscsi_conn *conn, int sleep) return; } - if (iscsi_thread_set_force_reinstatement(conn) < 0) { - spin_unlock_bh(&conn->state_lock); - return; - } + if (conn->tx_thread && conn->tx_thread_active) + send_sig(SIGINT, conn->tx_thread, 1); + if (conn->rx_thread && conn->rx_thread_active) + send_sig(SIGINT, conn->rx_thread, 1); atomic_set(&conn->connection_reinstatement, 1); if (!sleep) { diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 153fb66ac1b8..345f073ff6dc 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -699,6 +699,51 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn) iscsit_start_nopin_timer(conn); } +int iscsit_start_kthreads(struct iscsi_conn *conn) +{ + int ret = 0; + + spin_lock(&iscsit_global->ts_bitmap_lock); + conn->bitmap_id = bitmap_find_free_region(iscsit_global->ts_bitmap, + ISCSIT_BITMAP_BITS, get_order(1)); + spin_unlock(&iscsit_global->ts_bitmap_lock); + + if (conn->bitmap_id < 0) { + pr_err("bitmap_find_free_region() failed for" + " iscsit_start_kthreads()\n"); + return -ENOMEM; + } + + conn->tx_thread = kthread_run(iscsi_target_tx_thread, conn, + "%s", ISCSI_TX_THREAD_NAME); + if (IS_ERR(conn->tx_thread)) { + pr_err("Unable to start iscsi_target_tx_thread\n"); + ret = PTR_ERR(conn->tx_thread); + goto out_bitmap; + } + conn->tx_thread_active = true; + + conn->rx_thread = kthread_run(iscsi_target_rx_thread, conn, + "%s", ISCSI_RX_THREAD_NAME); + if (IS_ERR(conn->rx_thread)) { + pr_err("Unable to start iscsi_target_rx_thread\n"); + ret = PTR_ERR(conn->rx_thread); + goto out_tx; + } + conn->rx_thread_active = true; + + return 0; +out_tx: + kthread_stop(conn->tx_thread); + conn->tx_thread_active = false; +out_bitmap: + spin_lock(&iscsit_global->ts_bitmap_lock); + bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, + get_order(1)); + spin_unlock(&iscsit_global->ts_bitmap_lock); + return ret; +} + int iscsi_post_login_handler( struct iscsi_np *np, struct iscsi_conn *conn, @@ -709,7 +754,7 @@ int iscsi_post_login_handler( struct se_session *se_sess = sess->se_sess; struct iscsi_portal_group *tpg = sess->tpg; struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; - struct iscsi_thread_set *ts; + int rc; iscsit_inc_conn_usage_count(conn); @@ -724,7 +769,6 @@ int iscsi_post_login_handler( /* * SCSI Initiator -> SCSI Target Port Mapping */ - ts = iscsi_get_thread_set(); if (!zero_tsih) { iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 0); @@ -751,9 +795,11 @@ int iscsi_post_login_handler( sess->sess_ops->InitiatorName); spin_unlock_bh(&sess->conn_lock); - iscsi_post_login_start_timers(conn); + rc = iscsit_start_kthreads(conn); + if (rc) + return rc; - iscsi_activate_thread_set(conn, ts); + iscsi_post_login_start_timers(conn); /* * Determine CPU mask to ensure connection's RX and TX kthreads * are scheduled on the same CPU. @@ -810,8 +856,11 @@ int iscsi_post_login_handler( " iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt); spin_unlock_bh(&se_tpg->session_lock); + rc = iscsit_start_kthreads(conn); + if (rc) + return rc; + iscsi_post_login_start_timers(conn); - iscsi_activate_thread_set(conn, ts); /* * Determine CPU mask to ensure connection's RX and TX kthreads * are scheduled on the same CPU. diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index d3583d3ee193..dd0f3abde75d 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -602,6 +602,11 @@ struct iscsi_conn { struct iscsi_session *sess; /* Pointer to thread_set in use for this conn's threads */ struct iscsi_thread_set *thread_set; + int bitmap_id; + int rx_thread_active; + struct task_struct *rx_thread; + int tx_thread_active; + struct task_struct *tx_thread; /* list_head for session connection list */ struct list_head conn_list; } ____cacheline_aligned; @@ -871,10 +876,12 @@ struct iscsit_global { /* Unique identifier used for the authentication daemon */ u32 auth_id; u32 inactive_ts; +#define ISCSIT_BITMAP_BITS 262144 /* Thread Set bitmap count */ int ts_bitmap_count; /* Thread Set bitmap pointer */ unsigned long *ts_bitmap; + spinlock_t ts_bitmap_lock; /* Used for iSCSI discovery session authentication */ struct iscsi_node_acl discovery_acl; struct iscsi_portal_group *discovery_tpg; -- cgit v1.2.3 From 073900bdb4e34109a647c7cb871856a771634460 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 27 Feb 2015 10:21:06 +0000 Subject: iscsi-target: Drop legacy iscsi_target_tq.c logic Now that iscsi_conn allocates new [rx,tx] threads using kthread.h primitives on the fly, and kthread_stop() is called directly during connection shutdown, it's time to go ahead and drop iscsi_target_tq.c legacy code. The use of multiple struct completion in iscsi_activate_thread_set() has been proven to cause issues during repeated iser login/logout. Tested-by: Sagi Grimberg Cc: Slava Shwartsman Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/Makefile | 1 - drivers/target/iscsi/iscsi_target.c | 3 - drivers/target/iscsi/iscsi_target_erl0.c | 1 - drivers/target/iscsi/iscsi_target_login.c | 1 - drivers/target/iscsi/iscsi_target_tq.c | 495 ------------------------------ drivers/target/iscsi/iscsi_target_tq.h | 84 ----- drivers/target/iscsi/iscsi_target_util.c | 1 - include/target/iscsi/iscsi_target_core.h | 6 +- 8 files changed, 2 insertions(+), 590 deletions(-) delete mode 100644 drivers/target/iscsi/iscsi_target_tq.c delete mode 100644 drivers/target/iscsi/iscsi_target_tq.h (limited to 'include') diff --git a/drivers/target/iscsi/Makefile b/drivers/target/iscsi/Makefile index 13a92403fe3e..0f43be9c3453 100644 --- a/drivers/target/iscsi/Makefile +++ b/drivers/target/iscsi/Makefile @@ -1,6 +1,5 @@ iscsi_target_mod-y += iscsi_target_parameters.o \ iscsi_target_seq_pdu_list.o \ - iscsi_target_tq.o \ iscsi_target_auth.o \ iscsi_target_datain_values.o \ iscsi_target_device.o \ diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 163773fb4f84..cd611e740de7 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -33,7 +33,6 @@ #include #include "iscsi_target_parameters.h" #include "iscsi_target_seq_pdu_list.h" -#include "iscsi_target_tq.h" #include "iscsi_target_configfs.h" #include "iscsi_target_datain_values.h" #include "iscsi_target_erl0.h" @@ -4360,8 +4359,6 @@ int iscsit_close_connection( iscsit_put_transport(conn->conn_transport); - conn->thread_set = NULL; - pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); conn->conn_state = TARG_CONN_STATE_FREE; kfree(conn); diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index d4e2159f53c2..e1f4c7eedb08 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -24,7 +24,6 @@ #include #include #include "iscsi_target_seq_pdu_list.h" -#include "iscsi_target_tq.h" #include "iscsi_target_erl0.h" #include "iscsi_target_erl1.h" #include "iscsi_target_erl2.h" diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 345f073ff6dc..af20ddf2bbb4 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -26,7 +26,6 @@ #include #include -#include "iscsi_target_tq.h" #include "iscsi_target_device.h" #include "iscsi_target_nego.h" #include "iscsi_target_erl0.h" diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c deleted file mode 100644 index 26aa50996473..000000000000 --- a/drivers/target/iscsi/iscsi_target_tq.c +++ /dev/null @@ -1,495 +0,0 @@ -/******************************************************************************* - * This file contains the iSCSI Login Thread and Thread Queue functions. - * - * (c) Copyright 2007-2013 Datera, Inc. - * - * Author: Nicholas A. Bellinger - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include - -#include -#include "iscsi_target_tq.h" -#include "iscsi_target.h" - -static LIST_HEAD(inactive_ts_list); -static DEFINE_SPINLOCK(inactive_ts_lock); -static DEFINE_SPINLOCK(ts_bitmap_lock); - -static void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts) -{ - if (!list_empty(&ts->ts_list)) { - WARN_ON(1); - return; - } - spin_lock(&inactive_ts_lock); - list_add_tail(&ts->ts_list, &inactive_ts_list); - iscsit_global->inactive_ts++; - spin_unlock(&inactive_ts_lock); -} - -static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void) -{ - struct iscsi_thread_set *ts; - - spin_lock(&inactive_ts_lock); - if (list_empty(&inactive_ts_list)) { - spin_unlock(&inactive_ts_lock); - return NULL; - } - - ts = list_first_entry(&inactive_ts_list, struct iscsi_thread_set, ts_list); - - list_del_init(&ts->ts_list); - iscsit_global->inactive_ts--; - spin_unlock(&inactive_ts_lock); - - return ts; -} - -int iscsi_allocate_thread_sets(u32 thread_pair_count) -{ - int allocated_thread_pair_count = 0, i, thread_id; - struct iscsi_thread_set *ts = NULL; - - for (i = 0; i < thread_pair_count; i++) { - ts = kzalloc(sizeof(struct iscsi_thread_set), GFP_KERNEL); - if (!ts) { - pr_err("Unable to allocate memory for" - " thread set.\n"); - return allocated_thread_pair_count; - } - /* - * Locate the next available regision in the thread_set_bitmap - */ - spin_lock(&ts_bitmap_lock); - thread_id = bitmap_find_free_region(iscsit_global->ts_bitmap, - iscsit_global->ts_bitmap_count, get_order(1)); - spin_unlock(&ts_bitmap_lock); - if (thread_id < 0) { - pr_err("bitmap_find_free_region() failed for" - " thread_set_bitmap\n"); - kfree(ts); - return allocated_thread_pair_count; - } - - ts->thread_id = thread_id; - ts->status = ISCSI_THREAD_SET_FREE; - INIT_LIST_HEAD(&ts->ts_list); - spin_lock_init(&ts->ts_state_lock); - init_completion(&ts->rx_restart_comp); - init_completion(&ts->tx_restart_comp); - init_completion(&ts->rx_start_comp); - init_completion(&ts->tx_start_comp); - sema_init(&ts->ts_activate_sem, 0); - - ts->create_threads = 1; - ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s", - ISCSI_TX_THREAD_NAME); - if (IS_ERR(ts->tx_thread)) { - dump_stack(); - pr_err("Unable to start iscsi_target_tx_thread\n"); - break; - } - - ts->rx_thread = kthread_run(iscsi_target_rx_thread, ts, "%s", - ISCSI_RX_THREAD_NAME); - if (IS_ERR(ts->rx_thread)) { - kthread_stop(ts->tx_thread); - pr_err("Unable to start iscsi_target_rx_thread\n"); - break; - } - ts->create_threads = 0; - - iscsi_add_ts_to_inactive_list(ts); - allocated_thread_pair_count++; - } - - pr_debug("Spawned %d thread set(s) (%d total threads).\n", - allocated_thread_pair_count, allocated_thread_pair_count * 2); - return allocated_thread_pair_count; -} - -static void iscsi_deallocate_thread_one(struct iscsi_thread_set *ts) -{ - spin_lock_bh(&ts->ts_state_lock); - ts->status = ISCSI_THREAD_SET_DIE; - - if (ts->rx_thread) { - complete(&ts->rx_start_comp); - spin_unlock_bh(&ts->ts_state_lock); - kthread_stop(ts->rx_thread); - spin_lock_bh(&ts->ts_state_lock); - } - if (ts->tx_thread) { - complete(&ts->tx_start_comp); - spin_unlock_bh(&ts->ts_state_lock); - kthread_stop(ts->tx_thread); - spin_lock_bh(&ts->ts_state_lock); - } - spin_unlock_bh(&ts->ts_state_lock); - /* - * Release this thread_id in the thread_set_bitmap - */ - spin_lock(&ts_bitmap_lock); - bitmap_release_region(iscsit_global->ts_bitmap, - ts->thread_id, get_order(1)); - spin_unlock(&ts_bitmap_lock); - - kfree(ts); -} - -void iscsi_deallocate_thread_sets(void) -{ - struct iscsi_thread_set *ts = NULL; - u32 released_count = 0; - - while ((ts = iscsi_get_ts_from_inactive_list())) { - - iscsi_deallocate_thread_one(ts); - released_count++; - } - - if (released_count) - pr_debug("Stopped %d thread set(s) (%d total threads)." - "\n", released_count, released_count * 2); -} - -static void iscsi_deallocate_extra_thread_sets(void) -{ - u32 orig_count, released_count = 0; - struct iscsi_thread_set *ts = NULL; - - orig_count = TARGET_THREAD_SET_COUNT; - - while ((iscsit_global->inactive_ts + 1) > orig_count) { - ts = iscsi_get_ts_from_inactive_list(); - if (!ts) - break; - - iscsi_deallocate_thread_one(ts); - released_count++; - } - - if (released_count) - pr_debug("Stopped %d thread set(s) (%d total threads)." - "\n", released_count, released_count * 2); -} - -void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts) -{ - spin_lock_bh(&ts->ts_state_lock); - conn->thread_set = ts; - ts->conn = conn; - ts->status = ISCSI_THREAD_SET_ACTIVE; - spin_unlock_bh(&ts->ts_state_lock); - - complete(&ts->rx_start_comp); - complete(&ts->tx_start_comp); - - down(&ts->ts_activate_sem); -} - -struct iscsi_thread_set *iscsi_get_thread_set(void) -{ - struct iscsi_thread_set *ts; - -get_set: - ts = iscsi_get_ts_from_inactive_list(); - if (!ts) { - iscsi_allocate_thread_sets(1); - goto get_set; - } - - ts->delay_inactive = 1; - ts->signal_sent = 0; - ts->thread_count = 2; - init_completion(&ts->rx_restart_comp); - init_completion(&ts->tx_restart_comp); - sema_init(&ts->ts_activate_sem, 0); - - return ts; -} - -void iscsi_set_thread_clear(struct iscsi_conn *conn, u8 thread_clear) -{ - struct iscsi_thread_set *ts = NULL; - - if (!conn->thread_set) { - pr_err("struct iscsi_conn->thread_set is NULL\n"); - return; - } - ts = conn->thread_set; - - spin_lock_bh(&ts->ts_state_lock); - ts->thread_clear &= ~thread_clear; - - if ((thread_clear & ISCSI_CLEAR_RX_THREAD) && - (ts->blocked_threads & ISCSI_BLOCK_RX_THREAD)) - complete(&ts->rx_restart_comp); - else if ((thread_clear & ISCSI_CLEAR_TX_THREAD) && - (ts->blocked_threads & ISCSI_BLOCK_TX_THREAD)) - complete(&ts->tx_restart_comp); - spin_unlock_bh(&ts->ts_state_lock); -} - -void iscsi_set_thread_set_signal(struct iscsi_conn *conn, u8 signal_sent) -{ - struct iscsi_thread_set *ts = NULL; - - if (!conn->thread_set) { - pr_err("struct iscsi_conn->thread_set is NULL\n"); - return; - } - ts = conn->thread_set; - - spin_lock_bh(&ts->ts_state_lock); - ts->signal_sent |= signal_sent; - spin_unlock_bh(&ts->ts_state_lock); -} - -int iscsi_release_thread_set(struct iscsi_conn *conn) -{ - int thread_called = 0; - struct iscsi_thread_set *ts = NULL; - - if (!conn || !conn->thread_set) { - pr_err("connection or thread set pointer is NULL\n"); - BUG(); - } - ts = conn->thread_set; - - spin_lock_bh(&ts->ts_state_lock); - ts->status = ISCSI_THREAD_SET_RESET; - - if (!strncmp(current->comm, ISCSI_RX_THREAD_NAME, - strlen(ISCSI_RX_THREAD_NAME))) - thread_called = ISCSI_RX_THREAD; - else if (!strncmp(current->comm, ISCSI_TX_THREAD_NAME, - strlen(ISCSI_TX_THREAD_NAME))) - thread_called = ISCSI_TX_THREAD; - - if (ts->rx_thread && (thread_called == ISCSI_TX_THREAD) && - (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) { - - if (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD)) { - send_sig(SIGINT, ts->rx_thread, 1); - ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD; - } - ts->blocked_threads |= ISCSI_BLOCK_RX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); - wait_for_completion(&ts->rx_restart_comp); - spin_lock_bh(&ts->ts_state_lock); - ts->blocked_threads &= ~ISCSI_BLOCK_RX_THREAD; - } - if (ts->tx_thread && (thread_called == ISCSI_RX_THREAD) && - (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) { - - if (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD)) { - send_sig(SIGINT, ts->tx_thread, 1); - ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD; - } - ts->blocked_threads |= ISCSI_BLOCK_TX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); - wait_for_completion(&ts->tx_restart_comp); - spin_lock_bh(&ts->ts_state_lock); - ts->blocked_threads &= ~ISCSI_BLOCK_TX_THREAD; - } - - ts->conn = NULL; - ts->status = ISCSI_THREAD_SET_FREE; - spin_unlock_bh(&ts->ts_state_lock); - - return 0; -} - -int iscsi_thread_set_force_reinstatement(struct iscsi_conn *conn) -{ - struct iscsi_thread_set *ts; - - if (!conn->thread_set) - return -1; - ts = conn->thread_set; - - spin_lock_bh(&ts->ts_state_lock); - if (ts->status != ISCSI_THREAD_SET_ACTIVE) { - spin_unlock_bh(&ts->ts_state_lock); - return -1; - } - - if (ts->tx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD))) { - send_sig(SIGINT, ts->tx_thread, 1); - ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD; - } - if (ts->rx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD))) { - send_sig(SIGINT, ts->rx_thread, 1); - ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD; - } - spin_unlock_bh(&ts->ts_state_lock); - - return 0; -} - -static void iscsi_check_to_add_additional_sets(void) -{ - int thread_sets_add; - - spin_lock(&inactive_ts_lock); - thread_sets_add = iscsit_global->inactive_ts; - spin_unlock(&inactive_ts_lock); - if (thread_sets_add == 1) - iscsi_allocate_thread_sets(1); -} - -static int iscsi_signal_thread_pre_handler(struct iscsi_thread_set *ts) -{ - spin_lock_bh(&ts->ts_state_lock); - if (ts->status == ISCSI_THREAD_SET_DIE || kthread_should_stop() || - signal_pending(current)) { - spin_unlock_bh(&ts->ts_state_lock); - return -1; - } - spin_unlock_bh(&ts->ts_state_lock); - - return 0; -} - -struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts) -{ - int ret; - - spin_lock_bh(&ts->ts_state_lock); - if (ts->create_threads) { - spin_unlock_bh(&ts->ts_state_lock); - goto sleep; - } - - if (ts->status != ISCSI_THREAD_SET_DIE) - flush_signals(current); - - if (ts->delay_inactive && (--ts->thread_count == 0)) { - spin_unlock_bh(&ts->ts_state_lock); - - if (!iscsit_global->in_shutdown) - iscsi_deallocate_extra_thread_sets(); - - iscsi_add_ts_to_inactive_list(ts); - spin_lock_bh(&ts->ts_state_lock); - } - - if ((ts->status == ISCSI_THREAD_SET_RESET) && - (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) - complete(&ts->rx_restart_comp); - - ts->thread_clear &= ~ISCSI_CLEAR_RX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); -sleep: - ret = wait_for_completion_interruptible(&ts->rx_start_comp); - if (ret != 0) - return NULL; - - if (iscsi_signal_thread_pre_handler(ts) < 0) - return NULL; - - iscsi_check_to_add_additional_sets(); - - spin_lock_bh(&ts->ts_state_lock); - if (!ts->conn) { - pr_err("struct iscsi_thread_set->conn is NULL for" - " RX thread_id: %s/%d\n", current->comm, current->pid); - spin_unlock_bh(&ts->ts_state_lock); - return NULL; - } - ts->thread_clear |= ISCSI_CLEAR_RX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); - - up(&ts->ts_activate_sem); - - return ts->conn; -} - -struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts) -{ - int ret; - - spin_lock_bh(&ts->ts_state_lock); - if (ts->create_threads) { - spin_unlock_bh(&ts->ts_state_lock); - goto sleep; - } - - if (ts->status != ISCSI_THREAD_SET_DIE) - flush_signals(current); - - if (ts->delay_inactive && (--ts->thread_count == 0)) { - spin_unlock_bh(&ts->ts_state_lock); - - if (!iscsit_global->in_shutdown) - iscsi_deallocate_extra_thread_sets(); - - iscsi_add_ts_to_inactive_list(ts); - spin_lock_bh(&ts->ts_state_lock); - } - if ((ts->status == ISCSI_THREAD_SET_RESET) && - (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) - complete(&ts->tx_restart_comp); - - ts->thread_clear &= ~ISCSI_CLEAR_TX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); -sleep: - ret = wait_for_completion_interruptible(&ts->tx_start_comp); - if (ret != 0) - return NULL; - - if (iscsi_signal_thread_pre_handler(ts) < 0) - return NULL; - - iscsi_check_to_add_additional_sets(); - - spin_lock_bh(&ts->ts_state_lock); - if (!ts->conn) { - pr_err("struct iscsi_thread_set->conn is NULL for" - " TX thread_id: %s/%d\n", current->comm, current->pid); - spin_unlock_bh(&ts->ts_state_lock); - return NULL; - } - ts->thread_clear |= ISCSI_CLEAR_TX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); - - up(&ts->ts_activate_sem); - - return ts->conn; -} - -int iscsi_thread_set_init(void) -{ - int size; - - iscsit_global->ts_bitmap_count = ISCSI_TS_BITMAP_BITS; - - size = BITS_TO_LONGS(iscsit_global->ts_bitmap_count) * sizeof(long); - iscsit_global->ts_bitmap = kzalloc(size, GFP_KERNEL); - if (!iscsit_global->ts_bitmap) { - pr_err("Unable to allocate iscsit_global->ts_bitmap\n"); - return -ENOMEM; - } - - return 0; -} - -void iscsi_thread_set_free(void) -{ - kfree(iscsit_global->ts_bitmap); -} diff --git a/drivers/target/iscsi/iscsi_target_tq.h b/drivers/target/iscsi/iscsi_target_tq.h deleted file mode 100644 index cc1eede5ab3a..000000000000 --- a/drivers/target/iscsi/iscsi_target_tq.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef ISCSI_THREAD_QUEUE_H -#define ISCSI_THREAD_QUEUE_H - -/* - * Defines for thread sets. - */ -extern int iscsi_thread_set_force_reinstatement(struct iscsi_conn *); -extern int iscsi_allocate_thread_sets(u32); -extern void iscsi_deallocate_thread_sets(void); -extern void iscsi_activate_thread_set(struct iscsi_conn *, struct iscsi_thread_set *); -extern struct iscsi_thread_set *iscsi_get_thread_set(void); -extern void iscsi_set_thread_clear(struct iscsi_conn *, u8); -extern void iscsi_set_thread_set_signal(struct iscsi_conn *, u8); -extern int iscsi_release_thread_set(struct iscsi_conn *); -extern struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *); -extern struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *); -extern int iscsi_thread_set_init(void); -extern void iscsi_thread_set_free(void); - -extern int iscsi_target_tx_thread(void *); -extern int iscsi_target_rx_thread(void *); - -#define TARGET_THREAD_SET_COUNT 4 - -#define ISCSI_RX_THREAD 1 -#define ISCSI_TX_THREAD 2 -#define ISCSI_RX_THREAD_NAME "iscsi_trx" -#define ISCSI_TX_THREAD_NAME "iscsi_ttx" -#define ISCSI_BLOCK_RX_THREAD 0x1 -#define ISCSI_BLOCK_TX_THREAD 0x2 -#define ISCSI_CLEAR_RX_THREAD 0x1 -#define ISCSI_CLEAR_TX_THREAD 0x2 -#define ISCSI_SIGNAL_RX_THREAD 0x1 -#define ISCSI_SIGNAL_TX_THREAD 0x2 - -/* struct iscsi_thread_set->status */ -#define ISCSI_THREAD_SET_FREE 1 -#define ISCSI_THREAD_SET_ACTIVE 2 -#define ISCSI_THREAD_SET_DIE 3 -#define ISCSI_THREAD_SET_RESET 4 -#define ISCSI_THREAD_SET_DEALLOCATE_THREADS 5 - -/* By default allow a maximum of 32K iSCSI connections */ -#define ISCSI_TS_BITMAP_BITS 32768 - -struct iscsi_thread_set { - /* flags used for blocking and restarting sets */ - int blocked_threads; - /* flag for creating threads */ - int create_threads; - /* flag for delaying readding to inactive list */ - int delay_inactive; - /* status for thread set */ - int status; - /* which threads have had signals sent */ - int signal_sent; - /* flag for which threads exited first */ - int thread_clear; - /* Active threads in the thread set */ - int thread_count; - /* Unique thread ID */ - u32 thread_id; - /* pointer to connection if set is active */ - struct iscsi_conn *conn; - /* used for controlling ts state accesses */ - spinlock_t ts_state_lock; - /* used for restarting thread queue */ - struct completion rx_restart_comp; - /* used for restarting thread queue */ - struct completion tx_restart_comp; - /* used for normal unused blocking */ - struct completion rx_start_comp; - /* used for normal unused blocking */ - struct completion tx_start_comp; - /* OS descriptor for rx thread */ - struct task_struct *rx_thread; - /* OS descriptor for tx thread */ - struct task_struct *tx_thread; - /* struct iscsi_thread_set in list list head*/ - struct list_head ts_list; - struct semaphore ts_activate_sem; -}; - -#endif /*** ISCSI_THREAD_QUEUE_H ***/ diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 390df8ed72b2..b18edda3e8af 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -33,7 +33,6 @@ #include "iscsi_target_erl1.h" #include "iscsi_target_erl2.h" #include "iscsi_target_tpg.h" -#include "iscsi_target_tq.h" #include "iscsi_target_util.h" #include "iscsi_target.h" diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index dd0f3abde75d..0e394a031c28 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -20,6 +20,8 @@ #define ISCSIT_MIN_TAGS 16 #define ISCSIT_EXTRA_TAGS 8 #define ISCSIT_TCP_BACKLOG 256 +#define ISCSI_RX_THREAD_NAME "iscsi_trx" +#define ISCSI_TX_THREAD_NAME "iscsi_ttx" /* struct iscsi_node_attrib sanity values */ #define NA_DATAOUT_TIMEOUT 3 @@ -600,8 +602,6 @@ struct iscsi_conn { struct iscsi_tpg_np *tpg_np; /* Pointer to parent session */ struct iscsi_session *sess; - /* Pointer to thread_set in use for this conn's threads */ - struct iscsi_thread_set *thread_set; int bitmap_id; int rx_thread_active; struct task_struct *rx_thread; @@ -877,8 +877,6 @@ struct iscsit_global { u32 auth_id; u32 inactive_ts; #define ISCSIT_BITMAP_BITS 262144 - /* Thread Set bitmap count */ - int ts_bitmap_count; /* Thread Set bitmap pointer */ unsigned long *ts_bitmap; spinlock_t ts_bitmap_lock; -- cgit v1.2.3 From ee97d0e3f06498487671c23cad4230bf9aa5fd88 Mon Sep 17 00:00:00 2001 From: Mans Rullgard Date: Sun, 8 Mar 2015 14:30:04 +0000 Subject: serial: 8250: allow specifying iomem size in addition to address This adds a mapsize field to struct uart_port to be used in conjunction with mapbase. If set, it overrides whatever value serial8250_port_size() would otherwise report. Signed-off-by: Mans Rullgard Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 4 ++++ include/linux/serial_core.h | 1 + 2 files changed, 5 insertions(+) (limited to 'include') diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 9b2de25359d1..e0fb5f053d09 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -2722,6 +2722,8 @@ serial8250_pm(struct uart_port *port, unsigned int state, static unsigned int serial8250_port_size(struct uart_8250_port *pt) { + if (pt->port.mapsize) + return pt->port.mapsize; if (pt->port.iotype == UPIO_AU) { if (pt->port.type == PORT_RT2880) return 0x100; @@ -3553,6 +3555,7 @@ int __init early_serial_setup(struct uart_port *port) p->iotype = port->iotype; p->flags = port->flags; p->mapbase = port->mapbase; + p->mapsize = port->mapsize; p->private_data = port->private_data; p->type = port->type; p->line = port->line; @@ -3807,6 +3810,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF; uart->bugs = up->bugs; uart->port.mapbase = up->port.mapbase; + uart->port.mapsize = up->port.mapsize; uart->port.private_data = up->port.private_data; uart->port.fifosize = up->port.fifosize; uart->tx_loadsz = up->tx_loadsz; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 8aeec4913a9c..34de16840152 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -237,6 +237,7 @@ struct uart_port { unsigned int line; /* port index */ unsigned int minor; resource_size_t mapbase; /* for ioremap */ + resource_size_t mapsize; struct device *dev; /* parent device */ unsigned char hub6; /* this should be in the 8250 driver */ unsigned char suspended; -- cgit v1.2.3 From 911a88829725572820dad9a168e735c606a2fdcb Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Mon, 9 Mar 2015 14:29:04 +0000 Subject: memory: jz4780-nemc: driver for the NEMC on JZ4780 SoCs Add a driver for the NAND/External Memory Controller (NEMC) on JZ4780 and later SoCs. The primary function of this driver is to configure parameters, such as timings, for external memory devices using data supplied in the device tree. Devices connected to the NEMC are represented in the DT as children of the NEMC node, the driver uses optional properties specified in these child nodes to configure the parameters of each bank. Signed-off-by: Alex Smith Signed-off-by: Zubair Lutfullah Kakakhel Signed-off-by: Greg Kroah-Hartman --- drivers/memory/Kconfig | 9 + drivers/memory/Makefile | 1 + drivers/memory/jz4780-nemc.c | 391 +++++++++++++++++++++++++++++++++++++++++++ include/linux/jz4780-nemc.h | 43 +++++ 4 files changed, 444 insertions(+) create mode 100644 drivers/memory/jz4780-nemc.c create mode 100644 include/linux/jz4780-nemc.h (limited to 'include') diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index 191383d8c94d..868036f70f8f 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -83,6 +83,15 @@ config FSL_IFC bool depends on FSL_SOC +config JZ4780_NEMC + bool "Ingenic JZ4780 SoC NEMC driver" + default y + depends on MACH_JZ4780 + help + This driver is for the NAND/External Memory Controller (NEMC) in + the Ingenic JZ4780. This controller is used to handle external + memory devices such as NAND and SRAM. + source "drivers/memory/tegra/Kconfig" endif diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index 6b6548124473..b670441e3cdf 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -13,5 +13,6 @@ obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o obj-$(CONFIG_FSL_IFC) += fsl_ifc.o obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o +obj-$(CONFIG_JZ4780_NEMC) += jz4780-nemc.o obj-$(CONFIG_TEGRA_MC) += tegra/ diff --git a/drivers/memory/jz4780-nemc.c b/drivers/memory/jz4780-nemc.c new file mode 100644 index 000000000000..919d1925acb9 --- /dev/null +++ b/drivers/memory/jz4780-nemc.c @@ -0,0 +1,391 @@ +/* + * JZ4780 NAND/external memory controller (NEMC) + * + * Copyright (c) 2015 Imagination Technologies + * Author: Alex Smith + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define NEMC_SMCRn(n) (0x14 + (((n) - 1) * 4)) +#define NEMC_NFCSR 0x50 + +#define NEMC_SMCR_SMT BIT(0) +#define NEMC_SMCR_BW_SHIFT 6 +#define NEMC_SMCR_BW_MASK (0x3 << NEMC_SMCR_BW_SHIFT) +#define NEMC_SMCR_BW_8 (0 << 6) +#define NEMC_SMCR_TAS_SHIFT 8 +#define NEMC_SMCR_TAS_MASK (0xf << NEMC_SMCR_TAS_SHIFT) +#define NEMC_SMCR_TAH_SHIFT 12 +#define NEMC_SMCR_TAH_MASK (0xf << NEMC_SMCR_TAH_SHIFT) +#define NEMC_SMCR_TBP_SHIFT 16 +#define NEMC_SMCR_TBP_MASK (0xf << NEMC_SMCR_TBP_SHIFT) +#define NEMC_SMCR_TAW_SHIFT 20 +#define NEMC_SMCR_TAW_MASK (0xf << NEMC_SMCR_TAW_SHIFT) +#define NEMC_SMCR_TSTRV_SHIFT 24 +#define NEMC_SMCR_TSTRV_MASK (0x3f << NEMC_SMCR_TSTRV_SHIFT) + +#define NEMC_NFCSR_NFEn(n) BIT(((n) - 1) << 1) +#define NEMC_NFCSR_NFCEn(n) BIT((((n) - 1) << 1) + 1) +#define NEMC_NFCSR_TNFEn(n) BIT(16 + (n) - 1) + +struct jz4780_nemc { + spinlock_t lock; + struct device *dev; + void __iomem *base; + struct clk *clk; + uint32_t clk_period; + unsigned long banks_present; +}; + +/** + * jz4780_nemc_num_banks() - count the number of banks referenced by a device + * @dev: device to count banks for, must be a child of the NEMC. + * + * Return: The number of unique NEMC banks referred to by the specified NEMC + * child device. Unique here means that a device that references the same bank + * multiple times in the its "reg" property will only count once. + */ +unsigned int jz4780_nemc_num_banks(struct device *dev) +{ + const __be32 *prop; + unsigned int bank, count = 0; + unsigned long referenced = 0; + int i = 0; + + while ((prop = of_get_address(dev->of_node, i++, NULL, NULL))) { + bank = of_read_number(prop, 1); + if (!(referenced & BIT(bank))) { + referenced |= BIT(bank); + count++; + } + } + + return count; +} +EXPORT_SYMBOL(jz4780_nemc_num_banks); + +/** + * jz4780_nemc_set_type() - set the type of device connected to a bank + * @dev: child device of the NEMC. + * @bank: bank number to configure. + * @type: type of device connected to the bank. + */ +void jz4780_nemc_set_type(struct device *dev, unsigned int bank, + enum jz4780_nemc_bank_type type) +{ + struct jz4780_nemc *nemc = dev_get_drvdata(dev->parent); + uint32_t nfcsr; + + nfcsr = readl(nemc->base + NEMC_NFCSR); + + /* TODO: Support toggle NAND devices. */ + switch (type) { + case JZ4780_NEMC_BANK_SRAM: + nfcsr &= ~(NEMC_NFCSR_TNFEn(bank) | NEMC_NFCSR_NFEn(bank)); + break; + case JZ4780_NEMC_BANK_NAND: + nfcsr &= ~NEMC_NFCSR_TNFEn(bank); + nfcsr |= NEMC_NFCSR_NFEn(bank); + break; + } + + writel(nfcsr, nemc->base + NEMC_NFCSR); +} +EXPORT_SYMBOL(jz4780_nemc_set_type); + +/** + * jz4780_nemc_assert() - (de-)assert a NAND device's chip enable pin + * @dev: child device of the NEMC. + * @bank: bank number of device. + * @assert: whether the chip enable pin should be asserted. + * + * (De-)asserts the chip enable pin for the NAND device connected to the + * specified bank. + */ +void jz4780_nemc_assert(struct device *dev, unsigned int bank, bool assert) +{ + struct jz4780_nemc *nemc = dev_get_drvdata(dev->parent); + uint32_t nfcsr; + + nfcsr = readl(nemc->base + NEMC_NFCSR); + + if (assert) + nfcsr |= NEMC_NFCSR_NFCEn(bank); + else + nfcsr &= ~NEMC_NFCSR_NFCEn(bank); + + writel(nfcsr, nemc->base + NEMC_NFCSR); +} +EXPORT_SYMBOL(jz4780_nemc_assert); + +static uint32_t jz4780_nemc_clk_period(struct jz4780_nemc *nemc) +{ + unsigned long rate; + + rate = clk_get_rate(nemc->clk); + if (!rate) + return 0; + + /* Return in picoseconds. */ + return div64_ul(1000000000000ull, rate); +} + +static uint32_t jz4780_nemc_ns_to_cycles(struct jz4780_nemc *nemc, uint32_t ns) +{ + return ((ns * 1000) + nemc->clk_period - 1) / nemc->clk_period; +} + +static bool jz4780_nemc_configure_bank(struct jz4780_nemc *nemc, + unsigned int bank, + struct device_node *node) +{ + uint32_t smcr, val, cycles; + + /* + * Conversion of tBP and tAW cycle counts to values supported by the + * hardware (round up to the next supported value). + */ + static const uint32_t convert_tBP_tAW[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + + /* 11 - 12 -> 12 cycles */ + 11, 11, + + /* 13 - 15 -> 15 cycles */ + 12, 12, 12, + + /* 16 - 20 -> 20 cycles */ + 13, 13, 13, 13, 13, + + /* 21 - 25 -> 25 cycles */ + 14, 14, 14, 14, 14, + + /* 26 - 31 -> 31 cycles */ + 15, 15, 15, 15, 15, 15 + }; + + smcr = readl(nemc->base + NEMC_SMCRn(bank)); + smcr &= ~NEMC_SMCR_SMT; + + if (!of_property_read_u32(node, "ingenic,nemc-bus-width", &val)) { + smcr &= ~NEMC_SMCR_BW_MASK; + switch (val) { + case 8: + smcr |= NEMC_SMCR_BW_8; + break; + default: + /* + * Earlier SoCs support a 16 bit bus width (the 4780 + * does not), until those are properly supported, error. + */ + dev_err(nemc->dev, "unsupported bus width: %u\n", val); + return false; + } + } + + if (of_property_read_u32(node, "ingenic,nemc-tAS", &val) == 0) { + smcr &= ~NEMC_SMCR_TAS_MASK; + cycles = jz4780_nemc_ns_to_cycles(nemc, val); + if (cycles > 15) { + dev_err(nemc->dev, "tAS %u is too high (%u cycles)\n", + val, cycles); + return false; + } + + smcr |= cycles << NEMC_SMCR_TAS_SHIFT; + } + + if (of_property_read_u32(node, "ingenic,nemc-tAH", &val) == 0) { + smcr &= ~NEMC_SMCR_TAH_MASK; + cycles = jz4780_nemc_ns_to_cycles(nemc, val); + if (cycles > 15) { + dev_err(nemc->dev, "tAH %u is too high (%u cycles)\n", + val, cycles); + return false; + } + + smcr |= cycles << NEMC_SMCR_TAH_SHIFT; + } + + if (of_property_read_u32(node, "ingenic,nemc-tBP", &val) == 0) { + smcr &= ~NEMC_SMCR_TBP_MASK; + cycles = jz4780_nemc_ns_to_cycles(nemc, val); + if (cycles > 31) { + dev_err(nemc->dev, "tBP %u is too high (%u cycles)\n", + val, cycles); + return false; + } + + smcr |= convert_tBP_tAW[cycles] << NEMC_SMCR_TBP_SHIFT; + } + + if (of_property_read_u32(node, "ingenic,nemc-tAW", &val) == 0) { + smcr &= ~NEMC_SMCR_TAW_MASK; + cycles = jz4780_nemc_ns_to_cycles(nemc, val); + if (cycles > 31) { + dev_err(nemc->dev, "tAW %u is too high (%u cycles)\n", + val, cycles); + return false; + } + + smcr |= convert_tBP_tAW[cycles] << NEMC_SMCR_TAW_SHIFT; + } + + if (of_property_read_u32(node, "ingenic,nemc-tSTRV", &val) == 0) { + smcr &= ~NEMC_SMCR_TSTRV_MASK; + cycles = jz4780_nemc_ns_to_cycles(nemc, val); + if (cycles > 63) { + dev_err(nemc->dev, "tSTRV %u is too high (%u cycles)\n", + val, cycles); + return false; + } + + smcr |= cycles << NEMC_SMCR_TSTRV_SHIFT; + } + + writel(smcr, nemc->base + NEMC_SMCRn(bank)); + return true; +} + +static int jz4780_nemc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct jz4780_nemc *nemc; + struct resource *res; + struct device_node *child; + const __be32 *prop; + unsigned int bank; + unsigned long referenced; + int i, ret; + + nemc = devm_kzalloc(dev, sizeof(*nemc), GFP_KERNEL); + if (!nemc) + return -ENOMEM; + + spin_lock_init(&nemc->lock); + nemc->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + nemc->base = devm_ioremap_resource(dev, res); + if (IS_ERR(nemc->base)) { + dev_err(dev, "failed to get I/O memory\n"); + return PTR_ERR(nemc->base); + } + + writel(0, nemc->base + NEMC_NFCSR); + + nemc->clk = devm_clk_get(dev, NULL); + if (IS_ERR(nemc->clk)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(nemc->clk); + } + + ret = clk_prepare_enable(nemc->clk); + if (ret) { + dev_err(dev, "failed to enable clock: %d\n", ret); + return ret; + } + + nemc->clk_period = jz4780_nemc_clk_period(nemc); + if (!nemc->clk_period) { + dev_err(dev, "failed to calculate clock period\n"); + clk_disable_unprepare(nemc->clk); + return -EINVAL; + } + + /* + * Iterate over child devices, check that they do not conflict with + * each other, and register child devices for them. If a child device + * has invalid properties, it is ignored and no platform device is + * registered for it. + */ + for_each_child_of_node(nemc->dev->of_node, child) { + referenced = 0; + i = 0; + while ((prop = of_get_address(child, i++, NULL, NULL))) { + bank = of_read_number(prop, 1); + if (bank < 1 || bank >= JZ4780_NEMC_NUM_BANKS) { + dev_err(nemc->dev, + "%s requests invalid bank %u\n", + child->full_name, bank); + + /* Will continue the outer loop below. */ + referenced = 0; + break; + } + + referenced |= BIT(bank); + } + + if (!referenced) { + dev_err(nemc->dev, "%s has no addresses\n", + child->full_name); + continue; + } else if (nemc->banks_present & referenced) { + dev_err(nemc->dev, "%s conflicts with another node\n", + child->full_name); + continue; + } + + /* Configure bank parameters. */ + for_each_set_bit(bank, &referenced, JZ4780_NEMC_NUM_BANKS) { + if (!jz4780_nemc_configure_bank(nemc, bank, child)) { + referenced = 0; + break; + } + } + + if (referenced) { + if (of_platform_device_create(child, NULL, nemc->dev)) + nemc->banks_present |= referenced; + } + } + + platform_set_drvdata(pdev, nemc); + dev_info(dev, "JZ4780 NEMC initialised\n"); + return 0; +} + +static int jz4780_nemc_remove(struct platform_device *pdev) +{ + struct jz4780_nemc *nemc = platform_get_drvdata(pdev); + + clk_disable_unprepare(nemc->clk); + return 0; +} + +static const struct of_device_id jz4780_nemc_dt_match[] = { + { .compatible = "ingenic,jz4780-nemc" }, + {}, +}; + +static struct platform_driver jz4780_nemc_driver = { + .probe = jz4780_nemc_probe, + .remove = jz4780_nemc_remove, + .driver = { + .name = "jz4780-nemc", + .of_match_table = of_match_ptr(jz4780_nemc_dt_match), + }, +}; + +static int __init jz4780_nemc_init(void) +{ + return platform_driver_register(&jz4780_nemc_driver); +} +subsys_initcall(jz4780_nemc_init); diff --git a/include/linux/jz4780-nemc.h b/include/linux/jz4780-nemc.h new file mode 100644 index 000000000000..e7f1cc7a2284 --- /dev/null +++ b/include/linux/jz4780-nemc.h @@ -0,0 +1,43 @@ +/* + * JZ4780 NAND/external memory controller (NEMC) + * + * Copyright (c) 2015 Imagination Technologies + * Author: Alex Smith + * + * 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. + */ + +#ifndef __LINUX_JZ4780_NEMC_H__ +#define __LINUX_JZ4780_NEMC_H__ + +#include + +struct device; + +/* + * Number of NEMC banks. Note that there are actually 6, but they are numbered + * from 1. + */ +#define JZ4780_NEMC_NUM_BANKS 7 + +/** + * enum jz4780_nemc_bank_type - device types which can be connected to a bank + * @JZ4780_NEMC_BANK_SRAM: SRAM + * @JZ4780_NEMC_BANK_NAND: NAND + */ +enum jz4780_nemc_bank_type { + JZ4780_NEMC_BANK_SRAM, + JZ4780_NEMC_BANK_NAND, +}; + +extern unsigned int jz4780_nemc_num_banks(struct device *dev); + +extern void jz4780_nemc_set_type(struct device *dev, unsigned int bank, + enum jz4780_nemc_bank_type type); +extern void jz4780_nemc_assert(struct device *dev, unsigned int bank, + bool assert); + +#endif /* __LINUX_JZ4780_NEMC_H__ */ -- cgit v1.2.3 From 2c60fae1489c70206e66c28d72b69a3e496c313d Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Thu, 26 Mar 2015 21:47:16 +0200 Subject: drm/i915: fix definition of the DRM_IOCTL_I915_GET_SPRITE_COLORKEY ioctl Fix definition of the DRM_IOCTL_I915_GET_SPRITE_COLORKEY ioctl, so that it is different from the DRM_IOCTL_I915_SET_SPRITE_COLORKEY ioctl. Note that this is just for accuracy, the ioctl implementation itself is totally unused and already ripped out. Signed-off-by: Tommi Rantala [danvet: Add note that this is a dead ioctl.] Signed-off-by: Daniel Vetter --- include/uapi/drm/i915_drm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 8d1be9073380..551b6737f5df 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -270,7 +270,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image) #define DRM_IOCTL_I915_OVERLAY_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs) #define DRM_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey) -#define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey) +#define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey) #define DRM_IOCTL_I915_GEM_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_WAIT, struct drm_i915_gem_wait) #define DRM_IOCTL_I915_GEM_CONTEXT_CREATE DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create) #define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy) -- cgit v1.2.3 From fe87414f71d0035756cf91a80ac256557d16b488 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Wed, 12 Mar 2014 18:33:45 +0200 Subject: ARM: OMAP2+: PRCM: split PRCM module init to their own driver files Splits the clock related provider module inits under their own driver files. Previously this was done for all modules under the common PRM driver. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/cm.h | 1 + arch/arm/mach-omap2/cm_common.c | 51 ++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/control.c | 47 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/control.h | 1 + arch/arm/mach-omap2/io.c | 4 ++++ arch/arm/mach-omap2/prm_common.c | 23 ++---------------- include/linux/clk/ti.h | 5 ++-- 7 files changed, 108 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h index 6222e87a79b6..748ac338812b 100644 --- a/arch/arm/mach-omap2/cm.h +++ b/arch/arm/mach-omap2/cm.h @@ -70,6 +70,7 @@ int omap_cm_module_enable(u8 mode, u8 part, u16 inst, u16 clkctrl_offs); int omap_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs); extern int cm_register(struct cm_ll_data *cld); extern int cm_unregister(struct cm_ll_data *cld); +int omap_cm_init(void); # endif diff --git a/arch/arm/mach-omap2/cm_common.c b/arch/arm/mach-omap2/cm_common.c index 8fe02fcedc48..f3d578be3272 100644 --- a/arch/arm/mach-omap2/cm_common.c +++ b/arch/arm/mach-omap2/cm_common.c @@ -15,10 +15,13 @@ #include #include #include +#include +#include #include "cm2xxx.h" #include "cm3xxx.h" #include "cm44xx.h" +#include "clock.h" /* * cm_ll_data: function pointers to SoC-specific implementations of @@ -212,3 +215,51 @@ int cm_unregister(struct cm_ll_data *cld) return 0; } + +static struct omap_prcm_init_data cm_data = { + .index = TI_CLKM_CM, +}; + +static struct omap_prcm_init_data cm2_data = { + .index = TI_CLKM_CM2, +}; + +static const struct of_device_id omap_cm_dt_match_table[] = { + { .compatible = "ti,omap3-cm", .data = &cm_data }, + { .compatible = "ti,omap4-cm1", .data = &cm_data }, + { .compatible = "ti,omap4-cm2", .data = &cm2_data }, + { .compatible = "ti,omap5-cm-core-aon", .data = &cm_data }, + { .compatible = "ti,omap5-cm-core", .data = &cm2_data }, + { .compatible = "ti,dra7-cm-core-aon", .data = &cm_data }, + { .compatible = "ti,dra7-cm-core", .data = &cm2_data }, + { } +}; + +/** + * omap_cm_init - low level init for the CM drivers + * + * Initializes the low level clock infrastructure for CM drivers. + * Returns 0 in success, negative error value in failure. + */ +int __init omap_cm_init(void) +{ + struct device_node *np; + void __iomem *mem; + const struct of_device_id *match; + const struct omap_prcm_init_data *data; + int ret; + + for_each_matching_node_and_match(np, omap_cm_dt_match_table, &match) { + data = match->data; + + mem = of_iomap(np, 0); + if (!mem) + return -ENOMEM; + + ret = omap2_clk_provider_init(np, data->index, mem); + if (ret) + return ret; + } + + return 0; +} diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index da041b4ab29c..e8818242f968 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -14,6 +14,7 @@ #include #include +#include #include "soc.h" #include "iomap.h" @@ -25,6 +26,7 @@ #include "sdrc.h" #include "pm.h" #include "control.h" +#include "clock.h" /* Used by omap3_ctrl_save_padconf() */ #define START_PADCONF_SAVE 0x2 @@ -611,3 +613,48 @@ void __init omap3_ctrl_init(void) omap3_ctrl_setup_d2d_padconf(); } #endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */ + +struct control_init_data { + int index; +}; + +static struct control_init_data ctrl_data = { + .index = TI_CLKM_CTRL, +}; + +static const struct of_device_id omap_scrm_dt_match_table[] = { + { .compatible = "ti,am3-scrm", .data = &ctrl_data }, + { .compatible = "ti,am4-scrm", .data = &ctrl_data }, + { .compatible = "ti,omap2-scrm", .data = &ctrl_data }, + { .compatible = "ti,omap3-scrm", .data = &ctrl_data }, + { } +}; + +/** + * omap_control_init - low level init for the control driver + * + * Initializes the low level clock infrastructure for control driver. + * Returns 0 in success, negative error value in failure. + */ +int __init omap_control_init(void) +{ + struct device_node *np; + void __iomem *mem; + const struct of_device_id *match; + const struct omap_prcm_init_data *data; + int ret; + + for_each_matching_node_and_match(np, omap_scrm_dt_match_table, &match) { + data = match->data; + + mem = of_iomap(np, 0); + if (!mem) + return -ENOMEM; + + ret = omap2_clk_provider_init(np, data->index, mem); + if (ret) + return ret; + } + + return 0; +} diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h index b8a487181210..baf5783cb05d 100644 --- a/arch/arm/mach-omap2/control.h +++ b/arch/arm/mach-omap2/control.h @@ -464,6 +464,7 @@ extern void omap_ctrl_write_dsp_boot_mode(u8 bootmode); extern void omap3630_ctrl_disable_rta(void); extern int omap3_ctrl_save_padconf(void); void omap3_ctrl_init(void); +int omap_control_init(void); extern void omap2_set_globals_control(void __iomem *ctrl, void __iomem *ctrl_pad); #else diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 460da22a005c..46640c0ddc0f 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -756,6 +756,10 @@ int __init omap_clk_init(void) ti_clk_init_features(); if (of_have_populated_dt()) { + ret = omap_control_init(); + if (ret) + return ret; + ret = omap_prcm_init(); if (ret) return ret; diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index 1bfd00e10f76..6cbebbe252c4 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -637,43 +637,22 @@ static struct omap_prcm_init_data prm_data = { .index = TI_CLKM_PRM, }; -static struct omap_prcm_init_data cm_data = { - .index = TI_CLKM_CM, -}; - -static struct omap_prcm_init_data cm2_data = { - .index = TI_CLKM_CM2, -}; - static struct omap_prcm_init_data scrm_data = { .index = TI_CLKM_SCRM, }; static const struct of_device_id omap_prcm_dt_match_table[] = { { .compatible = "ti,am3-prcm", .data = &prm_data }, - { .compatible = "ti,am3-scrm", .data = &scrm_data }, { .compatible = "ti,am4-prcm", .data = &prm_data }, - { .compatible = "ti,am4-scrm", .data = &scrm_data }, { .compatible = "ti,dm814-prcm", .data = &prm_data }, - { .compatible = "ti,dm814-scrm", .data = &scrm_data }, { .compatible = "ti,dm816-prcm", .data = &prm_data }, - { .compatible = "ti,dm816-scrm", .data = &scrm_data }, { .compatible = "ti,omap2-prcm", .data = &prm_data }, - { .compatible = "ti,omap2-scrm", .data = &scrm_data }, { .compatible = "ti,omap3-prm", .data = &prm_data }, - { .compatible = "ti,omap3-cm", .data = &cm_data }, - { .compatible = "ti,omap3-scrm", .data = &scrm_data }, - { .compatible = "ti,omap4-cm1", .data = &cm_data }, { .compatible = "ti,omap4-prm", .data = &prm_data }, - { .compatible = "ti,omap4-cm2", .data = &cm2_data }, { .compatible = "ti,omap4-scrm", .data = &scrm_data }, { .compatible = "ti,omap5-prm", .data = &prm_data }, - { .compatible = "ti,omap5-cm-core-aon", .data = &cm_data }, { .compatible = "ti,omap5-scrm", .data = &scrm_data }, - { .compatible = "ti,omap5-cm-core", .data = &cm2_data }, { .compatible = "ti,dra7-prm", .data = &prm_data }, - { .compatible = "ti,dra7-cm-core-aon", .data = &cm_data }, - { .compatible = "ti,dra7-cm-core", .data = &cm2_data }, { } }; @@ -703,6 +682,8 @@ int __init omap_prcm_init(void) return ret; } + omap_cm_init(); + return 0; } diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 19895a3f48b7..79b76e13d904 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -215,15 +215,14 @@ struct ti_dt_clk { .node_name = name, \ } -/* Maximum number of clock memmaps */ -#define CLK_MAX_MEMMAPS 4 - /* Static memmap indices */ enum { TI_CLKM_CM = 0, TI_CLKM_CM2, TI_CLKM_PRM, TI_CLKM_SCRM, + TI_CLKM_CTRL, + CLK_MAX_MEMMAPS }; typedef void (*ti_of_clk_init_cb_t)(struct clk_hw *, struct device_node *); -- cgit v1.2.3 From 772742a6c7ea4612fe043353531e6435ed33e719 Mon Sep 17 00:00:00 2001 From: "Suzuki K. Poulose" Date: Wed, 18 Mar 2015 12:24:40 +0000 Subject: arm-cci: Get rid of secure transactions for PMU driver Avoid secure transactions while probing the CCI PMU. The existing code makes use of the Peripheral ID2 (PID2) register to determine the revision of the CCI400, which requires a secure transaction. This puts a limitation on the usage of the driver on systems running non-secure Linux(e.g, ARM64). Updated the device-tree binding for cci pmu node to add the explicit revision number for the compatible field. The supported strings are : arm,cci-400-pmu,r0 arm,cci-400-pmu,r1 arm,cci-400-pmu - DEPRECATED. See NOTE below NOTE: If the revision is not mentioned, we need to probe the cci revision, which could be fatal on a platform running non-secure. We need a reliable way to know if we can poke the CCI registers at runtime on ARM32. We depend on 'mcpm_is_available()' when it is available. mcpm_is_available() returns true only when there is a registered driver for mcpm. Otherwise, we assume that we don't have secure access, and skips probing the revision number(ARM64 case). The MCPM should figure out if it is safe to access the CCI. Unfortunately there isn't a reliable way to indicate the same via dtb. This patch doesn't address/change the current situation. It only deals with the CCI-PMU, leaving the assumptions about the secure access as it has been, prior to this patch. Cc: devicetree@vger.kernel.org Cc: Punit Agrawal Tested-by: Sudeep Holla Acked-by: Nicolas Pitre Acked-by: Mark Rutland Signed-off-by: Suzuki K. Poulose Signed-off-by: Will Deacon --- Documentation/devicetree/bindings/arm/cci.txt | 7 +++-- arch/arm/include/asm/arm-cci.h | 42 +++++++++++++++++++++++++++ arch/arm64/include/asm/arm-cci.h | 27 +++++++++++++++++ drivers/bus/arm-cci.c | 17 ++++++++++- include/linux/arm-cci.h | 2 ++ 5 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 arch/arm/include/asm/arm-cci.h create mode 100644 arch/arm64/include/asm/arm-cci.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/arm/cci.txt b/Documentation/devicetree/bindings/arm/cci.txt index f28d82bbbc56..3c5c631328d3 100644 --- a/Documentation/devicetree/bindings/arm/cci.txt +++ b/Documentation/devicetree/bindings/arm/cci.txt @@ -94,8 +94,11 @@ specific to ARM. - compatible Usage: required Value type: - Definition: must be "arm,cci-400-pmu" - + Definition: Must contain one of: + "arm,cci-400-pmu,r0" + "arm,cci-400-pmu,r1" + "arm,cci-400-pmu" - DEPRECATED, permitted only where OS has + secure acces to CCI registers - reg: Usage: required Value type: Integer cells. A register entry, expressed diff --git a/arch/arm/include/asm/arm-cci.h b/arch/arm/include/asm/arm-cci.h new file mode 100644 index 000000000000..fe77f7ab7e6b --- /dev/null +++ b/arch/arm/include/asm/arm-cci.h @@ -0,0 +1,42 @@ +/* + * arch/arm/include/asm/arm-cci.h + * + * Copyright (C) 2015 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ASM_ARM_CCI_H +#define __ASM_ARM_CCI_H + +#ifdef CONFIG_MCPM +#include + +/* + * We don't have a reliable way of detecting whether, + * if we have access to secure-only registers, unless + * mcpm is registered. + */ +static inline bool platform_has_secure_cci_access(void) +{ + return mcpm_is_available(); +} + +#else +static inline bool platform_has_secure_cci_access(void) +{ + return false; +} +#endif + +#endif diff --git a/arch/arm64/include/asm/arm-cci.h b/arch/arm64/include/asm/arm-cci.h new file mode 100644 index 000000000000..f0b63712e10e --- /dev/null +++ b/arch/arm64/include/asm/arm-cci.h @@ -0,0 +1,27 @@ +/* + * arch/arm64/include/asm/arm-cci.h + * + * Copyright (C) 2015 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ASM_ARM_CCI_H +#define __ASM_ARM_CCI_H + +static inline bool platform_has_secure_cci_access(void) +{ + return false; +} + +#endif diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c index ae3864d95e6c..a23663c7a306 100644 --- a/drivers/bus/arm-cci.c +++ b/drivers/bus/arm-cci.c @@ -217,7 +217,9 @@ static int probe_cci_revision(void) static const struct cci_pmu_model *probe_cci_model(struct platform_device *pdev) { - return &cci_pmu_models[probe_cci_revision()]; + if (platform_has_secure_cci_access()) + return &cci_pmu_models[probe_cci_revision()]; + return NULL; } static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx) @@ -882,6 +884,15 @@ static struct cci_pmu_model cci_pmu_models[] = { static const struct of_device_id arm_cci_pmu_matches[] = { { .compatible = "arm,cci-400-pmu", + .data = NULL, + }, + { + .compatible = "arm,cci-400-pmu,r0", + .data = &cci_pmu_models[CCI_REV_R0], + }, + { + .compatible = "arm,cci-400-pmu,r1", + .data = &cci_pmu_models[CCI_REV_R1], }, {}, }; @@ -892,7 +903,11 @@ static inline const struct cci_pmu_model *get_cci_model(struct platform_device * pdev->dev.of_node); if (!match) return NULL; + if (match->data) + return match->data; + dev_warn(&pdev->dev, "DEPRECATED compatible property," + "requires secure access to CCI registers"); return probe_cci_model(pdev); } diff --git a/include/linux/arm-cci.h b/include/linux/arm-cci.h index 79d6edf446d5..aede5c765eec 100644 --- a/include/linux/arm-cci.h +++ b/include/linux/arm-cci.h @@ -24,6 +24,8 @@ #include #include +#include + struct device_node; #ifdef CONFIG_ARM_CCI -- cgit v1.2.3 From ee8e5d5fbec0e880b18bbdbfe12de53ab1dec21f Mon Sep 17 00:00:00 2001 From: "Suzuki K. Poulose" Date: Wed, 18 Mar 2015 12:24:41 +0000 Subject: arm-cci: Split the code for PMU vs driver support This patch separates the PMU driver code from the low level CCI driver code and enables the PMU driver for ARM64. Introduces config options for both. ARM_CCI400_PORT_CTRL - controls the low level driver code for CCI400 ports. ARM_CCI400_PMU - controls the PMU driver code ARM_CCI400_COMMON - Common defintions for CCI400 This patch also changes: ARM_CCI - common code for probing the CCI devices. This can be used for adding support for newer CCI versions(e.g, CCI-500). Cc: Bartlomiej Zolnierkiewicz Cc: Kukjin Kim Cc: Abhilash Kesavan Cc: Liviu Dudau Cc: Lorenzo Pieralisi Cc: Sudeep Holla Cc: Nicolas Pitre Cc: Punit Agrawal Acked-by: Sudeep Holla Acked-by: Nicolas Pitre Acked-by: Punit Agrawal Signed-off-by: Suzuki K. Poulose Signed-off-by: Will Deacon --- arch/arm/mach-exynos/Kconfig | 2 +- arch/arm/mach-vexpress/Kconfig | 4 ++-- drivers/bus/Kconfig | 28 ++++++++++++++++++++++++---- drivers/bus/arm-cci.c | 24 ++++++++++++++++++++---- include/linux/arm-cci.h | 7 ++++++- 5 files changed, 53 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 603820e5aba7..81064cd61a0a 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -123,7 +123,7 @@ config SOC_EXYNOS5800 config EXYNOS5420_MCPM bool "Exynos5420 Multi-Cluster PM support" depends on MCPM && SOC_EXYNOS5420 - select ARM_CCI + select ARM_CCI400_PORT_CTRL select ARM_CPU_SUSPEND help This is needed to provide CPU and cluster power management diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index 3c2509b4b694..daa7ab6cb909 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig @@ -53,7 +53,7 @@ config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA config ARCH_VEXPRESS_DCSCB bool "Dual Cluster System Control Block (DCSCB) support" depends on MCPM - select ARM_CCI + select ARM_CCI400_PORT_CTRL help Support for the Dual Cluster System Configuration Block (DCSCB). This is needed to provide CPU and cluster power management @@ -71,7 +71,7 @@ config ARCH_VEXPRESS_SPC config ARCH_VEXPRESS_TC2_PM bool "Versatile Express TC2 power management" depends on MCPM - select ARM_CCI + select ARM_CCI400_PORT_CTRL select ARCH_VEXPRESS_SPC select ARM_CPU_SUSPEND help diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index b99729e36860..79e297b1f221 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -43,12 +43,32 @@ config OMAP_INTERCONNECT help Driver to enable OMAP interconnect error handling driver. -config ARM_CCI - bool "ARM CCI driver support" +config ARM_CCI400_PORT_CTRL + bool depends on ARM && OF && CPU_V7 + select ARM_CCI400_COMMON + help + Low level power management driver for CCI400 cache coherent + interconnect for ARM platforms. + +config ARM_CCI400_PMU + bool "ARM CCI400 PMU support" + default y + depends on ARM || ARM64 + depends on HW_PERF_EVENTS + select ARM_CCI400_COMMON help - Driver supporting the CCI cache coherent interconnect for ARM - platforms. + Support for PMU events monitoring on the ARM CCI cache coherent + interconnect. + + If unsure, say Y + +config ARM_CCI400_COMMON + bool + select ARM_CCI + +config ARM_CCI + bool config ARM_CCN bool "ARM CCN driver support" diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c index a23663c7a306..054df84562c2 100644 --- a/drivers/bus/arm-cci.c +++ b/drivers/bus/arm-cci.c @@ -32,6 +32,7 @@ static void __iomem *cci_ctrl_base; static unsigned long cci_ctrl_phys; +#ifdef CONFIG_ARM_CCI400_PORT_CTRL struct cci_nb_ports { unsigned int nb_ace; unsigned int nb_ace_lite; @@ -42,12 +43,19 @@ static const struct cci_nb_ports cci400_ports = { .nb_ace_lite = 3 }; +#define CCI400_PORTS_DATA (&cci400_ports) +#else +#define CCI400_PORTS_DATA (NULL) +#endif + static const struct of_device_id arm_cci_matches[] = { - {.compatible = "arm,cci-400", .data = &cci400_ports }, +#ifdef CONFIG_ARM_CCI400_COMMON + {.compatible = "arm,cci-400", .data = CCI400_PORTS_DATA }, +#endif {}, }; -#ifdef CONFIG_HW_PERF_EVENTS +#ifdef CONFIG_ARM_CCI400_PMU #define DRIVER_NAME "CCI-400" #define DRIVER_NAME_PMU DRIVER_NAME " PMU" @@ -1022,14 +1030,16 @@ static int __init cci_platform_init(void) return platform_driver_register(&cci_platform_driver); } -#else /* !CONFIG_HW_PERF_EVENTS */ +#else /* !CONFIG_ARM_CCI400_PMU */ static int __init cci_platform_init(void) { return 0; } -#endif /* CONFIG_HW_PERF_EVENTS */ +#endif /* CONFIG_ARM_CCI400_PMU */ + +#ifdef CONFIG_ARM_CCI400_PORT_CTRL #define CCI_PORT_CTRL 0x0 #define CCI_CTRL_STATUS 0xc @@ -1460,6 +1470,12 @@ static int cci_probe_ports(struct device_node *np) return 0; } +#else /* !CONFIG_ARM_CCI400_PORT_CTRL */ +static inline int cci_probe_ports(struct device_node *np) +{ + return 0; +} +#endif /* CONFIG_ARM_CCI400_PORT_CTRL */ static int cci_probe(void) { diff --git a/include/linux/arm-cci.h b/include/linux/arm-cci.h index aede5c765eec..521ec1f2e6bc 100644 --- a/include/linux/arm-cci.h +++ b/include/linux/arm-cci.h @@ -30,12 +30,16 @@ struct device_node; #ifdef CONFIG_ARM_CCI extern bool cci_probed(void); +#else +static inline bool cci_probed(void) { return false; } +#endif + +#ifdef CONFIG_ARM_CCI400_PORT_CTRL extern int cci_ace_get_port(struct device_node *dn); extern int cci_disable_port_by_cpu(u64 mpidr); extern int __cci_control_port_by_device(struct device_node *dn, bool enable); extern int __cci_control_port_by_index(u32 port, bool enable); #else -static inline bool cci_probed(void) { return false; } static inline int cci_ace_get_port(struct device_node *dn) { return -ENODEV; @@ -51,6 +55,7 @@ static inline int __cci_control_port_by_index(u32 port, bool enable) return -ENODEV; } #endif + #define cci_disable_port_by_device(dev) \ __cci_control_port_by_device(dev, false) #define cci_enable_port_by_device(dev) \ -- cgit v1.2.3 From 9c7d3d3e289c9870ae688780a0f9807bb5ae9faf Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 27 Mar 2015 15:51:55 +0200 Subject: drm: Fix DRM_IOCTL_DEF_DRV() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently DRM_IOCTL_DEF_DRV does '[DRM_IOCTL_NR(DRM_##ioctl)]' which doesn't make much sense since DRM_##ioctl is already a the raw ioctl number. So change it to 'DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE' which means the DRM_IOCTL_NR() now makes sense, and also this also means if there's a mistake in the DRM_IOCTL_##ioctl macros we might get a warning about it (eg. we would have gotten a sparse warning about the i915 colorkey get/set ioctl being defined to be the same thing). Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- include/drm/drmP.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 63c0b0131f61..6195ee9b4c2a 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -263,7 +263,7 @@ struct drm_ioctl_desc { */ #define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ - [DRM_IOCTL_NR(DRM_##ioctl)] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl, .name = #ioctl} + [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl, .name = #ioctl} /* Event queued up for userspace to read */ struct drm_pending_event { -- cgit v1.2.3 From 7e7392a6e854a29016377b87bebe5ae263f65e5c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 27 Mar 2015 15:51:56 +0200 Subject: drm: Drop ioctl->cmd_drv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ioctl->cmd_drv is pointless and we can just as well stick the full ioctl definition into ioctl->cmd. Cc: Jakob Bornecrantz Cc: Thomas Hellstrom Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_ioctl.c | 6 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 4 ++-- include/drm/drmP.h | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index a6d773a61c2d..fc0cf4a84011 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -525,7 +525,7 @@ static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv) } #define DRM_IOCTL_DEF(ioctl, _func, _flags) \ - [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0, .name = #ioctl} + [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .name = #ioctl} /** Ioctl table */ static const struct drm_ioctl_desc drm_ioctls[] = { @@ -677,11 +677,11 @@ long drm_ioctl(struct file *filp, (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) { u32 drv_size; ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; - drv_size = _IOC_SIZE(ioctl->cmd_drv); + drv_size = _IOC_SIZE(ioctl->cmd); usize = asize = _IOC_SIZE(cmd); if (drv_size > asize) asize = drv_size; - cmd = ioctl->cmd_drv; + cmd = ioctl->cmd; } else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) { u32 drv_size; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 6c6b655defcf..761b2a767ce0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -134,7 +134,7 @@ */ #define VMW_IOCTL_DEF(ioctl, func, flags) \ - [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {DRM_##ioctl, flags, func, DRM_IOCTL_##ioctl} + [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {DRM_IOCTL_##ioctl, flags, func} /** * Ioctl definitions. @@ -1041,7 +1041,7 @@ static long vmw_generic_ioctl(struct file *filp, unsigned int cmd, const struct drm_ioctl_desc *ioctl = &vmw_ioctls[nr - DRM_COMMAND_BASE]; - if (unlikely(ioctl->cmd_drv != cmd)) { + if (unlikely(ioctl->cmd != cmd)) { DRM_ERROR("Invalid command format, ioctl %d\n", nr - DRM_COMMAND_BASE); return -EINVAL; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 6195ee9b4c2a..0d501ed20775 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -253,7 +253,6 @@ struct drm_ioctl_desc { unsigned int cmd; int flags; drm_ioctl_t *func; - unsigned int cmd_drv; const char *name; }; @@ -263,7 +262,7 @@ struct drm_ioctl_desc { */ #define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ - [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl, .name = #ioctl} + [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {.cmd = DRM_IOCTL_##ioctl, .func = _func, .flags = _flags, .name = #ioctl} /* Event queued up for userspace to read */ struct drm_pending_event { -- cgit v1.2.3 From 27842bb18b004a2802f4b3221c79ce638c4bf6ee Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 13 Mar 2015 11:09:39 -0700 Subject: mmc: Remove msm_sdcc driver This driver is orphaned now that mach-msm has been removed. Delete it. Cc: Chris Ball Cc: David Brown Cc: Bryan Huntsman Cc: Daniel Walker Signed-off-by: Stephen Boyd Acked-by: Ulf Hansson Signed-off-by: Kumar Gala --- drivers/mmc/host/Kconfig | 8 - drivers/mmc/host/Makefile | 1 - drivers/mmc/host/msm_sdcc.c | 1474 ---------------------------- drivers/mmc/host/msm_sdcc.h | 256 ----- include/linux/platform_data/mmc-msm_sdcc.h | 27 - 5 files changed, 1766 deletions(-) delete mode 100644 drivers/mmc/host/msm_sdcc.c delete mode 100644 drivers/mmc/host/msm_sdcc.h delete mode 100644 include/linux/platform_data/mmc-msm_sdcc.h (limited to 'include') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 61ac63a3776a..37d1d80fdf04 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -393,14 +393,6 @@ config MMC_SDHCI_MSM If unsure, say N. -config MMC_MSM - tristate "Qualcomm SDCC Controller Support" - depends on MMC && (ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50) - help - This provides support for the SD/MMC cell found in the - MSM and QSD SOCs from Qualcomm. The controller also has - support for SDIO devices. - config MMC_MXC tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support" depends on ARCH_MXC || PPC_MPC512x diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 6a7cfe0de332..47f9421d0281 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -24,7 +24,6 @@ obj-$(CONFIG_MMC_OMAP) += omap.o obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o -obj-$(CONFIG_MMC_MSM) += msm_sdcc.o obj-$(CONFIG_MMC_MVSDIO) += mvsdio.o obj-$(CONFIG_MMC_DAVINCI) += davinci_mmc.o obj-$(CONFIG_MMC_GOLDFISH) += android-goldfish.o diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c deleted file mode 100644 index 90c60fd4ff6e..000000000000 --- a/drivers/mmc/host/msm_sdcc.c +++ /dev/null @@ -1,1474 +0,0 @@ -/* - * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver - * - * Copyright (C) 2007 Google Inc, - * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - * Copyright (C) 2009, Code Aurora Forum. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Based on mmci.c - * - * Author: San Mehat (san@android.com) - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "msm_sdcc.h" - -#define DRIVER_NAME "msm-sdcc" - -#define BUSCLK_PWRSAVE 1 -#define BUSCLK_TIMEOUT (HZ) -static unsigned int msmsdcc_fmin = 144000; -static unsigned int msmsdcc_fmax = 50000000; -static unsigned int msmsdcc_4bit = 1; -static unsigned int msmsdcc_pwrsave = 1; -static unsigned int msmsdcc_piopoll = 1; -static unsigned int msmsdcc_sdioirq; - -#define PIO_SPINMAX 30 -#define CMD_SPINMAX 20 - - -static inline void -msmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr) -{ - WARN_ON(!host->clks_on); - - BUG_ON(host->curr.mrq); - - if (deferr) { - mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); - } else { - del_timer_sync(&host->busclk_timer); - /* Need to check clks_on again in case the busclk - * timer fired - */ - if (host->clks_on) { - clk_disable(host->clk); - clk_disable(host->pclk); - host->clks_on = 0; - } - } -} - -static inline int -msmsdcc_enable_clocks(struct msmsdcc_host *host) -{ - int rc; - - del_timer_sync(&host->busclk_timer); - - if (!host->clks_on) { - rc = clk_enable(host->pclk); - if (rc) - return rc; - rc = clk_enable(host->clk); - if (rc) { - clk_disable(host->pclk); - return rc; - } - udelay(1 + ((3 * USEC_PER_SEC) / - (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); - host->clks_on = 1; - } - return 0; -} - -static inline unsigned int -msmsdcc_readl(struct msmsdcc_host *host, unsigned int reg) -{ - return readl(host->base + reg); -} - -static inline void -msmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg) -{ - writel(data, host->base + reg); - /* 3 clk delay required! */ - udelay(1 + ((3 * USEC_PER_SEC) / - (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); -} - -static void -msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, - u32 c); - -static void msmsdcc_reset_and_restore(struct msmsdcc_host *host) -{ - u32 mci_clk = 0; - u32 mci_mask0 = 0; - int ret = 0; - - /* Save the controller state */ - mci_clk = readl(host->base + MMCICLOCK); - mci_mask0 = readl(host->base + MMCIMASK0); - - /* Reset the controller */ - ret = clk_reset(host->clk, CLK_RESET_ASSERT); - if (ret) - pr_err("%s: Clock assert failed at %u Hz with err %d\n", - mmc_hostname(host->mmc), host->clk_rate, ret); - - ret = clk_reset(host->clk, CLK_RESET_DEASSERT); - if (ret) - pr_err("%s: Clock deassert failed at %u Hz with err %d\n", - mmc_hostname(host->mmc), host->clk_rate, ret); - - pr_info("%s: Controller has been re-initialiazed\n", - mmc_hostname(host->mmc)); - - /* Restore the contoller state */ - writel(host->pwr, host->base + MMCIPOWER); - writel(mci_clk, host->base + MMCICLOCK); - writel(mci_mask0, host->base + MMCIMASK0); - ret = clk_set_rate(host->clk, host->clk_rate); - if (ret) - pr_err("%s: Failed to set clk rate %u Hz (%d)\n", - mmc_hostname(host->mmc), host->clk_rate, ret); -} - -static void -msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) -{ - BUG_ON(host->curr.data); - - host->curr.mrq = NULL; - host->curr.cmd = NULL; - - if (mrq->data) - mrq->data->bytes_xfered = host->curr.data_xfered; - if (mrq->cmd->error == -ETIMEDOUT) - mdelay(5); - -#if BUSCLK_PWRSAVE - msmsdcc_disable_clocks(host, 1); -#endif - /* - * Need to drop the host lock here; mmc_request_done may call - * back into the driver... - */ - spin_unlock(&host->lock); - mmc_request_done(host->mmc, mrq); - spin_lock(&host->lock); -} - -static void -msmsdcc_stop_data(struct msmsdcc_host *host) -{ - host->curr.data = NULL; - host->curr.got_dataend = 0; -} - -uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host) -{ - return host->memres->start + MMCIFIFO; -} - -static inline void -msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) { - msmsdcc_writel(host, arg, MMCIARGUMENT); - msmsdcc_writel(host, c, MMCICOMMAND); -} - -static void -msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) -{ - struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data; - - msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER); - msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, - MMCIDATALENGTH); - msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & - (~MCI_IRQ_PIO)) | host->cmd_pio_irqmask, MMCIMASK0); - msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL); - - if (host->cmd_cmd) { - msmsdcc_start_command_exec(host, - (u32) host->cmd_cmd->arg, - (u32) host->cmd_c); - } - host->dma.active = 1; -} - -static void -msmsdcc_dma_complete_tlet(unsigned long data) -{ - struct msmsdcc_host *host = (struct msmsdcc_host *)data; - unsigned long flags; - struct mmc_request *mrq; - struct msm_dmov_errdata err; - - spin_lock_irqsave(&host->lock, flags); - host->dma.active = 0; - - err = host->dma.err; - mrq = host->curr.mrq; - BUG_ON(!mrq); - WARN_ON(!mrq->data); - - if (!(host->dma.result & DMOV_RSLT_VALID)) { - pr_err("msmsdcc: Invalid DataMover result\n"); - goto out; - } - - if (host->dma.result & DMOV_RSLT_DONE) { - host->curr.data_xfered = host->curr.xfer_size; - } else { - /* Error or flush */ - if (host->dma.result & DMOV_RSLT_ERROR) - pr_err("%s: DMA error (0x%.8x)\n", - mmc_hostname(host->mmc), host->dma.result); - if (host->dma.result & DMOV_RSLT_FLUSH) - pr_err("%s: DMA channel flushed (0x%.8x)\n", - mmc_hostname(host->mmc), host->dma.result); - - pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n", - err.flush[0], err.flush[1], err.flush[2], - err.flush[3], err.flush[4], err.flush[5]); - - msmsdcc_reset_and_restore(host); - if (!mrq->data->error) - mrq->data->error = -EIO; - } - dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, - host->dma.dir); - - host->dma.sg = NULL; - host->dma.busy = 0; - - if (host->curr.got_dataend || mrq->data->error) { - - /* - * If we've already gotten our DATAEND / DATABLKEND - * for this request, then complete it through here. - */ - msmsdcc_stop_data(host); - - if (!mrq->data->error) - host->curr.data_xfered = host->curr.xfer_size; - if (!mrq->data->stop || mrq->cmd->error) { - host->curr.mrq = NULL; - host->curr.cmd = NULL; - mrq->data->bytes_xfered = host->curr.data_xfered; - - spin_unlock_irqrestore(&host->lock, flags); -#if BUSCLK_PWRSAVE - msmsdcc_disable_clocks(host, 1); -#endif - mmc_request_done(host->mmc, mrq); - return; - } else - msmsdcc_start_command(host, mrq->data->stop, 0); - } - -out: - spin_unlock_irqrestore(&host->lock, flags); - return; -} - -static void -msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, - unsigned int result, - struct msm_dmov_errdata *err) -{ - struct msmsdcc_dma_data *dma_data = - container_of(cmd, struct msmsdcc_dma_data, hdr); - struct msmsdcc_host *host = dma_data->host; - - dma_data->result = result; - if (err) - memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata)); - - tasklet_schedule(&host->dma_tlet); -} - -static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data) -{ - if (host->dma.channel == -1) - return -ENOENT; - - if ((data->blksz * data->blocks) < MCI_FIFOSIZE) - return -EINVAL; - if ((data->blksz * data->blocks) % MCI_FIFOSIZE) - return -EINVAL; - return 0; -} - -static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) -{ - struct msmsdcc_nc_dmadata *nc; - dmov_box *box; - uint32_t rows; - uint32_t crci; - unsigned int n; - int i, rc; - struct scatterlist *sg = data->sg; - - rc = validate_dma(host, data); - if (rc) - return rc; - - host->dma.sg = data->sg; - host->dma.num_ents = data->sg_len; - - BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */ - - nc = host->dma.nc; - - switch (host->pdev_id) { - case 1: - crci = MSMSDCC_CRCI_SDC1; - break; - case 2: - crci = MSMSDCC_CRCI_SDC2; - break; - case 3: - crci = MSMSDCC_CRCI_SDC3; - break; - case 4: - crci = MSMSDCC_CRCI_SDC4; - break; - default: - host->dma.sg = NULL; - host->dma.num_ents = 0; - return -ENOENT; - } - - if (data->flags & MMC_DATA_READ) - host->dma.dir = DMA_FROM_DEVICE; - else - host->dma.dir = DMA_TO_DEVICE; - - host->curr.user_pages = 0; - - box = &nc->cmd[0]; - - /* location of command block must be 64 bit aligned */ - BUG_ON(host->dma.cmd_busaddr & 0x07); - - nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP; - host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | - DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); - host->dma.hdr.complete_func = msmsdcc_dma_complete_func; - - n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, - host->dma.num_ents, host->dma.dir); - if (n == 0) { - pr_err("%s: Unable to map in all sg elements\n", - mmc_hostname(host->mmc)); - host->dma.sg = NULL; - host->dma.num_ents = 0; - return -ENOMEM; - } - - for_each_sg(host->dma.sg, sg, n, i) { - - box->cmd = CMD_MODE_BOX; - - if (i == n - 1) - box->cmd |= CMD_LC; - rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? - (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : - (sg_dma_len(sg) / MCI_FIFOSIZE) ; - - if (data->flags & MMC_DATA_READ) { - box->src_row_addr = msmsdcc_fifo_addr(host); - box->dst_row_addr = sg_dma_address(sg); - - box->src_dst_len = (MCI_FIFOSIZE << 16) | - (MCI_FIFOSIZE); - box->row_offset = MCI_FIFOSIZE; - - box->num_rows = rows * ((1 << 16) + 1); - box->cmd |= CMD_SRC_CRCI(crci); - } else { - box->src_row_addr = sg_dma_address(sg); - box->dst_row_addr = msmsdcc_fifo_addr(host); - - box->src_dst_len = (MCI_FIFOSIZE << 16) | - (MCI_FIFOSIZE); - box->row_offset = (MCI_FIFOSIZE << 16); - - box->num_rows = rows * ((1 << 16) + 1); - box->cmd |= CMD_DST_CRCI(crci); - } - box++; - } - - return 0; -} - -static int -snoop_cccr_abort(struct mmc_command *cmd) -{ - if ((cmd->opcode == 52) && - (cmd->arg & 0x80000000) && - (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) - return 1; - return 0; -} - -static void -msmsdcc_start_command_deferred(struct msmsdcc_host *host, - struct mmc_command *cmd, u32 *c) -{ - *c |= (cmd->opcode | MCI_CPSM_ENABLE); - - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) - *c |= MCI_CPSM_LONGRSP; - *c |= MCI_CPSM_RESPONSE; - } - - if (/*interrupt*/0) - *c |= MCI_CPSM_INTERRUPT; - - if ((((cmd->opcode == 17) || (cmd->opcode == 18)) || - ((cmd->opcode == 24) || (cmd->opcode == 25))) || - (cmd->opcode == 53)) - *c |= MCI_CSPM_DATCMD; - - if (host->prog_scan && (cmd->opcode == 12)) { - *c |= MCI_CPSM_PROGENA; - host->prog_enable = true; - } - - if (cmd == cmd->mrq->stop) - *c |= MCI_CSPM_MCIABORT; - - if (snoop_cccr_abort(cmd)) - *c |= MCI_CSPM_MCIABORT; - - if (host->curr.cmd != NULL) { - pr_err("%s: Overlapping command requests\n", - mmc_hostname(host->mmc)); - } - host->curr.cmd = cmd; -} - -static void -msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, - struct mmc_command *cmd, u32 c) -{ - unsigned int datactrl, timeout; - unsigned long long clks; - unsigned int pio_irqmask = 0; - - host->curr.data = data; - host->curr.xfer_size = data->blksz * data->blocks; - host->curr.xfer_remain = host->curr.xfer_size; - host->curr.data_xfered = 0; - host->curr.got_dataend = 0; - - memset(&host->pio, 0, sizeof(host->pio)); - - datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); - - if (!msmsdcc_config_dma(host, data)) - datactrl |= MCI_DPSM_DMAENABLE; - else { - host->pio.sg = data->sg; - host->pio.sg_len = data->sg_len; - host->pio.sg_off = 0; - - if (data->flags & MMC_DATA_READ) { - pio_irqmask = MCI_RXFIFOHALFFULLMASK; - if (host->curr.xfer_remain < MCI_FIFOSIZE) - pio_irqmask |= MCI_RXDATAAVLBLMASK; - } else - pio_irqmask = MCI_TXFIFOHALFEMPTYMASK; - } - - if (data->flags & MMC_DATA_READ) - datactrl |= MCI_DPSM_DIRECTION; - - clks = (unsigned long long)data->timeout_ns * host->clk_rate; - do_div(clks, NSEC_PER_SEC); - timeout = data->timeout_clks + (unsigned int)clks*2 ; - - if (datactrl & MCI_DPSM_DMAENABLE) { - /* Save parameters for the exec function */ - host->cmd_timeout = timeout; - host->cmd_pio_irqmask = pio_irqmask; - host->cmd_datactrl = datactrl; - host->cmd_cmd = cmd; - - host->dma.hdr.execute_func = msmsdcc_dma_exec_func; - host->dma.hdr.data = (void *)host; - host->dma.busy = 1; - - if (cmd) { - msmsdcc_start_command_deferred(host, cmd, &c); - host->cmd_c = c; - } - msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); - if (data->flags & MMC_DATA_WRITE) - host->prog_scan = true; - } else { - msmsdcc_writel(host, timeout, MMCIDATATIMER); - - msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); - - msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & - (~MCI_IRQ_PIO)) | pio_irqmask, MMCIMASK0); - - msmsdcc_writel(host, datactrl, MMCIDATACTRL); - - if (cmd) { - /* Daisy-chain the command if requested */ - msmsdcc_start_command(host, cmd, c); - } - } -} - -static void -msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) -{ - if (cmd == cmd->mrq->stop) - c |= MCI_CSPM_MCIABORT; - - host->stats.cmds++; - - msmsdcc_start_command_deferred(host, cmd, &c); - msmsdcc_start_command_exec(host, cmd->arg, c); -} - -static void -msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data, - unsigned int status) -{ - if (status & MCI_DATACRCFAIL) { - pr_err("%s: Data CRC error\n", mmc_hostname(host->mmc)); - pr_err("%s: opcode 0x%.8x\n", __func__, - data->mrq->cmd->opcode); - pr_err("%s: blksz %d, blocks %d\n", __func__, - data->blksz, data->blocks); - data->error = -EILSEQ; - } else if (status & MCI_DATATIMEOUT) { - pr_err("%s: Data timeout\n", mmc_hostname(host->mmc)); - data->error = -ETIMEDOUT; - } else if (status & MCI_RXOVERRUN) { - pr_err("%s: RX overrun\n", mmc_hostname(host->mmc)); - data->error = -EIO; - } else if (status & MCI_TXUNDERRUN) { - pr_err("%s: TX underrun\n", mmc_hostname(host->mmc)); - data->error = -EIO; - } else { - pr_err("%s: Unknown error (0x%.8x)\n", - mmc_hostname(host->mmc), status); - data->error = -EIO; - } -} - - -static int -msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) -{ - uint32_t *ptr = (uint32_t *) buffer; - int count = 0; - - if (remain % 4) - remain = ((remain >> 2) + 1) << 2; - - while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) { - *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE)); - ptr++; - count += sizeof(uint32_t); - - remain -= sizeof(uint32_t); - if (remain == 0) - break; - } - return count; -} - -static int -msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer, - unsigned int remain, u32 status) -{ - void __iomem *base = host->base; - char *ptr = buffer; - - do { - unsigned int count, maxcnt, sz; - - maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : - MCI_FIFOHALFSIZE; - count = min(remain, maxcnt); - - sz = count % 4 ? (count >> 2) + 1 : (count >> 2); - writesl(base + MMCIFIFO, ptr, sz); - ptr += count; - remain -= count; - - if (remain == 0) - break; - - status = msmsdcc_readl(host, MMCISTATUS); - } while (status & MCI_TXFIFOHALFEMPTY); - - return ptr - buffer; -} - -static int -msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) -{ - while (maxspin) { - if ((msmsdcc_readl(host, MMCISTATUS) & mask)) - return 0; - udelay(1); - --maxspin; - } - return -ETIMEDOUT; -} - -static irqreturn_t -msmsdcc_pio_irq(int irq, void *dev_id) -{ - struct msmsdcc_host *host = dev_id; - uint32_t status; - u32 mci_mask0; - - status = msmsdcc_readl(host, MMCISTATUS); - mci_mask0 = msmsdcc_readl(host, MMCIMASK0); - - if (((mci_mask0 & status) & MCI_IRQ_PIO) == 0) - return IRQ_NONE; - - do { - unsigned long flags; - unsigned int remain, len; - char *buffer; - - if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) { - if (host->curr.xfer_remain == 0 || !msmsdcc_piopoll) - break; - - if (msmsdcc_spin_on_status(host, - (MCI_TXFIFOHALFEMPTY | - MCI_RXDATAAVLBL), - PIO_SPINMAX)) { - break; - } - } - - /* Map the current scatter buffer */ - local_irq_save(flags); - buffer = kmap_atomic(sg_page(host->pio.sg)) - + host->pio.sg->offset; - buffer += host->pio.sg_off; - remain = host->pio.sg->length - host->pio.sg_off; - len = 0; - if (status & MCI_RXACTIVE) - len = msmsdcc_pio_read(host, buffer, remain); - if (status & MCI_TXACTIVE) - len = msmsdcc_pio_write(host, buffer, remain, status); - - /* Unmap the buffer */ - kunmap_atomic(buffer); - local_irq_restore(flags); - - host->pio.sg_off += len; - host->curr.xfer_remain -= len; - host->curr.data_xfered += len; - remain -= len; - - if (remain == 0) { - /* This sg page is full - do some housekeeping */ - if (status & MCI_RXACTIVE && host->curr.user_pages) - flush_dcache_page(sg_page(host->pio.sg)); - - if (!--host->pio.sg_len) { - memset(&host->pio, 0, sizeof(host->pio)); - break; - } - - /* Advance to next sg */ - host->pio.sg++; - host->pio.sg_off = 0; - } - - status = msmsdcc_readl(host, MMCISTATUS); - } while (1); - - if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) - msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | - MCI_RXDATAAVLBLMASK, MMCIMASK0); - - if (!host->curr.xfer_remain) - msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | 0, - MMCIMASK0); - - return IRQ_HANDLED; -} - -static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) -{ - struct mmc_command *cmd = host->curr.cmd; - - host->curr.cmd = NULL; - cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0); - cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1); - cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2); - cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3); - - if (status & MCI_CMDTIMEOUT) { - cmd->error = -ETIMEDOUT; - } else if (status & MCI_CMDCRCFAIL && - cmd->flags & MMC_RSP_CRC) { - pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc)); - cmd->error = -EILSEQ; - } - - if (!cmd->data || cmd->error) { - if (host->curr.data && host->dma.sg) - msm_dmov_stop_cmd(host->dma.channel, - &host->dma.hdr, 0); - else if (host->curr.data) { /* Non DMA */ - msmsdcc_reset_and_restore(host); - msmsdcc_stop_data(host); - msmsdcc_request_end(host, cmd->mrq); - } else { /* host->data == NULL */ - if (!cmd->error && host->prog_enable) { - if (status & MCI_PROGDONE) { - host->prog_scan = false; - host->prog_enable = false; - msmsdcc_request_end(host, cmd->mrq); - } else { - host->curr.cmd = cmd; - } - } else { - if (host->prog_enable) { - host->prog_scan = false; - host->prog_enable = false; - } - msmsdcc_request_end(host, cmd->mrq); - } - } - } else if (cmd->data) - if (!(cmd->data->flags & MMC_DATA_READ)) - msmsdcc_start_data(host, cmd->data, - NULL, 0); -} - -static void -msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, - void __iomem *base) -{ - struct mmc_data *data = host->curr.data; - - if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | - MCI_CMDTIMEOUT | MCI_PROGDONE) && host->curr.cmd) { - msmsdcc_do_cmdirq(host, status); - } - - if (!data) - return; - - /* Check for data errors */ - if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT | - MCI_TXUNDERRUN | MCI_RXOVERRUN)) { - msmsdcc_data_err(host, data, status); - host->curr.data_xfered = 0; - if (host->dma.sg) - msm_dmov_stop_cmd(host->dma.channel, - &host->dma.hdr, 0); - else { - msmsdcc_reset_and_restore(host); - if (host->curr.data) - msmsdcc_stop_data(host); - if (!data->stop) - msmsdcc_request_end(host, data->mrq); - else - msmsdcc_start_command(host, data->stop, 0); - } - } - - /* Check for data done */ - if (!host->curr.got_dataend && (status & MCI_DATAEND)) - host->curr.got_dataend = 1; - - /* - * If DMA is still in progress, we complete via the completion handler - */ - if (host->curr.got_dataend && !host->dma.busy) { - /* - * There appears to be an issue in the controller where - * if you request a small block transfer (< fifo size), - * you may get your DATAEND/DATABLKEND irq without the - * PIO data irq. - * - * Check to see if there is still data to be read, - * and simulate a PIO irq. - */ - if (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) - msmsdcc_pio_irq(1, host); - - msmsdcc_stop_data(host); - if (!data->error) - host->curr.data_xfered = host->curr.xfer_size; - - if (!data->stop) - msmsdcc_request_end(host, data->mrq); - else - msmsdcc_start_command(host, data->stop, 0); - } -} - -static irqreturn_t -msmsdcc_irq(int irq, void *dev_id) -{ - struct msmsdcc_host *host = dev_id; - void __iomem *base = host->base; - u32 status; - int ret = 0; - int cardint = 0; - - spin_lock(&host->lock); - - do { - status = msmsdcc_readl(host, MMCISTATUS); - status &= msmsdcc_readl(host, MMCIMASK0); - if ((status & (~MCI_IRQ_PIO)) == 0) - break; - msmsdcc_writel(host, status, MMCICLEAR); - - if (status & MCI_SDIOINTR) - status &= ~MCI_SDIOINTR; - - if (!status) - break; - - msmsdcc_handle_irq_data(host, status, base); - - if (status & MCI_SDIOINTOPER) { - cardint = 1; - status &= ~MCI_SDIOINTOPER; - } - ret = 1; - } while (status); - - spin_unlock(&host->lock); - - /* - * We have to delay handling the card interrupt as it calls - * back into the driver. - */ - if (cardint) - mmc_signal_sdio_irq(host->mmc); - - return IRQ_RETVAL(ret); -} - -static void -msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct msmsdcc_host *host = mmc_priv(mmc); - unsigned long flags; - - WARN_ON(host->curr.mrq != NULL); - WARN_ON(host->pwr == 0); - - spin_lock_irqsave(&host->lock, flags); - - host->stats.reqs++; - - if (host->eject) { - if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) { - mrq->cmd->error = 0; - mrq->data->bytes_xfered = mrq->data->blksz * - mrq->data->blocks; - } else - mrq->cmd->error = -ENOMEDIUM; - - spin_unlock_irqrestore(&host->lock, flags); - mmc_request_done(mmc, mrq); - return; - } - - msmsdcc_enable_clocks(host); - - host->curr.mrq = mrq; - - if (mrq->data && mrq->data->flags & MMC_DATA_READ) - /* Queue/read data, daisy-chain command when data starts */ - msmsdcc_start_data(host, mrq->data, mrq->cmd, 0); - else - msmsdcc_start_command(host, mrq->cmd, 0); - - if (host->cmdpoll && !msmsdcc_spin_on_status(host, - MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, - CMD_SPINMAX)) { - uint32_t status = msmsdcc_readl(host, MMCISTATUS); - msmsdcc_do_cmdirq(host, status); - msmsdcc_writel(host, - MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, - MMCICLEAR); - host->stats.cmdpoll_hits++; - } else { - host->stats.cmdpoll_misses++; - } - spin_unlock_irqrestore(&host->lock, flags); -} - -static void msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable) -{ - struct msm_mmc_gpio_data *curr; - int i, rc = 0; - - if (!host->plat->gpio_data || host->gpio_config_status == enable) - return; - - curr = host->plat->gpio_data; - for (i = 0; i < curr->size; i++) { - if (enable) { - rc = gpio_request(curr->gpio[i].no, - curr->gpio[i].name); - if (rc) { - pr_err("%s: gpio_request(%d, %s) failed %d\n", - mmc_hostname(host->mmc), - curr->gpio[i].no, - curr->gpio[i].name, rc); - goto free_gpios; - } - } else { - gpio_free(curr->gpio[i].no); - } - } - host->gpio_config_status = enable; - return; - -free_gpios: - for (; i >= 0; i--) - gpio_free(curr->gpio[i].no); -} - -static void -msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct msmsdcc_host *host = mmc_priv(mmc); - u32 clk = 0, pwr = 0; - int rc; - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - - msmsdcc_enable_clocks(host); - - spin_unlock_irqrestore(&host->lock, flags); - - if (ios->clock) { - if (ios->clock != host->clk_rate) { - rc = clk_set_rate(host->clk, ios->clock); - if (rc < 0) - pr_err("%s: Error setting clock rate (%d)\n", - mmc_hostname(host->mmc), rc); - else - host->clk_rate = ios->clock; - } - clk |= MCI_CLK_ENABLE; - } - - if (ios->bus_width == MMC_BUS_WIDTH_4) - clk |= (2 << 10); /* Set WIDEBUS */ - - if (ios->clock > 400000 && msmsdcc_pwrsave) - clk |= (1 << 9); /* PWRSAVE */ - - clk |= (1 << 12); /* FLOW_ENA */ - clk |= (1 << 15); /* feedback clock */ - - if (host->plat->translate_vdd) - pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); - - switch (ios->power_mode) { - case MMC_POWER_OFF: - msmsdcc_setup_gpio(host, false); - break; - case MMC_POWER_UP: - pwr |= MCI_PWR_UP; - msmsdcc_setup_gpio(host, true); - break; - case MMC_POWER_ON: - pwr |= MCI_PWR_ON; - break; - } - - if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) - pwr |= MCI_OD; - - msmsdcc_writel(host, clk, MMCICLOCK); - - if (host->pwr != pwr) { - host->pwr = pwr; - msmsdcc_writel(host, pwr, MMCIPOWER); - } -#if BUSCLK_PWRSAVE - spin_lock_irqsave(&host->lock, flags); - msmsdcc_disable_clocks(host, 1); - spin_unlock_irqrestore(&host->lock, flags); -#endif -} - -static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct msmsdcc_host *host = mmc_priv(mmc); - unsigned long flags; - u32 status; - - spin_lock_irqsave(&host->lock, flags); - if (msmsdcc_sdioirq == 1) { - status = msmsdcc_readl(host, MMCIMASK0); - if (enable) - status |= MCI_SDIOINTOPERMASK; - else - status &= ~MCI_SDIOINTOPERMASK; - host->saved_irq0mask = status; - msmsdcc_writel(host, status, MMCIMASK0); - } - spin_unlock_irqrestore(&host->lock, flags); -} - -static void msmsdcc_init_card(struct mmc_host *mmc, struct mmc_card *card) -{ - struct msmsdcc_host *host = mmc_priv(mmc); - - if (host->plat->init_card) - host->plat->init_card(card); -} - -static const struct mmc_host_ops msmsdcc_ops = { - .request = msmsdcc_request, - .set_ios = msmsdcc_set_ios, - .enable_sdio_irq = msmsdcc_enable_sdio_irq, - .init_card = msmsdcc_init_card, -}; - -static void -msmsdcc_check_status(unsigned long data) -{ - struct msmsdcc_host *host = (struct msmsdcc_host *)data; - unsigned int status; - - if (!host->plat->status) { - mmc_detect_change(host->mmc, 0); - goto out; - } - - status = host->plat->status(mmc_dev(host->mmc)); - host->eject = !status; - if (status ^ host->oldstat) { - pr_info("%s: Slot status change detected (%d -> %d)\n", - mmc_hostname(host->mmc), host->oldstat, status); - if (status) - mmc_detect_change(host->mmc, (5 * HZ) / 2); - else - mmc_detect_change(host->mmc, 0); - } - - host->oldstat = status; - -out: - if (host->timer.function) - mod_timer(&host->timer, jiffies + HZ); -} - -static irqreturn_t -msmsdcc_platform_status_irq(int irq, void *dev_id) -{ - struct msmsdcc_host *host = dev_id; - - pr_debug("%s: %d\n", __func__, irq); - msmsdcc_check_status((unsigned long) host); - return IRQ_HANDLED; -} - -static void -msmsdcc_status_notify_cb(int card_present, void *dev_id) -{ - struct msmsdcc_host *host = dev_id; - - pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc), - card_present); - msmsdcc_check_status((unsigned long) host); -} - -static void -msmsdcc_busclk_expired(unsigned long _data) -{ - struct msmsdcc_host *host = (struct msmsdcc_host *) _data; - - if (host->clks_on) - msmsdcc_disable_clocks(host, 0); -} - -static int -msmsdcc_init_dma(struct msmsdcc_host *host) -{ - memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data)); - host->dma.host = host; - host->dma.channel = -1; - - if (!host->dmares) - return -ENODEV; - - host->dma.nc = dma_alloc_coherent(NULL, - sizeof(struct msmsdcc_nc_dmadata), - &host->dma.nc_busaddr, - GFP_KERNEL); - if (host->dma.nc == NULL) { - pr_err("Unable to allocate DMA buffer\n"); - return -ENOMEM; - } - memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata)); - host->dma.cmd_busaddr = host->dma.nc_busaddr; - host->dma.cmdptr_busaddr = host->dma.nc_busaddr + - offsetof(struct msmsdcc_nc_dmadata, cmdptr); - host->dma.channel = host->dmares->start; - - return 0; -} - -static int -msmsdcc_probe(struct platform_device *pdev) -{ - struct msm_mmc_platform_data *plat = pdev->dev.platform_data; - struct msmsdcc_host *host; - struct mmc_host *mmc; - struct resource *cmd_irqres = NULL; - struct resource *stat_irqres = NULL; - struct resource *memres = NULL; - struct resource *dmares = NULL; - int ret; - - /* must have platform data */ - if (!plat) { - pr_err("%s: Platform data not available\n", __func__); - ret = -EINVAL; - goto out; - } - - if (pdev->id < 1 || pdev->id > 4) - return -EINVAL; - - if (pdev->resource == NULL || pdev->num_resources < 2) { - pr_err("%s: Invalid resource\n", __func__); - return -ENXIO; - } - - memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); - cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, - "cmd_irq"); - stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, - "status_irq"); - - if (!cmd_irqres || !memres) { - pr_err("%s: Invalid resource\n", __func__); - return -ENXIO; - } - - /* - * Setup our host structure - */ - - mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out; - } - - host = mmc_priv(mmc); - host->pdev_id = pdev->id; - host->plat = plat; - host->mmc = mmc; - host->curr.cmd = NULL; - init_timer(&host->busclk_timer); - host->busclk_timer.data = (unsigned long) host; - host->busclk_timer.function = msmsdcc_busclk_expired; - - - host->cmdpoll = 1; - - host->base = ioremap(memres->start, PAGE_SIZE); - if (!host->base) { - ret = -ENOMEM; - goto host_free; - } - - host->cmd_irqres = cmd_irqres; - host->memres = memres; - host->dmares = dmares; - spin_lock_init(&host->lock); - - tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet, - (unsigned long)host); - - /* - * Setup DMA - */ - if (host->dmares) { - ret = msmsdcc_init_dma(host); - if (ret) - goto ioremap_free; - } else { - host->dma.channel = -1; - } - - /* Get our clocks */ - host->pclk = clk_get(&pdev->dev, "sdc_pclk"); - if (IS_ERR(host->pclk)) { - ret = PTR_ERR(host->pclk); - goto dma_free; - } - - host->clk = clk_get(&pdev->dev, "sdc_clk"); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - goto pclk_put; - } - - ret = clk_set_rate(host->clk, msmsdcc_fmin); - if (ret) { - pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); - goto clk_put; - } - - ret = clk_prepare(host->pclk); - if (ret) - goto clk_put; - - ret = clk_prepare(host->clk); - if (ret) - goto clk_unprepare_p; - - /* Enable clocks */ - ret = msmsdcc_enable_clocks(host); - if (ret) - goto clk_unprepare; - - host->pclk_rate = clk_get_rate(host->pclk); - host->clk_rate = clk_get_rate(host->clk); - - /* - * Setup MMC host structure - */ - mmc->ops = &msmsdcc_ops; - mmc->f_min = msmsdcc_fmin; - mmc->f_max = msmsdcc_fmax; - mmc->ocr_avail = plat->ocr_mask; - - if (msmsdcc_4bit) - mmc->caps |= MMC_CAP_4_BIT_DATA; - if (msmsdcc_sdioirq) - mmc->caps |= MMC_CAP_SDIO_IRQ; - mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; - - mmc->max_segs = NR_SG; - mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */ - mmc->max_blk_count = 65536; - - mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ - mmc->max_seg_size = mmc->max_req_size; - - msmsdcc_writel(host, 0, MMCIMASK0); - msmsdcc_writel(host, 0x5e007ff, MMCICLEAR); - - msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0); - host->saved_irq0mask = MCI_IRQENABLE; - - /* - * Setup card detect change - */ - - memset(&host->timer, 0, sizeof(host->timer)); - - if (stat_irqres && !(stat_irqres->flags & IORESOURCE_DISABLED)) { - unsigned long irqflags = IRQF_SHARED | - (stat_irqres->flags & IRQF_TRIGGER_MASK); - - host->stat_irq = stat_irqres->start; - ret = request_irq(host->stat_irq, - msmsdcc_platform_status_irq, - irqflags, - DRIVER_NAME " (slot)", - host); - if (ret) { - pr_err("%s: Unable to get slot IRQ %d (%d)\n", - mmc_hostname(mmc), host->stat_irq, ret); - goto clk_disable; - } - } else if (plat->register_status_notify) { - plat->register_status_notify(msmsdcc_status_notify_cb, host); - } else if (!plat->status) - pr_err("%s: No card detect facilities available\n", - mmc_hostname(mmc)); - else { - init_timer(&host->timer); - host->timer.data = (unsigned long)host; - host->timer.function = msmsdcc_check_status; - host->timer.expires = jiffies + HZ; - add_timer(&host->timer); - } - - if (plat->status) { - host->oldstat = host->plat->status(mmc_dev(host->mmc)); - host->eject = !host->oldstat; - } - - ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, - DRIVER_NAME " (cmd)", host); - if (ret) - goto stat_irq_free; - - ret = request_irq(cmd_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, - DRIVER_NAME " (pio)", host); - if (ret) - goto cmd_irq_free; - - platform_set_drvdata(pdev, mmc); - mmc_add_host(mmc); - - pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n", - mmc_hostname(mmc), (unsigned long long)memres->start, - (unsigned int) cmd_irqres->start, - (unsigned int) host->stat_irq, host->dma.channel); - pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc), - (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled")); - pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n", - mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate); - pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject); - pr_info("%s: Power save feature enable = %d\n", - mmc_hostname(mmc), msmsdcc_pwrsave); - - if (host->dma.channel != -1) { - pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n", - mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr); - pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n", - mmc_hostname(mmc), host->dma.cmd_busaddr, - host->dma.cmdptr_busaddr); - } else - pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc)); - if (host->timer.function) - pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); - - return 0; - cmd_irq_free: - free_irq(cmd_irqres->start, host); - stat_irq_free: - if (host->stat_irq) - free_irq(host->stat_irq, host); - clk_disable: - msmsdcc_disable_clocks(host, 0); - clk_unprepare: - clk_unprepare(host->clk); - clk_unprepare_p: - clk_unprepare(host->pclk); - clk_put: - clk_put(host->clk); - pclk_put: - clk_put(host->pclk); -dma_free: - if (host->dmares) - dma_free_coherent(NULL, sizeof(struct msmsdcc_nc_dmadata), - host->dma.nc, host->dma.nc_busaddr); -ioremap_free: - tasklet_kill(&host->dma_tlet); - iounmap(host->base); - host_free: - mmc_free_host(mmc); - out: - return ret; -} - -#ifdef CONFIG_PM -static int -msmsdcc_suspend(struct platform_device *dev, pm_message_t state) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - - if (mmc) { - struct msmsdcc_host *host = mmc_priv(mmc); - - if (host->stat_irq) - disable_irq(host->stat_irq); - - msmsdcc_writel(host, 0, MMCIMASK0); - if (host->clks_on) - msmsdcc_disable_clocks(host, 0); - } - return 0; -} - -static int -msmsdcc_resume(struct platform_device *dev) -{ - struct mmc_host *mmc = platform_get_drvdata(dev); - - if (mmc) { - struct msmsdcc_host *host = mmc_priv(mmc); - - msmsdcc_enable_clocks(host); - - msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); - - if (host->stat_irq) - enable_irq(host->stat_irq); -#if BUSCLK_PWRSAVE - msmsdcc_disable_clocks(host, 1); -#endif - } - return 0; -} -#else -#define msmsdcc_suspend 0 -#define msmsdcc_resume 0 -#endif - -static struct platform_driver msmsdcc_driver = { - .probe = msmsdcc_probe, - .suspend = msmsdcc_suspend, - .resume = msmsdcc_resume, - .driver = { - .name = "msm_sdcc", - }, -}; - -module_platform_driver(msmsdcc_driver); - -MODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h deleted file mode 100644 index 402028d16b86..000000000000 --- a/drivers/mmc/host/msm_sdcc.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * linux/drivers/mmc/host/msmsdcc.h - QCT MSM7K SDC Controller - * - * Copyright (C) 2008 Google, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * - Based on mmci.h - */ - -#ifndef _MSM_SDCC_H -#define _MSM_SDCC_H - -#define MSMSDCC_CRCI_SDC1 6 -#define MSMSDCC_CRCI_SDC2 7 -#define MSMSDCC_CRCI_SDC3 12 -#define MSMSDCC_CRCI_SDC4 13 - -#define MMCIPOWER 0x000 -#define MCI_PWR_OFF 0x00 -#define MCI_PWR_UP 0x02 -#define MCI_PWR_ON 0x03 -#define MCI_OD (1 << 6) - -#define MMCICLOCK 0x004 -#define MCI_CLK_ENABLE (1 << 8) -#define MCI_CLK_PWRSAVE (1 << 9) -#define MCI_CLK_WIDEBUS (1 << 10) -#define MCI_CLK_FLOWENA (1 << 12) -#define MCI_CLK_INVERTOUT (1 << 13) -#define MCI_CLK_SELECTIN (1 << 14) - -#define MMCIARGUMENT 0x008 -#define MMCICOMMAND 0x00c -#define MCI_CPSM_RESPONSE (1 << 6) -#define MCI_CPSM_LONGRSP (1 << 7) -#define MCI_CPSM_INTERRUPT (1 << 8) -#define MCI_CPSM_PENDING (1 << 9) -#define MCI_CPSM_ENABLE (1 << 10) -#define MCI_CPSM_PROGENA (1 << 11) -#define MCI_CSPM_DATCMD (1 << 12) -#define MCI_CSPM_MCIABORT (1 << 13) -#define MCI_CSPM_CCSENABLE (1 << 14) -#define MCI_CSPM_CCSDISABLE (1 << 15) - - -#define MMCIRESPCMD 0x010 -#define MMCIRESPONSE0 0x014 -#define MMCIRESPONSE1 0x018 -#define MMCIRESPONSE2 0x01c -#define MMCIRESPONSE3 0x020 -#define MMCIDATATIMER 0x024 -#define MMCIDATALENGTH 0x028 - -#define MMCIDATACTRL 0x02c -#define MCI_DPSM_ENABLE (1 << 0) -#define MCI_DPSM_DIRECTION (1 << 1) -#define MCI_DPSM_MODE (1 << 2) -#define MCI_DPSM_DMAENABLE (1 << 3) - -#define MMCIDATACNT 0x030 -#define MMCISTATUS 0x034 -#define MCI_CMDCRCFAIL (1 << 0) -#define MCI_DATACRCFAIL (1 << 1) -#define MCI_CMDTIMEOUT (1 << 2) -#define MCI_DATATIMEOUT (1 << 3) -#define MCI_TXUNDERRUN (1 << 4) -#define MCI_RXOVERRUN (1 << 5) -#define MCI_CMDRESPEND (1 << 6) -#define MCI_CMDSENT (1 << 7) -#define MCI_DATAEND (1 << 8) -#define MCI_DATABLOCKEND (1 << 10) -#define MCI_CMDACTIVE (1 << 11) -#define MCI_TXACTIVE (1 << 12) -#define MCI_RXACTIVE (1 << 13) -#define MCI_TXFIFOHALFEMPTY (1 << 14) -#define MCI_RXFIFOHALFFULL (1 << 15) -#define MCI_TXFIFOFULL (1 << 16) -#define MCI_RXFIFOFULL (1 << 17) -#define MCI_TXFIFOEMPTY (1 << 18) -#define MCI_RXFIFOEMPTY (1 << 19) -#define MCI_TXDATAAVLBL (1 << 20) -#define MCI_RXDATAAVLBL (1 << 21) -#define MCI_SDIOINTR (1 << 22) -#define MCI_PROGDONE (1 << 23) -#define MCI_ATACMDCOMPL (1 << 24) -#define MCI_SDIOINTOPER (1 << 25) -#define MCI_CCSTIMEOUT (1 << 26) - -#define MMCICLEAR 0x038 -#define MCI_CMDCRCFAILCLR (1 << 0) -#define MCI_DATACRCFAILCLR (1 << 1) -#define MCI_CMDTIMEOUTCLR (1 << 2) -#define MCI_DATATIMEOUTCLR (1 << 3) -#define MCI_TXUNDERRUNCLR (1 << 4) -#define MCI_RXOVERRUNCLR (1 << 5) -#define MCI_CMDRESPENDCLR (1 << 6) -#define MCI_CMDSENTCLR (1 << 7) -#define MCI_DATAENDCLR (1 << 8) -#define MCI_DATABLOCKENDCLR (1 << 10) - -#define MMCIMASK0 0x03c -#define MCI_CMDCRCFAILMASK (1 << 0) -#define MCI_DATACRCFAILMASK (1 << 1) -#define MCI_CMDTIMEOUTMASK (1 << 2) -#define MCI_DATATIMEOUTMASK (1 << 3) -#define MCI_TXUNDERRUNMASK (1 << 4) -#define MCI_RXOVERRUNMASK (1 << 5) -#define MCI_CMDRESPENDMASK (1 << 6) -#define MCI_CMDSENTMASK (1 << 7) -#define MCI_DATAENDMASK (1 << 8) -#define MCI_DATABLOCKENDMASK (1 << 10) -#define MCI_CMDACTIVEMASK (1 << 11) -#define MCI_TXACTIVEMASK (1 << 12) -#define MCI_RXACTIVEMASK (1 << 13) -#define MCI_TXFIFOHALFEMPTYMASK (1 << 14) -#define MCI_RXFIFOHALFFULLMASK (1 << 15) -#define MCI_TXFIFOFULLMASK (1 << 16) -#define MCI_RXFIFOFULLMASK (1 << 17) -#define MCI_TXFIFOEMPTYMASK (1 << 18) -#define MCI_RXFIFOEMPTYMASK (1 << 19) -#define MCI_TXDATAAVLBLMASK (1 << 20) -#define MCI_RXDATAAVLBLMASK (1 << 21) -#define MCI_SDIOINTMASK (1 << 22) -#define MCI_PROGDONEMASK (1 << 23) -#define MCI_ATACMDCOMPLMASK (1 << 24) -#define MCI_SDIOINTOPERMASK (1 << 25) -#define MCI_CCSTIMEOUTMASK (1 << 26) - -#define MMCIMASK1 0x040 -#define MMCIFIFOCNT 0x044 -#define MCICCSTIMER 0x058 - -#define MMCIFIFO 0x080 /* to 0x0bc */ - -#define MCI_IRQENABLE \ - (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ - MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ - MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK|MCI_PROGDONEMASK) - -#define MCI_IRQ_PIO \ - (MCI_RXDATAAVLBLMASK | MCI_TXDATAAVLBLMASK | MCI_RXFIFOEMPTYMASK | \ - MCI_TXFIFOEMPTYMASK | MCI_RXFIFOFULLMASK | MCI_TXFIFOFULLMASK | \ - MCI_RXFIFOHALFFULLMASK | MCI_TXFIFOHALFEMPTYMASK | \ - MCI_RXACTIVEMASK | MCI_TXACTIVEMASK) -/* - * The size of the FIFO in bytes. - */ -#define MCI_FIFOSIZE (16*4) - -#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2) - -#define NR_SG 32 - -struct clk; - -struct msmsdcc_nc_dmadata { - dmov_box cmd[NR_SG]; - uint32_t cmdptr; -}; - -struct msmsdcc_dma_data { - struct msmsdcc_nc_dmadata *nc; - dma_addr_t nc_busaddr; - dma_addr_t cmd_busaddr; - dma_addr_t cmdptr_busaddr; - - struct msm_dmov_cmd hdr; - enum dma_data_direction dir; - - struct scatterlist *sg; - int num_ents; - - int channel; - struct msmsdcc_host *host; - int busy; /* Set if DM is busy */ - int active; - unsigned int result; - struct msm_dmov_errdata err; -}; - -struct msmsdcc_pio_data { - struct scatterlist *sg; - unsigned int sg_len; - unsigned int sg_off; -}; - -struct msmsdcc_curr_req { - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - unsigned int xfer_size; /* Total data size */ - unsigned int xfer_remain; /* Bytes remaining to send */ - unsigned int data_xfered; /* Bytes acked by BLKEND irq */ - int got_dataend; - int user_pages; -}; - -struct msmsdcc_stats { - unsigned int reqs; - unsigned int cmds; - unsigned int cmdpoll_hits; - unsigned int cmdpoll_misses; -}; - -struct msmsdcc_host { - struct resource *cmd_irqres; - struct resource *memres; - struct resource *dmares; - void __iomem *base; - int pdev_id; - unsigned int stat_irq; - - struct msmsdcc_curr_req curr; - - struct mmc_host *mmc; - struct clk *clk; /* main MMC bus clock */ - struct clk *pclk; /* SDCC peripheral bus clock */ - unsigned int clks_on; /* set if clocks are enabled */ - struct timer_list busclk_timer; - - unsigned int eject; /* eject state */ - - spinlock_t lock; - - unsigned int clk_rate; /* Current clock rate */ - unsigned int pclk_rate; - - u32 pwr; - u32 saved_irq0mask; /* MMCIMASK0 reg value */ - struct msm_mmc_platform_data *plat; - - struct timer_list timer; - unsigned int oldstat; - - struct msmsdcc_dma_data dma; - struct msmsdcc_pio_data pio; - int cmdpoll; - struct msmsdcc_stats stats; - - struct tasklet_struct dma_tlet; - /* Command parameters */ - unsigned int cmd_timeout; - unsigned int cmd_pio_irqmask; - unsigned int cmd_datactrl; - struct mmc_command *cmd_cmd; - u32 cmd_c; - bool gpio_config_status; - - bool prog_scan; - bool prog_enable; -}; - -#endif diff --git a/include/linux/platform_data/mmc-msm_sdcc.h b/include/linux/platform_data/mmc-msm_sdcc.h deleted file mode 100644 index 55aa873c9396..000000000000 --- a/include/linux/platform_data/mmc-msm_sdcc.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __MMC_MSM_SDCC_H -#define __MMC_MSM_SDCC_H - -#include -#include -#include - -struct msm_mmc_gpio { - unsigned no; - const char *name; -}; - -struct msm_mmc_gpio_data { - struct msm_mmc_gpio *gpio; - u8 size; -}; - -struct msm_mmc_platform_data { - unsigned int ocr_mask; /* available voltages */ - u32 (*translate_vdd)(struct device *, unsigned int); - unsigned int (*status)(struct device *); - int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id); - struct msm_mmc_gpio_data *gpio_data; - void (*init_card)(struct mmc_card *card); -}; - -#endif -- cgit v1.2.3 From 4e59080397faadee59d39ffa2116dc8607adc9c9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 9 Mar 2015 14:01:25 -0400 Subject: NFSv4.1: Allow getdeviceinfo to return notification info back to caller We are only allowed to cache deviceinfo if the server supports notifications and actually promises to call us back when changes occur. Right now, we request those notifications, but then we don't check the server's reply. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 5 +++++ fs/nfs/nfs4xdr.c | 14 +++++--------- include/linux/nfs_xdr.h | 2 ++ 3 files changed, 12 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 627f37c44456..ba8b2b5e98a1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -7944,6 +7944,8 @@ _nfs4_proc_getdeviceinfo(struct nfs_server *server, { struct nfs4_getdeviceinfo_args args = { .pdev = pdev, + .notify_types = NOTIFY_DEVICEID4_CHANGE | + NOTIFY_DEVICEID4_DELETE, }; struct nfs4_getdeviceinfo_res res = { .pdev = pdev, @@ -7958,6 +7960,9 @@ _nfs4_proc_getdeviceinfo(struct nfs_server *server, dprintk("--> %s\n", __func__); status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); + if (res.notification & ~args.notify_types) + dprintk("%s: unsupported notification\n", __func__); + dprintk("<-- %s status=%d\n", __func__, status); return status; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5c399ec41079..6b28a605c697 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1920,7 +1920,7 @@ encode_getdeviceinfo(struct xdr_stream *xdr, p = reserve_space(xdr, 4 + 4); *p++ = cpu_to_be32(1); /* bitmap length */ - *p++ = cpu_to_be32(NOTIFY_DEVICEID4_CHANGE | NOTIFY_DEVICEID4_DELETE); + *p++ = cpu_to_be32(args->notify_types); } static void @@ -5753,8 +5753,9 @@ out_overflow: #if defined(CONFIG_NFS_V4_1) static int decode_getdeviceinfo(struct xdr_stream *xdr, - struct pnfs_device *pdev) + struct nfs4_getdeviceinfo_res *res) { + struct pnfs_device *pdev = res->pdev; __be32 *p; uint32_t len, type; int status; @@ -5802,12 +5803,7 @@ static int decode_getdeviceinfo(struct xdr_stream *xdr, if (unlikely(!p)) goto out_overflow; - if (be32_to_cpup(p++) & - ~(NOTIFY_DEVICEID4_CHANGE | NOTIFY_DEVICEID4_DELETE)) { - dprintk("%s: unsupported notification\n", - __func__); - } - + res->notification = be32_to_cpup(p++); for (i = 1; i < len; i++) { if (be32_to_cpup(p++)) { dprintk("%s: unsupported notification\n", @@ -7061,7 +7057,7 @@ static int nfs4_xdr_dec_getdeviceinfo(struct rpc_rqst *rqstp, status = decode_sequence(xdr, &res->seq_res, rqstp); if (status != 0) goto out; - status = decode_getdeviceinfo(xdr, res->pdev); + status = decode_getdeviceinfo(xdr, res); out: return status; } diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 4cb3eaa89cf7..3d88908fd140 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -255,11 +255,13 @@ struct nfs4_layoutget { struct nfs4_getdeviceinfo_args { struct nfs4_sequence_args seq_args; struct pnfs_device *pdev; + __u32 notify_types; }; struct nfs4_getdeviceinfo_res { struct nfs4_sequence_res seq_res; struct pnfs_device *pdev; + __u32 notification; }; struct nfs4_layoutcommit_args { -- cgit v1.2.3 From 9e1681c2e74bdd84bad6f74b47a4d88ad2f433df Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 25 Mar 2015 17:23:31 -0400 Subject: NFSv4: Truncating file opens should also sync O_DIRECT writes We don't just want to sync out buffered writes, but also O_DIRECT ones. Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 3 ++- fs/nfs/nfs4file.c | 2 +- include/linux/nfs_fs.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 60f907666697..f1fc0e4c1c02 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -133,11 +133,12 @@ void nfs_evict_inode(struct inode *inode) nfs_clear_inode(inode); } -static int nfs_sync_inode(struct inode *inode) +int nfs_sync_inode(struct inode *inode) { nfs_inode_dio_wait(inode); return nfs_wb_all(inode); } +EXPORT_SYMBOL_GPL(nfs_sync_inode); /** * nfs_sync_mapping - helper to flush all mmapped dirty data to disk diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 0de62f7cfebf..8da5409e6f1a 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -59,7 +59,7 @@ nfs4_file_open(struct inode *inode, struct file *filp) if (openflags & O_TRUNC) { attr.ia_valid |= ATTR_SIZE; attr.ia_size = 0; - nfs_wb_all(inode); + nfs_sync_inode(inode); } inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, &opened); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index b01ccf371fdc..b638eb6727c6 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -512,6 +512,7 @@ extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned * Try to write back everything synchronously (but check the * return value!) */ +extern int nfs_sync_inode(struct inode *inode); extern int nfs_wb_all(struct inode *inode); extern int nfs_wb_page(struct inode *inode, struct page* page); extern int nfs_wb_page_cancel(struct inode *inode, struct page* page); -- cgit v1.2.3 From 8cc7f33aadc8fb37b5a3f4c46f5fa83748a92a01 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 13 Mar 2015 00:38:39 -0700 Subject: mtd: spi-nor: factor out replace-able flash_{lock,unlock} Flash lock/unlock is a flash-specific operations. Factor out a callback for it to more readily support other vendors. Signed-off-by: Brian Norris Tested-by: VIET NGA DAO --- drivers/mtd/spi-nor/spi-nor.c | 57 ++++++++++++++++++++++++++++--------------- include/linux/mtd/spi-nor.h | 5 ++++ 2 files changed, 43 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b6a5a0c269e1..60bf3caf1ead 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -369,17 +369,13 @@ erase_err: return ret; } -static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) { - struct spi_nor *nor = mtd_to_spi_nor(mtd); + struct mtd_info *mtd = nor->mtd; uint32_t offset = ofs; uint8_t status_old, status_new; int ret = 0; - ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK); - if (ret) - return ret; - status_old = read_sr(nor); if (offset < mtd->size - (mtd->size / 2)) @@ -402,26 +398,18 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { write_enable(nor); ret = write_sr(nor, status_new); - if (ret) - goto err; } -err: - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); return ret; } -static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) { - struct spi_nor *nor = mtd_to_spi_nor(mtd); + struct mtd_info *mtd = nor->mtd; uint32_t offset = ofs; uint8_t status_old, status_new; int ret = 0; - ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); - if (ret) - return ret; - status_old = read_sr(nor); if (offset+len > mtd->size - (mtd->size / 64)) @@ -444,15 +432,41 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { write_enable(nor); ret = write_sr(nor, status_new); - if (ret) - goto err; } -err: + return ret; +} + +static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + int ret; + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK); + if (ret) + return ret; + + ret = nor->flash_lock(nor, ofs, len); + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); return ret; } +static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + int ret; + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); + if (ret) + return ret; + + ret = nor->flash_unlock(nor, ofs, len); + + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); + return ret; +} + /* Used when the "_ext_id" is two bytes at most */ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ ((kernel_ulong_t)&(struct flash_info) { \ @@ -1045,6 +1059,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) /* nor protection support for STmicro chips */ if (JEDEC_MFR(info) == CFI_MFR_ST) { + nor->flash_lock = stm_lock; + nor->flash_unlock = stm_unlock; + } + + if (nor->flash_lock && nor->flash_unlock) { mtd->_lock = spi_nor_lock; mtd->_unlock = spi_nor_unlock; } diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 4720b86ee73d..e5409524bb0a 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -155,6 +155,8 @@ enum spi_nor_option_flags { * @write: [DRIVER-SPECIFIC] write data to the SPI NOR * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR * at the offset @offs + * @lock: [FLASH-SPECIFIC] lock a region of the SPI NOR + * @unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR * @priv: the private data */ struct spi_nor { @@ -189,6 +191,9 @@ struct spi_nor { size_t len, size_t *retlen, const u_char *write_buf); int (*erase)(struct spi_nor *nor, loff_t offs); + int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len); + int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len); + void *priv; }; -- cgit v1.2.3 From 0384e8c6c6fa49dae44ffad31958e9b897da0160 Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Wed, 21 Jan 2015 19:05:57 +0200 Subject: of: Empty node & property flag accessors when !OF Introduce empty node and property flag accessors when CONFIG_OF is not defined. This allows us to use them without ifdef'ing them in places where it makes sense to do so. Signed-off-by: Pantelis Antoniou Acked-by: Rob Herring Signed-off-by: Grant Likely --- include/linux/of.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'include') diff --git a/include/linux/of.h b/include/linux/of.h index dfde07e77a63..7ede4496bad6 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -616,6 +616,38 @@ static inline const char *of_prop_next_string(struct property *prop, return NULL; } +static inline int of_node_check_flag(struct device_node *n, unsigned long flag) +{ + return 0; +} + +static inline int of_node_test_and_set_flag(struct device_node *n, + unsigned long flag) +{ + return 0; +} + +static inline void of_node_set_flag(struct device_node *n, unsigned long flag) +{ +} + +static inline void of_node_clear_flag(struct device_node *n, unsigned long flag) +{ +} + +static inline int of_property_check_flag(struct property *p, unsigned long flag) +{ + return 0; +} + +static inline void of_property_set_flag(struct property *p, unsigned long flag) +{ +} + +static inline void of_property_clear_flag(struct property *p, unsigned long flag) +{ +} + #define of_match_ptr(_ptr) NULL #define of_match_node(_matches, _node) NULL #endif /* CONFIG_OF */ -- cgit v1.2.3 From 271c865161c57cfabca45b93eaa712b19da365bc Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 27 Mar 2015 12:46:12 +1030 Subject: Add virtio-input driver. virtio-input is basically evdev-events-over-virtio, so this driver isn't much more than reading configuration from config space and forwarding incoming events to the linux input layer. Signed-off-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Signed-off-by: Rusty Russell --- MAINTAINERS | 6 + drivers/virtio/Kconfig | 10 + drivers/virtio/Makefile | 1 + drivers/virtio/virtio_input.c | 384 ++++++++++++++++++++++++++++++++++++++ include/uapi/linux/Kbuild | 1 + include/uapi/linux/virtio_ids.h | 1 + include/uapi/linux/virtio_input.h | 76 ++++++++ 7 files changed, 479 insertions(+) create mode 100644 drivers/virtio/virtio_input.c create mode 100644 include/uapi/linux/virtio_input.h (limited to 'include') diff --git a/MAINTAINERS b/MAINTAINERS index 0e1abe8cc684..585e6cdd9186 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10435,6 +10435,12 @@ S: Maintained F: drivers/vhost/ F: include/uapi/linux/vhost.h +VIRTIO INPUT DRIVER +M: Gerd Hoffmann +S: Maintained +F: drivers/virtio/virtio_input.c +F: include/uapi/linux/virtio_input.h + VIA RHINE NETWORK DRIVER M: Roger Luethi S: Maintained diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index b546da5d8ea3..cab9f3f63a38 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -48,6 +48,16 @@ config VIRTIO_BALLOON If unsure, say M. +config VIRTIO_INPUT + tristate "Virtio input driver" + depends on VIRTIO + depends on INPUT + ---help--- + This driver supports virtio input devices such as + keyboards, mice and tablets. + + If unsure, say M. + config VIRTIO_MMIO tristate "Platform bus driver for memory mapped virtio devices" depends on HAS_IOMEM diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index d85565b8ea46..41e30e3dc842 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o +obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c new file mode 100644 index 000000000000..60e2a1677563 --- /dev/null +++ b/drivers/virtio/virtio_input.c @@ -0,0 +1,384 @@ +#include +#include +#include +#include + +#include +#include + +struct virtio_input { + struct virtio_device *vdev; + struct input_dev *idev; + char name[64]; + char serial[64]; + char phys[64]; + struct virtqueue *evt, *sts; + struct virtio_input_event evts[64]; + spinlock_t lock; + bool ready; +}; + +static void virtinput_queue_evtbuf(struct virtio_input *vi, + struct virtio_input_event *evtbuf) +{ + struct scatterlist sg[1]; + + sg_init_one(sg, evtbuf, sizeof(*evtbuf)); + virtqueue_add_inbuf(vi->evt, sg, 1, evtbuf, GFP_ATOMIC); +} + +static void virtinput_recv_events(struct virtqueue *vq) +{ + struct virtio_input *vi = vq->vdev->priv; + struct virtio_input_event *event; + unsigned long flags; + unsigned int len; + + spin_lock_irqsave(&vi->lock, flags); + if (vi->ready) { + while ((event = virtqueue_get_buf(vi->evt, &len)) != NULL) { + spin_unlock_irqrestore(&vi->lock, flags); + input_event(vi->idev, + le16_to_cpu(event->type), + le16_to_cpu(event->code), + le32_to_cpu(event->value)); + spin_lock_irqsave(&vi->lock, flags); + virtinput_queue_evtbuf(vi, event); + } + virtqueue_kick(vq); + } + spin_unlock_irqrestore(&vi->lock, flags); +} + +/* + * On error we are losing the status update, which isn't critical as + * this is typically used for stuff like keyboard leds. + */ +static int virtinput_send_status(struct virtio_input *vi, + u16 type, u16 code, s32 value) +{ + struct virtio_input_event *stsbuf; + struct scatterlist sg[1]; + unsigned long flags; + int rc; + + stsbuf = kzalloc(sizeof(*stsbuf), GFP_ATOMIC); + if (!stsbuf) + return -ENOMEM; + + stsbuf->type = cpu_to_le16(type); + stsbuf->code = cpu_to_le16(code); + stsbuf->value = cpu_to_le32(value); + sg_init_one(sg, stsbuf, sizeof(*stsbuf)); + + spin_lock_irqsave(&vi->lock, flags); + if (vi->ready) { + rc = virtqueue_add_outbuf(vi->sts, sg, 1, stsbuf, GFP_ATOMIC); + virtqueue_kick(vi->sts); + } else { + rc = -ENODEV; + } + spin_unlock_irqrestore(&vi->lock, flags); + + if (rc != 0) + kfree(stsbuf); + return rc; +} + +static void virtinput_recv_status(struct virtqueue *vq) +{ + struct virtio_input *vi = vq->vdev->priv; + struct virtio_input_event *stsbuf; + unsigned long flags; + unsigned int len; + + spin_lock_irqsave(&vi->lock, flags); + while ((stsbuf = virtqueue_get_buf(vi->sts, &len)) != NULL) + kfree(stsbuf); + spin_unlock_irqrestore(&vi->lock, flags); +} + +static int virtinput_status(struct input_dev *idev, unsigned int type, + unsigned int code, int value) +{ + struct virtio_input *vi = input_get_drvdata(idev); + + return virtinput_send_status(vi, type, code, value); +} + +static u8 virtinput_cfg_select(struct virtio_input *vi, + u8 select, u8 subsel) +{ + u8 size; + + virtio_cwrite(vi->vdev, struct virtio_input_config, select, &select); + virtio_cwrite(vi->vdev, struct virtio_input_config, subsel, &subsel); + virtio_cread(vi->vdev, struct virtio_input_config, size, &size); + return size; +} + +static void virtinput_cfg_bits(struct virtio_input *vi, int select, int subsel, + unsigned long *bits, unsigned int bitcount) +{ + unsigned int bit; + u8 *virtio_bits; + u8 bytes; + + bytes = virtinput_cfg_select(vi, select, subsel); + if (!bytes) + return; + if (bitcount > bytes * 8) + bitcount = bytes * 8; + + /* + * Bitmap in virtio config space is a simple stream of bytes, + * with the first byte carrying bits 0-7, second bits 8-15 and + * so on. + */ + virtio_bits = kzalloc(bytes, GFP_KERNEL); + if (!virtio_bits) + return; + virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config, + u.bitmap), + virtio_bits, bytes); + for (bit = 0; bit < bitcount; bit++) { + if (virtio_bits[bit / 8] & (1 << (bit % 8))) + __set_bit(bit, bits); + } + kfree(virtio_bits); + + if (select == VIRTIO_INPUT_CFG_EV_BITS) + __set_bit(subsel, vi->idev->evbit); +} + +static void virtinput_cfg_abs(struct virtio_input *vi, int abs) +{ + u32 mi, ma, re, fu, fl; + + virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ABS_INFO, abs); + virtio_cread(vi->vdev, struct virtio_input_config, u.abs.min, &mi); + virtio_cread(vi->vdev, struct virtio_input_config, u.abs.max, &ma); + virtio_cread(vi->vdev, struct virtio_input_config, u.abs.res, &re); + virtio_cread(vi->vdev, struct virtio_input_config, u.abs.fuzz, &fu); + virtio_cread(vi->vdev, struct virtio_input_config, u.abs.flat, &fl); + input_set_abs_params(vi->idev, abs, mi, ma, fu, fl); + input_abs_set_res(vi->idev, abs, re); +} + +static int virtinput_init_vqs(struct virtio_input *vi) +{ + struct virtqueue *vqs[2]; + vq_callback_t *cbs[] = { virtinput_recv_events, + virtinput_recv_status }; + static const char *names[] = { "events", "status" }; + int err; + + err = vi->vdev->config->find_vqs(vi->vdev, 2, vqs, cbs, names); + if (err) + return err; + vi->evt = vqs[0]; + vi->sts = vqs[1]; + + return 0; +} + +static void virtinput_fill_evt(struct virtio_input *vi) +{ + unsigned long flags; + int i, size; + + spin_lock_irqsave(&vi->lock, flags); + size = virtqueue_get_vring_size(vi->evt); + if (size > ARRAY_SIZE(vi->evts)) + size = ARRAY_SIZE(vi->evts); + for (i = 0; i < size; i++) + virtinput_queue_evtbuf(vi, &vi->evts[i]); + virtqueue_kick(vi->evt); + spin_unlock_irqrestore(&vi->lock, flags); +} + +static int virtinput_probe(struct virtio_device *vdev) +{ + struct virtio_input *vi; + unsigned long flags; + size_t size; + int abs, err; + + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) + return -ENODEV; + + vi = kzalloc(sizeof(*vi), GFP_KERNEL); + if (!vi) + return -ENOMEM; + + vdev->priv = vi; + vi->vdev = vdev; + spin_lock_init(&vi->lock); + + err = virtinput_init_vqs(vi); + if (err) + goto err_init_vq; + + vi->idev = input_allocate_device(); + if (!vi->idev) { + err = -ENOMEM; + goto err_input_alloc; + } + input_set_drvdata(vi->idev, vi); + + size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_NAME, 0); + virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config, + u.string), + vi->name, min(size, sizeof(vi->name))); + size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_SERIAL, 0); + virtio_cread_bytes(vi->vdev, offsetof(struct virtio_input_config, + u.string), + vi->serial, min(size, sizeof(vi->serial))); + snprintf(vi->phys, sizeof(vi->phys), + "virtio%d/input0", vdev->index); + vi->idev->name = vi->name; + vi->idev->phys = vi->phys; + vi->idev->uniq = vi->serial; + + size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_ID_DEVIDS, 0); + if (size >= sizeof(struct virtio_input_devids)) { + virtio_cread(vi->vdev, struct virtio_input_config, + u.ids.bustype, &vi->idev->id.bustype); + virtio_cread(vi->vdev, struct virtio_input_config, + u.ids.vendor, &vi->idev->id.vendor); + virtio_cread(vi->vdev, struct virtio_input_config, + u.ids.product, &vi->idev->id.product); + virtio_cread(vi->vdev, struct virtio_input_config, + u.ids.version, &vi->idev->id.version); + } else { + vi->idev->id.bustype = BUS_VIRTUAL; + } + + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_PROP_BITS, 0, + vi->idev->propbit, INPUT_PROP_CNT); + size = virtinput_cfg_select(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REP); + if (size) + __set_bit(EV_REP, vi->idev->evbit); + + vi->idev->dev.parent = &vdev->dev; + vi->idev->event = virtinput_status; + + /* device -> kernel */ + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_KEY, + vi->idev->keybit, KEY_CNT); + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_REL, + vi->idev->relbit, REL_CNT); + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_ABS, + vi->idev->absbit, ABS_CNT); + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_MSC, + vi->idev->mscbit, MSC_CNT); + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SW, + vi->idev->swbit, SW_CNT); + + /* kernel -> device */ + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_LED, + vi->idev->ledbit, LED_CNT); + virtinput_cfg_bits(vi, VIRTIO_INPUT_CFG_EV_BITS, EV_SND, + vi->idev->sndbit, SND_CNT); + + if (test_bit(EV_ABS, vi->idev->evbit)) { + for (abs = 0; abs < ABS_CNT; abs++) { + if (!test_bit(abs, vi->idev->absbit)) + continue; + virtinput_cfg_abs(vi, abs); + } + } + + virtio_device_ready(vdev); + vi->ready = true; + err = input_register_device(vi->idev); + if (err) + goto err_input_register; + + virtinput_fill_evt(vi); + return 0; + +err_input_register: + spin_lock_irqsave(&vi->lock, flags); + vi->ready = false; + spin_unlock_irqrestore(&vi->lock, flags); + input_free_device(vi->idev); +err_input_alloc: + vdev->config->del_vqs(vdev); +err_init_vq: + kfree(vi); + return err; +} + +static void virtinput_remove(struct virtio_device *vdev) +{ + struct virtio_input *vi = vdev->priv; + unsigned long flags; + + spin_lock_irqsave(&vi->lock, flags); + vi->ready = false; + spin_unlock_irqrestore(&vi->lock, flags); + + input_unregister_device(vi->idev); + vdev->config->del_vqs(vdev); + kfree(vi); +} + +#ifdef CONFIG_PM_SLEEP +static int virtinput_freeze(struct virtio_device *vdev) +{ + struct virtio_input *vi = vdev->priv; + unsigned long flags; + + spin_lock_irqsave(&vi->lock, flags); + vi->ready = false; + spin_unlock_irqrestore(&vi->lock, flags); + + vdev->config->del_vqs(vdev); + return 0; +} + +static int virtinput_restore(struct virtio_device *vdev) +{ + struct virtio_input *vi = vdev->priv; + int err; + + err = virtinput_init_vqs(vi); + if (err) + return err; + + virtio_device_ready(vdev); + vi->ready = true; + virtinput_fill_evt(vi); + return 0; +} +#endif + +static unsigned int features[] = { + /* none */ +}; +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_INPUT, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static struct virtio_driver virtio_input_driver = { + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), + .id_table = id_table, + .probe = virtinput_probe, + .remove = virtinput_remove, +#ifdef CONFIG_PM_SLEEP + .freeze = virtinput_freeze, + .restore = virtinput_restore, +#endif +}; + +module_virtio_driver(virtio_input_driver); +MODULE_DEVICE_TABLE(virtio, id_table); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Virtio input device driver"); +MODULE_AUTHOR("Gerd Hoffmann "); diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 68ceb97c458c..04b829e9ac46 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -430,6 +430,7 @@ header-y += virtio_blk.h header-y += virtio_config.h header-y += virtio_console.h header-y += virtio_ids.h +header-y += virtio_input.h header-y += virtio_net.h header-y += virtio_pci.h header-y += virtio_ring.h diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h index 284fc3a05f7b..5f60aa4be50a 100644 --- a/include/uapi/linux/virtio_ids.h +++ b/include/uapi/linux/virtio_ids.h @@ -39,5 +39,6 @@ #define VIRTIO_ID_9P 9 /* 9p virtio console */ #define VIRTIO_ID_RPROC_SERIAL 11 /* virtio remoteproc serial link */ #define VIRTIO_ID_CAIF 12 /* Virtio caif */ +#define VIRTIO_ID_INPUT 18 /* virtio input */ #endif /* _LINUX_VIRTIO_IDS_H */ diff --git a/include/uapi/linux/virtio_input.h b/include/uapi/linux/virtio_input.h new file mode 100644 index 000000000000..a7fe5c8fb135 --- /dev/null +++ b/include/uapi/linux/virtio_input.h @@ -0,0 +1,76 @@ +#ifndef _LINUX_VIRTIO_INPUT_H +#define _LINUX_VIRTIO_INPUT_H +/* This header is BSD licensed so anyone can use the definitions to implement + * compatible drivers/servers. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of IBM nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ + +#include + +enum virtio_input_config_select { + VIRTIO_INPUT_CFG_UNSET = 0x00, + VIRTIO_INPUT_CFG_ID_NAME = 0x01, + VIRTIO_INPUT_CFG_ID_SERIAL = 0x02, + VIRTIO_INPUT_CFG_ID_DEVIDS = 0x03, + VIRTIO_INPUT_CFG_PROP_BITS = 0x10, + VIRTIO_INPUT_CFG_EV_BITS = 0x11, + VIRTIO_INPUT_CFG_ABS_INFO = 0x12, +}; + +struct virtio_input_absinfo { + __u32 min; + __u32 max; + __u32 fuzz; + __u32 flat; + __u32 res; +}; + +struct virtio_input_devids { + __u16 bustype; + __u16 vendor; + __u16 product; + __u16 version; +}; + +struct virtio_input_config { + __u8 select; + __u8 subsel; + __u8 size; + __u8 reserved[5]; + union { + char string[128]; + __u8 bitmap[128]; + struct virtio_input_absinfo abs; + struct virtio_input_devids ids; + } u; +}; + +struct virtio_input_event { + __le16 type; + __le16 code; + __le32 value; +}; + +#endif /* _LINUX_VIRTIO_INPUT_H */ -- cgit v1.2.3 From 045ecad0fdb23f34a2769fa9d49384a3130f7831 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Mon, 2 Mar 2015 14:17:29 +0100 Subject: clk: samsung: exynos3250: Add driver for CMU_ISP clock domain Add clock controller for CMU ISP clock domain on Exynos3250, providing clocks for FIMC-IS subsystem. [b.michalska: use samsung_cmu_register_one to register the provider; updated DT binding documentation] Signed-off-by: Tomasz Figa Signed-off-by: Chanwoo Choi Signed-off-by: Beata Michalska Acked-by: Kyungmin Park [s.nawrocki: added __init attribute which was missing in function exynos3250_cmu_platform_init() in function, which has been] Reported-by: kbuild test robot Signed-off-by: Sylwester Nawrocki Signed-off-by: Michael Turquette --- .../devicetree/bindings/clock/exynos3250-clock.txt | 8 + drivers/clk/samsung/clk-exynos3250.c | 163 +++++++++++++++++++++ include/dt-bindings/clock/exynos3250.h | 61 ++++++++ 3 files changed, 232 insertions(+) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/exynos3250-clock.txt b/Documentation/devicetree/bindings/clock/exynos3250-clock.txt index f57d9dd9ea85..f1738b88c225 100644 --- a/Documentation/devicetree/bindings/clock/exynos3250-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos3250-clock.txt @@ -9,6 +9,8 @@ Required Properties: - "samsung,exynos3250-cmu" - controller compatible with Exynos3250 SoC. - "samsung,exynos3250-cmu-dmc" - controller compatible with Exynos3250 SoC for Dynamic Memory Controller domain. + - "samsung,exynos3250-cmu-isp" - ISP block clock controller compatible + with Exynos3250 SOC - reg: physical base address of the controller and length of memory mapped region. @@ -36,6 +38,12 @@ Example 1: Examples of clock controller nodes are listed below. #clock-cells = <1>; }; + cmu_isp: clock-controller@10048000 { + compatible = "samsung,exynos3250-cmu-isp"; + reg = <0x10048000 0x1000>; + #clock-cells = <1>; + }; + Example 2: UART controller node that consumes the clock generated by the clock controller. Refer to the standard clock bindings for information about 'clocks' and 'clock-names' property. diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index cc4c348d8a24..538de66a759e 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -894,3 +894,166 @@ static void __init exynos3250_cmu_dmc_init(struct device_node *np) } CLK_OF_DECLARE(exynos3250_cmu_dmc, "samsung,exynos3250-cmu-dmc", exynos3250_cmu_dmc_init); + + +/* + * CMU ISP + */ + +#define DIV_ISP0 0x300 +#define DIV_ISP1 0x304 +#define GATE_IP_ISP0 0x800 +#define GATE_IP_ISP1 0x804 +#define GATE_SCLK_ISP 0x900 + +static struct samsung_div_clock isp_div_clks[] __initdata = { + /* + * NOTE: Following table is sorted by register address in ascending + * order and then bitfield shift in descending order, as it is done + * in the User's Manual. When adding new entries, please make sure + * that the order is preserved, to avoid merge conflicts and make + * further work with defined data easier. + */ + /* DIV_ISP0 */ + DIV(CLK_DIV_ISP1, "div_isp1", "mout_aclk_266_sub", DIV_ISP0, 4, 3), + DIV(CLK_DIV_ISP0, "div_isp0", "mout_aclk_266_sub", DIV_ISP0, 0, 3), + + /* DIV_ISP1 */ + DIV(CLK_DIV_MCUISP1, "div_mcuisp1", "mout_aclk_400_mcuisp_sub", + DIV_ISP1, 8, 3), + DIV(CLK_DIV_MCUISP0, "div_mcuisp0", "mout_aclk_400_mcuisp_sub", + DIV_ISP1, 4, 3), + DIV(CLK_DIV_MPWM, "div_mpwm", "div_isp1", DIV_ISP1, 0, 3), +}; + +static struct samsung_gate_clock isp_gate_clks[] __initdata = { + /* + * NOTE: Following table is sorted by register address in ascending + * order and then bitfield shift in descending order, as it is done + * in the User's Manual. When adding new entries, please make sure + * that the order is preserved, to avoid merge conflicts and make + * further work with defined data easier. + */ + + /* GATE_IP_ISP0 */ + GATE(CLK_UART_ISP, "uart_isp", "uart_isp_top", + GATE_IP_ISP0, 31, CLK_IGNORE_UNUSED, 0), + GATE(CLK_WDT_ISP, "wdt_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 30, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PWM_ISP, "pwm_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 28, CLK_IGNORE_UNUSED, 0), + GATE(CLK_I2C1_ISP, "i2c1_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 26, CLK_IGNORE_UNUSED, 0), + GATE(CLK_I2C0_ISP, "i2c0_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 25, CLK_IGNORE_UNUSED, 0), + GATE(CLK_MPWM_ISP, "mpwm_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 24, CLK_IGNORE_UNUSED, 0), + GATE(CLK_MCUCTL_ISP, "mcuctl_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 23, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PPMUISPX, "ppmuispx", "mout_aclk_266_sub", + GATE_IP_ISP0, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_PPMUISPMX, "ppmuispmx", "mout_aclk_266_sub", + GATE_IP_ISP0, 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_LITE1, "qe_lite1", "mout_aclk_266_sub", + GATE_IP_ISP0, 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_LITE0, "qe_lite0", "mout_aclk_266_sub", + GATE_IP_ISP0, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_FD, "qe_fd", "mout_aclk_266_sub", + GATE_IP_ISP0, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_DRC, "qe_drc", "mout_aclk_266_sub", + GATE_IP_ISP0, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_ISP, "qe_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 14, CLK_IGNORE_UNUSED, 0), + GATE(CLK_CSIS1, "csis1", "mout_aclk_266_sub", + GATE_IP_ISP0, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_LITE1, "smmu_lite1", "mout_aclk_266_sub", + GATE_IP_ISP0, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_LITE0, "smmu_lite0", "mout_aclk_266_sub", + GATE_IP_ISP0, 11, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_FD, "smmu_fd", "mout_aclk_266_sub", + GATE_IP_ISP0, 10, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_DRC, "smmu_drc", "mout_aclk_266_sub", + GATE_IP_ISP0, 9, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_ISP, "smmu_isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 8, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GICISP, "gicisp", "mout_aclk_266_sub", + GATE_IP_ISP0, 7, CLK_IGNORE_UNUSED, 0), + GATE(CLK_CSIS0, "csis0", "mout_aclk_266_sub", + GATE_IP_ISP0, 6, CLK_IGNORE_UNUSED, 0), + GATE(CLK_MCUISP, "mcuisp", "mout_aclk_266_sub", + GATE_IP_ISP0, 5, CLK_IGNORE_UNUSED, 0), + GATE(CLK_LITE1, "lite1", "mout_aclk_266_sub", + GATE_IP_ISP0, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_LITE0, "lite0", "mout_aclk_266_sub", + GATE_IP_ISP0, 3, CLK_IGNORE_UNUSED, 0), + GATE(CLK_FD, "fd", "mout_aclk_266_sub", + GATE_IP_ISP0, 2, CLK_IGNORE_UNUSED, 0), + GATE(CLK_DRC, "drc", "mout_aclk_266_sub", + GATE_IP_ISP0, 1, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ISP, "isp", "mout_aclk_266_sub", + GATE_IP_ISP0, 0, CLK_IGNORE_UNUSED, 0), + + /* GATE_IP_ISP1 */ + GATE(CLK_QE_ISPCX, "qe_ispcx", "uart_isp_top", + GATE_IP_ISP0, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_SCALERP, "qe_scalerp", "uart_isp_top", + GATE_IP_ISP0, 20, CLK_IGNORE_UNUSED, 0), + GATE(CLK_QE_SCALERC, "qe_scalerc", "uart_isp_top", + GATE_IP_ISP0, 19, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_SCALERP, "smmu_scalerp", "uart_isp_top", + GATE_IP_ISP0, 18, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_SCALERC, "smmu_scalerc", "uart_isp_top", + GATE_IP_ISP0, 17, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCALERP, "scalerp", "uart_isp_top", + GATE_IP_ISP0, 16, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SCALERC, "scalerc", "uart_isp_top", + GATE_IP_ISP0, 15, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SPI1_ISP, "spi1_isp", "uart_isp_top", + GATE_IP_ISP0, 13, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SPI0_ISP, "spi0_isp", "uart_isp_top", + GATE_IP_ISP0, 12, CLK_IGNORE_UNUSED, 0), + GATE(CLK_SMMU_ISPCX, "smmu_ispcx", "uart_isp_top", + GATE_IP_ISP0, 4, CLK_IGNORE_UNUSED, 0), + GATE(CLK_ASYNCAXIM, "asyncaxim", "uart_isp_top", + GATE_IP_ISP0, 0, CLK_IGNORE_UNUSED, 0), + + /* GATE_SCLK_ISP */ + GATE(CLK_SCLK_MPWM_ISP, "sclk_mpwm_isp", "div_mpwm", + GATE_SCLK_ISP, 0, CLK_IGNORE_UNUSED, 0), +}; + +static struct samsung_cmu_info isp_cmu_info __initdata = { + .div_clks = isp_div_clks, + .nr_div_clks = ARRAY_SIZE(isp_div_clks), + .gate_clks = isp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(isp_gate_clks), + .nr_clk_ids = NR_CLKS_ISP, +}; + +static int __init exynos3250_cmu_isp_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + + samsung_cmu_register_one(np, &isp_cmu_info); + return 0; +} + +static const struct of_device_id exynos3250_cmu_isp_of_match[] = { + { .compatible = "samsung,exynos3250-cmu-isp", }, + { /* sentinel */ } +}; + +static struct platform_driver exynos3250_cmu_isp_driver = { + .driver = { + .name = "exynos3250-cmu-isp", + .of_match_table = exynos3250_cmu_isp_of_match, + }, +}; + +static int __init exynos3250_cmu_platform_init(void) +{ + return platform_driver_probe(&exynos3250_cmu_isp_driver, + exynos3250_cmu_isp_probe); +} +subsys_initcall(exynos3250_cmu_platform_init); + diff --git a/include/dt-bindings/clock/exynos3250.h b/include/dt-bindings/clock/exynos3250.h index 961b9c130ea9..aab088d30199 100644 --- a/include/dt-bindings/clock/exynos3250.h +++ b/include/dt-bindings/clock/exynos3250.h @@ -282,4 +282,65 @@ */ #define NR_CLKS_DMC 21 +/* + * CMU ISP + */ + +/* Dividers */ + +#define CLK_DIV_ISP1 1 +#define CLK_DIV_ISP0 2 +#define CLK_DIV_MCUISP1 3 +#define CLK_DIV_MCUISP0 4 +#define CLK_DIV_MPWM 5 + +/* Gates */ + +#define CLK_UART_ISP 8 +#define CLK_WDT_ISP 9 +#define CLK_PWM_ISP 10 +#define CLK_I2C1_ISP 11 +#define CLK_I2C0_ISP 12 +#define CLK_MPWM_ISP 13 +#define CLK_MCUCTL_ISP 14 +#define CLK_PPMUISPX 15 +#define CLK_PPMUISPMX 16 +#define CLK_QE_LITE1 17 +#define CLK_QE_LITE0 18 +#define CLK_QE_FD 19 +#define CLK_QE_DRC 20 +#define CLK_QE_ISP 21 +#define CLK_CSIS1 22 +#define CLK_SMMU_LITE1 23 +#define CLK_SMMU_LITE0 24 +#define CLK_SMMU_FD 25 +#define CLK_SMMU_DRC 26 +#define CLK_SMMU_ISP 27 +#define CLK_GICISP 28 +#define CLK_CSIS0 29 +#define CLK_MCUISP 30 +#define CLK_LITE1 31 +#define CLK_LITE0 32 +#define CLK_FD 33 +#define CLK_DRC 34 +#define CLK_ISP 35 +#define CLK_QE_ISPCX 36 +#define CLK_QE_SCALERP 37 +#define CLK_QE_SCALERC 38 +#define CLK_SMMU_SCALERP 39 +#define CLK_SMMU_SCALERC 40 +#define CLK_SCALERP 41 +#define CLK_SCALERC 42 +#define CLK_SPI1_ISP 43 +#define CLK_SPI0_ISP 44 +#define CLK_SMMU_ISPCX 45 +#define CLK_ASYNCAXIM 46 +#define CLK_SCLK_MPWM_ISP 47 + +/* + * Total number of clocks of CMU_ISP. + * NOTE: Must be equal to last clock ID increased by one. + */ +#define NR_CLKS_ISP 48 + #endif /* _DT_BINDINGS_CLOCK_SAMSUNG_EXYNOS3250_CLOCK_H */ -- cgit v1.2.3 From 3bbf7f4624856751aa4cf279a472bd14a8eb16fd Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 31 Mar 2015 13:25:05 +1030 Subject: linux/cpumask.h: add typechecking to cpumask_test_cpu The Subtlety (1) referred to vanished with 6ba2ef7baac2 ("cpumask: Move deprecated functions to end of header."). That used to mention some suboptimal code generation by a, by now, rather ancient gcc. With gcc 4.7, I don't see any change in the generated code by making it a static inline, so let's add type checking and get rid of the ghost reference. Signed-off-by: Rasmus Villemoes Signed-off-by: Rusty Russell --- include/linux/cpumask.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 4ad2d3c8e21f..89558d0b56ac 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -290,11 +290,11 @@ static inline void cpumask_clear_cpu(int cpu, struct cpumask *dstp) * @cpumask: the cpumask pointer * * Returns 1 if @cpu is set in @cpumask, else returns 0 - * - * No static inline type checking - see Subtlety (1) above. */ -#define cpumask_test_cpu(cpu, cpumask) \ - test_bit(cpumask_check(cpu), cpumask_bits((cpumask))) +static inline int cpumask_test_cpu(int cpu, const struct cpumask *cpumask) +{ + return test_bit(cpumask_check(cpu), cpumask_bits((cpumask))); +} /** * cpumask_test_and_set_cpu - atomically test and set a cpu in a cpumask -- cgit v1.2.3 From 066626d5d5548d7ff63772a840b8d40a0d278825 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Mon, 30 Mar 2015 17:10:36 +0000 Subject: drm: line wrap DRM_IOCTL_DEF* macros Improve the readability and keeps the lines shorter than 80 columns. Signed-off-by: Emil Velikov Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_ioctl.c | 9 +++++++-- include/drm/drmP.h | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 1f257aecd2b2..266dcd6cdf3b 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -524,8 +524,13 @@ static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv) return 0; } -#define DRM_IOCTL_DEF(ioctl, _func, _flags) \ - [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .name = #ioctl} +#define DRM_IOCTL_DEF(ioctl, _func, _flags) \ + [DRM_IOCTL_NR(ioctl)] = { \ + .cmd = ioctl, \ + .func = _func, \ + .flags = _flags, \ + .name = #ioctl \ + } /** Ioctl table */ static const struct drm_ioctl_desc drm_ioctls[] = { diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 0d501ed20775..62c40777c009 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -261,8 +261,13 @@ struct drm_ioctl_desc { * ioctl, for use by drm_ioctl(). */ -#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ - [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {.cmd = DRM_IOCTL_##ioctl, .func = _func, .flags = _flags, .name = #ioctl} +#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ + [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = { \ + .cmd = DRM_IOCTL_##ioctl, \ + .func = _func, \ + .flags = _flags, \ + .name = #ioctl \ + } /* Event queued up for userspace to read */ struct drm_pending_event { -- cgit v1.2.3 From 4b3a81a917a5ef21a4483d699cefd4d9fa35b841 Mon Sep 17 00:00:00 2001 From: Boris Brezillion Date: Wed, 28 Jan 2015 17:49:51 +0100 Subject: Add RGB444_1X12 and RGB565_1X16 media bus formats Add RGB444_1X12 and RGB565_1X16 format definitions and update the documentation. Signed-off-by: Boris Brezillon Acked-by: Mauro Carvalho Chehab Acked-by: Sakari Ailus Acked-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel --- Documentation/DocBook/media/v4l/subdev-formats.xml | 40 ++++++++++++++++++++++ include/uapi/linux/media-bus-format.h | 4 ++- 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index c5ea868e3909..29fe60112f4c 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -192,6 +192,24 @@ see . + + MEDIA_BUS_FMT_RGB444_1X12 + 0x100e + + &dash-ent-20; + r3 + r2 + r1 + r0 + g3 + g2 + g1 + g0 + b3 + b2 + b1 + b0 + MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 @@ -304,6 +322,28 @@ see . g4 g3 + + MEDIA_BUS_FMT_RGB565_1X16 + 0x100f + + &dash-ent-16; + r4 + r3 + r2 + r1 + r0 + g5 + g4 + g3 + g2 + g1 + g0 + b4 + b3 + b2 + b1 + b0 + MEDIA_BUS_FMT_BGR565_2X8_BE 0x1005 diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index 23b40908be30..37091c668f65 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -33,11 +33,13 @@ #define MEDIA_BUS_FMT_FIXED 0x0001 -/* RGB - next is 0x100e */ +/* RGB - next is 0x1010 */ +#define MEDIA_BUS_FMT_RGB444_1X12 0x100e #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 #define MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE 0x1003 #define MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE 0x1004 +#define MEDIA_BUS_FMT_RGB565_1X16 0x100f #define MEDIA_BUS_FMT_BGR565_2X8_BE 0x1005 #define MEDIA_BUS_FMT_BGR565_2X8_LE 0x1006 #define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007 -- cgit v1.2.3 From b295c22978b86fc62019d12f4108b68b7e795610 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 2 Dec 2014 17:49:04 +0100 Subject: Add LVDS RGB media bus formats This patch adds three new RGB media bus formats that describe 18-bit or 24-bit samples transferred over an LVDS bus with three or four differential data pairs, serialized into 7 time slots, using standard SPWG/PSWG/VESA or JEIDA data ordering. Signed-off-by: Philipp Zabel Acked-by: Sakari Ailus Acked-by: Hans Verkuil --- Documentation/DocBook/media/v4l/subdev-formats.xml | 255 +++++++++++++++++++++ include/uapi/linux/media-bus-format.h | 5 +- 2 files changed, 259 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index 29fe60112f4c..18449b32f240 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -622,6 +622,261 @@ see . + + On LVDS buses, usually each sample is transferred serialized in + seven time slots per pixel clock, on three (18-bit) or four (24-bit) + differential data pairs at the same time. The remaining bits are used for + control signals as defined by SPWG/PSWG/VESA or JEIDA standards. + The 24-bit RGB format serialized in seven time slots on four lanes using + JEIDA defined bit mapping will be named + MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, for example. + + + + LVDS RGB formats + + + + + + + + + + + + + Identifier + Code + + + Data organization + + + + + Timeslot + Lane + 3 + 2 + 1 + 0 + + + + + MEDIA_BUS_FMT_RGB666_1X7X3_SPWG + 0x1010 + 0 + + - + d + b1 + g0 + + + + + 1 + + - + d + b0 + r5 + + + + + 2 + + - + d + g5 + r4 + + + + + 3 + + - + b5 + g4 + r3 + + + + + 4 + + - + b4 + g3 + r2 + + + + + 5 + + - + b3 + g2 + r1 + + + + + 6 + + - + b2 + g1 + r0 + + + MEDIA_BUS_FMT_RGB888_1X7X4_SPWG + 0x1011 + 0 + + d + d + b1 + g0 + + + + + 1 + + b7 + d + b0 + r5 + + + + + 2 + + b6 + d + g5 + r4 + + + + + 3 + + g7 + b5 + g4 + r3 + + + + + 4 + + g6 + b4 + g3 + r2 + + + + + 5 + + r7 + b3 + g2 + r1 + + + + + 6 + + r6 + b2 + g1 + r0 + + + MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA + 0x1012 + 0 + + d + d + b3 + g2 + + + + + 1 + + b1 + d + b2 + r7 + + + + + 2 + + b0 + d + g7 + r6 + + + + + 3 + + g1 + b7 + g6 + r5 + + + + + 4 + + g0 + b6 + g5 + r4 + + + + + 5 + + r1 + b5 + g4 + r3 + + + + + 6 + + r0 + b4 + g3 + r2 + + + +
diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index 37091c668f65..3fb9cbbb603f 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -33,7 +33,7 @@ #define MEDIA_BUS_FMT_FIXED 0x0001 -/* RGB - next is 0x1010 */ +/* RGB - next is 0x1013 */ #define MEDIA_BUS_FMT_RGB444_1X12 0x100e #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 @@ -45,9 +45,12 @@ #define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007 #define MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008 #define MEDIA_BUS_FMT_RGB666_1X18 0x1009 +#define MEDIA_BUS_FMT_RGB666_1X7X3_SPWG 0x1010 #define MEDIA_BUS_FMT_RGB888_1X24 0x100a #define MEDIA_BUS_FMT_RGB888_2X12_BE 0x100b #define MEDIA_BUS_FMT_RGB888_2X12_LE 0x100c +#define MEDIA_BUS_FMT_RGB888_1X7X4_SPWG 0x1011 +#define MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA 0x1012 #define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d /* YUV (including grey) - next is 0x2024 */ -- cgit v1.2.3 From 08c38458be7efa36a1d2dffd40500448e46d29c5 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 2 Dec 2014 15:45:25 +0100 Subject: Add BGR888_1X24 and GBR888_1X24 media bus formats This patch adds two more 24-bit RGB formats. BGR888 is more or less common, GBR888 is used on the internal connection between the IPU display interface and the TVE (VGA DAC) on i.MX53 SoCs. Signed-off-by: Philipp Zabel Acked-by: Laurent Pinchart Acked-by: Hans Verkuil --- Documentation/DocBook/media/v4l/subdev-formats.xml | 60 ++++++++++++++++++++++ include/uapi/linux/media-bus-format.h | 4 +- 2 files changed, 63 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index 18449b32f240..805cbe1acab7 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -480,6 +480,66 @@ see . b1 b0 + + MEDIA_BUS_FMT_BGR888_1X24 + 0x1013 + + &dash-ent-8; + b7 + b6 + b5 + b4 + b3 + b2 + b1 + b0 + g7 + g6 + g5 + g4 + g3 + g2 + g1 + g0 + r7 + r6 + r5 + r4 + r3 + r2 + r1 + r0 + + + MEDIA_BUS_FMT_GBR888_1X24 + 0x1014 + + &dash-ent-8; + g7 + g6 + g5 + g4 + g3 + g2 + g1 + g0 + b7 + b6 + b5 + b4 + b3 + b2 + b1 + b0 + r7 + r6 + r5 + r4 + r3 + r2 + r1 + r0 + MEDIA_BUS_FMT_RGB888_1X24 0x100a diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index 3fb9cbbb603f..6f6942e8dae6 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -33,7 +33,7 @@ #define MEDIA_BUS_FMT_FIXED 0x0001 -/* RGB - next is 0x1013 */ +/* RGB - next is 0x1015 */ #define MEDIA_BUS_FMT_RGB444_1X12 0x100e #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 @@ -46,6 +46,8 @@ #define MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008 #define MEDIA_BUS_FMT_RGB666_1X18 0x1009 #define MEDIA_BUS_FMT_RGB666_1X7X3_SPWG 0x1010 +#define MEDIA_BUS_FMT_BGR888_1X24 0x1013 +#define MEDIA_BUS_FMT_GBR888_1X24 0x1014 #define MEDIA_BUS_FMT_RGB888_1X24 0x100a #define MEDIA_BUS_FMT_RGB888_2X12_BE 0x100b #define MEDIA_BUS_FMT_RGB888_2X12_LE 0x100c -- cgit v1.2.3 From 0fc63eb104d76e20654cd97eeb1bfd0f35bc3d3a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 3 Dec 2014 11:01:54 +0100 Subject: Add YUV8_1X24 media bus format This patch adds the media bus format for a 24-bit bus format with three 8-bit YUV components. Signed-off-by: Philipp Zabel Acked-by: Laurent Pinchart Acked-by: Hans Verkuil --- Documentation/DocBook/media/v4l/subdev-formats.xml | 37 ++++++++++++++++++++++ include/uapi/linux/media-bus-format.h | 3 +- 2 files changed, 39 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index 805cbe1acab7..8d1f62402f88 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -3015,6 +3015,43 @@ see . u1 u0 + + MEDIA_BUS_FMT_YUV8_1X24 + 0x2024 + + - + - + - + - + - + - + - + - + y7 + y6 + y5 + y4 + y3 + y2 + y1 + y0 + u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + v7 + v6 + v5 + v4 + v3 + v2 + v1 + v0 + MEDIA_BUS_FMT_YUV10_1X30 0x2016 diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index 6f6942e8dae6..8dbf16cc5d1c 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -55,7 +55,7 @@ #define MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA 0x1012 #define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d -/* YUV (including grey) - next is 0x2024 */ +/* YUV (including grey) - next is 0x2025 */ #define MEDIA_BUS_FMT_Y8_1X8 0x2001 #define MEDIA_BUS_FMT_UV8_1X8 0x2015 #define MEDIA_BUS_FMT_UYVY8_1_5X8 0x2002 @@ -81,6 +81,7 @@ #define MEDIA_BUS_FMT_VYUY10_1X20 0x201b #define MEDIA_BUS_FMT_YUYV10_1X20 0x200d #define MEDIA_BUS_FMT_YVYU10_1X20 0x200e +#define MEDIA_BUS_FMT_YUV8_1X24 0x2024 #define MEDIA_BUS_FMT_YUV10_1X30 0x2016 #define MEDIA_BUS_FMT_AYUV8_1X32 0x2017 #define MEDIA_BUS_FMT_UYVY12_2X12 0x201c -- cgit v1.2.3 From 203508ef52e3fee93b71262928541ecea82c735d Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 2 Dec 2014 17:56:04 +0100 Subject: Add RGB666_1X24_CPADHI media bus format Commit 9e74d2926a28 ("staging: imx-drm: add LVDS666 support for parallel display") describes a 24-bit bus format where three 6-bit components each take the lower part of 8 bits with the two high bits zero padded. Add a component-wise padded media bus format RGB666_1X24_CPADHI to support this connection. Signed-off-by: Philipp Zabel Acked-by: Hans Verkuil Tested-by: Emil Renner Berthing --- Documentation/DocBook/media/v4l/subdev-formats.xml | 34 +++++++++++++++++++++- include/uapi/linux/media-bus-format.h | 3 +- 2 files changed, 35 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index 8d1f62402f88..18b71aff48c9 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -91,7 +91,9 @@ see . For formats where the total number of bits per pixel is smaller than the number of bus samples per pixel times the bus width, a padding value stating if the bytes are padded in their most high order bits - (PADHI) or low order bits (PADLO). + (PADHI) or low order bits (PADLO). A "C" prefix is used for component-wise + padding in the most high order bits (CPADHI) or low order bits (CPADLO) + of each separate component. For formats where the number of bus samples per pixel is larger than 1, an endianness value stating if the pixel is transferred MSB first (BE) or LSB first (LE). @@ -480,6 +482,36 @@ see . b1 b0 + + MEDIA_BUS_FMT_RGB666_1X24_CPADHI + 0x1015 + + &dash-ent-8; + 0 + 0 + r5 + r4 + r3 + r2 + r1 + r0 + 0 + 0 + g5 + g4 + g3 + g2 + g1 + g0 + 0 + 0 + b5 + b4 + b3 + b2 + b1 + b0 + MEDIA_BUS_FMT_BGR888_1X24 0x1013 diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index 8dbf16cc5d1c..83ea46f4be51 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -33,7 +33,7 @@ #define MEDIA_BUS_FMT_FIXED 0x0001 -/* RGB - next is 0x1015 */ +/* RGB - next is 0x1016 */ #define MEDIA_BUS_FMT_RGB444_1X12 0x100e #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 @@ -45,6 +45,7 @@ #define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007 #define MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008 #define MEDIA_BUS_FMT_RGB666_1X18 0x1009 +#define MEDIA_BUS_FMT_RGB666_1X24_CPADHI 0x1015 #define MEDIA_BUS_FMT_RGB666_1X7X3_SPWG 0x1010 #define MEDIA_BUS_FMT_BGR888_1X24 0x1013 #define MEDIA_BUS_FMT_GBR888_1X24 0x1014 -- cgit v1.2.3 From 2872c8072aae65fa55cafea50e73d69d423df168 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 2 Feb 2015 17:25:59 +0100 Subject: drm/imx: consolidate bus format variable names This patch consolidates the different interface_pix_fmt, pixel_fmt, pix_fmt, and pixfmt variables to a common name "bus_format" wherever they describe the pixel format on the bus between display controller and encoder hardware. At the same time, it renames imx_drm_panel_format to imx_drm_set_bus_format. Signed-off-by: Philipp Zabel Tested-by: Emil Renner Berthing --- drivers/gpu/drm/imx/dw_hdmi-imx.c | 2 +- drivers/gpu/drm/imx/imx-drm-core.c | 14 +++++++------- drivers/gpu/drm/imx/imx-drm.h | 10 +++++----- drivers/gpu/drm/imx/imx-ldb.c | 10 +++++----- drivers/gpu/drm/imx/imx-tve.c | 6 +++--- drivers/gpu/drm/imx/ipuv3-crtc.c | 13 +++++-------- drivers/gpu/drm/imx/parallel-display.c | 13 ++++++------- drivers/gpu/ipu-v3/ipu-dc.c | 4 ++-- include/video/imx-ipu-v3.h | 2 +- 9 files changed, 35 insertions(+), 39 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index 61ef987ec37b..1834ac8998cc 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -123,7 +123,7 @@ static void dw_hdmi_imx_encoder_commit(struct drm_encoder *encoder) static void dw_hdmi_imx_encoder_prepare(struct drm_encoder *encoder) { - imx_drm_panel_format(encoder, MEDIA_BUS_FMT_RGB888_1X24); + imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_RGB888_1X24); } static struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = { diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index a002f53aab0e..c6f2c4723b1b 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -103,8 +103,8 @@ static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc) return NULL; } -int imx_drm_panel_format_pins(struct drm_encoder *encoder, - u32 interface_pix_fmt, int hsync_pin, int vsync_pin) +int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, u32 bus_format, + int hsync_pin, int vsync_pin) { struct imx_drm_crtc_helper_funcs *helper; struct imx_drm_crtc *imx_crtc; @@ -116,16 +116,16 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder, helper = &imx_crtc->imx_drm_helper_funcs; if (helper->set_interface_pix_fmt) return helper->set_interface_pix_fmt(encoder->crtc, - interface_pix_fmt, hsync_pin, vsync_pin); + bus_format, hsync_pin, vsync_pin); return 0; } -EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins); +EXPORT_SYMBOL_GPL(imx_drm_set_bus_format_pins); -int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt) +int imx_drm_set_bus_format(struct drm_encoder *encoder, u32 bus_format) { - return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3); + return imx_drm_set_bus_format_pins(encoder, bus_format, 2, 3); } -EXPORT_SYMBOL_GPL(imx_drm_panel_format); +EXPORT_SYMBOL_GPL(imx_drm_set_bus_format); int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) { diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h index 3c559ccd6af0..28e776d8d9d2 100644 --- a/drivers/gpu/drm/imx/imx-drm.h +++ b/drivers/gpu/drm/imx/imx-drm.h @@ -18,7 +18,7 @@ struct imx_drm_crtc_helper_funcs { int (*enable_vblank)(struct drm_crtc *crtc); void (*disable_vblank)(struct drm_crtc *crtc); int (*set_interface_pix_fmt)(struct drm_crtc *crtc, - u32 pix_fmt, int hsync_pin, int vsync_pin); + u32 bus_format, int hsync_pin, int vsync_pin); const struct drm_crtc_helper_funcs *crtc_helper_funcs; const struct drm_crtc_funcs *crtc_funcs; }; @@ -40,10 +40,10 @@ void imx_drm_mode_config_init(struct drm_device *drm); struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); -int imx_drm_panel_format_pins(struct drm_encoder *encoder, - u32 interface_pix_fmt, int hsync_pin, int vsync_pin); -int imx_drm_panel_format(struct drm_encoder *encoder, - u32 interface_pix_fmt); +int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, + u32 bus_format, int hsync_pin, int vsync_pin); +int imx_drm_set_bus_format(struct drm_encoder *encoder, + u32 bus_format); int imx_drm_encoder_get_mux_id(struct device_node *node, struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index f9ec17a43458..cd062b11a102 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -163,24 +163,24 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) { struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb *ldb = imx_ldb_ch->ldb; - u32 pixel_fmt; + u32 bus_format; switch (imx_ldb_ch->chno) { case 0: - pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH0_24) ? + bus_format = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH0_24) ? MEDIA_BUS_FMT_RGB888_1X24 : MEDIA_BUS_FMT_RGB666_1X18; break; case 1: - pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH1_24) ? + bus_format = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH1_24) ? MEDIA_BUS_FMT_RGB888_1X24 : MEDIA_BUS_FMT_RGB666_1X18; break; default: dev_err(ldb->dev, "unable to config di%d panel format\n", imx_ldb_ch->chno); - pixel_fmt = MEDIA_BUS_FMT_RGB888_1X24; + bus_format = MEDIA_BUS_FMT_RGB888_1X24; } - imx_drm_panel_format(encoder, pixel_fmt); + imx_drm_set_bus_format(encoder, bus_format); } static void imx_ldb_encoder_commit(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index bcdcb1b8f0ba..214eceefc981 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c @@ -301,11 +301,11 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder) switch (tve->mode) { case TVE_MODE_VGA: - imx_drm_panel_format_pins(encoder, MEDIA_BUS_FMT_YUV8_1X24, - tve->hsync_pin, tve->vsync_pin); + imx_drm_set_bus_format_pins(encoder, MEDIA_BUS_FMT_YUV8_1X24, + tve->hsync_pin, tve->vsync_pin); break; case TVE_MODE_TVOUT: - imx_drm_panel_format(encoder, MEDIA_BUS_FMT_YUV8_1X24); + imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_YUV8_1X24); break; } } diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index 4a393f609220..7bc8301fafff 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -45,7 +45,7 @@ struct ipu_crtc { struct drm_pending_vblank_event *page_flip_event; struct drm_framebuffer *newfb; int irq; - u32 interface_pix_fmt; + u32 bus_format; int di_hsync_pin; int di_vsync_pin; }; @@ -145,7 +145,6 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); struct ipu_di_signal_cfg sig_cfg = {}; unsigned long encoder_types = 0; - u32 out_pixel_fmt; int ret; dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, @@ -173,11 +172,9 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, else sig_cfg.clkflags = 0; - out_pixel_fmt = ipu_crtc->interface_pix_fmt; - sig_cfg.enable_pol = 1; sig_cfg.clk_pol = 0; - sig_cfg.pixel_fmt = out_pixel_fmt; + sig_cfg.bus_format = ipu_crtc->bus_format; sig_cfg.v_to_h_sync = 0; sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin; sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin; @@ -186,7 +183,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, mode->flags & DRM_MODE_FLAG_INTERLACE, - out_pixel_fmt, mode->hdisplay); + ipu_crtc->bus_format, mode->hdisplay); if (ret) { dev_err(ipu_crtc->dev, "initializing display controller failed with %d\n", @@ -294,11 +291,11 @@ static void ipu_disable_vblank(struct drm_crtc *crtc) } static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, - u32 pixfmt, int hsync_pin, int vsync_pin) + u32 bus_format, int hsync_pin, int vsync_pin) { struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); - ipu_crtc->interface_pix_fmt = pixfmt; + ipu_crtc->bus_format = bus_format; ipu_crtc->di_hsync_pin = hsync_pin; ipu_crtc->di_vsync_pin = vsync_pin; diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index e645fe18c1a7..74a9ce40ddc4 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -33,7 +33,7 @@ struct imx_parallel_display { struct device *dev; void *edid; int edid_len; - u32 interface_pix_fmt; + u32 bus_format; int mode_valid; struct drm_display_mode mode; struct drm_panel *panel; @@ -118,7 +118,7 @@ static void imx_pd_encoder_prepare(struct drm_encoder *encoder) { struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); - imx_drm_panel_format(encoder, imxpd->interface_pix_fmt); + imx_drm_set_bus_format(encoder, imxpd->bus_format); } static void imx_pd_encoder_commit(struct drm_encoder *encoder) @@ -225,14 +225,13 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) ret = of_property_read_string(np, "interface-pix-fmt", &fmt); if (!ret) { if (!strcmp(fmt, "rgb24")) - imxpd->interface_pix_fmt = MEDIA_BUS_FMT_RGB888_1X24; + imxpd->bus_format = MEDIA_BUS_FMT_RGB888_1X24; else if (!strcmp(fmt, "rgb565")) - imxpd->interface_pix_fmt = MEDIA_BUS_FMT_RGB565_1X16; + imxpd->bus_format = MEDIA_BUS_FMT_RGB565_1X16; else if (!strcmp(fmt, "bgr666")) - imxpd->interface_pix_fmt = MEDIA_BUS_FMT_RGB666_1X18; + imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X18; else if (!strcmp(fmt, "lvds666")) - imxpd->interface_pix_fmt = - MEDIA_BUS_FMT_RGB666_1X24_CPADHI; + imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI; } panel_node = of_parse_phandle(np, "fsl,panel", 0); diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/ipu-v3/ipu-dc.c index 651c20cfe7e1..9ef2e1f54ca4 100644 --- a/drivers/gpu/ipu-v3/ipu-dc.c +++ b/drivers/gpu/ipu-v3/ipu-dc.c @@ -168,7 +168,7 @@ static int ipu_bus_format_to_map(u32 fmt) } int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, - u32 pixel_fmt, u32 width) + u32 bus_format, u32 width) { struct ipu_dc_priv *priv = dc->priv; u32 reg = 0; @@ -176,7 +176,7 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, dc->di = ipu_di_get_num(di); - map = ipu_bus_format_to_map(pixel_fmt); + map = ipu_bus_format_to_map(bus_format); if (map < 0) { dev_dbg(priv->dev, "IPU_DISP: No MAP\n"); return map; diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index 73390c120cad..85dedca3dcfb 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h @@ -39,7 +39,7 @@ struct ipu_di_signal_cfg { struct videomode mode; - u32 pixel_fmt; + u32 bus_format; u32 v_to_h_sync; #define IPU_DI_CLKMODE_SYNC (1 << 0) -- cgit v1.2.3 From 938c470976192590b4adc921b2e10fa31237eddc Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 26 Mar 2015 13:43:04 +0100 Subject: iommu: Introduce domain_alloc and domain_free iommu_ops These new call-backs defer the allocation and destruction of 'struct iommu_domain' to the iommu driver. This allows drivers to embed this struct into their private domain structures and to get rid of the domain_init and domain_destroy call-backs when all drivers have been converted. Tested-by: Thierry Reding Tested-by: Heiko Stuebner Reviewed-by: Alex Williamson Acked-by: Will Deacon Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 29 +++++++++++++++++++++-------- include/linux/iommu.h | 5 +++++ 2 files changed, 26 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 72e683df0731..11de2620bbf4 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -900,26 +900,34 @@ EXPORT_SYMBOL_GPL(iommu_set_fault_handler); struct iommu_domain *iommu_domain_alloc(struct bus_type *bus) { + const struct iommu_ops *ops; struct iommu_domain *domain; - int ret; if (bus == NULL || bus->iommu_ops == NULL) return NULL; - domain = kzalloc(sizeof(*domain), GFP_KERNEL); + ops = bus->iommu_ops; + + if (ops->domain_alloc) + domain = ops->domain_alloc(); + else + domain = kzalloc(sizeof(*domain), GFP_KERNEL); + if (!domain) return NULL; domain->ops = bus->iommu_ops; - ret = domain->ops->domain_init(domain); - if (ret) + if (ops->domain_init && domain->ops->domain_init(domain)) goto out_free; return domain; out_free: - kfree(domain); + if (ops->domain_free) + ops->domain_free(domain); + else + kfree(domain); return NULL; } @@ -927,10 +935,15 @@ EXPORT_SYMBOL_GPL(iommu_domain_alloc); void iommu_domain_free(struct iommu_domain *domain) { - if (likely(domain->ops->domain_destroy != NULL)) - domain->ops->domain_destroy(domain); + const struct iommu_ops *ops = domain->ops; - kfree(domain); + if (likely(ops->domain_destroy != NULL)) + ops->domain_destroy(domain); + + if (ops->domain_free) + ops->domain_free(domain); + else + kfree(domain); } EXPORT_SYMBOL_GPL(iommu_domain_free); diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 38daa453f2e5..69d1d120c0a3 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -115,6 +115,11 @@ struct iommu_ops { bool (*capable)(enum iommu_cap); int (*domain_init)(struct iommu_domain *domain); void (*domain_destroy)(struct iommu_domain *domain); + + /* Domain allocation and freeing by the iommu driver */ + struct iommu_domain *(*domain_alloc)(void); + void (*domain_free)(struct iommu_domain *); + int (*attach_dev)(struct iommu_domain *domain, struct device *dev); void (*detach_dev)(struct iommu_domain *domain, struct device *dev); int (*map)(struct iommu_domain *domain, unsigned long iova, -- cgit v1.2.3 From 8539c7c16b970258e14761d8a1f7d10fe798031a Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 26 Mar 2015 13:43:05 +0100 Subject: iommu: Introduce iommu domain types This allows to handle domains differently based on their type in the future. An IOMMU driver can implement certain optimizations for DMA-API domains for example. The domain types can be extended later and some of the existing domain attributes can be migrated to become domain flags. Tested-by: Thierry Reding Tested-by: Heiko Stuebner Reviewed-by: Alex Williamson Acked-by: Will Deacon Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 5 +++-- include/linux/iommu.h | 27 ++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 11de2620bbf4..4920605892a3 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -909,14 +909,15 @@ struct iommu_domain *iommu_domain_alloc(struct bus_type *bus) ops = bus->iommu_ops; if (ops->domain_alloc) - domain = ops->domain_alloc(); + domain = ops->domain_alloc(IOMMU_DOMAIN_UNMANAGED); else domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return NULL; - domain->ops = bus->iommu_ops; + domain->ops = bus->iommu_ops; + domain->type = IOMMU_DOMAIN_UNMANAGED; if (ops->domain_init && domain->ops->domain_init(domain)) goto out_free; diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 69d1d120c0a3..72d03fe78cf6 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -51,7 +51,32 @@ struct iommu_domain_geometry { bool force_aperture; /* DMA only allowed in mappable range? */ }; +/* Domain feature flags */ +#define __IOMMU_DOMAIN_PAGING (1U << 0) /* Support for iommu_map/unmap */ +#define __IOMMU_DOMAIN_DMA_API (1U << 1) /* Domain for use in DMA-API + implementation */ +#define __IOMMU_DOMAIN_PT (1U << 2) /* Domain is identity mapped */ + +/* + * This are the possible domain-types + * + * IOMMU_DOMAIN_BLOCKED - All DMA is blocked, can be used to isolate + * devices + * IOMMU_DOMAIN_IDENTITY - DMA addresses are system physical addresses + * IOMMU_DOMAIN_UNMANAGED - DMA mappings managed by IOMMU-API user, used + * for VMs + * IOMMU_DOMAIN_DMA - Internally used for DMA-API implementations. + * This flag allows IOMMU drivers to implement + * certain optimizations for these domains + */ +#define IOMMU_DOMAIN_BLOCKED (0U) +#define IOMMU_DOMAIN_IDENTITY (__IOMMU_DOMAIN_PT) +#define IOMMU_DOMAIN_UNMANAGED (__IOMMU_DOMAIN_PAGING) +#define IOMMU_DOMAIN_DMA (__IOMMU_DOMAIN_PAGING | \ + __IOMMU_DOMAIN_DMA_API) + struct iommu_domain { + unsigned type; const struct iommu_ops *ops; void *priv; iommu_fault_handler_t handler; @@ -117,7 +142,7 @@ struct iommu_ops { void (*domain_destroy)(struct iommu_domain *domain); /* Domain allocation and freeing by the iommu driver */ - struct iommu_domain *(*domain_alloc)(void); + struct iommu_domain *(*domain_alloc)(unsigned iommu_domain_type); void (*domain_free)(struct iommu_domain *); int (*attach_dev)(struct iommu_domain *domain, struct device *dev); -- cgit v1.2.3 From 89be34a1ced886880a3219f9d2ba2192dc738ef2 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 26 Mar 2015 13:43:19 +0100 Subject: iommu: Remove domain_init and domain_free iommu_ops All drivers have been converted to the new domain_alloc and domain_free iommu-ops. So remove the old ones and get rid of iommu_domain->priv too, as this is no longer needed when the struct iommu_domain is embedded in the private structures of the iommu drivers. Tested-by: Thierry Reding Tested-by: Heiko Stuebner Reviewed-by: Alex Williamson Acked-by: Will Deacon Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 30 ++---------------------------- include/linux/iommu.h | 3 --- 2 files changed, 2 insertions(+), 31 deletions(-) (limited to 'include') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 656b9499e748..d4f527e56679 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -900,51 +900,25 @@ EXPORT_SYMBOL_GPL(iommu_set_fault_handler); struct iommu_domain *iommu_domain_alloc(struct bus_type *bus) { - const struct iommu_ops *ops; struct iommu_domain *domain; if (bus == NULL || bus->iommu_ops == NULL) return NULL; - ops = bus->iommu_ops; - - if (ops->domain_alloc) - domain = ops->domain_alloc(IOMMU_DOMAIN_UNMANAGED); - else - domain = kzalloc(sizeof(*domain), GFP_KERNEL); - + domain = bus->iommu_ops->domain_alloc(IOMMU_DOMAIN_UNMANAGED); if (!domain) return NULL; domain->ops = bus->iommu_ops; domain->type = IOMMU_DOMAIN_UNMANAGED; - if (ops->domain_init && domain->ops->domain_init(domain)) - goto out_free; - return domain; - -out_free: - if (ops->domain_free) - ops->domain_free(domain); - else - kfree(domain); - - return NULL; } EXPORT_SYMBOL_GPL(iommu_domain_alloc); void iommu_domain_free(struct iommu_domain *domain) { - const struct iommu_ops *ops = domain->ops; - - if (likely(ops->domain_destroy != NULL)) - ops->domain_destroy(domain); - - if (ops->domain_free) - ops->domain_free(domain); - else - kfree(domain); + domain->ops->domain_free(domain); } EXPORT_SYMBOL_GPL(iommu_domain_free); diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 72d03fe78cf6..0546b8710ce3 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -78,7 +78,6 @@ struct iommu_domain_geometry { struct iommu_domain { unsigned type; const struct iommu_ops *ops; - void *priv; iommu_fault_handler_t handler; void *handler_token; struct iommu_domain_geometry geometry; @@ -138,8 +137,6 @@ enum iommu_attr { */ struct iommu_ops { bool (*capable)(enum iommu_cap); - int (*domain_init)(struct iommu_domain *domain); - void (*domain_destroy)(struct iommu_domain *domain); /* Domain allocation and freeing by the iommu driver */ struct iommu_domain *(*domain_alloc)(unsigned iommu_domain_type); -- cgit v1.2.3 From dbbc14775ae395a50d91f22904670ca4c9297542 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 30 Mar 2015 14:33:33 -0400 Subject: SUNRPC: Introduce missing well-known netids Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- include/linux/sunrpc/msg_prot.h | 8 +++++++- include/linux/sunrpc/xprtrdma.h | 5 ----- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h index aadc6a04e1ac..807371357160 100644 --- a/include/linux/sunrpc/msg_prot.h +++ b/include/linux/sunrpc/msg_prot.h @@ -142,12 +142,18 @@ typedef __be32 rpc_fraghdr; (RPC_REPHDRSIZE + (2 + RPC_MAX_AUTH_SIZE/4)) /* - * RFC1833/RFC3530 rpcbind (v3+) well-known netid's. + * Well-known netids. See: + * + * http://www.iana.org/assignments/rpc-netids/rpc-netids.xhtml */ #define RPCBIND_NETID_UDP "udp" #define RPCBIND_NETID_TCP "tcp" +#define RPCBIND_NETID_RDMA "rdma" +#define RPCBIND_NETID_SCTP "sctp" #define RPCBIND_NETID_UDP6 "udp6" #define RPCBIND_NETID_TCP6 "tcp6" +#define RPCBIND_NETID_RDMA6 "rdma6" +#define RPCBIND_NETID_SCTP6 "sctp6" #define RPCBIND_NETID_LOCAL "local" /* diff --git a/include/linux/sunrpc/xprtrdma.h b/include/linux/sunrpc/xprtrdma.h index 64a0a0a97b23..c984c85981ea 100644 --- a/include/linux/sunrpc/xprtrdma.h +++ b/include/linux/sunrpc/xprtrdma.h @@ -40,11 +40,6 @@ #ifndef _LINUX_SUNRPC_XPRTRDMA_H #define _LINUX_SUNRPC_XPRTRDMA_H -/* - * rpcbind (v3+) RDMA netid. - */ -#define RPCBIND_NETID_RDMA "rdma" - /* * Constants. Max RPC/NFS header is big enough to account for * additional marshaling buffers passed down by Linux client. -- cgit v1.2.3 From 52b09914af86fa3e728175c1125c91520e437b2f Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Mon, 23 Feb 2015 16:36:41 -0500 Subject: dm: remove unnecessary wrapper around blk_lld_busy There is no need for DM to export a wrapper around the already exported blk_lld_busy(). Signed-off-by: Mike Snitzer --- drivers/md/dm-mpath.c | 2 +- drivers/md/dm.c | 6 ------ include/linux/device-mapper.h | 5 ----- 3 files changed, 1 insertion(+), 12 deletions(-) (limited to 'include') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index d376dc87716e..add6391f3f8e 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1627,7 +1627,7 @@ static int __pgpath_busy(struct pgpath *pgpath) { struct request_queue *q = bdev_get_queue(pgpath->path.dev->bdev); - return dm_underlying_device_busy(q); + return blk_lld_busy(q); } /* diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 0e5f3441fcda..e7095ebb8d64 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -2006,12 +2006,6 @@ out: dm_put_live_table(md, srcu_idx); } -int dm_underlying_device_busy(struct request_queue *q) -{ - return blk_lld_busy(q); -} -EXPORT_SYMBOL_GPL(dm_underlying_device_busy); - static int dm_lld_busy(struct request_queue *q) { int r; diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index fd23978d93fe..51cc1deb7af3 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -605,9 +605,4 @@ static inline unsigned long to_bytes(sector_t n) return (n << SECTOR_SHIFT); } -/*----------------------------------------------------------------- - * Helper for block layer and dm core operations - *---------------------------------------------------------------*/ -int dm_underlying_device_busy(struct request_queue *q); - #endif /* _LINUX_DEVICE_MAPPER_H */ -- cgit v1.2.3 From d894fc6046fecd66b0d8ec35c7d2515781cc030b Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 18 Mar 2015 16:16:36 +0000 Subject: dmaengine: jz4780: add driver for the Ingenic JZ4780 DMA controller This patch adds a driver for the DMA controller found in the Ingenic JZ4780. It currently does not implement any support for the programmable firmware feature of the controller - this is not necessary for most uses. It also does not take priority into account when allocating channels, it just allocates the first available channel. This can be implemented later. Signed-off-by: Alex Smith Signed-off-by: Zubair Lutfullah Kakakhel [Updated for dmaengine api changes, Add residue support, couple of minor fixes] Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 10 + drivers/dma/Makefile | 1 + drivers/dma/dma-jz4780.c | 877 +++++++++++++++++++++++++++++++++++ include/dt-bindings/dma/jz4780-dma.h | 49 ++ 4 files changed, 937 insertions(+) create mode 100644 drivers/dma/dma-jz4780.c create mode 100644 include/dt-bindings/dma/jz4780-dma.h (limited to 'include') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index a874b6ec6650..ce09734248da 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -358,6 +358,16 @@ config DMA_JZ4740 select DMA_ENGINE select DMA_VIRTUAL_CHANNELS +config DMA_JZ4780 + tristate "JZ4780 DMA support" + depends on MACH_JZ4780 + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + This selects support for the DMA controller in Ingenic JZ4780 SoCs. + If you have a board based on such a SoC and wish to use DMA for + devices which can use the DMA controller, say Y or M here. + config K3_DMA tristate "Hisilicon K3 DMA support" depends on ARCH_HI3xxx diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index f915f61ec574..af239e765cbb 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_DMA_OMAP) += omap-dma.o obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o +obj-$(CONFIG_DMA_JZ4780) += dma-jz4780.o obj-$(CONFIG_TI_CPPI41) += cppi41.o obj-$(CONFIG_K3_DMA) += k3dma.o obj-$(CONFIG_MOXART_DMA) += moxart-dma.o diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c new file mode 100644 index 000000000000..26d2f0e09ea3 --- /dev/null +++ b/drivers/dma/dma-jz4780.c @@ -0,0 +1,877 @@ +/* + * Ingenic JZ4780 DMA controller + * + * Copyright (c) 2015 Imagination Technologies + * Author: Alex Smith + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dmaengine.h" +#include "virt-dma.h" + +#define JZ_DMA_NR_CHANNELS 32 + +/* Global registers. */ +#define JZ_DMA_REG_DMAC 0x1000 +#define JZ_DMA_REG_DIRQP 0x1004 +#define JZ_DMA_REG_DDR 0x1008 +#define JZ_DMA_REG_DDRS 0x100c +#define JZ_DMA_REG_DMACP 0x101c +#define JZ_DMA_REG_DSIRQP 0x1020 +#define JZ_DMA_REG_DSIRQM 0x1024 +#define JZ_DMA_REG_DCIRQP 0x1028 +#define JZ_DMA_REG_DCIRQM 0x102c + +/* Per-channel registers. */ +#define JZ_DMA_REG_CHAN(n) (n * 0x20) +#define JZ_DMA_REG_DSA(n) (0x00 + JZ_DMA_REG_CHAN(n)) +#define JZ_DMA_REG_DTA(n) (0x04 + JZ_DMA_REG_CHAN(n)) +#define JZ_DMA_REG_DTC(n) (0x08 + JZ_DMA_REG_CHAN(n)) +#define JZ_DMA_REG_DRT(n) (0x0c + JZ_DMA_REG_CHAN(n)) +#define JZ_DMA_REG_DCS(n) (0x10 + JZ_DMA_REG_CHAN(n)) +#define JZ_DMA_REG_DCM(n) (0x14 + JZ_DMA_REG_CHAN(n)) +#define JZ_DMA_REG_DDA(n) (0x18 + JZ_DMA_REG_CHAN(n)) +#define JZ_DMA_REG_DSD(n) (0x1c + JZ_DMA_REG_CHAN(n)) + +#define JZ_DMA_DMAC_DMAE BIT(0) +#define JZ_DMA_DMAC_AR BIT(2) +#define JZ_DMA_DMAC_HLT BIT(3) +#define JZ_DMA_DMAC_FMSC BIT(31) + +#define JZ_DMA_DRT_AUTO 0x8 + +#define JZ_DMA_DCS_CTE BIT(0) +#define JZ_DMA_DCS_HLT BIT(2) +#define JZ_DMA_DCS_TT BIT(3) +#define JZ_DMA_DCS_AR BIT(4) +#define JZ_DMA_DCS_DES8 BIT(30) + +#define JZ_DMA_DCM_LINK BIT(0) +#define JZ_DMA_DCM_TIE BIT(1) +#define JZ_DMA_DCM_STDE BIT(2) +#define JZ_DMA_DCM_TSZ_SHIFT 8 +#define JZ_DMA_DCM_TSZ_MASK (0x7 << JZ_DMA_DCM_TSZ_SHIFT) +#define JZ_DMA_DCM_DP_SHIFT 12 +#define JZ_DMA_DCM_SP_SHIFT 14 +#define JZ_DMA_DCM_DAI BIT(22) +#define JZ_DMA_DCM_SAI BIT(23) + +#define JZ_DMA_SIZE_4_BYTE 0x0 +#define JZ_DMA_SIZE_1_BYTE 0x1 +#define JZ_DMA_SIZE_2_BYTE 0x2 +#define JZ_DMA_SIZE_16_BYTE 0x3 +#define JZ_DMA_SIZE_32_BYTE 0x4 +#define JZ_DMA_SIZE_64_BYTE 0x5 +#define JZ_DMA_SIZE_128_BYTE 0x6 + +#define JZ_DMA_WIDTH_32_BIT 0x0 +#define JZ_DMA_WIDTH_8_BIT 0x1 +#define JZ_DMA_WIDTH_16_BIT 0x2 + +#define JZ_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)) + +/** + * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller. + * @dcm: value for the DCM (channel command) register + * @dsa: source address + * @dta: target address + * @dtc: transfer count (number of blocks of the transfer size specified in DCM + * to transfer) in the low 24 bits, offset of the next descriptor from the + * descriptor base address in the upper 8 bits. + * @sd: target/source stride difference (in stride transfer mode). + * @drt: request type + */ +struct jz4780_dma_hwdesc { + uint32_t dcm; + uint32_t dsa; + uint32_t dta; + uint32_t dtc; + uint32_t sd; + uint32_t drt; + uint32_t reserved[2]; +}; + +/* Size of allocations for hardware descriptor blocks. */ +#define JZ_DMA_DESC_BLOCK_SIZE PAGE_SIZE +#define JZ_DMA_MAX_DESC \ + (JZ_DMA_DESC_BLOCK_SIZE / sizeof(struct jz4780_dma_hwdesc)) + +struct jz4780_dma_desc { + struct virt_dma_desc vdesc; + + struct jz4780_dma_hwdesc *desc; + dma_addr_t desc_phys; + unsigned int count; + enum dma_transaction_type type; + uint32_t status; +}; + +struct jz4780_dma_chan { + struct virt_dma_chan vchan; + unsigned int id; + struct dma_pool *desc_pool; + + uint32_t transfer_type; + uint32_t transfer_shift; + struct dma_slave_config config; + + struct jz4780_dma_desc *desc; + unsigned int curr_hwdesc; +}; + +struct jz4780_dma_dev { + struct dma_device dma_device; + void __iomem *base; + struct clk *clk; + unsigned int irq; + + uint32_t chan_reserved; + struct jz4780_dma_chan chan[JZ_DMA_NR_CHANNELS]; +}; + +struct jz4780_dma_data { + uint32_t transfer_type; + int channel; +}; + +static inline struct jz4780_dma_chan *to_jz4780_dma_chan(struct dma_chan *chan) +{ + return container_of(chan, struct jz4780_dma_chan, vchan.chan); +} + +static inline struct jz4780_dma_desc *to_jz4780_dma_desc( + struct virt_dma_desc *vdesc) +{ + return container_of(vdesc, struct jz4780_dma_desc, vdesc); +} + +static inline struct jz4780_dma_dev *jz4780_dma_chan_parent( + struct jz4780_dma_chan *jzchan) +{ + return container_of(jzchan->vchan.chan.device, struct jz4780_dma_dev, + dma_device); +} + +static inline uint32_t jz4780_dma_readl(struct jz4780_dma_dev *jzdma, + unsigned int reg) +{ + return readl(jzdma->base + reg); +} + +static inline void jz4780_dma_writel(struct jz4780_dma_dev *jzdma, + unsigned int reg, uint32_t val) +{ + writel(val, jzdma->base + reg); +} + +static struct jz4780_dma_desc *jz4780_dma_desc_alloc( + struct jz4780_dma_chan *jzchan, unsigned int count, + enum dma_transaction_type type) +{ + struct jz4780_dma_desc *desc; + + if (count > JZ_DMA_MAX_DESC) + return NULL; + + desc = kzalloc(sizeof(*desc), GFP_NOWAIT); + if (!desc) + return NULL; + + desc->desc = dma_pool_alloc(jzchan->desc_pool, GFP_NOWAIT, + &desc->desc_phys); + if (!desc->desc) { + kfree(desc); + return NULL; + } + + desc->count = count; + desc->type = type; + return desc; +} + +static void jz4780_dma_desc_free(struct virt_dma_desc *vdesc) +{ + struct jz4780_dma_desc *desc = to_jz4780_dma_desc(vdesc); + struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(vdesc->tx.chan); + + dma_pool_free(jzchan->desc_pool, desc->desc, desc->desc_phys); + kfree(desc); +} + +static uint32_t jz4780_dma_transfer_size(unsigned long val, int *ord) +{ + *ord = ffs(val) - 1; + + switch (*ord) { + case 0: + return JZ_DMA_SIZE_1_BYTE; + case 1: + return JZ_DMA_SIZE_2_BYTE; + case 2: + return JZ_DMA_SIZE_4_BYTE; + case 4: + return JZ_DMA_SIZE_16_BYTE; + case 5: + return JZ_DMA_SIZE_32_BYTE; + case 6: + return JZ_DMA_SIZE_64_BYTE; + case 7: + return JZ_DMA_SIZE_128_BYTE; + default: + return -EINVAL; + } +} + +static uint32_t jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan, + struct jz4780_dma_hwdesc *desc, dma_addr_t addr, size_t len, + enum dma_transfer_direction direction) +{ + struct dma_slave_config *config = &jzchan->config; + uint32_t width, maxburst, tsz; + int ord; + + if (direction == DMA_MEM_TO_DEV) { + desc->dcm = JZ_DMA_DCM_SAI; + desc->dsa = addr; + desc->dta = config->dst_addr; + desc->drt = jzchan->transfer_type; + + width = config->dst_addr_width; + maxburst = config->dst_maxburst; + } else { + desc->dcm = JZ_DMA_DCM_DAI; + desc->dsa = config->src_addr; + desc->dta = addr; + desc->drt = jzchan->transfer_type; + + width = config->src_addr_width; + maxburst = config->src_maxburst; + } + + /* + * This calculates the maximum transfer size that can be used with the + * given address, length, width and maximum burst size. The address + * must be aligned to the transfer size, the total length must be + * divisible by the transfer size, and we must not use more than the + * maximum burst specified by the user. + */ + tsz = jz4780_dma_transfer_size(addr | len | (width * maxburst), &ord); + jzchan->transfer_shift = ord; + + switch (width) { + case DMA_SLAVE_BUSWIDTH_1_BYTE: + case DMA_SLAVE_BUSWIDTH_2_BYTES: + break; + case DMA_SLAVE_BUSWIDTH_4_BYTES: + width = JZ_DMA_WIDTH_32_BIT; + break; + default: + return -EINVAL; + } + + desc->dcm |= tsz << JZ_DMA_DCM_TSZ_SHIFT; + desc->dcm |= width << JZ_DMA_DCM_SP_SHIFT; + desc->dcm |= width << JZ_DMA_DCM_DP_SHIFT; + + desc->dtc = len >> ord; +} + +static struct dma_async_tx_descriptor *jz4780_dma_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, + enum dma_transfer_direction direction, unsigned long flags) +{ + struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); + struct jz4780_dma_desc *desc; + unsigned int i; + int err; + + desc = jz4780_dma_desc_alloc(jzchan, sg_len, DMA_SLAVE); + if (!desc) + return NULL; + + for (i = 0; i < sg_len; i++) { + err = jz4780_dma_setup_hwdesc(jzchan, &desc->desc[i], + sg_dma_address(&sgl[i]), + sg_dma_len(&sgl[i]), + direction); + if (err < 0) + return ERR_PTR(err); + + + desc->desc[i].dcm |= JZ_DMA_DCM_TIE; + + if (i != (sg_len - 1)) { + /* Automatically proceeed to the next descriptor. */ + desc->desc[i].dcm |= JZ_DMA_DCM_LINK; + + /* + * The upper 8 bits of the DTC field in the descriptor + * must be set to (offset from descriptor base of next + * descriptor >> 4). + */ + desc->desc[i].dtc |= + (((i + 1) * sizeof(*desc->desc)) >> 4) << 24; + } + } + + return vchan_tx_prep(&jzchan->vchan, &desc->vdesc, flags); +} + +static struct dma_async_tx_descriptor *jz4780_dma_prep_dma_cyclic( + struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, + size_t period_len, enum dma_transfer_direction direction, + unsigned long flags) +{ + struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); + struct jz4780_dma_desc *desc; + unsigned int periods, i; + int err; + + if (buf_len % period_len) + return NULL; + + periods = buf_len / period_len; + + desc = jz4780_dma_desc_alloc(jzchan, periods, DMA_CYCLIC); + if (!desc) + return NULL; + + for (i = 0; i < periods; i++) { + err = jz4780_dma_setup_hwdesc(jzchan, &desc->desc[i], buf_addr, + period_len, direction); + if (err < 0) + return ERR_PTR(err); + + buf_addr += period_len; + + /* + * Set the link bit to indicate that the controller should + * automatically proceed to the next descriptor. In + * jz4780_dma_begin(), this will be cleared if we need to issue + * an interrupt after each period. + */ + desc->desc[i].dcm |= JZ_DMA_DCM_TIE | JZ_DMA_DCM_LINK; + + /* + * The upper 8 bits of the DTC field in the descriptor must be + * set to (offset from descriptor base of next descriptor >> 4). + * If this is the last descriptor, link it back to the first, + * i.e. leave offset set to 0, otherwise point to the next one. + */ + if (i != (periods - 1)) { + desc->desc[i].dtc |= + (((i + 1) * sizeof(*desc->desc)) >> 4) << 24; + } + } + + return vchan_tx_prep(&jzchan->vchan, &desc->vdesc, flags); +} + +struct dma_async_tx_descriptor *jz4780_dma_prep_dma_memcpy( + struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, + size_t len, unsigned long flags) +{ + struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); + struct jz4780_dma_desc *desc; + uint32_t tsz; + int ord; + + desc = jz4780_dma_desc_alloc(jzchan, 1, DMA_MEMCPY); + if (!desc) + return NULL; + + tsz = jz4780_dma_transfer_size(dest | src | len, &ord); + if (tsz < 0) + return ERR_PTR(tsz); + + desc->desc[0].dsa = src; + desc->desc[0].dta = dest; + desc->desc[0].drt = JZ_DMA_DRT_AUTO; + desc->desc[0].dcm = JZ_DMA_DCM_TIE | JZ_DMA_DCM_SAI | JZ_DMA_DCM_DAI | + tsz << JZ_DMA_DCM_TSZ_SHIFT | + JZ_DMA_WIDTH_32_BIT << JZ_DMA_DCM_SP_SHIFT | + JZ_DMA_WIDTH_32_BIT << JZ_DMA_DCM_DP_SHIFT; + desc->desc[0].dtc = len >> ord; + + return vchan_tx_prep(&jzchan->vchan, &desc->vdesc, flags); +} + +static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan) +{ + struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); + struct virt_dma_desc *vdesc; + unsigned int i; + dma_addr_t desc_phys; + + if (!jzchan->desc) { + vdesc = vchan_next_desc(&jzchan->vchan); + if (!vdesc) + return; + + list_del(&vdesc->node); + + jzchan->desc = to_jz4780_dma_desc(vdesc); + jzchan->curr_hwdesc = 0; + + if (jzchan->desc->type == DMA_CYCLIC && vdesc->tx.callback) { + /* + * The DMA controller doesn't support triggering an + * interrupt after processing each descriptor, only + * after processing an entire terminated list of + * descriptors. For a cyclic DMA setup the list of + * descriptors is not terminated so we can never get an + * interrupt. + * + * If the user requested a callback for a cyclic DMA + * setup then we workaround this hardware limitation + * here by degrading to a set of unlinked descriptors + * which we will submit in sequence in response to the + * completion of processing the previous descriptor. + */ + for (i = 0; i < jzchan->desc->count; i++) + jzchan->desc->desc[i].dcm &= ~JZ_DMA_DCM_LINK; + } + } else { + /* + * There is an existing transfer, therefore this must be one + * for which we unlinked the descriptors above. Advance to the + * next one in the list. + */ + jzchan->curr_hwdesc = + (jzchan->curr_hwdesc + 1) % jzchan->desc->count; + } + + /* Use 8-word descriptors. */ + jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), JZ_DMA_DCS_DES8); + + /* Write descriptor address and initiate descriptor fetch. */ + desc_phys = jzchan->desc->desc_phys + + (jzchan->curr_hwdesc * sizeof(*jzchan->desc->desc)); + jz4780_dma_writel(jzdma, JZ_DMA_REG_DDA(jzchan->id), desc_phys); + jz4780_dma_writel(jzdma, JZ_DMA_REG_DDRS, BIT(jzchan->id)); + + /* Enable the channel. */ + jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), + JZ_DMA_DCS_DES8 | JZ_DMA_DCS_CTE); +} + +static void jz4780_dma_issue_pending(struct dma_chan *chan) +{ + struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&jzchan->vchan.lock, flags); + + if (vchan_issue_pending(&jzchan->vchan) && !jzchan->desc) + jz4780_dma_begin(jzchan); + + spin_unlock_irqrestore(&jzchan->vchan.lock, flags); +} + +static int jz4780_dma_terminate_all(struct jz4780_dma_chan *jzchan) +{ + struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); + unsigned long flags; + LIST_HEAD(head); + + spin_lock_irqsave(&jzchan->vchan.lock, flags); + + /* Clear the DMA status and stop the transfer. */ + jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), 0); + if (jzchan->desc) { + jz4780_dma_desc_free(&jzchan->desc->vdesc); + jzchan->desc = NULL; + } + + vchan_get_all_descriptors(&jzchan->vchan, &head); + + spin_unlock_irqrestore(&jzchan->vchan.lock, flags); + + vchan_dma_desc_free_list(&jzchan->vchan, &head); + return 0; +} + +static int jz4780_dma_slave_config(struct jz4780_dma_chan *jzchan, + const struct dma_slave_config *config) +{ + if ((config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) + || (config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)) + return -EINVAL; + + /* Copy the reset of the slave configuration, it is used later. */ + memcpy(&jzchan->config, config, sizeof(jzchan->config)); + + return 0; +} + +static size_t jz4780_dma_desc_residue(struct jz4780_dma_chan *jzchan, + struct jz4780_dma_desc *desc, unsigned int next_sg) +{ + struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); + unsigned int residue, count; + unsigned int i; + + residue = 0; + + for (i = next_sg; i < desc->count; i++) + residue += desc->desc[i].dtc << jzchan->transfer_shift; + + if (next_sg != 0) { + count = jz4780_dma_readl(jzdma, + JZ_DMA_REG_DTC(jzchan->id)); + residue += count << jzchan->transfer_shift; + } + + return residue; +} + +static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *txstate) +{ + struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); + struct virt_dma_desc *vdesc; + enum dma_status status; + unsigned long flags; + + status = dma_cookie_status(chan, cookie, txstate); + if ((status == DMA_COMPLETE) || (txstate == NULL)) + return status; + + spin_lock_irqsave(&jzchan->vchan.lock, flags); + + vdesc = vchan_find_desc(&jzchan->vchan, cookie); + if (vdesc) { + /* On the issued list, so hasn't been processed yet */ + txstate->residue = jz4780_dma_desc_residue(jzchan, + to_jz4780_dma_desc(vdesc), 0); + } else if (cookie == jzchan->desc->vdesc.tx.cookie) { + txstate->residue = jz4780_dma_desc_residue(jzchan, jzchan->desc, + (jzchan->curr_hwdesc + 1) % jzchan->desc->count); + } else + txstate->residue = 0; + + if (vdesc && jzchan->desc && vdesc == &jzchan->desc->vdesc + && jzchan->desc->status & (JZ_DMA_DCS_AR | JZ_DMA_DCS_HLT)) + status = DMA_ERROR; + + spin_unlock_irqrestore(&jzchan->vchan.lock, flags); + return status; +} + +static void jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma, + struct jz4780_dma_chan *jzchan) +{ + uint32_t dcs; + + spin_lock(&jzchan->vchan.lock); + + dcs = jz4780_dma_readl(jzdma, JZ_DMA_REG_DCS(jzchan->id)); + jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), 0); + + if (dcs & JZ_DMA_DCS_AR) { + dev_warn(&jzchan->vchan.chan.dev->device, + "address error (DCS=0x%x)\n", dcs); + } + + if (dcs & JZ_DMA_DCS_HLT) { + dev_warn(&jzchan->vchan.chan.dev->device, + "channel halt (DCS=0x%x)\n", dcs); + } + + if (jzchan->desc) { + jzchan->desc->status = dcs; + + if ((dcs & (JZ_DMA_DCS_AR | JZ_DMA_DCS_HLT)) == 0) { + if (jzchan->desc->type == DMA_CYCLIC) { + vchan_cyclic_callback(&jzchan->desc->vdesc); + } else { + vchan_cookie_complete(&jzchan->desc->vdesc); + jzchan->desc = NULL; + } + + jz4780_dma_begin(jzchan); + } + } else { + dev_err(&jzchan->vchan.chan.dev->device, + "channel IRQ with no active transfer\n"); + } + + spin_unlock(&jzchan->vchan.lock); +} + +static irqreturn_t jz4780_dma_irq_handler(int irq, void *data) +{ + struct jz4780_dma_dev *jzdma = data; + uint32_t pending, dmac; + int i; + + pending = jz4780_dma_readl(jzdma, JZ_DMA_REG_DIRQP); + + for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) { + if (!(pending & (1<chan[i]); + } + + /* Clear halt and address error status of all channels. */ + dmac = jz4780_dma_readl(jzdma, JZ_DMA_REG_DMAC); + dmac &= ~(JZ_DMA_DMAC_HLT | JZ_DMA_DMAC_AR); + jz4780_dma_writel(jzdma, JZ_DMA_REG_DMAC, dmac); + + /* Clear interrupt pending status. */ + jz4780_dma_writel(jzdma, JZ_DMA_REG_DIRQP, 0); + + return IRQ_HANDLED; +} + +static int jz4780_dma_alloc_chan_resources(struct dma_chan *chan) +{ + struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); + + jzchan->desc_pool = dma_pool_create(dev_name(&chan->dev->device), + chan->device->dev, + JZ_DMA_DESC_BLOCK_SIZE, + PAGE_SIZE, 0); + if (!jzchan->desc_pool) { + dev_err(&chan->dev->device, + "failed to allocate descriptor pool\n"); + return -ENOMEM; + } + + return 0; +} + +static void jz4780_dma_free_chan_resources(struct dma_chan *chan) +{ + struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); + + vchan_free_chan_resources(&jzchan->vchan); + dma_pool_destroy(jzchan->desc_pool); + jzchan->desc_pool = NULL; +} + +static bool jz4780_dma_filter_fn(struct dma_chan *chan, void *param) +{ + struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); + struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan); + struct jz4780_dma_data *data = param; + + if (data->channel > -1) { + if (data->channel != jzchan->id) + return false; + } else if (jzdma->chan_reserved & BIT(jzchan->id)) { + return false; + } + + jzchan->transfer_type = data->transfer_type; + + return true; +} + +static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct jz4780_dma_dev *jzdma = ofdma->of_dma_data; + dma_cap_mask_t mask = jzdma->dma_device.cap_mask; + struct jz4780_dma_data data; + + if (dma_spec->args_count != 2) + return NULL; + + data.transfer_type = dma_spec->args[0]; + data.channel = dma_spec->args[1]; + + if (data.channel > -1) { + if (data.channel >= JZ_DMA_NR_CHANNELS) { + dev_err(jzdma->dma_device.dev, + "device requested non-existent channel %u\n", + data.channel); + return NULL; + } + + /* Can only select a channel marked as reserved. */ + if (!(jzdma->chan_reserved & BIT(data.channel))) { + dev_err(jzdma->dma_device.dev, + "device requested unreserved channel %u\n", + data.channel); + return NULL; + } + } + + return dma_request_channel(mask, jz4780_dma_filter_fn, &data); +} + +static int jz4780_dma_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct jz4780_dma_dev *jzdma; + struct jz4780_dma_chan *jzchan; + struct dma_device *dd; + struct resource *res; + int i, ret; + + jzdma = devm_kzalloc(dev, sizeof(*jzdma), GFP_KERNEL); + if (!jzdma) + return -ENOMEM; + + platform_set_drvdata(pdev, jzdma); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "failed to get I/O memory\n"); + return -EINVAL; + } + + jzdma->base = devm_ioremap_resource(dev, res); + if (IS_ERR(jzdma->base)) + return PTR_ERR(jzdma->base); + + jzdma->irq = platform_get_irq(pdev, 0); + if (jzdma->irq < 0) { + dev_err(dev, "failed to get IRQ: %d\n", ret); + return jzdma->irq; + } + + ret = devm_request_irq(dev, jzdma->irq, jz4780_dma_irq_handler, 0, + dev_name(dev), jzdma); + if (ret) { + dev_err(dev, "failed to request IRQ %u!\n", jzdma->irq); + return -EINVAL; + } + + jzdma->clk = devm_clk_get(dev, NULL); + if (IS_ERR(jzdma->clk)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(jzdma->clk); + } + + clk_prepare_enable(jzdma->clk); + + /* Property is optional, if it doesn't exist the value will remain 0. */ + of_property_read_u32_index(dev->of_node, "ingenic,reserved-channels", + 0, &jzdma->chan_reserved); + + dd = &jzdma->dma_device; + + dma_cap_set(DMA_MEMCPY, dd->cap_mask); + dma_cap_set(DMA_SLAVE, dd->cap_mask); + dma_cap_set(DMA_CYCLIC, dd->cap_mask); + + dd->dev = dev; + dd->copy_align = 2; /* 2^2 = 4 byte alignment */ + dd->device_alloc_chan_resources = jz4780_dma_alloc_chan_resources; + dd->device_free_chan_resources = jz4780_dma_free_chan_resources; + dd->device_prep_slave_sg = jz4780_dma_prep_slave_sg; + dd->device_prep_dma_cyclic = jz4780_dma_prep_dma_cyclic; + dd->device_prep_dma_memcpy = jz4780_dma_prep_dma_memcpy; + dd->device_config = jz4780_dma_slave_config; + dd->device_terminate_all = jz4780_dma_terminate_all; + dd->device_tx_status = jz4780_dma_tx_status; + dd->device_issue_pending = jz4780_dma_issue_pending; + dd->src_addr_widths = JZ_DMA_BUSWIDTHS; + dd->dst_addr_widths = JZ_DMA_BUSWIDTHS; + dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + + + /* + * Enable DMA controller, mark all channels as not programmable. + * Also set the FMSC bit - it increases MSC performance, so it makes + * little sense not to enable it. + */ + jz4780_dma_writel(jzdma, JZ_DMA_REG_DMAC, + JZ_DMA_DMAC_DMAE | JZ_DMA_DMAC_FMSC); + jz4780_dma_writel(jzdma, JZ_DMA_REG_DMACP, 0); + + INIT_LIST_HEAD(&dd->channels); + + for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) { + jzchan = &jzdma->chan[i]; + jzchan->id = i; + + vchan_init(&jzchan->vchan, dd); + jzchan->vchan.desc_free = jz4780_dma_desc_free; + } + + ret = dma_async_device_register(dd); + if (ret) { + dev_err(dev, "failed to register device\n"); + goto err_disable_clk; + } + + /* Register with OF DMA helpers. */ + ret = of_dma_controller_register(dev->of_node, jz4780_of_dma_xlate, + jzdma); + if (ret) { + dev_err(dev, "failed to register OF DMA controller\n"); + goto err_unregister_dev; + } + + dev_info(dev, "JZ4780 DMA controller initialised\n"); + return 0; + +err_unregister_dev: + dma_async_device_unregister(dd); + +err_disable_clk: + clk_disable_unprepare(jzdma->clk); + return ret; +} + +static int jz4780_dma_remove(struct platform_device *pdev) +{ + struct jz4780_dma_dev *jzdma = platform_get_drvdata(pdev); + + of_dma_controller_free(pdev->dev.of_node); + devm_free_irq(&pdev->dev, jzdma->irq, jzdma); + dma_async_device_unregister(&jzdma->dma_device); + return 0; +} + +static const struct of_device_id jz4780_dma_dt_match[] = { + { .compatible = "ingenic,jz4780-dma", .data = NULL }, + {}, +}; +MODULE_DEVICE_TABLE(of, jz4780_dma_dt_match); + +static struct platform_driver jz4780_dma_driver = { + .probe = jz4780_dma_probe, + .remove = jz4780_dma_remove, + .driver = { + .name = "jz4780-dma", + .of_match_table = of_match_ptr(jz4780_dma_dt_match), + }, +}; + +static int __init jz4780_dma_init(void) +{ + return platform_driver_register(&jz4780_dma_driver); +} +subsys_initcall(jz4780_dma_init); + +static void __exit jz4780_dma_exit(void) +{ + platform_driver_unregister(&jz4780_dma_driver); +} +module_exit(jz4780_dma_exit); + +MODULE_AUTHOR("Alex Smith "); +MODULE_DESCRIPTION("Ingenic JZ4780 DMA controller driver"); +MODULE_LICENSE("GPL"); diff --git a/include/dt-bindings/dma/jz4780-dma.h b/include/dt-bindings/dma/jz4780-dma.h new file mode 100644 index 000000000000..df017fdfb44e --- /dev/null +++ b/include/dt-bindings/dma/jz4780-dma.h @@ -0,0 +1,49 @@ +#ifndef __DT_BINDINGS_DMA_JZ4780_DMA_H__ +#define __DT_BINDINGS_DMA_JZ4780_DMA_H__ + +/* + * Request type numbers for the JZ4780 DMA controller (written to the DRTn + * register for the channel). + */ +#define JZ4780_DMA_I2S1_TX 0x4 +#define JZ4780_DMA_I2S1_RX 0x5 +#define JZ4780_DMA_I2S0_TX 0x6 +#define JZ4780_DMA_I2S0_RX 0x7 +#define JZ4780_DMA_AUTO 0x8 +#define JZ4780_DMA_SADC_RX 0x9 +#define JZ4780_DMA_UART4_TX 0xc +#define JZ4780_DMA_UART4_RX 0xd +#define JZ4780_DMA_UART3_TX 0xe +#define JZ4780_DMA_UART3_RX 0xf +#define JZ4780_DMA_UART2_TX 0x10 +#define JZ4780_DMA_UART2_RX 0x11 +#define JZ4780_DMA_UART1_TX 0x12 +#define JZ4780_DMA_UART1_RX 0x13 +#define JZ4780_DMA_UART0_TX 0x14 +#define JZ4780_DMA_UART0_RX 0x15 +#define JZ4780_DMA_SSI0_TX 0x16 +#define JZ4780_DMA_SSI0_RX 0x17 +#define JZ4780_DMA_SSI1_TX 0x18 +#define JZ4780_DMA_SSI1_RX 0x19 +#define JZ4780_DMA_MSC0_TX 0x1a +#define JZ4780_DMA_MSC0_RX 0x1b +#define JZ4780_DMA_MSC1_TX 0x1c +#define JZ4780_DMA_MSC1_RX 0x1d +#define JZ4780_DMA_MSC2_TX 0x1e +#define JZ4780_DMA_MSC2_RX 0x1f +#define JZ4780_DMA_PCM0_TX 0x20 +#define JZ4780_DMA_PCM0_RX 0x21 +#define JZ4780_DMA_SMB0_TX 0x24 +#define JZ4780_DMA_SMB0_RX 0x25 +#define JZ4780_DMA_SMB1_TX 0x26 +#define JZ4780_DMA_SMB1_RX 0x27 +#define JZ4780_DMA_SMB2_TX 0x28 +#define JZ4780_DMA_SMB2_RX 0x29 +#define JZ4780_DMA_SMB3_TX 0x2a +#define JZ4780_DMA_SMB3_RX 0x2b +#define JZ4780_DMA_SMB4_TX 0x2c +#define JZ4780_DMA_SMB4_RX 0x2d +#define JZ4780_DMA_DES_TX 0x2e +#define JZ4780_DMA_DES_RX 0x2f + +#endif /* __DT_BINDINGS_DMA_JZ4780_DMA_H__ */ -- cgit v1.2.3 From caa0e2d0e331a04cbc1cb9bca3169c1d94b80838 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 1 Apr 2015 08:21:51 +1030 Subject: virtio_config: reorder functions This simply reorders functions in virtio_config so width access wrapper helpers are all together. Drops an extra empty line while we are at it. Signed-off-by: Michael S. Tsirkin Signed-off-by: Rusty Russell --- include/linux/virtio_config.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index ca3ed78e5ec7..22d33034b578 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -298,13 +298,6 @@ static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val) } \ } while(0) -static inline u8 virtio_cread8(struct virtio_device *vdev, unsigned int offset) -{ - u8 ret; - vdev->config->get(vdev, offset, &ret, sizeof(ret)); - return ret; -} - /* Read @count fields, @bytes each. */ static inline void __virtio_cread_many(struct virtio_device *vdev, unsigned int offset, @@ -326,7 +319,6 @@ static inline void __virtio_cread_many(struct virtio_device *vdev, } while (gen != old); } - static inline void virtio_cread_bytes(struct virtio_device *vdev, unsigned int offset, void *buf, size_t len) @@ -334,6 +326,13 @@ static inline void virtio_cread_bytes(struct virtio_device *vdev, __virtio_cread_many(vdev, offset, buf, len, 1); } +static inline u8 virtio_cread8(struct virtio_device *vdev, unsigned int offset) +{ + u8 ret; + vdev->config->get(vdev, offset, &ret, sizeof(ret)); + return ret; +} + static inline void virtio_cwrite8(struct virtio_device *vdev, unsigned int offset, u8 val) { -- cgit v1.2.3 From 012665391dfe12bf8a88d1000e627be012c39dbf Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 1 Apr 2015 13:31:20 +1030 Subject: virtio: drop a useless config read "virtio: core support for config generation" fixed reading up 64 bit values, adding generation checks for such reads. By mistake, it left an explicit get call in place as well. the result is that the value is read twice, the first result is discarded. Not a big deal since this only happens with virtio blk and only on boot ATM, so performance isn't affected, but let's clean it up. Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck Signed-off-by: Rusty Russell --- include/linux/virtio_config.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 22d33034b578..1e306f727edc 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -373,7 +373,6 @@ static inline u64 virtio_cread64(struct virtio_device *vdev, unsigned int offset) { u64 ret; - vdev->config->get(vdev, offset, &ret, sizeof(ret)); __virtio_cread_many(vdev, offset, &ret, 1, sizeof(ret)); return virtio64_to_cpu(vdev, (__force __virtio64)ret); } -- cgit v1.2.3 From 034705a48bcae9d51661c461b7dd21e0d5b85afc Mon Sep 17 00:00:00 2001 From: Yakir Yang Date: Tue, 31 Mar 2015 23:56:10 -0400 Subject: drm: bridge/dw_hdmi: separate VLEVCTRL settting into platform driver Because of iMX6 & Rockchip have differnet mpll config parameter, the VLEVCTRL parameter would be different. In this case we should separate VLEVCTRL setting from the common dw_hdmi driver, config this parameter in platform driver(dw_hdmi-imx and dw_hdmi-rockchip) Signed-off-by: Yakir Yang Signed-off-by: Russell King --- drivers/gpu/drm/bridge/dw_hdmi.c | 14 +++++++------- drivers/gpu/drm/imx/dw_hdmi-imx.c | 24 ++++++++++++------------ drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 14 +++++++------- include/drm/bridge/dw_hdmi.h | 5 +++-- 4 files changed, 29 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c index 7943cedd63ce..49cafb61d290 100644 --- a/drivers/gpu/drm/bridge/dw_hdmi.c +++ b/drivers/gpu/drm/bridge/dw_hdmi.c @@ -758,7 +758,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, const struct dw_hdmi_plat_data *plat_data = hdmi->plat_data; const struct dw_hdmi_mpll_config *mpll_config = plat_data->mpll_cfg; const struct dw_hdmi_curr_ctrl *curr_ctrl = plat_data->cur_ctr; - const struct dw_hdmi_sym_term *sym_term = plat_data->sym_term; + const struct dw_hdmi_phy_config *phy_config = plat_data->phy_config; if (prep) return -EINVAL; @@ -829,18 +829,18 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); - for (i = 0; sym_term[i].mpixelclock != (~0UL); i++) + for (i = 0; phy_config[i].mpixelclock != (~0UL); i++) if (hdmi->hdmi_data.video_mode.mpixelclock <= - sym_term[i].mpixelclock) + phy_config[i].mpixelclock) break; /* RESISTANCE TERM 133Ohm Cfg */ - hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19); /* TXTERM */ + hdmi_phy_i2c_write(hdmi, phy_config[i].term, 0x19); /* TXTERM */ /* PREEMP Cgf 0.00 */ - hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09); /* CKSYMTXCTRL */ - + hdmi_phy_i2c_write(hdmi, phy_config[i].sym_ctr, 0x09); /* CKSYMTXCTRL */ /* TX/CK LVL 10 */ - hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */ + hdmi_phy_i2c_write(hdmi, phy_config[i].vlev_ctr, 0x0E); /* VLEVCTRL */ + /* REMOVE CLK TERM */ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */ diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index 121d30ca2d44..1032c07773e3 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -73,10 +73,10 @@ static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = { } }; -static const struct dw_hdmi_sym_term imx_sym_term[] = { - /*pixelclk symbol term*/ - { 148500000, 0x800d, 0x0005 }, - { ~0UL, 0x0000, 0x0000 } +static const struct dw_hdmi_phy_config imx_phy_config[] = { + /*pixelclk symbol term vlev */ + { 148500000, 0x800d, 0x0005, 0x01ad}, + { ~0UL, 0x0000, 0x0000, 0x0000} }; static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi) @@ -137,17 +137,17 @@ static struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = { }; static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = { - .mpll_cfg = imx_mpll_cfg, - .cur_ctr = imx_cur_ctr, - .sym_term = imx_sym_term, - .dev_type = IMX6Q_HDMI, + .mpll_cfg = imx_mpll_cfg, + .cur_ctr = imx_cur_ctr, + .phy_config = imx_phy_config, + .dev_type = IMX6Q_HDMI, }; static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = { - .mpll_cfg = imx_mpll_cfg, - .cur_ctr = imx_cur_ctr, - .sym_term = imx_sym_term, - .dev_type = IMX6DL_HDMI, + .mpll_cfg = imx_mpll_cfg, + .cur_ctr = imx_cur_ctr, + .phy_config = imx_phy_config, + .dev_type = IMX6DL_HDMI, }; static const struct of_device_id dw_hdmi_imx_dt_ids[] = { diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index d236faa05b19..65b0f7bf5b52 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -133,12 +133,12 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { } }; -static const struct dw_hdmi_sym_term rockchip_sym_term[] = { - /*pixelclk symbol term*/ - { 74250000, 0x8009, 0x0004 }, - { 148500000, 0x8029, 0x0004 }, - { 297000000, 0x8039, 0x0005 }, - { ~0UL, 0x0000, 0x0000 } +static const struct dw_hdmi_phy_config rockchip_phy_config[] = { + /*pixelclk symbol term vlev*/ + { 74250000, 0x8009, 0x0004, 0x01ad}, + { 148500000, 0x8029, 0x0004, 0x01ad}, + { 297000000, 0x8039, 0x0005, 0x01ad}, + { ~0UL, 0x0000, 0x0000, 0x0000} }; static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) @@ -230,7 +230,7 @@ static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = { .mode_valid = dw_hdmi_rockchip_mode_valid, .mpll_cfg = rockchip_mpll_cfg, .cur_ctr = rockchip_cur_ctr, - .sym_term = rockchip_sym_term, + .phy_config = rockchip_phy_config, .dev_type = RK3288_HDMI, }; diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 5a4f49005169..de13bfc35634 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -38,17 +38,18 @@ struct dw_hdmi_curr_ctrl { u16 curr[DW_HDMI_RES_MAX]; }; -struct dw_hdmi_sym_term { +struct dw_hdmi_phy_config { unsigned long mpixelclock; u16 sym_ctr; /*clock symbol and transmitter control*/ u16 term; /*transmission termination value*/ + u16 vlev_ctr; /* voltage level control */ }; struct dw_hdmi_plat_data { enum dw_hdmi_devtype dev_type; const struct dw_hdmi_mpll_config *mpll_cfg; const struct dw_hdmi_curr_ctrl *cur_ctr; - const struct dw_hdmi_sym_term *sym_term; + const struct dw_hdmi_phy_config *phy_config; enum drm_mode_status (*mode_valid)(struct drm_connector *connector, struct drm_display_mode *mode); }; -- cgit v1.2.3 From b4a20144e0c0a45431695fa5968ce2ed8c9ce6ca Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 28 Jan 2015 14:29:02 +0100 Subject: gpu: host1x: Export host1x_syncpt_read() This function is used to read the current value of the syncpt and is useful in situations where drivers don't schedule work and wait for the syncpoint to increment. One particular use-case is using the syncpoint as a VBLANK counter. Signed-off-by: Thierry Reding --- drivers/gpu/host1x/syncpt.c | 6 ++++++ include/linux/host1x.h | 1 + 2 files changed, 7 insertions(+) (limited to 'include') diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index b10550ee1d89..6b7fdc1e2ed0 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c @@ -425,6 +425,12 @@ u32 host1x_syncpt_read_min(struct host1x_syncpt *sp) } EXPORT_SYMBOL(host1x_syncpt_read_min); +u32 host1x_syncpt_read(struct host1x_syncpt *sp) +{ + return host1x_syncpt_load(sp); +} +EXPORT_SYMBOL(host1x_syncpt_read); + int host1x_syncpt_nb_pts(struct host1x *host) { return host->info->nb_pts; diff --git a/include/linux/host1x.h b/include/linux/host1x.h index 464f33814a94..d2ba7d334039 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -135,6 +135,7 @@ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id); u32 host1x_syncpt_id(struct host1x_syncpt *sp); u32 host1x_syncpt_read_min(struct host1x_syncpt *sp); u32 host1x_syncpt_read_max(struct host1x_syncpt *sp); +u32 host1x_syncpt_read(struct host1x_syncpt *sp); int host1x_syncpt_incr(struct host1x_syncpt *sp); u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs); int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, -- cgit v1.2.3 From f5e7840b0c4368f8cdbb055188c2a0eef50c3052 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 28 Jan 2015 14:54:32 +0100 Subject: drm/atomic: Add helpers for state-subclassing drivers Drivers that subclass CRTC, plane or connector state need to carefully duplicate the code that the atomic helpers have. This is bound to cause breakage eventually because it requires auditing all drivers and update them when code is added to the helpers. In order to avoid that, implement new helpers that perform the required steps when copying and destroying state. These new helpers are exported so that state-subclassing drivers can use them. The default helpers are implemented using them as well, providing a single location that needs to be changed when adding to base atomic states. Reviewed-by: Daniel Vetter Reviewed-by: Eric Anholt Signed-off-by: Thierry Reding --- drivers/gpu/drm/drm_atomic_helper.c | 144 ++++++++++++++++++++++++++++++++---- include/drm/drm_atomic_helper.h | 14 ++++ 2 files changed, 142 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 7e3a52b97c7d..60d28a18f0a3 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2049,6 +2049,26 @@ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); +/** + * __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state + * @crtc: CRTC object + * @state: atomic CRTC state + * + * Copies atomic state from a CRTC's current state and resets inferred values. + * This is useful for drivers that subclass the CRTC state. + */ +void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + memcpy(state, crtc->state, sizeof(*state)); + + state->mode_changed = false; + state->active_changed = false; + state->planes_changed = false; + state->event = NULL; +} +EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state); + /** * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook * @crtc: drm CRTC @@ -2064,19 +2084,34 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc) if (WARN_ON(!crtc->state)) return NULL; - state = kmemdup(crtc->state, sizeof(*crtc->state), GFP_KERNEL); - - if (state) { - state->mode_changed = false; - state->active_changed = false; - state->planes_changed = false; - state->event = NULL; - } + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_crtc_duplicate_state(crtc, state); return state; } EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); +/** + * __drm_atomic_helper_crtc_destroy_state - release CRTC state + * @crtc: CRTC object + * @state: CRTC state object to release + * + * Releases all resources stored in the CRTC state without actually freeing + * the memory of the CRTC state. This is useful for drivers that subclass the + * CRTC state. + */ +void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + /* + * This is currently a placeholder so that drivers that subclass the + * state will automatically do the right thing if code is ever added + * to this function. + */ +} +EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state); + /** * drm_atomic_helper_crtc_destroy_state - default state destroy hook * @crtc: drm CRTC @@ -2088,6 +2123,7 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state) { + __drm_atomic_helper_crtc_destroy_state(crtc, state); kfree(state); } EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state); @@ -2112,6 +2148,24 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane) } EXPORT_SYMBOL(drm_atomic_helper_plane_reset); +/** + * __drm_atomic_helper_plane_duplicate_state - copy atomic plane state + * @plane: plane object + * @state: atomic plane state + * + * Copies atomic state from a plane's current state. This is useful for + * drivers that subclass the plane state. + */ +void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + memcpy(state, plane->state, sizeof(*state)); + + if (state->fb) + drm_framebuffer_reference(state->fb); +} +EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state); + /** * drm_atomic_helper_plane_duplicate_state - default state duplicate hook * @plane: drm plane @@ -2127,15 +2181,31 @@ drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane) if (WARN_ON(!plane->state)) return NULL; - state = kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL); - - if (state && state->fb) - drm_framebuffer_reference(state->fb); + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_plane_duplicate_state(plane, state); return state; } EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state); +/** + * __drm_atomic_helper_plane_destroy_state - release plane state + * @plane: plane object + * @state: plane state object to release + * + * Releases all resources stored in the plane state without actually freeing + * the memory of the plane state. This is useful for drivers that subclass the + * plane state. + */ +void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + if (state->fb) + drm_framebuffer_unreference(state->fb); +} +EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state); + /** * drm_atomic_helper_plane_destroy_state - default state destroy hook * @plane: drm plane @@ -2147,9 +2217,7 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state); void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { - if (state->fb) - drm_framebuffer_unreference(state->fb); - + __drm_atomic_helper_plane_destroy_state(plane, state); kfree(state); } EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state); @@ -2172,6 +2240,22 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector) } EXPORT_SYMBOL(drm_atomic_helper_connector_reset); +/** + * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state + * @connector: connector object + * @state: atomic connector state + * + * Copies atomic state from a connector's current state. This is useful for + * drivers that subclass the connector state. + */ +void +__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *state) +{ + memcpy(state, connector->state, sizeof(*state)); +} +EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state); + /** * drm_atomic_helper_connector_duplicate_state - default state duplicate hook * @connector: drm connector @@ -2182,13 +2266,40 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_reset); struct drm_connector_state * drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector) { + struct drm_connector_state *state; + if (WARN_ON(!connector->state)) return NULL; - return kmemdup(connector->state, sizeof(*connector->state), GFP_KERNEL); + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_connector_duplicate_state(connector, state); + + return state; } EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); +/** + * __drm_atomic_helper_connector_destroy_state - release connector state + * @connector: connector object + * @state: connector state object to release + * + * Releases all resources stored in the connector state without actually + * freeing the memory of the connector state. This is useful for drivers that + * subclass the connector state. + */ +void +__drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, + struct drm_connector_state *state) +{ + /* + * This is currently a placeholder so that drivers that subclass the + * state will automatically do the right thing if code is ever added + * to this function. + */ +} +EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state); + /** * drm_atomic_helper_connector_destroy_state - default state destroy hook * @connector: drm connector @@ -2200,6 +2311,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, struct drm_connector_state *state) { + __drm_atomic_helper_connector_destroy_state(connector, state); kfree(state); } EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 8039d54a7441..e2086372ef61 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -87,20 +87,34 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector, /* default implementations for state handling */ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); +void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, + struct drm_crtc_state *state); struct drm_crtc_state * drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc); +void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state); void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state); void drm_atomic_helper_plane_reset(struct drm_plane *plane); +void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, + struct drm_plane_state *state); struct drm_plane_state * drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane); +void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state); void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state); void drm_atomic_helper_connector_reset(struct drm_connector *connector); +void +__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, + struct drm_connector_state *state); struct drm_connector_state * drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector); +void +__drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, + struct drm_connector_state *state); void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, struct drm_connector_state *state); -- cgit v1.2.3 From bdf765071a8b573f7b1ba14c02881fa3e623825e Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Fri, 30 Jan 2015 13:57:01 -0500 Subject: drm/tegra: gem: Return 64-bit offset for mmap(2) On 64-bit targets, tegra_gem_mmap() only returns a partial offset to userspace. As such, subsequent calls to mmap(2) may fail. Change the arguments to use a 64-bit offset to fix this. Signed-off-by: Sean Paul Acked-by: Erik Faye-Lund [treding@nvidia.com: tweak commit message] Signed-off-by: Thierry Reding --- include/uapi/drm/tegra_drm.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/drm/tegra_drm.h b/include/uapi/drm/tegra_drm.h index c15d781ecc0f..5391780c2b05 100644 --- a/include/uapi/drm/tegra_drm.h +++ b/include/uapi/drm/tegra_drm.h @@ -36,7 +36,8 @@ struct drm_tegra_gem_create { struct drm_tegra_gem_mmap { __u32 handle; - __u32 offset; + __u32 pad; + __u64 offset; }; struct drm_tegra_syncpt_read { -- cgit v1.2.3 From 2938931f3732a4ec70c299e221ec8dea01dfd796 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 11 Dec 2014 18:32:44 +0100 Subject: drm/panel: Add display timing support Many panel data sheets, additionally to typical values, list allowed ranges for timings such as hsync/vsync lengths, porches, and the pixel clock rate. These can be stored in a struct display_timing, to be used by an encoder mode_fixup callback to clamp user provided timing values or to validate workarounds for clock source limitations. This patch adds a new drm_panel_funcs callback that returns the panel's available display_timing entries. Signed-off-by: Philipp Zabel Signed-off-by: Thierry Reding --- include/drm/drm_panel.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 1fbcc96063a7..13ff44b28893 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -29,6 +29,7 @@ struct drm_connector; struct drm_device; struct drm_panel; +struct display_timing; /** * struct drm_panel_funcs - perform operations on a given panel @@ -38,6 +39,8 @@ struct drm_panel; * @enable: enable panel (turn on back light, etc.) * @get_modes: add modes to the connector that the panel is attached to and * return the number of modes added + * @get_timings: copy display timings into the provided array and return + * the number of display timings available * * The .prepare() function is typically called before the display controller * starts to transmit video data. Panel drivers can use this to turn the panel @@ -68,6 +71,8 @@ struct drm_panel_funcs { int (*prepare)(struct drm_panel *panel); int (*enable)(struct drm_panel *panel); int (*get_modes)(struct drm_panel *panel); + int (*get_timings)(struct drm_panel *panel, unsigned int num_timings, + struct display_timing *timings); }; struct drm_panel { -- cgit v1.2.3 From 6890874772e4c5e2925187f262893df0eb0322ba Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 25 Mar 2015 19:57:30 -0300 Subject: [media] omap3isp: Refactor device configuration structs for Device Tree Make omap3isp configuration data structures more suitable for consumption by the DT by separating the I2C bus information of all the sub-devices in a group and the ISP bus information from each other. The ISP bus information is made a pointer instead of being directly embedded in the struct. In the case of the DT only the sensor specific information on the ISP bus configuration is retained. The structs are renamed to reflect that. After this change the structs needed to describe device configuration can be allocated and accessed separately without those needed only in the case of platform data. The platform data related structs can be later removed once the support for platform data can be removed. Signed-off-by: Sakari Ailus Acked-by: Igor Grinberg (for cm-t35) Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- arch/arm/mach-omap2/board-cm-t35.c | 57 +++++++------------ drivers/media/platform/omap3isp/isp.c | 86 ++++++++++++++--------------- drivers/media/platform/omap3isp/isp.h | 2 +- drivers/media/platform/omap3isp/ispccdc.c | 26 ++++----- drivers/media/platform/omap3isp/ispccp2.c | 22 ++++---- drivers/media/platform/omap3isp/ispcsi2.c | 8 +-- drivers/media/platform/omap3isp/ispcsiphy.c | 21 ++++--- include/media/omap3isp.h | 34 ++++++------ 8 files changed, 119 insertions(+), 137 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index 91738a14ecbe..b5dfbc1b1fc6 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -492,51 +492,36 @@ static struct twl4030_platform_data cm_t35_twldata = { #include #include "devices.h" -static struct i2c_board_info cm_t35_isp_i2c_boardinfo[] = { +static struct isp_platform_subdev cm_t35_isp_subdevs[] = { { - I2C_BOARD_INFO("mt9t001", 0x5d), - }, - { - I2C_BOARD_INFO("tvp5150", 0x5c), - }, -}; - -static struct isp_subdev_i2c_board_info cm_t35_isp_primary_subdevs[] = { - { - .board_info = &cm_t35_isp_i2c_boardinfo[0], - .i2c_adapter_id = 3, - }, - { NULL, 0, }, -}; - -static struct isp_subdev_i2c_board_info cm_t35_isp_secondary_subdevs[] = { - { - .board_info = &cm_t35_isp_i2c_boardinfo[1], + .board_info = &(struct i2c_board_info){ + I2C_BOARD_INFO("mt9t001", 0x5d) + }, .i2c_adapter_id = 3, - }, - { NULL, 0, }, -}; - -static struct isp_v4l2_subdevs_group cm_t35_isp_subdevs[] = { - { - .subdevs = cm_t35_isp_primary_subdevs, - .interface = ISP_INTERFACE_PARALLEL, - .bus = { - .parallel = { - .clk_pol = 1, + .bus = &(struct isp_bus_cfg){ + .interface = ISP_INTERFACE_PARALLEL, + .bus = { + .parallel = { + .clk_pol = 1, + }, }, }, }, { - .subdevs = cm_t35_isp_secondary_subdevs, - .interface = ISP_INTERFACE_PARALLEL, - .bus = { - .parallel = { - .clk_pol = 0, + .board_info = &(struct i2c_board_info){ + I2C_BOARD_INFO("tvp5150", 0x5c), + }, + .i2c_adapter_id = 3, + .bus = &(struct isp_bus_cfg){ + .interface = ISP_INTERFACE_PARALLEL, + .bus = { + .parallel = { + .clk_pol = 0, + }, }, }, }, - { NULL, 0, }, + { 0 }, }; static struct isp_platform_data cm_t35_isp_pdata = { diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 537377b43083..1b5c6df3b645 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -447,7 +447,7 @@ static void isp_core_init(struct isp_device *isp, int idle) */ void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata, + const struct isp_parallel_cfg *parcfg, unsigned int shift, unsigned int bridge) { u32 ispctrl_val; @@ -462,8 +462,8 @@ void omap3isp_configure_bridge(struct isp_device *isp, switch (input) { case CCDC_INPUT_PARALLEL: ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL; - ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; - shift += pdata->data_lane_shift * 2; + ispctrl_val |= parcfg->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; + shift += parcfg->data_lane_shift * 2; break; case CCDC_INPUT_CSI2A: @@ -1809,52 +1809,44 @@ static void isp_unregister_entities(struct isp_device *isp) } /* - * isp_register_subdev_group - Register a group of subdevices + * isp_register_subdev - Register a sub-device * @isp: OMAP3 ISP device - * @board_info: I2C subdevs board information array + * @isp_subdev: platform data related to a sub-device * - * Register all I2C subdevices in the board_info array. The array must be - * terminated by a NULL entry, and the first entry must be the sensor. + * Register an I2C sub-device which has not been registered by other + * means (such as the Device Tree). * - * Return a pointer to the sensor media entity if it has been successfully + * Return a pointer to the sub-device if it has been successfully * registered, or NULL otherwise. */ static struct v4l2_subdev * -isp_register_subdev_group(struct isp_device *isp, - struct isp_subdev_i2c_board_info *board_info) +isp_register_subdev(struct isp_device *isp, + struct isp_platform_subdev *isp_subdev) { - struct v4l2_subdev *sensor = NULL; - unsigned int first; + struct i2c_adapter *adapter; + struct v4l2_subdev *sd; - if (board_info->board_info == NULL) + if (isp_subdev->board_info == NULL) return NULL; - for (first = 1; board_info->board_info; ++board_info, first = 0) { - struct v4l2_subdev *subdev; - struct i2c_adapter *adapter; - - adapter = i2c_get_adapter(board_info->i2c_adapter_id); - if (adapter == NULL) { - dev_err(isp->dev, "%s: Unable to get I2C adapter %d for " - "device %s\n", __func__, - board_info->i2c_adapter_id, - board_info->board_info->type); - continue; - } - - subdev = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter, - board_info->board_info, NULL); - if (subdev == NULL) { - dev_err(isp->dev, "%s: Unable to register subdev %s\n", - __func__, board_info->board_info->type); - continue; - } + adapter = i2c_get_adapter(isp_subdev->i2c_adapter_id); + if (adapter == NULL) { + dev_err(isp->dev, + "%s: Unable to get I2C adapter %d for device %s\n", + __func__, isp_subdev->i2c_adapter_id, + isp_subdev->board_info->type); + return NULL; + } - if (first) - sensor = subdev; + sd = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter, + isp_subdev->board_info, NULL); + if (sd == NULL) { + dev_err(isp->dev, "%s: Unable to register subdev %s\n", + __func__, isp_subdev->board_info->type); + return NULL; } - return sensor; + return sd; } static int isp_link_entity( @@ -1931,7 +1923,7 @@ static int isp_link_entity( static int isp_register_entities(struct isp_device *isp) { struct isp_platform_data *pdata = isp->pdata; - struct isp_v4l2_subdevs_group *subdevs; + struct isp_platform_subdev *isp_subdev; int ret; isp->media_dev.dev = isp->dev; @@ -1989,17 +1981,23 @@ static int isp_register_entities(struct isp_device *isp) goto done; /* Register external entities */ - for (subdevs = pdata ? pdata->subdevs : NULL; - subdevs && subdevs->subdevs; ++subdevs) { - struct v4l2_subdev *sensor; + for (isp_subdev = pdata ? pdata->subdevs : NULL; + isp_subdev && isp_subdev->board_info; isp_subdev++) { + struct v4l2_subdev *sd; - sensor = isp_register_subdev_group(isp, subdevs->subdevs); - if (sensor == NULL) + sd = isp_register_subdev(isp, isp_subdev); + + /* + * No bus information --- this is either a flash or a + * lens subdev. + */ + if (!sd || !isp_subdev->bus) continue; - sensor->host_priv = subdevs; + sd->host_priv = isp_subdev->bus; - ret = isp_link_entity(isp, &sensor->entity, subdevs->interface); + ret = isp_link_entity(isp, &sd->entity, + isp_subdev->bus->interface); if (ret < 0) goto done; } diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index cfdfc8714b6b..b932a6f22b52 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -229,7 +229,7 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, void omap3isp_pipeline_cancel_stream(struct isp_pipeline *pipe); void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata, + const struct isp_parallel_cfg *buscfg, unsigned int shift, unsigned int bridge); struct isp_device *omap3isp_get(struct isp_device *isp); diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 6e0291bca73f..a6a61cce43dd 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -958,11 +958,11 @@ void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc, /* * ccdc_config_sync_if - Set CCDC sync interface configuration * @ccdc: Pointer to ISP CCDC device. - * @pdata: Parallel interface platform data (may be NULL) + * @parcfg: Parallel interface platform data (may be NULL) * @data_size: Data size */ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, - struct isp_parallel_platform_data *pdata, + struct isp_parallel_cfg *parcfg, unsigned int data_size) { struct isp_device *isp = to_isp_device(ccdc); @@ -1000,19 +1000,19 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, break; } - if (pdata && pdata->data_pol) + if (parcfg && parcfg->data_pol) syn_mode |= ISPCCDC_SYN_MODE_DATAPOL; - if (pdata && pdata->hs_pol) + if (parcfg && parcfg->hs_pol) syn_mode |= ISPCCDC_SYN_MODE_HDPOL; /* The polarity of the vertical sync signal output by the BT.656 * decoder is not documented and seems to be active low. */ - if ((pdata && pdata->vs_pol) || ccdc->bt656) + if ((parcfg && parcfg->vs_pol) || ccdc->bt656) syn_mode |= ISPCCDC_SYN_MODE_VDPOL; - if (pdata && pdata->fld_pol) + if (parcfg && parcfg->fld_pol) syn_mode |= ISPCCDC_SYN_MODE_FLDPOL; isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); @@ -1115,7 +1115,7 @@ static const u32 ccdc_sgbrg_pattern = static void ccdc_configure(struct isp_ccdc_device *ccdc) { struct isp_device *isp = to_isp_device(ccdc); - struct isp_parallel_platform_data *pdata = NULL; + struct isp_parallel_cfg *parcfg = NULL; struct v4l2_subdev *sensor; struct v4l2_mbus_framefmt *format; const struct v4l2_rect *crop; @@ -1145,7 +1145,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) if (!ret) ccdc->bt656 = cfg.type == V4L2_MBUS_BT656; - pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) + parcfg = &((struct isp_bus_cfg *)sensor->host_priv) ->bus.parallel; } @@ -1175,10 +1175,10 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) else bridge = ISPCTRL_PAR_BRIDGE_DISABLE; - omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge); + omap3isp_configure_bridge(isp, ccdc->input, parcfg, shift, bridge); /* Configure the sync interface. */ - ccdc_config_sync_if(ccdc, pdata, depth_out); + ccdc_config_sync_if(ccdc, parcfg, depth_out); syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); @@ -2417,11 +2417,11 @@ static int ccdc_link_validate(struct v4l2_subdev *sd, /* We've got a parallel sensor here. */ if (ccdc->input == CCDC_INPUT_PARALLEL) { - struct isp_parallel_platform_data *pdata = - &((struct isp_v4l2_subdevs_group *) + struct isp_parallel_cfg *parcfg = + &((struct isp_bus_cfg *) media_entity_to_v4l2_subdev(link->source->entity) ->host_priv)->bus.parallel; - parallel_shift = pdata->data_lane_shift * 2; + parallel_shift = parcfg->data_lane_shift * 2; } else { parallel_shift = 0; } diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index 44c20fa8501a..38e6a974c5b1 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -201,14 +201,14 @@ static void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable) /* * ccp2_phyif_config - Initialize CCP2 phy interface config * @ccp2: Pointer to ISP CCP2 device - * @pdata: CCP2 platform data + * @buscfg: CCP2 platform data * * Configure the CCP2 physical interface module from platform data. * * Returns -EIO if strobe is chosen in CSI1 mode, or 0 on success. */ static int ccp2_phyif_config(struct isp_ccp2_device *ccp2, - const struct isp_ccp2_platform_data *pdata) + const struct isp_ccp2_cfg *buscfg) { struct isp_device *isp = to_isp_device(ccp2); u32 val; @@ -218,16 +218,16 @@ static int ccp2_phyif_config(struct isp_ccp2_device *ccp2, ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE; /* Data/strobe physical layer */ BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK, - pdata->phy_layer); + buscfg->phy_layer); BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK, - pdata->strobe_clk_pol); + buscfg->strobe_clk_pol); isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); if (!(val & ISPCCP2_CTRL_MODE)) { - if (pdata->ccp2_mode == ISP_CCP2_MODE_CCP2) + if (buscfg->ccp2_mode == ISP_CCP2_MODE_CCP2) dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n"); - if (pdata->phy_layer == ISP_CCP2_PHY_DATA_STROBE) + if (buscfg->phy_layer == ISP_CCP2_PHY_DATA_STROBE) /* Strobe mode requires CCP2 */ return -EIO; } @@ -347,7 +347,7 @@ static void ccp2_lcx_config(struct isp_ccp2_device *ccp2, */ static int ccp2_if_configure(struct isp_ccp2_device *ccp2) { - const struct isp_v4l2_subdevs_group *pdata; + const struct isp_bus_cfg *buscfg; struct v4l2_mbus_framefmt *format; struct media_pad *pad; struct v4l2_subdev *sensor; @@ -358,20 +358,20 @@ static int ccp2_if_configure(struct isp_ccp2_device *ccp2) pad = media_entity_remote_pad(&ccp2->pads[CCP2_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); - pdata = sensor->host_priv; + buscfg = sensor->host_priv; - ret = ccp2_phyif_config(ccp2, &pdata->bus.ccp2); + ret = ccp2_phyif_config(ccp2, &buscfg->bus.ccp2); if (ret < 0) return ret; - ccp2_vp_config(ccp2, pdata->bus.ccp2.vpclk_div + 1); + ccp2_vp_config(ccp2, buscfg->bus.ccp2.vpclk_div + 1); v4l2_subdev_call(sensor, sensor, g_skip_top_lines, &lines); format = &ccp2->formats[CCP2_PAD_SINK]; ccp2->if_cfg.data_start = lines; - ccp2->if_cfg.crc = pdata->bus.ccp2.crc; + ccp2->if_cfg.crc = buscfg->bus.ccp2.crc; ccp2->if_cfg.format = format->code; ccp2->if_cfg.data_size = format->height; diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index bbadf6653db7..45ac90a49889 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -548,7 +548,7 @@ int omap3isp_csi2_reset(struct isp_csi2_device *csi2) static int csi2_configure(struct isp_csi2_device *csi2) { - const struct isp_v4l2_subdevs_group *pdata; + const struct isp_bus_cfg *buscfg; struct isp_device *isp = csi2->isp; struct isp_csi2_timing_cfg *timing = &csi2->timing[0]; struct v4l2_subdev *sensor; @@ -565,14 +565,14 @@ static int csi2_configure(struct isp_csi2_device *csi2) pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); - pdata = sensor->host_priv; + buscfg = sensor->host_priv; csi2->frame_skip = 0; v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip); - csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div; + csi2->ctrl.vp_out_ctrl = buscfg->bus.csi2.vpclk_div; csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE; - csi2->ctrl.ecc_enable = pdata->bus.csi2.crc; + csi2->ctrl.ecc_enable = buscfg->bus.csi2.crc; timing->ionum = 1; timing->force_rx_mode = 1; diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c index e033f2237a72..4486e9f492df 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.c +++ b/drivers/media/platform/omap3isp/ispcsiphy.c @@ -168,18 +168,18 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy) { struct isp_csi2_device *csi2 = phy->csi2; struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); - struct isp_v4l2_subdevs_group *subdevs = pipe->external->host_priv; + struct isp_bus_cfg *buscfg = pipe->external->host_priv; struct isp_csiphy_lanes_cfg *lanes; int csi2_ddrclk_khz; unsigned int used_lanes = 0; unsigned int i; u32 reg; - if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1 - || subdevs->interface == ISP_INTERFACE_CCP2B_PHY2) - lanes = &subdevs->bus.ccp2.lanecfg; + if (buscfg->interface == ISP_INTERFACE_CCP2B_PHY1 + || buscfg->interface == ISP_INTERFACE_CCP2B_PHY2) + lanes = &buscfg->bus.ccp2.lanecfg; else - lanes = &subdevs->bus.csi2.lanecfg; + lanes = &buscfg->bus.csi2.lanecfg; /* Clock and data lanes verification */ for (i = 0; i < phy->num_data_lanes; i++) { @@ -203,8 +203,8 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy) * issue since the MPU power domain is forced on whilst the * ISP is in use. */ - csiphy_routing_cfg(phy, subdevs->interface, true, - subdevs->bus.ccp2.phy_layer); + csiphy_routing_cfg(phy, buscfg->interface, true, + buscfg->bus.ccp2.phy_layer); /* DPHY timing configuration */ /* CSI-2 is DDR and we only count used lanes. */ @@ -302,11 +302,10 @@ void omap3isp_csiphy_release(struct isp_csiphy *phy) struct isp_csi2_device *csi2 = phy->csi2; struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); - struct isp_v4l2_subdevs_group *subdevs = - pipe->external->host_priv; + struct isp_bus_cfg *buscfg = pipe->external->host_priv; - csiphy_routing_cfg(phy, subdevs->interface, false, - subdevs->bus.ccp2.phy_layer); + csiphy_routing_cfg(phy, buscfg->interface, false, + buscfg->bus.ccp2.phy_layer); csiphy_power_autoswitch_enable(phy, false); csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF); regulator_disable(phy->vdd); diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h index 398279dd1922..39e0748b0d31 100644 --- a/include/media/omap3isp.h +++ b/include/media/omap3isp.h @@ -45,7 +45,7 @@ enum { }; /** - * struct isp_parallel_platform_data - Parallel interface platform data + * struct isp_parallel_cfg - Parallel interface configuration * @data_lane_shift: Data lane shifter * ISP_LANE_SHIFT_0 - CAMEXT[13:0] -> CAM[13:0] * ISP_LANE_SHIFT_2 - CAMEXT[13:2] -> CAM[11:0] @@ -62,7 +62,7 @@ enum { * @data_pol: Data polarity * 0 - Normal, 1 - One's complement */ -struct isp_parallel_platform_data { +struct isp_parallel_cfg { unsigned int data_lane_shift:2; unsigned int clk_pol:1; unsigned int hs_pol:1; @@ -105,7 +105,7 @@ struct isp_csiphy_lanes_cfg { }; /** - * struct isp_ccp2_platform_data - CCP2 interface platform data + * struct isp_ccp2_cfg - CCP2 interface configuration * @strobe_clk_pol: Strobe/clock polarity * 0 - Non Inverted, 1 - Inverted * @crc: Enable the cyclic redundancy check @@ -117,7 +117,7 @@ struct isp_csiphy_lanes_cfg { * ISP_CCP2_PHY_DATA_STROBE - Data/strobe physical layer * @vpclk_div: Video port output clock control */ -struct isp_ccp2_platform_data { +struct isp_ccp2_cfg { unsigned int strobe_clk_pol:1; unsigned int crc:1; unsigned int ccp2_mode:1; @@ -127,31 +127,31 @@ struct isp_ccp2_platform_data { }; /** - * struct isp_csi2_platform_data - CSI2 interface platform data + * struct isp_csi2_cfg - CSI2 interface configuration * @crc: Enable the cyclic redundancy check * @vpclk_div: Video port output clock control */ -struct isp_csi2_platform_data { +struct isp_csi2_cfg { unsigned crc:1; unsigned vpclk_div:2; struct isp_csiphy_lanes_cfg lanecfg; }; -struct isp_subdev_i2c_board_info { - struct i2c_board_info *board_info; - int i2c_adapter_id; -}; - -struct isp_v4l2_subdevs_group { - struct isp_subdev_i2c_board_info *subdevs; +struct isp_bus_cfg { enum isp_interface_type interface; union { - struct isp_parallel_platform_data parallel; - struct isp_ccp2_platform_data ccp2; - struct isp_csi2_platform_data csi2; + struct isp_parallel_cfg parallel; + struct isp_ccp2_cfg ccp2; + struct isp_csi2_cfg csi2; } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */ }; +struct isp_platform_subdev { + struct i2c_board_info *board_info; + int i2c_adapter_id; + struct isp_bus_cfg *bus; +}; + struct isp_platform_xclk { const char *dev_id; const char *con_id; @@ -159,7 +159,7 @@ struct isp_platform_xclk { struct isp_platform_data { struct isp_platform_xclk xclks[2]; - struct isp_v4l2_subdevs_group *subdevs; + struct isp_platform_subdev *subdevs; void (*set_constraints)(struct isp_device *isp, bool enable); }; -- cgit v1.2.3 From 6387b75284aa7b78c2e947934fb874444ab427e9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 25 Mar 2015 19:57:32 -0300 Subject: [media] omap3isp: Calculate vpclk_div for CSI-2 The video port clock is l3_ick divided by vpclk_div. This clock must be high enough for the external pixel rate. The video port requires two clock cycles to process a pixel. Signed-off-by: Sakari Ailus Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispcsi2.c | 8 +++++++- include/media/omap3isp.h | 2 -- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index 45ac90a49889..a78338d012b4 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -548,6 +548,7 @@ int omap3isp_csi2_reset(struct isp_csi2_device *csi2) static int csi2_configure(struct isp_csi2_device *csi2) { + struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); const struct isp_bus_cfg *buscfg; struct isp_device *isp = csi2->isp; struct isp_csi2_timing_cfg *timing = &csi2->timing[0]; @@ -570,7 +571,12 @@ static int csi2_configure(struct isp_csi2_device *csi2) csi2->frame_skip = 0; v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip); - csi2->ctrl.vp_out_ctrl = buscfg->bus.csi2.vpclk_div; + csi2->ctrl.vp_out_ctrl = + clamp_t(unsigned int, pipe->l3_ick / pipe->external_rate - 1, + 1, 3); + dev_dbg(isp->dev, "%s: l3_ick %lu, external_rate %u, vp_out_ctrl %u\n", + __func__, pipe->l3_ick, pipe->external_rate, + csi2->ctrl.vp_out_ctrl); csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE; csi2->ctrl.ecc_enable = buscfg->bus.csi2.crc; diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h index 39e0748b0d31..0f0c08b48829 100644 --- a/include/media/omap3isp.h +++ b/include/media/omap3isp.h @@ -129,11 +129,9 @@ struct isp_ccp2_cfg { /** * struct isp_csi2_cfg - CSI2 interface configuration * @crc: Enable the cyclic redundancy check - * @vpclk_div: Video port output clock control */ struct isp_csi2_cfg { unsigned crc:1; - unsigned vpclk_div:2; struct isp_csiphy_lanes_cfg lanecfg; }; -- cgit v1.2.3 From b6eec1c4939962838ff51b10a8feb7a49bccc0d2 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 25 Mar 2015 19:57:37 -0300 Subject: [media] v4l: of: Read lane-polarities endpoint property Add lane_polarities field to struct v4l2_of_bus_mipi_csi2 and write the contents of the lane-polarities property to it. The field tells the polarity of the physical lanes starting from the first one. Any unused lanes are ignored, i.e. only the polarity of the used lanes is specified. Also rework reading the "data-lanes" property a little. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-of.c | 41 ++++++++++++++++++++++++++++++--------- include/media/v4l2-of.h | 3 +++ 2 files changed, 35 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c index b4ed9a955fbe..58e401f4893a 100644 --- a/drivers/media/v4l2-core/v4l2-of.c +++ b/drivers/media/v4l2-core/v4l2-of.c @@ -19,11 +19,10 @@ #include -static void v4l2_of_parse_csi_bus(const struct device_node *node, - struct v4l2_of_endpoint *endpoint) +static int v4l2_of_parse_csi_bus(const struct device_node *node, + struct v4l2_of_endpoint *endpoint) { struct v4l2_of_bus_mipi_csi2 *bus = &endpoint->bus.mipi_csi2; - u32 data_lanes[ARRAY_SIZE(bus->data_lanes)]; struct property *prop; bool have_clk_lane = false; unsigned int flags = 0; @@ -32,16 +31,34 @@ static void v4l2_of_parse_csi_bus(const struct device_node *node, prop = of_find_property(node, "data-lanes", NULL); if (prop) { const __be32 *lane = NULL; - int i; + unsigned int i; - for (i = 0; i < ARRAY_SIZE(data_lanes); i++) { - lane = of_prop_next_u32(prop, lane, &data_lanes[i]); + for (i = 0; i < ARRAY_SIZE(bus->data_lanes); i++) { + lane = of_prop_next_u32(prop, lane, &v); if (!lane) break; + bus->data_lanes[i] = v; } bus->num_data_lanes = i; - while (i--) - bus->data_lanes[i] = data_lanes[i]; + } + + prop = of_find_property(node, "lane-polarities", NULL); + if (prop) { + const __be32 *polarity = NULL; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(bus->lane_polarities); i++) { + polarity = of_prop_next_u32(prop, polarity, &v); + if (!polarity) + break; + bus->lane_polarities[i] = v; + } + + if (i < 1 + bus->num_data_lanes /* clock + data */) { + pr_warn("%s: too few lane-polarities entries (need %u, got %u)\n", + node->full_name, 1 + bus->num_data_lanes, i); + return -EINVAL; + } } if (!of_property_read_u32(node, "clock-lanes", &v)) { @@ -56,6 +73,8 @@ static void v4l2_of_parse_csi_bus(const struct device_node *node, bus->flags = flags; endpoint->bus_type = V4L2_MBUS_CSI2; + + return 0; } static void v4l2_of_parse_parallel_bus(const struct device_node *node, @@ -127,11 +146,15 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, int v4l2_of_parse_endpoint(const struct device_node *node, struct v4l2_of_endpoint *endpoint) { + int rval; + of_graph_parse_endpoint(node, &endpoint->base); endpoint->bus_type = 0; memset(&endpoint->bus, 0, sizeof(endpoint->bus)); - v4l2_of_parse_csi_bus(node, endpoint); + rval = v4l2_of_parse_csi_bus(node, endpoint); + if (rval) + return rval; /* * Parse the parallel video bus properties only if none * of the MIPI CSI-2 specific properties were found. diff --git a/include/media/v4l2-of.h b/include/media/v4l2-of.h index 70fa7b7b0487..2de42c584eb2 100644 --- a/include/media/v4l2-of.h +++ b/include/media/v4l2-of.h @@ -29,12 +29,15 @@ struct device_node; * @data_lanes: an array of physical data lane indexes * @clock_lane: physical lane index of the clock lane * @num_data_lanes: number of data lanes + * @lane_polarities: polarity of the lanes. The order is the same of + * the physical lanes. */ struct v4l2_of_bus_mipi_csi2 { unsigned int flags; unsigned char data_lanes[4]; unsigned char clock_lane; unsigned short num_data_lanes; + bool lane_polarities[5]; }; /** -- cgit v1.2.3 From 64bf8049a2ec1e61e1475eb02b5514d7061d443e Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Wed, 4 Mar 2015 17:13:24 -0300 Subject: [media] am437x: include linux/videodev2.h for expanding BASE_VIDIOC_PRIVATE In am437x-vpfe.h BASE_VIDIOC_PRIVATE is used for making the name of ioctl command(VIDIOC_AM437X_CCDC_CFG). The definition of BASE_VIDIOC_PRIVATE is in linux/videodev2.h. However, linux/videodev2.h is not included in am437x-vpfe.h. As the result an application using has to include both am437x-vpfe.h and linux/videodev2.h. With this patch, the application can include just am437x-vpfe.h. Signed-off-by: Masatake YAMATO Acked-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/am437x-vpfe.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/am437x-vpfe.h b/include/uapi/linux/am437x-vpfe.h index 9b03033f9cd6..d75774317b9b 100644 --- a/include/uapi/linux/am437x-vpfe.h +++ b/include/uapi/linux/am437x-vpfe.h @@ -21,6 +21,8 @@ #ifndef AM437X_VPFE_USER_H #define AM437X_VPFE_USER_H +#include + enum vpfe_ccdc_data_size { VPFE_CCDC_DATA_16BITS = 0, VPFE_CCDC_DATA_15BITS, -- cgit v1.2.3 From aa05b979f14998fec16fa38f1c91eaa197e73148 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 8 Mar 2015 04:53:32 -0300 Subject: [media] videodev2.h: fix comment The quantization comment in the header was incorrect w.r.t. BT.2020. Fix this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index fbdc3602ee27..15b21e481246 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -268,9 +268,10 @@ enum v4l2_ycbcr_encoding { enum v4l2_quantization { /* - * The default for R'G'B' quantization is always full range. For - * Y'CbCr the quantization is always limited range, except for - * SYCC, XV601, XV709 or JPEG: those are full range. + * The default for R'G'B' quantization is always full range, except + * for the BT2020 colorspace. For Y'CbCr the quantization is always + * limited range, except for COLORSPACE_JPEG, SYCC, XV601 or XV709: + * those are full range. */ V4L2_QUANTIZATION_DEFAULT = 0, V4L2_QUANTIZATION_FULL_RANGE = 1, -- cgit v1.2.3 From a37462b919e1368ea3cf4bb0cbdb00ca8e76959c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sat, 31 Jan 2015 20:21:32 -0300 Subject: [media] V4L: remove clock name from v4l2_clk API All uses of the v4l2_clk API so far only register one clock with a fixed name. This allows us to get rid of it, which also will make CCF and DT integration easier. Signed-off-by: Guennadi Liakhovetski Acked-by: Laurent Pinchart Tested-by: Josh Wu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/soc_camera.c | 6 ++--- drivers/media/usb/em28xx/em28xx-camera.c | 2 +- drivers/media/v4l2-core/v4l2-clk.c | 33 ++++++++++---------------- include/media/v4l2-clk.h | 8 +++---- 4 files changed, 20 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 1ed0a0bc8d44..2049037149a1 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1364,7 +1364,7 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd, snprintf(clk_name, sizeof(clk_name), "%d-%04x", shd->i2c_adapter_id, shd->board_info->addr); - icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd); + icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); if (IS_ERR(icd->clk)) { ret = PTR_ERR(icd->clk); goto eclkreg; @@ -1545,7 +1545,7 @@ static int scan_async_group(struct soc_camera_host *ici, snprintf(clk_name, sizeof(clk_name), "%d-%04x", sasd->asd.match.i2c.adapter_id, sasd->asd.match.i2c.address); - icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd); + icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); if (IS_ERR(icd->clk)) { ret = PTR_ERR(icd->clk); goto eclkreg; @@ -1650,7 +1650,7 @@ static int soc_of_bind(struct soc_camera_host *ici, snprintf(clk_name, sizeof(clk_name), "of-%s", of_node_full_name(remote)); - icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd); + icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); if (IS_ERR(icd->clk)) { ret = PTR_ERR(icd->clk); goto eclkreg; diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 7be661f73930..a4b22c2c3ba7 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -330,7 +330,7 @@ int em28xx_init_camera(struct em28xx *dev) v4l2_clk_name_i2c(clk_name, sizeof(clk_name), i2c_adapter_id(adap), client->addr); - v4l2->clk = v4l2_clk_register_fixed(clk_name, "mclk", -EINVAL); + v4l2->clk = v4l2_clk_register_fixed(clk_name, -EINVAL); if (IS_ERR(v4l2->clk)) return PTR_ERR(v4l2->clk); diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c index e18cc0469cf8..3ff0b0093b0e 100644 --- a/drivers/media/v4l2-core/v4l2-clk.c +++ b/drivers/media/v4l2-core/v4l2-clk.c @@ -23,17 +23,13 @@ static DEFINE_MUTEX(clk_lock); static LIST_HEAD(clk_list); -static struct v4l2_clk *v4l2_clk_find(const char *dev_id, const char *id) +static struct v4l2_clk *v4l2_clk_find(const char *dev_id) { struct v4l2_clk *clk; - list_for_each_entry(clk, &clk_list, list) { - if (strcmp(dev_id, clk->dev_id)) - continue; - - if (!id || !clk->id || !strcmp(clk->id, id)) + list_for_each_entry(clk, &clk_list, list) + if (!strcmp(dev_id, clk->dev_id)) return clk; - } return ERR_PTR(-ENODEV); } @@ -43,7 +39,7 @@ struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id) struct v4l2_clk *clk; mutex_lock(&clk_lock); - clk = v4l2_clk_find(dev_name(dev), id); + clk = v4l2_clk_find(dev_name(dev)); if (!IS_ERR(clk)) atomic_inc(&clk->use_count); @@ -127,8 +123,8 @@ void v4l2_clk_disable(struct v4l2_clk *clk) mutex_lock(&clk->lock); enable = --clk->enable; - if (WARN(enable < 0, "Unbalanced %s() on %s:%s!\n", __func__, - clk->dev_id, clk->id)) + if (WARN(enable < 0, "Unbalanced %s() on %s!\n", __func__, + clk->dev_id)) clk->enable++; else if (!enable && clk->ops->disable) clk->ops->disable(clk); @@ -181,7 +177,7 @@ EXPORT_SYMBOL(v4l2_clk_set_rate); struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops, const char *dev_id, - const char *id, void *priv) + void *priv) { struct v4l2_clk *clk; int ret; @@ -193,9 +189,8 @@ struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops, if (!clk) return ERR_PTR(-ENOMEM); - clk->id = kstrdup(id, GFP_KERNEL); clk->dev_id = kstrdup(dev_id, GFP_KERNEL); - if ((id && !clk->id) || !clk->dev_id) { + if (!clk->dev_id) { ret = -ENOMEM; goto ealloc; } @@ -205,7 +200,7 @@ struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops, mutex_init(&clk->lock); mutex_lock(&clk_lock); - if (!IS_ERR(v4l2_clk_find(dev_id, id))) { + if (!IS_ERR(v4l2_clk_find(dev_id))) { mutex_unlock(&clk_lock); ret = -EEXIST; goto eexist; @@ -217,7 +212,6 @@ struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops, eexist: ealloc: - kfree(clk->id); kfree(clk->dev_id); kfree(clk); return ERR_PTR(ret); @@ -227,15 +221,14 @@ EXPORT_SYMBOL(v4l2_clk_register); void v4l2_clk_unregister(struct v4l2_clk *clk) { if (WARN(atomic_read(&clk->use_count), - "%s(): Refusing to unregister ref-counted %s:%s clock!\n", - __func__, clk->dev_id, clk->id)) + "%s(): Refusing to unregister ref-counted %s clock!\n", + __func__, clk->dev_id)) return; mutex_lock(&clk_lock); list_del(&clk->list); mutex_unlock(&clk_lock); - kfree(clk->id); kfree(clk->dev_id); kfree(clk); } @@ -253,7 +246,7 @@ static unsigned long fixed_get_rate(struct v4l2_clk *clk) } struct v4l2_clk *__v4l2_clk_register_fixed(const char *dev_id, - const char *id, unsigned long rate, struct module *owner) + unsigned long rate, struct module *owner) { struct v4l2_clk *clk; struct v4l2_clk_fixed *priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -265,7 +258,7 @@ struct v4l2_clk *__v4l2_clk_register_fixed(const char *dev_id, priv->ops.get_rate = fixed_get_rate; priv->ops.owner = owner; - clk = v4l2_clk_register(&priv->ops, dev_id, id, priv); + clk = v4l2_clk_register(&priv->ops, dev_id, priv); if (IS_ERR(clk)) kfree(priv); diff --git a/include/media/v4l2-clk.h b/include/media/v4l2-clk.h index 0b36cc138304..928045f4e70c 100644 --- a/include/media/v4l2-clk.h +++ b/include/media/v4l2-clk.h @@ -26,7 +26,6 @@ struct v4l2_clk { struct list_head list; const struct v4l2_clk_ops *ops; const char *dev_id; - const char *id; int enable; struct mutex lock; /* Protect the enable count */ atomic_t use_count; @@ -43,7 +42,7 @@ struct v4l2_clk_ops { struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops, const char *dev_name, - const char *name, void *priv); + void *priv); void v4l2_clk_unregister(struct v4l2_clk *clk); struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id); void v4l2_clk_put(struct v4l2_clk *clk); @@ -55,14 +54,13 @@ int v4l2_clk_set_rate(struct v4l2_clk *clk, unsigned long rate); struct module; struct v4l2_clk *__v4l2_clk_register_fixed(const char *dev_id, - const char *id, unsigned long rate, struct module *owner); + unsigned long rate, struct module *owner); void v4l2_clk_unregister_fixed(struct v4l2_clk *clk); static inline struct v4l2_clk *v4l2_clk_register_fixed(const char *dev_id, - const char *id, unsigned long rate) { - return __v4l2_clk_register_fixed(dev_id, id, rate, THIS_MODULE); + return __v4l2_clk_register_fixed(dev_id, rate, THIS_MODULE); } #define v4l2_clk_name_i2c(name, size, adap, client) snprintf(name, size, \ -- cgit v1.2.3 From 4f528afcfbcac540c8690b41307cac5c22088ff1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sun, 1 Feb 2015 08:12:33 -0300 Subject: [media] V4L: add CCF support to the v4l2_clk API V4L2 clocks, e.g. used by camera sensors for their master clock, do not have to be supplied by a different V4L2 driver, they can also be supplied by an independent source. In this case the standart kernel clock API should be used to handle such clocks. This patch adds support for such cases. Signed-off-by: Guennadi Liakhovetski Acked-by: Laurent Pinchart Tested-by: Josh Wu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-clk.c | 48 +++++++++++++++++++++++++++++++++++--- include/media/v4l2-clk.h | 2 ++ 2 files changed, 47 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c index 3ff0b0093b0e..34e416a554f6 100644 --- a/drivers/media/v4l2-core/v4l2-clk.c +++ b/drivers/media/v4l2-core/v4l2-clk.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -37,6 +38,21 @@ static struct v4l2_clk *v4l2_clk_find(const char *dev_id) struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id) { struct v4l2_clk *clk; + struct clk *ccf_clk = clk_get(dev, id); + + if (PTR_ERR(ccf_clk) == -EPROBE_DEFER) + return ERR_PTR(-EPROBE_DEFER); + + if (!IS_ERR_OR_NULL(ccf_clk)) { + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + if (!clk) { + clk_put(ccf_clk); + return ERR_PTR(-ENOMEM); + } + clk->clk = ccf_clk; + + return clk; + } mutex_lock(&clk_lock); clk = v4l2_clk_find(dev_name(dev)); @@ -56,6 +72,12 @@ void v4l2_clk_put(struct v4l2_clk *clk) if (IS_ERR(clk)) return; + if (clk->clk) { + clk_put(clk->clk); + kfree(clk); + return; + } + mutex_lock(&clk_lock); list_for_each_entry(tmp, &clk_list, list) @@ -93,8 +115,12 @@ static void v4l2_clk_unlock_driver(struct v4l2_clk *clk) int v4l2_clk_enable(struct v4l2_clk *clk) { - int ret = v4l2_clk_lock_driver(clk); + int ret; + if (clk->clk) + return clk_prepare_enable(clk->clk); + + ret = v4l2_clk_lock_driver(clk); if (ret < 0) return ret; @@ -120,6 +146,9 @@ void v4l2_clk_disable(struct v4l2_clk *clk) { int enable; + if (clk->clk) + return clk_disable_unprepare(clk->clk); + mutex_lock(&clk->lock); enable = --clk->enable; @@ -137,8 +166,12 @@ EXPORT_SYMBOL(v4l2_clk_disable); unsigned long v4l2_clk_get_rate(struct v4l2_clk *clk) { - int ret = v4l2_clk_lock_driver(clk); + int ret; + + if (clk->clk) + return clk_get_rate(clk->clk); + ret = v4l2_clk_lock_driver(clk); if (ret < 0) return ret; @@ -157,7 +190,16 @@ EXPORT_SYMBOL(v4l2_clk_get_rate); int v4l2_clk_set_rate(struct v4l2_clk *clk, unsigned long rate) { - int ret = v4l2_clk_lock_driver(clk); + int ret; + + if (clk->clk) { + long r = clk_round_rate(clk->clk, rate); + if (r < 0) + return r; + return clk_set_rate(clk->clk, r); + } + + ret = v4l2_clk_lock_driver(clk); if (ret < 0) return ret; diff --git a/include/media/v4l2-clk.h b/include/media/v4l2-clk.h index 928045f4e70c..3ef6e3d5ed6c 100644 --- a/include/media/v4l2-clk.h +++ b/include/media/v4l2-clk.h @@ -22,6 +22,7 @@ struct module; struct device; +struct clk; struct v4l2_clk { struct list_head list; const struct v4l2_clk_ops *ops; @@ -29,6 +30,7 @@ struct v4l2_clk { int enable; struct mutex lock; /* Protect the enable count */ atomic_t use_count; + struct clk *clk; void *priv; }; -- cgit v1.2.3 From 7c3be9f812be6c2466ecb705200fc13cc34caa9c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 20 Sep 2014 18:38:56 -0300 Subject: [media] v4l: mt9p031: Convert to the gpiod API This simplifies platform data and DT integration. Signed-off-by: Laurent Pinchart Reviewed-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9p031.c | 31 +++++++++++-------------------- include/media/mt9p031.h | 2 -- 2 files changed, 11 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 9258d048a1e3..0db15f528ac1 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -15,12 +15,11 @@ #include #include #include -#include +#include #include #include #include #include -#include #include #include #include @@ -136,7 +135,7 @@ struct mt9p031 { struct aptina_pll pll; unsigned int clk_div; bool use_pll; - int reset; + struct gpio_desc *reset; struct v4l2_ctrl_handler ctrls; struct v4l2_ctrl *blc_auto; @@ -309,9 +308,9 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031) { int ret; - /* Ensure RESET_BAR is low */ - if (gpio_is_valid(mt9p031->reset)) { - gpio_set_value(mt9p031->reset, 0); + /* Ensure RESET_BAR is active */ + if (mt9p031->reset) { + gpiod_set_value(mt9p031->reset, 1); usleep_range(1000, 2000); } @@ -332,8 +331,8 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031) } /* Now RESET_BAR must be high */ - if (gpio_is_valid(mt9p031->reset)) { - gpio_set_value(mt9p031->reset, 1); + if (mt9p031->reset) { + gpiod_set_value(mt9p031->reset, 0); usleep_range(1000, 2000); } @@ -342,8 +341,8 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031) static void mt9p031_power_off(struct mt9p031 *mt9p031) { - if (gpio_is_valid(mt9p031->reset)) { - gpio_set_value(mt9p031->reset, 0); + if (mt9p031->reset) { + gpiod_set_value(mt9p031->reset, 1); usleep_range(1000, 2000); } @@ -1023,7 +1022,6 @@ mt9p031_get_pdata(struct i2c_client *client) if (!pdata) goto done; - pdata->reset = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0); of_property_read_u32(np, "input-clock-frequency", &pdata->ext_freq); of_property_read_u32(np, "pixel-clock-frequency", &pdata->target_freq); @@ -1060,7 +1058,6 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->output_control = MT9P031_OUTPUT_CONTROL_DEF; mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC; mt9p031->model = did->driver_data; - mt9p031->reset = -1; mt9p031->regulators[0].supply = "vdd"; mt9p031->regulators[1].supply = "vdd_io"; @@ -1136,14 +1133,8 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->format.field = V4L2_FIELD_NONE; mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB; - if (gpio_is_valid(pdata->reset)) { - ret = devm_gpio_request_one(&client->dev, pdata->reset, - GPIOF_OUT_INIT_LOW, "mt9p031_rst"); - if (ret < 0) - goto done; - - mt9p031->reset = pdata->reset; - } + mt9p031->reset = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); ret = mt9p031_clk_setup(mt9p031); if (ret) diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h index b1e63f2b72bd..1ba361205af1 100644 --- a/include/media/mt9p031.h +++ b/include/media/mt9p031.h @@ -5,12 +5,10 @@ struct v4l2_subdev; /* * struct mt9p031_platform_data - MT9P031 platform data - * @reset: Chip reset GPIO (set to -1 if not used) * @ext_freq: Input clock frequency * @target_freq: Pixel clock frequency */ struct mt9p031_platform_data { - int reset; int ext_freq; int target_freq; }; -- cgit v1.2.3 From c4c0283ab3cd78f8c53e708f8e75e8ed80468a31 Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 20 Mar 2015 18:03:52 -0300 Subject: [media] media: i2c: add support for omnivision's ov2659 sensor this patch adds support for omnivision's ov2659 sensor, the driver supports following features: 1: Asynchronous probing 2: DT support 3: Media controller support Signed-off-by: Benoit Parrot Signed-off-by: Lad, Prabhakar Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/ov2659.txt | 38 + MAINTAINERS | 10 + drivers/media/i2c/Kconfig | 11 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/ov2659.c | 1509 ++++++++++++++++++++ include/media/ov2659.h | 34 + 6 files changed, 1603 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/ov2659.txt create mode 100644 drivers/media/i2c/ov2659.c create mode 100644 include/media/ov2659.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/media/i2c/ov2659.txt b/Documentation/devicetree/bindings/media/i2c/ov2659.txt new file mode 100644 index 000000000000..cabc7d827dfb --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ov2659.txt @@ -0,0 +1,38 @@ +* OV2659 1/5-Inch 2Mp SOC Camera + +The Omnivision OV2659 is a 1/5-inch SOC camera, with an active array size of +1632H x 1212V. It is programmable through a SCCB. The OV2659 sensor supports +multiple resolutions output, such as UXGA, SVGA, 720p. It also can support +YUV422, RGB565/555 or raw RGB output formats. + +Required Properties: +- compatible: Must be "ovti,ov2659" +- reg: I2C slave address +- clocks: reference to the xvclk input clock. +- clock-names: should be "xvclk". +- link-frequencies: target pixel clock frequency. + +For further reading on port node refer to +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + i2c0@1c22000 { + ... + ... + ov2659@30 { + compatible = "ovti,ov2659"; + reg = <0x30>; + + clocks = <&clk_ov2659 0>; + clock-names = "xvclk"; + + port { + ov2659_0: endpoint { + remote-endpoint = <&vpfe_ep>; + link-frequencies = /bits/ 64 <70000000>; + }; + }; + }; + ... + }; diff --git a/MAINTAINERS b/MAINTAINERS index 97c174b544a4..460194ca7927 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8911,6 +8911,16 @@ T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git S: Maintained F: drivers/media/platform/am437x/ +OV2659 OMNIVISION SENSOR DRIVER +M: Lad, Prabhakar +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git +S: Maintained +F: drivers/media/i2c/ov2659.c +F: include/media/ov2659.h + SIS 190 ETHERNET DRIVER M: Francois Romieu L: netdev@vger.kernel.org diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index da58c9bb67c2..6f30ea76151a 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -466,6 +466,17 @@ config VIDEO_APTINA_PLL config VIDEO_SMIAPP_PLL tristate +config VIDEO_OV2659 + tristate "OmniVision OV2659 sensor support" + depends on VIDEO_V4L2 && I2C + depends on MEDIA_CAMERA_SUPPORT + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV2659 camera. + + To compile this driver as a module, choose M here: the + module will be called ov2659. + config VIDEO_OV7640 tristate "OmniVision OV7640 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 9858900168bf..f165faea5b3f 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -77,3 +77,4 @@ obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o obj-$(CONFIG_VIDEO_AK881X) += ak881x.o obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o +obj-$(CONFIG_VIDEO_OV2659) += ov2659.o diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c new file mode 100644 index 000000000000..edebd114279d --- /dev/null +++ b/drivers/media/i2c/ov2659.c @@ -0,0 +1,1509 @@ +/* + * Omnivision OV2659 CMOS Image Sensor driver + * + * Copyright (C) 2015 Texas Instruments, Inc. + * + * Benoit Parrot + * Lad, Prabhakar + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "ov2659" + +/* + * OV2659 register definitions + */ +#define REG_SOFTWARE_STANDBY 0x0100 +#define REG_SOFTWARE_RESET 0x0103 +#define REG_IO_CTRL00 0x3000 +#define REG_IO_CTRL01 0x3001 +#define REG_IO_CTRL02 0x3002 +#define REG_OUTPUT_VALUE00 0x3008 +#define REG_OUTPUT_VALUE01 0x3009 +#define REG_OUTPUT_VALUE02 0x300d +#define REG_OUTPUT_SELECT00 0x300e +#define REG_OUTPUT_SELECT01 0x300f +#define REG_OUTPUT_SELECT02 0x3010 +#define REG_OUTPUT_DRIVE 0x3011 +#define REG_INPUT_READOUT00 0x302d +#define REG_INPUT_READOUT01 0x302e +#define REG_INPUT_READOUT02 0x302f + +#define REG_SC_PLL_CTRL0 0x3003 +#define REG_SC_PLL_CTRL1 0x3004 +#define REG_SC_PLL_CTRL2 0x3005 +#define REG_SC_PLL_CTRL3 0x3006 +#define REG_SC_CHIP_ID_H 0x300a +#define REG_SC_CHIP_ID_L 0x300b +#define REG_SC_PWC 0x3014 +#define REG_SC_CLKRST0 0x301a +#define REG_SC_CLKRST1 0x301b +#define REG_SC_CLKRST2 0x301c +#define REG_SC_CLKRST3 0x301d +#define REG_SC_SUB_ID 0x302a +#define REG_SC_SCCB_ID 0x302b + +#define REG_GROUP_ADDRESS_00 0x3200 +#define REG_GROUP_ADDRESS_01 0x3201 +#define REG_GROUP_ADDRESS_02 0x3202 +#define REG_GROUP_ADDRESS_03 0x3203 +#define REG_GROUP_ACCESS 0x3208 + +#define REG_AWB_R_GAIN_H 0x3400 +#define REG_AWB_R_GAIN_L 0x3401 +#define REG_AWB_G_GAIN_H 0x3402 +#define REG_AWB_G_GAIN_L 0x3403 +#define REG_AWB_B_GAIN_H 0x3404 +#define REG_AWB_B_GAIN_L 0x3405 +#define REG_AWB_MANUAL_CONTROL 0x3406 + +#define REG_TIMING_HS_H 0x3800 +#define REG_TIMING_HS_L 0x3801 +#define REG_TIMING_VS_H 0x3802 +#define REG_TIMING_VS_L 0x3803 +#define REG_TIMING_HW_H 0x3804 +#define REG_TIMING_HW_L 0x3805 +#define REG_TIMING_VH_H 0x3806 +#define REG_TIMING_VH_L 0x3807 +#define REG_TIMING_DVPHO_H 0x3808 +#define REG_TIMING_DVPHO_L 0x3809 +#define REG_TIMING_DVPVO_H 0x380a +#define REG_TIMING_DVPVO_L 0x380b +#define REG_TIMING_HTS_H 0x380c +#define REG_TIMING_HTS_L 0x380d +#define REG_TIMING_VTS_H 0x380e +#define REG_TIMING_VTS_L 0x380f +#define REG_TIMING_HOFFS_H 0x3810 +#define REG_TIMING_HOFFS_L 0x3811 +#define REG_TIMING_VOFFS_H 0x3812 +#define REG_TIMING_VOFFS_L 0x3813 +#define REG_TIMING_XINC 0x3814 +#define REG_TIMING_YINC 0x3815 +#define REG_TIMING_VERT_FORMAT 0x3820 +#define REG_TIMING_HORIZ_FORMAT 0x3821 + +#define REG_FORMAT_CTRL00 0x4300 + +#define REG_VFIFO_READ_START_H 0x4608 +#define REG_VFIFO_READ_START_L 0x4609 + +#define REG_DVP_CTRL02 0x4708 + +#define REG_ISP_CTRL00 0x5000 +#define REG_ISP_CTRL01 0x5001 +#define REG_ISP_CTRL02 0x5002 + +#define REG_LENC_RED_X0_H 0x500c +#define REG_LENC_RED_X0_L 0x500d +#define REG_LENC_RED_Y0_H 0x500e +#define REG_LENC_RED_Y0_L 0x500f +#define REG_LENC_RED_A1 0x5010 +#define REG_LENC_RED_B1 0x5011 +#define REG_LENC_RED_A2_B2 0x5012 +#define REG_LENC_GREEN_X0_H 0x5013 +#define REG_LENC_GREEN_X0_L 0x5014 +#define REG_LENC_GREEN_Y0_H 0x5015 +#define REG_LENC_GREEN_Y0_L 0x5016 +#define REG_LENC_GREEN_A1 0x5017 +#define REG_LENC_GREEN_B1 0x5018 +#define REG_LENC_GREEN_A2_B2 0x5019 +#define REG_LENC_BLUE_X0_H 0x501a +#define REG_LENC_BLUE_X0_L 0x501b +#define REG_LENC_BLUE_Y0_H 0x501c +#define REG_LENC_BLUE_Y0_L 0x501d +#define REG_LENC_BLUE_A1 0x501e +#define REG_LENC_BLUE_B1 0x501f +#define REG_LENC_BLUE_A2_B2 0x5020 + +#define REG_AWB_CTRL00 0x5035 +#define REG_AWB_CTRL01 0x5036 +#define REG_AWB_CTRL02 0x5037 +#define REG_AWB_CTRL03 0x5038 +#define REG_AWB_CTRL04 0x5039 +#define REG_AWB_LOCAL_LIMIT 0x503a +#define REG_AWB_CTRL12 0x5049 +#define REG_AWB_CTRL13 0x504a +#define REG_AWB_CTRL14 0x504b + +#define REG_SHARPENMT_THRESH1 0x5064 +#define REG_SHARPENMT_THRESH2 0x5065 +#define REG_SHARPENMT_OFFSET1 0x5066 +#define REG_SHARPENMT_OFFSET2 0x5067 +#define REG_DENOISE_THRESH1 0x5068 +#define REG_DENOISE_THRESH2 0x5069 +#define REG_DENOISE_OFFSET1 0x506a +#define REG_DENOISE_OFFSET2 0x506b +#define REG_SHARPEN_THRESH1 0x506c +#define REG_SHARPEN_THRESH2 0x506d +#define REG_CIP_CTRL00 0x506e +#define REG_CIP_CTRL01 0x506f + +#define REG_CMX_SIGN 0x5079 +#define REG_CMX_MISC_CTRL 0x507a + +#define REG_PRE_ISP_CTRL00 0x50a0 +#define TEST_PATTERN_ENABLE BIT(7) +#define VERTICAL_COLOR_BAR_MASK 0x53 + +#define REG_NULL 0x0000 /* Array end token */ + +#define OV265X_ID(_msb, _lsb) ((_msb) << 8 | (_lsb)) +#define OV2659_ID 0x2656 + +struct sensor_register { + u16 addr; + u8 value; +}; + +struct ov2659_framesize { + u16 width; + u16 height; + u16 max_exp_lines; + const struct sensor_register *regs; +}; + +struct ov2659_pll_ctrl { + u8 ctrl1; + u8 ctrl2; + u8 ctrl3; +}; + +struct ov2659_pixfmt { + u32 code; + /* Output format Register Value (REG_FORMAT_CTRL00) */ + struct sensor_register *format_ctrl_regs; +}; + +struct pll_ctrl_reg { + unsigned int div; + unsigned char reg; +}; + +struct ov2659 { + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_mbus_framefmt format; + unsigned int xvclk_frequency; + const struct ov2659_platform_data *pdata; + struct mutex lock; + struct i2c_client *client; + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *link_frequency; + const struct ov2659_framesize *frame_size; + struct sensor_register *format_ctrl_regs; + struct ov2659_pll_ctrl pll; + int streaming; +}; + +static const struct sensor_register ov2659_init_regs[] = { + { REG_IO_CTRL00, 0x03 }, + { REG_IO_CTRL01, 0xff }, + { REG_IO_CTRL02, 0xe0 }, + { 0x3633, 0x3d }, + { 0x3620, 0x02 }, + { 0x3631, 0x11 }, + { 0x3612, 0x04 }, + { 0x3630, 0x20 }, + { 0x4702, 0x02 }, + { 0x370c, 0x34 }, + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xb7 }, + { REG_TIMING_DVPHO_H, 0x03 }, + { REG_TIMING_DVPHO_L, 0x20 }, + { REG_TIMING_DVPVO_H, 0x02 }, + { REG_TIMING_DVPVO_L, 0x58 }, + { REG_TIMING_HTS_H, 0x05 }, + { REG_TIMING_HTS_L, 0x14 }, + { REG_TIMING_VTS_H, 0x02 }, + { REG_TIMING_VTS_L, 0x68 }, + { REG_TIMING_HOFFS_L, 0x08 }, + { REG_TIMING_VOFFS_L, 0x02 }, + { REG_TIMING_XINC, 0x31 }, + { REG_TIMING_YINC, 0x31 }, + { 0x3a02, 0x02 }, + { 0x3a03, 0x68 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0x5c }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x4d }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x02 }, + { 0x3a15, 0x28 }, + { REG_DVP_CTRL02, 0x01 }, + { 0x3623, 0x00 }, + { 0x3634, 0x76 }, + { 0x3701, 0x44 }, + { 0x3702, 0x18 }, + { 0x3703, 0x24 }, + { 0x3704, 0x24 }, + { 0x3705, 0x0c }, + { REG_TIMING_VERT_FORMAT, 0x81 }, + { REG_TIMING_HORIZ_FORMAT, 0x01 }, + { 0x370a, 0x52 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_FORMAT_CTRL00, 0x30 }, + { 0x5086, 0x02 }, + { REG_ISP_CTRL00, 0xfb }, + { REG_ISP_CTRL01, 0x1f }, + { REG_ISP_CTRL02, 0x00 }, + { 0x5025, 0x0e }, + { 0x5026, 0x18 }, + { 0x5027, 0x34 }, + { 0x5028, 0x4c }, + { 0x5029, 0x62 }, + { 0x502a, 0x74 }, + { 0x502b, 0x85 }, + { 0x502c, 0x92 }, + { 0x502d, 0x9e }, + { 0x502e, 0xb2 }, + { 0x502f, 0xc0 }, + { 0x5030, 0xcc }, + { 0x5031, 0xe0 }, + { 0x5032, 0xee }, + { 0x5033, 0xf6 }, + { 0x5034, 0x11 }, + { 0x5070, 0x1c }, + { 0x5071, 0x5b }, + { 0x5072, 0x05 }, + { 0x5073, 0x20 }, + { 0x5074, 0x94 }, + { 0x5075, 0xb4 }, + { 0x5076, 0xb4 }, + { 0x5077, 0xaf }, + { 0x5078, 0x05 }, + { REG_CMX_SIGN, 0x98 }, + { REG_CMX_MISC_CTRL, 0x21 }, + { REG_AWB_CTRL00, 0x6a }, + { REG_AWB_CTRL01, 0x11 }, + { REG_AWB_CTRL02, 0x92 }, + { REG_AWB_CTRL03, 0x21 }, + { REG_AWB_CTRL04, 0xe1 }, + { REG_AWB_LOCAL_LIMIT, 0x01 }, + { 0x503c, 0x05 }, + { 0x503d, 0x08 }, + { 0x503e, 0x08 }, + { 0x503f, 0x64 }, + { 0x5040, 0x58 }, + { 0x5041, 0x2a }, + { 0x5042, 0xc5 }, + { 0x5043, 0x2e }, + { 0x5044, 0x3a }, + { 0x5045, 0x3c }, + { 0x5046, 0x44 }, + { 0x5047, 0xf8 }, + { 0x5048, 0x08 }, + { REG_AWB_CTRL12, 0x70 }, + { REG_AWB_CTRL13, 0xf0 }, + { REG_AWB_CTRL14, 0xf0 }, + { REG_LENC_RED_X0_H, 0x03 }, + { REG_LENC_RED_X0_L, 0x20 }, + { REG_LENC_RED_Y0_H, 0x02 }, + { REG_LENC_RED_Y0_L, 0x5c }, + { REG_LENC_RED_A1, 0x48 }, + { REG_LENC_RED_B1, 0x00 }, + { REG_LENC_RED_A2_B2, 0x66 }, + { REG_LENC_GREEN_X0_H, 0x03 }, + { REG_LENC_GREEN_X0_L, 0x30 }, + { REG_LENC_GREEN_Y0_H, 0x02 }, + { REG_LENC_GREEN_Y0_L, 0x7c }, + { REG_LENC_GREEN_A1, 0x40 }, + { REG_LENC_GREEN_B1, 0x00 }, + { REG_LENC_GREEN_A2_B2, 0x66 }, + { REG_LENC_BLUE_X0_H, 0x03 }, + { REG_LENC_BLUE_X0_L, 0x10 }, + { REG_LENC_BLUE_Y0_H, 0x02 }, + { REG_LENC_BLUE_Y0_L, 0x7c }, + { REG_LENC_BLUE_A1, 0x3a }, + { REG_LENC_BLUE_B1, 0x00 }, + { REG_LENC_BLUE_A2_B2, 0x66 }, + { REG_CIP_CTRL00, 0x44 }, + { REG_SHARPENMT_THRESH1, 0x08 }, + { REG_SHARPENMT_THRESH2, 0x10 }, + { REG_SHARPENMT_OFFSET1, 0x12 }, + { REG_SHARPENMT_OFFSET2, 0x02 }, + { REG_SHARPEN_THRESH1, 0x08 }, + { REG_SHARPEN_THRESH2, 0x10 }, + { REG_CIP_CTRL01, 0xa6 }, + { REG_DENOISE_THRESH1, 0x08 }, + { REG_DENOISE_THRESH2, 0x10 }, + { REG_DENOISE_OFFSET1, 0x04 }, + { REG_DENOISE_OFFSET2, 0x12 }, + { 0x507e, 0x40 }, + { 0x507f, 0x20 }, + { 0x507b, 0x02 }, + { REG_CMX_MISC_CTRL, 0x01 }, + { 0x5084, 0x0c }, + { 0x5085, 0x3e }, + { 0x5005, 0x80 }, + { 0x3a0f, 0x30 }, + { 0x3a10, 0x28 }, + { 0x3a1b, 0x32 }, + { 0x3a1e, 0x26 }, + { 0x3a11, 0x60 }, + { 0x3a1f, 0x14 }, + { 0x5060, 0x69 }, + { 0x5061, 0x7d }, + { 0x5062, 0x7d }, + { 0x5063, 0x69 }, + { REG_NULL, 0x00 }, +}; + +/* 1280X720 720p */ +static struct sensor_register ov2659_720p[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0xa0 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0xf0 }, + { REG_TIMING_HW_H, 0x05 }, + { REG_TIMING_HW_L, 0xbf }, + { REG_TIMING_VH_H, 0x03 }, + { REG_TIMING_VH_L, 0xcb }, + { REG_TIMING_DVPHO_H, 0x05 }, + { REG_TIMING_DVPHO_L, 0x00 }, + { REG_TIMING_DVPVO_H, 0x02 }, + { REG_TIMING_DVPVO_L, 0xd0 }, + { REG_TIMING_HTS_H, 0x06 }, + { REG_TIMING_HTS_L, 0x4c }, + { REG_TIMING_VTS_H, 0x02 }, + { REG_TIMING_VTS_L, 0xe8 }, + { REG_TIMING_HOFFS_L, 0x10 }, + { REG_TIMING_VOFFS_L, 0x06 }, + { REG_TIMING_XINC, 0x11 }, + { REG_TIMING_YINC, 0x11 }, + { REG_TIMING_VERT_FORMAT, 0x80 }, + { REG_TIMING_HORIZ_FORMAT, 0x00 }, + { 0x3a03, 0xe8 }, + { 0x3a09, 0x6f }, + { 0x3a0b, 0x5d }, + { 0x3a15, 0x9a }, + { REG_NULL, 0x00 }, +}; + +/* 1600X1200 UXGA */ +static struct sensor_register ov2659_uxga[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xbb }, + { REG_TIMING_DVPHO_H, 0x06 }, + { REG_TIMING_DVPHO_L, 0x40 }, + { REG_TIMING_DVPVO_H, 0x04 }, + { REG_TIMING_DVPVO_L, 0xb0 }, + { REG_TIMING_HTS_H, 0x07 }, + { REG_TIMING_HTS_L, 0x9f }, + { REG_TIMING_VTS_H, 0x04 }, + { REG_TIMING_VTS_L, 0xd0 }, + { REG_TIMING_HOFFS_L, 0x10 }, + { REG_TIMING_VOFFS_L, 0x06 }, + { REG_TIMING_XINC, 0x11 }, + { REG_TIMING_YINC, 0x11 }, + { 0x3a02, 0x04 }, + { 0x3a03, 0xd0 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0xb8 }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x9a }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x04 }, + { 0x3a15, 0x50 }, + { 0x3623, 0x00 }, + { 0x3634, 0x44 }, + { 0x3701, 0x44 }, + { 0x3702, 0x30 }, + { 0x3703, 0x48 }, + { 0x3704, 0x48 }, + { 0x3705, 0x18 }, + { REG_TIMING_VERT_FORMAT, 0x80 }, + { REG_TIMING_HORIZ_FORMAT, 0x00 }, + { 0x370a, 0x12 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_ISP_CTRL02, 0x00 }, + { REG_NULL, 0x00 }, +}; + +/* 1280X1024 SXGA */ +static struct sensor_register ov2659_sxga[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xb7 }, + { REG_TIMING_DVPHO_H, 0x05 }, + { REG_TIMING_DVPHO_L, 0x00 }, + { REG_TIMING_DVPVO_H, 0x04 }, + { REG_TIMING_DVPVO_L, 0x00 }, + { REG_TIMING_HTS_H, 0x07 }, + { REG_TIMING_HTS_L, 0x9c }, + { REG_TIMING_VTS_H, 0x04 }, + { REG_TIMING_VTS_L, 0xd0 }, + { REG_TIMING_HOFFS_L, 0x10 }, + { REG_TIMING_VOFFS_L, 0x06 }, + { REG_TIMING_XINC, 0x11 }, + { REG_TIMING_YINC, 0x11 }, + { 0x3a02, 0x02 }, + { 0x3a03, 0x68 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0x5c }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x4d }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x02 }, + { 0x3a15, 0x28 }, + { 0x3623, 0x00 }, + { 0x3634, 0x76 }, + { 0x3701, 0x44 }, + { 0x3702, 0x18 }, + { 0x3703, 0x24 }, + { 0x3704, 0x24 }, + { 0x3705, 0x0c }, + { REG_TIMING_VERT_FORMAT, 0x80 }, + { REG_TIMING_HORIZ_FORMAT, 0x00 }, + { 0x370a, 0x52 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_ISP_CTRL02, 0x00 }, + { REG_NULL, 0x00 }, +}; + +/* 1024X768 SXGA */ +static struct sensor_register ov2659_xga[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xb7 }, + { REG_TIMING_DVPHO_H, 0x04 }, + { REG_TIMING_DVPHO_L, 0x00 }, + { REG_TIMING_DVPVO_H, 0x03 }, + { REG_TIMING_DVPVO_L, 0x00 }, + { REG_TIMING_HTS_H, 0x07 }, + { REG_TIMING_HTS_L, 0x9c }, + { REG_TIMING_VTS_H, 0x04 }, + { REG_TIMING_VTS_L, 0xd0 }, + { REG_TIMING_HOFFS_L, 0x10 }, + { REG_TIMING_VOFFS_L, 0x06 }, + { REG_TIMING_XINC, 0x11 }, + { REG_TIMING_YINC, 0x11 }, + { 0x3a02, 0x02 }, + { 0x3a03, 0x68 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0x5c }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x4d }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x02 }, + { 0x3a15, 0x28 }, + { 0x3623, 0x00 }, + { 0x3634, 0x76 }, + { 0x3701, 0x44 }, + { 0x3702, 0x18 }, + { 0x3703, 0x24 }, + { 0x3704, 0x24 }, + { 0x3705, 0x0c }, + { REG_TIMING_VERT_FORMAT, 0x80 }, + { REG_TIMING_HORIZ_FORMAT, 0x00 }, + { 0x370a, 0x52 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_ISP_CTRL02, 0x00 }, + { REG_NULL, 0x00 }, +}; + +/* 800X600 SVGA */ +static struct sensor_register ov2659_svga[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xb7 }, + { REG_TIMING_DVPHO_H, 0x03 }, + { REG_TIMING_DVPHO_L, 0x20 }, + { REG_TIMING_DVPVO_H, 0x02 }, + { REG_TIMING_DVPVO_L, 0x58 }, + { REG_TIMING_HTS_H, 0x05 }, + { REG_TIMING_HTS_L, 0x14 }, + { REG_TIMING_VTS_H, 0x02 }, + { REG_TIMING_VTS_L, 0x68 }, + { REG_TIMING_HOFFS_L, 0x08 }, + { REG_TIMING_VOFFS_L, 0x02 }, + { REG_TIMING_XINC, 0x31 }, + { REG_TIMING_YINC, 0x31 }, + { 0x3a02, 0x02 }, + { 0x3a03, 0x68 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0x5c }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x4d }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x02 }, + { 0x3a15, 0x28 }, + { 0x3623, 0x00 }, + { 0x3634, 0x76 }, + { 0x3701, 0x44 }, + { 0x3702, 0x18 }, + { 0x3703, 0x24 }, + { 0x3704, 0x24 }, + { 0x3705, 0x0c }, + { REG_TIMING_VERT_FORMAT, 0x81 }, + { REG_TIMING_HORIZ_FORMAT, 0x01 }, + { 0x370a, 0x52 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_ISP_CTRL02, 0x00 }, + { REG_NULL, 0x00 }, +}; + +/* 640X480 VGA */ +static struct sensor_register ov2659_vga[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xb7 }, + { REG_TIMING_DVPHO_H, 0x02 }, + { REG_TIMING_DVPHO_L, 0x80 }, + { REG_TIMING_DVPVO_H, 0x01 }, + { REG_TIMING_DVPVO_L, 0xe0 }, + { REG_TIMING_HTS_H, 0x05 }, + { REG_TIMING_HTS_L, 0x14 }, + { REG_TIMING_VTS_H, 0x02 }, + { REG_TIMING_VTS_L, 0x68 }, + { REG_TIMING_HOFFS_L, 0x08 }, + { REG_TIMING_VOFFS_L, 0x02 }, + { REG_TIMING_XINC, 0x31 }, + { REG_TIMING_YINC, 0x31 }, + { 0x3a02, 0x02 }, + { 0x3a03, 0x68 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0x5c }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x4d }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x02 }, + { 0x3a15, 0x28 }, + { 0x3623, 0x00 }, + { 0x3634, 0x76 }, + { 0x3701, 0x44 }, + { 0x3702, 0x18 }, + { 0x3703, 0x24 }, + { 0x3704, 0x24 }, + { 0x3705, 0x0c }, + { REG_TIMING_VERT_FORMAT, 0x81 }, + { REG_TIMING_HORIZ_FORMAT, 0x01 }, + { 0x370a, 0x52 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_ISP_CTRL02, 0x10 }, + { REG_NULL, 0x00 }, +}; + +/* 320X240 QVGA */ +static struct sensor_register ov2659_qvga[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xb7 }, + { REG_TIMING_DVPHO_H, 0x01 }, + { REG_TIMING_DVPHO_L, 0x40 }, + { REG_TIMING_DVPVO_H, 0x00 }, + { REG_TIMING_DVPVO_L, 0xf0 }, + { REG_TIMING_HTS_H, 0x05 }, + { REG_TIMING_HTS_L, 0x14 }, + { REG_TIMING_VTS_H, 0x02 }, + { REG_TIMING_VTS_L, 0x68 }, + { REG_TIMING_HOFFS_L, 0x08 }, + { REG_TIMING_VOFFS_L, 0x02 }, + { REG_TIMING_XINC, 0x31 }, + { REG_TIMING_YINC, 0x31 }, + { 0x3a02, 0x02 }, + { 0x3a03, 0x68 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0x5c }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x4d }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x02 }, + { 0x3a15, 0x28 }, + { 0x3623, 0x00 }, + { 0x3634, 0x76 }, + { 0x3701, 0x44 }, + { 0x3702, 0x18 }, + { 0x3703, 0x24 }, + { 0x3704, 0x24 }, + { 0x3705, 0x0c }, + { REG_TIMING_VERT_FORMAT, 0x81 }, + { REG_TIMING_HORIZ_FORMAT, 0x01 }, + { 0x370a, 0x52 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_ISP_CTRL02, 0x10 }, + { REG_NULL, 0x00 }, +}; + +static const struct pll_ctrl_reg ctrl3[] = { + { 1, 0x00 }, + { 2, 0x02 }, + { 3, 0x03 }, + { 4, 0x06 }, + { 6, 0x0d }, + { 8, 0x0e }, + { 12, 0x0f }, + { 16, 0x12 }, + { 24, 0x13 }, + { 32, 0x16 }, + { 48, 0x1b }, + { 64, 0x1e }, + { 96, 0x1f }, + { 0, 0x00 }, +}; + +static const struct pll_ctrl_reg ctrl1[] = { + { 2, 0x10 }, + { 4, 0x20 }, + { 6, 0x30 }, + { 8, 0x40 }, + { 10, 0x50 }, + { 12, 0x60 }, + { 14, 0x70 }, + { 16, 0x80 }, + { 18, 0x90 }, + { 20, 0xa0 }, + { 22, 0xb0 }, + { 24, 0xc0 }, + { 26, 0xd0 }, + { 28, 0xe0 }, + { 30, 0xf0 }, + { 0, 0x00 }, +}; + +static const struct ov2659_framesize ov2659_framesizes[] = { + { /* QVGA */ + .width = 320, + .height = 240, + .regs = ov2659_qvga, + .max_exp_lines = 248, + }, { /* VGA */ + .width = 640, + .height = 480, + .regs = ov2659_vga, + .max_exp_lines = 498, + }, { /* SVGA */ + .width = 800, + .height = 600, + .regs = ov2659_svga, + .max_exp_lines = 498, + }, { /* XGA */ + .width = 1024, + .height = 768, + .regs = ov2659_xga, + .max_exp_lines = 498, + }, { /* 720P */ + .width = 1280, + .height = 720, + .regs = ov2659_720p, + .max_exp_lines = 498, + }, { /* SXGA */ + .width = 1280, + .height = 1024, + .regs = ov2659_sxga, + .max_exp_lines = 1048, + }, { /* UXGA */ + .width = 1600, + .height = 1200, + .regs = ov2659_uxga, + .max_exp_lines = 498, + }, +}; + +/* YUV422 YUYV*/ +static struct sensor_register ov2659_format_yuyv[] = { + { REG_FORMAT_CTRL00, 0x30 }, + { REG_NULL, 0x0 }, +}; + +/* YUV422 UYVY */ +static struct sensor_register ov2659_format_uyvy[] = { + { REG_FORMAT_CTRL00, 0x32 }, + { REG_NULL, 0x0 }, +}; + +/* Raw Bayer BGGR */ +static struct sensor_register ov2659_format_bggr[] = { + { REG_FORMAT_CTRL00, 0x00 }, + { REG_NULL, 0x0 }, +}; + +/* RGB565 */ +static struct sensor_register ov2659_format_rgb565[] = { + { REG_FORMAT_CTRL00, 0x60 }, + { REG_NULL, 0x0 }, +}; + +static const struct ov2659_pixfmt ov2659_formats[] = { + { + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .format_ctrl_regs = ov2659_format_yuyv, + }, { + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .format_ctrl_regs = ov2659_format_uyvy, + }, { + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .format_ctrl_regs = ov2659_format_rgb565, + }, { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .format_ctrl_regs = ov2659_format_bggr, + }, +}; + +static inline struct ov2659 *to_ov2659(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ov2659, sd); +} + +/* sensor register write */ +static int ov2659_write(struct i2c_client *client, u16 reg, u8 val) +{ + struct i2c_msg msg; + u8 buf[3]; + int ret; + + buf[0] = reg >> 8; + buf[1] = reg & 0xFF; + buf[2] = val; + + msg.addr = client->addr; + msg.flags = client->flags; + msg.buf = buf; + msg.len = sizeof(buf); + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret >= 0) + return 0; + + dev_dbg(&client->dev, + "ov2659 write reg(0x%x val:0x%x) failed !\n", reg, val); + + return ret; +} + +/* sensor register read */ +static int ov2659_read(struct i2c_client *client, u16 reg, u8 *val) +{ + struct i2c_msg msg[2]; + u8 buf[2]; + int ret; + + buf[0] = reg >> 8; + buf[1] = reg & 0xFF; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + + msg[1].addr = client->addr; + msg[1].flags = client->flags | I2C_M_RD; + msg[1].buf = buf; + msg[1].len = 1; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret >= 0) { + *val = buf[0]; + return 0; + } + + dev_dbg(&client->dev, + "ov2659 read reg(0x%x val:0x%x) failed !\n", reg, *val); + + return ret; +} + +static int ov2659_write_array(struct i2c_client *client, + const struct sensor_register *regs) +{ + int i, ret = 0; + + for (i = 0; ret == 0 && regs[i].addr; i++) + ret = ov2659_write(client, regs[i].addr, regs[i].value); + + return ret; +} + +static void ov2659_pll_calc_params(struct ov2659 *ov2659) +{ + const struct ov2659_platform_data *pdata = ov2659->pdata; + u8 ctrl1_reg = 0, ctrl2_reg = 0, ctrl3_reg = 0; + struct i2c_client *client = ov2659->client; + unsigned int desired = pdata->link_frequency; + u32 s_prediv = 1, s_postdiv = 1, s_mult = 1; + u32 prediv, postdiv, mult; + u32 bestdelta = -1; + u32 delta, actual; + int i, j; + + for (i = 0; ctrl1[i].div != 0; i++) { + postdiv = ctrl1[i].div; + for (j = 0; ctrl3[j].div != 0; j++) { + prediv = ctrl3[j].div; + for (mult = 1; mult <= 63; mult++) { + actual = ov2659->xvclk_frequency; + actual *= mult; + actual /= prediv; + actual /= postdiv; + delta = actual - desired; + delta = abs(delta); + + if ((delta < bestdelta) || (bestdelta == -1)) { + bestdelta = delta; + s_mult = mult; + s_prediv = prediv; + s_postdiv = postdiv; + ctrl1_reg = ctrl1[i].reg; + ctrl2_reg = mult; + ctrl3_reg = ctrl3[j].reg; + } + } + } + } + + ov2659->pll.ctrl1 = ctrl1_reg; + ov2659->pll.ctrl2 = ctrl2_reg; + ov2659->pll.ctrl3 = ctrl3_reg; + + dev_dbg(&client->dev, + "Actual reg config: ctrl1_reg: %02x ctrl2_reg: %02x ctrl3_reg: %02x\n", + ctrl1_reg, ctrl2_reg, ctrl3_reg); +} + +static int ov2659_set_pixel_clock(struct ov2659 *ov2659) +{ + struct i2c_client *client = ov2659->client; + struct sensor_register pll_regs[] = { + {REG_SC_PLL_CTRL1, ov2659->pll.ctrl1}, + {REG_SC_PLL_CTRL2, ov2659->pll.ctrl2}, + {REG_SC_PLL_CTRL3, ov2659->pll.ctrl3}, + {REG_NULL, 0x00}, + }; + + dev_dbg(&client->dev, "%s\n", __func__); + + return ov2659_write_array(client, pll_regs); +}; + +static void ov2659_get_default_format(struct v4l2_mbus_framefmt *format) +{ + format->width = ov2659_framesizes[2].width; + format->height = ov2659_framesizes[2].height; + format->colorspace = V4L2_COLORSPACE_SRGB; + format->code = ov2659_formats[0].code; + format->field = V4L2_FIELD_NONE; +} + +static void ov2659_set_streaming(struct ov2659 *ov2659, int on) +{ + struct i2c_client *client = ov2659->client; + int ret; + + on = !!on; + + dev_dbg(&client->dev, "%s: on: %d\n", __func__, on); + + ret = ov2659_write(client, REG_SOFTWARE_STANDBY, on); + if (ret) + dev_err(&client->dev, "ov2659 soft standby failed\n"); +} + +static int ov2659_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return ov2659_write_array(client, ov2659_init_regs); +} + +/* + * V4L2 subdev video and pad level operations + */ + +static int ov2659_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + dev_dbg(&client->dev, "%s:\n", __func__); + + if (code->index >= ARRAY_SIZE(ov2659_formats)) + return -EINVAL; + + code->code = ov2659_formats[code->index].code; + + return 0; +} + +static int ov2659_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int i = ARRAY_SIZE(ov2659_formats); + + dev_dbg(&client->dev, "%s:\n", __func__); + + if (fse->index >= ARRAY_SIZE(ov2659_framesizes)) + return -EINVAL; + + while (--i) + if (fse->code == ov2659_formats[i].code) + break; + + fse->code = ov2659_formats[i].code; + + fse->min_width = ov2659_framesizes[fse->index].width; + fse->max_width = fse->min_width; + fse->max_height = ov2659_framesizes[fse->index].height; + fse->min_height = fse->max_height; + + return 0; +} + +static int ov2659_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov2659 *ov2659 = to_ov2659(sd); + struct v4l2_mbus_framefmt *mf; + + dev_dbg(&client->dev, "ov2659_get_fmt\n"); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(sd, cfg, 0); + mutex_lock(&ov2659->lock); + fmt->format = *mf; + mutex_unlock(&ov2659->lock); + return 0; + } + + mutex_lock(&ov2659->lock); + fmt->format = ov2659->format; + mutex_unlock(&ov2659->lock); + + dev_dbg(&client->dev, "ov2659_get_fmt: %x %dx%d\n", + ov2659->format.code, ov2659->format.width, + ov2659->format.height); + + return 0; +} + +static void __ov2659_try_frame_size(struct v4l2_mbus_framefmt *mf, + const struct ov2659_framesize **size) +{ + const struct ov2659_framesize *fsize = &ov2659_framesizes[0]; + const struct ov2659_framesize *match = NULL; + int i = ARRAY_SIZE(ov2659_framesizes); + unsigned int min_err = UINT_MAX; + + while (i--) { + int err = abs(fsize->width - mf->width) + + abs(fsize->height - mf->height); + if ((err < min_err) && (fsize->regs[0].addr)) { + min_err = err; + match = fsize; + } + fsize++; + } + + if (!match) + match = &ov2659_framesizes[2]; + + mf->width = match->width; + mf->height = match->height; + + if (size) + *size = match; +} + +static int ov2659_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + unsigned int index = ARRAY_SIZE(ov2659_formats); + struct v4l2_mbus_framefmt *mf = &fmt->format; + const struct ov2659_framesize *size = NULL; + struct ov2659 *ov2659 = to_ov2659(sd); + int ret = 0; + + dev_dbg(&client->dev, "ov2659_set_fmt\n"); + + __ov2659_try_frame_size(mf, &size); + + while (--index >= 0) + if (ov2659_formats[index].code == mf->code) + break; + + if (index < 0) + return -EINVAL; + + mf->colorspace = V4L2_COLORSPACE_SRGB; + mf->code = ov2659_formats[index].code; + mf->field = V4L2_FIELD_NONE; + + mutex_lock(&ov2659->lock); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); + *mf = fmt->format; + } else { + s64 val; + + if (ov2659->streaming) { + mutex_unlock(&ov2659->lock); + return -EBUSY; + } + + ov2659->frame_size = size; + ov2659->format = fmt->format; + ov2659->format_ctrl_regs = + ov2659_formats[index].format_ctrl_regs; + + if (ov2659->format.code != MEDIA_BUS_FMT_SBGGR8_1X8) + val = ov2659->pdata->link_frequency / 2; + else + val = ov2659->pdata->link_frequency; + + ret = v4l2_ctrl_s_ctrl_int64(ov2659->link_frequency, val); + if (ret < 0) + dev_warn(&client->dev, + "failed to set link_frequency rate (%d)\n", + ret); + } + + mutex_unlock(&ov2659->lock); + return ret; +} + +static int ov2659_set_frame_size(struct ov2659 *ov2659) +{ + struct i2c_client *client = ov2659->client; + + dev_dbg(&client->dev, "%s\n", __func__); + + return ov2659_write_array(ov2659->client, ov2659->frame_size->regs); +} + +static int ov2659_set_format(struct ov2659 *ov2659) +{ + struct i2c_client *client = ov2659->client; + + dev_dbg(&client->dev, "%s\n", __func__); + + return ov2659_write_array(ov2659->client, ov2659->format_ctrl_regs); +} + +static int ov2659_s_stream(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov2659 *ov2659 = to_ov2659(sd); + int ret = 0; + + dev_dbg(&client->dev, "%s: on: %d\n", __func__, on); + + mutex_lock(&ov2659->lock); + + on = !!on; + + if (ov2659->streaming == on) + goto unlock; + + if (!on) { + /* Stop Streaming Sequence */ + ov2659_set_streaming(ov2659, 0); + ov2659->streaming = on; + goto unlock; + } + + ov2659_set_pixel_clock(ov2659); + ov2659_set_frame_size(ov2659); + ov2659_set_format(ov2659); + ov2659_set_streaming(ov2659, 1); + ov2659->streaming = on; + +unlock: + mutex_unlock(&ov2659->lock); + return ret; +} + +static int ov2659_set_test_pattern(struct ov2659 *ov2659, int value) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov2659->sd); + int ret; + u8 val; + + ret = ov2659_read(client, REG_PRE_ISP_CTRL00, &val); + if (ret < 0) + return ret; + + switch (value) { + case 0: + val &= ~TEST_PATTERN_ENABLE; + break; + case 1: + val &= VERTICAL_COLOR_BAR_MASK; + val |= TEST_PATTERN_ENABLE; + break; + } + + return ov2659_write(client, REG_PRE_ISP_CTRL00, val); +} + +static int ov2659_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2659 *ov2659 = + container_of(ctrl->handler, struct ov2659, ctrls); + + switch (ctrl->id) { + case V4L2_CID_TEST_PATTERN: + return ov2659_set_test_pattern(ov2659, ctrl->val); + } + + return 0; +} + +static struct v4l2_ctrl_ops ov2659_ctrl_ops = { + .s_ctrl = ov2659_s_ctrl, +}; + +static const char * const ov2659_test_pattern_menu[] = { + "Disabled", + "Vertical Color Bars", +}; + +/* ----------------------------------------------------------------------------- + * V4L2 subdev internal operations + */ + +static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format = + v4l2_subdev_get_try_format(sd, fh->pad, 0); + + dev_dbg(&client->dev, "%s:\n", __func__); + + ov2659_get_default_format(format); + + return 0; +} + +static const struct v4l2_subdev_core_ops ov2659_subdev_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_video_ops ov2659_subdev_video_ops = { + .s_stream = ov2659_s_stream, +}; + +static const struct v4l2_subdev_pad_ops ov2659_subdev_pad_ops = { + .enum_mbus_code = ov2659_enum_mbus_code, + .enum_frame_size = ov2659_enum_frame_sizes, + .get_fmt = ov2659_get_fmt, + .set_fmt = ov2659_set_fmt, +}; + +static const struct v4l2_subdev_ops ov2659_subdev_ops = { + .core = &ov2659_subdev_core_ops, + .video = &ov2659_subdev_video_ops, + .pad = &ov2659_subdev_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops ov2659_subdev_internal_ops = { + .open = ov2659_open, +}; + +static int ov2659_detect(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 pid, ver; + int ret; + + dev_dbg(&client->dev, "%s:\n", __func__); + + ret = ov2659_write(client, REG_SOFTWARE_RESET, 0x01); + if (ret != 0) { + dev_err(&client->dev, "Sensor soft reset failed\n"); + return -ENODEV; + } + usleep_range(1000, 2000); + + ret = ov2659_init(sd, 0); + if (ret < 0) + return ret; + + /* Check sensor revision */ + ret = ov2659_read(client, REG_SC_CHIP_ID_H, &pid); + if (!ret) + ret = ov2659_read(client, REG_SC_CHIP_ID_L, &ver); + + if (!ret) { + unsigned short id; + + id = OV265X_ID(pid, ver); + if (id != OV2659_ID) + dev_err(&client->dev, + "Sensor detection failed (%04X, %d)\n", + id, ret); + else + dev_info(&client->dev, "Found OV%04X sensor\n", id); + } + + return ret; +} + +static struct ov2659_platform_data * +ov2659_get_pdata(struct i2c_client *client) +{ + struct ov2659_platform_data *pdata; + struct device_node *endpoint; + int ret; + + if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) + return client->dev.platform_data; + + endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL); + if (!endpoint) + return NULL; + + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + goto done; + + ret = of_property_read_u64(endpoint, "link-frequencies", + &pdata->link_frequency); + if (ret) { + dev_err(&client->dev, "link-frequencies property not found\n"); + pdata = NULL; + } + +done: + of_node_put(endpoint); + return pdata; +} + +static int ov2659_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct ov2659_platform_data *pdata = ov2659_get_pdata(client); + struct v4l2_subdev *sd; + struct ov2659 *ov2659; + struct clk *clk; + int ret; + + if (!pdata) { + dev_err(&client->dev, "platform data not specified\n"); + return -EINVAL; + } + + ov2659 = devm_kzalloc(&client->dev, sizeof(*ov2659), GFP_KERNEL); + if (!ov2659) + return -ENOMEM; + + ov2659->pdata = pdata; + ov2659->client = client; + + clk = devm_clk_get(&client->dev, "xvclk"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ov2659->xvclk_frequency = clk_get_rate(clk); + if (ov2659->xvclk_frequency < 6000000 || + ov2659->xvclk_frequency > 27000000) + return -EINVAL; + + v4l2_ctrl_handler_init(&ov2659->ctrls, 2); + ov2659->link_frequency = + v4l2_ctrl_new_std(&ov2659->ctrls, &ov2659_ctrl_ops, + V4L2_CID_PIXEL_RATE, + pdata->link_frequency / 2, + pdata->link_frequency, 1, + pdata->link_frequency); + v4l2_ctrl_new_std_menu_items(&ov2659->ctrls, &ov2659_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov2659_test_pattern_menu) - 1, + 0, 0, ov2659_test_pattern_menu); + ov2659->sd.ctrl_handler = &ov2659->ctrls; + + if (ov2659->ctrls.error) { + dev_err(&client->dev, "%s: control initialization error %d\n", + __func__, ov2659->ctrls.error); + return ov2659->ctrls.error; + } + + sd = &ov2659->sd; + client->flags |= I2C_CLIENT_SCCB; + v4l2_i2c_subdev_init(sd, client, &ov2659_subdev_ops); + + sd->internal_ops = &ov2659_subdev_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; + +#if defined(CONFIG_MEDIA_CONTROLLER) + ov2659->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; + ret = media_entity_init(&sd->entity, 1, &ov2659->pad, 0); + if (ret < 0) { + v4l2_ctrl_handler_free(&ov2659->ctrls); + return ret; + } +#endif + + mutex_init(&ov2659->lock); + + ov2659_get_default_format(&ov2659->format); + ov2659->frame_size = &ov2659_framesizes[2]; + ov2659->format_ctrl_regs = ov2659_formats[0].format_ctrl_regs; + + ret = ov2659_detect(sd); + if (ret < 0) + goto error; + + /* Calculate the PLL register value needed */ + ov2659_pll_calc_params(ov2659); + + ret = v4l2_async_register_subdev(&ov2659->sd); + if (ret) + goto error; + + dev_info(&client->dev, "%s sensor driver registered !!\n", sd->name); + + return 0; + +error: + v4l2_ctrl_handler_free(&ov2659->ctrls); +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&sd->entity); +#endif + mutex_destroy(&ov2659->lock); + return ret; +} + +static int ov2659_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2659 *ov2659 = to_ov2659(sd); + + v4l2_ctrl_handler_free(&ov2659->ctrls); + v4l2_async_unregister_subdev(sd); +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&sd->entity); +#endif + mutex_destroy(&ov2659->lock); + + return 0; +} + +static const struct i2c_device_id ov2659_id[] = { + { "ov2659", 0 }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i2c, ov2659_id); + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id ov2659_of_match[] = { + { .compatible = "ovti,ov2659", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ov2659_of_match); +#endif + +static struct i2c_driver ov2659_i2c_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(ov2659_of_match), + }, + .probe = ov2659_probe, + .remove = ov2659_remove, + .id_table = ov2659_id, +}; + +module_i2c_driver(ov2659_i2c_driver); + +MODULE_AUTHOR("Benoit Parrot "); +MODULE_DESCRIPTION("OV2659 CMOS Image Sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/media/ov2659.h b/include/media/ov2659.h new file mode 100644 index 000000000000..4216adc1ede2 --- /dev/null +++ b/include/media/ov2659.h @@ -0,0 +1,34 @@ +/* + * Omnivision OV2659 CMOS Image Sensor driver + * + * Copyright (C) 2015 Texas Instruments, Inc. + * + * Benoit Parrot + * Lad, Prabhakar + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef OV2659_H +#define OV2659_H + +/** + * struct ov2659_platform_data - ov2659 driver platform data + * @link_frequency: target pixel clock frequency + */ +struct ov2659_platform_data { + s64 link_frequency; +}; + +#endif /* OV2659_H */ -- cgit v1.2.3 From 590ce4bcbfb4e0462a720a4ad901e84416080bba Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 22 Dec 2014 18:30:08 -0600 Subject: mnt: Add MNT_UMOUNT flag In some instances it is necessary to know if the the unmounting process has begun on a mount. Add MNT_UMOUNT to make that reliably testable. This fix gets used in fixing locked mounts in MNT_DETACH Cc: stable@vger.kernel.org Signed-off-by: "Eric W. Biederman" --- fs/namespace.c | 4 +++- fs/pnode.c | 1 + include/linux/mount.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/fs/namespace.c b/fs/namespace.c index 54cbef129f4a..d1708147eb45 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1331,8 +1331,10 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how) struct mount *p; /* Gather the mounts to umount */ - for (p = mnt; p; p = next_mnt(p, mnt)) + for (p = mnt; p; p = next_mnt(p, mnt)) { + p->mnt.mnt_flags |= MNT_UMOUNT; list_move(&p->mnt_list, &tmp_list); + } /* Hide the mounts from lookup_mnt and mnt_mounts */ list_for_each_entry(p, &tmp_list, mnt_list) { diff --git a/fs/pnode.c b/fs/pnode.c index bf012af709dd..ac3aa0d43b90 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -384,6 +384,7 @@ static void __propagate_umount(struct mount *mnt) if (child && list_empty(&child->mnt_mounts)) { list_del_init(&child->mnt_child); hlist_del_init_rcu(&child->mnt_hash); + child->mnt.mnt_flags |= MNT_UMOUNT; list_move_tail(&child->mnt_list, &mnt->mnt_list); } } diff --git a/include/linux/mount.h b/include/linux/mount.h index c2c561dc0114..564beeec5d83 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -61,6 +61,7 @@ struct mnt_namespace; #define MNT_DOOMED 0x1000000 #define MNT_SYNC_UMOUNT 0x2000000 #define MNT_MARKED 0x4000000 +#define MNT_UMOUNT 0x8000000 struct vfsmount { struct dentry *mnt_root; /* root of the mounted tree */ -- cgit v1.2.3 From 3ae863e0db47ae7815f9e52975e1fddfca59520a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Mar 2015 13:33:57 -0300 Subject: [media] saa7146: embed video_device Embed the video_device struct to simplify the error handling and in order to (eventually) get rid of video_device_alloc/release. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_fops.c | 19 ++++--------------- drivers/media/pci/saa7146/hexium_gemini.c | 2 +- drivers/media/pci/saa7146/hexium_orion.c | 2 +- drivers/media/pci/saa7146/mxb.c | 4 ++-- drivers/media/pci/ttpci/av7110.h | 4 ++-- drivers/media/pci/ttpci/budget-av.c | 2 +- include/media/saa7146_vv.h | 4 ++-- 7 files changed, 13 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index b7d63933dae6..df1e8c975cd8 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -587,26 +587,20 @@ int saa7146_vv_release(struct saa7146_dev* dev) } EXPORT_SYMBOL_GPL(saa7146_vv_release); -int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, +int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev, char *name, int type) { - struct video_device *vfd; int err; int i; DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type); - // released by vfd->release - vfd = video_device_alloc(); - if (vfd == NULL) - return -ENOMEM; - vfd->fops = &video_fops; if (type == VFL_TYPE_GRABBER) vfd->ioctl_ops = &dev->ext_vv_data->vid_ops; else vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops; - vfd->release = video_device_release; + vfd->release = video_device_release_empty; vfd->lock = &dev->v4l2_lock; vfd->v4l2_dev = &dev->v4l2_dev; vfd->tvnorms = 0; @@ -618,25 +612,20 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, err = video_register_device(vfd, type, -1); if (err < 0) { ERR("cannot register v4l2 device. skipping.\n"); - video_device_release(vfd); return err; } pr_info("%s: registered device %s [v4l2]\n", dev->name, video_device_node_name(vfd)); - - *vid = vfd; return 0; } EXPORT_SYMBOL_GPL(saa7146_register_device); -int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev) +int saa7146_unregister_device(struct video_device *vfd, struct saa7146_dev *dev) { DEB_EE("dev:%p\n", dev); - video_unregister_device(*vid); - *vid = NULL; - + video_unregister_device(vfd); return 0; } EXPORT_SYMBOL_GPL(saa7146_unregister_device); diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index 366434f5647e..03cbcd2095c6 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -66,7 +66,7 @@ struct hexium { int type; - struct video_device *video_dev; + struct video_device video_dev; struct i2c_adapter i2c_adapter; int cur_input; /* current input */ diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index a1eb26d11070..15f0d66ff78a 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -63,7 +63,7 @@ struct hexium_data struct hexium { int type; - struct video_device *video_dev; + struct video_device video_dev; struct i2c_adapter i2c_adapter; int cur_input; /* current input */ diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index c4c8fce8f2b4..0ca1e07ae783 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -151,8 +151,8 @@ static struct mxb_routing TEA6420_line[MXB_AUDIOS + 1][2] = { struct mxb { - struct video_device *video_dev; - struct video_device *vbi_dev; + struct video_device video_dev; + struct video_device vbi_dev; struct i2c_adapter i2c_adapter; diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h index ef3d9606b269..835635b0c712 100644 --- a/drivers/media/pci/ttpci/av7110.h +++ b/drivers/media/pci/ttpci/av7110.h @@ -102,8 +102,8 @@ struct av7110 { struct dvb_device dvb_dev; struct dvb_net dvb_net; - struct video_device *v4l_dev; - struct video_device *vbi_dev; + struct video_device v4l_dev; + struct video_device vbi_dev; struct saa7146_dev *dev; diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c index 0ba3875af22e..54c9910256f8 100644 --- a/drivers/media/pci/ttpci/budget-av.c +++ b/drivers/media/pci/ttpci/budget-av.c @@ -68,7 +68,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); struct budget_av { struct budget budget; - struct video_device *vd; + struct video_device vd; int cur_input; int has_saa7113; struct tasklet_struct ciintf_irq_tasklet; diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h index 944ecdf3530f..92766f77a5de 100644 --- a/include/media/saa7146_vv.h +++ b/include/media/saa7146_vv.h @@ -178,8 +178,8 @@ struct saa7146_use_ops { }; /* from saa7146_fops.c */ -int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, char *name, int type); -int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev); +int saa7146_register_device(struct video_device *vid, struct saa7146_dev *dev, char *name, int type); +int saa7146_unregister_device(struct video_device *vid, struct saa7146_dev *dev); void saa7146_buffer_finish(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, int state); void saa7146_buffer_next(struct saa7146_dev *dev, struct saa7146_dmaqueue *q,int vbi); int saa7146_buffer_queue(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, struct saa7146_buf *buf); -- cgit v1.2.3 From 03c278f01d70ce168a24f85a08e11636df30f580 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Tue, 10 Mar 2015 14:53:05 -0300 Subject: [media] media: davinci: vpfe_capture: embed video_device Embed the video_device struct to simplify the error handling and in order to (eventually) get rid of video_device_alloc/release. Signed-off-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 26 +++++++------------------- include/media/davinci/vpfe_capture.h | 2 +- 2 files changed, 8 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index b41bf7e822c8..ccfcf3f528d3 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1871,16 +1871,9 @@ static int vpfe_probe(struct platform_device *pdev) goto probe_free_ccdc_cfg_mem; } - /* Allocate memory for video device */ - vfd = video_device_alloc(); - if (NULL == vfd) { - ret = -ENOMEM; - v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); - goto probe_out_release_irq; - } - + vfd = &vpfe_dev->video_dev; /* Initialize field of video device */ - vfd->release = video_device_release; + vfd->release = video_device_release_empty; vfd->fops = &vpfe_fops; vfd->ioctl_ops = &vpfe_ioctl_ops; vfd->tvnorms = 0; @@ -1891,14 +1884,12 @@ static int vpfe_probe(struct platform_device *pdev) (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff, (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff, (VPFE_CAPTURE_VERSION_CODE) & 0xff); - /* Set video_dev to the video device */ - vpfe_dev->video_dev = vfd; ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); if (ret) { v4l2_err(pdev->dev.driver, "Unable to register v4l2 device.\n"); - goto probe_out_video_release; + goto probe_out_release_irq; } v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); spin_lock_init(&vpfe_dev->irqlock); @@ -1914,7 +1905,7 @@ static int vpfe_probe(struct platform_device *pdev) v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "video_dev=%p\n", &vpfe_dev->video_dev); vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = video_register_device(vpfe_dev->video_dev, + ret = video_register_device(&vpfe_dev->video_dev, VFL_TYPE_GRABBER, -1); if (ret) { @@ -1927,7 +1918,7 @@ static int vpfe_probe(struct platform_device *pdev) /* set the driver data in platform device */ platform_set_drvdata(pdev, vpfe_dev); /* set driver private data */ - video_set_drvdata(vpfe_dev->video_dev, vpfe_dev); + video_set_drvdata(&vpfe_dev->video_dev, vpfe_dev); i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id); num_subdevs = vpfe_cfg->num_subdevs; vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs, @@ -1979,12 +1970,9 @@ static int vpfe_probe(struct platform_device *pdev) probe_sd_out: kfree(vpfe_dev->sd); probe_out_video_unregister: - video_unregister_device(vpfe_dev->video_dev); + video_unregister_device(&vpfe_dev->video_dev); probe_out_v4l2_unregister: v4l2_device_unregister(&vpfe_dev->v4l2_dev); -probe_out_video_release: - if (!video_is_registered(vpfe_dev->video_dev)) - video_device_release(vpfe_dev->video_dev); probe_out_release_irq: free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); probe_free_ccdc_cfg_mem: @@ -2007,7 +1995,7 @@ static int vpfe_remove(struct platform_device *pdev) free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); kfree(vpfe_dev->sd); v4l2_device_unregister(&vpfe_dev->v4l2_dev); - video_unregister_device(vpfe_dev->video_dev); + video_unregister_device(&vpfe_dev->video_dev); kfree(vpfe_dev); kfree(ccdc_cfg); return 0; diff --git a/include/media/davinci/vpfe_capture.h b/include/media/davinci/vpfe_capture.h index 288772e6900a..28bcd71cdd26 100644 --- a/include/media/davinci/vpfe_capture.h +++ b/include/media/davinci/vpfe_capture.h @@ -102,7 +102,7 @@ struct vpfe_config { struct vpfe_device { /* V4l2 specific parameters */ /* Identifies video device for this channel */ - struct video_device *video_dev; + struct video_device video_dev; /* sub devices */ struct v4l2_subdev **sd; /* vpfe cfg */ -- cgit v1.2.3 From cc7d2dfb75b3ac0f248801ceed65f69465eb0389 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 15 Mar 2015 14:30:25 -0300 Subject: [media] v4l2_plane_pix_format: use __u32 bytesperline instead of __u16 While running v4l2-compliance tests on vivid I suddenly got errors due to a call to vmalloc_user with size 0 from vb2. Digging deeper into the cause I discovered that this was due to the fact that struct v4l2_plane_pix_format defines bytesperline as a __u16 instead of a __u32. The test I was running selected a format of 4 * 4096 by 4 * 2048 with a 32 bit pixelformat. So bytesperline was 4 * 4 * 4096 = 65536, which becomes 0 in a __u16. And bytesperline * height is suddenly 0 as well. While the vivid driver may be a virtual driver, it is to be expected that this limit will be hit for real hardware as well in the near future: 8k deep-color video will already reach it. The solution is to change the type to __u32. The only drivers besides vivid that use the multiplanar API are little-endian ARM and SH platforms (exynos, ti-vpe, vsp1), so this is safe. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/pixfmt.xml | 4 ++-- drivers/media/platform/s5p-tv/mixer_video.c | 2 +- include/uapi/linux/videodev2.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index 0a1528f3e891..fcde4e20205e 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -182,14 +182,14 @@ see . - __u16 + __u32 bytesperline Distance in bytes between the leftmost pixels in two adjacent lines. See &v4l2-pix-format;. __u16 - reserved[7] + reserved[6] Reserved for future extensions. Should be zeroed by the application. diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 72d4f2e1efc0..751f3b618337 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -287,7 +287,7 @@ static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes, u32 bl_width = divup(width, blk->width); u32 bl_height = divup(height, blk->height); u32 sizeimage = bl_width * bl_height * blk->size; - u16 bytesperline = bl_width * blk->size / blk->height; + u32 bytesperline = bl_width * blk->size / blk->height; plane->sizeimage += sizeimage; plane->bytesperline = max(plane->bytesperline, bytesperline); diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 15b21e481246..47df18f36c4b 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1842,8 +1842,8 @@ struct v4l2_mpeg_vbi_fmt_ivtv { */ struct v4l2_plane_pix_format { __u32 sizeimage; - __u16 bytesperline; - __u16 reserved[7]; + __u32 bytesperline; + __u16 reserved[6]; } __attribute__ ((packed)); /** -- cgit v1.2.3 From 5a5394be30dd9725351cdd0f923c1e374dc140cc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 26 Mar 2014 00:01:44 -0300 Subject: [media] media: entity: Document the media_entity_ops structure Currently, there's no documentation for the structure. Add a kernel-doc nano documentation to it. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/media-entity.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'include') diff --git a/include/media/media-entity.h b/include/media/media-entity.h index d6d74bcfe183..0c003d817493 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -44,6 +44,15 @@ struct media_pad { unsigned long flags; /* Pad flags (MEDIA_PAD_FL_*) */ }; +/** + * struct media_entity_operations - Media entity operations + * @link_setup: Notify the entity of link changes. The operation can + * return an error, in which case link setup will be + * cancelled. Optional. + * @link_validate: Return whether a link is valid from the entity point of + * view. The media_entity_pipeline_start() function + * validates all links by calling this operation. Optional. + */ struct media_entity_operations { int (*link_setup)(struct media_entity *entity, const struct media_pad *local, -- cgit v1.2.3 From 7b0fd4568bee379474eb0d989ef1125064f19fa7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 15 May 2013 11:34:26 -0300 Subject: [media] v4l: Add RBG and RGB 8:8:8 media bus formats on 24 and 32 bit busses Add support and documentation for two media bus formats: MEDIA_BUS_FMT_RBG888_1X24 and MEDIA_BUS_FMT_RGB888_1X32_PADHI Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/subdev-formats.xml | 67 ++++++++++++++++++++++ include/uapi/linux/media-bus-format.h | 4 +- 2 files changed, 70 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index c5ea868e3909..d253e8f85f4d 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -440,6 +440,36 @@ see . b1 b0 + + MEDIA_BUS_FMT_RBG888_1X24 + 0x100e + + &dash-ent-8; + r7 + r6 + r5 + r4 + r3 + r2 + r1 + r0 + b7 + b6 + b5 + b4 + b3 + b2 + b1 + b0 + g7 + g6 + g5 + g4 + g3 + g2 + g1 + g0 + MEDIA_BUS_FMT_RGB888_1X24 0x100a @@ -579,6 +609,43 @@ see . b1 b0 + + MEDIA_BUS_FMT_RGB888_1X32_PADHI + 0x100f + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + r7 + r6 + r5 + r4 + r3 + r2 + r1 + r0 + g7 + g6 + g5 + g4 + g3 + g2 + g1 + g0 + b7 + b6 + b5 + b4 + b3 + b2 + b1 + b0 + diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index 23b40908be30..b585bb32d25e 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -33,7 +33,7 @@ #define MEDIA_BUS_FMT_FIXED 0x0001 -/* RGB - next is 0x100e */ +/* RGB - next is 0x1010 */ #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 #define MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE 0x1003 @@ -43,10 +43,12 @@ #define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007 #define MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008 #define MEDIA_BUS_FMT_RGB666_1X18 0x1009 +#define MEDIA_BUS_FMT_RBG888_1X24 0x100e #define MEDIA_BUS_FMT_RGB888_1X24 0x100a #define MEDIA_BUS_FMT_RGB888_2X12_BE 0x100b #define MEDIA_BUS_FMT_RGB888_2X12_LE 0x100c #define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d +#define MEDIA_BUS_FMT_RGB888_1X32_PADHI 0x100f /* YUV (including grey) - next is 0x2024 */ #define MEDIA_BUS_FMT_Y8_1X8 0x2001 -- cgit v1.2.3 From e8b2d7a565ae4fc8627ffe35b953062ff6119533 Mon Sep 17 00:00:00 2001 From: Hyun Kwon Date: Tue, 18 Mar 2014 13:18:14 -0300 Subject: [media] v4l: Sort YUV formats of v4l2_mbus_pixelcode Keep the formats sorted by type, bus_width, bits per component, samples per pixel and order of subsamples, in that order. Signed-off-by: Hyun Kwon Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/subdev-formats.xml | 600 ++++++++++----------- include/uapi/linux/media-bus-format.h | 12 +- 2 files changed, 306 insertions(+), 306 deletions(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index d253e8f85f4d..9bfd468cd524 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -2255,11 +2255,15 @@ see . y1 y0 - - MEDIA_BUS_FMT_UYVY8_1X16 - 0x200f + + MEDIA_BUS_FMT_UYVY12_2X12 + 0x201c - &dash-ent-16; + &dash-ent-20; + u11 + u10 + u9 + u8 u7 u6 u5 @@ -2268,6 +2272,16 @@ see . u2 u1 u0 + + + + + + &dash-ent-20; + y11 + y10 + y9 + y8 y7 y6 y5 @@ -2281,7 +2295,11 @@ see . - &dash-ent-16; + &dash-ent-20; + v11 + v10 + v9 + v8 v7 v6 v5 @@ -2290,6 +2308,16 @@ see . v2 v1 v0 + + + + + + &dash-ent-20; + y11 + y10 + y9 + y8 y7 y6 y5 @@ -2299,11 +2327,15 @@ see . y1 y0 - - MEDIA_BUS_FMT_VYUY8_1X16 - 0x2010 + + MEDIA_BUS_FMT_VYUY12_2X12 + 0x201d - &dash-ent-16; + &dash-ent-20; + v11 + v10 + v9 + v8 v7 v6 v5 @@ -2312,6 +2344,16 @@ see . v2 v1 v0 + + + + + + &dash-ent-20; + y11 + y10 + y9 + y8 y7 y6 y5 @@ -2325,7 +2367,11 @@ see . - &dash-ent-16; + &dash-ent-20; + u11 + u10 + u9 + u8 u7 u6 u5 @@ -2334,6 +2380,16 @@ see . u2 u1 u0 + + + + + + &dash-ent-20; + y11 + y10 + y9 + y8 y7 y6 y5 @@ -2343,11 +2399,15 @@ see . y1 y0 - - MEDIA_BUS_FMT_YUYV8_1X16 - 0x2011 + + MEDIA_BUS_FMT_YUYV12_2X12 + 0x201e - &dash-ent-16; + &dash-ent-20; + y11 + y10 + y9 + y8 y7 y6 y5 @@ -2356,6 +2416,16 @@ see . y2 y1 y0 + + + + + + &dash-ent-20; + u11 + u10 + u9 + u8 u7 u6 u5 @@ -2369,7 +2439,11 @@ see . - &dash-ent-16; + &dash-ent-20; + y11 + y10 + y9 + y8 y7 y6 y5 @@ -2378,6 +2452,16 @@ see . y2 y1 y0 + + + + + + &dash-ent-20; + v11 + v10 + v9 + v8 v7 v6 v5 @@ -2387,11 +2471,15 @@ see . v1 v0 - - MEDIA_BUS_FMT_YVYU8_1X16 - 0x2012 + + MEDIA_BUS_FMT_YVYU12_2X12 + 0x201f - &dash-ent-16; + &dash-ent-20; + y11 + y10 + y9 + y8 y7 y6 y5 @@ -2400,6 +2488,16 @@ see . y2 y1 y0 + + + + + + &dash-ent-20; + v11 + v10 + v9 + v8 v7 v6 v5 @@ -2413,29 +2511,11 @@ see . - &dash-ent-16; - y7 - y6 - y5 - y4 - y3 - y2 - y1 - y0 - u7 - u6 - u5 - u4 - u3 - u2 - u1 - u0 - - - MEDIA_BUS_FMT_YDYUYDYV8_1X16 - 0x2014 - - &dash-ent-16; + &dash-ent-20; + y11 + y10 + y9 + y8 y7 y6 y5 @@ -2444,28 +2524,16 @@ see . y2 y1 y0 - d - d - d - d - d - d - d - d - &dash-ent-16; - y7 - y6 - y5 - y4 - y3 - y2 - y1 - y0 + &dash-ent-20; + u11 + u10 + u9 + u8 u7 u6 u5 @@ -2475,57 +2543,11 @@ see . u1 u0 - - - - - &dash-ent-16; - y7 - y6 - y5 - y4 - y3 - y2 - y1 - y0 - d - d - d - d - d - d - d - d - - - - + + MEDIA_BUS_FMT_UYVY8_1X16 + 0x200f &dash-ent-16; - y7 - y6 - y5 - y4 - y3 - y2 - y1 - y0 - v7 - v6 - v5 - v4 - v3 - v2 - v1 - v0 - - - MEDIA_BUS_FMT_UYVY10_1X20 - 0x201a - - &dash-ent-12; - u9 - u8 u7 u6 u5 @@ -2534,8 +2556,6 @@ see . u2 u1 u0 - y9 - y8 y7 y6 y5 @@ -2549,9 +2569,7 @@ see . - &dash-ent-12; - v9 - v8 + &dash-ent-16; v7 v6 v5 @@ -2560,8 +2578,6 @@ see . v2 v1 v0 - y9 - y8 y7 y6 y5 @@ -2571,13 +2587,11 @@ see . y1 y0 - - MEDIA_BUS_FMT_VYUY10_1X20 - 0x201b + + MEDIA_BUS_FMT_VYUY8_1X16 + 0x2010 - &dash-ent-12; - v9 - v8 + &dash-ent-16; v7 v6 v5 @@ -2586,8 +2600,6 @@ see . v2 v1 v0 - y9 - y8 y7 y6 y5 @@ -2601,9 +2613,7 @@ see . - &dash-ent-12; - u9 - u8 + &dash-ent-16; u7 u6 u5 @@ -2612,8 +2622,6 @@ see . u2 u1 u0 - y9 - y8 y7 y6 y5 @@ -2623,13 +2631,11 @@ see . y1 y0 - - MEDIA_BUS_FMT_YUYV10_1X20 - 0x200d + + MEDIA_BUS_FMT_YUYV8_1X16 + 0x2011 - &dash-ent-12; - y9 - y8 + &dash-ent-16; y7 y6 y5 @@ -2638,8 +2644,6 @@ see . y2 y1 y0 - u9 - u8 u7 u6 u5 @@ -2653,9 +2657,7 @@ see . - &dash-ent-12; - y9 - y8 + &dash-ent-16; y7 y6 y5 @@ -2664,8 +2666,6 @@ see . y2 y1 y0 - v9 - v8 v7 v6 v5 @@ -2675,13 +2675,11 @@ see . v1 v0 - - MEDIA_BUS_FMT_YVYU10_1X20 - 0x200e + + MEDIA_BUS_FMT_YVYU8_1X16 + 0x2012 - &dash-ent-12; - y9 - y8 + &dash-ent-16; y7 y6 y5 @@ -2690,8 +2688,6 @@ see . y2 y1 y0 - v9 - v8 v7 v6 v5 @@ -2705,9 +2701,51 @@ see . - &dash-ent-12; - y9 - y8 + &dash-ent-16; + y7 + y6 + y5 + y4 + y3 + y2 + y1 + y0 + u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + + + MEDIA_BUS_FMT_YDYUYDYV8_1X16 + 0x2014 + + &dash-ent-16; + y7 + y6 + y5 + y4 + y3 + y2 + y1 + y0 + d + d + d + d + d + d + d + d + + + + + + &dash-ent-16; y7 y6 y5 @@ -2716,8 +2754,6 @@ see . y2 y1 y0 - u9 - u8 u7 u6 u5 @@ -2727,14 +2763,11 @@ see . u1 u0 - - MEDIA_BUS_FMT_YUV10_1X30 - 0x2016 + - - - - - y9 - y8 + + + &dash-ent-16; y7 y6 y5 @@ -2743,39 +2776,20 @@ see . y2 y1 y0 - u9 - u8 - u7 - u6 - u5 - u4 - u3 - u2 - u1 - u0 - v9 - v8 - v7 - v6 - v5 - v4 - v3 - v2 - v1 - v0 + d + d + d + d + d + d + d + d - - MEDIA_BUS_FMT_AYUV8_1X32 - 0x2017 + - a7 - a6 - a5 - a4 - a3 - a2 - a1 - a0 + + + &dash-ent-16; y7 y6 y5 @@ -2784,14 +2798,6 @@ see . y2 y1 y0 - u7 - u6 - u5 - u4 - u3 - u2 - u1 - u0 v7 v6 v5 @@ -2801,13 +2807,11 @@ see . v1 v0 - - MEDIA_BUS_FMT_UYVY12_2X12 - 0x201c + + MEDIA_BUS_FMT_UYVY10_1X20 + 0x201a - &dash-ent-20; - u11 - u10 + &dash-ent-12; u9 u8 u7 @@ -2818,14 +2822,6 @@ see . u2 u1 u0 - - - - - - &dash-ent-20; - y11 - y10 y9 y8 y7 @@ -2841,9 +2837,7 @@ see . - &dash-ent-20; - v11 - v10 + &dash-ent-12; v9 v8 v7 @@ -2854,14 +2848,6 @@ see . v2 v1 v0 - - - - - - &dash-ent-20; - y11 - y10 y9 y8 y7 @@ -2873,13 +2859,11 @@ see . y1 y0 - - MEDIA_BUS_FMT_VYUY12_2X12 - 0x201d + + MEDIA_BUS_FMT_VYUY10_1X20 + 0x201b - &dash-ent-20; - v11 - v10 + &dash-ent-12; v9 v8 v7 @@ -2890,14 +2874,6 @@ see . v2 v1 v0 - - - - - - &dash-ent-20; - y11 - y10 y9 y8 y7 @@ -2913,9 +2889,7 @@ see . - &dash-ent-20; - u11 - u10 + &dash-ent-12; u9 u8 u7 @@ -2926,14 +2900,6 @@ see . u2 u1 u0 - - - - - - &dash-ent-20; - y11 - y10 y9 y8 y7 @@ -2945,13 +2911,11 @@ see . y1 y0 - - MEDIA_BUS_FMT_YUYV12_2X12 - 0x201e + + MEDIA_BUS_FMT_YUYV10_1X20 + 0x200d - &dash-ent-20; - y11 - y10 + &dash-ent-12; y9 y8 y7 @@ -2962,14 +2926,6 @@ see . y2 y1 y0 - - - - - - &dash-ent-20; - u11 - u10 u9 u8 u7 @@ -2985,9 +2941,7 @@ see . - &dash-ent-20; - y11 - y10 + &dash-ent-12; y9 y8 y7 @@ -2998,14 +2952,6 @@ see . y2 y1 y0 - - - - - - &dash-ent-20; - v11 - v10 v9 v8 v7 @@ -3017,13 +2963,11 @@ see . v1 v0 - - MEDIA_BUS_FMT_YVYU12_2X12 - 0x201f + + MEDIA_BUS_FMT_YVYU10_1X20 + 0x200e - &dash-ent-20; - y11 - y10 + &dash-ent-12; y9 y8 y7 @@ -3034,14 +2978,6 @@ see . y2 y1 y0 - - - - - - &dash-ent-20; - v11 - v10 v9 v8 v7 @@ -3057,9 +2993,7 @@ see . - &dash-ent-20; - y11 - y10 + &dash-ent-12; y9 y8 y7 @@ -3070,14 +3004,6 @@ see . y2 y1 y0 - - - - - - &dash-ent-20; - u11 - u10 u9 u8 u7 @@ -3329,6 +3255,80 @@ see . u1 u0 + + MEDIA_BUS_FMT_YUV10_1X30 + 0x2016 + + - + - + y9 + y8 + y7 + y6 + y5 + y4 + y3 + y2 + y1 + y0 + u9 + u8 + u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + v9 + v8 + v7 + v6 + v5 + v4 + v3 + v2 + v1 + v0 + + + MEDIA_BUS_FMT_AYUV8_1X32 + 0x2017 + + a7 + a6 + a5 + a4 + a3 + a2 + a1 + a0 + y7 + y6 + y5 + y4 + y3 + y2 + y1 + y0 + u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + v7 + v6 + v5 + v4 + v3 + v2 + v1 + v0 + diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index b585bb32d25e..363a30fd8a21 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -67,6 +67,10 @@ #define MEDIA_BUS_FMT_YUYV10_2X10 0x200b #define MEDIA_BUS_FMT_YVYU10_2X10 0x200c #define MEDIA_BUS_FMT_Y12_1X12 0x2013 +#define MEDIA_BUS_FMT_UYVY12_2X12 0x201c +#define MEDIA_BUS_FMT_VYUY12_2X12 0x201d +#define MEDIA_BUS_FMT_YUYV12_2X12 0x201e +#define MEDIA_BUS_FMT_YVYU12_2X12 0x201f #define MEDIA_BUS_FMT_UYVY8_1X16 0x200f #define MEDIA_BUS_FMT_VYUY8_1X16 0x2010 #define MEDIA_BUS_FMT_YUYV8_1X16 0x2011 @@ -76,16 +80,12 @@ #define MEDIA_BUS_FMT_VYUY10_1X20 0x201b #define MEDIA_BUS_FMT_YUYV10_1X20 0x200d #define MEDIA_BUS_FMT_YVYU10_1X20 0x200e -#define MEDIA_BUS_FMT_YUV10_1X30 0x2016 -#define MEDIA_BUS_FMT_AYUV8_1X32 0x2017 -#define MEDIA_BUS_FMT_UYVY12_2X12 0x201c -#define MEDIA_BUS_FMT_VYUY12_2X12 0x201d -#define MEDIA_BUS_FMT_YUYV12_2X12 0x201e -#define MEDIA_BUS_FMT_YVYU12_2X12 0x201f #define MEDIA_BUS_FMT_UYVY12_1X24 0x2020 #define MEDIA_BUS_FMT_VYUY12_1X24 0x2021 #define MEDIA_BUS_FMT_YUYV12_1X24 0x2022 #define MEDIA_BUS_FMT_YVYU12_1X24 0x2023 +#define MEDIA_BUS_FMT_YUV10_1X30 0x2016 +#define MEDIA_BUS_FMT_AYUV8_1X32 0x2017 /* Bayer - next is 0x3019 */ #define MEDIA_BUS_FMT_SBGGR8_1X8 0x3001 -- cgit v1.2.3 From 2dca0551e4e2f3fc2b9beee784c7071e1e79c14b Mon Sep 17 00:00:00 2001 From: Hyun Kwon Date: Tue, 18 Mar 2014 13:18:15 -0300 Subject: [media] v4l: Add VUY8 24 bits bus format Add VUY8 24 bits bus format, V4L2_MBUS_FMT_VUY8_1X24. Signed-off-by: Hyun Kwon Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/subdev-formats.xml | 30 ++++++++++++++++++++++ include/uapi/linux/media-bus-format.h | 3 ++- 2 files changed, 32 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index 9bfd468cd524..bc8d3fb9e4a9 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -3015,6 +3015,36 @@ see . u1 u0 + + MEDIA_BUS_FMT_VUY8_1X24 + 0x201a + + &dash-ent-8; + v7 + v6 + v5 + v4 + v3 + v2 + v1 + v0 + u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + y7 + y6 + y5 + y4 + y3 + y2 + y1 + y0 + MEDIA_BUS_FMT_UYVY12_1X24 0x2020 diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index 363a30fd8a21..d391893064a0 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -50,7 +50,7 @@ #define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d #define MEDIA_BUS_FMT_RGB888_1X32_PADHI 0x100f -/* YUV (including grey) - next is 0x2024 */ +/* YUV (including grey) - next is 0x2025 */ #define MEDIA_BUS_FMT_Y8_1X8 0x2001 #define MEDIA_BUS_FMT_UV8_1X8 0x2015 #define MEDIA_BUS_FMT_UYVY8_1_5X8 0x2002 @@ -80,6 +80,7 @@ #define MEDIA_BUS_FMT_VYUY10_1X20 0x201b #define MEDIA_BUS_FMT_YUYV10_1X20 0x200d #define MEDIA_BUS_FMT_YVYU10_1X20 0x200e +#define MEDIA_BUS_FMT_VUY8_1X24 0x2024 #define MEDIA_BUS_FMT_UYVY12_1X24 0x2020 #define MEDIA_BUS_FMT_VYUY12_1X24 0x2021 #define MEDIA_BUS_FMT_YUYV12_1X24 0x2022 -- cgit v1.2.3 From c9bca8b33118573da9b7ac2ea21947a8e4d287dd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 17 May 2013 07:31:04 -0300 Subject: [media] v4l: of: Add v4l2_of_parse_link() function The function fills a link data structure with the device node and port number at both the local and remote ends of a link defined by one of its endpoint nodes. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Acked-by: Sakari Ailus Acked-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-of.c | 61 +++++++++++++++++++++++++++++++++++++++ include/media/v4l2-of.h | 27 +++++++++++++++++ 2 files changed, 88 insertions(+) (limited to 'include') diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c index 58e401f4893a..83143d39dea7 100644 --- a/drivers/media/v4l2-core/v4l2-of.c +++ b/drivers/media/v4l2-core/v4l2-of.c @@ -165,3 +165,64 @@ int v4l2_of_parse_endpoint(const struct device_node *node, return 0; } EXPORT_SYMBOL(v4l2_of_parse_endpoint); + +/** + * v4l2_of_parse_link() - parse a link between two endpoints + * @node: pointer to the endpoint at the local end of the link + * @link: pointer to the V4L2 OF link data structure + * + * Fill the link structure with the local and remote nodes and port numbers. + * The local_node and remote_node fields are set to point to the local and + * remote port's parent nodes respectively (the port parent node being the + * parent node of the port node if that node isn't a 'ports' node, or the + * grand-parent node of the port node otherwise). + * + * A reference is taken to both the local and remote nodes, the caller must use + * v4l2_of_put_link() to drop the references when done with the link. + * + * Return: 0 on success, or -ENOLINK if the remote endpoint can't be found. + */ +int v4l2_of_parse_link(const struct device_node *node, + struct v4l2_of_link *link) +{ + struct device_node *np; + + memset(link, 0, sizeof(*link)); + + np = of_get_parent(node); + of_property_read_u32(np, "reg", &link->local_port); + np = of_get_next_parent(np); + if (of_node_cmp(np->name, "ports") == 0) + np = of_get_next_parent(np); + link->local_node = np; + + np = of_parse_phandle(node, "remote-endpoint", 0); + if (!np) { + of_node_put(link->local_node); + return -ENOLINK; + } + + np = of_get_parent(np); + of_property_read_u32(np, "reg", &link->remote_port); + np = of_get_next_parent(np); + if (of_node_cmp(np->name, "ports") == 0) + np = of_get_next_parent(np); + link->remote_node = np; + + return 0; +} +EXPORT_SYMBOL(v4l2_of_parse_link); + +/** + * v4l2_of_put_link() - drop references to nodes in a link + * @link: pointer to the V4L2 OF link data structure + * + * Drop references to the local and remote nodes in the link. This function must + * be called on every link parsed with v4l2_of_parse_link(). + */ +void v4l2_of_put_link(struct v4l2_of_link *link) +{ + of_node_put(link->local_node); + of_node_put(link->remote_node); +} +EXPORT_SYMBOL(v4l2_of_put_link); diff --git a/include/media/v4l2-of.h b/include/media/v4l2-of.h index 2de42c584eb2..f831c9c225b6 100644 --- a/include/media/v4l2-of.h +++ b/include/media/v4l2-of.h @@ -69,9 +69,26 @@ struct v4l2_of_endpoint { struct list_head head; }; +/** + * struct v4l2_of_link - a link between two endpoints + * @local_node: pointer to device_node of this endpoint + * @local_port: identifier of the port this endpoint belongs to + * @remote_node: pointer to device_node of the remote endpoint + * @remote_port: identifier of the port the remote endpoint belongs to + */ +struct v4l2_of_link { + struct device_node *local_node; + unsigned int local_port; + struct device_node *remote_node; + unsigned int remote_port; +}; + #ifdef CONFIG_OF int v4l2_of_parse_endpoint(const struct device_node *node, struct v4l2_of_endpoint *endpoint); +int v4l2_of_parse_link(const struct device_node *node, + struct v4l2_of_link *link); +void v4l2_of_put_link(struct v4l2_of_link *link); #else /* CONFIG_OF */ static inline int v4l2_of_parse_endpoint(const struct device_node *node, @@ -80,6 +97,16 @@ static inline int v4l2_of_parse_endpoint(const struct device_node *node, return -ENOSYS; } +static inline int v4l2_of_parse_link(const struct device_node *node, + struct v4l2_of_link *link) +{ + return -ENOSYS; +} + +static inline void v4l2_of_put_link(struct v4l2_of_link *link) +{ +} + #endif /* CONFIG_OF */ #endif /* _V4L2_OF_H */ -- cgit v1.2.3 From df3305156f989339529b3d6744b898d498fb1f7b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 15 May 2013 11:36:19 -0300 Subject: [media] v4l: xilinx: Add Xilinx Video IP core Xilinx platforms have no hardwired video capture or video processing interface. Users create capture and memory to memory processing pipelines in the FPGA fabric to suit their particular needs, by instantiating video IP cores from a large library. The Xilinx Video IP core is a framework that models a video pipeline described in the device tree and expose the pipeline to userspace through the media controller and V4L2 APIs. Signed-off-by: Laurent Pinchart Signed-off-by: Hyun Kwon Signed-off-by: Radhey Shyam Pandey Signed-off-by: Michal Simek Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/xilinx/video.txt | 35 + .../bindings/media/xilinx/xlnx,video.txt | 55 ++ MAINTAINERS | 9 + drivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 2 + drivers/media/platform/xilinx/Kconfig | 10 + drivers/media/platform/xilinx/Makefile | 3 + drivers/media/platform/xilinx/xilinx-dma.c | 766 +++++++++++++++++++++ drivers/media/platform/xilinx/xilinx-dma.h | 109 +++ drivers/media/platform/xilinx/xilinx-vip.c | 323 +++++++++ drivers/media/platform/xilinx/xilinx-vip.h | 238 +++++++ drivers/media/platform/xilinx/xilinx-vipp.c | 669 ++++++++++++++++++ drivers/media/platform/xilinx/xilinx-vipp.h | 49 ++ include/dt-bindings/media/xilinx-vip.h | 39 ++ 14 files changed, 2308 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/xilinx/video.txt create mode 100644 Documentation/devicetree/bindings/media/xilinx/xlnx,video.txt create mode 100644 drivers/media/platform/xilinx/Kconfig create mode 100644 drivers/media/platform/xilinx/Makefile create mode 100644 drivers/media/platform/xilinx/xilinx-dma.c create mode 100644 drivers/media/platform/xilinx/xilinx-dma.h create mode 100644 drivers/media/platform/xilinx/xilinx-vip.c create mode 100644 drivers/media/platform/xilinx/xilinx-vip.h create mode 100644 drivers/media/platform/xilinx/xilinx-vipp.c create mode 100644 drivers/media/platform/xilinx/xilinx-vipp.h create mode 100644 include/dt-bindings/media/xilinx-vip.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/media/xilinx/video.txt b/Documentation/devicetree/bindings/media/xilinx/video.txt new file mode 100644 index 000000000000..cbd46fa0988f --- /dev/null +++ b/Documentation/devicetree/bindings/media/xilinx/video.txt @@ -0,0 +1,35 @@ +DT bindings for Xilinx video IP cores +------------------------------------- + +Xilinx video IP cores process video streams by acting as video sinks and/or +sources. They are connected by links through their input and output ports, +creating a video pipeline. + +Each video IP core is represented by an AMBA bus child node in the device +tree using bindings documented in this directory. Connections between the IP +cores are represented as defined in ../video-interfaces.txt. + +The whole pipeline is represented by an AMBA bus child node in the device +tree using bindings documented in ./xlnx,video.txt. + +Common properties +----------------- + +The following properties are common to all Xilinx video IP cores. + +- xlnx,video-format: This property represents a video format transmitted on an + AXI bus between video IP cores, using its VF code as defined in "AXI4-Stream + Video IP and System Design Guide" [UG934]. How the format relates to the IP + core is decribed in the IP core bindings documentation. + +- xlnx,video-width: This property qualifies the video format with the sample + width expressed as a number of bits per pixel component. All components must + use the same width. + +- xlnx,cfa-pattern: When the video format is set to Mono/Sensor, this property + describes the sensor's color filter array pattern. Supported values are + "bggr", "gbrg", "grbg", "rggb" and "mono". If not specified, the pattern + defaults to "mono". + + +[UG934] http://www.xilinx.com/support/documentation/ip_documentation/axi_videoip/v1_0/ug934_axi_videoIP.pdf diff --git a/Documentation/devicetree/bindings/media/xilinx/xlnx,video.txt b/Documentation/devicetree/bindings/media/xilinx/xlnx,video.txt new file mode 100644 index 000000000000..5a0227023608 --- /dev/null +++ b/Documentation/devicetree/bindings/media/xilinx/xlnx,video.txt @@ -0,0 +1,55 @@ +Xilinx Video IP Pipeline (VIPP) +------------------------------- + +General concept +--------------- + +Xilinx video IP pipeline processes video streams through one or more Xilinx +video IP cores. Each video IP core is represented as documented in video.txt +and IP core specific documentation, xlnx,v-*.txt, in this directory. The DT +node of the VIPP represents as a top level node of the pipeline and defines +mappings between DMAs and the video IP cores. + +Required properties: + +- compatible: Must be "xlnx,video". + +- dmas, dma-names: List of one DMA specifier and identifier string (as defined + in Documentation/devicetree/bindings/dma/dma.txt) per port. Each port + requires a DMA channel with the identifier string set to "port" followed by + the port index. + +- ports: Video port, using the DT bindings defined in ../video-interfaces.txt. + +Required port properties: + +- direction: should be either "input" or "output" depending on the direction + of stream. + +Example: + + video_cap { + compatible = "xlnx,video"; + dmas = <&vdma_1 1>, <&vdma_3 1>; + dma-names = "port0", "port1"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + direction = "input"; + vcap0_in0: endpoint { + remote-endpoint = <&scaler0_out>; + }; + }; + port@1 { + reg = <1>; + direction = "input"; + vcap0_in1: endpoint { + remote-endpoint = <&switch_out1>; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index ec9bf9f54c97..ca3b2638fcc6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10818,6 +10818,15 @@ L: linux-serial@vger.kernel.org S: Maintained F: drivers/tty/serial/uartlite.c +XILINX VIDEO IP CORES +M: Hyun Kwon +M: Laurent Pinchart +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Supported +F: Documentation/devicetree/bindings/media/xilinx/ +F: drivers/media/platform/xilinx/ + XILLYBUS DRIVER M: Eli Billauer L: linux-kernel@vger.kernel.org diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 272dc8c40f57..421f53188c6c 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -118,6 +118,7 @@ source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" source "drivers/media/platform/am437x/Kconfig" +source "drivers/media/platform/xilinx/Kconfig" endif # V4L_PLATFORM_DRIVERS diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 3ec154742083..8f855616c237 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -48,4 +48,6 @@ obj-y += omap/ obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ +obj-$(CONFIG_VIDEO_XILINX) += xilinx/ + ccflags-y += -I$(srctree)/drivers/media/i2c diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig new file mode 100644 index 000000000000..f4347e9af252 --- /dev/null +++ b/drivers/media/platform/xilinx/Kconfig @@ -0,0 +1,10 @@ +config VIDEO_XILINX + tristate "Xilinx Video IP (EXPERIMENTAL)" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF + select VIDEOBUF2_DMA_CONTIG + ---help--- + Driver for Xilinx Video IP Pipelines + +if VIDEO_XILINX + +endif #VIDEO_XILINX diff --git a/drivers/media/platform/xilinx/Makefile b/drivers/media/platform/xilinx/Makefile new file mode 100644 index 000000000000..3ef9c8e3cc8d --- /dev/null +++ b/drivers/media/platform/xilinx/Makefile @@ -0,0 +1,3 @@ +xilinx-video-objs += xilinx-dma.o xilinx-vip.o xilinx-vipp.o + +obj-$(CONFIG_VIDEO_XILINX) += xilinx-video.o diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c new file mode 100644 index 000000000000..10209c294168 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -0,0 +1,766 @@ +/* + * Xilinx Video DMA + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon + * Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "xilinx-dma.h" +#include "xilinx-vip.h" +#include "xilinx-vipp.h" + +#define XVIP_DMA_DEF_FORMAT V4L2_PIX_FMT_YUYV +#define XVIP_DMA_DEF_WIDTH 1920 +#define XVIP_DMA_DEF_HEIGHT 1080 + +/* Minimum and maximum widths are expressed in bytes */ +#define XVIP_DMA_MIN_WIDTH 1U +#define XVIP_DMA_MAX_WIDTH 65535U +#define XVIP_DMA_MIN_HEIGHT 1U +#define XVIP_DMA_MAX_HEIGHT 8191U + +/* ----------------------------------------------------------------------------- + * Helper functions + */ + +static struct v4l2_subdev * +xvip_dma_remote_subdev(struct media_pad *local, u32 *pad) +{ + struct media_pad *remote; + + remote = media_entity_remote_pad(local); + if (remote == NULL || + media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + return NULL; + + if (pad) + *pad = remote->index; + + return media_entity_to_v4l2_subdev(remote->entity); +} + +static int xvip_dma_verify_format(struct xvip_dma *dma) +{ + struct v4l2_subdev_format fmt; + struct v4l2_subdev *subdev; + int ret; + + subdev = xvip_dma_remote_subdev(&dma->pad, &fmt.pad); + if (subdev == NULL) + return -EPIPE; + + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); + if (ret < 0) + return ret == -ENOIOCTLCMD ? -EINVAL : ret; + + if (dma->fmtinfo->code != fmt.format.code || + dma->format.height != fmt.format.height || + dma->format.width != fmt.format.width || + dma->format.colorspace != fmt.format.colorspace) + return -EINVAL; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Pipeline Stream Management + */ + +/** + * xvip_pipeline_start_stop - Start ot stop streaming on a pipeline + * @pipe: The pipeline + * @start: Start (when true) or stop (when false) the pipeline + * + * Walk the entities chain starting at the pipeline output video node and start + * or stop all of them. + * + * Return: 0 if successful, or the return value of the failed video::s_stream + * operation otherwise. + */ +static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start) +{ + struct xvip_dma *dma = pipe->output; + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + int ret; + + entity = &dma->video.entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + ret = v4l2_subdev_call(subdev, video, s_stream, start); + if (start && ret < 0 && ret != -ENOIOCTLCMD) + return ret; + } + + return 0; +} + +/** + * xvip_pipeline_set_stream - Enable/disable streaming on a pipeline + * @pipe: The pipeline + * @on: Turn the stream on when true or off when false + * + * The pipeline is shared between all DMA engines connect at its input and + * output. While the stream state of DMA engines can be controlled + * independently, pipelines have a shared stream state that enable or disable + * all entities in the pipeline. For this reason the pipeline uses a streaming + * counter that tracks the number of DMA engines that have requested the stream + * to be enabled. + * + * When called with the @on argument set to true, this function will increment + * the pipeline streaming count. If the streaming count reaches the number of + * DMA engines in the pipeline it will enable all entities that belong to the + * pipeline. + * + * Similarly, when called with the @on argument set to false, this function will + * decrement the pipeline streaming count and disable all entities in the + * pipeline when the streaming count reaches zero. + * + * Return: 0 if successful, or the return value of the failed video::s_stream + * operation otherwise. Stopping the pipeline never fails. The pipeline state is + * not updated when the operation fails. + */ +static int xvip_pipeline_set_stream(struct xvip_pipeline *pipe, bool on) +{ + int ret = 0; + + mutex_lock(&pipe->lock); + + if (on) { + if (pipe->stream_count == pipe->num_dmas - 1) { + ret = xvip_pipeline_start_stop(pipe, true); + if (ret < 0) + goto done; + } + pipe->stream_count++; + } else { + if (--pipe->stream_count == 0) + xvip_pipeline_start_stop(pipe, false); + } + +done: + mutex_unlock(&pipe->lock); + return ret; +} + +static int xvip_pipeline_validate(struct xvip_pipeline *pipe, + struct xvip_dma *start) +{ + struct media_entity_graph graph; + struct media_entity *entity = &start->video.entity; + struct media_device *mdev = entity->parent; + unsigned int num_inputs = 0; + unsigned int num_outputs = 0; + + mutex_lock(&mdev->graph_mutex); + + /* Walk the graph to locate the video nodes. */ + media_entity_graph_walk_start(&graph, entity); + + while ((entity = media_entity_graph_walk_next(&graph))) { + struct xvip_dma *dma; + + if (entity->type != MEDIA_ENT_T_DEVNODE_V4L) + continue; + + dma = to_xvip_dma(media_entity_to_video_device(entity)); + + if (dma->pad.flags & MEDIA_PAD_FL_SINK) { + pipe->output = dma; + num_outputs++; + } else { + num_inputs++; + } + } + + mutex_unlock(&mdev->graph_mutex); + + /* We need exactly one output and zero or one input. */ + if (num_outputs != 1 || num_inputs > 1) + return -EPIPE; + + pipe->num_dmas = num_inputs + num_outputs; + + return 0; +} + +static void __xvip_pipeline_cleanup(struct xvip_pipeline *pipe) +{ + pipe->num_dmas = 0; + pipe->output = NULL; +} + +/** + * xvip_pipeline_cleanup - Cleanup the pipeline after streaming + * @pipe: the pipeline + * + * Decrease the pipeline use count and clean it up if we were the last user. + */ +static void xvip_pipeline_cleanup(struct xvip_pipeline *pipe) +{ + mutex_lock(&pipe->lock); + + /* If we're the last user clean up the pipeline. */ + if (--pipe->use_count == 0) + __xvip_pipeline_cleanup(pipe); + + mutex_unlock(&pipe->lock); +} + +/** + * xvip_pipeline_prepare - Prepare the pipeline for streaming + * @pipe: the pipeline + * @dma: DMA engine at one end of the pipeline + * + * Validate the pipeline if no user exists yet, otherwise just increase the use + * count. + * + * Return: 0 if successful or -EPIPE if the pipeline is not valid. + */ +static int xvip_pipeline_prepare(struct xvip_pipeline *pipe, + struct xvip_dma *dma) +{ + int ret; + + mutex_lock(&pipe->lock); + + /* If we're the first user validate and initialize the pipeline. */ + if (pipe->use_count == 0) { + ret = xvip_pipeline_validate(pipe, dma); + if (ret < 0) { + __xvip_pipeline_cleanup(pipe); + goto done; + } + } + + pipe->use_count++; + ret = 0; + +done: + mutex_unlock(&pipe->lock); + return ret; +} + +/* ----------------------------------------------------------------------------- + * videobuf2 queue operations + */ + +/** + * struct xvip_dma_buffer - Video DMA buffer + * @buf: vb2 buffer base object + * @queue: buffer list entry in the DMA engine queued buffers list + * @dma: DMA channel that uses the buffer + */ +struct xvip_dma_buffer { + struct vb2_buffer buf; + struct list_head queue; + struct xvip_dma *dma; +}; + +#define to_xvip_dma_buffer(vb) container_of(vb, struct xvip_dma_buffer, buf) + +static void xvip_dma_complete(void *param) +{ + struct xvip_dma_buffer *buf = param; + struct xvip_dma *dma = buf->dma; + + spin_lock(&dma->queued_lock); + list_del(&buf->queue); + spin_unlock(&dma->queued_lock); + + buf->buf.v4l2_buf.field = V4L2_FIELD_NONE; + buf->buf.v4l2_buf.sequence = dma->sequence++; + v4l2_get_timestamp(&buf->buf.v4l2_buf.timestamp); + vb2_set_plane_payload(&buf->buf, 0, dma->format.sizeimage); + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE); +} + +static int +xvip_dma_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vq); + + /* Make sure the image size is large enough. */ + if (fmt && fmt->fmt.pix.sizeimage < dma->format.sizeimage) + return -EINVAL; + + *nplanes = 1; + + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : dma->format.sizeimage; + alloc_ctxs[0] = dma->alloc_ctx; + + return 0; +} + +static int xvip_dma_buffer_prepare(struct vb2_buffer *vb) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vb->vb2_queue); + struct xvip_dma_buffer *buf = to_xvip_dma_buffer(vb); + + buf->dma = dma; + + return 0; +} + +static void xvip_dma_buffer_queue(struct vb2_buffer *vb) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vb->vb2_queue); + struct xvip_dma_buffer *buf = to_xvip_dma_buffer(vb); + struct dma_async_tx_descriptor *desc; + dma_addr_t addr = vb2_dma_contig_plane_dma_addr(vb, 0); + u32 flags; + + if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; + dma->xt.dir = DMA_DEV_TO_MEM; + dma->xt.src_sgl = false; + dma->xt.dst_sgl = true; + dma->xt.dst_start = addr; + } else { + flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; + dma->xt.dir = DMA_MEM_TO_DEV; + dma->xt.src_sgl = true; + dma->xt.dst_sgl = false; + dma->xt.src_start = addr; + } + + dma->xt.frame_size = 1; + dma->sgl[0].size = dma->format.width * dma->fmtinfo->bpp; + dma->sgl[0].icg = dma->format.bytesperline - dma->sgl[0].size; + dma->xt.numf = dma->format.height; + + desc = dmaengine_prep_interleaved_dma(dma->dma, &dma->xt, flags); + if (!desc) { + dev_err(dma->xdev->dev, "Failed to prepare DMA transfer\n"); + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR); + return; + } + desc->callback = xvip_dma_complete; + desc->callback_param = buf; + + spin_lock_irq(&dma->queued_lock); + list_add_tail(&buf->queue, &dma->queued_bufs); + spin_unlock_irq(&dma->queued_lock); + + dmaengine_submit(desc); + + if (vb2_is_streaming(&dma->queue)) + dma_async_issue_pending(dma->dma); +} + +static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vq); + struct xvip_dma_buffer *buf, *nbuf; + struct xvip_pipeline *pipe; + int ret; + + dma->sequence = 0; + + /* + * Start streaming on the pipeline. No link touching an entity in the + * pipeline can be activated or deactivated once streaming is started. + * + * Use the pipeline object embedded in the first DMA object that starts + * streaming. + */ + pipe = dma->video.entity.pipe + ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe; + + ret = media_entity_pipeline_start(&dma->video.entity, &pipe->pipe); + if (ret < 0) + goto error; + + /* Verify that the configured format matches the output of the + * connected subdev. + */ + ret = xvip_dma_verify_format(dma); + if (ret < 0) + goto error_stop; + + ret = xvip_pipeline_prepare(pipe, dma); + if (ret < 0) + goto error_stop; + + /* Start the DMA engine. This must be done before starting the blocks + * in the pipeline to avoid DMA synchronization issues. + */ + dma_async_issue_pending(dma->dma); + + /* Start the pipeline. */ + xvip_pipeline_set_stream(pipe, true); + + return 0; + +error_stop: + media_entity_pipeline_stop(&dma->video.entity); + +error: + /* Give back all queued buffers to videobuf2. */ + spin_lock_irq(&dma->queued_lock); + list_for_each_entry_safe(buf, nbuf, &dma->queued_bufs, queue) { + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_QUEUED); + list_del(&buf->queue); + } + spin_unlock_irq(&dma->queued_lock); + + return ret; +} + +static void xvip_dma_stop_streaming(struct vb2_queue *vq) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vq); + struct xvip_pipeline *pipe = to_xvip_pipeline(&dma->video.entity); + struct xvip_dma_buffer *buf, *nbuf; + + /* Stop the pipeline. */ + xvip_pipeline_set_stream(pipe, false); + + /* Stop and reset the DMA engine. */ + dmaengine_terminate_all(dma->dma); + + /* Cleanup the pipeline and mark it as being stopped. */ + xvip_pipeline_cleanup(pipe); + media_entity_pipeline_stop(&dma->video.entity); + + /* Give back all queued buffers to videobuf2. */ + spin_lock_irq(&dma->queued_lock); + list_for_each_entry_safe(buf, nbuf, &dma->queued_bufs, queue) { + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR); + list_del(&buf->queue); + } + spin_unlock_irq(&dma->queued_lock); +} + +static struct vb2_ops xvip_dma_queue_qops = { + .queue_setup = xvip_dma_queue_setup, + .buf_prepare = xvip_dma_buffer_prepare, + .buf_queue = xvip_dma_buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = xvip_dma_start_streaming, + .stop_streaming = xvip_dma_stop_streaming, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 ioctls + */ + +static int +xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + + cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING + | dma->xdev->v4l2_caps; + + if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + else + cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + + strlcpy(cap->driver, "xilinx-vipp", sizeof(cap->driver)); + strlcpy(cap->card, dma->video.name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s:%u", + dma->xdev->dev->of_node->name, dma->port); + + return 0; +} + +/* FIXME: without this callback function, some applications are not configured + * with correct formats, and it results in frames in wrong format. Whether this + * callback needs to be required is not clearly defined, so it should be + * clarified through the mailing list. + */ +static int +xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + + if (f->index > 0) + return -EINVAL; + + f->pixelformat = dma->format.pixelformat; + strlcpy(f->description, dma->fmtinfo->description, + sizeof(f->description)); + + return 0; +} + +static int +xvip_dma_get_format(struct file *file, void *fh, struct v4l2_format *format) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + + format->fmt.pix = dma->format; + + return 0; +} + +static void +__xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix, + const struct xvip_video_format **fmtinfo) +{ + const struct xvip_video_format *info; + unsigned int min_width; + unsigned int max_width; + unsigned int min_bpl; + unsigned int max_bpl; + unsigned int width; + unsigned int align; + unsigned int bpl; + + /* Retrieve format information and select the default format if the + * requested format isn't supported. + */ + info = xvip_get_format_by_fourcc(pix->pixelformat); + if (IS_ERR(info)) + info = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT); + + pix->pixelformat = info->fourcc; + pix->field = V4L2_FIELD_NONE; + + /* The transfer alignment requirements are expressed in bytes. Compute + * the minimum and maximum values, clamp the requested width and convert + * it back to pixels. + */ + align = lcm(dma->align, info->bpp); + min_width = roundup(XVIP_DMA_MIN_WIDTH, align); + max_width = rounddown(XVIP_DMA_MAX_WIDTH, align); + width = rounddown(pix->width * info->bpp, align); + + pix->width = clamp(width, min_width, max_width) / info->bpp; + pix->height = clamp(pix->height, XVIP_DMA_MIN_HEIGHT, + XVIP_DMA_MAX_HEIGHT); + + /* Clamp the requested bytes per line value. If the maximum bytes per + * line value is zero, the module doesn't support user configurable line + * sizes. Override the requested value with the minimum in that case. + */ + min_bpl = pix->width * info->bpp; + max_bpl = rounddown(XVIP_DMA_MAX_WIDTH, dma->align); + bpl = rounddown(pix->bytesperline, dma->align); + + pix->bytesperline = clamp(bpl, min_bpl, max_bpl); + pix->sizeimage = pix->bytesperline * pix->height; + + if (fmtinfo) + *fmtinfo = info; +} + +static int +xvip_dma_try_format(struct file *file, void *fh, struct v4l2_format *format) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + + __xvip_dma_try_format(dma, &format->fmt.pix, NULL); + return 0; +} + +static int +xvip_dma_set_format(struct file *file, void *fh, struct v4l2_format *format) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + const struct xvip_video_format *info; + + __xvip_dma_try_format(dma, &format->fmt.pix, &info); + + if (vb2_is_busy(&dma->queue)) + return -EBUSY; + + dma->format = format->fmt.pix; + dma->fmtinfo = info; + + return 0; +} + +static const struct v4l2_ioctl_ops xvip_dma_ioctl_ops = { + .vidioc_querycap = xvip_dma_querycap, + .vidioc_enum_fmt_vid_cap = xvip_dma_enum_format, + .vidioc_g_fmt_vid_cap = xvip_dma_get_format, + .vidioc_g_fmt_vid_out = xvip_dma_get_format, + .vidioc_s_fmt_vid_cap = xvip_dma_set_format, + .vidioc_s_fmt_vid_out = xvip_dma_set_format, + .vidioc_try_fmt_vid_cap = xvip_dma_try_format, + .vidioc_try_fmt_vid_out = xvip_dma_try_format, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 file operations + */ + +static const struct v4l2_file_operations xvip_dma_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, +}; + +/* ----------------------------------------------------------------------------- + * Xilinx Video DMA Core + */ + +int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, + enum v4l2_buf_type type, unsigned int port) +{ + char name[14]; + int ret; + + dma->xdev = xdev; + dma->port = port; + mutex_init(&dma->lock); + mutex_init(&dma->pipe.lock); + INIT_LIST_HEAD(&dma->queued_bufs); + spin_lock_init(&dma->queued_lock); + + dma->fmtinfo = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT); + dma->format.pixelformat = dma->fmtinfo->fourcc; + dma->format.colorspace = V4L2_COLORSPACE_SRGB; + dma->format.field = V4L2_FIELD_NONE; + dma->format.width = XVIP_DMA_DEF_WIDTH; + dma->format.height = XVIP_DMA_DEF_HEIGHT; + dma->format.bytesperline = dma->format.width * dma->fmtinfo->bpp; + dma->format.sizeimage = dma->format.bytesperline * dma->format.height; + + /* Initialize the media entity... */ + dma->pad.flags = type == V4L2_BUF_TYPE_VIDEO_CAPTURE + ? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; + + ret = media_entity_init(&dma->video.entity, 1, &dma->pad, 0); + if (ret < 0) + goto error; + + /* ... and the video node... */ + dma->video.fops = &xvip_dma_fops; + dma->video.v4l2_dev = &xdev->v4l2_dev; + dma->video.queue = &dma->queue; + snprintf(dma->video.name, sizeof(dma->video.name), "%s %s %u", + xdev->dev->of_node->name, + type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "output" : "input", + port); + dma->video.vfl_type = VFL_TYPE_GRABBER; + dma->video.vfl_dir = type == V4L2_BUF_TYPE_VIDEO_CAPTURE + ? VFL_DIR_RX : VFL_DIR_TX; + dma->video.release = video_device_release_empty; + dma->video.ioctl_ops = &xvip_dma_ioctl_ops; + dma->video.lock = &dma->lock; + + video_set_drvdata(&dma->video, dma); + + /* ... and the buffers queue... */ + dma->alloc_ctx = vb2_dma_contig_init_ctx(dma->xdev->dev); + if (IS_ERR(dma->alloc_ctx)) + goto error; + + /* Don't enable VB2_READ and VB2_WRITE, as using the read() and write() + * V4L2 APIs would be inefficient. Testing on the command line with a + * 'cat /dev/video?' thus won't be possible, but given that the driver + * anyway requires a test tool to setup the pipeline before any video + * stream can be started, requiring a specific V4L2 test tool as well + * instead of 'cat' isn't really a drawback. + */ + dma->queue.type = type; + dma->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + dma->queue.lock = &dma->lock; + dma->queue.drv_priv = dma; + dma->queue.buf_struct_size = sizeof(struct xvip_dma_buffer); + dma->queue.ops = &xvip_dma_queue_qops; + dma->queue.mem_ops = &vb2_dma_contig_memops; + dma->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC + | V4L2_BUF_FLAG_TSTAMP_SRC_EOF; + ret = vb2_queue_init(&dma->queue); + if (ret < 0) { + dev_err(dma->xdev->dev, "failed to initialize VB2 queue\n"); + goto error; + } + + /* ... and the DMA channel. */ + sprintf(name, "port%u", port); + dma->dma = dma_request_slave_channel(dma->xdev->dev, name); + if (dma->dma == NULL) { + dev_err(dma->xdev->dev, "no VDMA channel found\n"); + ret = -ENODEV; + goto error; + } + + dma->align = 1 << dma->dma->device->copy_align; + + ret = video_register_device(&dma->video, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + dev_err(dma->xdev->dev, "failed to register video device\n"); + goto error; + } + + return 0; + +error: + xvip_dma_cleanup(dma); + return ret; +} + +void xvip_dma_cleanup(struct xvip_dma *dma) +{ + if (video_is_registered(&dma->video)) + video_unregister_device(&dma->video); + + if (dma->dma) + dma_release_channel(dma->dma); + + if (!IS_ERR_OR_NULL(dma->alloc_ctx)) + vb2_dma_contig_cleanup_ctx(dma->alloc_ctx); + + media_entity_cleanup(&dma->video.entity); + + mutex_destroy(&dma->lock); + mutex_destroy(&dma->pipe.lock); +} diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h new file mode 100644 index 000000000000..a540111f8d3d --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-dma.h @@ -0,0 +1,109 @@ +/* + * Xilinx Video DMA + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon + * Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __XILINX_VIP_DMA_H__ +#define __XILINX_VIP_DMA_H__ + +#include +#include +#include +#include + +#include +#include +#include + +struct dma_chan; +struct xvip_composite_device; +struct xvip_video_format; + +/** + * struct xvip_pipeline - Xilinx Video IP pipeline structure + * @pipe: media pipeline + * @lock: protects the pipeline @stream_count + * @use_count: number of DMA engines using the pipeline + * @stream_count: number of DMA engines currently streaming + * @num_dmas: number of DMA engines in the pipeline + * @output: DMA engine at the output of the pipeline + */ +struct xvip_pipeline { + struct media_pipeline pipe; + + struct mutex lock; + unsigned int use_count; + unsigned int stream_count; + + unsigned int num_dmas; + struct xvip_dma *output; +}; + +static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e) +{ + return container_of(e->pipe, struct xvip_pipeline, pipe); +} + +/** + * struct xvip_dma - Video DMA channel + * @list: list entry in a composite device dmas list + * @video: V4L2 video device associated with the DMA channel + * @pad: media pad for the video device entity + * @xdev: composite device the DMA channel belongs to + * @pipe: pipeline belonging to the DMA channel + * @port: composite device DT node port number for the DMA channel + * @lock: protects the @format, @fmtinfo and @queue fields + * @format: active V4L2 pixel format + * @fmtinfo: format information corresponding to the active @format + * @queue: vb2 buffers queue + * @alloc_ctx: allocation context for the vb2 @queue + * @sequence: V4L2 buffers sequence number + * @queued_bufs: list of queued buffers + * @queued_lock: protects the buf_queued list + * @dma: DMA engine channel + * @align: transfer alignment required by the DMA channel (in bytes) + * @xt: dma interleaved template for dma configuration + * @sgl: data chunk structure for dma_interleaved_template + */ +struct xvip_dma { + struct list_head list; + struct video_device video; + struct media_pad pad; + + struct xvip_composite_device *xdev; + struct xvip_pipeline pipe; + unsigned int port; + + struct mutex lock; + struct v4l2_pix_format format; + const struct xvip_video_format *fmtinfo; + + struct vb2_queue queue; + void *alloc_ctx; + unsigned int sequence; + + struct list_head queued_bufs; + spinlock_t queued_lock; + + struct dma_chan *dma; + unsigned int align; + struct dma_interleaved_template xt; + struct data_chunk sgl[1]; +}; + +#define to_xvip_dma(vdev) container_of(vdev, struct xvip_dma, video) + +int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, + enum v4l2_buf_type type, unsigned int port); +void xvip_dma_cleanup(struct xvip_dma *dma); + +#endif /* __XILINX_VIP_DMA_H__ */ diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c new file mode 100644 index 000000000000..311259129504 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vip.c @@ -0,0 +1,323 @@ +/* + * Xilinx Video IP Core + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon + * Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include + +#include "xilinx-vip.h" + +/* ----------------------------------------------------------------------------- + * Helper functions + */ + +static const struct xvip_video_format xvip_video_formats[] = { + { XVIP_VF_YUV_422, 8, NULL, MEDIA_BUS_FMT_UYVY8_1X16, + 2, V4L2_PIX_FMT_YUYV, "4:2:2, packed, YUYV" }, + { XVIP_VF_YUV_444, 8, NULL, MEDIA_BUS_FMT_VUY8_1X24, + 3, V4L2_PIX_FMT_YUV444, "4:4:4, packed, YUYV" }, + { XVIP_VF_RBG, 8, NULL, MEDIA_BUS_FMT_RBG888_1X24, + 3, 0, NULL }, + { XVIP_VF_MONO_SENSOR, 8, "mono", MEDIA_BUS_FMT_Y8_1X8, + 1, V4L2_PIX_FMT_GREY, "Greyscale 8-bit" }, + { XVIP_VF_MONO_SENSOR, 8, "rggb", MEDIA_BUS_FMT_SRGGB8_1X8, + 1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit RGGB" }, + { XVIP_VF_MONO_SENSOR, 8, "grbg", MEDIA_BUS_FMT_SGRBG8_1X8, + 1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit GRBG" }, + { XVIP_VF_MONO_SENSOR, 8, "gbrg", MEDIA_BUS_FMT_SGBRG8_1X8, + 1, V4L2_PIX_FMT_SGBRG8, "Bayer 8-bit GBRG" }, + { XVIP_VF_MONO_SENSOR, 8, "bggr", MEDIA_BUS_FMT_SBGGR8_1X8, + 1, V4L2_PIX_FMT_SBGGR8, "Bayer 8-bit BGGR" }, +}; + +/** + * xvip_get_format_by_code - Retrieve format information for a media bus code + * @code: the format media bus code + * + * Return: a pointer to the format information structure corresponding to the + * given V4L2 media bus format @code, or ERR_PTR if no corresponding format can + * be found. + */ +const struct xvip_video_format *xvip_get_format_by_code(unsigned int code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) { + const struct xvip_video_format *format = &xvip_video_formats[i]; + + if (format->code == code) + return format; + } + + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(xvip_get_format_by_code); + +/** + * xvip_get_format_by_fourcc - Retrieve format information for a 4CC + * @fourcc: the format 4CC + * + * Return: a pointer to the format information structure corresponding to the + * given V4L2 format @fourcc, or ERR_PTR if no corresponding format can be + * found. + */ +const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) { + const struct xvip_video_format *format = &xvip_video_formats[i]; + + if (format->fourcc == fourcc) + return format; + } + + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(xvip_get_format_by_fourcc); + +/** + * xvip_of_get_format - Parse a device tree node and return format information + * @node: the device tree node + * + * Read the xlnx,video-format, xlnx,video-width and xlnx,cfa-pattern properties + * from the device tree @node passed as an argument and return the corresponding + * format information. + * + * Return: a pointer to the format information structure corresponding to the + * format name and width, or ERR_PTR if no corresponding format can be found. + */ +const struct xvip_video_format *xvip_of_get_format(struct device_node *node) +{ + const char *pattern = "mono"; + unsigned int vf_code; + unsigned int i; + u32 width; + int ret; + + ret = of_property_read_u32(node, "xlnx,video-format", &vf_code); + if (ret < 0) + return ERR_PTR(ret); + + ret = of_property_read_u32(node, "xlnx,video-width", &width); + if (ret < 0) + return ERR_PTR(ret); + + if (vf_code == XVIP_VF_MONO_SENSOR) + of_property_read_string(node, "xlnx,cfa-pattern", &pattern); + + for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) { + const struct xvip_video_format *format = &xvip_video_formats[i]; + + if (format->vf_code != vf_code || format->width != width) + continue; + + if (vf_code == XVIP_VF_MONO_SENSOR && + strcmp(pattern, format->pattern)) + continue; + + return format; + } + + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(xvip_of_get_format); + +/** + * xvip_set_format_size - Set the media bus frame format size + * @format: V4L2 frame format on media bus + * @fmt: media bus format + * + * Set the media bus frame format size. The width / height from the subdevice + * format are set to the given media bus format. The new format size is stored + * in @format. The width and height are clamped using default min / max values. + */ +void xvip_set_format_size(struct v4l2_mbus_framefmt *format, + const struct v4l2_subdev_format *fmt) +{ + format->width = clamp_t(unsigned int, fmt->format.width, + XVIP_MIN_WIDTH, XVIP_MAX_WIDTH); + format->height = clamp_t(unsigned int, fmt->format.height, + XVIP_MIN_HEIGHT, XVIP_MAX_HEIGHT); +} +EXPORT_SYMBOL_GPL(xvip_set_format_size); + +/** + * xvip_clr_or_set - Clear or set the register with a bitmask + * @xvip: Xilinx Video IP device + * @addr: address of register + * @mask: bitmask to be set or cleared + * @set: boolean flag indicating whether to set or clear + * + * Clear or set the register at address @addr with a bitmask @mask depending on + * the boolean flag @set. When the flag @set is true, the bitmask is set in + * the register, otherwise the bitmask is cleared from the register + * when the flag @set is false. + * + * Fox eample, this function can be used to set a control with a boolean value + * requested by users. If the caller knows whether to set or clear in the first + * place, the caller should call xvip_clr() or xvip_set() directly instead of + * using this function. + */ +void xvip_clr_or_set(struct xvip_device *xvip, u32 addr, u32 mask, bool set) +{ + u32 reg; + + reg = xvip_read(xvip, addr); + reg = set ? reg | mask : reg & ~mask; + xvip_write(xvip, addr, reg); +} +EXPORT_SYMBOL_GPL(xvip_clr_or_set); + +/** + * xvip_clr_and_set - Clear and set the register with a bitmask + * @xvip: Xilinx Video IP device + * @addr: address of register + * @clr: bitmask to be cleared + * @set: bitmask to be set + * + * Clear a bit(s) of mask @clr in the register at address @addr, then set + * a bit(s) of mask @set in the register after. + */ +void xvip_clr_and_set(struct xvip_device *xvip, u32 addr, u32 clr, u32 set) +{ + u32 reg; + + reg = xvip_read(xvip, addr); + reg &= ~clr; + reg |= set; + xvip_write(xvip, addr, reg); +} +EXPORT_SYMBOL_GPL(xvip_clr_and_set); + +int xvip_init_resources(struct xvip_device *xvip) +{ + struct platform_device *pdev = to_platform_device(xvip->dev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xvip->iomem = devm_ioremap_resource(xvip->dev, res); + if (IS_ERR(xvip->iomem)) + return PTR_ERR(xvip->iomem); + + xvip->clk = devm_clk_get(xvip->dev, NULL); + if (IS_ERR(xvip->clk)) + return PTR_ERR(xvip->clk); + + clk_prepare_enable(xvip->clk); + return 0; +} +EXPORT_SYMBOL_GPL(xvip_init_resources); + +void xvip_cleanup_resources(struct xvip_device *xvip) +{ + clk_disable_unprepare(xvip->clk); +} +EXPORT_SYMBOL_GPL(xvip_cleanup_resources); + +/* ----------------------------------------------------------------------------- + * Subdev operations handlers + */ + +/** + * xvip_enum_mbus_code - Enumerate the media format code + * @subdev: V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @code: returning media bus code + * + * Enumerate the media bus code of the subdevice. Return the corresponding + * pad format code. This function only works for subdevices with fixed format + * on all pads. Subdevices with multiple format should have their own + * function to enumerate mbus codes. + * + * Return: 0 if the media bus code is found, or -EINVAL if the format index + * is not valid. + */ +int xvip_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct v4l2_mbus_framefmt *format; + + /* Enumerating frame sizes based on the active configuration isn't + * supported yet. + */ + if (code->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + if (code->index) + return -EINVAL; + + format = v4l2_subdev_get_try_format(subdev, cfg, code->pad); + + code->code = format->code; + + return 0; +} +EXPORT_SYMBOL_GPL(xvip_enum_mbus_code); + +/** + * xvip_enum_frame_size - Enumerate the media bus frame size + * @subdev: V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fse: returning media bus frame size + * + * This function is a drop-in implementation of the subdev enum_frame_size pad + * operation. It assumes that the subdevice has one sink pad and one source + * pad, and that the format on the source pad is always identical to the + * format on the sink pad. Entities with different requirements need to + * implement their own enum_frame_size handlers. + * + * Return: 0 if the media bus frame size is found, or -EINVAL + * if the index or the code is not valid. + */ +int xvip_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct v4l2_mbus_framefmt *format; + + /* Enumerating frame sizes based on the active configuration isn't + * supported yet. + */ + if (fse->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad); + + if (fse->index || fse->code != format->code) + return -EINVAL; + + if (fse->pad == XVIP_PAD_SINK) { + fse->min_width = XVIP_MIN_WIDTH; + fse->max_width = XVIP_MAX_WIDTH; + fse->min_height = XVIP_MIN_HEIGHT; + fse->max_height = XVIP_MAX_HEIGHT; + } else { + /* The size on the source pad is fixed and always identical to + * the size on the sink pad. + */ + fse->min_width = format->width; + fse->max_width = format->width; + fse->min_height = format->height; + fse->max_height = format->height; + } + + return 0; +} +EXPORT_SYMBOL_GPL(xvip_enum_frame_size); diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h new file mode 100644 index 000000000000..42fee2026815 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vip.h @@ -0,0 +1,238 @@ +/* + * Xilinx Video IP Core + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon + * Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __XILINX_VIP_H__ +#define __XILINX_VIP_H__ + +#include +#include + +struct clk; + +/* + * Minimum and maximum width and height common to most video IP cores. IP + * cores with different requirements must define their own values. + */ +#define XVIP_MIN_WIDTH 32 +#define XVIP_MAX_WIDTH 7680 +#define XVIP_MIN_HEIGHT 32 +#define XVIP_MAX_HEIGHT 7680 + +/* + * Pad IDs. IP cores with with multiple inputs or outputs should define + * their own values. + */ +#define XVIP_PAD_SINK 0 +#define XVIP_PAD_SOURCE 1 + +/* Xilinx Video IP Control Registers */ +#define XVIP_CTRL_CONTROL 0x0000 +#define XVIP_CTRL_CONTROL_SW_ENABLE (1 << 0) +#define XVIP_CTRL_CONTROL_REG_UPDATE (1 << 1) +#define XVIP_CTRL_CONTROL_BYPASS (1 << 4) +#define XVIP_CTRL_CONTROL_TEST_PATTERN (1 << 5) +#define XVIP_CTRL_CONTROL_FRAME_SYNC_RESET (1 << 30) +#define XVIP_CTRL_CONTROL_SW_RESET (1 << 31) +#define XVIP_CTRL_STATUS 0x0004 +#define XVIP_CTRL_STATUS_PROC_STARTED (1 << 0) +#define XVIP_CTRL_STATUS_EOF (1 << 1) +#define XVIP_CTRL_ERROR 0x0008 +#define XVIP_CTRL_ERROR_SLAVE_EOL_EARLY (1 << 0) +#define XVIP_CTRL_ERROR_SLAVE_EOL_LATE (1 << 1) +#define XVIP_CTRL_ERROR_SLAVE_SOF_EARLY (1 << 2) +#define XVIP_CTRL_ERROR_SLAVE_SOF_LATE (1 << 3) +#define XVIP_CTRL_IRQ_ENABLE 0x000c +#define XVIP_CTRL_IRQ_ENABLE_PROC_STARTED (1 << 0) +#define XVIP_CTRL_IRQ_EOF (1 << 1) +#define XVIP_CTRL_VERSION 0x0010 +#define XVIP_CTRL_VERSION_MAJOR_MASK (0xff << 24) +#define XVIP_CTRL_VERSION_MAJOR_SHIFT 24 +#define XVIP_CTRL_VERSION_MINOR_MASK (0xff << 16) +#define XVIP_CTRL_VERSION_MINOR_SHIFT 16 +#define XVIP_CTRL_VERSION_REVISION_MASK (0xf << 12) +#define XVIP_CTRL_VERSION_REVISION_SHIFT 12 +#define XVIP_CTRL_VERSION_PATCH_MASK (0xf << 8) +#define XVIP_CTRL_VERSION_PATCH_SHIFT 8 +#define XVIP_CTRL_VERSION_INTERNAL_MASK (0xff << 0) +#define XVIP_CTRL_VERSION_INTERNAL_SHIFT 0 + +/* Xilinx Video IP Timing Registers */ +#define XVIP_ACTIVE_SIZE 0x0020 +#define XVIP_ACTIVE_VSIZE_MASK (0x7ff << 16) +#define XVIP_ACTIVE_VSIZE_SHIFT 16 +#define XVIP_ACTIVE_HSIZE_MASK (0x7ff << 0) +#define XVIP_ACTIVE_HSIZE_SHIFT 0 +#define XVIP_ENCODING 0x0028 +#define XVIP_ENCODING_NBITS_8 (0 << 4) +#define XVIP_ENCODING_NBITS_10 (1 << 4) +#define XVIP_ENCODING_NBITS_12 (2 << 4) +#define XVIP_ENCODING_NBITS_16 (3 << 4) +#define XVIP_ENCODING_NBITS_MASK (3 << 4) +#define XVIP_ENCODING_NBITS_SHIFT 4 +#define XVIP_ENCODING_VIDEO_FORMAT_YUV422 (0 << 0) +#define XVIP_ENCODING_VIDEO_FORMAT_YUV444 (1 << 0) +#define XVIP_ENCODING_VIDEO_FORMAT_RGB (2 << 0) +#define XVIP_ENCODING_VIDEO_FORMAT_YUV420 (3 << 0) +#define XVIP_ENCODING_VIDEO_FORMAT_MASK (3 << 0) +#define XVIP_ENCODING_VIDEO_FORMAT_SHIFT 0 + +/** + * struct xvip_device - Xilinx Video IP device structure + * @subdev: V4L2 subdevice + * @dev: (OF) device + * @iomem: device I/O register space remapped to kernel virtual memory + * @clk: video core clock + * @saved_ctrl: saved control register for resume / suspend + */ +struct xvip_device { + struct v4l2_subdev subdev; + struct device *dev; + void __iomem *iomem; + struct clk *clk; + u32 saved_ctrl; +}; + +/** + * struct xvip_video_format - Xilinx Video IP video format description + * @vf_code: AXI4 video format code + * @width: AXI4 format width in bits per component + * @pattern: CFA pattern for Mono/Sensor formats + * @code: media bus format code + * @bpp: bytes per pixel (when stored in memory) + * @fourcc: V4L2 pixel format FCC identifier + * @description: format description, suitable for userspace + */ +struct xvip_video_format { + unsigned int vf_code; + unsigned int width; + const char *pattern; + unsigned int code; + unsigned int bpp; + u32 fourcc; + const char *description; +}; + +const struct xvip_video_format *xvip_get_format_by_code(unsigned int code); +const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc); +const struct xvip_video_format *xvip_of_get_format(struct device_node *node); +void xvip_set_format_size(struct v4l2_mbus_framefmt *format, + const struct v4l2_subdev_format *fmt); +int xvip_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code); +int xvip_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse); + +static inline u32 xvip_read(struct xvip_device *xvip, u32 addr) +{ + return ioread32(xvip->iomem + addr); +} + +static inline void xvip_write(struct xvip_device *xvip, u32 addr, u32 value) +{ + iowrite32(value, xvip->iomem + addr); +} + +static inline void xvip_clr(struct xvip_device *xvip, u32 addr, u32 clr) +{ + xvip_write(xvip, addr, xvip_read(xvip, addr) & ~clr); +} + +static inline void xvip_set(struct xvip_device *xvip, u32 addr, u32 set) +{ + xvip_write(xvip, addr, xvip_read(xvip, addr) | set); +} + +void xvip_clr_or_set(struct xvip_device *xvip, u32 addr, u32 mask, bool set); +void xvip_clr_and_set(struct xvip_device *xvip, u32 addr, u32 clr, u32 set); + +int xvip_init_resources(struct xvip_device *xvip); +void xvip_cleanup_resources(struct xvip_device *xvip); + +static inline void xvip_reset(struct xvip_device *xvip) +{ + xvip_write(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_SW_RESET); +} + +static inline void xvip_start(struct xvip_device *xvip) +{ + xvip_set(xvip, XVIP_CTRL_CONTROL, + XVIP_CTRL_CONTROL_SW_ENABLE | XVIP_CTRL_CONTROL_REG_UPDATE); +} + +static inline void xvip_stop(struct xvip_device *xvip) +{ + xvip_clr(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_SW_ENABLE); +} + +static inline void xvip_resume(struct xvip_device *xvip) +{ + xvip_write(xvip, XVIP_CTRL_CONTROL, + xvip->saved_ctrl | XVIP_CTRL_CONTROL_SW_ENABLE); +} + +static inline void xvip_suspend(struct xvip_device *xvip) +{ + xvip->saved_ctrl = xvip_read(xvip, XVIP_CTRL_CONTROL); + xvip_write(xvip, XVIP_CTRL_CONTROL, + xvip->saved_ctrl & ~XVIP_CTRL_CONTROL_SW_ENABLE); +} + +static inline void xvip_set_frame_size(struct xvip_device *xvip, + const struct v4l2_mbus_framefmt *format) +{ + xvip_write(xvip, XVIP_ACTIVE_SIZE, + (format->height << XVIP_ACTIVE_VSIZE_SHIFT) | + (format->width << XVIP_ACTIVE_HSIZE_SHIFT)); +} + +static inline void xvip_get_frame_size(struct xvip_device *xvip, + struct v4l2_mbus_framefmt *format) +{ + u32 reg; + + reg = xvip_read(xvip, XVIP_ACTIVE_SIZE); + format->width = (reg & XVIP_ACTIVE_HSIZE_MASK) >> + XVIP_ACTIVE_HSIZE_SHIFT; + format->height = (reg & XVIP_ACTIVE_VSIZE_MASK) >> + XVIP_ACTIVE_VSIZE_SHIFT; +} + +static inline void xvip_enable_reg_update(struct xvip_device *xvip) +{ + xvip_set(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_REG_UPDATE); +} + +static inline void xvip_disable_reg_update(struct xvip_device *xvip) +{ + xvip_clr(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_REG_UPDATE); +} + +static inline void xvip_print_version(struct xvip_device *xvip) +{ + u32 version; + + version = xvip_read(xvip, XVIP_CTRL_VERSION); + + dev_info(xvip->dev, "device found, version %u.%02x%x\n", + ((version & XVIP_CTRL_VERSION_MAJOR_MASK) >> + XVIP_CTRL_VERSION_MAJOR_SHIFT), + ((version & XVIP_CTRL_VERSION_MINOR_MASK) >> + XVIP_CTRL_VERSION_MINOR_SHIFT), + ((version & XVIP_CTRL_VERSION_REVISION_MASK) >> + XVIP_CTRL_VERSION_REVISION_SHIFT)); +} + +#endif /* __XILINX_VIP_H__ */ diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c new file mode 100644 index 000000000000..7b7cb9c28d2c --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -0,0 +1,669 @@ +/* + * Xilinx Video IP Composite Device + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon + * Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "xilinx-dma.h" +#include "xilinx-vipp.h" + +#define XVIPP_DMA_S2MM 0 +#define XVIPP_DMA_MM2S 1 + +/** + * struct xvip_graph_entity - Entity in the video graph + * @list: list entry in a graph entities list + * @node: the entity's DT node + * @entity: media entity, from the corresponding V4L2 subdev + * @asd: subdev asynchronous registration information + * @subdev: V4L2 subdev + */ +struct xvip_graph_entity { + struct list_head list; + struct device_node *node; + struct media_entity *entity; + + struct v4l2_async_subdev asd; + struct v4l2_subdev *subdev; +}; + +/* ----------------------------------------------------------------------------- + * Graph Management + */ + +static struct xvip_graph_entity * +xvip_graph_find_entity(struct xvip_composite_device *xdev, + const struct device_node *node) +{ + struct xvip_graph_entity *entity; + + list_for_each_entry(entity, &xdev->entities, list) { + if (entity->node == node) + return entity; + } + + return NULL; +} + +static int xvip_graph_build_one(struct xvip_composite_device *xdev, + struct xvip_graph_entity *entity) +{ + u32 link_flags = MEDIA_LNK_FL_ENABLED; + struct media_entity *local = entity->entity; + struct media_entity *remote; + struct media_pad *local_pad; + struct media_pad *remote_pad; + struct xvip_graph_entity *ent; + struct v4l2_of_link link; + struct device_node *ep = NULL; + struct device_node *next; + int ret = 0; + + dev_dbg(xdev->dev, "creating links for entity %s\n", local->name); + + while (1) { + /* Get the next endpoint and parse its link. */ + next = of_graph_get_next_endpoint(entity->node, ep); + if (next == NULL) + break; + + of_node_put(ep); + ep = next; + + dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name); + + ret = v4l2_of_parse_link(ep, &link); + if (ret < 0) { + dev_err(xdev->dev, "failed to parse link for %s\n", + ep->full_name); + continue; + } + + /* Skip sink ports, they will be processed from the other end of + * the link. + */ + if (link.local_port >= local->num_pads) { + dev_err(xdev->dev, "invalid port number %u on %s\n", + link.local_port, link.local_node->full_name); + v4l2_of_put_link(&link); + ret = -EINVAL; + break; + } + + local_pad = &local->pads[link.local_port]; + + if (local_pad->flags & MEDIA_PAD_FL_SINK) { + dev_dbg(xdev->dev, "skipping sink port %s:%u\n", + link.local_node->full_name, link.local_port); + v4l2_of_put_link(&link); + continue; + } + + /* Skip DMA engines, they will be processed separately. */ + if (link.remote_node == xdev->dev->of_node) { + dev_dbg(xdev->dev, "skipping DMA port %s:%u\n", + link.local_node->full_name, link.local_port); + v4l2_of_put_link(&link); + continue; + } + + /* Find the remote entity. */ + ent = xvip_graph_find_entity(xdev, link.remote_node); + if (ent == NULL) { + dev_err(xdev->dev, "no entity found for %s\n", + link.remote_node->full_name); + v4l2_of_put_link(&link); + ret = -ENODEV; + break; + } + + remote = ent->entity; + + if (link.remote_port >= remote->num_pads) { + dev_err(xdev->dev, "invalid port number %u on %s\n", + link.remote_port, link.remote_node->full_name); + v4l2_of_put_link(&link); + ret = -EINVAL; + break; + } + + remote_pad = &remote->pads[link.remote_port]; + + v4l2_of_put_link(&link); + + /* Create the media link. */ + dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n", + local->name, local_pad->index, + remote->name, remote_pad->index); + + ret = media_entity_create_link(local, local_pad->index, + remote, remote_pad->index, + link_flags); + if (ret < 0) { + dev_err(xdev->dev, + "failed to create %s:%u -> %s:%u link\n", + local->name, local_pad->index, + remote->name, remote_pad->index); + break; + } + } + + of_node_put(ep); + return ret; +} + +static struct xvip_dma * +xvip_graph_find_dma(struct xvip_composite_device *xdev, unsigned int port) +{ + struct xvip_dma *dma; + + list_for_each_entry(dma, &xdev->dmas, list) { + if (dma->port == port) + return dma; + } + + return NULL; +} + +static int xvip_graph_build_dma(struct xvip_composite_device *xdev) +{ + u32 link_flags = MEDIA_LNK_FL_ENABLED; + struct device_node *node = xdev->dev->of_node; + struct media_entity *source; + struct media_entity *sink; + struct media_pad *source_pad; + struct media_pad *sink_pad; + struct xvip_graph_entity *ent; + struct v4l2_of_link link; + struct device_node *ep = NULL; + struct device_node *next; + struct xvip_dma *dma; + int ret = 0; + + dev_dbg(xdev->dev, "creating links for DMA engines\n"); + + while (1) { + /* Get the next endpoint and parse its link. */ + next = of_graph_get_next_endpoint(node, ep); + if (next == NULL) + break; + + of_node_put(ep); + ep = next; + + dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name); + + ret = v4l2_of_parse_link(ep, &link); + if (ret < 0) { + dev_err(xdev->dev, "failed to parse link for %s\n", + ep->full_name); + continue; + } + + /* Find the DMA engine. */ + dma = xvip_graph_find_dma(xdev, link.local_port); + if (dma == NULL) { + dev_err(xdev->dev, "no DMA engine found for port %u\n", + link.local_port); + v4l2_of_put_link(&link); + ret = -EINVAL; + break; + } + + dev_dbg(xdev->dev, "creating link for DMA engine %s\n", + dma->video.name); + + /* Find the remote entity. */ + ent = xvip_graph_find_entity(xdev, link.remote_node); + if (ent == NULL) { + dev_err(xdev->dev, "no entity found for %s\n", + link.remote_node->full_name); + v4l2_of_put_link(&link); + ret = -ENODEV; + break; + } + + if (link.remote_port >= ent->entity->num_pads) { + dev_err(xdev->dev, "invalid port number %u on %s\n", + link.remote_port, link.remote_node->full_name); + v4l2_of_put_link(&link); + ret = -EINVAL; + break; + } + + if (dma->pad.flags & MEDIA_PAD_FL_SOURCE) { + source = &dma->video.entity; + source_pad = &dma->pad; + sink = ent->entity; + sink_pad = &sink->pads[link.remote_port]; + } else { + source = ent->entity; + source_pad = &source->pads[link.remote_port]; + sink = &dma->video.entity; + sink_pad = &dma->pad; + } + + v4l2_of_put_link(&link); + + /* Create the media link. */ + dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n", + source->name, source_pad->index, + sink->name, sink_pad->index); + + ret = media_entity_create_link(source, source_pad->index, + sink, sink_pad->index, + link_flags); + if (ret < 0) { + dev_err(xdev->dev, + "failed to create %s:%u -> %s:%u link\n", + source->name, source_pad->index, + sink->name, sink_pad->index); + break; + } + } + + of_node_put(ep); + return ret; +} + +static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier) +{ + struct xvip_composite_device *xdev = + container_of(notifier, struct xvip_composite_device, notifier); + struct xvip_graph_entity *entity; + int ret; + + dev_dbg(xdev->dev, "notify complete, all subdevs registered\n"); + + /* Create links for every entity. */ + list_for_each_entry(entity, &xdev->entities, list) { + ret = xvip_graph_build_one(xdev, entity); + if (ret < 0) + return ret; + } + + /* Create links for DMA channels. */ + ret = xvip_graph_build_dma(xdev); + if (ret < 0) + return ret; + + ret = v4l2_device_register_subdev_nodes(&xdev->v4l2_dev); + if (ret < 0) + dev_err(xdev->dev, "failed to register subdev nodes\n"); + + return ret; +} + +static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct xvip_composite_device *xdev = + container_of(notifier, struct xvip_composite_device, notifier); + struct xvip_graph_entity *entity; + + /* Locate the entity corresponding to the bound subdev and store the + * subdev pointer. + */ + list_for_each_entry(entity, &xdev->entities, list) { + if (entity->node != subdev->dev->of_node) + continue; + + if (entity->subdev) { + dev_err(xdev->dev, "duplicate subdev for node %s\n", + entity->node->full_name); + return -EINVAL; + } + + dev_dbg(xdev->dev, "subdev %s bound\n", subdev->name); + entity->entity = &subdev->entity; + entity->subdev = subdev; + return 0; + } + + dev_err(xdev->dev, "no entity for subdev %s\n", subdev->name); + return -EINVAL; +} + +static int xvip_graph_parse_one(struct xvip_composite_device *xdev, + struct device_node *node) +{ + struct xvip_graph_entity *entity; + struct device_node *remote; + struct device_node *ep = NULL; + struct device_node *next; + int ret = 0; + + dev_dbg(xdev->dev, "parsing node %s\n", node->full_name); + + while (1) { + next = of_graph_get_next_endpoint(node, ep); + if (next == NULL) + break; + + of_node_put(ep); + ep = next; + + dev_dbg(xdev->dev, "handling endpoint %s\n", ep->full_name); + + remote = of_graph_get_remote_port_parent(ep); + if (remote == NULL) { + ret = -EINVAL; + break; + } + + /* Skip entities that we have already processed. */ + if (remote == xdev->dev->of_node || + xvip_graph_find_entity(xdev, remote)) { + of_node_put(remote); + continue; + } + + entity = devm_kzalloc(xdev->dev, sizeof(*entity), GFP_KERNEL); + if (entity == NULL) { + of_node_put(remote); + ret = -ENOMEM; + break; + } + + entity->node = remote; + entity->asd.match_type = V4L2_ASYNC_MATCH_OF; + entity->asd.match.of.node = remote; + list_add_tail(&entity->list, &xdev->entities); + xdev->num_subdevs++; + } + + of_node_put(ep); + return ret; +} + +static int xvip_graph_parse(struct xvip_composite_device *xdev) +{ + struct xvip_graph_entity *entity; + int ret; + + /* + * Walk the links to parse the full graph. Start by parsing the + * composite node and then parse entities in turn. The list_for_each + * loop will handle entities added at the end of the list while walking + * the links. + */ + ret = xvip_graph_parse_one(xdev, xdev->dev->of_node); + if (ret < 0) + return 0; + + list_for_each_entry(entity, &xdev->entities, list) { + ret = xvip_graph_parse_one(xdev, entity->node); + if (ret < 0) + break; + } + + return ret; +} + +static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev, + struct device_node *node) +{ + struct xvip_dma *dma; + enum v4l2_buf_type type; + const char *direction; + unsigned int index; + int ret; + + ret = of_property_read_string(node, "direction", &direction); + if (ret < 0) + return ret; + + if (strcmp(direction, "input") == 0) + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + else if (strcmp(direction, "output") == 0) + type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + else + return -EINVAL; + + of_property_read_u32(node, "reg", &index); + + dma = devm_kzalloc(xdev->dev, sizeof(*dma), GFP_KERNEL); + if (dma == NULL) + return -ENOMEM; + + ret = xvip_dma_init(xdev, dma, type, index); + if (ret < 0) { + dev_err(xdev->dev, "%s initialization failed\n", + node->full_name); + return ret; + } + + list_add_tail(&dma->list, &xdev->dmas); + + xdev->v4l2_caps |= type == V4L2_BUF_TYPE_VIDEO_CAPTURE + ? V4L2_CAP_VIDEO_CAPTURE : V4L2_CAP_VIDEO_OUTPUT; + + return 0; +} + +static int xvip_graph_dma_init(struct xvip_composite_device *xdev) +{ + struct device_node *ports; + struct device_node *port; + int ret; + + ports = of_get_child_by_name(xdev->dev->of_node, "ports"); + if (ports == NULL) { + dev_err(xdev->dev, "ports node not present\n"); + return -EINVAL; + } + + for_each_child_of_node(ports, port) { + ret = xvip_graph_dma_init_one(xdev, port); + if (ret < 0) + return ret; + } + + return 0; +} + +static void xvip_graph_cleanup(struct xvip_composite_device *xdev) +{ + struct xvip_graph_entity *entityp; + struct xvip_graph_entity *entity; + struct xvip_dma *dmap; + struct xvip_dma *dma; + + v4l2_async_notifier_unregister(&xdev->notifier); + + list_for_each_entry_safe(entity, entityp, &xdev->entities, list) { + of_node_put(entity->node); + list_del(&entity->list); + } + + list_for_each_entry_safe(dma, dmap, &xdev->dmas, list) { + xvip_dma_cleanup(dma); + list_del(&dma->list); + } +} + +static int xvip_graph_init(struct xvip_composite_device *xdev) +{ + struct xvip_graph_entity *entity; + struct v4l2_async_subdev **subdevs = NULL; + unsigned int num_subdevs; + unsigned int i; + int ret; + + /* Init the DMA channels. */ + ret = xvip_graph_dma_init(xdev); + if (ret < 0) { + dev_err(xdev->dev, "DMA initialization failed\n"); + goto done; + } + + /* Parse the graph to extract a list of subdevice DT nodes. */ + ret = xvip_graph_parse(xdev); + if (ret < 0) { + dev_err(xdev->dev, "graph parsing failed\n"); + goto done; + } + + if (!xdev->num_subdevs) { + dev_err(xdev->dev, "no subdev found in graph\n"); + goto done; + } + + /* Register the subdevices notifier. */ + num_subdevs = xdev->num_subdevs; + subdevs = devm_kzalloc(xdev->dev, sizeof(*subdevs) * num_subdevs, + GFP_KERNEL); + if (subdevs == NULL) { + ret = -ENOMEM; + goto done; + } + + i = 0; + list_for_each_entry(entity, &xdev->entities, list) + subdevs[i++] = &entity->asd; + + xdev->notifier.subdevs = subdevs; + xdev->notifier.num_subdevs = num_subdevs; + xdev->notifier.bound = xvip_graph_notify_bound; + xdev->notifier.complete = xvip_graph_notify_complete; + + ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier); + if (ret < 0) { + dev_err(xdev->dev, "notifier registration failed\n"); + goto done; + } + + ret = 0; + +done: + if (ret < 0) + xvip_graph_cleanup(xdev); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * Media Controller and V4L2 + */ + +static void xvip_composite_v4l2_cleanup(struct xvip_composite_device *xdev) +{ + v4l2_device_unregister(&xdev->v4l2_dev); + media_device_unregister(&xdev->media_dev); +} + +static int xvip_composite_v4l2_init(struct xvip_composite_device *xdev) +{ + int ret; + + xdev->media_dev.dev = xdev->dev; + strlcpy(xdev->media_dev.model, "Xilinx Video Composite Device", + sizeof(xdev->media_dev.model)); + xdev->media_dev.hw_revision = 0; + + ret = media_device_register(&xdev->media_dev); + if (ret < 0) { + dev_err(xdev->dev, "media device registration failed (%d)\n", + ret); + return ret; + } + + xdev->v4l2_dev.mdev = &xdev->media_dev; + ret = v4l2_device_register(xdev->dev, &xdev->v4l2_dev); + if (ret < 0) { + dev_err(xdev->dev, "V4L2 device registration failed (%d)\n", + ret); + media_device_unregister(&xdev->media_dev); + return ret; + } + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Platform Device Driver + */ + +static int xvip_composite_probe(struct platform_device *pdev) +{ + struct xvip_composite_device *xdev; + int ret; + + xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); + if (!xdev) + return -ENOMEM; + + xdev->dev = &pdev->dev; + INIT_LIST_HEAD(&xdev->entities); + INIT_LIST_HEAD(&xdev->dmas); + + ret = xvip_composite_v4l2_init(xdev); + if (ret < 0) + return ret; + + ret = xvip_graph_init(xdev); + if (ret < 0) + goto error; + + platform_set_drvdata(pdev, xdev); + + dev_info(xdev->dev, "device registered\n"); + + return 0; + +error: + xvip_composite_v4l2_cleanup(xdev); + return ret; +} + +static int xvip_composite_remove(struct platform_device *pdev) +{ + struct xvip_composite_device *xdev = platform_get_drvdata(pdev); + + xvip_graph_cleanup(xdev); + xvip_composite_v4l2_cleanup(xdev); + + return 0; +} + +static const struct of_device_id xvip_composite_of_id_table[] = { + { .compatible = "xlnx,video" }, + { } +}; +MODULE_DEVICE_TABLE(of, xvip_composite_of_id_table); + +static struct platform_driver xvip_composite_driver = { + .driver = { + .name = "xilinx-video", + .of_match_table = xvip_composite_of_id_table, + }, + .probe = xvip_composite_probe, + .remove = xvip_composite_remove, +}; + +module_platform_driver(xvip_composite_driver); + +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_DESCRIPTION("Xilinx Video IP Composite Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/xilinx/xilinx-vipp.h b/drivers/media/platform/xilinx/xilinx-vipp.h new file mode 100644 index 000000000000..faf6b6e80b3b --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vipp.h @@ -0,0 +1,49 @@ +/* + * Xilinx Video IP Composite Device + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon + * Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __XILINX_VIPP_H__ +#define __XILINX_VIPP_H__ + +#include +#include +#include +#include +#include +#include + +/** + * struct xvip_composite_device - Xilinx Video IP device structure + * @v4l2_dev: V4L2 device + * @media_dev: media device + * @dev: (OF) device + * @notifier: V4L2 asynchronous subdevs notifier + * @entities: entities in the graph as a list of xvip_graph_entity + * @num_subdevs: number of subdevs in the pipeline + * @dmas: list of DMA channels at the pipeline output and input + * @v4l2_caps: V4L2 capabilities of the whole device (see VIDIOC_QUERYCAP) + */ +struct xvip_composite_device { + struct v4l2_device v4l2_dev; + struct media_device media_dev; + struct device *dev; + + struct v4l2_async_notifier notifier; + struct list_head entities; + unsigned int num_subdevs; + + struct list_head dmas; + u32 v4l2_caps; +}; + +#endif /* __XILINX_VIPP_H__ */ diff --git a/include/dt-bindings/media/xilinx-vip.h b/include/dt-bindings/media/xilinx-vip.h new file mode 100644 index 000000000000..6298fec00685 --- /dev/null +++ b/include/dt-bindings/media/xilinx-vip.h @@ -0,0 +1,39 @@ +/* + * Xilinx Video IP Core + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon + * Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DT_BINDINGS_MEDIA_XILINX_VIP_H__ +#define __DT_BINDINGS_MEDIA_XILINX_VIP_H__ + +/* + * Video format codes as defined in "AXI4-Stream Video IP and System Design + * Guide". + */ +#define XVIP_VF_YUV_422 0 +#define XVIP_VF_YUV_444 1 +#define XVIP_VF_RBG 2 +#define XVIP_VF_YUV_420 3 +#define XVIP_VF_YUVA_422 4 +#define XVIP_VF_YUVA_444 5 +#define XVIP_VF_RGBA 6 +#define XVIP_VF_YUVA_420 7 +#define XVIP_VF_YUVD_422 8 +#define XVIP_VF_YUVD_444 9 +#define XVIP_VF_RGBD 10 +#define XVIP_VF_YUVD_420 11 +#define XVIP_VF_MONO_SENSOR 12 +#define XVIP_VF_CUSTOM2 13 +#define XVIP_VF_CUSTOM3 14 +#define XVIP_VF_CUSTOM4 15 + +#endif /* __DT_BINDINGS_MEDIA_XILINX_VIP_H__ */ -- cgit v1.2.3 From a5562f65b1371a0988b707c10c44fcc2bba56990 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 15 May 2013 11:36:56 -0300 Subject: [media] v4l: xilinx: Add Test Pattern Generator driver The TPG generates multiple static or dynamic test patterns. The driver currently hardcodes the pattern to the moving box pattern. Signed-off-by: Christian Kohn Signed-off-by: Hyun Kwon Signed-off-by: Laurent Pinchart Signed-off-by: Michal Simek Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/xilinx/xlnx,v-tpg.txt | 71 ++ MAINTAINERS | 1 + drivers/media/platform/xilinx/Kconfig | 7 + drivers/media/platform/xilinx/Makefile | 1 + drivers/media/platform/xilinx/xilinx-tpg.c | 931 +++++++++++++++++++++ include/uapi/linux/Kbuild | 1 + include/uapi/linux/xilinx-v4l2-controls.h | 73 ++ 7 files changed, 1085 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/xilinx/xlnx,v-tpg.txt create mode 100644 drivers/media/platform/xilinx/xilinx-tpg.c create mode 100644 include/uapi/linux/xilinx-v4l2-controls.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/media/xilinx/xlnx,v-tpg.txt b/Documentation/devicetree/bindings/media/xilinx/xlnx,v-tpg.txt new file mode 100644 index 000000000000..9dd86b3db937 --- /dev/null +++ b/Documentation/devicetree/bindings/media/xilinx/xlnx,v-tpg.txt @@ -0,0 +1,71 @@ +Xilinx Video Test Pattern Generator (TPG) +----------------------------------------- + +Required properties: + +- compatible: Must contain at least one of + + "xlnx,v-tpg-5.0" (TPG version 5.0) + "xlnx,v-tpg-6.0" (TPG version 6.0) + + TPG versions backward-compatible with previous versions should list all + compatible versions in the newer to older order. + +- reg: Physical base address and length of the registers set for the device. + +- clocks: Reference to the video core clock. + +- xlnx,video-format, xlnx,video-width: Video format and width, as defined in + video.txt. + +- port: Video port, using the DT bindings defined in ../video-interfaces.txt. + The TPG has a single output port numbered 0. + +Optional properties: + +- xlnx,vtc: A phandle referencing the Video Timing Controller that generates + video timings for the TPG test patterns. + +- timing-gpios: Specifier for a GPIO that controls the timing mux at the TPG + input. The GPIO active level corresponds to the selection of VTC-generated + video timings. + +The xlnx,vtc and timing-gpios properties are mandatory when the TPG is +synthesized with two ports and forbidden when synthesized with one port. + +Example: + + tpg_0: tpg@40050000 { + compatible = "xlnx,v-tpg-6.0", "xlnx,v-tpg-5.0"; + reg = <0x40050000 0x10000>; + clocks = <&clkc 15>; + + xlnx,vtc = <&vtc_3>; + timing-gpios = <&ps7_gpio_0 55 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + xlnx,video-format = ; + xlnx,video-width = <8>; + + tpg_in: endpoint { + remote-endpoint = <&adv7611_out>; + }; + }; + port@1 { + reg = <1>; + + xlnx,video-format = ; + xlnx,video-width = <8>; + + tpg1_out: endpoint { + remote-endpoint = <&switch_in0>; + }; + }: + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index ca3b2638fcc6..30e7e38ccad0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10826,6 +10826,7 @@ T: git git://linuxtv.org/media_tree.git S: Supported F: Documentation/devicetree/bindings/media/xilinx/ F: drivers/media/platform/xilinx/ +F: include/uapi/linux/xilinx-v4l2-controls.h XILLYBUS DRIVER M: Eli Billauer diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig index 19db82343bb8..d7324c726fc2 100644 --- a/drivers/media/platform/xilinx/Kconfig +++ b/drivers/media/platform/xilinx/Kconfig @@ -7,6 +7,13 @@ config VIDEO_XILINX if VIDEO_XILINX +config VIDEO_XILINX_TPG + tristate "Xilinx Video Test Pattern Generator" + depends on VIDEO_XILINX + select VIDEO_XILINX_VTC + ---help--- + Driver for the Xilinx Video Test Pattern Generator + config VIDEO_XILINX_VTC tristate "Xilinx Video Timing Controller" depends on VIDEO_XILINX diff --git a/drivers/media/platform/xilinx/Makefile b/drivers/media/platform/xilinx/Makefile index 6611e3228e3c..e8a0f2a9f733 100644 --- a/drivers/media/platform/xilinx/Makefile +++ b/drivers/media/platform/xilinx/Makefile @@ -1,4 +1,5 @@ xilinx-video-objs += xilinx-dma.o xilinx-vip.o xilinx-vipp.o obj-$(CONFIG_VIDEO_XILINX) += xilinx-video.o +obj-$(CONFIG_VIDEO_XILINX_TPG) += xilinx-tpg.o obj-$(CONFIG_VIDEO_XILINX_VTC) += xilinx-vtc.o diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c new file mode 100644 index 000000000000..b5f7d5ecb7f6 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-tpg.c @@ -0,0 +1,931 @@ +/* + * Xilinx Test Pattern Generator + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon + * Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "xilinx-vip.h" +#include "xilinx-vtc.h" + +#define XTPG_CTRL_STATUS_SLAVE_ERROR (1 << 16) +#define XTPG_CTRL_IRQ_SLAVE_ERROR (1 << 16) + +#define XTPG_PATTERN_CONTROL 0x0100 +#define XTPG_PATTERN_MASK (0xf << 0) +#define XTPG_PATTERN_CONTROL_CROSS_HAIRS (1 << 4) +#define XTPG_PATTERN_CONTROL_MOVING_BOX (1 << 5) +#define XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT 6 +#define XTPG_PATTERN_CONTROL_COLOR_MASK_MASK (0xf << 6) +#define XTPG_PATTERN_CONTROL_STUCK_PIXEL (1 << 9) +#define XTPG_PATTERN_CONTROL_NOISE (1 << 10) +#define XTPG_PATTERN_CONTROL_MOTION (1 << 12) +#define XTPG_MOTION_SPEED 0x0104 +#define XTPG_CROSS_HAIRS 0x0108 +#define XTPG_CROSS_HAIRS_ROW_SHIFT 0 +#define XTPG_CROSS_HAIRS_ROW_MASK (0xfff << 0) +#define XTPG_CROSS_HAIRS_COLUMN_SHIFT 16 +#define XTPG_CROSS_HAIRS_COLUMN_MASK (0xfff << 16) +#define XTPG_ZPLATE_HOR_CONTROL 0x010c +#define XTPG_ZPLATE_VER_CONTROL 0x0110 +#define XTPG_ZPLATE_START_SHIFT 0 +#define XTPG_ZPLATE_START_MASK (0xffff << 0) +#define XTPG_ZPLATE_SPEED_SHIFT 16 +#define XTPG_ZPLATE_SPEED_MASK (0xffff << 16) +#define XTPG_BOX_SIZE 0x0114 +#define XTPG_BOX_COLOR 0x0118 +#define XTPG_STUCK_PIXEL_THRESH 0x011c +#define XTPG_NOISE_GAIN 0x0120 +#define XTPG_BAYER_PHASE 0x0124 +#define XTPG_BAYER_PHASE_RGGB 0 +#define XTPG_BAYER_PHASE_GRBG 1 +#define XTPG_BAYER_PHASE_GBRG 2 +#define XTPG_BAYER_PHASE_BGGR 3 +#define XTPG_BAYER_PHASE_OFF 4 + +/* + * The minimum blanking value is one clock cycle for the front porch, one clock + * cycle for the sync pulse and one clock cycle for the back porch. + */ +#define XTPG_MIN_HBLANK 3 +#define XTPG_MAX_HBLANK (XVTC_MAX_HSIZE - XVIP_MIN_WIDTH) +#define XTPG_MIN_VBLANK 3 +#define XTPG_MAX_VBLANK (XVTC_MAX_VSIZE - XVIP_MIN_HEIGHT) + +/** + * struct xtpg_device - Xilinx Test Pattern Generator device structure + * @xvip: Xilinx Video IP device + * @pads: media pads + * @npads: number of pads (1 or 2) + * @has_input: whether an input is connected to the sink pad + * @formats: active V4L2 media bus format for each pad + * @default_format: default V4L2 media bus format + * @vip_format: format information corresponding to the active format + * @bayer: boolean flag if TPG is set to any bayer format + * @ctrl_handler: control handler + * @hblank: horizontal blanking control + * @vblank: vertical blanking control + * @pattern: test pattern control + * @streaming: is the video stream active + * @vtc: video timing controller + * @vtmux_gpio: video timing mux GPIO + */ +struct xtpg_device { + struct xvip_device xvip; + + struct media_pad pads[2]; + unsigned int npads; + bool has_input; + + struct v4l2_mbus_framefmt formats[2]; + struct v4l2_mbus_framefmt default_format; + const struct xvip_video_format *vip_format; + bool bayer; + + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *pattern; + bool streaming; + + struct xvtc_device *vtc; + struct gpio_desc *vtmux_gpio; +}; + +static inline struct xtpg_device *to_tpg(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct xtpg_device, xvip.subdev); +} + +static u32 xtpg_get_bayer_phase(unsigned int code) +{ + switch (code) { + case MEDIA_BUS_FMT_SRGGB8_1X8: + return XTPG_BAYER_PHASE_RGGB; + case MEDIA_BUS_FMT_SGRBG8_1X8: + return XTPG_BAYER_PHASE_GRBG; + case MEDIA_BUS_FMT_SGBRG8_1X8: + return XTPG_BAYER_PHASE_GBRG; + case MEDIA_BUS_FMT_SBGGR8_1X8: + return XTPG_BAYER_PHASE_BGGR; + default: + return XTPG_BAYER_PHASE_OFF; + } +} + +static void __xtpg_update_pattern_control(struct xtpg_device *xtpg, + bool passthrough, bool pattern) +{ + u32 pattern_mask = (1 << (xtpg->pattern->maximum + 1)) - 1; + + /* + * If the TPG has no sink pad or no input connected to its sink pad + * passthrough mode can't be enabled. + */ + if (xtpg->npads == 1 || !xtpg->has_input) + passthrough = false; + + /* If passthrough mode is allowed unmask bit 0. */ + if (passthrough) + pattern_mask &= ~1; + + /* If test pattern mode is allowed unmask all other bits. */ + if (pattern) + pattern_mask &= 1; + + __v4l2_ctrl_modify_range(xtpg->pattern, 0, xtpg->pattern->maximum, + pattern_mask, pattern ? 9 : 0); +} + +static void xtpg_update_pattern_control(struct xtpg_device *xtpg, + bool passthrough, bool pattern) +{ + mutex_lock(xtpg->ctrl_handler.lock); + __xtpg_update_pattern_control(xtpg, passthrough, pattern); + mutex_unlock(xtpg->ctrl_handler.lock); +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Video Operations + */ + +static int xtpg_s_stream(struct v4l2_subdev *subdev, int enable) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + unsigned int width = xtpg->formats[0].width; + unsigned int height = xtpg->formats[0].height; + bool passthrough; + u32 bayer_phase; + + if (!enable) { + xvip_stop(&xtpg->xvip); + if (xtpg->vtc) + xvtc_generator_stop(xtpg->vtc); + + xtpg_update_pattern_control(xtpg, true, true); + xtpg->streaming = false; + return 0; + } + + xvip_set_frame_size(&xtpg->xvip, &xtpg->formats[0]); + + if (xtpg->vtc) { + struct xvtc_config config = { + .hblank_start = width, + .hsync_start = width + 1, + .vblank_start = height, + .vsync_start = height + 1, + }; + unsigned int htotal; + unsigned int vtotal; + + htotal = min_t(unsigned int, XVTC_MAX_HSIZE, + v4l2_ctrl_g_ctrl(xtpg->hblank) + width); + vtotal = min_t(unsigned int, XVTC_MAX_VSIZE, + v4l2_ctrl_g_ctrl(xtpg->vblank) + height); + + config.hsync_end = htotal - 1; + config.hsize = htotal; + config.vsync_end = vtotal - 1; + config.vsize = vtotal; + + xvtc_generator_start(xtpg->vtc, &config); + } + + /* + * Configure the bayer phase and video timing mux based on the + * operation mode (passthrough or test pattern generation). The test + * pattern can be modified by the control set handler, we thus need to + * take the control lock here to avoid races. + */ + mutex_lock(xtpg->ctrl_handler.lock); + + xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_MASK, xtpg->pattern->cur.val); + + /* + * Switching between passthrough and test pattern generation modes isn't + * allowed during streaming, update the control range accordingly. + */ + passthrough = xtpg->pattern->cur.val == 0; + __xtpg_update_pattern_control(xtpg, passthrough, !passthrough); + + xtpg->streaming = true; + + mutex_unlock(xtpg->ctrl_handler.lock); + + /* + * For TPG v5.0, the bayer phase needs to be off for the pass through + * mode, otherwise the external input would be subsampled. + */ + bayer_phase = passthrough ? XTPG_BAYER_PHASE_OFF + : xtpg_get_bayer_phase(xtpg->formats[0].code); + xvip_write(&xtpg->xvip, XTPG_BAYER_PHASE, bayer_phase); + + if (xtpg->vtmux_gpio) + gpiod_set_value_cansleep(xtpg->vtmux_gpio, !passthrough); + + xvip_start(&xtpg->xvip); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Pad Operations + */ + +static struct v4l2_mbus_framefmt * +__xtpg_get_pad_format(struct xtpg_device *xtpg, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, u32 which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_format(&xtpg->xvip.subdev, cfg, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &xtpg->formats[pad]; + default: + return NULL; + } +} + +static int xtpg_get_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + + fmt->format = *__xtpg_get_pad_format(xtpg, cfg, fmt->pad, fmt->which); + + return 0; +} + +static int xtpg_set_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + struct v4l2_mbus_framefmt *__format; + u32 bayer_phase; + + __format = __xtpg_get_pad_format(xtpg, cfg, fmt->pad, fmt->which); + + /* In two pads mode the source pad format is always identical to the + * sink pad format. + */ + if (xtpg->npads == 2 && fmt->pad == 1) { + fmt->format = *__format; + return 0; + } + + /* Bayer phase is configurable at runtime */ + if (xtpg->bayer) { + bayer_phase = xtpg_get_bayer_phase(fmt->format.code); + if (bayer_phase != XTPG_BAYER_PHASE_OFF) + __format->code = fmt->format.code; + } + + xvip_set_format_size(__format, fmt); + + fmt->format = *__format; + + /* Propagate the format to the source pad. */ + if (xtpg->npads == 2) { + __format = __xtpg_get_pad_format(xtpg, cfg, 1, fmt->which); + *__format = fmt->format; + } + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Operations + */ + +static int xtpg_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad); + + if (fse->index || fse->code != format->code) + return -EINVAL; + + /* Min / max values for pad 0 is always fixed in both one and two pads + * modes. In two pads mode, the source pad(= 1) size is identical to + * the sink pad size */ + if (fse->pad == 0) { + fse->min_width = XVIP_MIN_WIDTH; + fse->max_width = XVIP_MAX_WIDTH; + fse->min_height = XVIP_MIN_HEIGHT; + fse->max_height = XVIP_MAX_HEIGHT; + } else { + fse->min_width = format->width; + fse->max_width = format->width; + fse->min_height = format->height; + fse->max_height = format->height; + } + + return 0; +} + +static int xtpg_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_try_format(subdev, fh->pad, 0); + *format = xtpg->default_format; + + if (xtpg->npads == 2) { + format = v4l2_subdev_get_try_format(subdev, fh->pad, 1); + *format = xtpg->default_format; + } + + return 0; +} + +static int xtpg_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) +{ + return 0; +} + +static int xtpg_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct xtpg_device *xtpg = container_of(ctrl->handler, + struct xtpg_device, + ctrl_handler); + switch (ctrl->id) { + case V4L2_CID_TEST_PATTERN: + xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_MASK, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_CROSS_HAIRS: + xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_CONTROL_CROSS_HAIRS, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_MOVING_BOX: + xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_CONTROL_MOVING_BOX, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_COLOR_MASK: + xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_CONTROL_COLOR_MASK_MASK, + ctrl->val << + XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_STUCK_PIXEL: + xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_CONTROL_STUCK_PIXEL, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_NOISE: + xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_CONTROL_NOISE, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_MOTION: + xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_CONTROL_MOTION, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_MOTION_SPEED: + xvip_write(&xtpg->xvip, XTPG_MOTION_SPEED, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW: + xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS, + XTPG_CROSS_HAIRS_ROW_MASK, + ctrl->val << XTPG_CROSS_HAIRS_ROW_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN: + xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS, + XTPG_CROSS_HAIRS_COLUMN_MASK, + ctrl->val << XTPG_CROSS_HAIRS_COLUMN_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_ZPLATE_HOR_START: + xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL, + XTPG_ZPLATE_START_MASK, + ctrl->val << XTPG_ZPLATE_START_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED: + xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL, + XTPG_ZPLATE_SPEED_MASK, + ctrl->val << XTPG_ZPLATE_SPEED_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_ZPLATE_VER_START: + xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL, + XTPG_ZPLATE_START_MASK, + ctrl->val << XTPG_ZPLATE_START_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED: + xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL, + XTPG_ZPLATE_SPEED_MASK, + ctrl->val << XTPG_ZPLATE_SPEED_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_BOX_SIZE: + xvip_write(&xtpg->xvip, XTPG_BOX_SIZE, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_BOX_COLOR: + xvip_write(&xtpg->xvip, XTPG_BOX_COLOR, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH: + xvip_write(&xtpg->xvip, XTPG_STUCK_PIXEL_THRESH, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_NOISE_GAIN: + xvip_write(&xtpg->xvip, XTPG_NOISE_GAIN, ctrl->val); + return 0; + } + + return 0; +} + +static const struct v4l2_ctrl_ops xtpg_ctrl_ops = { + .s_ctrl = xtpg_s_ctrl, +}; + +static struct v4l2_subdev_core_ops xtpg_core_ops = { +}; + +static struct v4l2_subdev_video_ops xtpg_video_ops = { + .s_stream = xtpg_s_stream, +}; + +static struct v4l2_subdev_pad_ops xtpg_pad_ops = { + .enum_mbus_code = xvip_enum_mbus_code, + .enum_frame_size = xtpg_enum_frame_size, + .get_fmt = xtpg_get_format, + .set_fmt = xtpg_set_format, +}; + +static struct v4l2_subdev_ops xtpg_ops = { + .core = &xtpg_core_ops, + .video = &xtpg_video_ops, + .pad = &xtpg_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops xtpg_internal_ops = { + .open = xtpg_open, + .close = xtpg_close, +}; + +/* + * Control Config + */ + +static const char *const xtpg_pattern_strings[] = { + "Passthrough", + "Horizontal Ramp", + "Vertical Ramp", + "Temporal Ramp", + "Solid Red", + "Solid Green", + "Solid Blue", + "Solid Black", + "Solid White", + "Color Bars", + "Zone Plate", + "Tartan Color Bars", + "Cross Hatch", + "None", + "Vertical/Horizontal Ramps", + "Black/White Checker Board", +}; + +static struct v4l2_ctrl_config xtpg_ctrls[] = { + { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_CROSS_HAIRS, + .name = "Test Pattern: Cross Hairs", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = false, + .max = true, + .step = 1, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_MOVING_BOX, + .name = "Test Pattern: Moving Box", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = false, + .max = true, + .step = 1, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_COLOR_MASK, + .name = "Test Pattern: Color Mask", + .type = V4L2_CTRL_TYPE_BITMASK, + .min = 0, + .max = 0xf, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_STUCK_PIXEL, + .name = "Test Pattern: Stuck Pixel", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = false, + .max = true, + .step = 1, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_NOISE, + .name = "Test Pattern: Noise", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = false, + .max = true, + .step = 1, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_MOTION, + .name = "Test Pattern: Motion", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = false, + .max = true, + .step = 1, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_MOTION_SPEED, + .name = "Test Pattern: Motion Speed", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 8) - 1, + .step = 1, + .def = 4, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW, + .name = "Test Pattern: Cross Hairs Row", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 12) - 1, + .step = 1, + .def = 0x64, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN, + .name = "Test Pattern: Cross Hairs Column", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 12) - 1, + .step = 1, + .def = 0x64, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_ZPLATE_HOR_START, + .name = "Test Pattern: Zplate Horizontal Start Pos", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 16) - 1, + .step = 1, + .def = 0x1e, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED, + .name = "Test Pattern: Zplate Horizontal Speed", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 16) - 1, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_ZPLATE_VER_START, + .name = "Test Pattern: Zplate Vertical Start Pos", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 16) - 1, + .step = 1, + .def = 1, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED, + .name = "Test Pattern: Zplate Vertical Speed", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 16) - 1, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_BOX_SIZE, + .name = "Test Pattern: Box Size", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 12) - 1, + .step = 1, + .def = 0x32, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_BOX_COLOR, + .name = "Test Pattern: Box Color(RGB)", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 24) - 1, + .step = 1, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH, + .name = "Test Pattern: Stuck Pixel threshold", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 16) - 1, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_NOISE_GAIN, + .name = "Test Pattern: Noise Gain", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 8) - 1, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, +}; + +/* ----------------------------------------------------------------------------- + * Media Operations + */ + +static const struct media_entity_operations xtpg_media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* ----------------------------------------------------------------------------- + * Power Management + */ + +static int __maybe_unused xtpg_pm_suspend(struct device *dev) +{ + struct xtpg_device *xtpg = dev_get_drvdata(dev); + + xvip_suspend(&xtpg->xvip); + + return 0; +} + +static int __maybe_unused xtpg_pm_resume(struct device *dev) +{ + struct xtpg_device *xtpg = dev_get_drvdata(dev); + + xvip_resume(&xtpg->xvip); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Platform Device Driver + */ + +static int xtpg_parse_of(struct xtpg_device *xtpg) +{ + struct device *dev = xtpg->xvip.dev; + struct device_node *node = xtpg->xvip.dev->of_node; + struct device_node *ports; + struct device_node *port; + unsigned int nports = 0; + bool has_endpoint = false; + + ports = of_get_child_by_name(node, "ports"); + if (ports == NULL) + ports = node; + + for_each_child_of_node(ports, port) { + const struct xvip_video_format *format; + struct device_node *endpoint; + + if (!port->name || of_node_cmp(port->name, "port")) + continue; + + format = xvip_of_get_format(port); + if (IS_ERR(format)) { + dev_err(dev, "invalid format in DT"); + return PTR_ERR(format); + } + + /* Get and check the format description */ + if (!xtpg->vip_format) { + xtpg->vip_format = format; + } else if (xtpg->vip_format != format) { + dev_err(dev, "in/out format mismatch in DT"); + return -EINVAL; + } + + if (nports == 0) { + endpoint = of_get_next_child(port, NULL); + if (endpoint) + has_endpoint = true; + of_node_put(endpoint); + } + + /* Count the number of ports. */ + nports++; + } + + if (nports != 1 && nports != 2) { + dev_err(dev, "invalid number of ports %u\n", nports); + return -EINVAL; + } + + xtpg->npads = nports; + if (nports == 2 && has_endpoint) + xtpg->has_input = true; + + return 0; +} + +static int xtpg_probe(struct platform_device *pdev) +{ + struct v4l2_subdev *subdev; + struct xtpg_device *xtpg; + u32 i, bayer_phase; + int ret; + + xtpg = devm_kzalloc(&pdev->dev, sizeof(*xtpg), GFP_KERNEL); + if (!xtpg) + return -ENOMEM; + + xtpg->xvip.dev = &pdev->dev; + + ret = xtpg_parse_of(xtpg); + if (ret < 0) + return ret; + + ret = xvip_init_resources(&xtpg->xvip); + if (ret < 0) + return ret; + + xtpg->vtmux_gpio = devm_gpiod_get_optional(&pdev->dev, "timing", + GPIOD_OUT_HIGH); + if (IS_ERR(xtpg->vtmux_gpio)) { + ret = PTR_ERR(xtpg->vtmux_gpio); + goto error_resource; + } + + xtpg->vtc = xvtc_of_get(pdev->dev.of_node); + if (IS_ERR(xtpg->vtc)) { + ret = PTR_ERR(xtpg->vtc); + goto error_resource; + } + + /* Reset and initialize the core */ + xvip_reset(&xtpg->xvip); + + /* Initialize V4L2 subdevice and media entity. Pad numbers depend on the + * number of pads. + */ + if (xtpg->npads == 2) { + xtpg->pads[0].flags = MEDIA_PAD_FL_SINK; + xtpg->pads[1].flags = MEDIA_PAD_FL_SOURCE; + } else { + xtpg->pads[0].flags = MEDIA_PAD_FL_SOURCE; + } + + /* Initialize the default format */ + xtpg->default_format.code = xtpg->vip_format->code; + xtpg->default_format.field = V4L2_FIELD_NONE; + xtpg->default_format.colorspace = V4L2_COLORSPACE_SRGB; + xvip_get_frame_size(&xtpg->xvip, &xtpg->default_format); + + bayer_phase = xtpg_get_bayer_phase(xtpg->vip_format->code); + if (bayer_phase != XTPG_BAYER_PHASE_OFF) + xtpg->bayer = true; + + xtpg->formats[0] = xtpg->default_format; + if (xtpg->npads == 2) + xtpg->formats[1] = xtpg->default_format; + + /* Initialize V4L2 subdevice and media entity */ + subdev = &xtpg->xvip.subdev; + v4l2_subdev_init(subdev, &xtpg_ops); + subdev->dev = &pdev->dev; + subdev->internal_ops = &xtpg_internal_ops; + strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name)); + v4l2_set_subdevdata(subdev, xtpg); + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + subdev->entity.ops = &xtpg_media_ops; + + ret = media_entity_init(&subdev->entity, xtpg->npads, xtpg->pads, 0); + if (ret < 0) + goto error; + + v4l2_ctrl_handler_init(&xtpg->ctrl_handler, 3 + ARRAY_SIZE(xtpg_ctrls)); + + xtpg->vblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops, + V4L2_CID_VBLANK, XTPG_MIN_VBLANK, + XTPG_MAX_VBLANK, 1, 100); + xtpg->hblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops, + V4L2_CID_HBLANK, XTPG_MIN_HBLANK, + XTPG_MAX_HBLANK, 1, 100); + xtpg->pattern = v4l2_ctrl_new_std_menu_items(&xtpg->ctrl_handler, + &xtpg_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(xtpg_pattern_strings) - 1, + 1, 9, xtpg_pattern_strings); + + for (i = 0; i < ARRAY_SIZE(xtpg_ctrls); i++) + v4l2_ctrl_new_custom(&xtpg->ctrl_handler, &xtpg_ctrls[i], NULL); + + if (xtpg->ctrl_handler.error) { + dev_err(&pdev->dev, "failed to add controls\n"); + ret = xtpg->ctrl_handler.error; + goto error; + } + subdev->ctrl_handler = &xtpg->ctrl_handler; + + xtpg_update_pattern_control(xtpg, true, true); + + ret = v4l2_ctrl_handler_setup(&xtpg->ctrl_handler); + if (ret < 0) { + dev_err(&pdev->dev, "failed to set controls\n"); + goto error; + } + + platform_set_drvdata(pdev, xtpg); + + xvip_print_version(&xtpg->xvip); + + ret = v4l2_async_register_subdev(subdev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to register subdev\n"); + goto error; + } + + return 0; + +error: + v4l2_ctrl_handler_free(&xtpg->ctrl_handler); + media_entity_cleanup(&subdev->entity); + xvtc_put(xtpg->vtc); +error_resource: + xvip_cleanup_resources(&xtpg->xvip); + return ret; +} + +static int xtpg_remove(struct platform_device *pdev) +{ + struct xtpg_device *xtpg = platform_get_drvdata(pdev); + struct v4l2_subdev *subdev = &xtpg->xvip.subdev; + + v4l2_async_unregister_subdev(subdev); + v4l2_ctrl_handler_free(&xtpg->ctrl_handler); + media_entity_cleanup(&subdev->entity); + + xvip_cleanup_resources(&xtpg->xvip); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(xtpg_pm_ops, xtpg_pm_suspend, xtpg_pm_resume); + +static const struct of_device_id xtpg_of_id_table[] = { + { .compatible = "xlnx,v-tpg-5.0" }, + { } +}; +MODULE_DEVICE_TABLE(of, xtpg_of_id_table); + +static struct platform_driver xtpg_driver = { + .driver = { + .name = "xilinx-tpg", + .pm = &xtpg_pm_ops, + .of_match_table = xtpg_of_id_table, + }, + .probe = xtpg_probe, + .remove = xtpg_remove, +}; + +module_platform_driver(xtpg_driver); + +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_DESCRIPTION("Xilinx Test Pattern Generator Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 68ceb97c458c..d4cfc17cc414 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -446,5 +446,6 @@ header-y += wireless.h header-y += x25.h header-y += xattr.h header-y += xfrm.h +header-y += xilinx-v4l2-controls.h header-y += zorro.h header-y += zorro_ids.h diff --git a/include/uapi/linux/xilinx-v4l2-controls.h b/include/uapi/linux/xilinx-v4l2-controls.h new file mode 100644 index 000000000000..fb495b91e800 --- /dev/null +++ b/include/uapi/linux/xilinx-v4l2-controls.h @@ -0,0 +1,73 @@ +/* + * Xilinx Controls Header + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon + * Laurent Pinchart + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __UAPI_XILINX_V4L2_CONTROLS_H__ +#define __UAPI_XILINX_V4L2_CONTROLS_H__ + +#include + +#define V4L2_CID_XILINX_OFFSET 0xc000 +#define V4L2_CID_XILINX_BASE (V4L2_CID_USER_BASE + V4L2_CID_XILINX_OFFSET) + +/* + * Private Controls for Xilinx Video IPs + */ + +/* + * Xilinx TPG Video IP + */ + +#define V4L2_CID_XILINX_TPG (V4L2_CID_USER_BASE + 0xc000) + +/* Draw cross hairs */ +#define V4L2_CID_XILINX_TPG_CROSS_HAIRS (V4L2_CID_XILINX_TPG + 1) +/* Enable a moving box */ +#define V4L2_CID_XILINX_TPG_MOVING_BOX (V4L2_CID_XILINX_TPG + 2) +/* Mask out a color component */ +#define V4L2_CID_XILINX_TPG_COLOR_MASK (V4L2_CID_XILINX_TPG + 3) +/* Enable a stuck pixel feature */ +#define V4L2_CID_XILINX_TPG_STUCK_PIXEL (V4L2_CID_XILINX_TPG + 4) +/* Enable a noisy output */ +#define V4L2_CID_XILINX_TPG_NOISE (V4L2_CID_XILINX_TPG + 5) +/* Enable the motion feature */ +#define V4L2_CID_XILINX_TPG_MOTION (V4L2_CID_XILINX_TPG + 6) +/* Configure the motion speed of moving patterns */ +#define V4L2_CID_XILINX_TPG_MOTION_SPEED (V4L2_CID_XILINX_TPG + 7) +/* The row of horizontal cross hair location */ +#define V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW (V4L2_CID_XILINX_TPG + 8) +/* The colum of vertical cross hair location */ +#define V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN (V4L2_CID_XILINX_TPG + 9) +/* Set starting point of sine wave for horizontal component */ +#define V4L2_CID_XILINX_TPG_ZPLATE_HOR_START (V4L2_CID_XILINX_TPG + 10) +/* Set speed of the horizontal component */ +#define V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED (V4L2_CID_XILINX_TPG + 11) +/* Set starting point of sine wave for vertical component */ +#define V4L2_CID_XILINX_TPG_ZPLATE_VER_START (V4L2_CID_XILINX_TPG + 12) +/* Set speed of the vertical component */ +#define V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED (V4L2_CID_XILINX_TPG + 13) +/* Moving box size */ +#define V4L2_CID_XILINX_TPG_BOX_SIZE (V4L2_CID_XILINX_TPG + 14) +/* Moving box color */ +#define V4L2_CID_XILINX_TPG_BOX_COLOR (V4L2_CID_XILINX_TPG + 15) +/* Upper limit count of generated stuck pixels */ +#define V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH (V4L2_CID_XILINX_TPG + 16) +/* Noise level */ +#define V4L2_CID_XILINX_TPG_NOISE_GAIN (V4L2_CID_XILINX_TPG + 17) + +#endif /* __UAPI_XILINX_V4L2_CONTROLS_H__ */ -- cgit v1.2.3 From 9b3075c59f858d64478f46a15daa6ecda3cf2318 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 1 Apr 2015 01:37:05 -0700 Subject: nfsd: add NFSEXP_PNFS to the exflags array Signed-off-by: J. Bruce Fields --- fs/nfsd/export.c | 1 + include/uapi/linux/nfsd/export.h | 3 +++ 2 files changed, 4 insertions(+) (limited to 'include') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 2911f519fe64..900c3ae94adc 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -1158,6 +1158,7 @@ static struct flags { { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}}, { NFSEXP_V4ROOT, {"v4root", ""}}, + { NFSEXP_PNFS, {"pnfs", ""}}, { 0, {"", ""}} }; diff --git a/include/uapi/linux/nfsd/export.h b/include/uapi/linux/nfsd/export.h index d3bd6ffec041..0df7bd5d2fb1 100644 --- a/include/uapi/linux/nfsd/export.h +++ b/include/uapi/linux/nfsd/export.h @@ -21,6 +21,9 @@ /* * Export flags. + * + * Please update the expflags[] array in fs/nfsd/export.c when adding + * a new flag. */ #define NFSEXP_READONLY 0x0001 #define NFSEXP_INSECURE_PORT 0x0002 -- cgit v1.2.3 From aadc3780f31865edc84c587ab718a33a8eeeb09d Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Fri, 27 Mar 2015 09:10:10 -0700 Subject: hv: remove the per-channel workqueue It's not necessary any longer, since we can safely run the blocking message handlers in vmbus_connection.work_queue now. Signed-off-by: Dexuan Cui Cc: K. Y. Srinivasan Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 30 +----------------------------- include/linux/hyperv.h | 3 --- 2 files changed, 1 insertion(+), 32 deletions(-) (limited to 'include') diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index d69864d4a4d7..0eeb1b3bc048 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -147,43 +147,15 @@ static struct vmbus_channel *alloc_channel(void) INIT_LIST_HEAD(&channel->sc_list); INIT_LIST_HEAD(&channel->percpu_list); - channel->controlwq = alloc_workqueue("hv_vmbus_ctl/%d", WQ_MEM_RECLAIM, - 1, channel->id); - if (!channel->controlwq) { - kfree(channel); - return NULL; - } - return channel; } -/* - * release_hannel - Release the vmbus channel object itself - */ -static void release_channel(struct work_struct *work) -{ - struct vmbus_channel *channel = container_of(work, - struct vmbus_channel, - work); - - destroy_workqueue(channel->controlwq); - - kfree(channel); -} - /* * free_channel - Release the resources used by the vmbus channel object */ static void free_channel(struct vmbus_channel *channel) { - - /* - * We have to release the channel's workqueue/thread in the vmbus's - * workqueue/thread context - * ie we can't destroy ourselves. - */ - INIT_WORK(&channel->work, release_channel); - queue_work(vmbus_connection.work_queue, &channel->work); + kfree(channel); } static void percpu_channel_enq(void *arg) diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 80e444bfc9dc..902c37aef67e 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -653,8 +653,6 @@ struct vmbus_channel { struct hv_device *device_obj; - struct work_struct work; - enum vmbus_channel_state state; struct vmbus_channel_offer_channel offermsg; @@ -675,7 +673,6 @@ struct vmbus_channel { struct hv_ring_buffer_info outbound; /* send to parent */ struct hv_ring_buffer_info inbound; /* receive from parent */ spinlock_t inbound_lock; - struct workqueue_struct *controlwq; struct vmbus_close_msg close_msg; -- cgit v1.2.3 From 83bd147952ef5c8a99df27b8597ee21f2424348d Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Wed, 18 Mar 2015 16:08:21 +0200 Subject: dt-bindings: Add #defines for MSM8916 clocks and resets Add clocks/resets defines for the global clock controller found on Qualcomm MSM8916 SoCs. Signed-off-by: Georgi Djakov Signed-off-by: Kumar Gala Signed-off-by: Olof Johansson --- .../devicetree/bindings/clock/qcom,gcc.txt | 1 + include/dt-bindings/clock/qcom,gcc-msm8916.h | 156 +++++++++++++++++++++ include/dt-bindings/reset/qcom,gcc-msm8916.h | 108 ++++++++++++++ 3 files changed, 265 insertions(+) create mode 100644 include/dt-bindings/clock/qcom,gcc-msm8916.h create mode 100644 include/dt-bindings/reset/qcom,gcc-msm8916.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index aba3d254e037..54c23f34f194 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -8,6 +8,7 @@ Required properties : "qcom,gcc-apq8084" "qcom,gcc-ipq8064" "qcom,gcc-msm8660" + "qcom,gcc-msm8916" "qcom,gcc-msm8960" "qcom,gcc-msm8974" "qcom,gcc-msm8974pro" diff --git a/include/dt-bindings/clock/qcom,gcc-msm8916.h b/include/dt-bindings/clock/qcom,gcc-msm8916.h new file mode 100644 index 000000000000..e430f644dd6c --- /dev/null +++ b/include/dt-bindings/clock/qcom,gcc-msm8916.h @@ -0,0 +1,156 @@ +/* + * Copyright 2015 Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_CLK_MSM_GCC_8916_H +#define _DT_BINDINGS_CLK_MSM_GCC_8916_H + +#define GPLL0 0 +#define GPLL0_VOTE 1 +#define BIMC_PLL 2 +#define BIMC_PLL_VOTE 3 +#define GPLL1 4 +#define GPLL1_VOTE 5 +#define GPLL2 6 +#define GPLL2_VOTE 7 +#define PCNOC_BFDCD_CLK_SRC 8 +#define SYSTEM_NOC_BFDCD_CLK_SRC 9 +#define CAMSS_AHB_CLK_SRC 10 +#define APSS_AHB_CLK_SRC 11 +#define CSI0_CLK_SRC 12 +#define CSI1_CLK_SRC 13 +#define GFX3D_CLK_SRC 14 +#define VFE0_CLK_SRC 15 +#define BLSP1_QUP1_I2C_APPS_CLK_SRC 16 +#define BLSP1_QUP1_SPI_APPS_CLK_SRC 17 +#define BLSP1_QUP2_I2C_APPS_CLK_SRC 18 +#define BLSP1_QUP2_SPI_APPS_CLK_SRC 19 +#define BLSP1_QUP3_I2C_APPS_CLK_SRC 20 +#define BLSP1_QUP3_SPI_APPS_CLK_SRC 21 +#define BLSP1_QUP4_I2C_APPS_CLK_SRC 22 +#define BLSP1_QUP4_SPI_APPS_CLK_SRC 23 +#define BLSP1_QUP5_I2C_APPS_CLK_SRC 24 +#define BLSP1_QUP5_SPI_APPS_CLK_SRC 25 +#define BLSP1_QUP6_I2C_APPS_CLK_SRC 26 +#define BLSP1_QUP6_SPI_APPS_CLK_SRC 27 +#define BLSP1_UART1_APPS_CLK_SRC 28 +#define BLSP1_UART2_APPS_CLK_SRC 29 +#define CCI_CLK_SRC 30 +#define CAMSS_GP0_CLK_SRC 31 +#define CAMSS_GP1_CLK_SRC 32 +#define JPEG0_CLK_SRC 33 +#define MCLK0_CLK_SRC 34 +#define MCLK1_CLK_SRC 35 +#define CSI0PHYTIMER_CLK_SRC 36 +#define CSI1PHYTIMER_CLK_SRC 37 +#define CPP_CLK_SRC 38 +#define CRYPTO_CLK_SRC 39 +#define GP1_CLK_SRC 40 +#define GP2_CLK_SRC 41 +#define GP3_CLK_SRC 42 +#define BYTE0_CLK_SRC 43 +#define ESC0_CLK_SRC 44 +#define MDP_CLK_SRC 45 +#define PCLK0_CLK_SRC 46 +#define VSYNC_CLK_SRC 47 +#define PDM2_CLK_SRC 48 +#define SDCC1_APPS_CLK_SRC 49 +#define SDCC2_APPS_CLK_SRC 50 +#define APSS_TCU_CLK_SRC 51 +#define USB_HS_SYSTEM_CLK_SRC 52 +#define VCODEC0_CLK_SRC 53 +#define GCC_BLSP1_AHB_CLK 54 +#define GCC_BLSP1_SLEEP_CLK 55 +#define GCC_BLSP1_QUP1_I2C_APPS_CLK 56 +#define GCC_BLSP1_QUP1_SPI_APPS_CLK 57 +#define GCC_BLSP1_QUP2_I2C_APPS_CLK 58 +#define GCC_BLSP1_QUP2_SPI_APPS_CLK 59 +#define GCC_BLSP1_QUP3_I2C_APPS_CLK 60 +#define GCC_BLSP1_QUP3_SPI_APPS_CLK 61 +#define GCC_BLSP1_QUP4_I2C_APPS_CLK 62 +#define GCC_BLSP1_QUP4_SPI_APPS_CLK 63 +#define GCC_BLSP1_QUP5_I2C_APPS_CLK 64 +#define GCC_BLSP1_QUP5_SPI_APPS_CLK 65 +#define GCC_BLSP1_QUP6_I2C_APPS_CLK 66 +#define GCC_BLSP1_QUP6_SPI_APPS_CLK 67 +#define GCC_BLSP1_UART1_APPS_CLK 68 +#define GCC_BLSP1_UART2_APPS_CLK 69 +#define GCC_BOOT_ROM_AHB_CLK 70 +#define GCC_CAMSS_CCI_AHB_CLK 71 +#define GCC_CAMSS_CCI_CLK 72 +#define GCC_CAMSS_CSI0_AHB_CLK 73 +#define GCC_CAMSS_CSI0_CLK 74 +#define GCC_CAMSS_CSI0PHY_CLK 75 +#define GCC_CAMSS_CSI0PIX_CLK 76 +#define GCC_CAMSS_CSI0RDI_CLK 77 +#define GCC_CAMSS_CSI1_AHB_CLK 78 +#define GCC_CAMSS_CSI1_CLK 79 +#define GCC_CAMSS_CSI1PHY_CLK 80 +#define GCC_CAMSS_CSI1PIX_CLK 81 +#define GCC_CAMSS_CSI1RDI_CLK 82 +#define GCC_CAMSS_CSI_VFE0_CLK 83 +#define GCC_CAMSS_GP0_CLK 84 +#define GCC_CAMSS_GP1_CLK 85 +#define GCC_CAMSS_ISPIF_AHB_CLK 86 +#define GCC_CAMSS_JPEG0_CLK 87 +#define GCC_CAMSS_JPEG_AHB_CLK 88 +#define GCC_CAMSS_JPEG_AXI_CLK 89 +#define GCC_CAMSS_MCLK0_CLK 90 +#define GCC_CAMSS_MCLK1_CLK 91 +#define GCC_CAMSS_MICRO_AHB_CLK 92 +#define GCC_CAMSS_CSI0PHYTIMER_CLK 93 +#define GCC_CAMSS_CSI1PHYTIMER_CLK 94 +#define GCC_CAMSS_AHB_CLK 95 +#define GCC_CAMSS_TOP_AHB_CLK 96 +#define GCC_CAMSS_CPP_AHB_CLK 97 +#define GCC_CAMSS_CPP_CLK 98 +#define GCC_CAMSS_VFE0_CLK 99 +#define GCC_CAMSS_VFE_AHB_CLK 100 +#define GCC_CAMSS_VFE_AXI_CLK 101 +#define GCC_CRYPTO_AHB_CLK 102 +#define GCC_CRYPTO_AXI_CLK 103 +#define GCC_CRYPTO_CLK 104 +#define GCC_OXILI_GMEM_CLK 105 +#define GCC_GP1_CLK 106 +#define GCC_GP2_CLK 107 +#define GCC_GP3_CLK 108 +#define GCC_MDSS_AHB_CLK 109 +#define GCC_MDSS_AXI_CLK 110 +#define GCC_MDSS_BYTE0_CLK 111 +#define GCC_MDSS_ESC0_CLK 112 +#define GCC_MDSS_MDP_CLK 113 +#define GCC_MDSS_PCLK0_CLK 114 +#define GCC_MDSS_VSYNC_CLK 115 +#define GCC_MSS_CFG_AHB_CLK 116 +#define GCC_OXILI_AHB_CLK 117 +#define GCC_OXILI_GFX3D_CLK 118 +#define GCC_PDM2_CLK 119 +#define GCC_PDM_AHB_CLK 120 +#define GCC_PRNG_AHB_CLK 121 +#define GCC_SDCC1_AHB_CLK 122 +#define GCC_SDCC1_APPS_CLK 123 +#define GCC_SDCC2_AHB_CLK 124 +#define GCC_SDCC2_APPS_CLK 125 +#define GCC_GTCU_AHB_CLK 126 +#define GCC_JPEG_TBU_CLK 127 +#define GCC_MDP_TBU_CLK 128 +#define GCC_SMMU_CFG_CLK 129 +#define GCC_VENUS_TBU_CLK 130 +#define GCC_VFE_TBU_CLK 131 +#define GCC_USB2A_PHY_SLEEP_CLK 132 +#define GCC_USB_HS_AHB_CLK 133 +#define GCC_USB_HS_SYSTEM_CLK 134 +#define GCC_VENUS0_AHB_CLK 135 +#define GCC_VENUS0_AXI_CLK 136 +#define GCC_VENUS0_VCODEC0_CLK 137 + +#endif diff --git a/include/dt-bindings/reset/qcom,gcc-msm8916.h b/include/dt-bindings/reset/qcom,gcc-msm8916.h new file mode 100644 index 000000000000..3d90410f09c7 --- /dev/null +++ b/include/dt-bindings/reset/qcom,gcc-msm8916.h @@ -0,0 +1,108 @@ +/* + * Copyright 2015 Linaro Limited + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_RESET_MSM_GCC_8916_H +#define _DT_BINDINGS_RESET_MSM_GCC_8916_H + +#define GCC_BLSP1_BCR 0 +#define GCC_BLSP1_QUP1_BCR 1 +#define GCC_BLSP1_UART1_BCR 2 +#define GCC_BLSP1_QUP2_BCR 3 +#define GCC_BLSP1_UART2_BCR 4 +#define GCC_BLSP1_QUP3_BCR 5 +#define GCC_BLSP1_QUP4_BCR 6 +#define GCC_BLSP1_QUP5_BCR 7 +#define GCC_BLSP1_QUP6_BCR 8 +#define GCC_IMEM_BCR 9 +#define GCC_SMMU_BCR 10 +#define GCC_APSS_TCU_BCR 11 +#define GCC_SMMU_XPU_BCR 12 +#define GCC_PCNOC_TBU_BCR 13 +#define GCC_PRNG_BCR 14 +#define GCC_BOOT_ROM_BCR 15 +#define GCC_CRYPTO_BCR 16 +#define GCC_SEC_CTRL_BCR 17 +#define GCC_AUDIO_CORE_BCR 18 +#define GCC_ULT_AUDIO_BCR 19 +#define GCC_DEHR_BCR 20 +#define GCC_SYSTEM_NOC_BCR 21 +#define GCC_PCNOC_BCR 22 +#define GCC_TCSR_BCR 23 +#define GCC_QDSS_BCR 24 +#define GCC_DCD_BCR 25 +#define GCC_MSG_RAM_BCR 26 +#define GCC_MPM_BCR 27 +#define GCC_SPMI_BCR 28 +#define GCC_SPDM_BCR 29 +#define GCC_MM_SPDM_BCR 30 +#define GCC_BIMC_BCR 31 +#define GCC_RBCPR_BCR 32 +#define GCC_TLMM_BCR 33 +#define GCC_USB_HS_BCR 34 +#define GCC_USB2A_PHY_BCR 35 +#define GCC_SDCC1_BCR 36 +#define GCC_SDCC2_BCR 37 +#define GCC_PDM_BCR 38 +#define GCC_SNOC_BUS_TIMEOUT0_BCR 39 +#define GCC_PCNOC_BUS_TIMEOUT0_BCR 40 +#define GCC_PCNOC_BUS_TIMEOUT1_BCR 41 +#define GCC_PCNOC_BUS_TIMEOUT2_BCR 42 +#define GCC_PCNOC_BUS_TIMEOUT3_BCR 43 +#define GCC_PCNOC_BUS_TIMEOUT4_BCR 44 +#define GCC_PCNOC_BUS_TIMEOUT5_BCR 45 +#define GCC_PCNOC_BUS_TIMEOUT6_BCR 46 +#define GCC_PCNOC_BUS_TIMEOUT7_BCR 47 +#define GCC_PCNOC_BUS_TIMEOUT8_BCR 48 +#define GCC_PCNOC_BUS_TIMEOUT9_BCR 49 +#define GCC_MMSS_BCR 50 +#define GCC_VENUS0_BCR 51 +#define GCC_MDSS_BCR 52 +#define GCC_CAMSS_PHY0_BCR 53 +#define GCC_CAMSS_CSI0_BCR 54 +#define GCC_CAMSS_CSI0PHY_BCR 55 +#define GCC_CAMSS_CSI0RDI_BCR 56 +#define GCC_CAMSS_CSI0PIX_BCR 57 +#define GCC_CAMSS_PHY1_BCR 58 +#define GCC_CAMSS_CSI1_BCR 59 +#define GCC_CAMSS_CSI1PHY_BCR 60 +#define GCC_CAMSS_CSI1RDI_BCR 61 +#define GCC_CAMSS_CSI1PIX_BCR 62 +#define GCC_CAMSS_ISPIF_BCR 63 +#define GCC_CAMSS_CCI_BCR 64 +#define GCC_CAMSS_MCLK0_BCR 65 +#define GCC_CAMSS_MCLK1_BCR 66 +#define GCC_CAMSS_GP0_BCR 67 +#define GCC_CAMSS_GP1_BCR 68 +#define GCC_CAMSS_TOP_BCR 69 +#define GCC_CAMSS_MICRO_BCR 70 +#define GCC_CAMSS_JPEG_BCR 71 +#define GCC_CAMSS_VFE_BCR 72 +#define GCC_CAMSS_CSI_VFE0_BCR 73 +#define GCC_OXILI_BCR 74 +#define GCC_GMEM_BCR 75 +#define GCC_CAMSS_AHB_BCR 76 +#define GCC_MDP_TBU_BCR 77 +#define GCC_GFX_TBU_BCR 78 +#define GCC_GFX_TCU_BCR 79 +#define GCC_MSS_TBU_AXI_BCR 80 +#define GCC_MSS_TBU_GSS_AXI_BCR 81 +#define GCC_MSS_TBU_Q6_AXI_BCR 82 +#define GCC_GTCU_AHB_BCR 83 +#define GCC_SMMU_CFG_BCR 84 +#define GCC_VFE_TBU_BCR 85 +#define GCC_VENUS_TBU_BCR 86 +#define GCC_JPEG_TBU_BCR 87 +#define GCC_PRONTO_TBU_BCR 88 +#define GCC_SMMU_CATS_BCR 89 + +#endif -- cgit v1.2.3 From 4c385b25fab119144bffb255ad77712fe586ac10 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 2 Apr 2015 11:20:41 +0530 Subject: clk: qcom: Add EBI2 clocks for IPQ806x The NAND controller within EBI2 requires EBI2_CLK and EBI2_ALWAYS_ON_CLK clocks. Create structs for these clocks so that they can be used by the NAND controller driver. Add an entry for EBI2_AON_CLK in the gcc-ipq806x DT binding document. Signed-off-by: Archit Taneja Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-ipq806x.c | 32 ++++++++++++++++++++++++++++ include/dt-bindings/clock/qcom,gcc-ipq806x.h | 1 + 2 files changed, 33 insertions(+) (limited to 'include') diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index ee73cc7f6e55..a50936a17376 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c @@ -2172,6 +2172,36 @@ static struct clk_branch usb_fs1_h_clk = { }, }; +static struct clk_branch ebi2_clk = { + .hwcg_reg = 0x3b00, + .hwcg_bit = 6, + .halt_reg = 0x2fcc, + .halt_bit = 1, + .clkr = { + .enable_reg = 0x3b00, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "ebi2_clk", + .ops = &clk_branch_ops, + .flags = CLK_IS_ROOT, + }, + }, +}; + +static struct clk_branch ebi2_aon_clk = { + .halt_reg = 0x2fcc, + .halt_bit = 0, + .clkr = { + .enable_reg = 0x3b00, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .name = "ebi2_always_on_clk", + .ops = &clk_branch_ops, + .flags = CLK_IS_ROOT, + }, + }, +}; + static struct clk_regmap *gcc_ipq806x_clks[] = { [PLL0] = &pll0.clkr, [PLL0_VOTE] = &pll0_vote, @@ -2275,6 +2305,8 @@ static struct clk_regmap *gcc_ipq806x_clks[] = { [USB_FS1_XCVR_SRC] = &usb_fs1_xcvr_clk_src.clkr, [USB_FS1_XCVR_CLK] = &usb_fs1_xcvr_clk.clkr, [USB_FS1_SYSTEM_CLK] = &usb_fs1_sys_clk.clkr, + [EBI2_CLK] = &ebi2_clk.clkr, + [EBI2_AON_CLK] = &ebi2_aon_clk.clkr, }; static const struct qcom_reset_map gcc_ipq806x_resets[] = { diff --git a/include/dt-bindings/clock/qcom,gcc-ipq806x.h b/include/dt-bindings/clock/qcom,gcc-ipq806x.h index 04fb29ae30e6..ebd63fd05649 100644 --- a/include/dt-bindings/clock/qcom,gcc-ipq806x.h +++ b/include/dt-bindings/clock/qcom,gcc-ipq806x.h @@ -288,5 +288,6 @@ #define UBI32_CORE2_CLK_SRC 278 #define UBI32_CORE1_CLK 279 #define UBI32_CORE2_CLK 280 +#define EBI2_AON_CLK 281 #endif -- cgit v1.2.3 From 0578be680c6623ad6515b60a0b41ec70ebc1f204 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 7 Apr 2015 15:56:07 +0200 Subject: drm: Use kref_put_mutex in drm_gem_object_unreference_unlocked If kref_put_mutex returns true then the caller or the put function is responsible for unlocking the mutex. The usual pattern assumes that the free callback unlocks the mutex, but since that is shared with the locked variant we need to explicitly unlock here. Signed-off-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- include/drm/drm_gem.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index 1e6ae1458f7a..7a592d7e398b 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -149,14 +149,16 @@ drm_gem_object_unreference(struct drm_gem_object *obj) static inline void drm_gem_object_unreference_unlocked(struct drm_gem_object *obj) { - if (obj && !atomic_add_unless(&obj->refcount.refcount, -1, 1)) { - struct drm_device *dev = obj->dev; + struct drm_device *dev; + + if (!obj) + return; - mutex_lock(&dev->struct_mutex); - if (likely(atomic_dec_and_test(&obj->refcount.refcount))) - drm_gem_object_free(&obj->refcount); + dev = obj->dev; + if (kref_put_mutex(&obj->refcount, drm_gem_object_free, &dev->struct_mutex)) mutex_unlock(&dev->struct_mutex); - } + else + might_lock(&dev->struct_mutex); } int drm_gem_handle_create(struct drm_file *file_priv, -- cgit v1.2.3 From 38b57f82f66dfb21ebe321d71c84c0e3469980c4 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 27 Feb 2015 22:05:21 -0800 Subject: target: Add protected fabric + unprotected device support This patch adds a new target_core_fabric_ops callback for allowing fabric drivers to expose a TPG attribute for signaling when a T10-PI protected fabric wants to function with an un-protected device without T10-PI. This specifically is to allow LIO to perform WRITE_STRIP + READ_INSERT operations when functioning with non T10-PI enabled devices, seperate from any available hw offloads the fabric supports. This is done using a new se_sess->sess_prot_type that is set at fabric session creation time based upon the TPG attribute. It currently cannot be changed for individual sessions after initial creation. Also, update existing target_core_sbc.c code to honor sess_prot_type when setting up cmd->prot_op + cmd->prot_type assignments. (Add unlikely and !! boolean conversion in sbc_check_prot - Sagi) Cc: Martin Petersen Cc: Sagi Grimberg Cc: Christoph Hellwig Cc: Doug Gilbert Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 44 +++++++++++++++++++++++++--------- drivers/target/target_core_transport.c | 8 +++++++ include/target/target_core_base.h | 1 + include/target/target_core_fabric.h | 8 +++++++ 4 files changed, 50 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 95a7a7444965..9efd1fd985ee 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -581,12 +581,13 @@ sbc_compare_and_write(struct se_cmd *cmd) } static int -sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type, +sbc_set_prot_op_checks(u8 protect, bool fabric_prot, enum target_prot_type prot_type, bool is_write, struct se_cmd *cmd) { if (is_write) { - cmd->prot_op = protect ? TARGET_PROT_DOUT_PASS : - TARGET_PROT_DOUT_INSERT; + cmd->prot_op = fabric_prot ? TARGET_PROT_DOUT_STRIP : + protect ? TARGET_PROT_DOUT_PASS : + TARGET_PROT_DOUT_INSERT; switch (protect) { case 0x0: case 0x3: @@ -610,8 +611,9 @@ sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type, return -EINVAL; } } else { - cmd->prot_op = protect ? TARGET_PROT_DIN_PASS : - TARGET_PROT_DIN_STRIP; + cmd->prot_op = fabric_prot ? TARGET_PROT_DIN_INSERT : + protect ? TARGET_PROT_DIN_PASS : + TARGET_PROT_DIN_STRIP; switch (protect) { case 0x0: case 0x1: @@ -644,11 +646,15 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, u32 sectors, bool is_write) { u8 protect = cdb[1] >> 5; + int sp_ops = cmd->se_sess->sup_prot_ops; + int pi_prot_type = dev->dev_attrib.pi_prot_type; + bool fabric_prot = false; if (!cmd->t_prot_sg || !cmd->t_prot_nents) { - if (protect && !dev->dev_attrib.pi_prot_type) { - pr_err("CDB contains protect bit, but device does not" - " advertise PROTECT=1 feature bit\n"); + if (unlikely(protect && + !dev->dev_attrib.pi_prot_type && !cmd->se_sess->sess_prot_type)) { + pr_err("CDB contains protect bit, but device + fabric does" + " not advertise PROTECT=1 feature bit\n"); return TCM_INVALID_CDB_FIELD; } if (cmd->prot_pto) @@ -669,15 +675,28 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, cmd->reftag_seed = cmd->t_task_lba; break; case TARGET_DIF_TYPE0_PROT: + /* + * See if the fabric supports T10-PI, and the session has been + * configured to allow export PROTECT=1 feature bit with backend + * devices that don't support T10-PI. + */ + fabric_prot = is_write ? + !!(sp_ops & (TARGET_PROT_DOUT_PASS | TARGET_PROT_DOUT_STRIP)) : + !!(sp_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DIN_INSERT)); + + if (fabric_prot && cmd->se_sess->sess_prot_type) { + pi_prot_type = cmd->se_sess->sess_prot_type; + break; + } + /* Fallthrough */ default: return TCM_NO_SENSE; } - if (sbc_set_prot_op_checks(protect, dev->dev_attrib.pi_prot_type, - is_write, cmd)) + if (sbc_set_prot_op_checks(protect, fabric_prot, pi_prot_type, is_write, cmd)) return TCM_INVALID_CDB_FIELD; - cmd->prot_type = dev->dev_attrib.pi_prot_type; + cmd->prot_type = pi_prot_type; cmd->prot_length = dev->prot_length * sectors; /** @@ -1231,6 +1250,9 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, unsigned int i, len, left; unsigned int offset = sg_off; + if (!sg) + return; + left = sectors * dev->prot_length; for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) { diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 4a00ed5c1880..aef989e165ed 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -322,10 +322,18 @@ void __transport_register_session( struct se_session *se_sess, void *fabric_sess_ptr) { + struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo; unsigned char buf[PR_REG_ISID_LEN]; se_sess->se_tpg = se_tpg; se_sess->fabric_sess_ptr = fabric_sess_ptr; + /* + * Determine if fabric allows for T10-PI feature bits to be exposed + * to initiators for device backends with !dev->dev_attrib.pi_prot_type + */ + if (tfo->tpg_check_prot_fabric_only) + se_sess->sess_prot_type = tfo->tpg_check_prot_fabric_only(se_tpg); + /* * Used by struct se_node_acl's under ConfigFS to locate active se_session-t * diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 672150b6aaf5..fe25a78fff46 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -616,6 +616,7 @@ struct se_session { unsigned sess_tearing_down:1; u64 sess_bin_isid; enum target_prot_op sup_prot_ops; + enum target_prot_type sess_prot_type; struct se_node_acl *se_node_acl; struct se_portal_group *se_tpg; void *fabric_sess_ptr; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 2f4a2505db4c..c93cfdf0d8e5 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -27,6 +27,14 @@ struct target_core_fabric_ops { * inquiry response */ int (*tpg_check_demo_mode_login_only)(struct se_portal_group *); + /* + * Optionally used as a configfs tunable to determine when + * target-core should signal the PROTECT=1 feature bit for + * backends that don't support T10-PI, so that either fabric + * HW offload or target-core emulation performs the associated + * WRITE_STRIP and READ_INSERT operations. + */ + int (*tpg_check_prot_fabric_only)(struct se_portal_group *); struct se_node_acl *(*tpg_alloc_fabric_acl)( struct se_portal_group *); void (*tpg_release_fabric_acl)(struct se_portal_group *, -- cgit v1.2.3 From 901c04a33f138e5fb935a1621375a1a0997fe7b1 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 29 Mar 2015 19:36:16 -0700 Subject: iscsi/iser-target: Add fabric_prot_type attribute support This patch updates iscsi/iser-target to add a new fabric_prot_type TPG attribute for iser-target, used for controlling LLD level protection into LIO when the backend device does not support T10-PI. This is required for ib_isert to enable WRITE_STRIP + READ_INSERT hardware offloads. It's disabled by default and controls which se_sesion->sess_prot_type are set at iscsi_target_locate_portal() session registration time. Cc: Sagi Grimberg Cc: Martin Petersen Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_configfs.c | 22 ++++++++++++++++++++++ drivers/target/iscsi/iscsi_target_tpg.c | 19 +++++++++++++++++++ drivers/target/iscsi/iscsi_target_tpg.h | 1 + include/target/iscsi/iscsi_target_core.h | 2 ++ 4 files changed, 44 insertions(+) (limited to 'include') diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 95a67f604073..9cb5ab472a52 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1052,6 +1052,11 @@ TPG_ATTR(default_erl, S_IRUGO | S_IWUSR); */ DEF_TPG_ATTRIB(t10_pi); TPG_ATTR(t10_pi, S_IRUGO | S_IWUSR); +/* + * Define iscsi_tpg_attrib_s_fabric_prot_type + */ +DEF_TPG_ATTRIB(fabric_prot_type); +TPG_ATTR(fabric_prot_type, S_IRUGO | S_IWUSR); static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = { &iscsi_tpg_attrib_authentication.attr, @@ -1065,6 +1070,7 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = { &iscsi_tpg_attrib_demo_mode_discovery.attr, &iscsi_tpg_attrib_default_erl.attr, &iscsi_tpg_attrib_t10_pi.attr, + &iscsi_tpg_attrib_fabric_prot_type.attr, NULL, }; @@ -1882,6 +1888,20 @@ static int lio_tpg_check_prod_mode_write_protect( return tpg->tpg_attrib.prod_mode_write_protect; } +static int lio_tpg_check_prot_fabric_only( + struct se_portal_group *se_tpg) +{ + struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; + /* + * Only report fabric_prot_type if t10_pi has also been enabled + * for incoming ib_isert sessions. + */ + if (!tpg->tpg_attrib.t10_pi) + return 0; + + return tpg->tpg_attrib.fabric_prot_type; +} + static void lio_tpg_release_fabric_acl( struct se_portal_group *se_tpg, struct se_node_acl *se_acl) @@ -1997,6 +2017,8 @@ int iscsi_target_register_configfs(void) &lio_tpg_check_demo_mode_write_protect; fabric->tf_ops.tpg_check_prod_mode_write_protect = &lio_tpg_check_prod_mode_write_protect; + fabric->tf_ops.tpg_check_prot_fabric_only = + &lio_tpg_check_prot_fabric_only; fabric->tf_ops.tpg_alloc_fabric_acl = &lio_tpg_alloc_fabric_acl; fabric->tf_ops.tpg_release_fabric_acl = &lio_tpg_release_fabric_acl; fabric->tf_ops.tpg_get_inst_index = &lio_tpg_get_inst_index; diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index bdd127c0e3ae..3076e6f3a831 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -228,6 +228,7 @@ static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg) a->demo_mode_discovery = TA_DEMO_MODE_DISCOVERY; a->default_erl = TA_DEFAULT_ERL; a->t10_pi = TA_DEFAULT_T10_PI; + a->fabric_prot_type = TA_DEFAULT_FABRIC_PROT_TYPE; } int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg) @@ -878,3 +879,21 @@ int iscsit_ta_t10_pi( return 0; } + +int iscsit_ta_fabric_prot_type( + struct iscsi_portal_group *tpg, + u32 prot_type) +{ + struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; + + if ((prot_type != 0) && (prot_type != 1) && (prot_type != 3)) { + pr_err("Illegal value for fabric_prot_type: %u\n", prot_type); + return -EINVAL; + } + + a->fabric_prot_type = prot_type; + pr_debug("iSCSI_TPG[%hu] - T10 Fabric Protection Type: %u\n", + tpg->tpgt, prot_type); + + return 0; +} diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h index e7265337bc43..95ff5bdecd71 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.h +++ b/drivers/target/iscsi/iscsi_target_tpg.h @@ -39,5 +39,6 @@ extern int iscsit_ta_prod_mode_write_protect(struct iscsi_portal_group *, u32); extern int iscsit_ta_demo_mode_discovery(struct iscsi_portal_group *, u32); extern int iscsit_ta_default_erl(struct iscsi_portal_group *, u32); extern int iscsit_ta_t10_pi(struct iscsi_portal_group *, u32); +extern int iscsit_ta_fabric_prot_type(struct iscsi_portal_group *, u32); #endif /* ISCSI_TARGET_TPG_H */ diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 0e394a031c28..54e7af301888 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -62,6 +62,7 @@ #define TA_CACHE_CORE_NPS 0 /* T10 protection information disabled by default */ #define TA_DEFAULT_T10_PI 0 +#define TA_DEFAULT_FABRIC_PROT_TYPE 0 #define ISCSI_IOV_DATA_BUFFER 5 @@ -772,6 +773,7 @@ struct iscsi_tpg_attrib { u32 demo_mode_discovery; u32 default_erl; u8 t10_pi; + u32 fabric_prot_type; struct iscsi_portal_group *tpg; }; -- cgit v1.2.3 From c3d0a7c21db219ef87679c2a667aba9f138524db Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 7 Apr 2015 19:11:16 +0200 Subject: target: remove the unused SCF_CMD_XCOPY_PASSTHROUGH flag Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_xcopy.c | 4 ++-- include/target/target_core_base.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 04cad3b36297..b09b40e058a0 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -553,7 +553,7 @@ static int target_xcopy_init_pt_lun( * target_xcopy_setup_pt_port() */ if (!remote_port) { - pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH; + pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; return 0; } @@ -561,7 +561,7 @@ static int target_xcopy_init_pt_lun( pt_cmd->se_dev = se_dev; pr_debug("Setup emulated se_dev: %p from se_dev\n", pt_cmd->se_dev); - pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH; + pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; pr_debug("Setup emulated se_dev: %p to pt_cmd->se_lun->lun_se_dev\n", pt_cmd->se_lun->lun_se_dev); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index fe25a78fff46..71699cf3cc71 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -168,7 +168,6 @@ enum se_cmd_flags_table { SCF_ACK_KREF = 0x00040000, SCF_COMPARE_AND_WRITE = 0x00080000, SCF_COMPARE_AND_WRITE_POST = 0x00100000, - SCF_CMD_XCOPY_PASSTHROUGH = 0x00200000, }; /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */ -- cgit v1.2.3 From b6e5b8f1a90230f922de8af59cdaf1ad83e1ac1e Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 20 Mar 2015 10:45:43 -0300 Subject: [media] media: New flag V4L2_CTRL_FLAG_EXECUTE_ON_WRITE Create a new flag that represent controls which its value needs to be passed to the driver even if it has not changed. They typically represent actions, like triggering a flash or clearing an error flag. So writing to such a control means some action is executed. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 47df18f36c4b..810bade873f4 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1457,6 +1457,7 @@ struct v4l2_querymenu { #define V4L2_CTRL_FLAG_WRITE_ONLY 0x0040 #define V4L2_CTRL_FLAG_VOLATILE 0x0080 #define V4L2_CTRL_FLAG_HAS_PAYLOAD 0x0100 +#define V4L2_CTRL_FLAG_EXECUTE_ON_WRITE 0x0200 /* Query flags, to be ORed with the control ID */ #define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000 -- cgit v1.2.3 From 5ce65d1f874ddc109780fc781bb3b099bff82001 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Mar 2015 14:05:03 -0300 Subject: [media] videodev2.h/v4l2-dv-timings.h: add V4L2_DV_FL_IS_CE_VIDEO flag In the past the V4L2_DV_BT_STD_CEA861 standard bit was used to determine whether the format is a CE (Consumer Electronics) format or not. However, the 640x480p59.94 format is part of the CEA-861 standard, but it is *not* a CE video format. Add a new flag to make this explicit. This information is needed in order to determine the default R'G'B' encoding for the format: for CE video this is limited range (16-235) instead of full range (0-255). The header with all the timings has been updated with this new flag. Signed-off-by: Hans Verkuil Cc: Martin Bugge Cc: Mats Randgaard Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/v4l2-dv-timings.h | 64 ++++++++++++++++++++++-------------- include/uapi/linux/videodev2.h | 6 ++++ 2 files changed, 45 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/v4l2-dv-timings.h b/include/uapi/linux/v4l2-dv-timings.h index 6c8f159e416e..c039f1d68a09 100644 --- a/include/uapi/linux/v4l2-dv-timings.h +++ b/include/uapi/linux/v4l2-dv-timings.h @@ -48,14 +48,15 @@ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(720, 480, 1, 0, \ 13500000, 19, 62, 57, 4, 3, 15, 4, 3, 16, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_HALF_LINE | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_720X480P59_94 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(720, 480, 0, 0, \ 27000000, 16, 62, 60, 9, 6, 30, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } /* Note: these are the nominal timings, for HDMI links this format is typically @@ -64,14 +65,15 @@ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(720, 576, 1, 0, \ 13500000, 12, 63, 69, 2, 3, 19, 2, 3, 20, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_HALF_LINE | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_720X576P50 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(720, 576, 0, 0, \ 27000000, 12, 64, 68, 5, 5, 39, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1280X720P24 { \ @@ -88,7 +90,7 @@ V4L2_INIT_BT_TIMINGS(1280, 720, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 2420, 40, 220, 5, 5, 20, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1280X720P30 { \ @@ -96,7 +98,8 @@ V4L2_INIT_BT_TIMINGS(1280, 720, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 1760, 40, 220, 5, 5, 20, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1280X720P50 { \ @@ -104,7 +107,7 @@ V4L2_INIT_BT_TIMINGS(1280, 720, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 440, 40, 220, 5, 5, 20, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1280X720P60 { \ @@ -112,7 +115,8 @@ V4L2_INIT_BT_TIMINGS(1280, 720, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 110, 40, 220, 5, 5, 20, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080P24 { \ @@ -120,7 +124,8 @@ V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 638, 44, 148, 4, 5, 36, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080P25 { \ @@ -128,7 +133,7 @@ V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 528, 44, 148, 4, 5, 36, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080P30 { \ @@ -136,7 +141,8 @@ V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 88, 44, 148, 4, 5, 36, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080I50 { \ @@ -144,7 +150,8 @@ V4L2_INIT_BT_TIMINGS(1920, 1080, 1, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 528, 44, 148, 2, 5, 15, 2, 5, 16, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_HALF_LINE | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080P50 { \ @@ -152,7 +159,7 @@ V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 148500000, 528, 44, 148, 4, 5, 36, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080I60 { \ @@ -161,7 +168,8 @@ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 88, 44, 148, 2, 5, 15, 2, 5, 16, \ V4L2_DV_BT_STD_CEA861, \ - V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_HALF_LINE) \ + V4L2_DV_FL_CAN_REDUCE_FPS | \ + V4L2_DV_FL_HALF_LINE | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080P60 { \ @@ -170,77 +178,83 @@ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 148500000, 88, 44, 148, 4, 5, 36, 0, 0, 0, \ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861, \ - V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_3840X2160P24 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 1276, 88, 296, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_3840X2160P25 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 1056, 88, 296, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_3840X2160P30 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 176, 88, 296, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_3840X2160P50 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 594000000, 1056, 88, 296, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_3840X2160P60 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 594000000, 176, 88, 296, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_4096X2160P24 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 1020, 88, 296, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_4096X2160P25 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 968, 88, 128, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_4096X2160P30 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 88, 88, 128, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_4096X2160P50 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 594000000, 968, 88, 128, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_4096X2160P60 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 594000000, 88, 88, 128, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 810bade873f4..fa376f7666ba 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1188,6 +1188,12 @@ struct v4l2_bt_timings { exactly the same number of half-lines. Whether half-lines can be detected or used depends on the hardware. */ #define V4L2_DV_FL_HALF_LINE (1 << 3) +/* If set, then this is a Consumer Electronics (CE) video format. Such formats + * differ from other formats (commonly called IT formats) in that if RGB + * encoding is used then by default the RGB values use limited range (i.e. + * use the range 16-235) as opposed to 0-255. All formats defined in CEA-861 + * except for the 640x480 format are CE formats. */ +#define V4L2_DV_FL_IS_CE_VIDEO (1 << 4) /* A few useful defines to calculate the total blanking and frame sizes */ #define V4L2_DV_BT_BLANKING_WIDTH(bt) \ -- cgit v1.2.3 From 9b174527e7b756cda9f5d9e541f87b7fec9cfdf0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 Feb 2015 14:12:42 -0300 Subject: [media] Add and use IS_REACHABLE macro In the media drivers, the v4l2 core knows about all submodules and calls into them from a common function. However this cannot work if the modules that get called are loadable and the core is built-in. In that case we get drivers/built-in.o: In function `set_type': drivers/media/v4l2-core/tuner-core.c:301: undefined reference to `tea5767_attach' drivers/media/v4l2-core/tuner-core.c:307: undefined reference to `tea5761_attach' drivers/media/v4l2-core/tuner-core.c:349: undefined reference to `tda9887_attach' drivers/media/v4l2-core/tuner-core.c:405: undefined reference to `xc4000_attach' This was working previously, until the IS_ENABLED() macro was used to replace the construct like #if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE)) with the difference that the new code no longer checks whether it is being built as a loadable module itself. To fix this, this new patch adds an 'IS_REACHABLE' macro, which evaluates true in exactly the condition that was used previously. The downside of this is that this trades an obvious link error for a more subtle runtime failure, but it is clear that the change that introduced the link error was unintentional and it seems better to revert it for now. Also, a similar change was originally created by Trent Piepho and then reverted by teh change to the IS_ENABLED macro. Ideally Kconfig would be used to avoid the case of a broken dependency, or the code restructured in a way to turn around the dependency, but either way would require much larger changes here. Fixes: 7b34be71db53 ("[media] use IS_ENABLED() macro") See-also: c5dec9fb248e ("V4L/DVB (4751): Fix DBV_FE_CUSTOMISE for card drivers compiled into kernel") Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/a8293.h | 2 +- drivers/media/dvb-frontends/af9013.h | 2 +- drivers/media/dvb-frontends/atbm8830.h | 2 +- drivers/media/dvb-frontends/au8522.h | 2 +- drivers/media/dvb-frontends/bcm3510.h | 2 +- drivers/media/dvb-frontends/cx22700.h | 2 +- drivers/media/dvb-frontends/cx22702.h | 2 +- drivers/media/dvb-frontends/cx24110.h | 2 +- drivers/media/dvb-frontends/cx24113.h | 2 +- drivers/media/dvb-frontends/cx24116.h | 2 +- drivers/media/dvb-frontends/cx24117.h | 2 +- drivers/media/dvb-frontends/cx24123.h | 2 +- drivers/media/dvb-frontends/cxd2820r.h | 2 +- drivers/media/dvb-frontends/dib0070.h | 2 +- drivers/media/dvb-frontends/dib0090.h | 2 +- drivers/media/dvb-frontends/dib3000.h | 2 +- drivers/media/dvb-frontends/dib3000mc.h | 2 +- drivers/media/dvb-frontends/dib7000m.h | 2 +- drivers/media/dvb-frontends/dib7000p.h | 2 +- drivers/media/dvb-frontends/dib8000.h | 2 +- drivers/media/dvb-frontends/dib9000.h | 2 +- drivers/media/dvb-frontends/drxd.h | 2 +- drivers/media/dvb-frontends/drxk.h | 2 +- drivers/media/dvb-frontends/ds3000.h | 2 +- drivers/media/dvb-frontends/dvb-pll.h | 2 +- drivers/media/dvb-frontends/dvb_dummy_fe.h | 2 +- drivers/media/dvb-frontends/ec100.h | 2 +- drivers/media/dvb-frontends/hd29l2.h | 2 +- drivers/media/dvb-frontends/isl6405.h | 2 +- drivers/media/dvb-frontends/isl6421.h | 2 +- drivers/media/dvb-frontends/isl6423.h | 2 +- drivers/media/dvb-frontends/itd1000.h | 2 +- drivers/media/dvb-frontends/ix2505v.h | 2 +- drivers/media/dvb-frontends/l64781.h | 2 +- drivers/media/dvb-frontends/lg2160.h | 2 +- drivers/media/dvb-frontends/lgdt3305.h | 2 +- drivers/media/dvb-frontends/lgdt330x.h | 2 +- drivers/media/dvb-frontends/lgs8gl5.h | 2 +- drivers/media/dvb-frontends/lgs8gxx.h | 2 +- drivers/media/dvb-frontends/lnbh24.h | 2 +- drivers/media/dvb-frontends/lnbp21.h | 2 +- drivers/media/dvb-frontends/lnbp22.h | 2 +- drivers/media/dvb-frontends/m88rs2000.h | 2 +- drivers/media/dvb-frontends/mb86a16.h | 2 +- drivers/media/dvb-frontends/mb86a20s.h | 2 +- drivers/media/dvb-frontends/mt312.h | 2 +- drivers/media/dvb-frontends/mt352.h | 2 +- drivers/media/dvb-frontends/nxt200x.h | 2 +- drivers/media/dvb-frontends/nxt6000.h | 2 +- drivers/media/dvb-frontends/or51132.h | 2 +- drivers/media/dvb-frontends/or51211.h | 2 +- drivers/media/dvb-frontends/s5h1409.h | 2 +- drivers/media/dvb-frontends/s5h1411.h | 2 +- drivers/media/dvb-frontends/s5h1420.h | 2 +- drivers/media/dvb-frontends/s5h1432.h | 2 +- drivers/media/dvb-frontends/s921.h | 2 +- drivers/media/dvb-frontends/si21xx.h | 2 +- drivers/media/dvb-frontends/sp8870.h | 2 +- drivers/media/dvb-frontends/sp887x.h | 2 +- drivers/media/dvb-frontends/stb0899_drv.h | 2 +- drivers/media/dvb-frontends/stb6000.h | 2 +- drivers/media/dvb-frontends/stb6100.h | 2 +- drivers/media/dvb-frontends/stv0288.h | 2 +- drivers/media/dvb-frontends/stv0297.h | 2 +- drivers/media/dvb-frontends/stv0299.h | 2 +- drivers/media/dvb-frontends/stv0367.h | 2 +- drivers/media/dvb-frontends/stv0900.h | 2 +- drivers/media/dvb-frontends/stv090x.h | 2 +- drivers/media/dvb-frontends/stv6110.h | 2 +- drivers/media/dvb-frontends/stv6110x.h | 2 +- drivers/media/dvb-frontends/tda1002x.h | 4 ++-- drivers/media/dvb-frontends/tda10048.h | 2 +- drivers/media/dvb-frontends/tda1004x.h | 2 +- drivers/media/dvb-frontends/tda10071.h | 2 +- drivers/media/dvb-frontends/tda10086.h | 2 +- drivers/media/dvb-frontends/tda18271c2dd.h | 2 +- drivers/media/dvb-frontends/tda665x.h | 2 +- drivers/media/dvb-frontends/tda8083.h | 2 +- drivers/media/dvb-frontends/tda8261.h | 2 +- drivers/media/dvb-frontends/tda826x.h | 2 +- drivers/media/dvb-frontends/ts2020.h | 2 +- drivers/media/dvb-frontends/tua6100.h | 2 +- drivers/media/dvb-frontends/ves1820.h | 2 +- drivers/media/dvb-frontends/ves1x93.h | 2 +- drivers/media/dvb-frontends/zl10036.h | 2 +- drivers/media/dvb-frontends/zl10039.h | 2 +- drivers/media/dvb-frontends/zl10353.h | 2 +- drivers/media/pci/cx23885/altera-ci.h | 2 +- drivers/media/tuners/fc0011.h | 2 +- drivers/media/tuners/fc0012.h | 2 +- drivers/media/tuners/fc0013.h | 2 +- drivers/media/tuners/fc2580.h | 2 +- drivers/media/tuners/max2165.h | 2 +- drivers/media/tuners/mc44s803.h | 2 +- drivers/media/tuners/mt2060.h | 2 +- drivers/media/tuners/mt2063.h | 2 +- drivers/media/tuners/mt20xx.h | 2 +- drivers/media/tuners/mt2131.h | 2 +- drivers/media/tuners/mt2266.h | 2 +- drivers/media/tuners/mxl5005s.h | 2 +- drivers/media/tuners/mxl5007t.h | 2 +- drivers/media/tuners/qt1010.h | 2 +- drivers/media/tuners/r820t.h | 2 +- drivers/media/tuners/tda18218.h | 2 +- drivers/media/tuners/tda18271.h | 2 +- drivers/media/tuners/tda827x.h | 2 +- drivers/media/tuners/tda8290.h | 2 +- drivers/media/tuners/tda9887.h | 2 +- drivers/media/tuners/tea5761.h | 2 +- drivers/media/tuners/tea5767.h | 2 +- drivers/media/tuners/tua9001.h | 2 +- drivers/media/tuners/tuner-simple.h | 2 +- drivers/media/tuners/tuner-xc2028.h | 2 +- drivers/media/tuners/xc4000.h | 2 +- drivers/media/tuners/xc5000.h | 2 +- include/linux/kconfig.h | 9 +++++++++ 116 files changed, 125 insertions(+), 116 deletions(-) (limited to 'include') diff --git a/drivers/media/dvb-frontends/a8293.h b/drivers/media/dvb-frontends/a8293.h index b6ef6427cfa5..5f0411939ffc 100644 --- a/drivers/media/dvb-frontends/a8293.h +++ b/drivers/media/dvb-frontends/a8293.h @@ -27,7 +27,7 @@ struct a8293_config { u8 i2c_addr; }; -#if IS_ENABLED(CONFIG_DVB_A8293) +#if IS_REACHABLE(CONFIG_DVB_A8293) extern struct dvb_frontend *a8293_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct a8293_config *cfg); #else diff --git a/drivers/media/dvb-frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h index 09273b2cd310..1dcc936e1661 100644 --- a/drivers/media/dvb-frontends/af9013.h +++ b/drivers/media/dvb-frontends/af9013.h @@ -103,7 +103,7 @@ struct af9013_config { u8 gpio[4]; }; -#if IS_ENABLED(CONFIG_DVB_AF9013) +#if IS_REACHABLE(CONFIG_DVB_AF9013) extern struct dvb_frontend *af9013_attach(const struct af9013_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/atbm8830.h b/drivers/media/dvb-frontends/atbm8830.h index 8e0ac98f8d08..5446d13fdfe8 100644 --- a/drivers/media/dvb-frontends/atbm8830.h +++ b/drivers/media/dvb-frontends/atbm8830.h @@ -61,7 +61,7 @@ struct atbm8830_config { u8 agc_hold_loop; }; -#if IS_ENABLED(CONFIG_DVB_ATBM8830) +#if IS_REACHABLE(CONFIG_DVB_ATBM8830) extern struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/au8522.h b/drivers/media/dvb-frontends/au8522.h index 612251958855..dde61582c158 100644 --- a/drivers/media/dvb-frontends/au8522.h +++ b/drivers/media/dvb-frontends/au8522.h @@ -61,7 +61,7 @@ struct au8522_config { enum au8522_if_freq qam_if; }; -#if IS_ENABLED(CONFIG_DVB_AU8522_DTV) +#if IS_REACHABLE(CONFIG_DVB_AU8522_DTV) extern struct dvb_frontend *au8522_attach(const struct au8522_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/bcm3510.h b/drivers/media/dvb-frontends/bcm3510.h index 5bd56b1623bf..ff66492fb940 100644 --- a/drivers/media/dvb-frontends/bcm3510.h +++ b/drivers/media/dvb-frontends/bcm3510.h @@ -34,7 +34,7 @@ struct bcm3510_config int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; -#if IS_ENABLED(CONFIG_DVB_BCM3510) +#if IS_REACHABLE(CONFIG_DVB_BCM3510) extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/cx22700.h b/drivers/media/dvb-frontends/cx22700.h index 382a7b1f3618..e0a764868e6f 100644 --- a/drivers/media/dvb-frontends/cx22700.h +++ b/drivers/media/dvb-frontends/cx22700.h @@ -31,7 +31,7 @@ struct cx22700_config u8 demod_address; }; -#if IS_ENABLED(CONFIG_DVB_CX22700) +#if IS_REACHABLE(CONFIG_DVB_CX22700) extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/cx22702.h b/drivers/media/dvb-frontends/cx22702.h index 0b1a6c2f9d5f..68b69a7660d2 100644 --- a/drivers/media/dvb-frontends/cx22702.h +++ b/drivers/media/dvb-frontends/cx22702.h @@ -41,7 +41,7 @@ struct cx22702_config { u8 output_mode; }; -#if IS_ENABLED(CONFIG_DVB_CX22702) +#if IS_REACHABLE(CONFIG_DVB_CX22702) extern struct dvb_frontend *cx22702_attach( const struct cx22702_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/cx24110.h b/drivers/media/dvb-frontends/cx24110.h index 527aff1f2723..d5453ed20b28 100644 --- a/drivers/media/dvb-frontends/cx24110.h +++ b/drivers/media/dvb-frontends/cx24110.h @@ -46,7 +46,7 @@ static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) return 0; } -#if IS_ENABLED(CONFIG_DVB_CX24110) +#if IS_REACHABLE(CONFIG_DVB_CX24110) extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/cx24113.h b/drivers/media/dvb-frontends/cx24113.h index 782711ba1a32..962919b9b6e6 100644 --- a/drivers/media/dvb-frontends/cx24113.h +++ b/drivers/media/dvb-frontends/cx24113.h @@ -32,7 +32,7 @@ struct cx24113_config { u32 xtal_khz; }; -#if IS_ENABLED(CONFIG_DVB_TUNER_CX24113) +#if IS_REACHABLE(CONFIG_DVB_TUNER_CX24113) extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *, const struct cx24113_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/cx24116.h b/drivers/media/dvb-frontends/cx24116.h index 2ec84fae3f9f..f6dbabc1d62b 100644 --- a/drivers/media/dvb-frontends/cx24116.h +++ b/drivers/media/dvb-frontends/cx24116.h @@ -41,7 +41,7 @@ struct cx24116_config { u16 i2c_wr_max; }; -#if IS_ENABLED(CONFIG_DVB_CX24116) +#if IS_REACHABLE(CONFIG_DVB_CX24116) extern struct dvb_frontend *cx24116_attach( const struct cx24116_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/cx24117.h b/drivers/media/dvb-frontends/cx24117.h index 4e59e9574fa7..1648ab432168 100644 --- a/drivers/media/dvb-frontends/cx24117.h +++ b/drivers/media/dvb-frontends/cx24117.h @@ -30,7 +30,7 @@ struct cx24117_config { u8 demod_address; }; -#if IS_ENABLED(CONFIG_DVB_CX24117) +#if IS_REACHABLE(CONFIG_DVB_CX24117) extern struct dvb_frontend *cx24117_attach( const struct cx24117_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/cx24123.h b/drivers/media/dvb-frontends/cx24123.h index 102e70d17c43..758aee5a072f 100644 --- a/drivers/media/dvb-frontends/cx24123.h +++ b/drivers/media/dvb-frontends/cx24123.h @@ -39,7 +39,7 @@ struct cx24123_config { void (*agc_callback) (struct dvb_frontend *); }; -#if IS_ENABLED(CONFIG_DVB_CX24123) +#if IS_REACHABLE(CONFIG_DVB_CX24123) extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config, struct i2c_adapter *i2c); extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *); diff --git a/drivers/media/dvb-frontends/cxd2820r.h b/drivers/media/dvb-frontends/cxd2820r.h index 6095dbcf7850..56d42760263d 100644 --- a/drivers/media/dvb-frontends/cxd2820r.h +++ b/drivers/media/dvb-frontends/cxd2820r.h @@ -72,7 +72,7 @@ struct cxd2820r_config { }; -#if IS_ENABLED(CONFIG_DVB_CXD2820R) +#if IS_REACHABLE(CONFIG_DVB_CXD2820R) extern struct dvb_frontend *cxd2820r_attach( const struct cxd2820r_config *config, struct i2c_adapter *i2c, diff --git a/drivers/media/dvb-frontends/dib0070.h b/drivers/media/dvb-frontends/dib0070.h index 0c6befcc9143..6c0b6672b1d9 100644 --- a/drivers/media/dvb-frontends/dib0070.h +++ b/drivers/media/dvb-frontends/dib0070.h @@ -48,7 +48,7 @@ struct dib0070_config { u8 vga_filter; }; -#if IS_ENABLED(CONFIG_DVB_TUNER_DIB0070) +#if IS_REACHABLE(CONFIG_DVB_TUNER_DIB0070) extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); extern u16 dib0070_wbd_offset(struct dvb_frontend *); extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open); diff --git a/drivers/media/dvb-frontends/dib0090.h b/drivers/media/dvb-frontends/dib0090.h index 6a090954fa10..ad74bc823f08 100644 --- a/drivers/media/dvb-frontends/dib0090.h +++ b/drivers/media/dvb-frontends/dib0090.h @@ -75,7 +75,7 @@ struct dib0090_config { u8 force_crystal_mode; }; -#if IS_ENABLED(CONFIG_DVB_TUNER_DIB0090) +#if IS_REACHABLE(CONFIG_DVB_TUNER_DIB0090) extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast); diff --git a/drivers/media/dvb-frontends/dib3000.h b/drivers/media/dvb-frontends/dib3000.h index 9b6c3bbc983a..6ae9899b5b45 100644 --- a/drivers/media/dvb-frontends/dib3000.h +++ b/drivers/media/dvb-frontends/dib3000.h @@ -41,7 +41,7 @@ struct dib_fe_xfer_ops int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl); }; -#if IS_ENABLED(CONFIG_DVB_DIB3000MB) +#if IS_REACHABLE(CONFIG_DVB_DIB3000MB) extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops); #else diff --git a/drivers/media/dvb-frontends/dib3000mc.h b/drivers/media/dvb-frontends/dib3000mc.h index 129d1425516a..74816f793611 100644 --- a/drivers/media/dvb-frontends/dib3000mc.h +++ b/drivers/media/dvb-frontends/dib3000mc.h @@ -41,7 +41,7 @@ struct dib3000mc_config { #define DEFAULT_DIB3000MC_I2C_ADDRESS 16 #define DEFAULT_DIB3000P_I2C_ADDRESS 24 -#if IS_ENABLED(CONFIG_DVB_DIB3000MC) +#if IS_REACHABLE(CONFIG_DVB_DIB3000MC) extern struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg); diff --git a/drivers/media/dvb-frontends/dib7000m.h b/drivers/media/dvb-frontends/dib7000m.h index b585413f9a29..6468c278cc4d 100644 --- a/drivers/media/dvb-frontends/dib7000m.h +++ b/drivers/media/dvb-frontends/dib7000m.h @@ -40,7 +40,7 @@ struct dib7000m_config { #define DEFAULT_DIB7000M_I2C_ADDRESS 18 -#if IS_ENABLED(CONFIG_DVB_DIB7000M) +#if IS_REACHABLE(CONFIG_DVB_DIB7000M) extern struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg); diff --git a/drivers/media/dvb-frontends/dib7000p.h b/drivers/media/dvb-frontends/dib7000p.h index 1fea0e972654..baa278928cf3 100644 --- a/drivers/media/dvb-frontends/dib7000p.h +++ b/drivers/media/dvb-frontends/dib7000p.h @@ -66,7 +66,7 @@ struct dib7000p_ops { struct dvb_frontend *(*init)(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); }; -#if IS_ENABLED(CONFIG_DVB_DIB7000P) +#if IS_REACHABLE(CONFIG_DVB_DIB7000P) void *dib7000p_attach(struct dib7000p_ops *ops); #else static inline void *dib7000p_attach(struct dib7000p_ops *ops) diff --git a/drivers/media/dvb-frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h index 84cc10383dcd..780c37bdcb72 100644 --- a/drivers/media/dvb-frontends/dib8000.h +++ b/drivers/media/dvb-frontends/dib8000.h @@ -63,7 +63,7 @@ struct dib8000_ops { struct dvb_frontend *(*init)(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg); }; -#if IS_ENABLED(CONFIG_DVB_DIB8000) +#if IS_REACHABLE(CONFIG_DVB_DIB8000) void *dib8000_attach(struct dib8000_ops *ops); #else static inline int dib8000_attach(struct dib8000_ops *ops) diff --git a/drivers/media/dvb-frontends/dib9000.h b/drivers/media/dvb-frontends/dib9000.h index f3639f045ff0..b10a70aa7c9f 100644 --- a/drivers/media/dvb-frontends/dib9000.h +++ b/drivers/media/dvb-frontends/dib9000.h @@ -27,7 +27,7 @@ struct dib9000_config { #define DEFAULT_DIB9000_I2C_ADDRESS 18 -#if IS_ENABLED(CONFIG_DVB_DIB9000) +#if IS_REACHABLE(CONFIG_DVB_DIB9000) extern struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg); extern int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr); extern struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe); diff --git a/drivers/media/dvb-frontends/drxd.h b/drivers/media/dvb-frontends/drxd.h index d998e4d5a7fc..a47c22d6667e 100644 --- a/drivers/media/dvb-frontends/drxd.h +++ b/drivers/media/dvb-frontends/drxd.h @@ -52,7 +52,7 @@ struct drxd_config { s16(*osc_deviation) (void *priv, s16 dev, int flag); }; -#if IS_ENABLED(CONFIG_DVB_DRXD) +#if IS_REACHABLE(CONFIG_DVB_DRXD) extern struct dvb_frontend *drxd_attach(const struct drxd_config *config, void *priv, struct i2c_adapter *i2c, diff --git a/drivers/media/dvb-frontends/drxk.h b/drivers/media/dvb-frontends/drxk.h index f6cb34660327..8f0b9eec528f 100644 --- a/drivers/media/dvb-frontends/drxk.h +++ b/drivers/media/dvb-frontends/drxk.h @@ -51,7 +51,7 @@ struct drxk_config { int qam_demod_parameter_count; }; -#if IS_ENABLED(CONFIG_DVB_DRXK) +#if IS_REACHABLE(CONFIG_DVB_DRXK) extern struct dvb_frontend *drxk_attach(const struct drxk_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/ds3000.h b/drivers/media/dvb-frontends/ds3000.h index f9c21fb7af13..153169da9017 100644 --- a/drivers/media/dvb-frontends/ds3000.h +++ b/drivers/media/dvb-frontends/ds3000.h @@ -35,7 +35,7 @@ struct ds3000_config { void (*set_lock_led)(struct dvb_frontend *fe, int offon); }; -#if IS_ENABLED(CONFIG_DVB_DS3000) +#if IS_REACHABLE(CONFIG_DVB_DS3000) extern struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/dvb-pll.h b/drivers/media/dvb-frontends/dvb-pll.h index f4b5a0601c3a..bf9602a88b6c 100644 --- a/drivers/media/dvb-frontends/dvb-pll.h +++ b/drivers/media/dvb-frontends/dvb-pll.h @@ -38,7 +38,7 @@ * @param pll_desc_id dvb_pll_desc to use. * @return Frontend pointer on success, NULL on failure */ -#if IS_ENABLED(CONFIG_DVB_PLL) +#if IS_REACHABLE(CONFIG_DVB_PLL) extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.h b/drivers/media/dvb-frontends/dvb_dummy_fe.h index 0cbf96105631..15e4ceab869a 100644 --- a/drivers/media/dvb-frontends/dvb_dummy_fe.h +++ b/drivers/media/dvb-frontends/dvb_dummy_fe.h @@ -26,7 +26,7 @@ #include #include "dvb_frontend.h" -#if IS_ENABLED(CONFIG_DVB_DUMMY_FE) +#if IS_REACHABLE(CONFIG_DVB_DUMMY_FE) extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void); extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void); extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void); diff --git a/drivers/media/dvb-frontends/ec100.h b/drivers/media/dvb-frontends/ec100.h index 37558403068d..9544bab5cd1d 100644 --- a/drivers/media/dvb-frontends/ec100.h +++ b/drivers/media/dvb-frontends/ec100.h @@ -31,7 +31,7 @@ struct ec100_config { }; -#if IS_ENABLED(CONFIG_DVB_EC100) +#if IS_REACHABLE(CONFIG_DVB_EC100) extern struct dvb_frontend *ec100_attach(const struct ec100_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/hd29l2.h b/drivers/media/dvb-frontends/hd29l2.h index 05cd13028a91..48e9ab74c883 100644 --- a/drivers/media/dvb-frontends/hd29l2.h +++ b/drivers/media/dvb-frontends/hd29l2.h @@ -51,7 +51,7 @@ struct hd29l2_config { }; -#if IS_ENABLED(CONFIG_DVB_HD29L2) +#if IS_REACHABLE(CONFIG_DVB_HD29L2) extern struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/isl6405.h b/drivers/media/dvb-frontends/isl6405.h index 8abb70c26fd9..3c148b830bd1 100644 --- a/drivers/media/dvb-frontends/isl6405.h +++ b/drivers/media/dvb-frontends/isl6405.h @@ -55,7 +55,7 @@ #define ISL6405_ENT2 0x20 #define ISL6405_ISEL2 0x40 -#if IS_ENABLED(CONFIG_DVB_ISL6405) +#if IS_REACHABLE(CONFIG_DVB_ISL6405) /* override_set and override_clear control which system register bits (above) * to always set & clear */ diff --git a/drivers/media/dvb-frontends/isl6421.h b/drivers/media/dvb-frontends/isl6421.h index 630e7f8a150e..3273597833fd 100644 --- a/drivers/media/dvb-frontends/isl6421.h +++ b/drivers/media/dvb-frontends/isl6421.h @@ -39,7 +39,7 @@ #define ISL6421_ISEL1 0x20 #define ISL6421_DCL 0x40 -#if IS_ENABLED(CONFIG_DVB_ISL6421) +#if IS_REACHABLE(CONFIG_DVB_ISL6421) /* override_set and override_clear control which system register bits (above) to always set & clear */ extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, u8 override_set, u8 override_clear, bool override_tone); diff --git a/drivers/media/dvb-frontends/isl6423.h b/drivers/media/dvb-frontends/isl6423.h index 80dfd9cc4f41..a64df0ee256b 100644 --- a/drivers/media/dvb-frontends/isl6423.h +++ b/drivers/media/dvb-frontends/isl6423.h @@ -42,7 +42,7 @@ struct isl6423_config { u8 mod_extern; }; -#if IS_ENABLED(CONFIG_DVB_ISL6423) +#if IS_REACHABLE(CONFIG_DVB_ISL6423) extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/itd1000.h b/drivers/media/dvb-frontends/itd1000.h index edae0902f4fd..a691bb6f26de 100644 --- a/drivers/media/dvb-frontends/itd1000.h +++ b/drivers/media/dvb-frontends/itd1000.h @@ -29,7 +29,7 @@ struct itd1000_config { u8 i2c_address; }; -#if IS_ENABLED(CONFIG_DVB_TUNER_ITD1000) +#if IS_REACHABLE(CONFIG_DVB_TUNER_ITD1000) extern struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg); #else static inline struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg) diff --git a/drivers/media/dvb-frontends/ix2505v.h b/drivers/media/dvb-frontends/ix2505v.h index 1a735a75aa98..af107a2dd357 100644 --- a/drivers/media/dvb-frontends/ix2505v.h +++ b/drivers/media/dvb-frontends/ix2505v.h @@ -49,7 +49,7 @@ struct ix2505v_config { }; -#if IS_ENABLED(CONFIG_DVB_IX2505V) +#if IS_REACHABLE(CONFIG_DVB_IX2505V) extern struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe, const struct ix2505v_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/l64781.h b/drivers/media/dvb-frontends/l64781.h index 6813b08a774d..8697e2c2ba36 100644 --- a/drivers/media/dvb-frontends/l64781.h +++ b/drivers/media/dvb-frontends/l64781.h @@ -31,7 +31,7 @@ struct l64781_config u8 demod_address; }; -#if IS_ENABLED(CONFIG_DVB_L64781) +#if IS_REACHABLE(CONFIG_DVB_L64781) extern struct dvb_frontend* l64781_attach(const struct l64781_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/lg2160.h b/drivers/media/dvb-frontends/lg2160.h index 194a07a78dc1..d20bd909de39 100644 --- a/drivers/media/dvb-frontends/lg2160.h +++ b/drivers/media/dvb-frontends/lg2160.h @@ -67,7 +67,7 @@ struct lg2160_config { enum lg_chip_type lg_chip; }; -#if IS_ENABLED(CONFIG_DVB_LG2160) +#if IS_REACHABLE(CONFIG_DVB_LG2160) extern struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, struct i2c_adapter *i2c_adap); diff --git a/drivers/media/dvb-frontends/lgdt3305.h b/drivers/media/dvb-frontends/lgdt3305.h index 9c03e530e01b..f91a1b49ce2f 100644 --- a/drivers/media/dvb-frontends/lgdt3305.h +++ b/drivers/media/dvb-frontends/lgdt3305.h @@ -80,7 +80,7 @@ struct lgdt3305_config { enum lgdt_demod_chip_type demod_chip; }; -#if IS_ENABLED(CONFIG_DVB_LGDT3305) +#if IS_REACHABLE(CONFIG_DVB_LGDT3305) extern struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, struct i2c_adapter *i2c_adap); diff --git a/drivers/media/dvb-frontends/lgdt330x.h b/drivers/media/dvb-frontends/lgdt330x.h index 8bb332219fc4..c73eeb45e330 100644 --- a/drivers/media/dvb-frontends/lgdt330x.h +++ b/drivers/media/dvb-frontends/lgdt330x.h @@ -52,7 +52,7 @@ struct lgdt330x_config int clock_polarity_flip; }; -#if IS_ENABLED(CONFIG_DVB_LGDT330X) +#if IS_REACHABLE(CONFIG_DVB_LGDT330X) extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/lgs8gl5.h b/drivers/media/dvb-frontends/lgs8gl5.h index c2da59614727..a5b3faf121f0 100644 --- a/drivers/media/dvb-frontends/lgs8gl5.h +++ b/drivers/media/dvb-frontends/lgs8gl5.h @@ -31,7 +31,7 @@ struct lgs8gl5_config { u8 demod_address; }; -#if IS_ENABLED(CONFIG_DVB_LGS8GL5) +#if IS_REACHABLE(CONFIG_DVB_LGS8GL5) extern struct dvb_frontend *lgs8gl5_attach( const struct lgs8gl5_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/lgs8gxx.h b/drivers/media/dvb-frontends/lgs8gxx.h index dadb78bf61a9..368c9928ef7f 100644 --- a/drivers/media/dvb-frontends/lgs8gxx.h +++ b/drivers/media/dvb-frontends/lgs8gxx.h @@ -80,7 +80,7 @@ struct lgs8gxx_config { u8 tuner_address; }; -#if IS_ENABLED(CONFIG_DVB_LGS8GXX) +#if IS_REACHABLE(CONFIG_DVB_LGS8GXX) extern struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/lnbh24.h b/drivers/media/dvb-frontends/lnbh24.h index b327a4f31d16..a088b8ec1e53 100644 --- a/drivers/media/dvb-frontends/lnbh24.h +++ b/drivers/media/dvb-frontends/lnbh24.h @@ -37,7 +37,7 @@ #include -#if IS_ENABLED(CONFIG_DVB_LNBP21) +#if IS_REACHABLE(CONFIG_DVB_LNBP21) /* override_set and override_clear control which system register bits (above) to always set & clear */ extern struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/lnbp21.h b/drivers/media/dvb-frontends/lnbp21.h index dbcbcc2f20a3..a9b530de62a6 100644 --- a/drivers/media/dvb-frontends/lnbp21.h +++ b/drivers/media/dvb-frontends/lnbp21.h @@ -57,7 +57,7 @@ #include -#if IS_ENABLED(CONFIG_DVB_LNBP21) +#if IS_REACHABLE(CONFIG_DVB_LNBP21) /* override_set and override_clear control which system register bits (above) to always set & clear */ extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/lnbp22.h b/drivers/media/dvb-frontends/lnbp22.h index 63861b311dd8..628148385182 100644 --- a/drivers/media/dvb-frontends/lnbp22.h +++ b/drivers/media/dvb-frontends/lnbp22.h @@ -39,7 +39,7 @@ #include -#if IS_ENABLED(CONFIG_DVB_LNBP22) +#if IS_REACHABLE(CONFIG_DVB_LNBP22) /* * override_set and override_clear control which system register bits (above) * to always set & clear diff --git a/drivers/media/dvb-frontends/m88rs2000.h b/drivers/media/dvb-frontends/m88rs2000.h index 0a50ea90736b..de7430178e9e 100644 --- a/drivers/media/dvb-frontends/m88rs2000.h +++ b/drivers/media/dvb-frontends/m88rs2000.h @@ -41,7 +41,7 @@ enum { CALL_IS_READ, }; -#if IS_ENABLED(CONFIG_DVB_M88RS2000) +#if IS_REACHABLE(CONFIG_DVB_M88RS2000) extern struct dvb_frontend *m88rs2000_attach( const struct m88rs2000_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/mb86a16.h b/drivers/media/dvb-frontends/mb86a16.h index 277ce061acf9..e486dc0d8e60 100644 --- a/drivers/media/dvb-frontends/mb86a16.h +++ b/drivers/media/dvb-frontends/mb86a16.h @@ -33,7 +33,7 @@ struct mb86a16_config { -#if IS_ENABLED(CONFIG_DVB_MB86A16) +#if IS_REACHABLE(CONFIG_DVB_MB86A16) extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config, struct i2c_adapter *i2c_adap); diff --git a/drivers/media/dvb-frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h index cbeb941fba7c..f749c8ac5f39 100644 --- a/drivers/media/dvb-frontends/mb86a20s.h +++ b/drivers/media/dvb-frontends/mb86a20s.h @@ -34,7 +34,7 @@ struct mb86a20s_config { bool is_serial; }; -#if IS_ENABLED(CONFIG_DVB_MB86A20S) +#if IS_REACHABLE(CONFIG_DVB_MB86A20S) extern struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, struct i2c_adapter *i2c); extern struct i2c_adapter *mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *); diff --git a/drivers/media/dvb-frontends/mt312.h b/drivers/media/dvb-frontends/mt312.h index 5706621ad79d..386939a90555 100644 --- a/drivers/media/dvb-frontends/mt312.h +++ b/drivers/media/dvb-frontends/mt312.h @@ -36,7 +36,7 @@ struct mt312_config { unsigned int voltage_inverted:1; }; -#if IS_ENABLED(CONFIG_DVB_MT312) +#if IS_REACHABLE(CONFIG_DVB_MT312) struct dvb_frontend *mt312_attach(const struct mt312_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/mt352.h b/drivers/media/dvb-frontends/mt352.h index 451d904e1500..5873263bd1af 100644 --- a/drivers/media/dvb-frontends/mt352.h +++ b/drivers/media/dvb-frontends/mt352.h @@ -51,7 +51,7 @@ struct mt352_config int (*demod_init)(struct dvb_frontend* fe); }; -#if IS_ENABLED(CONFIG_DVB_MT352) +#if IS_REACHABLE(CONFIG_DVB_MT352) extern struct dvb_frontend* mt352_attach(const struct mt352_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/nxt200x.h b/drivers/media/dvb-frontends/nxt200x.h index e38d01fb6c2b..825b928ef542 100644 --- a/drivers/media/dvb-frontends/nxt200x.h +++ b/drivers/media/dvb-frontends/nxt200x.h @@ -42,7 +42,7 @@ struct nxt200x_config int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); }; -#if IS_ENABLED(CONFIG_DVB_NXT200X) +#if IS_REACHABLE(CONFIG_DVB_NXT200X) extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/nxt6000.h b/drivers/media/dvb-frontends/nxt6000.h index b5867c2ae681..a94cefcc6dfd 100644 --- a/drivers/media/dvb-frontends/nxt6000.h +++ b/drivers/media/dvb-frontends/nxt6000.h @@ -33,7 +33,7 @@ struct nxt6000_config u8 clock_inversion:1; }; -#if IS_ENABLED(CONFIG_DVB_NXT6000) +#if IS_REACHABLE(CONFIG_DVB_NXT6000) extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/or51132.h b/drivers/media/dvb-frontends/or51132.h index cdb5be3c65d6..9acf8dc87413 100644 --- a/drivers/media/dvb-frontends/or51132.h +++ b/drivers/media/dvb-frontends/or51132.h @@ -34,7 +34,7 @@ struct or51132_config int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); }; -#if IS_ENABLED(CONFIG_DVB_OR51132) +#if IS_REACHABLE(CONFIG_DVB_OR51132) extern struct dvb_frontend* or51132_attach(const struct or51132_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/or51211.h b/drivers/media/dvb-frontends/or51211.h index 9a8ae936b62d..cc6adab63249 100644 --- a/drivers/media/dvb-frontends/or51211.h +++ b/drivers/media/dvb-frontends/or51211.h @@ -37,7 +37,7 @@ struct or51211_config void (*sleep)(struct dvb_frontend * fe); }; -#if IS_ENABLED(CONFIG_DVB_OR51211) +#if IS_REACHABLE(CONFIG_DVB_OR51211) extern struct dvb_frontend* or51211_attach(const struct or51211_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/s5h1409.h b/drivers/media/dvb-frontends/s5h1409.h index 9e143f5c8107..f58b9ca5557a 100644 --- a/drivers/media/dvb-frontends/s5h1409.h +++ b/drivers/media/dvb-frontends/s5h1409.h @@ -67,7 +67,7 @@ struct s5h1409_config { u8 hvr1600_opt; }; -#if IS_ENABLED(CONFIG_DVB_S5H1409) +#if IS_REACHABLE(CONFIG_DVB_S5H1409) extern struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/s5h1411.h b/drivers/media/dvb-frontends/s5h1411.h index 1d7deb615674..f3a87f7ec360 100644 --- a/drivers/media/dvb-frontends/s5h1411.h +++ b/drivers/media/dvb-frontends/s5h1411.h @@ -69,7 +69,7 @@ struct s5h1411_config { u8 status_mode; }; -#if IS_ENABLED(CONFIG_DVB_S5H1411) +#if IS_REACHABLE(CONFIG_DVB_S5H1411) extern struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/s5h1420.h b/drivers/media/dvb-frontends/s5h1420.h index 210049b5cf30..142d93e7d02b 100644 --- a/drivers/media/dvb-frontends/s5h1420.h +++ b/drivers/media/dvb-frontends/s5h1420.h @@ -40,7 +40,7 @@ struct s5h1420_config u8 serial_mpeg:1; }; -#if IS_ENABLED(CONFIG_DVB_S5H1420) +#if IS_REACHABLE(CONFIG_DVB_S5H1420) extern struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, struct i2c_adapter *i2c); extern struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe); diff --git a/drivers/media/dvb-frontends/s5h1432.h b/drivers/media/dvb-frontends/s5h1432.h index 70917dd2533a..f490c5ee5801 100644 --- a/drivers/media/dvb-frontends/s5h1432.h +++ b/drivers/media/dvb-frontends/s5h1432.h @@ -75,7 +75,7 @@ struct s5h1432_config { u8 status_mode; }; -#if IS_ENABLED(CONFIG_DVB_S5H1432) +#if IS_REACHABLE(CONFIG_DVB_S5H1432) extern struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/s921.h b/drivers/media/dvb-frontends/s921.h index 9b20c9e0eb88..7d3999a4e974 100644 --- a/drivers/media/dvb-frontends/s921.h +++ b/drivers/media/dvb-frontends/s921.h @@ -25,7 +25,7 @@ struct s921_config { u8 demod_address; }; -#if IS_ENABLED(CONFIG_DVB_S921) +#if IS_REACHABLE(CONFIG_DVB_S921) extern struct dvb_frontend *s921_attach(const struct s921_config *config, struct i2c_adapter *i2c); extern struct i2c_adapter *s921_get_tuner_i2c_adapter(struct dvb_frontend *); diff --git a/drivers/media/dvb-frontends/si21xx.h b/drivers/media/dvb-frontends/si21xx.h index 1509fed44a3a..ef5f351ca68e 100644 --- a/drivers/media/dvb-frontends/si21xx.h +++ b/drivers/media/dvb-frontends/si21xx.h @@ -13,7 +13,7 @@ struct si21xx_config { int min_delay_ms; }; -#if IS_ENABLED(CONFIG_DVB_SI21XX) +#if IS_REACHABLE(CONFIG_DVB_SI21XX) extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/sp8870.h b/drivers/media/dvb-frontends/sp8870.h index 065ec67d4e30..f507b9fd707b 100644 --- a/drivers/media/dvb-frontends/sp8870.h +++ b/drivers/media/dvb-frontends/sp8870.h @@ -35,7 +35,7 @@ struct sp8870_config int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; -#if IS_ENABLED(CONFIG_DVB_SP8870) +#if IS_REACHABLE(CONFIG_DVB_SP8870) extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/sp887x.h b/drivers/media/dvb-frontends/sp887x.h index 2cdc4e8bc9cd..412f011e6dfd 100644 --- a/drivers/media/dvb-frontends/sp887x.h +++ b/drivers/media/dvb-frontends/sp887x.h @@ -17,7 +17,7 @@ struct sp887x_config int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; -#if IS_ENABLED(CONFIG_DVB_SP887X) +#if IS_REACHABLE(CONFIG_DVB_SP887X) extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/stb0899_drv.h b/drivers/media/dvb-frontends/stb0899_drv.h index 139264d19263..0a72131a57db 100644 --- a/drivers/media/dvb-frontends/stb0899_drv.h +++ b/drivers/media/dvb-frontends/stb0899_drv.h @@ -141,7 +141,7 @@ struct stb0899_config { int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain); }; -#if IS_ENABLED(CONFIG_DVB_STB0899) +#if IS_REACHABLE(CONFIG_DVB_STB0899) extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/stb6000.h b/drivers/media/dvb-frontends/stb6000.h index a768189bfaad..da581b652cb9 100644 --- a/drivers/media/dvb-frontends/stb6000.h +++ b/drivers/media/dvb-frontends/stb6000.h @@ -35,7 +35,7 @@ * @param i2c i2c adapter to use. * @return FE pointer on success, NULL on failure. */ -#if IS_ENABLED(CONFIG_DVB_STB6000) +#if IS_REACHABLE(CONFIG_DVB_STB6000) extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/stb6100.h b/drivers/media/dvb-frontends/stb6100.h index 3a1e40f3b8be..218c8188865d 100644 --- a/drivers/media/dvb-frontends/stb6100.h +++ b/drivers/media/dvb-frontends/stb6100.h @@ -94,7 +94,7 @@ struct stb6100_state { u32 reference; }; -#if IS_ENABLED(CONFIG_DVB_STB6100) +#if IS_REACHABLE(CONFIG_DVB_STB6100) extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, const struct stb6100_config *config, diff --git a/drivers/media/dvb-frontends/stv0288.h b/drivers/media/dvb-frontends/stv0288.h index a0bd93107154..b58603c00c80 100644 --- a/drivers/media/dvb-frontends/stv0288.h +++ b/drivers/media/dvb-frontends/stv0288.h @@ -43,7 +43,7 @@ struct stv0288_config { int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); }; -#if IS_ENABLED(CONFIG_DVB_STV0288) +#if IS_REACHABLE(CONFIG_DVB_STV0288) extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/stv0297.h b/drivers/media/dvb-frontends/stv0297.h index c8ff3639ce00..b30632a67333 100644 --- a/drivers/media/dvb-frontends/stv0297.h +++ b/drivers/media/dvb-frontends/stv0297.h @@ -42,7 +42,7 @@ struct stv0297_config u8 stop_during_read:1; }; -#if IS_ENABLED(CONFIG_DVB_STV0297) +#if IS_REACHABLE(CONFIG_DVB_STV0297) extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/stv0299.h b/drivers/media/dvb-frontends/stv0299.h index 06f70fc8327b..0aca30a8ec25 100644 --- a/drivers/media/dvb-frontends/stv0299.h +++ b/drivers/media/dvb-frontends/stv0299.h @@ -95,7 +95,7 @@ struct stv0299_config int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); }; -#if IS_ENABLED(CONFIG_DVB_STV0299) +#if IS_REACHABLE(CONFIG_DVB_STV0299) extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/stv0367.h b/drivers/media/dvb-frontends/stv0367.h index ea80b341f094..92b3e85fb818 100644 --- a/drivers/media/dvb-frontends/stv0367.h +++ b/drivers/media/dvb-frontends/stv0367.h @@ -39,7 +39,7 @@ struct stv0367_config { int clk_pol; }; -#if IS_ENABLED(CONFIG_DVB_STV0367) +#if IS_REACHABLE(CONFIG_DVB_STV0367) extern struct dvb_frontend *stv0367ter_attach(const struct stv0367_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/stv0900.h b/drivers/media/dvb-frontends/stv0900.h index e2a6dc69ecb4..c90bf00ea9ce 100644 --- a/drivers/media/dvb-frontends/stv0900.h +++ b/drivers/media/dvb-frontends/stv0900.h @@ -58,7 +58,7 @@ struct stv0900_config { void (*set_lock_led)(struct dvb_frontend *fe, int offon); }; -#if IS_ENABLED(CONFIG_DVB_STV0900) +#if IS_REACHABLE(CONFIG_DVB_STV0900) extern struct dvb_frontend *stv0900_attach(const struct stv0900_config *config, struct i2c_adapter *i2c, int demod); #else diff --git a/drivers/media/dvb-frontends/stv090x.h b/drivers/media/dvb-frontends/stv090x.h index 742eeda99000..012e55e5032e 100644 --- a/drivers/media/dvb-frontends/stv090x.h +++ b/drivers/media/dvb-frontends/stv090x.h @@ -107,7 +107,7 @@ struct stv090x_config { u8 xor_value); }; -#if IS_ENABLED(CONFIG_DVB_STV090x) +#if IS_REACHABLE(CONFIG_DVB_STV090x) struct dvb_frontend *stv090x_attach(struct stv090x_config *config, struct i2c_adapter *i2c, diff --git a/drivers/media/dvb-frontends/stv6110.h b/drivers/media/dvb-frontends/stv6110.h index 8fa07e6a6745..f3c8a5c6b77d 100644 --- a/drivers/media/dvb-frontends/stv6110.h +++ b/drivers/media/dvb-frontends/stv6110.h @@ -46,7 +46,7 @@ struct stv6110_config { u8 clk_div; /* divisor value for the output clock */ }; -#if IS_ENABLED(CONFIG_DVB_STV6110) +#if IS_REACHABLE(CONFIG_DVB_STV6110) extern struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe, const struct stv6110_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/stv6110x.h b/drivers/media/dvb-frontends/stv6110x.h index bc4766db29c5..9f7eb251aec3 100644 --- a/drivers/media/dvb-frontends/stv6110x.h +++ b/drivers/media/dvb-frontends/stv6110x.h @@ -53,7 +53,7 @@ struct stv6110x_devctl { }; -#if IS_ENABLED(CONFIG_DVB_STV6110x) +#if IS_REACHABLE(CONFIG_DVB_STV6110x) extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, const struct stv6110x_config *config, diff --git a/drivers/media/dvb-frontends/tda1002x.h b/drivers/media/dvb-frontends/tda1002x.h index e404b6e44802..0d334613de1b 100644 --- a/drivers/media/dvb-frontends/tda1002x.h +++ b/drivers/media/dvb-frontends/tda1002x.h @@ -57,7 +57,7 @@ struct tda10023_config { u16 deltaf; }; -#if IS_ENABLED(CONFIG_DVB_TDA10021) +#if IS_REACHABLE(CONFIG_DVB_TDA10021) extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, struct i2c_adapter* i2c, u8 pwm); #else @@ -69,7 +69,7 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* } #endif // CONFIG_DVB_TDA10021 -#if IS_ENABLED(CONFIG_DVB_TDA10023) +#if IS_REACHABLE(CONFIG_DVB_TDA10023) extern struct dvb_frontend *tda10023_attach( const struct tda10023_config *config, struct i2c_adapter *i2c, u8 pwm); diff --git a/drivers/media/dvb-frontends/tda10048.h b/drivers/media/dvb-frontends/tda10048.h index 5e7bf4e47cb3..bc77a7311de1 100644 --- a/drivers/media/dvb-frontends/tda10048.h +++ b/drivers/media/dvb-frontends/tda10048.h @@ -73,7 +73,7 @@ struct tda10048_config { u8 pll_n; }; -#if IS_ENABLED(CONFIG_DVB_TDA10048) +#if IS_REACHABLE(CONFIG_DVB_TDA10048) extern struct dvb_frontend *tda10048_attach( const struct tda10048_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/tda1004x.h b/drivers/media/dvb-frontends/tda1004x.h index dd283fbb61c0..efd7659dace9 100644 --- a/drivers/media/dvb-frontends/tda1004x.h +++ b/drivers/media/dvb-frontends/tda1004x.h @@ -117,7 +117,7 @@ struct tda1004x_state { enum tda1004x_demod demod_type; }; -#if IS_ENABLED(CONFIG_DVB_TDA1004X) +#if IS_REACHABLE(CONFIG_DVB_TDA1004X) extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, struct i2c_adapter* i2c); diff --git a/drivers/media/dvb-frontends/tda10071.h b/drivers/media/dvb-frontends/tda10071.h index 331b5a819383..da89f4249846 100644 --- a/drivers/media/dvb-frontends/tda10071.h +++ b/drivers/media/dvb-frontends/tda10071.h @@ -72,7 +72,7 @@ struct tda10071_config { }; -#if IS_ENABLED(CONFIG_DVB_TDA10071) +#if IS_REACHABLE(CONFIG_DVB_TDA10071) extern struct dvb_frontend *tda10071_attach( const struct tda10071_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/tda10086.h b/drivers/media/dvb-frontends/tda10086.h index 458fe91c1b88..690e469995b6 100644 --- a/drivers/media/dvb-frontends/tda10086.h +++ b/drivers/media/dvb-frontends/tda10086.h @@ -46,7 +46,7 @@ struct tda10086_config enum tda10086_xtal xtal_freq; }; -#if IS_ENABLED(CONFIG_DVB_TDA10086) +#if IS_REACHABLE(CONFIG_DVB_TDA10086) extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/tda18271c2dd.h b/drivers/media/dvb-frontends/tda18271c2dd.h index dd84f7b69bec..7ebd8eaff4eb 100644 --- a/drivers/media/dvb-frontends/tda18271c2dd.h +++ b/drivers/media/dvb-frontends/tda18271c2dd.h @@ -3,7 +3,7 @@ #include -#if IS_ENABLED(CONFIG_DVB_TDA18271C2DD) +#if IS_REACHABLE(CONFIG_DVB_TDA18271C2DD) struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 adr); #else diff --git a/drivers/media/dvb-frontends/tda665x.h b/drivers/media/dvb-frontends/tda665x.h index 03a0da6d5cf2..baf520baa42e 100644 --- a/drivers/media/dvb-frontends/tda665x.h +++ b/drivers/media/dvb-frontends/tda665x.h @@ -31,7 +31,7 @@ struct tda665x_config { u32 ref_divider; }; -#if IS_ENABLED(CONFIG_DVB_TDA665x) +#if IS_REACHABLE(CONFIG_DVB_TDA665x) extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, const struct tda665x_config *config, diff --git a/drivers/media/dvb-frontends/tda8083.h b/drivers/media/dvb-frontends/tda8083.h index de6b1860dfdd..46be06fa7e0d 100644 --- a/drivers/media/dvb-frontends/tda8083.h +++ b/drivers/media/dvb-frontends/tda8083.h @@ -35,7 +35,7 @@ struct tda8083_config u8 demod_address; }; -#if IS_ENABLED(CONFIG_DVB_TDA8083) +#if IS_REACHABLE(CONFIG_DVB_TDA8083) extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/tda8261.h b/drivers/media/dvb-frontends/tda8261.h index 55cf4ffcbfdf..9fa5b3076d5b 100644 --- a/drivers/media/dvb-frontends/tda8261.h +++ b/drivers/media/dvb-frontends/tda8261.h @@ -34,7 +34,7 @@ struct tda8261_config { enum tda8261_step step_size; }; -#if IS_ENABLED(CONFIG_DVB_TDA8261) +#if IS_REACHABLE(CONFIG_DVB_TDA8261) extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, const struct tda8261_config *config, diff --git a/drivers/media/dvb-frontends/tda826x.h b/drivers/media/dvb-frontends/tda826x.h index 5f0f20e7e4f8..81abe1aebe9f 100644 --- a/drivers/media/dvb-frontends/tda826x.h +++ b/drivers/media/dvb-frontends/tda826x.h @@ -35,7 +35,7 @@ * @param has_loopthrough Set to 1 if the card has a loopthrough RF connector. * @return FE pointer on success, NULL on failure. */ -#if IS_ENABLED(CONFIG_DVB_TDA826X) +#if IS_REACHABLE(CONFIG_DVB_TDA826X) extern struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, int has_loopthrough); diff --git a/drivers/media/dvb-frontends/ts2020.h b/drivers/media/dvb-frontends/ts2020.h index 8a08dccc217f..1714af94eca2 100644 --- a/drivers/media/dvb-frontends/ts2020.h +++ b/drivers/media/dvb-frontends/ts2020.h @@ -54,7 +54,7 @@ struct ts2020_config { struct dvb_frontend *fe; }; -#if IS_ENABLED(CONFIG_DVB_TS2020) +#if IS_REACHABLE(CONFIG_DVB_TS2020) extern struct dvb_frontend *ts2020_attach( struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/tua6100.h b/drivers/media/dvb-frontends/tua6100.h index 83a9c30e67ca..52919e04e258 100644 --- a/drivers/media/dvb-frontends/tua6100.h +++ b/drivers/media/dvb-frontends/tua6100.h @@ -34,7 +34,7 @@ #include #include "dvb_frontend.h" -#if IS_ENABLED(CONFIG_DVB_TUA6100) +#if IS_REACHABLE(CONFIG_DVB_TUA6100) extern struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c); #else static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c) diff --git a/drivers/media/dvb-frontends/ves1820.h b/drivers/media/dvb-frontends/ves1820.h index c073f353ac38..ece46fdcd714 100644 --- a/drivers/media/dvb-frontends/ves1820.h +++ b/drivers/media/dvb-frontends/ves1820.h @@ -41,7 +41,7 @@ struct ves1820_config u8 selagc:1; }; -#if IS_ENABLED(CONFIG_DVB_VES1820) +#if IS_REACHABLE(CONFIG_DVB_VES1820) extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, struct i2c_adapter* i2c, u8 pwm); #else diff --git a/drivers/media/dvb-frontends/ves1x93.h b/drivers/media/dvb-frontends/ves1x93.h index 2307caea6aec..4510fe2f6676 100644 --- a/drivers/media/dvb-frontends/ves1x93.h +++ b/drivers/media/dvb-frontends/ves1x93.h @@ -40,7 +40,7 @@ struct ves1x93_config u8 invert_pwm:1; }; -#if IS_ENABLED(CONFIG_DVB_VES1X93) +#if IS_REACHABLE(CONFIG_DVB_VES1X93) extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/zl10036.h b/drivers/media/dvb-frontends/zl10036.h index 5f1e8217eeb6..670e76a654ee 100644 --- a/drivers/media/dvb-frontends/zl10036.h +++ b/drivers/media/dvb-frontends/zl10036.h @@ -38,7 +38,7 @@ struct zl10036_config { int rf_loop_enable; }; -#if IS_ENABLED(CONFIG_DVB_ZL10036) +#if IS_REACHABLE(CONFIG_DVB_ZL10036) extern struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe, const struct zl10036_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/zl10039.h b/drivers/media/dvb-frontends/zl10039.h index 750b9bca9d02..070929444e71 100644 --- a/drivers/media/dvb-frontends/zl10039.h +++ b/drivers/media/dvb-frontends/zl10039.h @@ -24,7 +24,7 @@ #include -#if IS_ENABLED(CONFIG_DVB_ZL10039) +#if IS_REACHABLE(CONFIG_DVB_ZL10039) struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, u8 i2c_addr, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/zl10353.h b/drivers/media/dvb-frontends/zl10353.h index 50c1004aef36..37aa6e8f454a 100644 --- a/drivers/media/dvb-frontends/zl10353.h +++ b/drivers/media/dvb-frontends/zl10353.h @@ -47,7 +47,7 @@ struct zl10353_config u8 pll_0; /* default: 0x15 */ }; -#if IS_ENABLED(CONFIG_DVB_ZL10353) +#if IS_REACHABLE(CONFIG_DVB_ZL10353) extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h index 5028f0cf83f4..6c511723fd1b 100644 --- a/drivers/media/pci/cx23885/altera-ci.h +++ b/drivers/media/pci/cx23885/altera-ci.h @@ -39,7 +39,7 @@ struct altera_ci_config { int (*fpga_rw) (void *dev, int ad_rg, int val, int rw); }; -#if IS_ENABLED(CONFIG_MEDIA_ALTERA_CI) +#if IS_REACHABLE(CONFIG_MEDIA_ALTERA_CI) extern int altera_ci_init(struct altera_ci_config *config, int ci_nr); extern void altera_ci_release(void *dev, int ci_nr); diff --git a/drivers/media/tuners/fc0011.h b/drivers/media/tuners/fc0011.h index 43ec893a6877..81bb568d6943 100644 --- a/drivers/media/tuners/fc0011.h +++ b/drivers/media/tuners/fc0011.h @@ -23,7 +23,7 @@ enum fc0011_fe_callback_commands { FC0011_FE_CALLBACK_RESET, }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0011) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_FC0011) struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct fc0011_config *config); diff --git a/drivers/media/tuners/fc0012.h b/drivers/media/tuners/fc0012.h index 1d08057e3275..9ad32859bab0 100644 --- a/drivers/media/tuners/fc0012.h +++ b/drivers/media/tuners/fc0012.h @@ -49,7 +49,7 @@ struct fc0012_config { bool clock_out; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0012) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_FC0012) extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct fc0012_config *cfg); diff --git a/drivers/media/tuners/fc0013.h b/drivers/media/tuners/fc0013.h index d65d5b37f56e..e130bd7a3230 100644 --- a/drivers/media/tuners/fc0013.h +++ b/drivers/media/tuners/fc0013.h @@ -26,7 +26,7 @@ #include "dvb_frontend.h" #include "fc001x-common.h" -#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0013) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_FC0013) extern struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_address, int dual_master, diff --git a/drivers/media/tuners/fc2580.h b/drivers/media/tuners/fc2580.h index 9c43c1cc82d9..b1ce6770f88e 100644 --- a/drivers/media/tuners/fc2580.h +++ b/drivers/media/tuners/fc2580.h @@ -37,7 +37,7 @@ struct fc2580_config { u32 clock; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC2580) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_FC2580) extern struct dvb_frontend *fc2580_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct fc2580_config *cfg); #else diff --git a/drivers/media/tuners/max2165.h b/drivers/media/tuners/max2165.h index 26e1dc64bb67..5054f01a78fb 100644 --- a/drivers/media/tuners/max2165.h +++ b/drivers/media/tuners/max2165.h @@ -32,7 +32,7 @@ struct max2165_config { u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */ }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MAX2165) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MAX2165) extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct max2165_config *cfg); diff --git a/drivers/media/tuners/mc44s803.h b/drivers/media/tuners/mc44s803.h index 9aae50aca2b7..b3e614be657d 100644 --- a/drivers/media/tuners/mc44s803.h +++ b/drivers/media/tuners/mc44s803.h @@ -32,7 +32,7 @@ struct mc44s803_config { u8 dig_out; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MC44S803) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MC44S803) extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mc44s803_config *cfg); #else diff --git a/drivers/media/tuners/mt2060.h b/drivers/media/tuners/mt2060.h index c64fc19cb278..6efed359a24f 100644 --- a/drivers/media/tuners/mt2060.h +++ b/drivers/media/tuners/mt2060.h @@ -30,7 +30,7 @@ struct mt2060_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2060) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT2060) extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1); #else static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) diff --git a/drivers/media/tuners/mt2063.h b/drivers/media/tuners/mt2063.h index e1acfc8e7ae3..e55e0a6dd1be 100644 --- a/drivers/media/tuners/mt2063.h +++ b/drivers/media/tuners/mt2063.h @@ -8,7 +8,7 @@ struct mt2063_config { u32 refclock; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2063) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT2063) struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, struct mt2063_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/tuners/mt20xx.h b/drivers/media/tuners/mt20xx.h index f56241ccaa00..9912362b415e 100644 --- a/drivers/media/tuners/mt20xx.h +++ b/drivers/media/tuners/mt20xx.h @@ -20,7 +20,7 @@ #include #include "dvb_frontend.h" -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT20XX) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT20XX) extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); diff --git a/drivers/media/tuners/mt2131.h b/drivers/media/tuners/mt2131.h index 837c854b9c65..8267a6ae5d84 100644 --- a/drivers/media/tuners/mt2131.h +++ b/drivers/media/tuners/mt2131.h @@ -30,7 +30,7 @@ struct mt2131_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2131) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT2131) extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, diff --git a/drivers/media/tuners/mt2266.h b/drivers/media/tuners/mt2266.h index fad6dd657d77..69abefa18c37 100644 --- a/drivers/media/tuners/mt2266.h +++ b/drivers/media/tuners/mt2266.h @@ -24,7 +24,7 @@ struct mt2266_config { u8 i2c_address; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2266) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT2266) extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); #else static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) diff --git a/drivers/media/tuners/mxl5005s.h b/drivers/media/tuners/mxl5005s.h index ae8db885ad87..5764b12c5c7c 100644 --- a/drivers/media/tuners/mxl5005s.h +++ b/drivers/media/tuners/mxl5005s.h @@ -118,7 +118,7 @@ struct mxl5005s_config { u8 AgcMasterByte; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MXL5005S) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MXL5005S) extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mxl5005s_config *config); diff --git a/drivers/media/tuners/mxl5007t.h b/drivers/media/tuners/mxl5007t.h index ae7037d681c5..e786d1f23ff1 100644 --- a/drivers/media/tuners/mxl5007t.h +++ b/drivers/media/tuners/mxl5007t.h @@ -77,7 +77,7 @@ struct mxl5007t_config { unsigned int clk_out_enable:1; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MXL5007T) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MXL5007T) extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 addr, struct mxl5007t_config *cfg); diff --git a/drivers/media/tuners/qt1010.h b/drivers/media/tuners/qt1010.h index 8ab5d479749f..e3198f23437c 100644 --- a/drivers/media/tuners/qt1010.h +++ b/drivers/media/tuners/qt1010.h @@ -36,7 +36,7 @@ struct qt1010_config { * @param cfg tuner hw based configuration * @return fe pointer on success, NULL on failure */ -#if IS_ENABLED(CONFIG_MEDIA_TUNER_QT1010) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_QT1010) extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct qt1010_config *cfg); diff --git a/drivers/media/tuners/r820t.h b/drivers/media/tuners/r820t.h index 48af3548027d..b1e5661af1c7 100644 --- a/drivers/media/tuners/r820t.h +++ b/drivers/media/tuners/r820t.h @@ -42,7 +42,7 @@ struct r820t_config { bool use_predetect; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_R820T) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_R820T) struct dvb_frontend *r820t_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct r820t_config *cfg); diff --git a/drivers/media/tuners/tda18218.h b/drivers/media/tuners/tda18218.h index 366410e0cc9a..1eacb4f84e93 100644 --- a/drivers/media/tuners/tda18218.h +++ b/drivers/media/tuners/tda18218.h @@ -30,7 +30,7 @@ struct tda18218_config { u8 loop_through:1; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18218) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA18218) extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct tda18218_config *cfg); #else diff --git a/drivers/media/tuners/tda18271.h b/drivers/media/tuners/tda18271.h index 4c418d63f540..0a846333ce57 100644 --- a/drivers/media/tuners/tda18271.h +++ b/drivers/media/tuners/tda18271.h @@ -121,7 +121,7 @@ enum tda18271_mode { TDA18271_DIGITAL, }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18271) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA18271) extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, struct i2c_adapter *i2c, struct tda18271_config *cfg); diff --git a/drivers/media/tuners/tda827x.h b/drivers/media/tuners/tda827x.h index b64292152baf..abf2e2fe5350 100644 --- a/drivers/media/tuners/tda827x.h +++ b/drivers/media/tuners/tda827x.h @@ -51,7 +51,7 @@ struct tda827x_config * @param cfg optional callback function pointers. * @return FE pointer on success, NULL on failure. */ -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA827X) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA827X) extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, struct tda827x_config *cfg); diff --git a/drivers/media/tuners/tda8290.h b/drivers/media/tuners/tda8290.h index cf96e585785e..901b8cac7105 100644 --- a/drivers/media/tuners/tda8290.h +++ b/drivers/media/tuners/tda8290.h @@ -38,7 +38,7 @@ struct tda829x_config { struct tda18271_std_map *tda18271_std_map; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA8290) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA8290) extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, diff --git a/drivers/media/tuners/tda9887.h b/drivers/media/tuners/tda9887.h index 37a4a1123e0c..95070eca02ca 100644 --- a/drivers/media/tuners/tda9887.h +++ b/drivers/media/tuners/tda9887.h @@ -21,7 +21,7 @@ #include "dvb_frontend.h" /* ------------------------------------------------------------------------ */ -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA9887) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA9887) extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr); diff --git a/drivers/media/tuners/tea5761.h b/drivers/media/tuners/tea5761.h index 933228ffb509..2d624d9919e3 100644 --- a/drivers/media/tuners/tea5761.h +++ b/drivers/media/tuners/tea5761.h @@ -20,7 +20,7 @@ #include #include "dvb_frontend.h" -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5761) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TEA5761) extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, diff --git a/drivers/media/tuners/tea5767.h b/drivers/media/tuners/tea5767.h index c39101199383..4f6f6c92db78 100644 --- a/drivers/media/tuners/tea5767.h +++ b/drivers/media/tuners/tea5767.h @@ -39,7 +39,7 @@ struct tea5767_ctrl { enum tea5767_xtal xtal_freq; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5767) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TEA5767) extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, diff --git a/drivers/media/tuners/tua9001.h b/drivers/media/tuners/tua9001.h index 26358da1c100..2c3375c7aeb9 100644 --- a/drivers/media/tuners/tua9001.h +++ b/drivers/media/tuners/tua9001.h @@ -51,7 +51,7 @@ struct tua9001_config { #define TUA9001_CMD_RESETN 1 #define TUA9001_CMD_RXEN 2 -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TUA9001) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TUA9001) extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct tua9001_config *cfg); #else diff --git a/drivers/media/tuners/tuner-simple.h b/drivers/media/tuners/tuner-simple.h index ffd12cfe650b..6399b45b0590 100644 --- a/drivers/media/tuners/tuner-simple.h +++ b/drivers/media/tuners/tuner-simple.h @@ -20,7 +20,7 @@ #include #include "dvb_frontend.h" -#if IS_ENABLED(CONFIG_MEDIA_TUNER_SIMPLE) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_SIMPLE) extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr, diff --git a/drivers/media/tuners/tuner-xc2028.h b/drivers/media/tuners/tuner-xc2028.h index 181d087faec4..98e4effca896 100644 --- a/drivers/media/tuners/tuner-xc2028.h +++ b/drivers/media/tuners/tuner-xc2028.h @@ -56,7 +56,7 @@ struct xc2028_config { #define XC2028_RESET_CLK 1 #define XC2028_I2C_FLUSH 2 -#if IS_ENABLED(CONFIG_MEDIA_TUNER_XC2028) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_XC2028) extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg); #else diff --git a/drivers/media/tuners/xc4000.h b/drivers/media/tuners/xc4000.h index 97c23de5296c..40517860cf67 100644 --- a/drivers/media/tuners/xc4000.h +++ b/drivers/media/tuners/xc4000.h @@ -50,7 +50,7 @@ struct xc4000_config { * it's passed back to a bridge during tuner_callback(). */ -#if IS_ENABLED(CONFIG_MEDIA_TUNER_XC4000) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_XC4000) extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct xc4000_config *cfg); diff --git a/drivers/media/tuners/xc5000.h b/drivers/media/tuners/xc5000.h index 6aa534f17a30..00ba29e21fb9 100644 --- a/drivers/media/tuners/xc5000.h +++ b/drivers/media/tuners/xc5000.h @@ -58,7 +58,7 @@ struct xc5000_config { * it's passed back to a bridge during tuner_callback(). */ -#if IS_ENABLED(CONFIG_MEDIA_TUNER_XC5000) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_XC5000) extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct xc5000_config *cfg); diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h index be342b94c640..16cfb3448568 100644 --- a/include/linux/kconfig.h +++ b/include/linux/kconfig.h @@ -43,4 +43,13 @@ */ #define IS_MODULE(option) config_enabled(option##_MODULE) +/* + * IS_REACHABLE(CONFIG_FOO) evaluates to 1 if the currently compiled + * code can call a function defined in code compiled based on CONFIG_FOO. + * This is similar to IS_ENABLED(), but returns false when invoked from + * built-in code when CONFIG_FOO is set to 'm'. + */ +#define IS_REACHABLE(option) (config_enabled(option) || \ + (config_enabled(option##_MODULE) && config_enabled(MODULE))) + #endif /* __LINUX_KCONFIG_H */ -- cgit v1.2.3 From 820f9f147dcce2602eefd9b575bbbd9ea14f0953 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 2 Apr 2015 16:35:48 -0500 Subject: fs_pin: Allow for the possibility that m_list or s_list go unused. This is needed to support lazily umounting locked mounts. Because the entire unmounted subtree needs to stay together until there are no users with references to any part of the subtree. To support this guarantee that the fs_pin m_list and s_list nodes are initialized by initializing them in init_fs_pin allowing for the possibility that pin_insert_group does not touch them. Further use hlist_del_init in pin_remove so that there is a hlist_unhashed test before the list we attempt to update the previous list item. Signed-off-by: "Eric W. Biederman" --- fs/fs_pin.c | 4 ++-- include/linux/fs_pin.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/fs/fs_pin.c b/fs/fs_pin.c index b06c98796afb..611b5408f6ec 100644 --- a/fs/fs_pin.c +++ b/fs/fs_pin.c @@ -9,8 +9,8 @@ static DEFINE_SPINLOCK(pin_lock); void pin_remove(struct fs_pin *pin) { spin_lock(&pin_lock); - hlist_del(&pin->m_list); - hlist_del(&pin->s_list); + hlist_del_init(&pin->m_list); + hlist_del_init(&pin->s_list); spin_unlock(&pin_lock); spin_lock_irq(&pin->wait.lock); pin->done = 1; diff --git a/include/linux/fs_pin.h b/include/linux/fs_pin.h index 9dc4e0384bfb..3886b3bffd7f 100644 --- a/include/linux/fs_pin.h +++ b/include/linux/fs_pin.h @@ -13,6 +13,8 @@ struct vfsmount; static inline void init_fs_pin(struct fs_pin *p, void (*kill)(struct fs_pin *)) { init_waitqueue_head(&p->wait); + INIT_HLIST_NODE(&p->s_list); + INIT_HLIST_NODE(&p->m_list); p->kill = kill; } -- cgit v1.2.3 From 99492c39f39fc2d8c4ae36ecfb88d7de5d8106b5 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Fri, 3 Apr 2015 08:57:51 -0400 Subject: earlycon: Fix __earlycon_table stride The compiler and the linker must agree on the alignment of struct earlycon_id; empirical testing and commit 07fca0e57fca92 ("tracing: Properly align linker defined symbols") suggests 32-byte alignment is the LCD. Reported-by: Yinghai Lu Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- include/asm-generic/vmlinux.lds.h | 2 +- include/linux/serial_core.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 87e5b6f8f4fc..561daf49e52f 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -151,7 +151,7 @@ #endif #ifdef CONFIG_SERIAL_EARLYCON -#define EARLYCON_TABLE() . = ALIGN(8); \ +#define EARLYCON_TABLE() STRUCT_ALIGN(); \ VMLINUX_SYMBOL(__earlycon_table) = .; \ *(__earlycon_table) \ *(__earlycon_table_end) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 34de16840152..025dad9dcde4 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -342,7 +342,7 @@ struct earlycon_device { struct earlycon_id { char name[16]; int (*setup)(struct earlycon_device *, const char *options); -}; +} __aligned(32); extern int setup_earlycon(char *buf); extern int of_setup_earlycon(unsigned long addr, -- cgit v1.2.3 From 06e7a9b638467fddf8f62ca9f07adc7754319461 Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Mon, 23 Feb 2015 09:26:16 -0300 Subject: [media] vb2: split the io_flags member of vb2_queue into a bit field This patch splits the io_flags member of vb2_queue into a bit field. Instead of an enum with flags separate bit fields were introduced. Signed-off-by: Kamil Debski Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 17 +++++++++-------- include/media/videobuf2-core.h | 18 +++++------------- 2 files changed, 14 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 167c1d93bd4c..8bc2a6e8623d 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -2760,7 +2760,8 @@ struct vb2_fileio_data { unsigned int initial_index; unsigned int q_count; unsigned int dq_count; - unsigned int flags; + unsigned read_once:1; + unsigned write_immediately:1; }; /** @@ -2798,14 +2799,16 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) */ count = 1; - dprintk(3, "setting up file io: mode %s, count %d, flags %08x\n", - (read) ? "read" : "write", count, q->io_flags); + dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n", + (read) ? "read" : "write", count, q->fileio_read_once, + q->fileio_write_immediately); fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL); if (fileio == NULL) return -ENOMEM; - fileio->flags = q->io_flags; + fileio->read_once = q->fileio_read_once; + fileio->write_immediately = q->fileio_write_immediately; /* * Request buffers and use MMAP type to force driver @@ -3028,13 +3031,11 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ /* * Queue next buffer if required. */ - if (buf->pos == buf->size || - (!read && (fileio->flags & VB2_FILEIO_WRITE_IMMEDIATELY))) { + if (buf->pos == buf->size || (!read && fileio->write_immediately)) { /* * Check if this is the last buffer to read. */ - if (read && (fileio->flags & VB2_FILEIO_READ_ONCE) && - fileio->dq_count == 1) { + if (read && fileio->read_once && fileio->dq_count == 1) { dprintk(3, "read limit reached\n"); return __vb2_cleanup_fileio(q); } diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index bd2cec2d6c3d..e49dc6b0de81 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -133,17 +133,6 @@ enum vb2_io_modes { VB2_DMABUF = (1 << 4), }; -/** - * enum vb2_fileio_flags - flags for selecting a mode of the file io emulator, - * by default the 'streaming' style is used by the file io emulator - * @VB2_FILEIO_READ_ONCE: report EOF after reading the first buffer - * @VB2_FILEIO_WRITE_IMMEDIATELY: queue buffer after each write() call - */ -enum vb2_fileio_flags { - VB2_FILEIO_READ_ONCE = (1 << 0), - VB2_FILEIO_WRITE_IMMEDIATELY = (1 << 1), -}; - /** * enum vb2_buffer_state - current video buffer state * @VB2_BUF_STATE_DEQUEUED: buffer under userspace control @@ -346,7 +335,8 @@ struct v4l2_fh; * * @type: queue type (see V4L2_BUF_TYPE_* in linux/videodev2.h * @io_modes: supported io methods (see vb2_io_modes enum) - * @io_flags: additional io flags (see vb2_fileio_flags enum) + * @fileio_read_once: report EOF after reading the first buffer + * @fileio_write_immediately: queue buffer after each write() call * @lock: pointer to a mutex that protects the vb2_queue struct. The * driver can set this to a mutex to let the v4l2 core serialize * the queuing ioctls. If the driver wants to handle locking @@ -396,7 +386,9 @@ struct v4l2_fh; struct vb2_queue { enum v4l2_buf_type type; unsigned int io_modes; - unsigned int io_flags; + unsigned fileio_read_once:1; + unsigned fileio_write_immediately:1; + struct mutex *lock; struct v4l2_fh *owner; -- cgit v1.2.3 From f61bf13b6a07a93b9348e77808d369803f40b681 Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Mon, 23 Feb 2015 09:26:17 -0300 Subject: [media] vb2: add allow_zero_bytesused flag to the vb2_queue struct The vb2: fix bytesused == 0 handling (8a75ffb) patch changed the behavior of __fill_vb2_buffer function, so that if bytesused is 0 it is set to the size of the buffer. However, bytesused set to 0 is used by older codec drivers as as indication used to mark the end of stream. To keep backward compatibility, this patch adds a flag passed to the vb2_queue_init function - allow_zero_bytesused. If the flag is set upon initialization of the queue, the videobuf2 keeps the value of bytesused intact in the OUTPUT queue and passes it to the driver. Reported-by: Nicolas Dufresne Signed-off-by: Kamil Debski Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 39 +++++++++++++++++++++++++++----- include/media/videobuf2-core.h | 2 ++ 2 files changed, 35 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 8bc2a6e8623d..1329dccfa072 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1247,6 +1247,16 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b { unsigned int plane; + if (V4L2_TYPE_IS_OUTPUT(b->type)) { + if (WARN_ON_ONCE(b->bytesused == 0)) { + pr_warn_once("use of bytesused == 0 is deprecated and will be removed in the future,\n"); + if (vb->vb2_queue->allow_zero_bytesused) + pr_warn_once("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n"); + else + pr_warn_once("use the actual size instead.\n"); + } + } + if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { if (b->memory == V4L2_MEMORY_USERPTR) { for (plane = 0; plane < vb->num_planes; ++plane) { @@ -1276,13 +1286,22 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b * userspace clearly never bothered to set it and * it's a safe assumption that they really meant to * use the full plane sizes. + * + * Some drivers, e.g. old codec drivers, use bytesused == 0 + * as a way to indicate that streaming is finished. + * In that case, the driver should use the + * allow_zero_bytesused flag to keep old userspace + * applications working. */ for (plane = 0; plane < vb->num_planes; ++plane) { struct v4l2_plane *pdst = &v4l2_planes[plane]; struct v4l2_plane *psrc = &b->m.planes[plane]; - pdst->bytesused = psrc->bytesused ? - psrc->bytesused : pdst->length; + if (vb->vb2_queue->allow_zero_bytesused) + pdst->bytesused = psrc->bytesused; + else + pdst->bytesused = psrc->bytesused ? + psrc->bytesused : pdst->length; pdst->data_offset = psrc->data_offset; } } @@ -1295,6 +1314,11 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b * * If bytesused == 0 for the output buffer, then fall back * to the full buffer size as that's a sensible default. + * + * Some drivers, e.g. old codec drivers, use bytesused == 0 as + * a way to indicate that streaming is finished. In that case, + * the driver should use the allow_zero_bytesused flag to keep + * old userspace applications working. */ if (b->memory == V4L2_MEMORY_USERPTR) { v4l2_planes[0].m.userptr = b->m.userptr; @@ -1306,10 +1330,13 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b v4l2_planes[0].length = b->length; } - if (V4L2_TYPE_IS_OUTPUT(b->type)) - v4l2_planes[0].bytesused = b->bytesused ? - b->bytesused : v4l2_planes[0].length; - else + if (V4L2_TYPE_IS_OUTPUT(b->type)) { + if (vb->vb2_queue->allow_zero_bytesused) + v4l2_planes[0].bytesused = b->bytesused; + else + v4l2_planes[0].bytesused = b->bytesused ? + b->bytesused : v4l2_planes[0].length; + } else v4l2_planes[0].bytesused = 0; } diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index e49dc6b0de81..a5790fd5d125 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -337,6 +337,7 @@ struct v4l2_fh; * @io_modes: supported io methods (see vb2_io_modes enum) * @fileio_read_once: report EOF after reading the first buffer * @fileio_write_immediately: queue buffer after each write() call + * @allow_zero_bytesused: allow bytesused == 0 to be passed to the driver * @lock: pointer to a mutex that protects the vb2_queue struct. The * driver can set this to a mutex to let the v4l2 core serialize * the queuing ioctls. If the driver wants to handle locking @@ -388,6 +389,7 @@ struct vb2_queue { unsigned int io_modes; unsigned fileio_read_once:1; unsigned fileio_write_immediately:1; + unsigned allow_zero_bytesused:1; struct mutex *lock; struct v4l2_fh *owner; -- cgit v1.2.3 From befd25a2bd61f1706508280f705e18be8b283e3e Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 3 Apr 2015 14:12:58 -0300 Subject: [media] media: omap3isp: remove unused clkdev No merged platform supplies xclks via platform data. As we want to slightly change the clkdev interface, rather than fixing this unused code, remove it instead. Signed-off-by: Russell King Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 24 ------------------------ drivers/media/platform/omap3isp/isp.h | 1 - include/media/omap3isp.h | 6 ------ 3 files changed, 31 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index ff51c4f9d35e..18d0a871747f 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -304,7 +304,6 @@ static struct clk *isp_xclk_src_get(struct of_phandle_args *clkspec, void *data) static int isp_xclk_init(struct isp_device *isp) { - struct isp_platform_data *pdata = isp->pdata; struct device_node *np = isp->dev->of_node; struct clk_init_data init; unsigned int i; @@ -335,26 +334,6 @@ static int isp_xclk_init(struct isp_device *isp) xclk->clk = clk_register(NULL, &xclk->hw); if (IS_ERR(xclk->clk)) return PTR_ERR(xclk->clk); - - /* When instantiated from DT we don't need to register clock - * aliases. - */ - if (np) - continue; - - if (!pdata || (pdata->xclks[i].con_id == NULL && - pdata->xclks[i].dev_id == NULL)) - continue; - - xclk->lookup = kzalloc(sizeof(*xclk->lookup), GFP_KERNEL); - if (xclk->lookup == NULL) - return -ENOMEM; - - xclk->lookup->con_id = pdata->xclks[i].con_id; - xclk->lookup->dev_id = pdata->xclks[i].dev_id; - xclk->lookup->clk = xclk->clk; - - clkdev_add(xclk->lookup); } if (np) @@ -376,9 +355,6 @@ static void isp_xclk_cleanup(struct isp_device *isp) if (!IS_ERR(xclk->clk)) clk_unregister(xclk->clk); - - if (xclk->lookup) - clkdev_drop(xclk->lookup); } } diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index 431224ec09ed..e579943175c4 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -132,7 +132,6 @@ enum isp_xclk_id { struct isp_xclk { struct isp_device *isp; struct clk_hw hw; - struct clk_lookup *lookup; struct clk *clk; enum isp_xclk_id id; diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h index 0f0c08b48829..048f8f9117ef 100644 --- a/include/media/omap3isp.h +++ b/include/media/omap3isp.h @@ -150,13 +150,7 @@ struct isp_platform_subdev { struct isp_bus_cfg *bus; }; -struct isp_platform_xclk { - const char *dev_id; - const char *con_id; -}; - struct isp_platform_data { - struct isp_platform_xclk xclks[2]; struct isp_platform_subdev *subdevs; void (*set_constraints)(struct isp_device *isp, bool enable); }; -- cgit v1.2.3 From c1d676cec572544616273d5853cb7cc38fbaa62b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 26 Mar 2015 17:53:01 +0100 Subject: clk: tegra: Use the proper parent for plld_dsi The current parent, plld_out0, does not exist. The proper name is pll_d_out0. While at it, rename the plld_dsi clock to pll_d_dsi_out to be more consistent with other clock names. Fixes: b270491eb9a0 ("clk: tegra: Define PLLD_DSI and remove dsia(b)_mux") Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra124.c | 14 ++++++++------ include/dt-bindings/clock/tegra124-car-common.h | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index f1fa29ec7951..11f857cd5f6a 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1113,16 +1113,18 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base, 1, 2); clks[TEGRA124_CLK_XUSB_SS_DIV2] = clk; - clk = clk_register_gate(NULL, "plld_dsi", "plld_out0", 0, + clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0, clk_base + PLLD_MISC, 30, 0, &pll_d_lock); - clks[TEGRA124_CLK_PLLD_DSI] = clk; + clks[TEGRA124_CLK_PLL_D_DSI_OUT] = clk; - clk = tegra_clk_register_periph_gate("dsia", "plld_dsi", 0, clk_base, - 0, 48, periph_clk_enb_refcnt); + clk = tegra_clk_register_periph_gate("dsia", "pll_d_dsi_out", 0, + clk_base, 0, 48, + periph_clk_enb_refcnt); clks[TEGRA124_CLK_DSIA] = clk; - clk = tegra_clk_register_periph_gate("dsib", "plld_dsi", 0, clk_base, - 0, 82, periph_clk_enb_refcnt); + clk = tegra_clk_register_periph_gate("dsib", "pll_d_dsi_out", 0, + clk_base, 0, 82, + periph_clk_enb_refcnt); clks[TEGRA124_CLK_DSIB] = clk; /* emc mux */ diff --git a/include/dt-bindings/clock/tegra124-car-common.h b/include/dt-bindings/clock/tegra124-car-common.h index ae2eb17a1658..a2156090563f 100644 --- a/include/dt-bindings/clock/tegra124-car-common.h +++ b/include/dt-bindings/clock/tegra124-car-common.h @@ -297,7 +297,7 @@ #define TEGRA124_CLK_PLL_C4 270 #define TEGRA124_CLK_PLL_DP 271 #define TEGRA124_CLK_PLL_E_MUX 272 -#define TEGRA124_CLK_PLLD_DSI 273 +#define TEGRA124_CLK_PLL_D_DSI_OUT 273 /* 274 */ /* 275 */ /* 276 */ -- cgit v1.2.3 From 8ce67cb07dbf6ba35aea1e07e8ad1ea004ced27b Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 17 Mar 2015 17:58:08 -0700 Subject: f2fs: add some tracepoints to debug volatile and atomic writes Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 2 ++ fs/f2fs/f2fs.h | 4 ++++ fs/f2fs/segment.c | 4 ++++ include/trace/events/f2fs.h | 27 ++++++++++++++++++++++++++- 4 files changed, 36 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 486113db97b1..241b98741df9 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1287,9 +1287,11 @@ int do_write_data_page(struct page *page, struct f2fs_io_info *fio) need_inplace_update(inode))) { rewrite_data_page(page, fio); set_inode_flag(F2FS_I(inode), FI_UPDATE_WRITE); + trace_f2fs_do_write_data_page(page, IPU); } else { write_data_page(page, &dn, fio); f2fs_update_extent_cache(&dn); + trace_f2fs_do_write_data_page(page, OPU); set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE); if (page->index == 0) set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 9e378179ff93..c9818193e15e 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -556,6 +556,10 @@ enum page_type { META, NR_PAGE_TYPE, META_FLUSH, + INMEM, /* the below types are used by tracepoints only. */ + INMEM_DROP, + IPU, + OPU, }; struct f2fs_io_info { diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index eafaf728236b..f939660941bb 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -205,6 +205,8 @@ retry: list_add_tail(&new->list, &fi->inmem_pages); inc_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES); mutex_unlock(&fi->inmem_lock); + + trace_f2fs_register_inmem_page(page, INMEM); } void commit_inmem_pages(struct inode *inode, bool abort) @@ -238,11 +240,13 @@ void commit_inmem_pages(struct inode *inode, bool abort) f2fs_wait_on_page_writeback(cur->page, DATA); if (clear_page_dirty_for_io(cur->page)) inode_dec_dirty_pages(inode); + trace_f2fs_commit_inmem_page(cur->page, INMEM); do_write_data_page(cur->page, &fio); submit_bio = true; } f2fs_put_page(cur->page, 1); } else { + trace_f2fs_commit_inmem_page(cur->page, INMEM_DROP); put_page(cur->page); } radix_tree_delete(&fi->inmem_root, cur->page->index); diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 09a56dc75f8d..75724bd28356 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -14,7 +14,11 @@ { NODE, "NODE" }, \ { DATA, "DATA" }, \ { META, "META" }, \ - { META_FLUSH, "META_FLUSH" }) + { META_FLUSH, "META_FLUSH" }, \ + { INMEM, "INMEM" }, \ + { INMEM_DROP, "INMEM_DROP" }, \ + { IPU, "IN-PLACE" }, \ + { OPU, "OUT-OF-PLACE" }) #define F2FS_BIO_MASK(t) (t & (READA | WRITE_FLUSH_FUA)) #define F2FS_BIO_EXTRA_MASK(t) (t & (REQ_META | REQ_PRIO)) @@ -854,6 +858,13 @@ DEFINE_EVENT(f2fs__page, f2fs_writepage, TP_ARGS(page, type) ); +DEFINE_EVENT(f2fs__page, f2fs_do_write_data_page, + + TP_PROTO(struct page *page, int type), + + TP_ARGS(page, type) +); + DEFINE_EVENT(f2fs__page, f2fs_readpage, TP_PROTO(struct page *page, int type), @@ -875,6 +886,20 @@ DEFINE_EVENT(f2fs__page, f2fs_vm_page_mkwrite, TP_ARGS(page, type) ); +DEFINE_EVENT(f2fs__page, f2fs_register_inmem_page, + + TP_PROTO(struct page *page, int type), + + TP_ARGS(page, type) +); + +DEFINE_EVENT(f2fs__page, f2fs_commit_inmem_page, + + TP_PROTO(struct page *page, int type), + + TP_ARGS(page, type) +); + TRACE_EVENT(f2fs_writepages, TP_PROTO(struct inode *inode, struct writeback_control *wbc, int type), -- cgit v1.2.3 From 510022a85839a8409d1e6a519bb86ce71a84f30a Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 30 Mar 2015 15:07:16 -0700 Subject: f2fs: add F2FS_INLINE_DOTS to recover missing dot dentries If f2fs was corrupted with missing dot dentries, it needs to recover them after fsck.f2fs detection. The underlying precedure is: 1. The fsck.f2fs remains F2FS_INLINE_DOTS flag in directory inode, if it detects missing dot dentries. 2. When f2fs looks up the corrupted directory, it triggers f2fs_add_link with proper inode numbers and their dot and dotdot names. 3. Once f2fs recovers the directory without errors, it removes F2FS_INLINE_DOTS finally. Signed-off-by: Jaegeuk Kim --- fs/f2fs/dir.c | 52 ++++++++++++++++++++++++++----------------------- fs/f2fs/f2fs.h | 22 ++++++++++++++++----- fs/f2fs/inline.c | 29 +++++++++++++++------------ fs/f2fs/namei.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/recovery.c | 2 +- include/linux/f2fs_fs.h | 1 + 6 files changed, 112 insertions(+), 42 deletions(-) (limited to 'include') diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 4e59c8219dde..906b5876dc27 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -59,9 +59,8 @@ static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = { [S_IFLNK >> S_SHIFT] = F2FS_FT_SYMLINK, }; -void set_de_type(struct f2fs_dir_entry *de, struct inode *inode) +void set_de_type(struct f2fs_dir_entry *de, umode_t mode) { - umode_t mode = inode->i_mode; de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT]; } @@ -282,7 +281,7 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, lock_page(page); f2fs_wait_on_page_writeback(page, type); de->ino = cpu_to_le32(inode->i_ino); - set_de_type(de, inode); + set_de_type(de, inode->i_mode); f2fs_dentry_kunmap(dir, page); set_page_dirty(page); dir->i_mtime = dir->i_ctime = CURRENT_TIME; @@ -328,14 +327,14 @@ void do_make_empty_dir(struct inode *inode, struct inode *parent, de->hash_code = 0; de->ino = cpu_to_le32(inode->i_ino); memcpy(d->filename[0], ".", 1); - set_de_type(de, inode); + set_de_type(de, inode->i_mode); de = &d->dentry[1]; de->hash_code = 0; de->name_len = cpu_to_le16(2); de->ino = cpu_to_le32(parent->i_ino); memcpy(d->filename[1], "..", 2); - set_de_type(de, inode); + set_de_type(de, inode->i_mode); test_and_set_bit_le(0, (void *)d->bitmap); test_and_set_bit_le(1, (void *)d->bitmap); @@ -432,7 +431,7 @@ error: void update_parent_metadata(struct inode *dir, struct inode *inode, unsigned int current_depth) { - if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { + if (inode && is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { if (S_ISDIR(inode->i_mode)) { inc_nlink(dir); set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); @@ -447,7 +446,7 @@ void update_parent_metadata(struct inode *dir, struct inode *inode, set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); } - if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) + if (inode && is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) clear_inode_flag(F2FS_I(inode), FI_INC_LINK); } @@ -471,7 +470,7 @@ next: goto next; } -void f2fs_update_dentry(struct inode *inode, struct f2fs_dentry_ptr *d, +void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d, const struct qstr *name, f2fs_hash_t name_hash, unsigned int bit_pos) { @@ -483,8 +482,8 @@ void f2fs_update_dentry(struct inode *inode, struct f2fs_dentry_ptr *d, de->hash_code = name_hash; de->name_len = cpu_to_le16(name->len); memcpy(d->filename[bit_pos], name->name, name->len); - de->ino = cpu_to_le32(inode->i_ino); - set_de_type(de, inode); + de->ino = cpu_to_le32(ino); + set_de_type(de, mode); for (i = 0; i < slots; i++) test_and_set_bit_le(bit_pos + i, (void *)d->bitmap); } @@ -494,7 +493,7 @@ void f2fs_update_dentry(struct inode *inode, struct f2fs_dentry_ptr *d, * f2fs_unlock_op(). */ int __f2fs_add_link(struct inode *dir, const struct qstr *name, - struct inode *inode) + struct inode *inode, nid_t ino, umode_t mode) { unsigned int bit_pos; unsigned int level; @@ -507,11 +506,11 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct f2fs_dentry_block *dentry_blk = NULL; struct f2fs_dentry_ptr d; int slots = GET_DENTRY_SLOTS(namelen); - struct page *page; + struct page *page = NULL; int err = 0; if (f2fs_has_inline_dentry(dir)) { - err = f2fs_add_inline_entry(dir, name, inode); + err = f2fs_add_inline_entry(dir, name, inode, ino, mode); if (!err || err != -EAGAIN) return err; else @@ -561,26 +560,31 @@ start: add_dentry: f2fs_wait_on_page_writeback(dentry_page, DATA); - down_write(&F2FS_I(inode)->i_sem); - page = init_inode_metadata(inode, dir, name, NULL); - if (IS_ERR(page)) { - err = PTR_ERR(page); - goto fail; + if (inode) { + down_write(&F2FS_I(inode)->i_sem); + page = init_inode_metadata(inode, dir, name, NULL); + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto fail; + } } make_dentry_ptr(&d, (void *)dentry_blk, 1); - f2fs_update_dentry(inode, &d, name, dentry_hash, bit_pos); + f2fs_update_dentry(ino, mode, &d, name, dentry_hash, bit_pos); set_page_dirty(dentry_page); - /* we don't need to mark_inode_dirty now */ - F2FS_I(inode)->i_pino = dir->i_ino; - update_inode(inode, page); - f2fs_put_page(page, 1); + if (inode) { + /* we don't need to mark_inode_dirty now */ + F2FS_I(inode)->i_pino = dir->i_ino; + update_inode(inode, page); + f2fs_put_page(page, 1); + } update_parent_metadata(dir, inode, current_depth); fail: - up_write(&F2FS_I(inode)->i_sem); + if (inode) + up_write(&F2FS_I(inode)->i_sem); if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { update_inode_page(dir); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 0be198339c3b..053361ace0ec 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1246,6 +1246,7 @@ enum { FI_FIRST_BLOCK_WRITTEN, /* indicate #0 data block was written */ FI_DROP_CACHE, /* drop dirty page cache */ FI_DATA_EXIST, /* indicate data exists */ + FI_INLINE_DOTS, /* indicate inline dot dentries */ }; static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag) @@ -1282,6 +1283,8 @@ static inline void get_inline_info(struct f2fs_inode_info *fi, set_inode_flag(fi, FI_INLINE_DENTRY); if (ri->i_inline & F2FS_DATA_EXIST) set_inode_flag(fi, FI_DATA_EXIST); + if (ri->i_inline & F2FS_INLINE_DOTS) + set_inode_flag(fi, FI_INLINE_DOTS); } static inline void set_raw_inline(struct f2fs_inode_info *fi, @@ -1297,6 +1300,8 @@ static inline void set_raw_inline(struct f2fs_inode_info *fi, ri->i_inline |= F2FS_INLINE_DENTRY; if (is_inode_flag_set(fi, FI_DATA_EXIST)) ri->i_inline |= F2FS_DATA_EXIST; + if (is_inode_flag_set(fi, FI_INLINE_DOTS)) + ri->i_inline |= F2FS_INLINE_DOTS; } static inline int f2fs_has_inline_xattr(struct inode *inode) @@ -1342,6 +1347,11 @@ static inline int f2fs_exist_data(struct inode *inode) return is_inode_flag_set(F2FS_I(inode), FI_DATA_EXIST); } +static inline int f2fs_has_inline_dots(struct inode *inode) +{ + return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DOTS); +} + static inline bool f2fs_is_atomic_file(struct inode *inode) { return is_inode_flag_set(F2FS_I(inode), FI_ATOMIC_FILE); @@ -1440,7 +1450,7 @@ struct dentry *f2fs_get_parent(struct dentry *child); * dir.c */ extern unsigned char f2fs_filetype_table[F2FS_FT_MAX]; -void set_de_type(struct f2fs_dir_entry *, struct inode *); +void set_de_type(struct f2fs_dir_entry *, umode_t); struct f2fs_dir_entry *find_target_dentry(struct qstr *, int *, struct f2fs_dentry_ptr *); bool f2fs_fill_dentries(struct dir_context *, struct f2fs_dentry_ptr *, @@ -1459,9 +1469,10 @@ ino_t f2fs_inode_by_name(struct inode *, struct qstr *); void f2fs_set_link(struct inode *, struct f2fs_dir_entry *, struct page *, struct inode *); int update_dent_inode(struct inode *, const struct qstr *); -void f2fs_update_dentry(struct inode *, struct f2fs_dentry_ptr *, +void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *, const struct qstr *, f2fs_hash_t , unsigned int); -int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *); +int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *, nid_t, + umode_t); void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *, struct inode *); int f2fs_do_tmpfile(struct inode *, struct inode *); @@ -1471,7 +1482,7 @@ bool f2fs_empty_dir(struct inode *); static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode) { return __f2fs_add_link(dentry->d_parent->d_inode, &dentry->d_name, - inode); + inode, inode->i_ino, inode->i_mode); } /* @@ -1792,7 +1803,8 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *, struct qstr *, struct page **); struct f2fs_dir_entry *f2fs_parent_inline_dir(struct inode *, struct page **); int make_empty_inline_dir(struct inode *inode, struct inode *, struct page *); -int f2fs_add_inline_entry(struct inode *, const struct qstr *, struct inode *); +int f2fs_add_inline_entry(struct inode *, const struct qstr *, struct inode *, + nid_t, umode_t); void f2fs_delete_inline_entry(struct f2fs_dir_entry *, struct page *, struct inode *, struct inode *); bool f2fs_empty_inline_dir(struct inode *); diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 8241a87046c3..8140e4f0e538 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -390,7 +390,7 @@ out: } int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, - struct inode *inode) + struct inode *inode, nid_t ino, umode_t mode) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct page *ipage; @@ -400,7 +400,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, struct f2fs_inline_dentry *dentry_blk = NULL; struct f2fs_dentry_ptr d; int slots = GET_DENTRY_SLOTS(namelen); - struct page *page; + struct page *page = NULL; int err = 0; ipage = get_node_page(sbi, dir->i_ino); @@ -417,29 +417,34 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, goto out; } - down_write(&F2FS_I(inode)->i_sem); - page = init_inode_metadata(inode, dir, name, ipage); - if (IS_ERR(page)) { - err = PTR_ERR(page); - goto fail; + if (inode) { + down_write(&F2FS_I(inode)->i_sem); + page = init_inode_metadata(inode, dir, name, ipage); + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto fail; + } } f2fs_wait_on_page_writeback(ipage, NODE); name_hash = f2fs_dentry_hash(name); make_dentry_ptr(&d, (void *)dentry_blk, 2); - f2fs_update_dentry(inode, &d, name, name_hash, bit_pos); + f2fs_update_dentry(ino, mode, &d, name, name_hash, bit_pos); set_page_dirty(ipage); /* we don't need to mark_inode_dirty now */ - F2FS_I(inode)->i_pino = dir->i_ino; - update_inode(inode, page); - f2fs_put_page(page, 1); + if (inode) { + F2FS_I(inode)->i_pino = dir->i_ino; + update_inode(inode, page); + f2fs_put_page(page, 1); + } update_parent_metadata(dir, inode, 0); fail: - up_write(&F2FS_I(inode)->i_sem); + if (inode) + up_write(&F2FS_I(inode)->i_sem); if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { update_inode(dir, ipage); diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 1e2ae21bd6b6..8055e30eb14d 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -187,6 +187,44 @@ struct dentry *f2fs_get_parent(struct dentry *child) return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino)); } +static int __recover_dot_dentries(struct inode *dir, nid_t pino) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); + struct qstr dot = QSTR_INIT(".", 1); + struct qstr dotdot = QSTR_INIT("..", 2); + struct f2fs_dir_entry *de; + struct page *page; + int err = 0; + + f2fs_lock_op(sbi); + + de = f2fs_find_entry(dir, &dot, &page); + if (de) { + f2fs_dentry_kunmap(dir, page); + f2fs_put_page(page, 0); + } else { + err = __f2fs_add_link(dir, &dot, NULL, dir->i_ino, S_IFDIR); + if (err) + goto out; + } + + de = f2fs_find_entry(dir, &dotdot, &page); + if (de) { + f2fs_dentry_kunmap(dir, page); + f2fs_put_page(page, 0); + } else { + err = __f2fs_add_link(dir, &dotdot, NULL, pino, S_IFDIR); + } +out: + if (!err) { + clear_inode_flag(F2FS_I(dir), FI_INLINE_DOTS); + mark_inode_dirty(dir); + } + + f2fs_unlock_op(sbi); + return err; +} + static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { @@ -206,6 +244,16 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, inode = f2fs_iget(dir->i_sb, ino); if (IS_ERR(inode)) return ERR_CAST(inode); + + if (f2fs_has_inline_dots(inode)) { + int err; + + err = __recover_dot_dentries(inode, dir->i_ino); + if (err) { + iget_failed(inode); + return ERR_PTR(err); + } + } } return d_splice_alias(inode, dentry); diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index c69de88a6453..679c465e9def 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -115,7 +115,7 @@ retry: iput(einode); goto retry; } - err = __f2fs_add_link(dir, &name, inode); + err = __f2fs_add_link(dir, &name, inode, inode->i_ino, inode->i_mode); if (err) goto out_err; diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 502f28cfb78e..591f8c3ef410 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -178,6 +178,7 @@ struct f2fs_extent { #define F2FS_INLINE_DATA 0x02 /* file inline data flag */ #define F2FS_INLINE_DENTRY 0x04 /* file inline dentry flag */ #define F2FS_DATA_EXIST 0x08 /* file inline data exist flag */ +#define F2FS_INLINE_DOTS 0x10 /* file having implicit dot dentries */ #define MAX_INLINE_DATA (sizeof(__le32) * (DEF_ADDRS_PER_INODE - \ F2FS_INLINE_XATTR_ADDRS - 1)) -- cgit v1.2.3 From 820ad9752c232239d3278eafe71c2c251ae233d3 Mon Sep 17 00:00:00 2001 From: Martin Fuzzey Date: Wed, 18 Mar 2015 14:53:17 +0100 Subject: clk: clk-gpio-gate: Fix active low The active low flag in the DT cell is currently ignored. This occurs because of_get_named_gpio_flags() does not apply the flags to the underlying struct gpio_desc so the test in clk_register_gpio_gate() was bogus. Note that this patch changes the internal kernel API for clk_register_gpio_gate() but there are currently no other users. Signed-off-by: Martin Fuzzey Acked-by: Jyri Sarha Signed-off-by: Michael Turquette --- drivers/clk/clk-gpio-gate.c | 31 +++++++++++++++++-------------- include/linux/clk-provider.h | 2 +- 2 files changed, 18 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/clk/clk-gpio-gate.c b/drivers/clk/clk-gpio-gate.c index 08e43224fd52..a71cabedda93 100644 --- a/drivers/clk/clk-gpio-gate.c +++ b/drivers/clk/clk-gpio-gate.c @@ -65,10 +65,12 @@ EXPORT_SYMBOL_GPL(clk_gpio_gate_ops); * @dev: device that is registering this clock * @name: name of this clock * @parent_name: name of this clock's parent - * @gpiod: gpio descriptor to gate this clock + * @gpio: gpio number to gate this clock + * @active_low: true if gpio should be set to 0 to enable clock + * @flags: clock flags */ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, - const char *parent_name, struct gpio_desc *gpiod, + const char *parent_name, unsigned gpio, bool active_low, unsigned long flags) { struct clk_gpio *clk_gpio = NULL; @@ -77,20 +79,19 @@ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, unsigned long gpio_flags; int err; - if (gpiod_is_active_low(gpiod)) - gpio_flags = GPIOF_OUT_INIT_HIGH; + if (active_low) + gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH; else gpio_flags = GPIOF_OUT_INIT_LOW; if (dev) - err = devm_gpio_request_one(dev, desc_to_gpio(gpiod), - gpio_flags, name); + err = devm_gpio_request_one(dev, gpio, gpio_flags, name); else - err = gpio_request_one(desc_to_gpio(gpiod), gpio_flags, name); + err = gpio_request_one(gpio, gpio_flags, name); if (err) { pr_err("%s: %s: Error requesting clock control gpio %u\n", - __func__, name, desc_to_gpio(gpiod)); + __func__, name, gpio); return ERR_PTR(err); } @@ -111,7 +112,7 @@ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, init.parent_names = (parent_name ? &parent_name : NULL); init.num_parents = (parent_name ? 1 : 0); - clk_gpio->gpiod = gpiod; + clk_gpio->gpiod = gpio_to_desc(gpio); clk_gpio->hw.init = &init; clk = clk_register(dev, &clk_gpio->hw); @@ -123,7 +124,8 @@ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, kfree(clk_gpio); clk_register_gpio_gate_err: - gpiod_put(gpiod); + if (!dev) + gpio_free(gpio); return clk; } @@ -149,8 +151,8 @@ static struct clk *of_clk_gpio_gate_delayed_register_get( struct clk *clk; const char *clk_name = data->node->name; const char *parent_name; - struct gpio_desc *gpiod; int gpio; + enum of_gpio_flags of_flags; mutex_lock(&data->lock); @@ -159,7 +161,8 @@ static struct clk *of_clk_gpio_gate_delayed_register_get( return data->clk; } - gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0, NULL); + gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0, + &of_flags); if (gpio < 0) { mutex_unlock(&data->lock); if (gpio != -EPROBE_DEFER) @@ -167,11 +170,11 @@ static struct clk *of_clk_gpio_gate_delayed_register_get( __func__, clk_name); return ERR_PTR(gpio); } - gpiod = gpio_to_desc(gpio); parent_name = of_clk_get_parent_name(data->node, 0); - clk = clk_register_gpio_gate(NULL, clk_name, parent_name, gpiod, 0); + clk = clk_register_gpio_gate(NULL, clk_name, parent_name, gpio, + of_flags & OF_GPIO_ACTIVE_LOW, 0); if (IS_ERR(clk)) { mutex_unlock(&data->lock); return clk; diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 5591ea71a8d1..df695313f975 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -541,7 +541,7 @@ struct clk_gpio { extern const struct clk_ops clk_gpio_gate_ops; struct clk *clk_register_gpio_gate(struct device *dev, const char *name, - const char *parent_name, struct gpio_desc *gpio, + const char *parent_name, unsigned gpio, bool active_low, unsigned long flags); void of_gpio_clk_gate_setup(struct device_node *node); -- cgit v1.2.3 From df63b9994eaf942afcdb946d27a28661d7dfbf2a Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Fri, 10 Apr 2015 14:58:39 +0300 Subject: drm/atomic: Add for_each_{connector,crtc,plane}_in_state helper macros This saves some typing whenever a iteration over all the connector, crtc or plane states in the atomic state is written, which happens quite often. Cc: dri-devel@lists.freedesktop.org Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 62 +++------ drivers/gpu/drm/drm_atomic_helper.c | 253 +++++++++++------------------------- include/drm/drm_atomic.h | 24 ++++ 3 files changed, 117 insertions(+), 222 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 0537f327b145..6e3b78ee7d16 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -909,14 +909,13 @@ int drm_atomic_connectors_for_crtc(struct drm_atomic_state *state, struct drm_crtc *crtc) { - int i, num_connected_connectors = 0; - - for (i = 0; i < state->num_connector; i++) { - struct drm_connector_state *conn_state; + struct drm_connector *connector; + struct drm_connector_state *conn_state; - conn_state = state->connector_states[i]; + int i, num_connected_connectors = 0; - if (conn_state && conn_state->crtc == crtc) + for_each_connector_in_state(state, connector, conn_state, i) { + if (conn_state->crtc == crtc) num_connected_connectors++; } @@ -968,19 +967,16 @@ int drm_atomic_check_only(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct drm_mode_config *config = &dev->mode_config; - int nplanes = config->num_total_plane; - int ncrtcs = config->num_crtc; + struct drm_plane *plane; + struct drm_plane_state *plane_state; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; int i, ret = 0; DRM_DEBUG_ATOMIC("checking %p\n", state); - for (i = 0; i < nplanes; i++) { - struct drm_plane *plane = state->planes[i]; - - if (!plane) - continue; - - ret = drm_atomic_plane_check(plane, state->plane_states[i]); + for_each_plane_in_state(state, plane, plane_state, i) { + ret = drm_atomic_plane_check(plane, plane_state); if (ret) { DRM_DEBUG_ATOMIC("[PLANE:%d] atomic core check failed\n", plane->base.id); @@ -988,13 +984,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) } } - for (i = 0; i < ncrtcs; i++) { - struct drm_crtc *crtc = state->crtcs[i]; - - if (!crtc) - continue; - - ret = drm_atomic_crtc_check(crtc, state->crtc_states[i]); + for_each_crtc_in_state(state, crtc, crtc_state, i) { + ret = drm_atomic_crtc_check(crtc, crtc_state); if (ret) { DRM_DEBUG_ATOMIC("[CRTC:%d] atomic core check failed\n", crtc->base.id); @@ -1006,13 +997,7 @@ int drm_atomic_check_only(struct drm_atomic_state *state) ret = config->funcs->atomic_check(state->dev, state); if (!state->allow_modeset) { - for (i = 0; i < ncrtcs; i++) { - struct drm_crtc *crtc = state->crtcs[i]; - struct drm_crtc_state *crtc_state = state->crtc_states[i]; - - if (!crtc) - continue; - + for_each_crtc_in_state(state, crtc, crtc_state, i) { if (crtc_state->mode_changed || crtc_state->active_changed) { DRM_DEBUG_ATOMIC("[CRTC:%d] requires full modeset\n", @@ -1210,6 +1195,8 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, struct drm_atomic_state *state; struct drm_modeset_acquire_ctx ctx; struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; unsigned plane_mask = 0; int ret = 0; unsigned int i, j; @@ -1313,15 +1300,9 @@ retry: } if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { - int ncrtcs = dev->mode_config.num_crtc; - - for (i = 0; i < ncrtcs; i++) { - struct drm_crtc_state *crtc_state = state->crtc_states[i]; + for_each_crtc_in_state(state, crtc, crtc_state, i) { struct drm_pending_vblank_event *e; - if (!crtc_state) - continue; - e = create_vblank_event(dev, file_priv, arg->user_data); if (!e) { ret = -ENOMEM; @@ -1373,14 +1354,7 @@ fail: goto backoff; if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { - int ncrtcs = dev->mode_config.num_crtc; - - for (i = 0; i < ncrtcs; i++) { - struct drm_crtc_state *crtc_state = state->crtc_states[i]; - - if (!crtc_state) - continue; - + for_each_crtc_in_state(state, crtc, crtc_state, i) { destroy_vblank_event(dev, file_priv, crtc_state->event); crtc_state->event = NULL; } diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index e67d4d69faf7..a2fb0d45217a 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -248,30 +248,24 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) static int mode_fixup(struct drm_atomic_state *state) { - int ncrtcs = state->dev->mode_config.num_crtc; + struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; + struct drm_connector *connector; struct drm_connector_state *conn_state; int i; bool ret; - for (i = 0; i < ncrtcs; i++) { - crtc_state = state->crtc_states[i]; - - if (!crtc_state || !crtc_state->mode_changed) + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (!crtc_state->mode_changed) continue; drm_mode_copy(&crtc_state->adjusted_mode, &crtc_state->mode); } - for (i = 0; i < state->num_connector; i++) { + for_each_connector_in_state(state, connector, conn_state, i) { const struct drm_encoder_helper_funcs *funcs; struct drm_encoder *encoder; - conn_state = state->connector_states[i]; - - if (!conn_state) - continue; - WARN_ON(!!conn_state->best_encoder != !!conn_state->crtc); if (!conn_state->crtc || !conn_state->best_encoder) @@ -316,14 +310,10 @@ mode_fixup(struct drm_atomic_state *state) } } - for (i = 0; i < ncrtcs; i++) { + for_each_crtc_in_state(state, crtc, crtc_state, i) { const struct drm_crtc_helper_funcs *funcs; - struct drm_crtc *crtc; - crtc_state = state->crtc_states[i]; - crtc = state->crtcs[i]; - - if (!crtc_state || !crtc_state->mode_changed) + if (!crtc_state->mode_changed) continue; funcs = crtc->helper_private; @@ -371,18 +361,13 @@ int drm_atomic_helper_check_modeset(struct drm_device *dev, struct drm_atomic_state *state) { - int ncrtcs = dev->mode_config.num_crtc; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; + struct drm_connector *connector; + struct drm_connector_state *connector_state; int i, ret; - for (i = 0; i < ncrtcs; i++) { - crtc = state->crtcs[i]; - crtc_state = state->crtc_states[i]; - - if (!crtc) - continue; - + for_each_crtc_in_state(state, crtc, crtc_state, i) { if (!drm_mode_equal(&crtc->state->mode, &crtc_state->mode)) { DRM_DEBUG_ATOMIC("[CRTC:%d] mode changed\n", crtc->base.id); @@ -396,7 +381,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, } } - for (i = 0; i < state->num_connector; i++) { + for_each_connector_in_state(state, connector, connector_state, i) { /* * This only sets crtc->mode_changed for routing changes, * drivers must set crtc->mode_changed themselves when connector @@ -413,15 +398,9 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, * configuration. This must be done before calling mode_fixup in case a * crtc only changed its mode but has the same set of connectors. */ - for (i = 0; i < ncrtcs; i++) { + for_each_crtc_in_state(state, crtc, crtc_state, i) { int num_connectors; - crtc = state->crtcs[i]; - crtc_state = state->crtc_states[i]; - - if (!crtc) - continue; - /* * We must set ->active_changed after walking connectors for * otherwise an update that only changes active would result in @@ -476,17 +455,14 @@ int drm_atomic_helper_check_planes(struct drm_device *dev, struct drm_atomic_state *state) { - int nplanes = dev->mode_config.num_total_plane; - int ncrtcs = dev->mode_config.num_crtc; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_plane *plane; + struct drm_plane_state *plane_state; int i, ret = 0; - for (i = 0; i < nplanes; i++) { + for_each_plane_in_state(state, plane, plane_state, i) { const struct drm_plane_helper_funcs *funcs; - struct drm_plane *plane = state->planes[i]; - struct drm_plane_state *plane_state = state->plane_states[i]; - - if (!plane) - continue; funcs = plane->helper_private; @@ -503,12 +479,8 @@ drm_atomic_helper_check_planes(struct drm_device *dev, } } - for (i = 0; i < ncrtcs; i++) { + for_each_crtc_in_state(state, crtc, crtc_state, i) { const struct drm_crtc_helper_funcs *funcs; - struct drm_crtc *crtc = state->crtcs[i]; - - if (!crtc) - continue; funcs = crtc->helper_private; @@ -567,22 +539,20 @@ EXPORT_SYMBOL(drm_atomic_helper_check); static void disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) { - int ncrtcs = old_state->dev->mode_config.num_crtc; + struct drm_connector *connector; + struct drm_connector_state *old_conn_state; + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; int i; - for (i = 0; i < old_state->num_connector; i++) { + for_each_connector_in_state(old_state, connector, old_conn_state, i) { const struct drm_encoder_helper_funcs *funcs; - struct drm_connector_state *old_conn_state; - struct drm_connector *connector; struct drm_encoder *encoder; struct drm_crtc_state *old_crtc_state; - old_conn_state = old_state->connector_states[i]; - connector = old_state->connectors[i]; - /* Shut down everything that's in the changeset and currently * still on. So need to check the old, saved state. */ - if (!old_conn_state || !old_conn_state->crtc) + if (!old_conn_state->crtc) continue; old_crtc_state = old_state->crtc_states[drm_crtc_index(old_conn_state->crtc)]; @@ -623,16 +593,11 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) encoder->bridge->funcs->post_disable(encoder->bridge); } - for (i = 0; i < ncrtcs; i++) { + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { const struct drm_crtc_helper_funcs *funcs; - struct drm_crtc *crtc; - struct drm_crtc_state *old_crtc_state; - - crtc = old_state->crtcs[i]; - old_crtc_state = old_state->crtc_states[i]; /* Shut down everything that needs a full modeset. */ - if (!crtc || !needs_modeset(crtc->state)) + if (!needs_modeset(crtc->state)) continue; if (!old_crtc_state->active) @@ -657,16 +622,15 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) static void set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state) { - int ncrtcs = old_state->dev->mode_config.num_crtc; + struct drm_connector *connector; + struct drm_connector_state *old_conn_state; + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; int i; /* clear out existing links */ - for (i = 0; i < old_state->num_connector; i++) { - struct drm_connector *connector; - - connector = old_state->connectors[i]; - - if (!connector || !connector->encoder) + for_each_connector_in_state(old_state, connector, old_conn_state, i) { + if (!connector->encoder) continue; WARN_ON(!connector->encoder->crtc); @@ -676,12 +640,8 @@ set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state) } /* set new links */ - for (i = 0; i < old_state->num_connector; i++) { - struct drm_connector *connector; - - connector = old_state->connectors[i]; - - if (!connector || !connector->state->crtc) + for_each_connector_in_state(old_state, connector, old_conn_state, i) { + if (!connector->state->crtc) continue; if (WARN_ON(!connector->state->best_encoder)) @@ -692,14 +652,7 @@ set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state) } /* set legacy state in the crtc structure */ - for (i = 0; i < ncrtcs; i++) { - struct drm_crtc *crtc; - - crtc = old_state->crtcs[i]; - - if (!crtc) - continue; - + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { crtc->mode = crtc->state->mode; crtc->enabled = crtc->state->enable; crtc->x = crtc->primary->state->src_x >> 16; @@ -710,16 +663,16 @@ set_routing_links(struct drm_device *dev, struct drm_atomic_state *old_state) static void crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) { - int ncrtcs = old_state->dev->mode_config.num_crtc; + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; + struct drm_connector *connector; + struct drm_connector_state *old_conn_state; int i; - for (i = 0; i < ncrtcs; i++) { + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { const struct drm_crtc_helper_funcs *funcs; - struct drm_crtc *crtc; - - crtc = old_state->crtcs[i]; - if (!crtc || !crtc->state->mode_changed) + if (!crtc->state->mode_changed) continue; funcs = crtc->helper_private; @@ -732,16 +685,13 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) } } - for (i = 0; i < old_state->num_connector; i++) { + for_each_connector_in_state(old_state, connector, old_conn_state, i) { const struct drm_encoder_helper_funcs *funcs; - struct drm_connector *connector; struct drm_crtc_state *new_crtc_state; struct drm_encoder *encoder; struct drm_display_mode *mode, *adjusted_mode; - connector = old_state->connectors[i]; - - if (!connector || !connector->state->best_encoder) + if (!connector->state->best_encoder) continue; encoder = connector->state->best_encoder; @@ -809,17 +759,17 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables); void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, struct drm_atomic_state *old_state) { - int ncrtcs = old_state->dev->mode_config.num_crtc; + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; + struct drm_connector *connector; + struct drm_connector_state *old_conn_state; int i; - for (i = 0; i < ncrtcs; i++) { + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { const struct drm_crtc_helper_funcs *funcs; - struct drm_crtc *crtc; - - crtc = old_state->crtcs[i]; /* Need to filter out CRTCs where only planes change. */ - if (!crtc || !needs_modeset(crtc->state)) + if (!needs_modeset(crtc->state)) continue; if (!crtc->state->active) @@ -838,14 +788,11 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, } } - for (i = 0; i < old_state->num_connector; i++) { + for_each_connector_in_state(old_state, connector, old_conn_state, i) { const struct drm_encoder_helper_funcs *funcs; - struct drm_connector *connector; struct drm_encoder *encoder; - connector = old_state->connectors[i]; - - if (!connector || !connector->state->best_encoder) + if (!connector->state->best_encoder) continue; if (!connector->state->crtc->state->active || @@ -879,13 +826,12 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables); static void wait_for_fences(struct drm_device *dev, struct drm_atomic_state *state) { - int nplanes = dev->mode_config.num_total_plane; + struct drm_plane *plane; + struct drm_plane_state *plane_state; int i; - for (i = 0; i < nplanes; i++) { - struct drm_plane *plane = state->planes[i]; - - if (!plane || !plane->state->fence) + for_each_plane_in_state(state, plane, plane_state, i) { + if (!plane->state->fence) continue; WARN_ON(!plane->state->fb); @@ -902,16 +848,9 @@ static bool framebuffer_changed(struct drm_device *dev, { struct drm_plane *plane; struct drm_plane_state *old_plane_state; - int nplanes = old_state->dev->mode_config.num_total_plane; int i; - for (i = 0; i < nplanes; i++) { - plane = old_state->planes[i]; - old_plane_state = old_state->plane_states[i]; - - if (!plane) - continue; - + for_each_plane_in_state(old_state, plane, old_plane_state, i) { if (plane->state->crtc != crtc && old_plane_state->crtc != crtc) continue; @@ -940,16 +879,9 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, { struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; - int ncrtcs = old_state->dev->mode_config.num_crtc; int i, ret; - for (i = 0; i < ncrtcs; i++) { - crtc = old_state->crtcs[i]; - old_crtc_state = old_state->crtc_states[i]; - - if (!crtc) - continue; - + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { /* No one cares about the old state, so abuse it for tracking * and store whether we hold a vblank reference (and should do a * vblank wait) in the ->enable boolean. */ @@ -974,11 +906,8 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, old_crtc_state->last_vblank_count = drm_vblank_count(dev, i); } - for (i = 0; i < ncrtcs; i++) { - crtc = old_state->crtcs[i]; - old_crtc_state = old_state->crtc_states[i]; - - if (!crtc || !old_crtc_state->enable) + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { + if (!old_crtc_state->enable) continue; ret = wait_event_timeout(dev->vblank[i].queue, @@ -1176,16 +1105,14 @@ EXPORT_SYMBOL(drm_atomic_helper_prepare_planes); void drm_atomic_helper_commit_planes(struct drm_device *dev, struct drm_atomic_state *old_state) { - int nplanes = dev->mode_config.num_total_plane; - int ncrtcs = dev->mode_config.num_crtc; + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; + struct drm_plane *plane; + struct drm_plane_state *old_plane_state; int i; - for (i = 0; i < ncrtcs; i++) { + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { const struct drm_crtc_helper_funcs *funcs; - struct drm_crtc *crtc = old_state->crtcs[i]; - - if (!crtc) - continue; funcs = crtc->helper_private; @@ -1195,13 +1122,8 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, funcs->atomic_begin(crtc); } - for (i = 0; i < nplanes; i++) { + for_each_plane_in_state(old_state, plane, old_plane_state, i) { const struct drm_plane_helper_funcs *funcs; - struct drm_plane *plane = old_state->planes[i]; - struct drm_plane_state *old_plane_state; - - if (!plane) - continue; funcs = plane->helper_private; @@ -1220,12 +1142,8 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, funcs->atomic_update(plane, old_plane_state); } - for (i = 0; i < ncrtcs; i++) { + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { const struct drm_crtc_helper_funcs *funcs; - struct drm_crtc *crtc = old_state->crtcs[i]; - - if (!crtc) - continue; funcs = crtc->helper_private; @@ -1252,18 +1170,14 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_planes); void drm_atomic_helper_cleanup_planes(struct drm_device *dev, struct drm_atomic_state *old_state) { - int nplanes = dev->mode_config.num_total_plane; + struct drm_plane *plane; + struct drm_plane_state *plane_state; int i; - for (i = 0; i < nplanes; i++) { + for_each_plane_in_state(old_state, plane, plane_state, i) { const struct drm_plane_helper_funcs *funcs; - struct drm_plane *plane = old_state->planes[i]; - struct drm_plane_state *plane_state = old_state->plane_states[i]; struct drm_framebuffer *old_fb; - if (!plane) - continue; - funcs = plane->helper_private; old_fb = plane_state->fb; @@ -1512,8 +1426,10 @@ static int update_output_state(struct drm_atomic_state *state, struct drm_mode_set *set) { struct drm_device *dev = set->crtc->dev; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_connector *connector; struct drm_connector_state *conn_state; - int ncrtcs = state->dev->mode_config.num_crtc; int ret, i, j; ret = drm_modeset_lock(&dev->mode_config.connection_mutex, @@ -1529,27 +1445,14 @@ static int update_output_state(struct drm_atomic_state *state, return PTR_ERR(conn_state); } - for (i = 0; i < ncrtcs; i++) { - struct drm_crtc *crtc = state->crtcs[i]; - - if (!crtc) - continue; - + for_each_crtc_in_state(state, crtc, crtc_state, i) { ret = drm_atomic_add_affected_connectors(state, crtc); if (ret) return ret; } /* Then recompute connector->crtc links and crtc enabling state. */ - for (i = 0; i < state->num_connector; i++) { - struct drm_connector *connector; - - connector = state->connectors[i]; - conn_state = state->connector_states[i]; - - if (!connector) - continue; - + for_each_connector_in_state(state, connector, conn_state, i) { if (conn_state->crtc == set->crtc) { ret = drm_atomic_set_crtc_for_connector(conn_state, NULL); @@ -1568,13 +1471,7 @@ static int update_output_state(struct drm_atomic_state *state, } } - for (i = 0; i < ncrtcs; i++) { - struct drm_crtc *crtc = state->crtcs[i]; - struct drm_crtc_state *crtc_state = state->crtc_states[i]; - - if (!crtc) - continue; - + for_each_crtc_in_state(state, crtc, crtc_state, i) { /* Don't update ->enable for the CRTC in the set_config request, * since a mismatch would indicate a bug in the upper layers. * The actual modeset code later on will catch any diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 51168a8b723a..c157103492b0 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -75,4 +75,28 @@ int __must_check drm_atomic_check_only(struct drm_atomic_state *state); int __must_check drm_atomic_commit(struct drm_atomic_state *state); int __must_check drm_atomic_async_commit(struct drm_atomic_state *state); +#define for_each_connector_in_state(state, connector, connector_state, __i) \ + for ((__i) = 0; \ + (connector) = (state)->connectors[__i], \ + (connector_state) = (state)->connector_states[__i], \ + (__i) < (state)->num_connector; \ + (__i)++) \ + if (connector) + +#define for_each_crtc_in_state(state, crtc, crtc_state, __i) \ + for ((__i) = 0; \ + (crtc) = (state)->crtcs[__i], \ + (crtc_state) = (state)->crtc_states[__i], \ + (__i) < (state)->dev->mode_config.num_crtc; \ + (__i)++) \ + if (crtc_state) + +#define for_each_plane_in_state(state, plane, plane_state, __i) \ + for ((__i) = 0; \ + (plane) = (state)->planes[__i], \ + (plane_state) = (state)->plane_states[__i], \ + (__i) < (state)->dev->mode_config.num_total_plane; \ + (__i)++) \ + if (plane_state) + #endif /* DRM_ATOMIC_H_ */ -- cgit v1.2.3 From f6194213cbe871341cd5dfcfe31b4de78ef9503f Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 26 Mar 2015 13:07:29 +0000 Subject: clk: at91: change to using endian agnositc IO Change to using endian agnostic _relaxed IO accessors instead of __raw Signed-off-by: Ben Dooks -- CC: Andrew Victor CC: Nicolas Ferre CC: Jean-Christophe Plagniol-Villard CC: Mike Turquette (maintainer:COMMON CLK FRAMEWORK) CC: Stephen Boyd (maintainer:COMMON CLK FRAMEWORK) CC: linux-kernel@vger.kernel.org (open list:COMMON CLK FRAMEWORK) Signed-off-by: Michael Turquette --- include/linux/clk/at91_pmc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index c8e3b3d1eded..7669f7618f39 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -20,10 +20,10 @@ extern void __iomem *at91_pmc_base; #define at91_pmc_read(field) \ - __raw_readl(at91_pmc_base + field) + readl_relaxed(at91_pmc_base + field) #define at91_pmc_write(field, value) \ - __raw_writel(value, at91_pmc_base + field) + writel_relaxed(value, at91_pmc_base + field) #else .extern at91_pmc_base #endif -- cgit v1.2.3 From 453b44a3f6f3f43f50387a9af27c5356c273e831 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 1 Apr 2015 13:02:05 -0300 Subject: drm/exynos: fimd: fix alpha setting for XR24 pixel format XR24 planes were not shown properly, so now set the right registers to correctly enable displaying these planes. It also moves the alpha register settings to fimd_win_set_pixfmt() to keep all pixel format stuff together. v2: remove leftover var alpha Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 33 +++++++++++++++++++++----------- include/video/samsung_fimd.h | 5 +++++ 2 files changed, 27 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 33a10ce967ea..6f51d3d7ef6f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -54,6 +54,9 @@ /* size control register for hardware windows 1 ~ 2. */ #define VIDOSD_D(win) (VIDOSD_BASE + 0x0C + (win) * 16) +#define VIDWnALPHA0(win) (VIDW_ALPHA + 0x00 + (win) * 8) +#define VIDWnALPHA1(win) (VIDW_ALPHA + 0x04 + (win) * 8) + #define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8) #define VIDWx_BUF_END(win, buf) (VIDW_BUF_END(buf) + (win) * 8) #define VIDWx_BUF_SIZE(win, buf) (VIDW_BUF_SIZE(buf) + (win) * 4) @@ -620,6 +623,24 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) } writel(val, ctx->regs + WINCON(win)); + + /* hardware window 0 doesn't support alpha channel. */ + if (win != 0) { + /* OSD alpha */ + val = VIDISD14C_ALPHA0_R(0xf) | + VIDISD14C_ALPHA0_G(0xf) | + VIDISD14C_ALPHA0_B(0xf) | + VIDISD14C_ALPHA1_R(0xf) | + VIDISD14C_ALPHA1_G(0xf) | + VIDISD14C_ALPHA1_B(0xf); + + writel(val, ctx->regs + VIDOSD_C(win)); + + val = VIDW_ALPHA_R(0xf) | VIDW_ALPHA_G(0xf) | + VIDW_ALPHA_G(0xf); + writel(val, ctx->regs + VIDWnALPHA0(win)); + writel(val, ctx->regs + VIDWnALPHA1(win)); + } } static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win) @@ -667,7 +688,7 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos) struct fimd_context *ctx = crtc->ctx; struct fimd_win_data *win_data; int win = zpos; - unsigned long val, alpha, size; + unsigned long val, size; unsigned int last_x; unsigned int last_y; @@ -744,16 +765,6 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos) DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n", win_data->offset_x, win_data->offset_y, last_x, last_y); - /* hardware window 0 doesn't support alpha channel. */ - if (win != 0) { - /* OSD alpha */ - alpha = VIDISD14C_ALPHA1_R(0xf) | - VIDISD14C_ALPHA1_G(0xf) | - VIDISD14C_ALPHA1_B(0xf); - - writel(alpha, ctx->regs + VIDOSD_C(win)); - } - /* OSD size */ if (win != 3 && win != 4) { u32 offset = VIDOSD_D(win); diff --git a/include/video/samsung_fimd.h b/include/video/samsung_fimd.h index a20e4a3a8b15..513242827b07 100644 --- a/include/video/samsung_fimd.h +++ b/include/video/samsung_fimd.h @@ -289,6 +289,11 @@ #define VIDISD14C_ALPHA1_B_LIMIT 0xf #define VIDISD14C_ALPHA1_B(_x) ((_x) << 0) +#define VIDW_ALPHA 0x021c +#define VIDW_ALPHA_R(_x) ((_x) << 16) +#define VIDW_ALPHA_G(_x) ((_x) << 8) +#define VIDW_ALPHA_B(_x) ((_x) << 0) + /* Video buffer addresses */ #define VIDW_BUF_START(_buff) (0xA0 + ((_buff) * 8)) #define VIDW_BUF_START1(_buff) (0xA4 + ((_buff) * 8)) -- cgit v1.2.3 From 1c363c7cccf64128087002b0779986ad16aff6dc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Apr 2015 22:28:50 +0900 Subject: drm/exynos: Enable DP clock to fix display on Exynos5250 and other MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After adding display power domain for Exynos5250 in commit 2d2c9a8d0a4f ("ARM: dts: add display power domain for exynos5250") the display on Chromebook Snow and others stopped working after boot. The reason for this suggested Andrzej Hajda: the DP clock was disabled. This clock is required by Display Port and is enabled by bootloader. However when FIMD driver probing was deferred, the display power domain was turned off. This effectively reset the value of DP clock enable register. When exynos-dp is later probed, the clock is not enabled and display is not properly configured: exynos-dp 145b0000.dp-controller: Timeout of video streamclk ok exynos-dp 145b0000.dp-controller: unable to config video Fixes: 2d2c9a8d0a4f ("ARM: dts: add display power domain for exynos5250") Cc: Signed-off-by: Krzysztof Kozlowski Reported-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Tested-by: Andreas Färber Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_dp_core.c | 10 ++++++++++ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 19 +++++++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_fimd.h | 15 +++++++++++++++ include/video/samsung_fimd.h | 6 ++++++ 4 files changed, 50 insertions(+) create mode 100644 drivers/gpu/drm/exynos/exynos_drm_fimd.h (limited to 'include') diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index bf17a60b40ed..1dbfba58f909 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -32,10 +32,16 @@ #include #include "exynos_dp_core.h" +#include "exynos_drm_fimd.h" #define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \ connector) +static inline struct exynos_drm_crtc *dp_to_crtc(struct exynos_dp_device *dp) +{ + return to_exynos_crtc(dp->encoder->crtc); +} + static inline struct exynos_dp_device * display_to_dp(struct exynos_drm_display *d) { @@ -1070,6 +1076,8 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp) } } + fimd_dp_clock_enable(dp_to_crtc(dp), true); + clk_prepare_enable(dp->clock); exynos_dp_phy_init(dp); exynos_dp_init_dp(dp); @@ -1094,6 +1102,8 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp) exynos_dp_phy_exit(dp); clk_disable_unprepare(dp->clock); + fimd_dp_clock_enable(dp_to_crtc(dp), false); + if (dp->panel) { if (drm_panel_unprepare(dp->panel)) DRM_ERROR("failed to turnoff the panel\n"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index bf29a44cf77b..6d2858ae6ad5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -33,6 +33,7 @@ #include "exynos_drm_crtc.h" #include "exynos_drm_plane.h" #include "exynos_drm_iommu.h" +#include "exynos_drm_fimd.h" /* * FIMD stands for Fully Interactive Mobile Display and @@ -1191,6 +1192,24 @@ static int fimd_remove(struct platform_device *pdev) return 0; } +void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable) +{ + struct fimd_context *ctx = crtc->ctx; + u32 val; + + /* + * Only Exynos 5250, 5260, 5410 and 542x requires enabling DP/MIE + * clock. On these SoCs the bootloader may enable it but any + * power domain off/on will reset it to disable state. + */ + if (ctx->driver_data != &exynos5_fimd_driver_data) + return; + + val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE; + writel(DP_MIE_CLK_DP_ENABLE, ctx->regs + DP_MIE_CLKCON); +} +EXPORT_SYMBOL_GPL(fimd_dp_clock_enable); + struct platform_driver fimd_driver = { .probe = fimd_probe, .remove = fimd_remove, diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.h b/drivers/gpu/drm/exynos/exynos_drm_fimd.h new file mode 100644 index 000000000000..b4fcaa568456 --- /dev/null +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#ifndef _EXYNOS_DRM_FIMD_H_ +#define _EXYNOS_DRM_FIMD_H_ + +extern void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable); + +#endif /* _EXYNOS_DRM_FIMD_H_ */ diff --git a/include/video/samsung_fimd.h b/include/video/samsung_fimd.h index 513242827b07..0530e5a4c6b1 100644 --- a/include/video/samsung_fimd.h +++ b/include/video/samsung_fimd.h @@ -441,6 +441,12 @@ #define BLENDCON_NEW_8BIT_ALPHA_VALUE (1 << 0) #define BLENDCON_NEW_4BIT_ALPHA_VALUE (0 << 0) +/* Display port clock control */ +#define DP_MIE_CLKCON 0x27c +#define DP_MIE_CLK_DISABLE 0x0 +#define DP_MIE_CLK_DP_ENABLE 0x2 +#define DP_MIE_CLK_MIE_ENABLE 0x3 + /* Notes on per-window bpp settings * * Value Win0 Win1 Win2 Win3 Win 4 -- cgit v1.2.3 From 9e1a27ea42691429e31f158cce6fc61bc79bb2e9 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 13 Apr 2015 21:03:49 +0930 Subject: virtio_ring: Update weak barriers to use dma_wmb/rmb This change makes it so that instead of using smp_wmb/rmb which varies depending on the kernel configuration we can can use dma_wmb/rmb which for most architectures should be equal to or slightly more strict than smp_wmb/rmb. The advantage to this is that these barriers are available to uniprocessor builds as well so the performance should improve under such a configuration. Signed-off-by: Alexander Duyck Signed-off-by: Rusty Russell --- include/linux/virtio_ring.h | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h index 67e06fe18c03..8e50888a6d59 100644 --- a/include/linux/virtio_ring.h +++ b/include/linux/virtio_ring.h @@ -21,19 +21,20 @@ * actually quite cheap. */ -#ifdef CONFIG_SMP static inline void virtio_mb(bool weak_barriers) { +#ifdef CONFIG_SMP if (weak_barriers) smp_mb(); else +#endif mb(); } static inline void virtio_rmb(bool weak_barriers) { if (weak_barriers) - smp_rmb(); + dma_rmb(); else rmb(); } @@ -41,26 +42,10 @@ static inline void virtio_rmb(bool weak_barriers) static inline void virtio_wmb(bool weak_barriers) { if (weak_barriers) - smp_wmb(); + dma_wmb(); else wmb(); } -#else -static inline void virtio_mb(bool weak_barriers) -{ - mb(); -} - -static inline void virtio_rmb(bool weak_barriers) -{ - rmb(); -} - -static inline void virtio_wmb(bool weak_barriers) -{ - wmb(); -} -#endif struct virtio_device; struct virtqueue; -- cgit v1.2.3 From 1b54bdb8ccbc46e5a406a690d48a1639d5001f4b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 13 Apr 2015 10:57:14 +0300 Subject: drm/edid: add #defines for ELD versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ELD versions according to HDA Specification v1.0a. 2 indicates version 2, which supports CEA_Ver 861D or below. Maximum Baseline ELD size of 80 bytes (15 SAD count). 31 indicates an ELD that has been partially populated through implementation specific mean of default programming before an external graphics driver is loaded. Only the field that is called out as "canned" field will be populated, and audio driver should ignore the non "canned" field. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- include/drm/drm_edid.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 87d85e81d3a7..799050198323 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -215,6 +215,8 @@ struct detailed_timing { #define DRM_ELD_VER 0 # define DRM_ELD_VER_SHIFT 3 # define DRM_ELD_VER_MASK (0x1f << 3) +# define DRM_ELD_VER_CEA861D (2 << 3) /* supports 861D or below */ +# define DRM_ELD_VER_CANNED (0x1f << 3) #define DRM_ELD_BASELINE_ELD_LEN 2 /* in dwords! */ -- cgit v1.2.3 From 9a436ee6c3f311f2ae604d775d7de06a49f8c9a0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 13 Apr 2015 11:21:42 +0300 Subject: drm: make crtc/encoder/connector/plane helper_private a const pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They're only used to store const pointers anyway. This helps to keep Ville and the compiler happy. Signed-off-by: Jani Nikula Reviewed-by: Christian König Signed-off-by: Daniel Vetter --- include/drm/drm_crtc.h | 8 ++++---- include/drm/drm_crtc_helper.h | 6 +++--- include/drm/drm_plane_helper.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 7b5c661b37d8..97c33b40005f 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -467,7 +467,7 @@ struct drm_crtc { int framedur_ns, linedur_ns, pixeldur_ns; /* if you are using the helper */ - void *helper_private; + const void *helper_private; struct drm_object_properties properties; @@ -597,7 +597,7 @@ struct drm_encoder { struct drm_crtc *crtc; struct drm_bridge *bridge; const struct drm_encoder_funcs *funcs; - void *helper_private; + const void *helper_private; }; /* should we poll this connector for connects and disconnects */ @@ -701,7 +701,7 @@ struct drm_connector { /* requested DPMS state */ int dpms; - void *helper_private; + const void *helper_private; /* forced on connector */ struct drm_cmdline_mode cmdline_mode; @@ -864,7 +864,7 @@ struct drm_plane { enum drm_plane_type type; - void *helper_private; + const void *helper_private; struct drm_plane_state *state; }; diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 92d5135b55d2..c8fc187061de 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -197,19 +197,19 @@ extern void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, static inline void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_crtc_helper_funcs *funcs) { - crtc->helper_private = (void *)funcs; + crtc->helper_private = funcs; } static inline void drm_encoder_helper_add(struct drm_encoder *encoder, const struct drm_encoder_helper_funcs *funcs) { - encoder->helper_private = (void *)funcs; + encoder->helper_private = funcs; } static inline void drm_connector_helper_add(struct drm_connector *connector, const struct drm_connector_helper_funcs *funcs) { - connector->helper_private = (void *)funcs; + connector->helper_private = funcs; } extern void drm_helper_resume_force_mode(struct drm_device *dev); diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index e48157a5a59c..96e16283afb9 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -76,7 +76,7 @@ struct drm_plane_helper_funcs { static inline void drm_plane_helper_add(struct drm_plane *plane, const struct drm_plane_helper_funcs *funcs) { - plane->helper_private = (void *)funcs; + plane->helper_private = funcs; } extern int drm_plane_helper_check_update(struct drm_plane *plane, -- cgit v1.2.3 From 9fdd8a875c6f3b02af48d5fa426206ca009b2b06 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 6 Apr 2015 14:36:09 +0900 Subject: tracing, mm: Record pfn instead of pointer to struct page The struct page is opaque for userspace tools, so it'd be better to save pfn in order to identify page frames. The textual output of $debugfs/tracing/trace file remains unchanged and only raw (binary) data format is changed - but thanks to libtraceevent, userspace tools which deal with the raw data (like perf and trace-cmd) can parse the format easily. So impact on the userspace will also be minimal. Signed-off-by: Namhyung Kim Based-on-patch-by: Joonsoo Kim Acked-by: Ingo Molnar Acked-by: Steven Rostedt Cc: David Ahern Cc: Jiri Olsa Cc: Minchan Kim Cc: Peter Zijlstra Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/1428298576-9785-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- include/trace/events/filemap.h | 8 ++++---- include/trace/events/kmem.h | 42 +++++++++++++++++++++--------------------- include/trace/events/vmscan.h | 8 ++++---- 3 files changed, 29 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/include/trace/events/filemap.h b/include/trace/events/filemap.h index 0421f49a20f7..42febb6bc1d5 100644 --- a/include/trace/events/filemap.h +++ b/include/trace/events/filemap.h @@ -18,14 +18,14 @@ DECLARE_EVENT_CLASS(mm_filemap_op_page_cache, TP_ARGS(page), TP_STRUCT__entry( - __field(struct page *, page) + __field(unsigned long, pfn) __field(unsigned long, i_ino) __field(unsigned long, index) __field(dev_t, s_dev) ), TP_fast_assign( - __entry->page = page; + __entry->pfn = page_to_pfn(page); __entry->i_ino = page->mapping->host->i_ino; __entry->index = page->index; if (page->mapping->host->i_sb) @@ -37,8 +37,8 @@ DECLARE_EVENT_CLASS(mm_filemap_op_page_cache, TP_printk("dev %d:%d ino %lx page=%p pfn=%lu ofs=%lu", MAJOR(__entry->s_dev), MINOR(__entry->s_dev), __entry->i_ino, - __entry->page, - page_to_pfn(__entry->page), + pfn_to_page(__entry->pfn), + __entry->pfn, __entry->index << PAGE_SHIFT) ); diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h index 4ad10baecd4d..81ea59812117 100644 --- a/include/trace/events/kmem.h +++ b/include/trace/events/kmem.h @@ -154,18 +154,18 @@ TRACE_EVENT(mm_page_free, TP_ARGS(page, order), TP_STRUCT__entry( - __field( struct page *, page ) + __field( unsigned long, pfn ) __field( unsigned int, order ) ), TP_fast_assign( - __entry->page = page; + __entry->pfn = page_to_pfn(page); __entry->order = order; ), TP_printk("page=%p pfn=%lu order=%d", - __entry->page, - page_to_pfn(__entry->page), + pfn_to_page(__entry->pfn), + __entry->pfn, __entry->order) ); @@ -176,18 +176,18 @@ TRACE_EVENT(mm_page_free_batched, TP_ARGS(page, cold), TP_STRUCT__entry( - __field( struct page *, page ) + __field( unsigned long, pfn ) __field( int, cold ) ), TP_fast_assign( - __entry->page = page; + __entry->pfn = page_to_pfn(page); __entry->cold = cold; ), TP_printk("page=%p pfn=%lu order=0 cold=%d", - __entry->page, - page_to_pfn(__entry->page), + pfn_to_page(__entry->pfn), + __entry->pfn, __entry->cold) ); @@ -199,22 +199,22 @@ TRACE_EVENT(mm_page_alloc, TP_ARGS(page, order, gfp_flags, migratetype), TP_STRUCT__entry( - __field( struct page *, page ) + __field( unsigned long, pfn ) __field( unsigned int, order ) __field( gfp_t, gfp_flags ) __field( int, migratetype ) ), TP_fast_assign( - __entry->page = page; + __entry->pfn = page ? page_to_pfn(page) : -1UL; __entry->order = order; __entry->gfp_flags = gfp_flags; __entry->migratetype = migratetype; ), TP_printk("page=%p pfn=%lu order=%d migratetype=%d gfp_flags=%s", - __entry->page, - __entry->page ? page_to_pfn(__entry->page) : 0, + __entry->pfn != -1UL ? pfn_to_page(__entry->pfn) : NULL, + __entry->pfn != -1UL ? __entry->pfn : 0, __entry->order, __entry->migratetype, show_gfp_flags(__entry->gfp_flags)) @@ -227,20 +227,20 @@ DECLARE_EVENT_CLASS(mm_page, TP_ARGS(page, order, migratetype), TP_STRUCT__entry( - __field( struct page *, page ) + __field( unsigned long, pfn ) __field( unsigned int, order ) __field( int, migratetype ) ), TP_fast_assign( - __entry->page = page; + __entry->pfn = page ? page_to_pfn(page) : -1UL; __entry->order = order; __entry->migratetype = migratetype; ), TP_printk("page=%p pfn=%lu order=%u migratetype=%d percpu_refill=%d", - __entry->page, - __entry->page ? page_to_pfn(__entry->page) : 0, + __entry->pfn != -1UL ? pfn_to_page(__entry->pfn) : NULL, + __entry->pfn != -1UL ? __entry->pfn : 0, __entry->order, __entry->migratetype, __entry->order == 0) @@ -260,7 +260,7 @@ DEFINE_EVENT_PRINT(mm_page, mm_page_pcpu_drain, TP_ARGS(page, order, migratetype), TP_printk("page=%p pfn=%lu order=%d migratetype=%d", - __entry->page, page_to_pfn(__entry->page), + pfn_to_page(__entry->pfn), __entry->pfn, __entry->order, __entry->migratetype) ); @@ -275,7 +275,7 @@ TRACE_EVENT(mm_page_alloc_extfrag, alloc_migratetype, fallback_migratetype), TP_STRUCT__entry( - __field( struct page *, page ) + __field( unsigned long, pfn ) __field( int, alloc_order ) __field( int, fallback_order ) __field( int, alloc_migratetype ) @@ -284,7 +284,7 @@ TRACE_EVENT(mm_page_alloc_extfrag, ), TP_fast_assign( - __entry->page = page; + __entry->pfn = page_to_pfn(page); __entry->alloc_order = alloc_order; __entry->fallback_order = fallback_order; __entry->alloc_migratetype = alloc_migratetype; @@ -294,8 +294,8 @@ TRACE_EVENT(mm_page_alloc_extfrag, ), TP_printk("page=%p pfn=%lu alloc_order=%d fallback_order=%d pageblock_order=%d alloc_migratetype=%d fallback_migratetype=%d fragmenting=%d change_ownership=%d", - __entry->page, - page_to_pfn(__entry->page), + pfn_to_page(__entry->pfn), + __entry->pfn, __entry->alloc_order, __entry->fallback_order, pageblock_order, diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h index 69590b6ffc09..f66476b96264 100644 --- a/include/trace/events/vmscan.h +++ b/include/trace/events/vmscan.h @@ -336,18 +336,18 @@ TRACE_EVENT(mm_vmscan_writepage, TP_ARGS(page, reclaim_flags), TP_STRUCT__entry( - __field(struct page *, page) + __field(unsigned long, pfn) __field(int, reclaim_flags) ), TP_fast_assign( - __entry->page = page; + __entry->pfn = page_to_pfn(page); __entry->reclaim_flags = reclaim_flags; ), TP_printk("page=%p pfn=%lu flags=%s", - __entry->page, - page_to_pfn(__entry->page), + pfn_to_page(__entry->pfn), + __entry->pfn, show_reclaim_flags(__entry->reclaim_flags)) ); -- cgit v1.2.3 From 996f545fbb0dc9ed4a640b5ef098f51fe28cca5c Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Thu, 26 Feb 2015 12:44:51 +0900 Subject: drm/nouveau/gem: allow user-space to specify an object should be coherent User-space use mappable BOs notably for fences, and expects that a value update by the GPU will be immediatly visible through the user-space mapping. ARM has a property that may prevent this from happening though: memory can be mapped multiple times only if the different mappings share the same caching properties. However all the lowmem memory is already identity-mapped into the kernel with cache enabled, so when user-space requests an uncached mapping, we actually get an "undefined caching policy" one and this has strange side-effects described on Freedesktop bug 86690. To prevent this from happening, allow user-space to explicitly specify which objects should be coherent, and create such objects with the TTM_PL_FLAG_UNCACHED flag. This will make TTM allocate memory using the DMA API, which will fix the identify mapping and allow us to safely map the objects to user-space uncached. Signed-off-by: Alexandre Courbot Reviewed-by: Lucas Stach Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_gem.c | 3 +++ include/uapi/drm/nouveau_drm.h | 1 + 2 files changed, 4 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 7c077fced1d1..0e690bf19fc9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -189,6 +189,9 @@ nouveau_gem_new(struct drm_device *dev, int size, int align, uint32_t domain, if (!flags || domain & NOUVEAU_GEM_DOMAIN_CPU) flags |= TTM_PL_FLAG_SYSTEM; + if (domain & NOUVEAU_GEM_DOMAIN_COHERENT) + flags |= TTM_PL_FLAG_UNCACHED; + ret = nouveau_bo_new(dev, size, align, flags, tile_mode, tile_flags, NULL, NULL, pnvbo); if (ret) diff --git a/include/uapi/drm/nouveau_drm.h b/include/uapi/drm/nouveau_drm.h index 0d7608dc1a34..5507eead5863 100644 --- a/include/uapi/drm/nouveau_drm.h +++ b/include/uapi/drm/nouveau_drm.h @@ -39,6 +39,7 @@ #define NOUVEAU_GEM_DOMAIN_VRAM (1 << 1) #define NOUVEAU_GEM_DOMAIN_GART (1 << 2) #define NOUVEAU_GEM_DOMAIN_MAPPABLE (1 << 3) +#define NOUVEAU_GEM_DOMAIN_COHERENT (1 << 4) #define NOUVEAU_GEM_TILE_COMP 0x00030000 /* nv50-only */ #define NOUVEAU_GEM_TILE_LAYOUT_MASK 0x0000ff00 -- cgit v1.2.3 From 2b1193d5287004edfbf89407149a3159656f47f1 Mon Sep 17 00:00:00 2001 From: John Hunter Date: Tue, 14 Apr 2015 17:07:22 +0800 Subject: drm: fix trivial typo mistake Signed-off-by: John Hunter Signed-off-by: Daniel Vetter --- include/drm/drm_crtc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 97c33b40005f..b009d707f562 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -975,7 +975,7 @@ struct drm_mode_set { * struct drm_mode_config_funcs - basic driver provided mode setting functions * @fb_create: create a new framebuffer object * @output_poll_changed: function to handle output configuration changes - * @atomic_check: check whether a give atomic state update is possible + * @atomic_check: check whether a given atomic state update is possible * @atomic_commit: commit an atomic state update previously verified with * atomic_check() * -- cgit v1.2.3 From 9ac8928e6a3e1ed02e632e45aa766129fe6b1802 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 8 Apr 2015 20:01:35 +0200 Subject: target: simplify the target template registration API Instead of calling target_fabric_configfs_init() + target_fabric_configfs_register() / target_fabric_configfs_deregister() target_fabric_configfs_free() from every target driver, rewrite the API so that we have simple register/unregister functions that operate on a const operations vector. This patch also fixes a memory leak in several target drivers. Several target drivers namely called target_fabric_configfs_deregister() without calling target_fabric_configfs_free(). A large part of this patch is based on earlier changes from Bart Van Assche . (v2: Add a new TF_CIT_SETUP_DRV macro so that the core configfs code can declare attributes as either core only or for drivers) Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 79 ++---------- drivers/infiniband/ulp/srpt/ib_srpt.c | 49 ++------ drivers/scsi/qla2xxx/qla_target.c | 2 +- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 118 ++++-------------- drivers/target/iscsi/iscsi_target.c | 23 ++-- drivers/target/iscsi/iscsi_target.h | 2 +- drivers/target/iscsi/iscsi_target_configfs.c | 180 +++++++++------------------ drivers/target/iscsi/iscsi_target_configfs.h | 7 -- drivers/target/iscsi/iscsi_target_tpg.c | 6 +- drivers/target/loopback/tcm_loop.c | 178 ++++++++------------------ drivers/target/sbp/sbp_target.c | 68 ++-------- drivers/target/target_core_configfs.c | 176 +++++++------------------- drivers/target/target_core_fabric_configfs.c | 38 ++++-- drivers/target/target_core_pr.c | 16 +-- drivers/target/target_core_tpg.c | 2 +- drivers/target/target_core_transport.c | 6 +- drivers/target/target_core_xcopy.c | 2 +- drivers/target/tcm_fc/tcm_fc.h | 1 - drivers/target/tcm_fc/tfc_conf.c | 89 ++++--------- drivers/usb/gadget/legacy/tcm_usb_gadget.c | 57 ++------- drivers/vhost/scsi.c | 76 ++--------- drivers/xen/xen-scsiback.c | 74 ++--------- include/target/target_core_base.h | 4 +- include/target/target_core_configfs.h | 6 - include/target/target_core_fabric.h | 24 +++- 25 files changed, 356 insertions(+), 927 deletions(-) delete mode 100644 drivers/target/iscsi/iscsi_target_configfs.h (limited to 'include') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 2b47704f75cb..27afc033761f 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -237,8 +237,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "#include \"" + fabric_mod_name + "_base.h\"\n" buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n" - buf += "/* Local pointer to allocated TCM configfs fabric module */\n" - buf += "struct target_fabric_configfs *" + fabric_mod_name + "_fabric_configfs;\n\n" + buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops;\n\n" buf += "static struct se_node_acl *" + fabric_mod_name + "_make_nodeacl(\n" buf += " struct se_portal_group *se_tpg,\n" @@ -309,8 +308,8 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " }\n" buf += " tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n" buf += " tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n" - buf += " ret = core_tpg_register(&" + fabric_mod_name + "_fabric_configfs->tf_ops, wwn,\n" - buf += " &tpg->se_tpg, (void *)tpg,\n" + buf += " ret = core_tpg_register(&" + fabric_mod_name + "_ops, wwn,\n" + buf += " &tpg->se_tpg, tpg,\n" buf += " TRANSPORT_TPG_TYPE_NORMAL);\n" buf += " if (ret < 0) {\n" buf += " kfree(tpg);\n" @@ -370,7 +369,10 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " NULL,\n" buf += "};\n\n" - buf += "static struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n" + buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n" + buf += " .module = THIS_MODULE\n", + buf += " .name = " + fabric_mod_name + ",\n" + buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n" buf += " .get_fabric_name = " + fabric_mod_name + "_get_fabric_name,\n" buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n" buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n" @@ -413,75 +415,18 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " .fabric_drop_np = NULL,\n" buf += " .fabric_make_nodeacl = " + fabric_mod_name + "_make_nodeacl,\n" buf += " .fabric_drop_nodeacl = " + fabric_mod_name + "_drop_nodeacl,\n" - buf += "};\n\n" - - buf += "static int " + fabric_mod_name + "_register_configfs(void)\n" - buf += "{\n" - buf += " struct target_fabric_configfs *fabric;\n" - buf += " int ret;\n\n" - buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + " fabric module %s on %s/%s\"\n" - buf += " \" on \"UTS_RELEASE\"\\n\"," + fabric_mod_name.upper() + "_VERSION, utsname()->sysname,\n" - buf += " utsname()->machine);\n" - buf += " /*\n" - buf += " * Register the top level struct config_item_type with TCM core\n" - buf += " */\n" - buf += " fabric = target_fabric_configfs_init(THIS_MODULE, \"" + fabric_mod_name + "\");\n" - buf += " if (IS_ERR(fabric)) {\n" - buf += " printk(KERN_ERR \"target_fabric_configfs_init() failed\\n\");\n" - buf += " return PTR_ERR(fabric);\n" - buf += " }\n" - buf += " /*\n" - buf += " * Setup fabric->tf_ops from our local " + fabric_mod_name + "_ops\n" - buf += " */\n" - buf += " fabric->tf_ops = " + fabric_mod_name + "_ops;\n" - buf += " /*\n" - buf += " * Setup default attribute lists for various fabric->tf_cit_tmpl\n" - buf += " */\n" - buf += " fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = " + fabric_mod_name + "_wwn_attrs;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;\n" - buf += " /*\n" - buf += " * Register the fabric for use within TCM\n" - buf += " */\n" - buf += " ret = target_fabric_configfs_register(fabric);\n" - buf += " if (ret < 0) {\n" - buf += " printk(KERN_ERR \"target_fabric_configfs_register() failed\"\n" - buf += " \" for " + fabric_mod_name.upper() + "\\n\");\n" - buf += " return ret;\n" - buf += " }\n" - buf += " /*\n" - buf += " * Setup our local pointer to *fabric\n" - buf += " */\n" - buf += " " + fabric_mod_name + "_fabric_configfs = fabric;\n" - buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Set fabric -> " + fabric_mod_name + "_fabric_configfs\\n\");\n" - buf += " return 0;\n" - buf += "};\n\n" - buf += "static void __exit " + fabric_mod_name + "_deregister_configfs(void)\n" - buf += "{\n" - buf += " if (!" + fabric_mod_name + "_fabric_configfs)\n" - buf += " return;\n\n" - buf += " target_fabric_configfs_deregister(" + fabric_mod_name + "_fabric_configfs);\n" - buf += " " + fabric_mod_name + "_fabric_configfs = NULL;\n" - buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Cleared " + fabric_mod_name + "_fabric_configfs\\n\");\n" + buf += "\n" + buf += " .tfc_wwn_attrs = " + fabric_mod_name + "_wwn_attrs;\n" buf += "};\n\n" buf += "static int __init " + fabric_mod_name + "_init(void)\n" buf += "{\n" - buf += " int ret;\n\n" - buf += " ret = " + fabric_mod_name + "_register_configfs();\n" - buf += " if (ret < 0)\n" - buf += " return ret;\n\n" - buf += " return 0;\n" + buf += " return target_register_template(" + fabric_mod_name + "_ops);\n" buf += "};\n\n" + buf += "static void __exit " + fabric_mod_name + "_exit(void)\n" buf += "{\n" - buf += " " + fabric_mod_name + "_deregister_configfs();\n" + buf += " target_unregister_template(" + fabric_mod_name + "_ops);\n" buf += "};\n\n" buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 6e0a477681e9..07015389ee5a 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -93,7 +93,7 @@ MODULE_PARM_DESC(srpt_service_guid, " instead of using the node_guid of the first HCA."); static struct ib_client srpt_client; -static struct target_fabric_configfs *srpt_target; +static const struct target_core_fabric_ops srpt_template; static void srpt_release_channel(struct srpt_rdma_ch *ch); static int srpt_queue_status(struct se_cmd *cmd); @@ -3851,7 +3851,7 @@ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn, int res; /* Initialize sport->port_wwn and sport->port_tpg_1 */ - res = core_tpg_register(&srpt_target->tf_ops, &sport->port_wwn, + res = core_tpg_register(&srpt_template, &sport->port_wwn, &sport->port_tpg_1, sport, TRANSPORT_TPG_TYPE_NORMAL); if (res) return ERR_PTR(res); @@ -3919,7 +3919,9 @@ static struct configfs_attribute *srpt_wwn_attrs[] = { NULL, }; -static struct target_core_fabric_ops srpt_template = { +static const struct target_core_fabric_ops srpt_template = { + .module = THIS_MODULE, + .name = "srpt", .get_fabric_name = srpt_get_fabric_name, .get_fabric_proto_ident = srpt_get_fabric_proto_ident, .tpg_get_wwn = srpt_get_fabric_wwn, @@ -3964,6 +3966,10 @@ static struct target_core_fabric_ops srpt_template = { .fabric_drop_np = NULL, .fabric_make_nodeacl = srpt_make_nodeacl, .fabric_drop_nodeacl = srpt_drop_nodeacl, + + .tfc_wwn_attrs = srpt_wwn_attrs, + .tfc_tpg_base_attrs = srpt_tpg_attrs, + .tfc_tpg_attrib_attrs = srpt_tpg_attrib_attrs, }; /** @@ -3994,33 +4000,9 @@ static int __init srpt_init_module(void) goto out; } - srpt_target = target_fabric_configfs_init(THIS_MODULE, "srpt"); - if (IS_ERR(srpt_target)) { - printk(KERN_ERR "couldn't register\n"); - ret = PTR_ERR(srpt_target); + ret = target_register_template(&srpt_template); + if (ret) goto out; - } - - srpt_target->tf_ops = srpt_template; - - /* - * Set up default attribute lists. - */ - srpt_target->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = srpt_wwn_attrs; - srpt_target->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = srpt_tpg_attrs; - srpt_target->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = srpt_tpg_attrib_attrs; - srpt_target->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - srpt_target->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - srpt_target->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - srpt_target->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - srpt_target->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - srpt_target->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - - ret = target_fabric_configfs_register(srpt_target); - if (ret < 0) { - printk(KERN_ERR "couldn't register\n"); - goto out_free_target; - } ret = ib_register_client(&srpt_client); if (ret) { @@ -4031,11 +4013,7 @@ static int __init srpt_init_module(void) return 0; out_unregister_target: - target_fabric_configfs_deregister(srpt_target); - srpt_target = NULL; -out_free_target: - if (srpt_target) - target_fabric_configfs_free(srpt_target); + target_unregister_template(&srpt_template); out: return ret; } @@ -4043,8 +4021,7 @@ out: static void __exit srpt_cleanup_module(void) { ib_unregister_client(&srpt_client); - target_fabric_configfs_deregister(srpt_target); - srpt_target = NULL; + target_unregister_template(&srpt_template); } module_init(srpt_init_module); diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 57418258c101..fe8a8d157e22 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -3065,7 +3065,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle, { struct qla_hw_data *ha = vha->hw; struct se_cmd *se_cmd; - struct target_core_fabric_ops *tfo; + const struct target_core_fabric_ops *tfo; struct qla_tgt_cmd *cmd; if (handle & CTIO_INTERMEDIATE_HANDLE_MARK) { diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 843b53b0e9f2..acf54cdbca2c 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -53,9 +53,8 @@ static struct workqueue_struct *tcm_qla2xxx_free_wq; static struct workqueue_struct *tcm_qla2xxx_cmd_wq; -/* Local pointer to allocated TCM configfs fabric module */ -static struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs; -static struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs; +static const struct target_core_fabric_ops tcm_qla2xxx_ops; +static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops; /* * Parse WWN. @@ -1177,7 +1176,7 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg( tpg->tpg_attrib.cache_dynamic_acls = 1; tpg->tpg_attrib.demo_mode_login_only = 1; - ret = core_tpg_register(&tcm_qla2xxx_fabric_configfs->tf_ops, wwn, + ret = core_tpg_register(&tcm_qla2xxx_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) { kfree(tpg); @@ -1297,7 +1296,7 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg( tpg->tpg_attrib.cache_dynamic_acls = 1; tpg->tpg_attrib.demo_mode_login_only = 1; - ret = core_tpg_register(&tcm_qla2xxx_npiv_fabric_configfs->tf_ops, wwn, + ret = core_tpg_register(&tcm_qla2xxx_npiv_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) { kfree(tpg); @@ -1987,7 +1986,9 @@ static struct configfs_attribute *tcm_qla2xxx_wwn_attrs[] = { NULL, }; -static struct target_core_fabric_ops tcm_qla2xxx_ops = { +static const struct target_core_fabric_ops tcm_qla2xxx_ops = { + .module = THIS_MODULE, + .name = "qla2xxx", .get_fabric_name = tcm_qla2xxx_get_fabric_name, .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, @@ -2037,9 +2038,15 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = { .fabric_drop_np = NULL, .fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl, .fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl, + + .tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs, + .tfc_tpg_base_attrs = tcm_qla2xxx_tpg_attrs, + .tfc_tpg_attrib_attrs = tcm_qla2xxx_tpg_attrib_attrs, }; -static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { +static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { + .module = THIS_MODULE, + .name = "qla2xxx_npiv", .get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name, .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, @@ -2087,94 +2094,26 @@ static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .fabric_drop_np = NULL, .fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl, .fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl, + + .tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs, + .tfc_tpg_base_attrs = tcm_qla2xxx_npiv_tpg_attrs, }; static int tcm_qla2xxx_register_configfs(void) { - struct target_fabric_configfs *fabric, *npiv_fabric; int ret; pr_debug("TCM QLOGIC QLA2XXX fabric module %s on %s/%s on " UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname, utsname()->machine); - /* - * Register the top level struct config_item_type with TCM core - */ - fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx"); - if (IS_ERR(fabric)) { - pr_err("target_fabric_configfs_init() failed\n"); - return PTR_ERR(fabric); - } - /* - * Setup fabric->tf_ops from our local tcm_qla2xxx_ops - */ - fabric->tf_ops = tcm_qla2xxx_ops; - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - */ - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = tcm_qla2xxx_tpg_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = - tcm_qla2xxx_tpg_attrib_attrs; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - /* - * Register the fabric for use within TCM - */ - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() failed for TCM_QLA2XXX\n"); + + ret = target_register_template(&tcm_qla2xxx_ops); + if (ret) return ret; - } - /* - * Setup our local pointer to *fabric - */ - tcm_qla2xxx_fabric_configfs = fabric; - pr_debug("TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_fabric_configfs\n"); - /* - * Register the top level struct config_item_type for NPIV with TCM core - */ - npiv_fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx_npiv"); - if (IS_ERR(npiv_fabric)) { - pr_err("target_fabric_configfs_init() failed\n"); - ret = PTR_ERR(npiv_fabric); + ret = target_register_template(&tcm_qla2xxx_npiv_ops); + if (ret) goto out_fabric; - } - /* - * Setup fabric->tf_ops from our local tcm_qla2xxx_npiv_ops - */ - npiv_fabric->tf_ops = tcm_qla2xxx_npiv_ops; - /* - * Setup default attribute lists for various npiv_fabric->tf_cit_tmpl - */ - npiv_fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs; - npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = - tcm_qla2xxx_npiv_tpg_attrs; - npiv_fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL; - npiv_fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - npiv_fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - /* - * Register the npiv_fabric for use within TCM - */ - ret = target_fabric_configfs_register(npiv_fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() failed for TCM_QLA2XXX\n"); - goto out_fabric; - } - /* - * Setup our local pointer to *npiv_fabric - */ - tcm_qla2xxx_npiv_fabric_configfs = npiv_fabric; - pr_debug("TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_npiv_fabric_configfs\n"); tcm_qla2xxx_free_wq = alloc_workqueue("tcm_qla2xxx_free", WQ_MEM_RECLAIM, 0); @@ -2194,9 +2133,9 @@ static int tcm_qla2xxx_register_configfs(void) out_free_wq: destroy_workqueue(tcm_qla2xxx_free_wq); out_fabric_npiv: - target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs); + target_unregister_template(&tcm_qla2xxx_npiv_ops); out_fabric: - target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs); + target_unregister_template(&tcm_qla2xxx_ops); return ret; } @@ -2205,13 +2144,8 @@ static void tcm_qla2xxx_deregister_configfs(void) destroy_workqueue(tcm_qla2xxx_cmd_wq); destroy_workqueue(tcm_qla2xxx_free_wq); - target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs); - tcm_qla2xxx_fabric_configfs = NULL; - pr_debug("TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_fabric_configfs\n"); - - target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs); - tcm_qla2xxx_npiv_fabric_configfs = NULL; - pr_debug("TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_npiv_fabric_configfs\n"); + target_unregister_template(&tcm_qla2xxx_ops); + target_unregister_template(&tcm_qla2xxx_npiv_ops); } static int __init tcm_qla2xxx_init(void) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index cd611e740de7..5d75bb418696 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -33,7 +33,6 @@ #include #include "iscsi_target_parameters.h" #include "iscsi_target_seq_pdu_list.h" -#include "iscsi_target_configfs.h" #include "iscsi_target_datain_values.h" #include "iscsi_target_erl0.h" #include "iscsi_target_erl1.h" @@ -551,8 +550,8 @@ static int __init iscsi_target_init_module(void) idr_init(&tiqn_idr); idr_init(&sess_idr); - ret = iscsi_target_register_configfs(); - if (ret < 0) + ret = target_register_template(&iscsi_ops); + if (ret) goto out; size = BITS_TO_LONGS(ISCSIT_BITMAP_BITS) * sizeof(long); @@ -616,7 +615,10 @@ qr_out: bitmap_out: vfree(iscsit_global->ts_bitmap); configfs_out: - iscsi_target_deregister_configfs(); + /* XXX: this probably wants it to be it's own unwind step.. */ + if (iscsit_global->discovery_tpg) + iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1); + target_unregister_template(&iscsi_ops); out: kfree(iscsit_global); return -ENOMEM; @@ -631,7 +633,13 @@ static void __exit iscsi_target_cleanup_module(void) kmem_cache_destroy(lio_ooo_cache); kmem_cache_destroy(lio_r2t_cache); - iscsi_target_deregister_configfs(); + /* + * Shutdown discovery sessions and disable discovery TPG + */ + if (iscsit_global->discovery_tpg) + iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1); + + target_unregister_template(&iscsi_ops); vfree(iscsit_global->ts_bitmap); kfree(iscsit_global); @@ -983,7 +991,7 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, /* * Initialize struct se_cmd descriptor from target_core_mod infrastructure */ - transport_init_se_cmd(&cmd->se_cmd, &lio_target_fabric_configfs->tf_ops, + transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops, conn->sess->se_sess, be32_to_cpu(hdr->data_length), cmd->data_direction, sam_task_attr, cmd->sense_buffer + 2); @@ -1798,8 +1806,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, u8 tcm_function; int ret; - transport_init_se_cmd(&cmd->se_cmd, - &lio_target_fabric_configfs->tf_ops, + transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops, conn->sess->se_sess, 0, DMA_NONE, TCM_SIMPLE_TAG, cmd->sense_buffer + 2); diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h index e936d56fb523..7d0f9c00d9c2 100644 --- a/drivers/target/iscsi/iscsi_target.h +++ b/drivers/target/iscsi/iscsi_target.h @@ -35,7 +35,7 @@ extern void iscsit_stop_session(struct iscsi_session *, int, int); extern int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *, int); extern struct iscsit_global *iscsit_global; -extern struct target_fabric_configfs *lio_target_fabric_configfs; +extern const struct target_core_fabric_ops iscsi_ops; extern struct kmem_cache *lio_dr_cache; extern struct kmem_cache *lio_ooo_cache; diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 9cb5ab472a52..469fce44ebad 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -37,9 +37,6 @@ #include "iscsi_target_util.h" #include "iscsi_target.h" #include -#include "iscsi_target_configfs.h" - -struct target_fabric_configfs *lio_target_fabric_configfs; struct lio_target_configfs_attribute { struct configfs_attribute attr; @@ -1466,10 +1463,8 @@ static struct se_portal_group *lio_target_tiqn_addtpg( if (!tpg) return NULL; - ret = core_tpg_register( - &lio_target_fabric_configfs->tf_ops, - wwn, &tpg->tpg_se_tpg, tpg, - TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&iscsi_ops, wwn, &tpg->tpg_se_tpg, + tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) return NULL; @@ -1983,117 +1978,60 @@ static void lio_release_cmd(struct se_cmd *se_cmd) iscsit_release_cmd(cmd); } -/* End functions for target_core_fabric_ops */ - -int iscsi_target_register_configfs(void) -{ - struct target_fabric_configfs *fabric; - int ret; - - lio_target_fabric_configfs = NULL; - fabric = target_fabric_configfs_init(THIS_MODULE, "iscsi"); - if (IS_ERR(fabric)) { - pr_err("target_fabric_configfs_init() for" - " LIO-Target failed!\n"); - return PTR_ERR(fabric); - } - /* - * Setup the fabric API of function pointers used by target_core_mod.. - */ - fabric->tf_ops.get_fabric_name = &iscsi_get_fabric_name; - fabric->tf_ops.get_fabric_proto_ident = &iscsi_get_fabric_proto_ident; - fabric->tf_ops.tpg_get_wwn = &lio_tpg_get_endpoint_wwn; - fabric->tf_ops.tpg_get_tag = &lio_tpg_get_tag; - fabric->tf_ops.tpg_get_default_depth = &lio_tpg_get_default_depth; - fabric->tf_ops.tpg_get_pr_transport_id = &iscsi_get_pr_transport_id; - fabric->tf_ops.tpg_get_pr_transport_id_len = - &iscsi_get_pr_transport_id_len; - fabric->tf_ops.tpg_parse_pr_out_transport_id = - &iscsi_parse_pr_out_transport_id; - fabric->tf_ops.tpg_check_demo_mode = &lio_tpg_check_demo_mode; - fabric->tf_ops.tpg_check_demo_mode_cache = - &lio_tpg_check_demo_mode_cache; - fabric->tf_ops.tpg_check_demo_mode_write_protect = - &lio_tpg_check_demo_mode_write_protect; - fabric->tf_ops.tpg_check_prod_mode_write_protect = - &lio_tpg_check_prod_mode_write_protect; - fabric->tf_ops.tpg_check_prot_fabric_only = - &lio_tpg_check_prot_fabric_only; - fabric->tf_ops.tpg_alloc_fabric_acl = &lio_tpg_alloc_fabric_acl; - fabric->tf_ops.tpg_release_fabric_acl = &lio_tpg_release_fabric_acl; - fabric->tf_ops.tpg_get_inst_index = &lio_tpg_get_inst_index; - fabric->tf_ops.check_stop_free = &lio_check_stop_free, - fabric->tf_ops.release_cmd = &lio_release_cmd; - fabric->tf_ops.shutdown_session = &lio_tpg_shutdown_session; - fabric->tf_ops.close_session = &lio_tpg_close_session; - fabric->tf_ops.sess_get_index = &lio_sess_get_index; - fabric->tf_ops.sess_get_initiator_sid = &lio_sess_get_initiator_sid; - fabric->tf_ops.write_pending = &lio_write_pending; - fabric->tf_ops.write_pending_status = &lio_write_pending_status; - fabric->tf_ops.set_default_node_attributes = - &lio_set_default_node_attributes; - fabric->tf_ops.get_task_tag = &iscsi_get_task_tag; - fabric->tf_ops.get_cmd_state = &iscsi_get_cmd_state; - fabric->tf_ops.queue_data_in = &lio_queue_data_in; - fabric->tf_ops.queue_status = &lio_queue_status; - fabric->tf_ops.queue_tm_rsp = &lio_queue_tm_rsp; - fabric->tf_ops.aborted_task = &lio_aborted_task; - /* - * Setup function pointers for generic logic in target_core_fabric_configfs.c - */ - fabric->tf_ops.fabric_make_wwn = &lio_target_call_coreaddtiqn; - fabric->tf_ops.fabric_drop_wwn = &lio_target_call_coredeltiqn; - fabric->tf_ops.fabric_make_tpg = &lio_target_tiqn_addtpg; - fabric->tf_ops.fabric_drop_tpg = &lio_target_tiqn_deltpg; - fabric->tf_ops.fabric_post_link = NULL; - fabric->tf_ops.fabric_pre_unlink = NULL; - fabric->tf_ops.fabric_make_np = &lio_target_call_addnptotpg; - fabric->tf_ops.fabric_drop_np = &lio_target_call_delnpfromtpg; - fabric->tf_ops.fabric_make_nodeacl = &lio_target_make_nodeacl; - fabric->tf_ops.fabric_drop_nodeacl = &lio_target_drop_nodeacl; - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - * sturct config_item_type's - */ - fabric->tf_cit_tmpl.tfc_discovery_cit.ct_attrs = lio_target_discovery_auth_attrs; - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = lio_target_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = lio_target_tpg_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = lio_target_tpg_attrib_attrs; - fabric->tf_cit_tmpl.tfc_tpg_auth_cit.ct_attrs = lio_target_tpg_auth_attrs; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = lio_target_tpg_param_attrs; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = lio_target_portal_attrs; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = lio_target_initiator_attrs; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = lio_target_nacl_attrib_attrs; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = lio_target_nacl_auth_attrs; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = lio_target_nacl_param_attrs; - - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() for" - " LIO-Target failed!\n"); - target_fabric_configfs_free(fabric); - return ret; - } - - lio_target_fabric_configfs = fabric; - pr_debug("LIO_TARGET[0] - Set fabric ->" - " lio_target_fabric_configfs\n"); - return 0; -} - - -void iscsi_target_deregister_configfs(void) -{ - if (!lio_target_fabric_configfs) - return; - /* - * Shutdown discovery sessions and disable discovery TPG - */ - if (iscsit_global->discovery_tpg) - iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1); - - target_fabric_configfs_deregister(lio_target_fabric_configfs); - lio_target_fabric_configfs = NULL; - pr_debug("LIO_TARGET[0] - Cleared" - " lio_target_fabric_configfs\n"); -} +const struct target_core_fabric_ops iscsi_ops = { + .module = THIS_MODULE, + .name = "iscsi", + .get_fabric_name = iscsi_get_fabric_name, + .get_fabric_proto_ident = iscsi_get_fabric_proto_ident, + .tpg_get_wwn = lio_tpg_get_endpoint_wwn, + .tpg_get_tag = lio_tpg_get_tag, + .tpg_get_default_depth = lio_tpg_get_default_depth, + .tpg_get_pr_transport_id = iscsi_get_pr_transport_id, + .tpg_get_pr_transport_id_len = iscsi_get_pr_transport_id_len, + .tpg_parse_pr_out_transport_id = iscsi_parse_pr_out_transport_id, + .tpg_check_demo_mode = lio_tpg_check_demo_mode, + .tpg_check_demo_mode_cache = lio_tpg_check_demo_mode_cache, + .tpg_check_demo_mode_write_protect = + lio_tpg_check_demo_mode_write_protect, + .tpg_check_prod_mode_write_protect = + lio_tpg_check_prod_mode_write_protect, + .tpg_check_prot_fabric_only = &lio_tpg_check_prot_fabric_only, + .tpg_alloc_fabric_acl = lio_tpg_alloc_fabric_acl, + .tpg_release_fabric_acl = lio_tpg_release_fabric_acl, + .tpg_get_inst_index = lio_tpg_get_inst_index, + .check_stop_free = lio_check_stop_free, + .release_cmd = lio_release_cmd, + .shutdown_session = lio_tpg_shutdown_session, + .close_session = lio_tpg_close_session, + .sess_get_index = lio_sess_get_index, + .sess_get_initiator_sid = lio_sess_get_initiator_sid, + .write_pending = lio_write_pending, + .write_pending_status = lio_write_pending_status, + .set_default_node_attributes = lio_set_default_node_attributes, + .get_task_tag = iscsi_get_task_tag, + .get_cmd_state = iscsi_get_cmd_state, + .queue_data_in = lio_queue_data_in, + .queue_status = lio_queue_status, + .queue_tm_rsp = lio_queue_tm_rsp, + .aborted_task = lio_aborted_task, + .fabric_make_wwn = lio_target_call_coreaddtiqn, + .fabric_drop_wwn = lio_target_call_coredeltiqn, + .fabric_make_tpg = lio_target_tiqn_addtpg, + .fabric_drop_tpg = lio_target_tiqn_deltpg, + .fabric_make_np = lio_target_call_addnptotpg, + .fabric_drop_np = lio_target_call_delnpfromtpg, + .fabric_make_nodeacl = lio_target_make_nodeacl, + .fabric_drop_nodeacl = lio_target_drop_nodeacl, + + .tfc_discovery_attrs = lio_target_discovery_auth_attrs, + .tfc_wwn_attrs = lio_target_wwn_attrs, + .tfc_tpg_base_attrs = lio_target_tpg_attrs, + .tfc_tpg_attrib_attrs = lio_target_tpg_attrib_attrs, + .tfc_tpg_auth_attrs = lio_target_tpg_auth_attrs, + .tfc_tpg_param_attrs = lio_target_tpg_param_attrs, + .tfc_tpg_np_base_attrs = lio_target_portal_attrs, + .tfc_tpg_nacl_base_attrs = lio_target_initiator_attrs, + .tfc_tpg_nacl_attrib_attrs = lio_target_nacl_attrib_attrs, + .tfc_tpg_nacl_auth_attrs = lio_target_nacl_auth_attrs, + .tfc_tpg_nacl_param_attrs = lio_target_nacl_param_attrs, +}; diff --git a/drivers/target/iscsi/iscsi_target_configfs.h b/drivers/target/iscsi/iscsi_target_configfs.h deleted file mode 100644 index 8cd5a63c4edc..000000000000 --- a/drivers/target/iscsi/iscsi_target_configfs.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef ISCSI_TARGET_CONFIGFS_H -#define ISCSI_TARGET_CONFIGFS_H - -extern int iscsi_target_register_configfs(void); -extern void iscsi_target_deregister_configfs(void); - -#endif /* ISCSI_TARGET_CONFIGFS_H */ diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 3076e6f3a831..e8a240818353 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -68,10 +68,8 @@ int iscsit_load_discovery_tpg(void) return -1; } - ret = core_tpg_register( - &lio_target_fabric_configfs->tf_ops, - NULL, &tpg->tpg_se_tpg, tpg, - TRANSPORT_TPG_TYPE_DISCOVERY); + ret = core_tpg_register(&iscsi_ops, NULL, &tpg->tpg_se_tpg, + tpg, TRANSPORT_TPG_TYPE_DISCOVERY); if (ret < 0) { kfree(tpg); return -1; diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 2114c1d2c9de..5b143d2c08f7 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -41,8 +41,7 @@ #define to_tcm_loop_hba(hba) container_of(hba, struct tcm_loop_hba, dev) -/* Local pointer to allocated TCM configfs fabric module */ -static struct target_fabric_configfs *tcm_loop_fabric_configfs; +static const struct target_core_fabric_ops loop_ops; static struct workqueue_struct *tcm_loop_workqueue; static struct kmem_cache *tcm_loop_cmd_cache; @@ -1238,8 +1237,7 @@ static struct se_portal_group *tcm_loop_make_naa_tpg( /* * Register the tl_tpg as a emulated SAS TCM Target Endpoint */ - ret = core_tpg_register(&tcm_loop_fabric_configfs->tf_ops, - wwn, &tl_tpg->tl_se_tpg, tl_tpg, + ret = core_tpg_register(&loop_ops, wwn, &tl_tpg->tl_se_tpg, tl_tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) return ERR_PTR(-ENOMEM); @@ -1387,129 +1385,51 @@ static struct configfs_attribute *tcm_loop_wwn_attrs[] = { /* End items for tcm_loop_cit */ -static int tcm_loop_register_configfs(void) -{ - struct target_fabric_configfs *fabric; - int ret; - /* - * Set the TCM Loop HBA counter to zero - */ - tcm_loop_hba_no_cnt = 0; - /* - * Register the top level struct config_item_type with TCM core - */ - fabric = target_fabric_configfs_init(THIS_MODULE, "loopback"); - if (IS_ERR(fabric)) { - pr_err("tcm_loop_register_configfs() failed!\n"); - return PTR_ERR(fabric); - } - /* - * Setup the fabric API of function pointers used by target_core_mod - */ - fabric->tf_ops.get_fabric_name = &tcm_loop_get_fabric_name; - fabric->tf_ops.get_fabric_proto_ident = &tcm_loop_get_fabric_proto_ident; - fabric->tf_ops.tpg_get_wwn = &tcm_loop_get_endpoint_wwn; - fabric->tf_ops.tpg_get_tag = &tcm_loop_get_tag; - fabric->tf_ops.tpg_get_default_depth = &tcm_loop_get_default_depth; - fabric->tf_ops.tpg_get_pr_transport_id = &tcm_loop_get_pr_transport_id; - fabric->tf_ops.tpg_get_pr_transport_id_len = - &tcm_loop_get_pr_transport_id_len; - fabric->tf_ops.tpg_parse_pr_out_transport_id = - &tcm_loop_parse_pr_out_transport_id; - fabric->tf_ops.tpg_check_demo_mode = &tcm_loop_check_demo_mode; - fabric->tf_ops.tpg_check_demo_mode_cache = - &tcm_loop_check_demo_mode_cache; - fabric->tf_ops.tpg_check_demo_mode_write_protect = - &tcm_loop_check_demo_mode_write_protect; - fabric->tf_ops.tpg_check_prod_mode_write_protect = - &tcm_loop_check_prod_mode_write_protect; - fabric->tf_ops.tpg_check_prot_fabric_only = - &tcm_loop_check_prot_fabric_only; - /* - * The TCM loopback fabric module runs in demo-mode to a local - * virtual SCSI device, so fabric dependent initator ACLs are - * not required. - */ - fabric->tf_ops.tpg_alloc_fabric_acl = &tcm_loop_tpg_alloc_fabric_acl; - fabric->tf_ops.tpg_release_fabric_acl = - &tcm_loop_tpg_release_fabric_acl; - fabric->tf_ops.tpg_get_inst_index = &tcm_loop_get_inst_index; - /* - * Used for setting up remaining TCM resources in process context - */ - fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free; - fabric->tf_ops.release_cmd = &tcm_loop_release_cmd; - fabric->tf_ops.shutdown_session = &tcm_loop_shutdown_session; - fabric->tf_ops.close_session = &tcm_loop_close_session; - fabric->tf_ops.sess_get_index = &tcm_loop_sess_get_index; - fabric->tf_ops.sess_get_initiator_sid = NULL; - fabric->tf_ops.write_pending = &tcm_loop_write_pending; - fabric->tf_ops.write_pending_status = &tcm_loop_write_pending_status; - /* - * Not used for TCM loopback - */ - fabric->tf_ops.set_default_node_attributes = - &tcm_loop_set_default_node_attributes; - fabric->tf_ops.get_task_tag = &tcm_loop_get_task_tag; - fabric->tf_ops.get_cmd_state = &tcm_loop_get_cmd_state; - fabric->tf_ops.queue_data_in = &tcm_loop_queue_data_in; - fabric->tf_ops.queue_status = &tcm_loop_queue_status; - fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp; - fabric->tf_ops.aborted_task = &tcm_loop_aborted_task; - - /* - * Setup function pointers for generic logic in target_core_fabric_configfs.c - */ - fabric->tf_ops.fabric_make_wwn = &tcm_loop_make_scsi_hba; - fabric->tf_ops.fabric_drop_wwn = &tcm_loop_drop_scsi_hba; - fabric->tf_ops.fabric_make_tpg = &tcm_loop_make_naa_tpg; - fabric->tf_ops.fabric_drop_tpg = &tcm_loop_drop_naa_tpg; - /* - * fabric_post_link() and fabric_pre_unlink() are used for - * registration and release of TCM Loop Virtual SCSI LUNs. - */ - fabric->tf_ops.fabric_post_link = &tcm_loop_port_link; - fabric->tf_ops.fabric_pre_unlink = &tcm_loop_port_unlink; - fabric->tf_ops.fabric_make_np = NULL; - fabric->tf_ops.fabric_drop_np = NULL; - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - */ - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_loop_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = tcm_loop_tpg_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = tcm_loop_tpg_attrib_attrs; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - /* - * Once fabric->tf_ops has been setup, now register the fabric for - * use within TCM - */ - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() for" - " TCM_Loop failed!\n"); - target_fabric_configfs_free(fabric); - return -1; - } - /* - * Setup our local pointer to *fabric. - */ - tcm_loop_fabric_configfs = fabric; - pr_debug("TCM_LOOP[0] - Set fabric ->" - " tcm_loop_fabric_configfs\n"); - return 0; -} - -static void tcm_loop_deregister_configfs(void) -{ - if (!tcm_loop_fabric_configfs) - return; - - target_fabric_configfs_deregister(tcm_loop_fabric_configfs); - tcm_loop_fabric_configfs = NULL; - pr_debug("TCM_LOOP[0] - Cleared" - " tcm_loop_fabric_configfs\n"); -} +static const struct target_core_fabric_ops loop_ops = { + .module = THIS_MODULE, + .name = "loopback", + .get_fabric_name = tcm_loop_get_fabric_name, + .get_fabric_proto_ident = tcm_loop_get_fabric_proto_ident, + .tpg_get_wwn = tcm_loop_get_endpoint_wwn, + .tpg_get_tag = tcm_loop_get_tag, + .tpg_get_default_depth = tcm_loop_get_default_depth, + .tpg_get_pr_transport_id = tcm_loop_get_pr_transport_id, + .tpg_get_pr_transport_id_len = tcm_loop_get_pr_transport_id_len, + .tpg_parse_pr_out_transport_id = tcm_loop_parse_pr_out_transport_id, + .tpg_check_demo_mode = tcm_loop_check_demo_mode, + .tpg_check_demo_mode_cache = tcm_loop_check_demo_mode_cache, + .tpg_check_demo_mode_write_protect = + tcm_loop_check_demo_mode_write_protect, + .tpg_check_prod_mode_write_protect = + tcm_loop_check_prod_mode_write_protect, + .tpg_check_prot_fabric_only = tcm_loop_check_prot_fabric_only, + .tpg_alloc_fabric_acl = tcm_loop_tpg_alloc_fabric_acl, + .tpg_release_fabric_acl = tcm_loop_tpg_release_fabric_acl, + .tpg_get_inst_index = tcm_loop_get_inst_index, + .check_stop_free = tcm_loop_check_stop_free, + .release_cmd = tcm_loop_release_cmd, + .shutdown_session = tcm_loop_shutdown_session, + .close_session = tcm_loop_close_session, + .sess_get_index = tcm_loop_sess_get_index, + .write_pending = tcm_loop_write_pending, + .write_pending_status = tcm_loop_write_pending_status, + .set_default_node_attributes = tcm_loop_set_default_node_attributes, + .get_task_tag = tcm_loop_get_task_tag, + .get_cmd_state = tcm_loop_get_cmd_state, + .queue_data_in = tcm_loop_queue_data_in, + .queue_status = tcm_loop_queue_status, + .queue_tm_rsp = tcm_loop_queue_tm_rsp, + .aborted_task = tcm_loop_aborted_task, + .fabric_make_wwn = tcm_loop_make_scsi_hba, + .fabric_drop_wwn = tcm_loop_drop_scsi_hba, + .fabric_make_tpg = tcm_loop_make_naa_tpg, + .fabric_drop_tpg = tcm_loop_drop_naa_tpg, + .fabric_post_link = tcm_loop_port_link, + .fabric_pre_unlink = tcm_loop_port_unlink, + .tfc_wwn_attrs = tcm_loop_wwn_attrs, + .tfc_tpg_base_attrs = tcm_loop_tpg_attrs, + .tfc_tpg_attrib_attrs = tcm_loop_tpg_attrib_attrs, +}; static int __init tcm_loop_fabric_init(void) { @@ -1533,7 +1453,7 @@ static int __init tcm_loop_fabric_init(void) if (ret) goto out_destroy_cache; - ret = tcm_loop_register_configfs(); + ret = target_register_template(&loop_ops); if (ret) goto out_release_core_bus; @@ -1551,7 +1471,7 @@ out: static void __exit tcm_loop_fabric_exit(void) { - tcm_loop_deregister_configfs(); + target_unregister_template(&loop_ops); tcm_loop_release_core_bus(); kmem_cache_destroy(tcm_loop_cmd_cache); destroy_workqueue(tcm_loop_workqueue); diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 9512af6a8114..18b0f9703ff2 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -42,8 +42,7 @@ #include "sbp_target.h" -/* Local pointer to allocated TCM configfs fabric module */ -static struct target_fabric_configfs *sbp_fabric_configfs; +static const struct target_core_fabric_ops sbp_ops; /* FireWire address region for management and command block address handlers */ static const struct fw_address_region sbp_register_region = { @@ -2215,8 +2214,7 @@ static struct se_portal_group *sbp_make_tpg( goto out_free_tpg; } - ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn, - &tpg->se_tpg, (void *)tpg, + ret = core_tpg_register(&sbp_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) goto out_unreg_mgt_agt; @@ -2503,7 +2501,9 @@ static struct configfs_attribute *sbp_tpg_attrib_attrs[] = { NULL, }; -static struct target_core_fabric_ops sbp_ops = { +static const struct target_core_fabric_ops sbp_ops = { + .module = THIS_MODULE, + .name = "sbp", .get_fabric_name = sbp_get_fabric_name, .get_fabric_proto_ident = sbp_get_fabric_proto_ident, .tpg_get_wwn = sbp_get_fabric_wwn, @@ -2544,68 +2544,20 @@ static struct target_core_fabric_ops sbp_ops = { .fabric_drop_np = NULL, .fabric_make_nodeacl = sbp_make_nodeacl, .fabric_drop_nodeacl = sbp_drop_nodeacl, -}; - -static int sbp_register_configfs(void) -{ - struct target_fabric_configfs *fabric; - int ret; - - fabric = target_fabric_configfs_init(THIS_MODULE, "sbp"); - if (IS_ERR(fabric)) { - pr_err("target_fabric_configfs_init() failed\n"); - return PTR_ERR(fabric); - } - - fabric->tf_ops = sbp_ops; - - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - */ - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = sbp_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = sbp_tpg_base_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = sbp_tpg_attrib_attrs; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() failed for SBP\n"); - return ret; - } - sbp_fabric_configfs = fabric; - - return 0; -}; - -static void sbp_deregister_configfs(void) -{ - if (!sbp_fabric_configfs) - return; - - target_fabric_configfs_deregister(sbp_fabric_configfs); - sbp_fabric_configfs = NULL; + .tfc_wwn_attrs = sbp_wwn_attrs, + .tfc_tpg_base_attrs = sbp_tpg_base_attrs, + .tfc_tpg_attrib_attrs = sbp_tpg_attrib_attrs, }; static int __init sbp_init(void) { - int ret; - - ret = sbp_register_configfs(); - if (ret < 0) - return ret; - - return 0; + return target_register_template(&sbp_ops); }; static void __exit sbp_exit(void) { - sbp_deregister_configfs(); + target_unregister_template(&sbp_ops); }; MODULE_DESCRIPTION("FireWire SBP fabric driver"); diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 69baf1c53d99..ddaf76a4ac2a 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -300,81 +300,17 @@ struct configfs_subsystem *target_core_subsystem[] = { // Start functions called by external Target Fabrics Modules //############################################################################*/ -/* - * First function called by fabric modules to: - * - * 1) Allocate a struct target_fabric_configfs and save the *fabric_cit pointer. - * 2) Add struct target_fabric_configfs to g_tf_list - * 3) Return struct target_fabric_configfs to fabric module to be passed - * into target_fabric_configfs_register(). - */ -struct target_fabric_configfs *target_fabric_configfs_init( - struct module *fabric_mod, - const char *name) +static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) { - struct target_fabric_configfs *tf; - - if (!(name)) { - pr_err("Unable to locate passed fabric name\n"); - return ERR_PTR(-EINVAL); + if (!tfo->name) { + pr_err("Missing tfo->name\n"); + return -EINVAL; } - if (strlen(name) >= TARGET_FABRIC_NAME_SIZE) { + if (strlen(tfo->name) >= TARGET_FABRIC_NAME_SIZE) { pr_err("Passed name: %s exceeds TARGET_FABRIC" - "_NAME_SIZE\n", name); - return ERR_PTR(-EINVAL); + "_NAME_SIZE\n", tfo->name); + return -EINVAL; } - - tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL); - if (!tf) - return ERR_PTR(-ENOMEM); - - INIT_LIST_HEAD(&tf->tf_list); - atomic_set(&tf->tf_access_cnt, 0); - /* - * Setup the default generic struct config_item_type's (cits) in - * struct target_fabric_configfs->tf_cit_tmpl - */ - tf->tf_module = fabric_mod; - target_fabric_setup_cits(tf); - - tf->tf_subsys = target_core_subsystem[0]; - snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", name); - - mutex_lock(&g_tf_lock); - list_add_tail(&tf->tf_list, &g_tf_list); - mutex_unlock(&g_tf_lock); - - pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>" - ">>>>>>>>>>>>>>\n"); - pr_debug("Initialized struct target_fabric_configfs: %p for" - " %s\n", tf, tf->tf_name); - return tf; -} -EXPORT_SYMBOL(target_fabric_configfs_init); - -/* - * Called by fabric plugins after FAILED target_fabric_configfs_register() call. - */ -void target_fabric_configfs_free( - struct target_fabric_configfs *tf) -{ - mutex_lock(&g_tf_lock); - list_del(&tf->tf_list); - mutex_unlock(&g_tf_lock); - - kfree(tf); -} -EXPORT_SYMBOL(target_fabric_configfs_free); - -/* - * Perform a sanity check of the passed tf->tf_ops before completing - * TCM fabric module registration. - */ -static int target_fabric_tf_ops_check( - struct target_fabric_configfs *tf) -{ - struct target_core_fabric_ops *tfo = &tf->tf_ops; - if (!tfo->get_fabric_name) { pr_err("Missing tfo->get_fabric_name()\n"); return -EINVAL; @@ -508,77 +444,59 @@ static int target_fabric_tf_ops_check( return 0; } -/* - * Called 2nd from fabric module with returned parameter of - * struct target_fabric_configfs * from target_fabric_configfs_init(). - * - * Upon a successful registration, the new fabric's struct config_item is - * return. Also, a pointer to this struct is set in the passed - * struct target_fabric_configfs. - */ -int target_fabric_configfs_register( - struct target_fabric_configfs *tf) +int target_register_template(const struct target_core_fabric_ops *fo) { + struct target_fabric_configfs *tf; int ret; + ret = target_fabric_tf_ops_check(fo); + if (ret) + return ret; + + tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL); if (!tf) { - pr_err("Unable to locate target_fabric_configfs" - " pointer\n"); - return -EINVAL; - } - if (!tf->tf_subsys) { - pr_err("Unable to target struct config_subsystem" - " pointer\n"); - return -EINVAL; + pr_err("%s: could not allocate memory!\n", __func__); + return -ENOMEM; } - ret = target_fabric_tf_ops_check(tf); - if (ret < 0) - return ret; - pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>" - ">>>>>>>>>>\n"); + INIT_LIST_HEAD(&tf->tf_list); + atomic_set(&tf->tf_access_cnt, 0); + + /* + * Setup the default generic struct config_item_type's (cits) in + * struct target_fabric_configfs->tf_cit_tmpl + */ + tf->tf_module = fo->module; + tf->tf_subsys = target_core_subsystem[0]; + snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", fo->name); + + tf->tf_ops = *fo; + target_fabric_setup_cits(tf); + + mutex_lock(&g_tf_lock); + list_add_tail(&tf->tf_list, &g_tf_list); + mutex_unlock(&g_tf_lock); + return 0; } -EXPORT_SYMBOL(target_fabric_configfs_register); +EXPORT_SYMBOL(target_register_template); -void target_fabric_configfs_deregister( - struct target_fabric_configfs *tf) +void target_unregister_template(const struct target_core_fabric_ops *fo) { - struct configfs_subsystem *su; + struct target_fabric_configfs *t; - if (!tf) { - pr_err("Unable to locate passed target_fabric_" - "configfs\n"); - return; - } - su = tf->tf_subsys; - if (!su) { - pr_err("Unable to locate passed tf->tf_subsys" - " pointer\n"); - return; - } - pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>>>" - ">>>>>>>>>>>>\n"); mutex_lock(&g_tf_lock); - if (atomic_read(&tf->tf_access_cnt)) { - mutex_unlock(&g_tf_lock); - pr_err("Non zero tf->tf_access_cnt for fabric %s\n", - tf->tf_name); - BUG(); + list_for_each_entry(t, &g_tf_list, tf_list) { + if (!strcmp(t->tf_name, fo->name)) { + BUG_ON(atomic_read(&t->tf_access_cnt)); + list_del(&t->tf_list); + kfree(t); + break; + } } - list_del(&tf->tf_list); mutex_unlock(&g_tf_lock); - - pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing tf:" - " %s\n", tf->tf_name); - tf->tf_module = NULL; - tf->tf_subsys = NULL; - kfree(tf); - - pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>>>>>>" - ">>>>>\n"); } -EXPORT_SYMBOL(target_fabric_configfs_deregister); +EXPORT_SYMBOL(target_unregister_template); /*############################################################################## // Stop functions called by external Target Fabrics Modules @@ -945,7 +863,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( struct se_lun *lun; struct se_portal_group *se_tpg; struct t10_pr_registration *pr_reg; - struct target_core_fabric_ops *tfo; + const struct target_core_fabric_ops *tfo; ssize_t len = 0; spin_lock(&dev->dev_reservation_lock); @@ -979,7 +897,7 @@ SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port); static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts( struct se_device *dev, char *page) { - struct target_core_fabric_ops *tfo; + const struct target_core_fabric_ops *tfo; struct t10_pr_registration *pr_reg; unsigned char buf[384]; char i_buf[PR_REG_ISID_ID_LEN]; diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 0c3f90130b7d..1f7886bb16bf 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -56,6 +56,20 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) pr_debug("Setup generic %s\n", __stringify(_name)); \ } +#define TF_CIT_SETUP_DRV(_name, _item_ops, _group_ops) \ +static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ +{ \ + struct target_fabric_configfs_template *tfc = &tf->tf_cit_tmpl; \ + struct config_item_type *cit = &tfc->tfc_##_name##_cit; \ + struct configfs_attribute **attrs = tf->tf_ops.tfc_##_name##_attrs; \ + \ + cit->ct_item_ops = _item_ops; \ + cit->ct_group_ops = _group_ops; \ + cit->ct_attrs = attrs; \ + cit->ct_owner = tf->tf_module; \ + pr_debug("Setup generic %s\n", __stringify(_name)); \ +} + /* Start of tfc_tpg_mappedlun_cit */ static int target_fabric_mappedlun_link( @@ -278,7 +292,7 @@ static struct configfs_item_operations target_fabric_nacl_attrib_item_ops = { .store_attribute = target_fabric_nacl_attrib_attr_store, }; -TF_CIT_SETUP(tpg_nacl_attrib, &target_fabric_nacl_attrib_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_nacl_attrib, &target_fabric_nacl_attrib_item_ops, NULL); /* End of tfc_tpg_nacl_attrib_cit */ @@ -291,7 +305,7 @@ static struct configfs_item_operations target_fabric_nacl_auth_item_ops = { .store_attribute = target_fabric_nacl_auth_attr_store, }; -TF_CIT_SETUP(tpg_nacl_auth, &target_fabric_nacl_auth_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_nacl_auth, &target_fabric_nacl_auth_item_ops, NULL); /* End of tfc_tpg_nacl_auth_cit */ @@ -304,7 +318,7 @@ static struct configfs_item_operations target_fabric_nacl_param_item_ops = { .store_attribute = target_fabric_nacl_param_attr_store, }; -TF_CIT_SETUP(tpg_nacl_param, &target_fabric_nacl_param_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_nacl_param, &target_fabric_nacl_param_item_ops, NULL); /* End of tfc_tpg_nacl_param_cit */ @@ -461,8 +475,8 @@ static struct configfs_group_operations target_fabric_nacl_base_group_ops = { .drop_item = target_fabric_drop_mappedlun, }; -TF_CIT_SETUP(tpg_nacl_base, &target_fabric_nacl_base_item_ops, - &target_fabric_nacl_base_group_ops, NULL); +TF_CIT_SETUP_DRV(tpg_nacl_base, &target_fabric_nacl_base_item_ops, + &target_fabric_nacl_base_group_ops); /* End of tfc_tpg_nacl_base_cit */ @@ -570,7 +584,7 @@ static struct configfs_item_operations target_fabric_np_base_item_ops = { .store_attribute = target_fabric_np_base_attr_store, }; -TF_CIT_SETUP(tpg_np_base, &target_fabric_np_base_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_np_base, &target_fabric_np_base_item_ops, NULL); /* End of tfc_tpg_np_base_cit */ @@ -966,7 +980,7 @@ static struct configfs_item_operations target_fabric_tpg_attrib_item_ops = { .store_attribute = target_fabric_tpg_attrib_attr_store, }; -TF_CIT_SETUP(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL); /* End of tfc_tpg_attrib_cit */ @@ -979,7 +993,7 @@ static struct configfs_item_operations target_fabric_tpg_auth_item_ops = { .store_attribute = target_fabric_tpg_auth_attr_store, }; -TF_CIT_SETUP(tpg_auth, &target_fabric_tpg_auth_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_auth, &target_fabric_tpg_auth_item_ops, NULL); /* End of tfc_tpg_attrib_cit */ @@ -992,7 +1006,7 @@ static struct configfs_item_operations target_fabric_tpg_param_item_ops = { .store_attribute = target_fabric_tpg_param_attr_store, }; -TF_CIT_SETUP(tpg_param, &target_fabric_tpg_param_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_param, &target_fabric_tpg_param_item_ops, NULL); /* End of tfc_tpg_param_cit */ @@ -1018,7 +1032,7 @@ static struct configfs_item_operations target_fabric_tpg_base_item_ops = { .store_attribute = target_fabric_tpg_attr_store, }; -TF_CIT_SETUP(tpg_base, &target_fabric_tpg_base_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_base, &target_fabric_tpg_base_item_ops, NULL); /* End of tfc_tpg_base_cit */ @@ -1192,7 +1206,7 @@ static struct configfs_item_operations target_fabric_wwn_item_ops = { .store_attribute = target_fabric_wwn_attr_store, }; -TF_CIT_SETUP(wwn, &target_fabric_wwn_item_ops, &target_fabric_wwn_group_ops, NULL); +TF_CIT_SETUP_DRV(wwn, &target_fabric_wwn_item_ops, &target_fabric_wwn_group_ops); /* End of tfc_wwn_cit */ @@ -1206,7 +1220,7 @@ static struct configfs_item_operations target_fabric_discovery_item_ops = { .store_attribute = target_fabric_discovery_attr_store, }; -TF_CIT_SETUP(discovery, &target_fabric_discovery_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(discovery, &target_fabric_discovery_item_ops, NULL); /* End of tfc_discovery_cit */ diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 7436fdaaad12..963a67729b65 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -680,7 +680,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( struct se_dev_entry *deve_tmp; struct se_node_acl *nacl_tmp; struct se_port *port, *port_tmp; - struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; + const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe; int ret; /* @@ -979,7 +979,7 @@ int core_scsi3_check_aptpl_registration( } static void __core_scsi3_dump_registration( - struct target_core_fabric_ops *tfo, + const struct target_core_fabric_ops *tfo, struct se_device *dev, struct se_node_acl *nacl, struct t10_pr_registration *pr_reg, @@ -1020,7 +1020,7 @@ static void __core_scsi3_add_registration( enum register_type register_type, int register_move) { - struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; + const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; struct t10_reservation *pr_tmpl = &dev->t10_pr; @@ -1237,7 +1237,7 @@ static void __core_scsi3_free_registration( struct list_head *preempt_and_abort_list, int dec_holders) { - struct target_core_fabric_ops *tfo = + const struct target_core_fabric_ops *tfo = pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; struct t10_reservation *pr_tmpl = &dev->t10_pr; char i_buf[PR_REG_ISID_ID_LEN]; @@ -1461,7 +1461,7 @@ core_scsi3_decode_spec_i_port( struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; LIST_HEAD(tid_dest_list); struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp; - struct target_core_fabric_ops *tmp_tf_ops; + const struct target_core_fabric_ops *tmp_tf_ops; unsigned char *buf; unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident; char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; @@ -2422,7 +2422,7 @@ static void __core_scsi3_complete_pro_release( int explicit, int unreg) { - struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo; + const struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo; char i_buf[PR_REG_ISID_ID_LEN]; int pr_res_type = 0, pr_res_scope = 0; @@ -2734,7 +2734,7 @@ static void __core_scsi3_complete_pro_preempt( enum preempt_type preempt_type) { struct se_node_acl *nacl = pr_reg->pr_reg_nacl; - struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; + const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; char i_buf[PR_REG_ISID_ID_LEN]; memset(i_buf, 0, PR_REG_ISID_ID_LEN); @@ -3119,7 +3119,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, struct se_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL; struct se_port *se_port; struct se_portal_group *se_tpg, *dest_se_tpg = NULL; - struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops; + const struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops; struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg; struct t10_reservation *pr_tmpl = &dev->t10_pr; unsigned char *buf; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 0696de9553d3..47f064415bf6 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -672,7 +672,7 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) } int core_tpg_register( - struct target_core_fabric_ops *tfo, + const struct target_core_fabric_ops *tfo, struct se_wwn *se_wwn, struct se_portal_group *se_tpg, void *tpg_fabric_ptr, diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index b671ebbe1df6..f884198a8511 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -322,7 +322,7 @@ void __transport_register_session( struct se_session *se_sess, void *fabric_sess_ptr) { - struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo; + const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo; unsigned char buf[PR_REG_ISID_LEN]; se_sess->se_tpg = se_tpg; @@ -494,7 +494,7 @@ EXPORT_SYMBOL(transport_free_session); void transport_deregister_session(struct se_session *se_sess) { struct se_portal_group *se_tpg = se_sess->se_tpg; - struct target_core_fabric_ops *se_tfo; + const struct target_core_fabric_ops *se_tfo; struct se_node_acl *se_nacl; unsigned long flags; bool comp_nacl = true; @@ -1150,7 +1150,7 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size) */ void transport_init_se_cmd( struct se_cmd *cmd, - struct target_core_fabric_ops *tfo, + const struct target_core_fabric_ops *tfo, struct se_session *se_sess, u32 data_length, int data_direction, diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 8585acba6fc9..a600ff15dcfd 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -425,7 +425,7 @@ static int xcopy_pt_queue_status(struct se_cmd *se_cmd) return 0; } -static struct target_core_fabric_ops xcopy_pt_tfo = { +static const struct target_core_fabric_ops xcopy_pt_tfo = { .get_fabric_name = xcopy_pt_get_fabric_name, .get_task_tag = xcopy_pt_get_tag, .get_cmd_state = xcopy_pt_get_cmd_state, diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index a0bcfd3e7e7d..881deb3d499a 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -129,7 +129,6 @@ struct ft_cmd { extern struct mutex ft_lport_lock; extern struct fc4_prov ft_prov; -extern struct target_fabric_configfs *ft_configfs; extern unsigned int ft_debug_logging; /* diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index efdcb9663a1a..65dce1345966 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -48,7 +48,7 @@ #include "tcm_fc.h" -struct target_fabric_configfs *ft_configfs; +static const struct target_core_fabric_ops ft_fabric_ops; static LIST_HEAD(ft_wwn_list); DEFINE_MUTEX(ft_lport_lock); @@ -337,7 +337,7 @@ static struct se_portal_group *ft_add_tpg( return NULL; } - ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, + ret = core_tpg_register(&ft_fabric_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) { destroy_workqueue(wq); @@ -507,7 +507,9 @@ static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg) return tpg->index; } -static struct target_core_fabric_ops ft_fabric_ops = { +static const struct target_core_fabric_ops ft_fabric_ops = { + .module = THIS_MODULE, + .name = "fc", .get_fabric_name = ft_get_fabric_name, .get_fabric_proto_ident = fc_get_fabric_proto_ident, .tpg_get_wwn = ft_get_fabric_wwn, @@ -552,62 +554,10 @@ static struct target_core_fabric_ops ft_fabric_ops = { .fabric_drop_np = NULL, .fabric_make_nodeacl = &ft_add_acl, .fabric_drop_nodeacl = &ft_del_acl, -}; - -static int ft_register_configfs(void) -{ - struct target_fabric_configfs *fabric; - int ret; - - /* - * Register the top level struct config_item_type with TCM core - */ - fabric = target_fabric_configfs_init(THIS_MODULE, "fc"); - if (IS_ERR(fabric)) { - pr_err("%s: target_fabric_configfs_init() failed!\n", - __func__); - return PTR_ERR(fabric); - } - fabric->tf_ops = ft_fabric_ops; - - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - */ - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = ft_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = - ft_nacl_base_attrs; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - /* - * register the fabric for use within TCM - */ - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_debug("target_fabric_configfs_register() for" - " FC Target failed!\n"); - target_fabric_configfs_free(fabric); - return -1; - } - - /* - * Setup our local pointer to *fabric. - */ - ft_configfs = fabric; - return 0; -} -static void ft_deregister_configfs(void) -{ - if (!ft_configfs) - return; - target_fabric_configfs_deregister(ft_configfs); - ft_configfs = NULL; -} + .tfc_wwn_attrs = ft_wwn_attrs, + .tfc_tpg_nacl_base_attrs = ft_nacl_base_attrs, +}; static struct notifier_block ft_notifier = { .notifier_call = ft_lport_notify @@ -615,15 +565,24 @@ static struct notifier_block ft_notifier = { static int __init ft_init(void) { - if (ft_register_configfs()) - return -1; - if (fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov)) { - ft_deregister_configfs(); - return -1; - } + int ret; + + ret = target_register_template(&ft_fabric_ops); + if (ret) + goto out; + + ret = fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov); + if (ret) + goto out_unregister_template; + blocking_notifier_chain_register(&fc_lport_notifier_head, &ft_notifier); fc_lport_iterate(ft_lport_add, NULL); return 0; + +out_unregister_template: + target_unregister_template(&ft_fabric_ops); +out: + return ret; } static void __exit ft_exit(void) @@ -632,7 +591,7 @@ static void __exit ft_exit(void) &ft_notifier); fc_fc4_deregister_provider(FC_TYPE_FCP, &ft_prov); fc_lport_iterate(ft_lport_del, NULL); - ft_deregister_configfs(); + target_unregister_template(&ft_fabric_ops); synchronize_rcu(); } diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 3a494168661e..7ea2a44cb228 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -29,7 +29,7 @@ USB_GADGET_COMPOSITE_OPTIONS(); -static struct target_fabric_configfs *usbg_fabric_configfs; +static const struct target_core_fabric_ops usbg_ops; static inline struct f_uas *to_f_uas(struct usb_function *f) { @@ -1572,8 +1572,7 @@ static struct se_portal_group *usbg_make_tpg( tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn, - &tpg->se_tpg, tpg, + ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) { destroy_workqueue(tpg->workqueue); @@ -1865,7 +1864,9 @@ static int usbg_check_stop_free(struct se_cmd *se_cmd) return 1; } -static struct target_core_fabric_ops usbg_ops = { +static const struct target_core_fabric_ops usbg_ops = { + .module = THIS_MODULE, + .name = "usb_gadget", .get_fabric_name = usbg_get_fabric_name, .get_fabric_proto_ident = usbg_get_fabric_proto_ident, .tpg_get_wwn = usbg_get_fabric_wwn, @@ -1907,46 +1908,9 @@ static struct target_core_fabric_ops usbg_ops = { .fabric_drop_np = NULL, .fabric_make_nodeacl = usbg_make_nodeacl, .fabric_drop_nodeacl = usbg_drop_nodeacl, -}; - -static int usbg_register_configfs(void) -{ - struct target_fabric_configfs *fabric; - int ret; - - fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget"); - if (IS_ERR(fabric)) { - printk(KERN_ERR "target_fabric_configfs_init() failed\n"); - return PTR_ERR(fabric); - } - - fabric->tf_ops = usbg_ops; - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = usbg_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = usbg_base_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - printk(KERN_ERR "target_fabric_configfs_register() failed" - " for usb-gadget\n"); - return ret; - } - usbg_fabric_configfs = fabric; - return 0; -}; -static void usbg_deregister_configfs(void) -{ - if (!(usbg_fabric_configfs)) - return; - - target_fabric_configfs_deregister(usbg_fabric_configfs); - usbg_fabric_configfs = NULL; + .tfc_wwn_attrs = usbg_wwn_attrs, + .tfc_tpg_base_attrs = usbg_base_attrs, }; /* Start gadget.c code */ @@ -2455,16 +2419,13 @@ static void usbg_detach(struct usbg_tpg *tpg) static int __init usb_target_gadget_init(void) { - int ret; - - ret = usbg_register_configfs(); - return ret; + return target_register_template(&usbg_ops); } module_init(usb_target_gadget_init); static void __exit usb_target_gadget_exit(void) { - usbg_deregister_configfs(); + target_unregister_template(&usbg_ops); } module_exit(usb_target_gadget_exit); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 27ed9642cc21..e8c88b453f79 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -216,9 +216,7 @@ struct vhost_scsi { int vs_events_nr; /* num of pending events, protected by vq->mutex */ }; -/* Local pointer to allocated TCM configfs fabric module */ -static struct target_fabric_configfs *vhost_scsi_fabric_configfs; - +static struct target_core_fabric_ops vhost_scsi_ops; static struct workqueue_struct *vhost_scsi_workqueue; /* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */ @@ -2205,7 +2203,7 @@ vhost_scsi_make_tpg(struct se_wwn *wwn, tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&vhost_scsi_fabric_configfs->tf_ops, wwn, + ret = core_tpg_register(&vhost_scsi_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) { kfree(tpg); @@ -2327,6 +2325,8 @@ static struct configfs_attribute *vhost_scsi_wwn_attrs[] = { }; static struct target_core_fabric_ops vhost_scsi_ops = { + .module = THIS_MODULE, + .name = "vhost", .get_fabric_name = vhost_scsi_get_fabric_name, .get_fabric_proto_ident = vhost_scsi_get_fabric_proto_ident, .tpg_get_wwn = vhost_scsi_get_fabric_wwn, @@ -2371,70 +2371,20 @@ static struct target_core_fabric_ops vhost_scsi_ops = { .fabric_drop_np = NULL, .fabric_make_nodeacl = vhost_scsi_make_nodeacl, .fabric_drop_nodeacl = vhost_scsi_drop_nodeacl, + + .tfc_wwn_attrs = vhost_scsi_wwn_attrs, + .tfc_tpg_base_attrs = vhost_scsi_tpg_attrs, + .tfc_tpg_attrib_attrs = vhost_scsi_tpg_attrib_attrs, }; -static int vhost_scsi_register_configfs(void) +static int __init vhost_scsi_init(void) { - struct target_fabric_configfs *fabric; - int ret; + int ret = -ENOMEM; - pr_debug("vhost-scsi fabric module %s on %s/%s" + pr_debug("TCM_VHOST fabric module %s on %s/%s" " on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname, utsname()->machine); - /* - * Register the top level struct config_item_type with TCM core - */ - fabric = target_fabric_configfs_init(THIS_MODULE, "vhost"); - if (IS_ERR(fabric)) { - pr_err("target_fabric_configfs_init() failed\n"); - return PTR_ERR(fabric); - } - /* - * Setup fabric->tf_ops from our local vhost_scsi_ops - */ - fabric->tf_ops = vhost_scsi_ops; - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - */ - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = vhost_scsi_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = vhost_scsi_tpg_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = vhost_scsi_tpg_attrib_attrs; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - /* - * Register the fabric for use within TCM - */ - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() failed" - " for TCM_VHOST\n"); - return ret; - } - /* - * Setup our local pointer to *fabric - */ - vhost_scsi_fabric_configfs = fabric; - pr_debug("TCM_VHOST[0] - Set fabric -> vhost_scsi_fabric_configfs\n"); - return 0; -}; - -static void vhost_scsi_deregister_configfs(void) -{ - if (!vhost_scsi_fabric_configfs) - return; - - target_fabric_configfs_deregister(vhost_scsi_fabric_configfs); - vhost_scsi_fabric_configfs = NULL; - pr_debug("TCM_VHOST[0] - Cleared vhost_scsi_fabric_configfs\n"); -}; -static int __init vhost_scsi_init(void) -{ - int ret = -ENOMEM; /* * Use our own dedicated workqueue for submitting I/O into * target core to avoid contention within system_wq. @@ -2447,7 +2397,7 @@ static int __init vhost_scsi_init(void) if (ret < 0) goto out_destroy_workqueue; - ret = vhost_scsi_register_configfs(); + ret = target_register_template(&vhost_scsi_ops); if (ret < 0) goto out_vhost_scsi_deregister; @@ -2463,7 +2413,7 @@ out: static void vhost_scsi_exit(void) { - vhost_scsi_deregister_configfs(); + target_unregister_template(&vhost_scsi_ops); vhost_scsi_deregister(); destroy_workqueue(vhost_scsi_workqueue); }; diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 61653a03a8f5..f8a1bd741b5d 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -205,8 +205,7 @@ static LIST_HEAD(scsiback_free_pages); static DEFINE_MUTEX(scsiback_mutex); static LIST_HEAD(scsiback_list); -/* Local pointer to allocated TCM configfs fabric module */ -static struct target_fabric_configfs *scsiback_fabric_configfs; +static const struct target_core_fabric_ops scsiback_ops; static void scsiback_get(struct vscsibk_info *info) { @@ -1901,7 +1900,7 @@ scsiback_make_tpg(struct se_wwn *wwn, tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&scsiback_fabric_configfs->tf_ops, wwn, + ret = core_tpg_register(&scsiback_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) { kfree(tpg); @@ -1943,7 +1942,9 @@ static int scsiback_check_false(struct se_portal_group *se_tpg) return 0; } -static struct target_core_fabric_ops scsiback_ops = { +static const struct target_core_fabric_ops scsiback_ops = { + .module = THIS_MODULE, + .name = "xen-pvscsi", .get_fabric_name = scsiback_get_fabric_name, .get_fabric_proto_ident = scsiback_get_fabric_proto_ident, .tpg_get_wwn = scsiback_get_fabric_wwn, @@ -1990,62 +1991,10 @@ static struct target_core_fabric_ops scsiback_ops = { .fabric_make_nodeacl = scsiback_make_nodeacl, .fabric_drop_nodeacl = scsiback_drop_nodeacl, #endif -}; - -static int scsiback_register_configfs(void) -{ - struct target_fabric_configfs *fabric; - int ret; - pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n", - VSCSI_VERSION, utsname()->sysname, utsname()->machine); - /* - * Register the top level struct config_item_type with TCM core - */ - fabric = target_fabric_configfs_init(THIS_MODULE, "xen-pvscsi"); - if (IS_ERR(fabric)) - return PTR_ERR(fabric); - - /* - * Setup fabric->tf_ops from our local scsiback_ops - */ - fabric->tf_ops = scsiback_ops; - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - */ - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = scsiback_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = scsiback_tpg_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = scsiback_param_attrs; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - /* - * Register the fabric for use within TCM - */ - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - target_fabric_configfs_free(fabric); - return ret; - } - /* - * Setup our local pointer to *fabric - */ - scsiback_fabric_configfs = fabric; - pr_debug("xen-pvscsi: Set fabric -> scsiback_fabric_configfs\n"); - return 0; -}; - -static void scsiback_deregister_configfs(void) -{ - if (!scsiback_fabric_configfs) - return; - - target_fabric_configfs_deregister(scsiback_fabric_configfs); - scsiback_fabric_configfs = NULL; - pr_debug("xen-pvscsi: Cleared scsiback_fabric_configfs\n"); + .tfc_wwn_attrs = scsiback_wwn_attrs, + .tfc_tpg_base_attrs = scsiback_tpg_attrs, + .tfc_tpg_param_attrs = scsiback_param_attrs, }; static const struct xenbus_device_id scsiback_ids[] = { @@ -2077,6 +2026,9 @@ static int __init scsiback_init(void) if (!xen_domain()) return -ENODEV; + pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n", + VSCSI_VERSION, utsname()->sysname, utsname()->machine); + scsiback_cachep = kmem_cache_create("vscsiif_cache", sizeof(struct vscsibk_pend), 0, 0, scsiback_init_pend); if (!scsiback_cachep) @@ -2086,7 +2038,7 @@ static int __init scsiback_init(void) if (ret) goto out_cache_destroy; - ret = scsiback_register_configfs(); + ret = target_register_template(&scsiback_ops); if (ret) goto out_unregister_xenbus; @@ -2109,7 +2061,7 @@ static void __exit scsiback_exit(void) BUG(); gnttab_free_pages(1, &page); } - scsiback_deregister_configfs(); + target_unregister_template(&scsiback_ops); xenbus_unregister_driver(&scsiback_driver); kmem_cache_destroy(scsiback_cachep); } diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 71699cf3cc71..383110d608a0 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -519,7 +519,7 @@ struct se_cmd { struct list_head se_cmd_list; struct completion cmd_wait_comp; struct kref cmd_kref; - struct target_core_fabric_ops *se_tfo; + const struct target_core_fabric_ops *se_tfo; sense_reason_t (*execute_cmd)(struct se_cmd *); sense_reason_t (*execute_rw)(struct se_cmd *, struct scatterlist *, u32, enum dma_data_direction); @@ -890,7 +890,7 @@ struct se_portal_group { /* List of TCM sessions associated wth this TPG */ struct list_head tpg_sess_list; /* Pointer to $FABRIC_MOD dependent code */ - struct target_core_fabric_ops *se_tpg_tfo; + const struct target_core_fabric_ops *se_tpg_tfo; struct se_wwn *se_tpg_wwn; struct config_group tpg_group; struct config_group *tpg_default_groups[7]; diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index e0801386e4dc..25bb04c4209e 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h @@ -5,12 +5,6 @@ #define TARGET_CORE_NAME_MAX_LEN 64 #define TARGET_FABRIC_NAME_SIZE 32 -extern struct target_fabric_configfs *target_fabric_configfs_init( - struct module *, const char *); -extern void target_fabric_configfs_free(struct target_fabric_configfs *); -extern int target_fabric_configfs_register(struct target_fabric_configfs *); -extern void target_fabric_configfs_deregister(struct target_fabric_configfs *); - struct target_fabric_configfs_template { struct config_item_type tfc_discovery_cit; struct config_item_type tfc_wwn_cit; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index c93cfdf0d8e5..17c7f5ac7ea0 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -2,6 +2,8 @@ #define TARGET_CORE_FABRIC_H struct target_core_fabric_ops { + struct module *module; + const char *name; struct configfs_subsystem *tf_subsys; char *(*get_fabric_name)(void); u8 (*get_fabric_proto_ident)(struct se_portal_group *); @@ -90,8 +92,23 @@ struct target_core_fabric_ops { struct se_node_acl *(*fabric_make_nodeacl)(struct se_portal_group *, struct config_group *, const char *); void (*fabric_drop_nodeacl)(struct se_node_acl *); + + struct configfs_attribute **tfc_discovery_attrs; + struct configfs_attribute **tfc_wwn_attrs; + struct configfs_attribute **tfc_tpg_base_attrs; + struct configfs_attribute **tfc_tpg_np_base_attrs; + struct configfs_attribute **tfc_tpg_attrib_attrs; + struct configfs_attribute **tfc_tpg_auth_attrs; + struct configfs_attribute **tfc_tpg_param_attrs; + struct configfs_attribute **tfc_tpg_nacl_base_attrs; + struct configfs_attribute **tfc_tpg_nacl_attrib_attrs; + struct configfs_attribute **tfc_tpg_nacl_auth_attrs; + struct configfs_attribute **tfc_tpg_nacl_param_attrs; }; +int target_register_template(const struct target_core_fabric_ops *fo); +void target_unregister_template(const struct target_core_fabric_ops *fo); + struct se_session *transport_init_session(enum target_prot_op); int transport_alloc_session_tags(struct se_session *, unsigned int, unsigned int); @@ -110,7 +127,8 @@ void transport_deregister_session_configfs(struct se_session *); void transport_deregister_session(struct se_session *); -void transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *, +void transport_init_se_cmd(struct se_cmd *, + const struct target_core_fabric_ops *, struct se_session *, u32, int, int, unsigned char *); sense_reason_t transport_lookup_cmd_lun(struct se_cmd *, u32); sense_reason_t target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *); @@ -162,8 +180,8 @@ int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, unsigned char *, u32, int); int core_tpg_set_initiator_node_tag(struct se_portal_group *, struct se_node_acl *, const char *); -int core_tpg_register(struct target_core_fabric_ops *, struct se_wwn *, - struct se_portal_group *, void *, int); +int core_tpg_register(const struct target_core_fabric_ops *, + struct se_wwn *, struct se_portal_group *, void *, int); int core_tpg_deregister(struct se_portal_group *); /* SAS helpers */ -- cgit v1.2.3 From c8e639852ad720499912acedfd6b072325fd2807 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 7 Apr 2015 21:53:27 +0000 Subject: target: Fix COMPARE_AND_WRITE with SG_TO_MEM_NOALLOC handling This patch fixes a bug for COMPARE_AND_WRITE handling with fabrics using SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC. It adds the missing allocation for cmd->t_bidi_data_sg within transport_generic_new_cmd() that is used by COMPARE_AND_WRITE for the initial READ payload, even if the fabric is already providing a pre-allocated buffer for cmd->t_data_sg. Also, fix zero-length COMPARE_AND_WRITE handling within the compare_and_write_callback() and target_complete_ok_work() to queue the response, skipping the initial READ. This fixes COMPARE_AND_WRITE emulation with loopback, vhost, and xen-backend fabric drivers using SG_TO_MEM_NOALLOC. Reported-by: Christoph Hellwig Cc: Christoph Hellwig Cc: # v3.12+ Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 15 +++++++++----- drivers/target/target_core_transport.c | 37 ++++++++++++++++++++++++++++++---- include/target/target_core_base.h | 2 +- 3 files changed, 44 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 315ff641408b..0064ffe9a219 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -321,7 +321,7 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o return 0; } -static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd) +static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success) { unsigned char *buf, *addr; struct scatterlist *sg; @@ -385,7 +385,7 @@ sbc_execute_rw(struct se_cmd *cmd) cmd->data_direction); } -static sense_reason_t compare_and_write_post(struct se_cmd *cmd) +static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success) { struct se_device *dev = cmd->se_dev; @@ -408,7 +408,7 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd) return TCM_NO_SENSE; } -static sense_reason_t compare_and_write_callback(struct se_cmd *cmd) +static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success) { struct se_device *dev = cmd->se_dev; struct scatterlist *write_sg = NULL, *sg; @@ -423,10 +423,15 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd) /* * Handle early failure in transport_generic_request_failure(), - * which will not have taken ->caw_mutex yet.. + * which will not have taken ->caw_sem yet.. */ - if (!cmd->t_data_sg || !cmd->t_bidi_data_sg) + if (!success && (!cmd->t_data_sg || !cmd->t_bidi_data_sg)) return TCM_NO_SENSE; + /* + * Handle special case for zero-length COMPARE_AND_WRITE + */ + if (!cmd->data_length) + goto out; /* * Immediately exit + release dev->caw_sem if command has already * been failed with a non-zero SCSI status. diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index f884198a8511..47334e5c47bf 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1647,11 +1647,11 @@ void transport_generic_request_failure(struct se_cmd *cmd, transport_complete_task_attr(cmd); /* * Handle special case for COMPARE_AND_WRITE failure, where the - * callback is expected to drop the per device ->caw_mutex. + * callback is expected to drop the per device ->caw_sem. */ if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && cmd->transport_complete_callback) - cmd->transport_complete_callback(cmd); + cmd->transport_complete_callback(cmd, false); switch (sense_reason) { case TCM_NON_EXISTENT_LUN: @@ -2048,8 +2048,12 @@ static void target_complete_ok_work(struct work_struct *work) if (cmd->transport_complete_callback) { sense_reason_t rc; - rc = cmd->transport_complete_callback(cmd); + rc = cmd->transport_complete_callback(cmd, true); if (!rc && !(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE_POST)) { + if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && + !cmd->data_length) + goto queue_rsp; + return; } else if (rc) { ret = transport_send_check_condition_and_sense(cmd, @@ -2063,6 +2067,7 @@ static void target_complete_ok_work(struct work_struct *work) } } +queue_rsp: switch (cmd->data_direction) { case DMA_FROM_DEVICE: spin_lock(&cmd->se_lun->lun_sep_lock); @@ -2166,6 +2171,16 @@ static inline void transport_reset_sgl_orig(struct se_cmd *cmd) static inline void transport_free_pages(struct se_cmd *cmd) { if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) { + /* + * Release special case READ buffer payload required for + * SG_TO_MEM_NOALLOC to function with COMPARE_AND_WRITE + */ + if (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) { + transport_free_sgl(cmd->t_bidi_data_sg, + cmd->t_bidi_data_nents); + cmd->t_bidi_data_sg = NULL; + cmd->t_bidi_data_nents = 0; + } transport_reset_sgl_orig(cmd); return; } @@ -2318,6 +2333,7 @@ sense_reason_t transport_generic_new_cmd(struct se_cmd *cmd) { int ret = 0; + bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB); /* * Determine is the TCM fabric module has already allocated physical @@ -2326,7 +2342,6 @@ transport_generic_new_cmd(struct se_cmd *cmd) */ if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) && cmd->data_length) { - bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB); if ((cmd->se_cmd_flags & SCF_BIDI) || (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE)) { @@ -2357,6 +2372,20 @@ transport_generic_new_cmd(struct se_cmd *cmd) cmd->data_length, zero_flag); if (ret < 0) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } else if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && + cmd->data_length) { + /* + * Special case for COMPARE_AND_WRITE with fabrics + * using SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC. + */ + u32 caw_length = cmd->t_task_nolb * + cmd->se_dev->dev_attrib.block_size; + + ret = target_alloc_sgl(&cmd->t_bidi_data_sg, + &cmd->t_bidi_data_nents, + caw_length, zero_flag); + if (ret < 0) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } /* * If this command is not a write we can execute it right here, diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 383110d608a0..dae468903d8b 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -523,7 +523,7 @@ struct se_cmd { sense_reason_t (*execute_cmd)(struct se_cmd *); sense_reason_t (*execute_rw)(struct se_cmd *, struct scatterlist *, u32, enum dma_data_direction); - sense_reason_t (*transport_complete_callback)(struct se_cmd *); + sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool); unsigned char *t_task_cdb; unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE]; -- cgit v1.2.3 From 054922bb3549abbea9ed2c1a78a1e331343cc05e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 10 Apr 2015 14:49:44 +0200 Subject: target: Remove the unused flag SCF_ACK_KREF The flag SCF_ACK_KREF is only set but never tested. Hence remove this flag. Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 4 +--- include/target/target_core_base.h | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 0b8411f8de85..4edb183cf8df 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2479,10 +2479,8 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, * fabric acknowledgement that requires two target_put_sess_cmd() * invocations before se_cmd descriptor release. */ - if (ack_kref) { + if (ack_kref) kref_get(&se_cmd->cmd_kref); - se_cmd->se_cmd_flags |= SCF_ACK_KREF; - } spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); if (se_sess->sess_tearing_down) { diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index dae468903d8b..e1de142b7b07 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -165,7 +165,6 @@ enum se_cmd_flags_table { SCF_SEND_DELAYED_TAS = 0x00004000, SCF_ALUA_NON_OPTIMIZED = 0x00008000, SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000, - SCF_ACK_KREF = 0x00040000, SCF_COMPARE_AND_WRITE = 0x00080000, SCF_COMPARE_AND_WRITE_POST = 0x00100000, }; -- cgit v1.2.3 From d616a703a52cf972425cddd43fc01cd4ef867faf Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 5 Apr 2015 16:59:25 +0200 Subject: of: Add dummy of_irq_to_resource_table() for IRQ_OF=n If CONFIG_IRQ_OF=n: drivers/built-in.o: In function `of_device_alloc': (.text+0x72bce): undefined reference to `of_irq_to_resource_table' make: *** [vmlinux] Error 1 of_device_alloc() calls of_irq_to_resource_table() with nr_irqs = 0 due to of_irq_count() already being a dummy, so just add a dummy for of_irq_to_resource_table(), too. Signed-off-by: Geert Uytterhoeven Signed-off-by: Rob Herring --- include/linux/of_irq.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index bfec136a6d1e..d884929a7747 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -37,8 +37,6 @@ extern int of_irq_parse_one(struct device_node *device, int index, extern unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data); extern int of_irq_to_resource(struct device_node *dev, int index, struct resource *r); -extern int of_irq_to_resource_table(struct device_node *dev, - struct resource *res, int nr_irqs); extern void of_irq_init(const struct of_device_id *matches); @@ -46,6 +44,8 @@ extern void of_irq_init(const struct of_device_id *matches); extern int of_irq_count(struct device_node *dev); extern int of_irq_get(struct device_node *dev, int index); extern int of_irq_get_byname(struct device_node *dev, const char *name); +extern int of_irq_to_resource_table(struct device_node *dev, + struct resource *res, int nr_irqs); #else static inline int of_irq_count(struct device_node *dev) { @@ -59,6 +59,11 @@ static inline int of_irq_get_byname(struct device_node *dev, const char *name) { return 0; } +static inline int of_irq_to_resource_table(struct device_node *dev, + struct resource *res, int nr_irqs) +{ + return 0; +} #endif #if defined(CONFIG_OF) -- cgit v1.2.3 From 37786c7fee40771d13901de129af7e084ed48b55 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Thu, 9 Apr 2015 13:05:14 -0700 Subject: of: Add helper function to check MMIO register endianness SoC peripherals can come in several different flavors: - little-endian: registers always need to be accessed in LE mode (so the kernel should perform a swap if the CPU is running BE) - big-endian: registers always need to be accessed in BE mode (so the kernel should perform a swap if the CPU is running LE) - native-endian: the bus will automatically swap accesses, so the kernel should never swap Introduce a function that checks an OF device node to see whether it contains a "big-endian" or "native-endian" property. For the former case, always return true. For the latter case, return true iff the kernel was built for BE (implying that the BE MMIO accessors do not perform a swap). Otherwise return false, assuming LE registers. LE registers are assumed by default because most existing drivers (libahci, serial8250, usb) always use readl/writel in the absence of instructions to the contrary, so that will be our fallback. Signed-off-by: Kevin Cernekee Reviewed-by: Peter Hurley Acked-by: Greg Kroah-Hartman Signed-off-by: Rob Herring --- drivers/of/base.c | 23 +++++++++++++++++++++++ include/linux/of.h | 6 ++++++ 2 files changed, 29 insertions(+) (limited to 'include') diff --git a/drivers/of/base.c b/drivers/of/base.c index 69566b6a876d..31ca3c8dae61 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -567,6 +567,29 @@ bool of_device_is_available(const struct device_node *device) } EXPORT_SYMBOL(of_device_is_available); +/** + * of_device_is_big_endian - check if a device has BE registers + * + * @device: Node to check for endianness + * + * Returns true if the device has a "big-endian" property, or if the kernel + * was compiled for BE *and* the device has a "native-endian" property. + * Returns false otherwise. + * + * Callers would nominally use ioread32be/iowrite32be if + * of_device_is_big_endian() == true, or readl/writel otherwise. + */ +bool of_device_is_big_endian(const struct device_node *device) +{ + if (of_property_read_bool(device, "big-endian")) + return true; + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && + of_property_read_bool(device, "native-endian")) + return true; + return false; +} +EXPORT_SYMBOL(of_device_is_big_endian); + /** * of_get_parent - Get a node's parent if any * @node: Node to get parent diff --git a/include/linux/of.h b/include/linux/of.h index dfde07e77a63..a0cd62ef22db 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -305,6 +305,7 @@ extern int of_property_read_string_helper(struct device_node *np, extern int of_device_is_compatible(const struct device_node *device, const char *); extern bool of_device_is_available(const struct device_node *device); +extern bool of_device_is_big_endian(const struct device_node *device); extern const void *of_get_property(const struct device_node *node, const char *name, int *lenp); @@ -466,6 +467,11 @@ static inline bool of_device_is_available(const struct device_node *device) return false; } +static inline bool of_device_is_big_endian(const struct device_node *device) +{ + return false; +} + static inline struct property *of_find_property(const struct device_node *np, const char *name, int *lenp) -- cgit v1.2.3 From cc7837867a559feba70fdf68eb53c24a84e3712f Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Thu, 9 Apr 2015 13:05:15 -0700 Subject: of/fdt: Add endianness helper function for early init code Provide a libfdt-based equivalent for of_device_is_big_endian(), suitable for use in the early_init_* functions. Signed-off-by: Kevin Cernekee Reviewed-by: Peter Hurley Acked-by: Greg Kroah-Hartman Signed-off-by: Rob Herring --- drivers/of/fdt.c | 19 +++++++++++++++++++ include/linux/of_fdt.h | 2 ++ 2 files changed, 21 insertions(+) (limited to 'include') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 34bdc4de83d0..4b15aa163b6e 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -108,6 +108,25 @@ int of_fdt_is_compatible(const void *blob, return 0; } +/** + * of_fdt_is_big_endian - Return true if given node needs BE MMIO accesses + * @blob: A device tree blob + * @node: node to test + * + * Returns true if the node has a "big-endian" property, or if the kernel + * was compiled for BE *and* the node has a "native-endian" property. + * Returns false otherwise. + */ +bool of_fdt_is_big_endian(const void *blob, unsigned long node) +{ + if (fdt_getprop(blob, node, "big-endian", NULL)) + return true; + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && + fdt_getprop(blob, node, "native-endian", NULL)) + return true; + return false; +} + /** * of_fdt_match - Return true if node matches a list of compatible values */ diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 0ff360d5b3b3..587ee507965d 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -33,6 +33,8 @@ extern void *of_fdt_get_property(const void *blob, extern int of_fdt_is_compatible(const void *blob, unsigned long node, const char *compat); +extern bool of_fdt_is_big_endian(const void *blob, + unsigned long node); extern int of_fdt_match(const void *blob, unsigned long node, const char *const *compat); extern void of_fdt_unflatten_tree(unsigned long *blob, -- cgit v1.2.3 From df81b29c7b81b9d70ee29b7a263dd5009daa0ce4 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 15 Apr 2015 10:17:43 +0930 Subject: virtio_balloon: transitional interface Virtio 1.0 doesn't include a modern balloon device. But it's not a big change to support a transitional balloon device: this has the advantage of supporting existing drivers, transparently. Signed-off-by: Michael S. Tsirkin Acked-by: Cornelia Huck Signed-off-by: Rusty Russell --- drivers/virtio/virtio_balloon.c | 21 +++++++++++++++------ include/uapi/linux/virtio_balloon.h | 32 ++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 6a356e344f82..82e80e034f25 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -214,8 +214,8 @@ static inline void update_stat(struct virtio_balloon *vb, int idx, u16 tag, u64 val) { BUG_ON(idx >= VIRTIO_BALLOON_S_NR); - vb->stats[idx].tag = tag; - vb->stats[idx].val = val; + vb->stats[idx].tag = cpu_to_virtio16(vb->vdev, tag); + vb->stats[idx].val = cpu_to_virtio64(vb->vdev, val); } #define pages_to_bytes(x) ((u64)(x) << PAGE_SHIFT) @@ -283,18 +283,27 @@ static void virtballoon_changed(struct virtio_device *vdev) static inline s64 towards_target(struct virtio_balloon *vb) { - __le32 v; s64 target; + u32 num_pages; - virtio_cread(vb->vdev, struct virtio_balloon_config, num_pages, &v); + virtio_cread(vb->vdev, struct virtio_balloon_config, num_pages, + &num_pages); - target = le32_to_cpu(v); + /* Legacy balloon config space is LE, unlike all other devices. */ + if (!virtio_has_feature(vb->vdev, VIRTIO_F_VERSION_1)) + num_pages = le32_to_cpu((__force __le32)num_pages); + + target = num_pages; return target - vb->num_pages; } static void update_balloon_size(struct virtio_balloon *vb) { - __le32 actual = cpu_to_le32(vb->num_pages); + u32 actual = vb->num_pages; + + /* Legacy balloon config space is LE, unlike all other devices. */ + if (!virtio_has_feature(vb->vdev, VIRTIO_F_VERSION_1)) + actual = (__force u32)cpu_to_le32(actual); virtio_cwrite(vb->vdev, struct virtio_balloon_config, actual, &actual); diff --git a/include/uapi/linux/virtio_balloon.h b/include/uapi/linux/virtio_balloon.h index 4b0488f20b2e..984169a819ee 100644 --- a/include/uapi/linux/virtio_balloon.h +++ b/include/uapi/linux/virtio_balloon.h @@ -25,6 +25,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ +#include #include #include @@ -38,9 +39,9 @@ struct virtio_balloon_config { /* Number of pages host wants Guest to give up. */ - __le32 num_pages; + __u32 num_pages; /* Number of pages we've actually got in balloon. */ - __le32 actual; + __u32 actual; }; #define VIRTIO_BALLOON_S_SWAP_IN 0 /* Amount of memory swapped in */ @@ -51,9 +52,32 @@ struct virtio_balloon_config { #define VIRTIO_BALLOON_S_MEMTOT 5 /* Total amount of memory */ #define VIRTIO_BALLOON_S_NR 6 +/* + * Memory statistics structure. + * Driver fills an array of these structures and passes to device. + * + * NOTE: fields are laid out in a way that would make compiler add padding + * between and after fields, so we have to use compiler-specific attributes to + * pack it, to disable this padding. This also often causes compiler to + * generate suboptimal code. + * + * We maintain this statistics structure format for backwards compatibility, + * but don't follow this example. + * + * If implementing a similar structure, do something like the below instead: + * struct virtio_balloon_stat { + * __virtio16 tag; + * __u8 reserved[6]; + * __virtio64 val; + * }; + * + * In other words, add explicit reserved fields to align field and + * structure boundaries at field size, avoiding compiler padding + * without the packed attribute. + */ struct virtio_balloon_stat { - __u16 tag; - __u64 val; + __virtio16 tag; + __virtio64 val; } __attribute__((packed)); #endif /* _LINUX_VIRTIO_BALLOON_H */ -- cgit v1.2.3 From 9abbfb486f5c254805bb6a3f263bc14d989eb90b Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 15 Apr 2015 10:17:45 +0930 Subject: virtio: drop virtio_device_is_legacy_only virtio_device_is_legacy_only is now unused, drop it from core. Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck Signed-off-by: Rusty Russell --- drivers/virtio/virtio.c | 6 ------ include/linux/virtio.h | 2 -- 2 files changed, 8 deletions(-) (limited to 'include') diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 5fa67b5282ad..b1877d73fa56 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -278,12 +278,6 @@ static struct bus_type virtio_bus = { .remove = virtio_dev_remove, }; -bool virtio_device_is_legacy_only(struct virtio_device_id id) -{ - return false; -} -EXPORT_SYMBOL_GPL(virtio_device_is_legacy_only); - int register_virtio_driver(struct virtio_driver *driver) { /* Catch this early. */ diff --git a/include/linux/virtio.h b/include/linux/virtio.h index 28f0e65b9a11..8f4d4bfa6d46 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -108,8 +108,6 @@ struct virtio_device { void *priv; }; -bool virtio_device_is_legacy_only(struct virtio_device_id id); - static inline struct virtio_device *dev_to_virtio(struct device *_dev) { return container_of(_dev, struct virtio_device, dev); -- cgit v1.2.3 From bfebd1cdb497a57757c83f5fbf1a29931591e2a4 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Sun, 8 Mar 2015 00:51:47 -0500 Subject: dm: add full blk-mq support to request-based DM Commit e5863d9ad ("dm: allocate requests in target when stacking on blk-mq devices") served as the first step toward fully utilizing blk-mq in request-based DM -- it enabled stacking an old-style (request_fn) request_queue ontop of the underlying blk-mq device(s). That first step didn't improve performance of DM multipath ontop of fast blk-mq devices (e.g. NVMe) because the top-level old-style request_queue was severely limited by the queue_lock. The second step offered here enables stacking a blk-mq request_queue ontop of the underlying blk-mq device(s). This unlocks significant performance gains on fast blk-mq devices, Keith Busch tested on his NVMe testbed and offered this really positive news: "Just providing a performance update. All my fio tests are getting roughly equal performance whether accessed through the raw block device or the multipath device mapper (~470k IOPS). I could only push ~20% of the raw iops through dm before this conversion, so this latest tree is looking really solid from a performance standpoint." Signed-off-by: Mike Snitzer Tested-by: Keith Busch --- drivers/md/dm-mpath.c | 2 +- drivers/md/dm-table.c | 11 +- drivers/md/dm.c | 317 +++++++++++++++++++++++++++++++++--------- include/uapi/linux/dm-ioctl.h | 4 +- 4 files changed, 261 insertions(+), 73 deletions(-) (limited to 'include') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index add6391f3f8e..c8f07e5a9a17 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1703,7 +1703,7 @@ out: *---------------------------------------------------------------*/ static struct target_type multipath_target = { .name = "multipath", - .version = {1, 8, 0}, + .version = {1, 9, 0}, .module = THIS_MODULE, .ctr = multipath_ctr, .dtr = multipath_dtr, diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 057312048b68..66600cab9fa5 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -18,6 +18,7 @@ #include #include #include +#include #define DM_MSG_PREFIX "table" @@ -1695,9 +1696,13 @@ void dm_table_run_md_queue_async(struct dm_table *t) md = dm_table_get_md(t); queue = dm_get_md_queue(md); if (queue) { - spin_lock_irqsave(queue->queue_lock, flags); - blk_run_queue_async(queue); - spin_unlock_irqrestore(queue->queue_lock, flags); + if (queue->mq_ops) + blk_mq_run_hw_queues(queue, true); + else { + spin_lock_irqsave(queue->queue_lock, flags); + blk_run_queue_async(queue); + spin_unlock_irqrestore(queue->queue_lock, flags); + } } } EXPORT_SYMBOL(dm_table_run_md_queue_async); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 5294e016e92b..3a66baac76ed 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -23,6 +23,7 @@ #include #include #include /* for rq_end_sector() */ +#include #include @@ -224,6 +225,9 @@ struct mapped_device { int last_rq_rw; sector_t last_rq_pos; ktime_t last_rq_start_time; + + /* for blk-mq request-based DM support */ + struct blk_mq_tag_set tag_set; }; /* @@ -1025,6 +1029,11 @@ static void end_clone_bio(struct bio *clone, int error) blk_update_request(tio->orig, 0, nr_bytes); } +static struct dm_rq_target_io *tio_from_request(struct request *rq) +{ + return (rq->q->mq_ops ? blk_mq_rq_to_pdu(rq) : rq->special); +} + /* * Don't touch any member of the md after calling this function because * the md may be freed in dm_put() at the end of this function. @@ -1048,8 +1057,10 @@ static void rq_completed(struct mapped_device *md, int rw, bool run_queue) * queue lock again. */ if (run_queue) { - if (!nr_requests_pending || - (nr_requests_pending >= md->queue->nr_congestion_on)) + if (md->queue->mq_ops) + blk_mq_run_hw_queues(md->queue, true); + else if (!nr_requests_pending || + (nr_requests_pending >= md->queue->nr_congestion_on)) blk_run_queue_async(md->queue); } @@ -1062,13 +1073,17 @@ static void rq_completed(struct mapped_device *md, int rw, bool run_queue) static void free_rq_clone(struct request *clone) { struct dm_rq_target_io *tio = clone->end_io_data; + struct mapped_device *md = tio->md; blk_rq_unprep_clone(clone); + if (clone->q && clone->q->mq_ops) tio->ti->type->release_clone_rq(clone); else - free_clone_request(tio->md, clone); - free_rq_tio(tio); + free_clone_request(md, clone); + + if (!md->queue->mq_ops) + free_rq_tio(tio); } /* @@ -1097,17 +1112,22 @@ static void dm_end_request(struct request *clone, int error) } free_rq_clone(clone); - blk_end_request_all(rq, error); + if (!rq->q->mq_ops) + blk_end_request_all(rq, error); + else + blk_mq_end_request(rq, error); rq_completed(md, rw, true); } static void dm_unprep_request(struct request *rq) { - struct dm_rq_target_io *tio = rq->special; + struct dm_rq_target_io *tio = tio_from_request(rq); struct request *clone = tio->clone; - rq->special = NULL; - rq->cmd_flags &= ~REQ_DONTPREP; + if (!rq->q->mq_ops) { + rq->special = NULL; + rq->cmd_flags &= ~REQ_DONTPREP; + } if (clone) free_rq_clone(clone); @@ -1116,18 +1136,29 @@ static void dm_unprep_request(struct request *rq) /* * Requeue the original request of a clone. */ -static void dm_requeue_unmapped_original_request(struct mapped_device *md, - struct request *rq) +static void old_requeue_request(struct request *rq) { - int rw = rq_data_dir(rq); struct request_queue *q = rq->q; unsigned long flags; - dm_unprep_request(rq); - spin_lock_irqsave(q->queue_lock, flags); blk_requeue_request(q, rq); spin_unlock_irqrestore(q->queue_lock, flags); +} + +static void dm_requeue_unmapped_original_request(struct mapped_device *md, + struct request *rq) +{ + int rw = rq_data_dir(rq); + + dm_unprep_request(rq); + + if (!rq->q->mq_ops) + old_requeue_request(rq); + else { + blk_mq_requeue_request(rq); + blk_mq_kick_requeue_list(rq->q); + } rq_completed(md, rw, false); } @@ -1139,35 +1170,44 @@ static void dm_requeue_unmapped_request(struct request *clone) dm_requeue_unmapped_original_request(tio->md, tio->orig); } -static void __stop_queue(struct request_queue *q) -{ - blk_stop_queue(q); -} - -static void stop_queue(struct request_queue *q) +static void old_stop_queue(struct request_queue *q) { unsigned long flags; + if (blk_queue_stopped(q)) + return; + spin_lock_irqsave(q->queue_lock, flags); - __stop_queue(q); + blk_stop_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); } -static void __start_queue(struct request_queue *q) +static void stop_queue(struct request_queue *q) { - if (blk_queue_stopped(q)) - blk_start_queue(q); + if (!q->mq_ops) + old_stop_queue(q); + else + blk_mq_stop_hw_queues(q); } -static void start_queue(struct request_queue *q) +static void old_start_queue(struct request_queue *q) { unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); - __start_queue(q); + if (blk_queue_stopped(q)) + blk_start_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); } +static void start_queue(struct request_queue *q) +{ + if (!q->mq_ops) + old_start_queue(q); + else + blk_mq_start_stopped_hw_queues(q, true); +} + static void dm_done(struct request *clone, int error, bool mapped) { int r = error; @@ -1206,13 +1246,20 @@ static void dm_done(struct request *clone, int error, bool mapped) static void dm_softirq_done(struct request *rq) { bool mapped = true; - struct dm_rq_target_io *tio = rq->special; + struct dm_rq_target_io *tio = tio_from_request(rq); struct request *clone = tio->clone; + int rw; if (!clone) { - blk_end_request_all(rq, tio->error); - rq_completed(tio->md, rq_data_dir(rq), false); - free_rq_tio(tio); + rw = rq_data_dir(rq); + if (!rq->q->mq_ops) { + blk_end_request_all(rq, tio->error); + rq_completed(tio->md, rw, false); + free_rq_tio(tio); + } else { + blk_mq_end_request(rq, tio->error); + rq_completed(tio->md, rw, false); + } return; } @@ -1228,7 +1275,7 @@ static void dm_softirq_done(struct request *rq) */ static void dm_complete_request(struct request *rq, int error) { - struct dm_rq_target_io *tio = rq->special; + struct dm_rq_target_io *tio = tio_from_request(rq); tio->error = error; blk_complete_request(rq); @@ -1247,7 +1294,7 @@ static void dm_kill_unmapped_request(struct request *rq, int error) } /* - * Called with the clone's queue lock held + * Called with the clone's queue lock held (for non-blk-mq) */ static void end_clone_request(struct request *clone, int error) { @@ -1808,6 +1855,18 @@ static struct request *clone_rq(struct request *rq, struct mapped_device *md, static void map_tio_request(struct kthread_work *work); +static void init_tio(struct dm_rq_target_io *tio, struct request *rq, + struct mapped_device *md) +{ + tio->md = md; + tio->ti = NULL; + tio->clone = NULL; + tio->orig = rq; + tio->error = 0; + memset(&tio->info, 0, sizeof(tio->info)); + init_kthread_work(&tio->work, map_tio_request); +} + static struct dm_rq_target_io *prep_tio(struct request *rq, struct mapped_device *md, gfp_t gfp_mask) { @@ -1819,13 +1878,7 @@ static struct dm_rq_target_io *prep_tio(struct request *rq, if (!tio) return NULL; - tio->md = md; - tio->ti = NULL; - tio->clone = NULL; - tio->orig = rq; - tio->error = 0; - memset(&tio->info, 0, sizeof(tio->info)); - init_kthread_work(&tio->work, map_tio_request); + init_tio(tio, rq, md); table = dm_get_live_table(md, &srcu_idx); if (!dm_table_mq_request_based(table)) { @@ -1869,11 +1922,11 @@ static int dm_prep_fn(struct request_queue *q, struct request *rq) * DM_MAPIO_REQUEUE : the original request needs to be requeued * < 0 : the request was completed due to failure */ -static int map_request(struct dm_target *ti, struct request *rq, +static int map_request(struct dm_rq_target_io *tio, struct request *rq, struct mapped_device *md) { int r; - struct dm_rq_target_io *tio = rq->special; + struct dm_target *ti = tio->ti; struct request *clone = NULL; if (tio->clone) { @@ -1888,7 +1941,7 @@ static int map_request(struct dm_target *ti, struct request *rq, } if (IS_ERR(clone)) return DM_MAPIO_REQUEUE; - if (setup_clone(clone, rq, tio, GFP_KERNEL)) { + if (setup_clone(clone, rq, tio, GFP_NOIO)) { /* -ENOMEM */ ti->type->release_clone_rq(clone); return DM_MAPIO_REQUEUE; @@ -1929,13 +1982,16 @@ static void map_tio_request(struct kthread_work *work) struct request *rq = tio->orig; struct mapped_device *md = tio->md; - if (map_request(tio->ti, rq, md) == DM_MAPIO_REQUEUE) + if (map_request(tio, rq, md) == DM_MAPIO_REQUEUE) dm_requeue_unmapped_original_request(md, rq); } static void dm_start_request(struct mapped_device *md, struct request *orig) { - blk_start_request(orig); + if (!orig->q->mq_ops) + blk_start_request(orig); + else + blk_mq_start_request(orig); atomic_inc(&md->pending[rq_data_dir(orig)]); if (md->seq_rq_merge_deadline_usecs) { @@ -2045,7 +2101,7 @@ static void dm_request_fn(struct request_queue *q) dm_start_request(md, rq); - tio = rq->special; + tio = tio_from_request(rq); /* Establish tio->ti before queuing work (map_tio_request) */ tio->ti = ti; queue_kthread_work(&md->kworker, &tio->work); @@ -2142,7 +2198,7 @@ static void dm_init_md_queue(struct mapped_device *md) { /* * Request-based dm devices cannot be stacked on top of bio-based dm - * devices. The type of this dm device has not been decided yet. + * devices. The type of this dm device may not have been decided yet. * The type is decided at the first table loading time. * To prevent problematic device stacking, clear the queue flag * for request stacking support until then. @@ -2150,7 +2206,15 @@ static void dm_init_md_queue(struct mapped_device *md) * This queue is new, so no concurrency on the queue_flags. */ queue_flag_clear_unlocked(QUEUE_FLAG_STACKABLE, md->queue); +} + +static void dm_init_old_md_queue(struct mapped_device *md) +{ + dm_init_md_queue(md); + /* + * Initialize aspects of queue that aren't relevant for blk-mq + */ md->queue->queuedata = md; md->queue->backing_dev_info.congested_fn = dm_any_congested; md->queue->backing_dev_info.congested_data = md; @@ -2273,6 +2337,7 @@ static void unlock_fs(struct mapped_device *md); static void free_dev(struct mapped_device *md) { int minor = MINOR(disk_devt(md->disk)); + bool using_blk_mq = !!md->queue->mq_ops; unlock_fs(md); destroy_workqueue(md->wq); @@ -2298,6 +2363,8 @@ static void free_dev(struct mapped_device *md) del_gendisk(md->disk); put_disk(md->disk); blk_cleanup_queue(md->queue); + if (using_blk_mq) + blk_mq_free_tag_set(&md->tag_set); bdput(md->bdev); free_minor(minor); @@ -2457,7 +2524,7 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t, * This must be done before setting the queue restrictions, * because request-based dm may be run just after the setting. */ - if (dm_table_request_based(t) && !blk_queue_stopped(q)) + if (dm_table_request_based(t)) stop_queue(q); __bind_mempools(md, t); @@ -2539,14 +2606,6 @@ unsigned dm_get_md_type(struct mapped_device *md) return md->type; } -static bool dm_md_type_request_based(struct mapped_device *md) -{ - unsigned table_type = dm_get_md_type(md); - - return (table_type == DM_TYPE_REQUEST_BASED || - table_type == DM_TYPE_MQ_REQUEST_BASED); -} - struct target_type *dm_get_immutable_target_type(struct mapped_device *md) { return md->immutable_target_type; @@ -2563,6 +2622,14 @@ struct queue_limits *dm_get_queue_limits(struct mapped_device *md) } EXPORT_SYMBOL_GPL(dm_get_queue_limits); +static void init_rq_based_worker_thread(struct mapped_device *md) +{ + /* Initialize the request-based DM worker thread */ + init_kthread_worker(&md->kworker); + md->kworker_task = kthread_run(kthread_worker_fn, &md->kworker, + "kdmwork-%s", dm_device_name(md)); +} + /* * Fully initialize a request-based queue (->elevator, ->request_fn, etc). */ @@ -2571,29 +2638,131 @@ static int dm_init_request_based_queue(struct mapped_device *md) struct request_queue *q = NULL; if (md->queue->elevator) - return 1; + return 0; /* Fully initialize the queue */ q = blk_init_allocated_queue(md->queue, dm_request_fn, NULL); if (!q) - return 0; + return -EINVAL; /* disable dm_request_fn's merge heuristic by default */ md->seq_rq_merge_deadline_usecs = 0; md->queue = q; - dm_init_md_queue(md); + dm_init_old_md_queue(md); blk_queue_softirq_done(md->queue, dm_softirq_done); blk_queue_prep_rq(md->queue, dm_prep_fn); - /* Also initialize the request-based DM worker thread */ - init_kthread_worker(&md->kworker); - md->kworker_task = kthread_run(kthread_worker_fn, &md->kworker, - "kdmwork-%s", dm_device_name(md)); + init_rq_based_worker_thread(md); elv_register_queue(md->queue); - return 1; + return 0; +} + +static int dm_mq_init_request(void *data, struct request *rq, + unsigned int hctx_idx, unsigned int request_idx, + unsigned int numa_node) +{ + struct mapped_device *md = data; + struct dm_rq_target_io *tio = blk_mq_rq_to_pdu(rq); + + /* + * Must initialize md member of tio, otherwise it won't + * be available in dm_mq_queue_rq. + */ + tio->md = md; + + return 0; +} + +static int dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx, + const struct blk_mq_queue_data *bd) +{ + struct request *rq = bd->rq; + struct dm_rq_target_io *tio = blk_mq_rq_to_pdu(rq); + struct mapped_device *md = tio->md; + int srcu_idx; + struct dm_table *map = dm_get_live_table(md, &srcu_idx); + struct dm_target *ti; + sector_t pos; + + /* always use block 0 to find the target for flushes for now */ + pos = 0; + if (!(rq->cmd_flags & REQ_FLUSH)) + pos = blk_rq_pos(rq); + + ti = dm_table_find_target(map, pos); + if (!dm_target_is_valid(ti)) { + dm_put_live_table(md, srcu_idx); + DMERR_LIMIT("request attempted access beyond the end of device"); + /* + * Must perform setup, that rq_completed() requires, + * before returning BLK_MQ_RQ_QUEUE_ERROR + */ + dm_start_request(md, rq); + return BLK_MQ_RQ_QUEUE_ERROR; + } + dm_put_live_table(md, srcu_idx); + + if (ti->type->busy && ti->type->busy(ti)) + return BLK_MQ_RQ_QUEUE_BUSY; + + dm_start_request(md, rq); + + /* Init tio using md established in .init_request */ + init_tio(tio, rq, md); + + /* Establish tio->ti before queuing work (map_tio_request) */ + tio->ti = ti; + queue_kthread_work(&md->kworker, &tio->work); + + return BLK_MQ_RQ_QUEUE_OK; +} + +static struct blk_mq_ops dm_mq_ops = { + .queue_rq = dm_mq_queue_rq, + .map_queue = blk_mq_map_queue, + .complete = dm_softirq_done, + .init_request = dm_mq_init_request, +}; + +static int dm_init_request_based_blk_mq_queue(struct mapped_device *md) +{ + struct request_queue *q; + int err; + + memset(&md->tag_set, 0, sizeof(md->tag_set)); + md->tag_set.ops = &dm_mq_ops; + md->tag_set.queue_depth = BLKDEV_MAX_RQ; + md->tag_set.numa_node = NUMA_NO_NODE; + md->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE; + md->tag_set.nr_hw_queues = 1; + md->tag_set.cmd_size = sizeof(struct dm_rq_target_io); + md->tag_set.driver_data = md; + + err = blk_mq_alloc_tag_set(&md->tag_set); + if (err) + return err; + + q = blk_mq_init_allocated_queue(&md->tag_set, md->queue); + if (IS_ERR(q)) { + err = PTR_ERR(q); + goto out_tag_set; + } + md->queue = q; + dm_init_md_queue(md); + + /* backfill 'mq' sysfs registration normally done in blk_register_queue */ + blk_mq_register_disk(md->disk); + + init_rq_based_worker_thread(md); + + return 0; + +out_tag_set: + blk_mq_free_tag_set(&md->tag_set); + return err; } /* @@ -2601,15 +2770,29 @@ static int dm_init_request_based_queue(struct mapped_device *md) */ int dm_setup_md_queue(struct mapped_device *md) { - if (dm_md_type_request_based(md)) { - if (!dm_init_request_based_queue(md)) { + int r; + unsigned md_type = dm_get_md_type(md); + + switch (md_type) { + case DM_TYPE_REQUEST_BASED: + r = dm_init_request_based_queue(md); + if (r) { DMWARN("Cannot initialize queue for request-based mapped device"); - return -EINVAL; + return r; } - } else { - /* bio-based specific initialization */ + break; + case DM_TYPE_MQ_REQUEST_BASED: + r = dm_init_request_based_blk_mq_queue(md); + if (r) { + DMWARN("Cannot initialize queue for request-based blk-mq mapped device"); + return r; + } + break; + case DM_TYPE_BIO_BASED: + dm_init_old_md_queue(md); blk_queue_make_request(md->queue, dm_make_request); blk_queue_merge_bvec(md->queue, dm_merge_bvec); + break; } return 0; diff --git a/include/uapi/linux/dm-ioctl.h b/include/uapi/linux/dm-ioctl.h index 889f3a5b7b18..eac8c3641f39 100644 --- a/include/uapi/linux/dm-ioctl.h +++ b/include/uapi/linux/dm-ioctl.h @@ -267,9 +267,9 @@ enum { #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) #define DM_VERSION_MAJOR 4 -#define DM_VERSION_MINOR 30 +#define DM_VERSION_MINOR 31 #define DM_VERSION_PATCHLEVEL 0 -#define DM_VERSION_EXTRA "-ioctl (2014-12-22)" +#define DM_VERSION_EXTRA "-ioctl (2015-3-12)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */ -- cgit v1.2.3 From e6e20a7a5f3f49bfee518d5c6849107398d83912 Mon Sep 17 00:00:00 2001 From: Dan Ehrenberg Date: Tue, 10 Feb 2015 15:20:49 -0800 Subject: init: export name_to_dev_t and mark name argument as const DM will switch its device lookup code to using name_to_dev_t() so it must be exported. Also, the @name argument should be marked const. Signed-off-by: Dan Ehrenberg Signed-off-by: Mike Snitzer --- include/linux/mount.h | 2 +- init/do_mounts.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/mount.h b/include/linux/mount.h index c2c561dc0114..bca086d62b1a 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -92,6 +92,6 @@ extern struct vfsmount *vfs_kern_mount(struct file_system_type *type, extern void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list); extern void mark_mounts_for_expiry(struct list_head *mounts); -extern dev_t name_to_dev_t(char *name); +extern dev_t name_to_dev_t(const char *name); #endif /* _LINUX_MOUNT_H */ diff --git a/init/do_mounts.c b/init/do_mounts.c index eb410083e8e0..c16adfbe4ad6 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -207,7 +207,7 @@ done: * bangs. */ -dev_t name_to_dev_t(char *name) +dev_t name_to_dev_t(const char *name) { char s[32]; char *p; @@ -286,6 +286,7 @@ fail: done: return res; } +EXPORT_SYMBOL_GPL(name_to_dev_t); static int __init root_dev_setup(char *line) { -- cgit v1.2.3 From 2b0143b5c986be1ce8408b3aadc4709e0a94429d Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 17 Mar 2015 22:25:59 +0000 Subject: VFS: normal filesystems (and lustre): d_inode() annotations that's the bulk of filesystem drivers dealing with inodes of their own Signed-off-by: David Howells Signed-off-by: Al Viro --- drivers/staging/lustre/lustre/llite/dcache.c | 14 +- drivers/staging/lustre/lustre/llite/file.c | 16 +- .../staging/lustre/lustre/llite/llite_internal.h | 2 +- drivers/staging/lustre/lustre/llite/llite_lib.c | 6 +- drivers/staging/lustre/lustre/llite/llite_nfs.c | 6 +- drivers/staging/lustre/lustre/llite/namei.c | 20 +-- drivers/staging/lustre/lustre/llite/statahead.c | 28 ++-- drivers/staging/lustre/lustre/llite/symlink.c | 2 +- drivers/staging/lustre/lustre/llite/xattr.c | 8 +- fs/9p/acl.c | 4 +- fs/9p/vfs_dentry.c | 4 +- fs/9p/vfs_inode.c | 34 ++--- fs/9p/vfs_inode_dotl.c | 16 +- fs/9p/vfs_super.c | 8 +- fs/adfs/inode.c | 2 +- fs/affs/amigaffs.c | 8 +- fs/affs/inode.c | 2 +- fs/affs/namei.c | 10 +- fs/afs/dir.c | 42 +++--- fs/afs/inode.c | 4 +- fs/afs/mntpt.c | 8 +- fs/afs/super.c | 2 +- fs/autofs4/autofs_i.h | 4 +- fs/autofs4/expire.c | 2 +- fs/autofs4/inode.c | 6 +- fs/autofs4/root.c | 18 +-- fs/autofs4/symlink.c | 2 +- fs/autofs4/waitq.c | 4 +- fs/befs/linuxvfs.c | 4 +- fs/bfs/dir.c | 8 +- fs/btrfs/export.c | 6 +- fs/btrfs/file.c | 2 +- fs/btrfs/inode.c | 30 ++-- fs/btrfs/ioctl.c | 22 +-- fs/btrfs/super.c | 8 +- fs/btrfs/tree-log.c | 14 +- fs/btrfs/xattr.c | 16 +- fs/ceph/caps.c | 2 +- fs/ceph/debugfs.c | 2 +- fs/ceph/dir.c | 60 ++++---- fs/ceph/export.c | 28 ++-- fs/ceph/file.c | 4 +- fs/ceph/inode.c | 52 +++---- fs/ceph/mds_client.c | 24 +-- fs/ceph/super.c | 4 +- fs/ceph/xattr.c | 16 +- fs/cifs/cifs_dfs_ref.c | 2 +- fs/cifs/cifsfs.c | 2 +- fs/cifs/cifssmb.c | 4 +- fs/cifs/dir.c | 8 +- fs/cifs/file.c | 48 +++--- fs/cifs/inode.c | 32 ++-- fs/cifs/link.c | 12 +- fs/cifs/misc.c | 2 +- fs/cifs/readdir.c | 4 +- fs/cifs/smb1ops.c | 2 +- fs/cifs/smb2file.c | 4 +- fs/cifs/smb2misc.c | 4 +- fs/cifs/smb2ops.c | 10 +- fs/cifs/xattr.c | 22 +-- fs/coda/cache.c | 4 +- fs/coda/dir.c | 22 +-- fs/coda/inode.c | 6 +- fs/coda/pioctl.c | 2 +- fs/coda/upcall.c | 4 +- fs/configfs/dir.c | 70 ++++----- fs/configfs/file.c | 4 +- fs/configfs/inode.c | 16 +- fs/debugfs/file.c | 2 +- fs/debugfs/inode.c | 56 +++---- fs/devpts/inode.c | 16 +- fs/ecryptfs/crypto.c | 4 +- fs/ecryptfs/dentry.c | 6 +- fs/ecryptfs/file.c | 2 +- fs/ecryptfs/inode.c | 164 ++++++++++----------- fs/ecryptfs/kthread.c | 2 +- fs/ecryptfs/main.c | 6 +- fs/ecryptfs/mmap.c | 2 +- fs/efivarfs/inode.c | 4 +- fs/efivarfs/super.c | 2 +- fs/efs/namei.c | 4 +- fs/exofs/dir.c | 4 +- fs/exofs/inode.c | 2 +- fs/exofs/namei.c | 10 +- fs/exofs/super.c | 2 +- fs/exofs/symlink.c | 2 +- fs/ext2/dir.c | 2 +- fs/ext2/ialloc.c | 2 +- fs/ext2/inode.c | 2 +- fs/ext2/namei.c | 14 +- fs/ext2/symlink.c | 2 +- fs/ext2/xattr.c | 4 +- fs/ext2/xattr_security.c | 4 +- fs/ext2/xattr_trusted.c | 4 +- fs/ext2/xattr_user.c | 4 +- fs/ext3/ialloc.c | 2 +- fs/ext3/inode.c | 2 +- fs/ext3/namei.c | 34 ++--- fs/ext3/super.c | 6 +- fs/ext3/symlink.c | 2 +- fs/ext3/xattr.c | 10 +- fs/ext3/xattr_security.c | 4 +- fs/ext3/xattr_trusted.c | 4 +- fs/ext3/xattr_user.c | 4 +- fs/ext4/fsync.c | 2 +- fs/ext4/ialloc.c | 2 +- fs/ext4/inline.c | 4 +- fs/ext4/inode.c | 4 +- fs/ext4/migrate.c | 2 +- fs/ext4/namei.c | 34 ++--- fs/ext4/super.c | 6 +- fs/ext4/symlink.c | 2 +- fs/ext4/xattr.c | 10 +- fs/ext4/xattr_security.c | 4 +- fs/ext4/xattr_trusted.c | 4 +- fs/ext4/xattr_user.c | 4 +- fs/f2fs/f2fs.h | 2 +- fs/f2fs/file.c | 4 +- fs/f2fs/namei.c | 18 +-- fs/f2fs/xattr.c | 10 +- fs/fat/file.c | 4 +- fs/fat/namei_msdos.c | 8 +- fs/fat/namei_vfat.c | 14 +- fs/fat/nfs.c | 4 +- fs/freevxfs/vxfs_immed.c | 2 +- fs/fuse/control.c | 6 +- fs/fuse/dir.c | 60 ++++---- fs/fuse/inode.c | 4 +- fs/gfs2/dentry.c | 12 +- fs/gfs2/export.c | 8 +- fs/gfs2/inode.c | 34 ++--- fs/gfs2/ops_fstype.c | 8 +- fs/gfs2/super.c | 2 +- fs/gfs2/xattr.c | 6 +- fs/hfs/attr.c | 6 +- fs/hfs/dir.c | 8 +- fs/hfs/inode.c | 2 +- fs/hfs/sysdep.c | 2 +- fs/hfsplus/dir.c | 12 +- fs/hfsplus/inode.c | 2 +- fs/hfsplus/ioctl.c | 2 +- fs/hfsplus/xattr.c | 4 +- fs/hfsplus/xattr.h | 4 +- fs/hostfs/hostfs_kern.c | 2 +- fs/hpfs/inode.c | 2 +- fs/hpfs/namei.c | 8 +- fs/hppfs/hppfs.c | 20 +-- fs/hugetlbfs/inode.c | 4 +- fs/isofs/export.c | 2 +- fs/jffs2/dir.c | 40 ++--- fs/jffs2/fs.c | 2 +- fs/jffs2/security.c | 4 +- fs/jffs2/super.c | 4 +- fs/jffs2/symlink.c | 2 +- fs/jffs2/xattr.c | 2 +- fs/jffs2/xattr_trusted.c | 4 +- fs/jffs2/xattr_user.c | 4 +- fs/jfs/file.c | 2 +- fs/jfs/namei.c | 18 +-- fs/jfs/symlink.c | 2 +- fs/jfs/xattr.c | 12 +- fs/kernfs/dir.c | 2 +- fs/kernfs/inode.c | 8 +- fs/logfs/dir.c | 14 +- fs/logfs/file.c | 2 +- fs/minix/dir.c | 4 +- fs/minix/file.c | 2 +- fs/minix/inode.c | 4 +- fs/minix/namei.c | 10 +- fs/ncpfs/dir.c | 48 +++--- fs/ncpfs/inode.c | 6 +- fs/ncpfs/ioctl.c | 8 +- fs/ncpfs/ncplib_kernel.c | 2 +- fs/ncpfs/symlink.c | 2 +- fs/nfs/dir.c | 59 ++++---- fs/nfs/direct.c | 4 +- fs/nfs/getroot.c | 4 +- fs/nfs/inode.c | 18 +-- fs/nfs/namespace.c | 10 +- fs/nfs/nfs3acl.c | 2 +- fs/nfs/nfs3proc.c | 12 +- fs/nfs/nfs4client.c | 2 +- fs/nfs/nfs4file.c | 4 +- fs/nfs/nfs4namespace.c | 4 +- fs/nfs/nfs4proc.c | 60 ++++---- fs/nfs/nfs4state.c | 4 +- fs/nfs/nfs4trace.h | 4 +- fs/nfs/pagelist.c | 2 +- fs/nfs/pnfs.h | 4 +- fs/nfs/proc.c | 4 +- fs/nfs/read.c | 2 +- fs/nfs/super.c | 6 +- fs/nfs/symlink.c | 2 +- fs/nfs/unlink.c | 20 +-- fs/nfs/write.c | 8 +- fs/nfsd/export.c | 4 +- fs/nfsd/nfs2acl.c | 8 +- fs/nfsd/nfs3acl.c | 8 +- fs/nfsd/nfs3proc.c | 6 +- fs/nfsd/nfs3xdr.c | 16 +- fs/nfsd/nfs4acl.c | 4 +- fs/nfsd/nfs4proc.c | 12 +- fs/nfsd/nfs4recover.c | 22 +-- fs/nfsd/nfs4state.c | 4 +- fs/nfsd/nfs4xdr.c | 10 +- fs/nfsd/nfsfh.c | 20 +-- fs/nfsd/nfsfh.h | 6 +- fs/nfsd/nfsproc.c | 4 +- fs/nfsd/nfsxdr.c | 2 +- fs/nfsd/vfs.c | 62 ++++---- fs/nfsd/xdr4.h | 2 +- fs/nilfs2/dir.c | 2 +- fs/nilfs2/inode.c | 2 +- fs/nilfs2/namei.c | 18 +-- fs/nilfs2/super.c | 6 +- fs/ntfs/inode.c | 2 +- fs/ntfs/namei.c | 4 +- fs/ocfs2/dcache.c | 14 +- fs/ocfs2/dir.h | 2 +- fs/ocfs2/dlmfs/dlmfs.c | 4 +- fs/ocfs2/export.c | 2 +- fs/ocfs2/file.c | 8 +- fs/ocfs2/inode.c | 2 +- fs/ocfs2/namei.c | 14 +- fs/ocfs2/refcounttree.c | 10 +- fs/ocfs2/xattr.c | 22 +-- fs/omfs/dir.c | 10 +- fs/omfs/file.c | 2 +- fs/proc/base.c | 32 ++-- fs/proc/fd.c | 6 +- fs/proc/generic.c | 4 +- fs/proc/inode.c | 2 +- fs/proc/namespaces.c | 4 +- fs/proc/proc_net.c | 2 +- fs/proc/proc_sysctl.c | 12 +- fs/proc/root.c | 2 +- fs/proc/self.c | 2 +- fs/proc/thread_self.c | 2 +- fs/pstore/inode.c | 10 +- fs/qnx6/inode.c | 2 +- fs/ramfs/file-nommu.c | 2 +- fs/reiserfs/dir.c | 4 +- fs/reiserfs/inode.c | 2 +- fs/reiserfs/namei.c | 12 +- fs/reiserfs/super.c | 4 +- fs/reiserfs/xattr.c | 126 ++++++++-------- fs/reiserfs/xattr.h | 2 +- fs/reiserfs/xattr_security.c | 10 +- fs/reiserfs/xattr_trusted.c | 10 +- fs/reiserfs/xattr_user.c | 4 +- fs/squashfs/export.c | 2 +- fs/squashfs/xattr.c | 8 +- fs/sysv/dir.c | 4 +- fs/sysv/file.c | 2 +- fs/sysv/itree.c | 2 +- fs/sysv/namei.c | 10 +- fs/sysv/symlink.c | 2 +- fs/ubifs/dir.c | 14 +- fs/ubifs/file.c | 4 +- fs/ubifs/journal.c | 4 +- fs/ubifs/xattr.c | 10 +- fs/udf/file.c | 2 +- fs/udf/namei.c | 16 +- fs/ufs/dir.c | 2 +- fs/ufs/namei.c | 10 +- fs/ufs/super.c | 4 +- fs/ufs/symlink.c | 2 +- fs/ufs/truncate.c | 2 +- fs/xfs/xfs_export.c | 2 +- fs/xfs/xfs_filestream.c | 2 +- fs/xfs/xfs_ioctl.c | 18 +-- fs/xfs/xfs_ioctl32.c | 12 +- fs/xfs/xfs_iops.c | 20 +-- fs/xfs/xfs_super.c | 2 +- fs/xfs/xfs_xattr.c | 6 +- include/trace/events/btrfs.h | 4 +- include/trace/events/ext3.h | 16 +- include/trace/events/ext4.h | 16 +- 278 files changed, 1419 insertions(+), 1420 deletions(-) (limited to 'include') diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index ddf1fa9f67f8..16e87e97121f 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c @@ -153,7 +153,7 @@ static int ll_ddelete(const struct dentry *de) CDEBUG(D_DENTRY, "%s dentry %pd (%p, parent %p, inode %p) %s%s\n", d_lustre_invalid((struct dentry *)de) ? "deleting" : "keeping", - de, de, de->d_parent, de->d_inode, + de, de, de->d_parent, d_inode(de), d_unhashed(de) ? "" : "hashed,", list_empty(&de->d_subdirs) ? "" : "subdirs"); @@ -167,8 +167,8 @@ static int ll_ddelete(const struct dentry *de) #if 0 /* if not ldlm lock for this inode, set i_nlink to 0 so that * this inode can be recycled later b=20433 */ - if (de->d_inode && !find_cbdata(de->d_inode)) - clear_nlink(de->d_inode); + if (d_really_is_positive(de) && !find_cbdata(d_inode(de))) + clear_nlink(d_inode(de)); #endif if (d_lustre_invalid((struct dentry *)de)) @@ -181,7 +181,7 @@ int ll_d_init(struct dentry *de) LASSERT(de != NULL); CDEBUG(D_DENTRY, "ldd on dentry %pd (%p) parent %p inode %p refc %d\n", - de, de, de->d_parent, de->d_inode, + de, de, de->d_parent, d_inode(de), d_count(de)); if (de->d_fsdata == NULL) { @@ -261,7 +261,7 @@ void ll_invalidate_aliases(struct inode *inode) ll_d_hlist_for_each_entry(dentry, p, &inode->i_dentry, d_u.d_alias) { CDEBUG(D_DENTRY, "dentry in drop %pd (%p) parent %p inode %p flags %d\n", dentry, dentry, dentry->d_parent, - dentry->d_inode, dentry->d_flags); + d_inode(dentry), dentry->d_flags); d_lustre_invalidate(dentry, 0); } @@ -309,7 +309,7 @@ void ll_lookup_finish_locks(struct lookup_intent *it, struct inode *inode) static int ll_revalidate_dentry(struct dentry *dentry, unsigned int lookup_flags) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); /* * if open&create is set, talk to MDS to make sure file is created if @@ -329,7 +329,7 @@ static int ll_revalidate_dentry(struct dentry *dentry, if (lookup_flags & LOOKUP_RCU) return -ECHILD; - do_statahead_enter(dir, &dentry, dentry->d_inode == NULL); + do_statahead_enter(dir, &dentry, d_inode(dentry) == NULL); ll_statahead_mark(dir, dentry); return 1; } diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index d73111ef949e..a6d43534871d 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -387,7 +387,7 @@ int ll_file_release(struct inode *inode, struct file *file) static int ll_intent_file_open(struct dentry *dentry, void *lmm, int lmmsize, struct lookup_intent *itp) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ll_sb_info *sbi = ll_i2sbi(inode); struct dentry *parent = dentry->d_parent; const char *name = dentry->d_name.name; @@ -412,7 +412,7 @@ static int ll_intent_file_open(struct dentry *dentry, void *lmm, opc = LUSTRE_OPC_CREATE; } - op_data = ll_prep_md_op_data(NULL, parent->d_inode, + op_data = ll_prep_md_op_data(NULL, d_inode(parent), inode, name, len, O_RDWR, opc, NULL); if (IS_ERR(op_data)) @@ -2889,7 +2889,7 @@ static int ll_inode_revalidate_fini(struct inode *inode, int rc) static int __ll_inode_revalidate(struct dentry *dentry, __u64 ibits) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ptlrpc_request *req = NULL; struct obd_export *exp; int rc = 0; @@ -2941,12 +2941,12 @@ static int __ll_inode_revalidate(struct dentry *dentry, __u64 ibits) do_lookup() -> ll_revalidate_it(). We cannot use d_drop here to preserve get_cwd functionality on 2.6. Bug 10503 */ - if (!dentry->d_inode->i_nlink) + if (!d_inode(dentry)->i_nlink) d_lustre_invalidate(dentry, 0); ll_lookup_finish_locks(&oit, inode); - } else if (!ll_have_md_lock(dentry->d_inode, &ibits, LCK_MINMODE)) { - struct ll_sb_info *sbi = ll_i2sbi(dentry->d_inode); + } else if (!ll_have_md_lock(d_inode(dentry), &ibits, LCK_MINMODE)) { + struct ll_sb_info *sbi = ll_i2sbi(d_inode(dentry)); u64 valid = OBD_MD_FLGETATTR; struct md_op_data *op_data; int ealen = 0; @@ -2984,7 +2984,7 @@ out: static int ll_inode_revalidate(struct dentry *dentry, __u64 ibits) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int rc; rc = __ll_inode_revalidate(dentry, ibits); @@ -3012,7 +3012,7 @@ static int ll_inode_revalidate(struct dentry *dentry, __u64 ibits) int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) { - struct inode *inode = de->d_inode; + struct inode *inode = d_inode(de); struct ll_sb_info *sbi = ll_i2sbi(inode); struct ll_inode_info *lli = ll_i2info(inode); int res = 0; diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index e7422f5c9c6f..5f918e3c4683 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -1488,7 +1488,7 @@ static inline void d_lustre_invalidate(struct dentry *dentry, int nested) { CDEBUG(D_DENTRY, "invalidate dentry %pd (%p) parent %p inode %p refc %d\n", dentry, dentry, - dentry->d_parent, dentry->d_inode, d_count(dentry)); + dentry->d_parent, d_inode(dentry), d_count(dentry)); spin_lock_nested(&dentry->d_lock, nested ? DENTRY_D_LOCK_NESTED : DENTRY_D_LOCK_NORMAL); diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 0c1b583a4ea1..f9132eddf51f 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -1169,7 +1169,7 @@ static int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data, struct md_open_data **mod) { struct lustre_md md; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ll_sb_info *sbi = ll_i2sbi(inode); struct ptlrpc_request *request = NULL; int rc, ia_valid; @@ -1293,7 +1293,7 @@ static int ll_setattr_ost(struct inode *inode, struct iattr *attr) */ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ll_inode_info *lli = ll_i2info(inode); struct md_op_data *op_data = NULL; struct md_open_data *mod = NULL; @@ -1467,7 +1467,7 @@ out: int ll_setattr(struct dentry *de, struct iattr *attr) { - int mode = de->d_inode->i_mode; + int mode = d_inode(de)->i_mode; if ((attr->ia_valid & (ATTR_CTIME|ATTR_SIZE|ATTR_MODE)) == (ATTR_CTIME|ATTR_SIZE|ATTR_MODE)) diff --git a/drivers/staging/lustre/lustre/llite/llite_nfs.c b/drivers/staging/lustre/lustre/llite/llite_nfs.c index 243a7840457f..db43b81386f7 100644 --- a/drivers/staging/lustre/lustre/llite/llite_nfs.c +++ b/drivers/staging/lustre/lustre/llite/llite_nfs.c @@ -230,11 +230,11 @@ static int ll_nfs_get_name_filldir(struct dir_context *ctx, const char *name, static int ll_get_name(struct dentry *dentry, char *name, struct dentry *child) { - struct inode *dir = dentry->d_inode; + struct inode *dir = d_inode(dentry); int rc; struct ll_getname_data lgd = { .lgd_name = name, - .lgd_fid = ll_i2info(child->d_inode)->lli_fid, + .lgd_fid = ll_i2info(d_inode(child))->lli_fid, .ctx.actor = ll_nfs_get_name_filldir, }; @@ -282,7 +282,7 @@ static struct dentry *ll_fh_to_parent(struct super_block *sb, struct fid *fid, static struct dentry *ll_get_parent(struct dentry *dchild) { struct ptlrpc_request *req = NULL; - struct inode *dir = dchild->d_inode; + struct inode *dir = d_inode(dchild); struct ll_sb_info *sbi; struct dentry *result = NULL; struct mdt_body *body; diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 890ac190f5fa..2ddb50c98acd 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -154,7 +154,7 @@ static void ll_invalidate_negative_children(struct inode *dir) list_for_each_entry_safe(child, tmp_subdir, &dentry->d_subdirs, d_child) { - if (child->d_inode == NULL) + if (d_really_is_negative(child)) d_lustre_invalidate(child, 1); } } @@ -391,7 +391,7 @@ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de) iput(inode); CDEBUG(D_DENTRY, "Reuse dentry %p inode %p refc %d flags %#x\n", - new, new->d_inode, d_count(new), new->d_flags); + new, d_inode(new), d_count(new), new->d_flags); return new; } } @@ -400,7 +400,7 @@ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de) return ERR_PTR(rc); d_add(de, inode); CDEBUG(D_DENTRY, "Add dentry %p inode %p refc %d flags %#x\n", - de, de->d_inode, d_count(de), de->d_flags); + de, d_inode(de), d_count(de), de->d_flags); return de; } @@ -447,7 +447,7 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request, !it_disposition(it, DISP_OPEN_CREATE)) { /* With DISP_OPEN_CREATE dentry will instantiated in ll_create_it. */ - LASSERT((*de)->d_inode == NULL); + LASSERT(d_inode(*de) == NULL); d_instantiate(*de, inode); } @@ -540,7 +540,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, goto out; } - inode = dentry->d_inode; + inode = d_inode(dentry); if ((it->it_op & IT_OPEN) && inode && !S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) { @@ -636,9 +636,9 @@ static int ll_atomic_open(struct inode *dir, struct dentry *dentry, *opened |= FILE_CREATED; } - if (dentry->d_inode && it_disposition(it, DISP_OPEN_OPEN)) { + if (d_really_is_positive(dentry) && it_disposition(it, DISP_OPEN_OPEN)) { /* Open dentry. */ - if (S_ISFIFO(dentry->d_inode->i_mode)) { + if (S_ISFIFO(d_inode(dentry)->i_mode)) { /* We cannot call open here as it would * deadlock. */ @@ -860,8 +860,8 @@ static int ll_create_nd(struct inode *dir, struct dentry *dentry, static inline void ll_get_child_fid(struct dentry *child, struct lu_fid *fid) { - if (child->d_inode) - *fid = *ll_inode2fid(child->d_inode); + if (d_really_is_positive(child)) + *fid = *ll_inode2fid(d_inode(child)); } /** @@ -1073,7 +1073,7 @@ static int ll_symlink(struct inode *dir, struct dentry *dentry, static int ll_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { - struct inode *src = old_dentry->d_inode; + struct inode *src = d_inode(old_dentry); struct ll_sb_info *sbi = ll_i2sbi(dir); struct ptlrpc_request *request = NULL; struct md_op_data *op_data; diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c index 6ad9dd0fe2b3..5537254d469e 100644 --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -871,7 +871,7 @@ static int do_sa_lookup(struct inode *dir, struct ll_sa_entry *entry) static int do_sa_revalidate(struct inode *dir, struct ll_sa_entry *entry, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct lookup_intent it = { .it_op = IT_GETATTR, .d.lustre.it_lock_handle = 0 }; struct md_enqueue_info *minfo; @@ -917,7 +917,7 @@ static int do_sa_revalidate(struct inode *dir, struct ll_sa_entry *entry, static void ll_statahead_one(struct dentry *parent, const char *entry_name, int entry_name_len) { - struct inode *dir = parent->d_inode; + struct inode *dir = d_inode(parent); struct ll_inode_info *lli = ll_i2info(dir); struct ll_statahead_info *sai = lli->lli_sai; struct dentry *dentry = NULL; @@ -935,8 +935,8 @@ static void ll_statahead_one(struct dentry *parent, const char *entry_name, rc = do_sa_lookup(dir, entry); } else { rc = do_sa_revalidate(dir, entry, dentry); - if (rc == 1 && agl_should_run(sai, dentry->d_inode)) - ll_agl_add(sai, dentry->d_inode, entry->se_index); + if (rc == 1 && agl_should_run(sai, d_inode(dentry))) + ll_agl_add(sai, d_inode(dentry), entry->se_index); } if (dentry != NULL) @@ -959,7 +959,7 @@ static void ll_statahead_one(struct dentry *parent, const char *entry_name, static int ll_agl_thread(void *arg) { struct dentry *parent = (struct dentry *)arg; - struct inode *dir = parent->d_inode; + struct inode *dir = d_inode(parent); struct ll_inode_info *plli = ll_i2info(dir); struct ll_inode_info *clli; struct ll_sb_info *sbi = ll_i2sbi(dir); @@ -1033,7 +1033,7 @@ static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai) CDEBUG(D_READA, "start agl thread: sai %p, parent %pd\n", sai, parent); - plli = ll_i2info(parent->d_inode); + plli = ll_i2info(d_inode(parent)); task = kthread_run(ll_agl_thread, parent, "ll_agl_%u", plli->lli_opendir_pid); if (IS_ERR(task)) { @@ -1050,7 +1050,7 @@ static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai) static int ll_statahead_thread(void *arg) { struct dentry *parent = (struct dentry *)arg; - struct inode *dir = parent->d_inode; + struct inode *dir = d_inode(parent); struct ll_inode_info *plli = ll_i2info(dir); struct ll_inode_info *clli; struct ll_sb_info *sbi = ll_i2sbi(dir); @@ -1595,7 +1595,7 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp, rc = md_revalidate_lock(ll_i2mdexp(dir), &it, ll_inode2fid(inode), &bits); if (rc == 1) { - if ((*dentryp)->d_inode == NULL) { + if (d_inode(*dentryp) == NULL) { struct dentry *alias; alias = ll_splice_alias(inode, @@ -1605,13 +1605,13 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp, return PTR_ERR(alias); } *dentryp = alias; - } else if ((*dentryp)->d_inode != inode) { + } else if (d_inode(*dentryp) != inode) { /* revalidate, but inode is recreated */ CDEBUG(D_READA, "stale dentry %pd inode %lu/%u, statahead inode %lu/%u\n", *dentryp, - (*dentryp)->d_inode->i_ino, - (*dentryp)->d_inode->i_generation, + d_inode(*dentryp)->i_ino, + d_inode(*dentryp)->i_generation, inode->i_ino, inode->i_generation); ll_sai_unplug(sai, entry); @@ -1657,8 +1657,8 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp, /* get parent reference count here, and put it in ll_statahead_thread */ parent = dget((*dentryp)->d_parent); - if (unlikely(sai->sai_inode != parent->d_inode)) { - struct ll_inode_info *nlli = ll_i2info(parent->d_inode); + if (unlikely(sai->sai_inode != d_inode(parent))) { + struct ll_inode_info *nlli = ll_i2info(d_inode(parent)); CWARN("Race condition, someone changed %pd just now: old parent "DFID", new parent "DFID"\n", *dentryp, @@ -1680,7 +1680,7 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp, ll_sai_get(sai); lli->lli_sai = sai; - plli = ll_i2info(parent->d_inode); + plli = ll_i2info(d_inode(parent)); rc = PTR_ERR(kthread_run(ll_statahead_thread, parent, "ll_sa_%u", plli->lli_opendir_pid)); thread = &sai->sai_thread; diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c index 686b6a574cc5..3711e671a4df 100644 --- a/drivers/staging/lustre/lustre/llite/symlink.c +++ b/drivers/staging/lustre/lustre/llite/symlink.c @@ -120,7 +120,7 @@ failed: static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ptlrpc_request *request = NULL; int rc; char *symname = NULL; diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c index b439936b4524..e0fcbe1395fd 100644 --- a/drivers/staging/lustre/lustre/llite/xattr.c +++ b/drivers/staging/lustre/lustre/llite/xattr.c @@ -214,7 +214,7 @@ int ll_setxattr_common(struct inode *inode, const char *name, int ll_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); LASSERT(inode); LASSERT(name); @@ -267,7 +267,7 @@ int ll_setxattr(struct dentry *dentry, const char *name, int ll_removexattr(struct dentry *dentry, const char *name) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); LASSERT(inode); LASSERT(name); @@ -457,7 +457,7 @@ out: ssize_t ll_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); LASSERT(inode); LASSERT(name); @@ -545,7 +545,7 @@ out: ssize_t ll_listxattr(struct dentry *dentry, char *buffer, size_t size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int rc = 0, rc2 = 0; struct lov_mds_md *lmm = NULL; struct ptlrpc_request *request = NULL; diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 8482f2d11606..31c010372660 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -247,7 +247,7 @@ static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name, if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) return v9fs_remote_get_acl(dentry, name, buffer, size, type); - acl = v9fs_get_cached_acl(dentry->d_inode, type); + acl = v9fs_get_cached_acl(d_inode(dentry), type); if (IS_ERR(acl)) return PTR_ERR(acl); if (acl == NULL) @@ -285,7 +285,7 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name, int retval; struct posix_acl *acl; struct v9fs_session_info *v9ses; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); if (strcmp(name, "") != 0) return -EINVAL; diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index a345b2d659cc..bd456c668d39 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -53,7 +53,7 @@ static int v9fs_cached_dentry_delete(const struct dentry *dentry) dentry, dentry); /* Don't cache negative dentries */ - if (!dentry->d_inode) + if (d_really_is_negative(dentry)) return 1; return 0; } @@ -83,7 +83,7 @@ static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags) if (flags & LOOKUP_RCU) return -ECHILD; - inode = dentry->d_inode; + inode = d_inode(dentry); if (!inode) goto out_valid; diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 3662f1d1d9cf..703342e309f5 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -595,7 +595,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags) dir, dentry, flags); v9ses = v9fs_inode2v9ses(dir); - inode = dentry->d_inode; + inode = d_inode(dentry); dfid = v9fs_fid_lookup(dentry->d_parent); if (IS_ERR(dfid)) { retval = PTR_ERR(dfid); @@ -864,7 +864,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, } /* Only creates */ - if (!(flags & O_CREAT) || dentry->d_inode) + if (!(flags & O_CREAT) || d_really_is_positive(dentry)) return finish_no_open(file, res); err = 0; @@ -881,7 +881,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, } v9fs_invalidate_inode_attr(dir); - v9inode = V9FS_I(dentry->d_inode); + v9inode = V9FS_I(d_inode(dentry)); mutex_lock(&v9inode->v_mutex); if ((v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) && !v9inode->writeback_fid && @@ -908,7 +908,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, file->private_data = fid; if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) - v9fs_cache_inode_set_cookie(dentry->d_inode, file); + v9fs_cache_inode_set_cookie(d_inode(dentry), file); *opened |= FILE_CREATED; out: @@ -969,8 +969,8 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, p9_debug(P9_DEBUG_VFS, "\n"); retval = 0; - old_inode = old_dentry->d_inode; - new_inode = new_dentry->d_inode; + old_inode = d_inode(old_dentry); + new_inode = d_inode(new_dentry); v9ses = v9fs_inode2v9ses(old_inode); oldfid = v9fs_fid_lookup(old_dentry); if (IS_ERR(oldfid)) @@ -1061,7 +1061,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry); v9ses = v9fs_dentry2v9ses(dentry); if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { - generic_fillattr(dentry->d_inode, stat); + generic_fillattr(d_inode(dentry), stat); return 0; } fid = v9fs_fid_lookup(dentry); @@ -1072,8 +1072,8 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, if (IS_ERR(st)) return PTR_ERR(st); - v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); - generic_fillattr(dentry->d_inode, stat); + v9fs_stat2inode(st, d_inode(dentry), d_inode(dentry)->i_sb); + generic_fillattr(d_inode(dentry), stat); p9stat_free(st); kfree(st); @@ -1095,7 +1095,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) struct p9_wstat wstat; p9_debug(P9_DEBUG_VFS, "\n"); - retval = inode_change_ok(dentry->d_inode, iattr); + retval = inode_change_ok(d_inode(dentry), iattr); if (retval) return retval; @@ -1128,20 +1128,20 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) /* Write all dirty data */ if (d_is_reg(dentry)) - filemap_write_and_wait(dentry->d_inode->i_mapping); + filemap_write_and_wait(d_inode(dentry)->i_mapping); retval = p9_client_wstat(fid, &wstat); if (retval < 0) return retval; if ((iattr->ia_valid & ATTR_SIZE) && - iattr->ia_size != i_size_read(dentry->d_inode)) - truncate_setsize(dentry->d_inode, iattr->ia_size); + iattr->ia_size != i_size_read(d_inode(dentry))) + truncate_setsize(d_inode(dentry), iattr->ia_size); - v9fs_invalidate_inode_attr(dentry->d_inode); + v9fs_invalidate_inode_attr(d_inode(dentry)); - setattr_copy(dentry->d_inode, iattr); - mark_inode_dirty(dentry->d_inode); + setattr_copy(d_inode(dentry), iattr); + mark_inode_dirty(d_inode(dentry)); return 0; } @@ -1403,7 +1403,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name); __putname(name); if (!retval) { - v9fs_refresh_inode(oldfid, old_dentry->d_inode); + v9fs_refresh_inode(oldfid, d_inode(old_dentry)); v9fs_invalidate_inode_attr(dir); } clunk_fid: diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 6054c16b8fae..9861c7c951a6 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -265,7 +265,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, } /* Only creates */ - if (!(flags & O_CREAT) || dentry->d_inode) + if (!(flags & O_CREAT) || d_really_is_positive(dentry)) return finish_no_open(file, res); v9ses = v9fs_inode2v9ses(dir); @@ -481,7 +481,7 @@ v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry, p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry); v9ses = v9fs_dentry2v9ses(dentry); if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { - generic_fillattr(dentry->d_inode, stat); + generic_fillattr(d_inode(dentry), stat); return 0; } fid = v9fs_fid_lookup(dentry); @@ -496,8 +496,8 @@ v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry, if (IS_ERR(st)) return PTR_ERR(st); - v9fs_stat2inode_dotl(st, dentry->d_inode); - generic_fillattr(dentry->d_inode, stat); + v9fs_stat2inode_dotl(st, d_inode(dentry)); + generic_fillattr(d_inode(dentry), stat); /* Change block size to what the server returned */ stat->blksize = st->st_blksize; @@ -557,7 +557,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) int retval; struct p9_fid *fid; struct p9_iattr_dotl p9attr; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); p9_debug(P9_DEBUG_VFS, "\n"); @@ -795,10 +795,10 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir, if (IS_ERR(fid)) return PTR_ERR(fid); - v9fs_refresh_inode_dotl(fid, old_dentry->d_inode); + v9fs_refresh_inode_dotl(fid, d_inode(old_dentry)); } - ihold(old_dentry->d_inode); - d_instantiate(dentry, old_dentry->d_inode); + ihold(d_inode(old_dentry)); + d_instantiate(dentry, d_inode(old_dentry)); return err; } diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 0afd0382822b..e99a338a4638 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -168,8 +168,8 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, retval = PTR_ERR(st); goto release_sb; } - root->d_inode->i_ino = v9fs_qid2ino(&st->qid); - v9fs_stat2inode_dotl(st, root->d_inode); + d_inode(root)->i_ino = v9fs_qid2ino(&st->qid); + v9fs_stat2inode_dotl(st, d_inode(root)); kfree(st); } else { struct p9_wstat *st = NULL; @@ -179,8 +179,8 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, goto release_sb; } - root->d_inode->i_ino = v9fs_qid2ino(&st->qid); - v9fs_stat2inode(st, root->d_inode, sb); + d_inode(root)->i_ino = v9fs_qid2ino(&st->qid); + v9fs_stat2inode(st, d_inode(root), sb); p9stat_free(st); kfree(st); diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index b9acadafa4a1..335055d828e4 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c @@ -298,7 +298,7 @@ out: int adfs_notify_change(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct super_block *sb = inode->i_sb; unsigned int ia_valid = attr->ia_valid; int error; diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index 388da1ea815d..40eb5814b98c 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c @@ -138,7 +138,7 @@ affs_fix_dcache(struct inode *inode, u32 entry_ino) static int affs_remove_link(struct dentry *dentry) { - struct inode *dir, *inode = dentry->d_inode; + struct inode *dir, *inode = d_inode(dentry); struct super_block *sb = inode->i_sb; struct buffer_head *bh = NULL, *link_bh = NULL; u32 link_ino, ino; @@ -268,11 +268,11 @@ affs_remove_header(struct dentry *dentry) struct buffer_head *bh = NULL; int retval; - dir = dentry->d_parent->d_inode; + dir = d_inode(dentry->d_parent); sb = dir->i_sb; retval = -ENOENT; - inode = dentry->d_inode; + inode = d_inode(dentry); if (!inode) goto done; @@ -471,7 +471,7 @@ affs_warning(struct super_block *sb, const char *function, const char *fmt, ...) bool affs_nofilenametruncate(const struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); return AFFS_SB(inode->i_sb)->s_flags & SF_NO_TRUNCATE; } diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 6f34510449e8..57ed17137a13 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -212,7 +212,7 @@ affs_write_inode(struct inode *inode, struct writeback_control *wbc) int affs_notify_change(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error; pr_debug("notify_change(%lu,0x%x)\n", inode->i_ino, attr->ia_valid); diff --git a/fs/affs/namei.c b/fs/affs/namei.c index ffb7bd82c2a5..372100288ee5 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -250,7 +250,7 @@ int affs_unlink(struct inode *dir, struct dentry *dentry) { pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino, - dentry->d_inode->i_ino, dentry); + d_inode(dentry)->i_ino, dentry); return affs_remove_header(dentry); } @@ -318,7 +318,7 @@ int affs_rmdir(struct inode *dir, struct dentry *dentry) { pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino, - dentry->d_inode->i_ino, dentry); + d_inode(dentry)->i_ino, dentry); return affs_remove_header(dentry); } @@ -401,7 +401,7 @@ err: int affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); pr_debug("%s(%lu, %lu, \"%pd\")\n", __func__, inode->i_ino, dir->i_ino, dentry); @@ -428,13 +428,13 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry, return retval; /* Unlink destination if it already exists */ - if (new_dentry->d_inode) { + if (d_really_is_positive(new_dentry)) { retval = affs_remove_header(new_dentry); if (retval) return retval; } - bh = affs_bread(sb, old_dentry->d_inode->i_ino); + bh = affs_bread(sb, d_inode(old_dentry)->i_ino); if (!bh) return -EIO; diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 4ec35e9130e1..e10e17788f06 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -505,7 +505,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, _enter("{%x:%u},%p{%pd},", vnode->fid.vid, vnode->fid.vnode, dentry, dentry); - ASSERTCMP(dentry->d_inode, ==, NULL); + ASSERTCMP(d_inode(dentry), ==, NULL); if (dentry->d_name.len >= AFSNAMEMAX) { _leave(" = -ENAMETOOLONG"); @@ -563,8 +563,8 @@ success: _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%u }", fid.vnode, fid.unique, - dentry->d_inode->i_ino, - dentry->d_inode->i_generation); + d_inode(dentry)->i_ino, + d_inode(dentry)->i_generation); return NULL; } @@ -586,9 +586,9 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) if (flags & LOOKUP_RCU) return -ECHILD; - vnode = AFS_FS_I(dentry->d_inode); + vnode = AFS_FS_I(d_inode(dentry)); - if (dentry->d_inode) + if (d_really_is_positive(dentry)) _enter("{v={%x:%u} n=%pd fl=%lx},", vnode->fid.vid, vnode->fid.vnode, dentry, vnode->flags); @@ -601,7 +601,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) /* lock down the parent dentry so we can peer at it */ parent = dget_parent(dentry); - dir = AFS_FS_I(parent->d_inode); + dir = AFS_FS_I(d_inode(parent)); /* validate the parent directory */ if (test_bit(AFS_VNODE_MODIFIED, &dir->flags)) @@ -623,9 +623,9 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) switch (ret) { case 0: /* the filename maps to something */ - if (!dentry->d_inode) + if (d_really_is_negative(dentry)) goto out_bad; - if (is_bad_inode(dentry->d_inode)) { + if (is_bad_inode(d_inode(dentry))) { printk("kAFS: afs_d_revalidate: %pd2 has bad inode\n", dentry); goto out_bad; @@ -647,7 +647,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) _debug("%pd: file deleted (uq %u -> %u I:%u)", dentry, fid.unique, vnode->fid.unique, - dentry->d_inode->i_generation); + d_inode(dentry)->i_generation); spin_lock(&vnode->lock); set_bit(AFS_VNODE_DELETED, &vnode->flags); spin_unlock(&vnode->lock); @@ -658,7 +658,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) case -ENOENT: /* the filename is unknown */ _debug("%pd: dirent not found", dentry); - if (dentry->d_inode) + if (d_really_is_positive(dentry)) goto not_found; goto out_valid; @@ -703,9 +703,9 @@ static int afs_d_delete(const struct dentry *dentry) if (dentry->d_flags & DCACHE_NFSFS_RENAMED) goto zap; - if (dentry->d_inode && - (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags) || - test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(dentry->d_inode)->flags))) + if (d_really_is_positive(dentry) && + (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(d_inode(dentry))->flags) || + test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(d_inode(dentry))->flags))) goto zap; _leave(" = 0 [keep]"); @@ -814,8 +814,8 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) if (ret < 0) goto rmdir_error; - if (dentry->d_inode) { - vnode = AFS_FS_I(dentry->d_inode); + if (d_really_is_positive(dentry)) { + vnode = AFS_FS_I(d_inode(dentry)); clear_nlink(&vnode->vfs_inode); set_bit(AFS_VNODE_DELETED, &vnode->flags); afs_discard_callback_on_delete(vnode); @@ -856,8 +856,8 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) goto error; } - if (dentry->d_inode) { - vnode = AFS_FS_I(dentry->d_inode); + if (d_really_is_positive(dentry)) { + vnode = AFS_FS_I(d_inode(dentry)); /* make sure we have a callback promise on the victim */ ret = afs_validate(vnode, key); @@ -869,7 +869,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) if (ret < 0) goto remove_error; - if (dentry->d_inode) { + if (d_really_is_positive(dentry)) { /* if the file wasn't deleted due to excess hard links, the * fileserver will break the callback promise on the file - if * it had one - before it returns to us, and if it was deleted, @@ -879,7 +879,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) * or it was outstanding on a different server, then it won't * break it either... */ - vnode = AFS_FS_I(dentry->d_inode); + vnode = AFS_FS_I(d_inode(dentry)); if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) _debug("AFS_VNODE_DELETED"); if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) @@ -977,7 +977,7 @@ static int afs_link(struct dentry *from, struct inode *dir, struct key *key; int ret; - vnode = AFS_FS_I(from->d_inode); + vnode = AFS_FS_I(d_inode(from)); dvnode = AFS_FS_I(dir); _enter("{%x:%u},{%x:%u},{%pd}", @@ -1089,7 +1089,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, struct key *key; int ret; - vnode = AFS_FS_I(old_dentry->d_inode); + vnode = AFS_FS_I(d_inode(old_dentry)); orig_dvnode = AFS_FS_I(old_dir); new_dvnode = AFS_FS_I(new_dir); diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 8a1d38ef0fc2..e06f5a23352a 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -379,7 +379,7 @@ int afs_getattr(struct vfsmount *mnt, struct dentry *dentry, { struct inode *inode; - inode = dentry->d_inode; + inode = d_inode(dentry); _enter("{ ino=%lu v=%u }", inode->i_ino, inode->i_generation); @@ -458,7 +458,7 @@ void afs_evict_inode(struct inode *inode) */ int afs_setattr(struct dentry *dentry, struct iattr *attr) { - struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); + struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); struct key *key; int ret; diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 938c5ab06d5a..ccd0b212e82a 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -134,7 +134,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) _enter("{%pd}", mntpt); - BUG_ON(!mntpt->d_inode); + BUG_ON(!d_inode(mntpt)); ret = -ENOMEM; devname = (char *) get_zeroed_page(GFP_KERNEL); @@ -145,7 +145,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) if (!options) goto error_no_options; - vnode = AFS_FS_I(mntpt->d_inode); + vnode = AFS_FS_I(d_inode(mntpt)); if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) { /* if the directory is a pseudo directory, use the d_name */ static const char afs_root_cell[] = ":root.cell."; @@ -169,14 +169,14 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) } } else { /* read the contents of the AFS special symlink */ - loff_t size = i_size_read(mntpt->d_inode); + loff_t size = i_size_read(d_inode(mntpt)); char *buf; ret = -EINVAL; if (size > PAGE_SIZE - 1) goto error_no_page; - page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); + page = read_mapping_page(d_inode(mntpt)->i_mapping, 0, NULL); if (IS_ERR(page)) { ret = PTR_ERR(page); goto error_no_page; diff --git a/fs/afs/super.c b/fs/afs/super.c index c4861557e385..1fb4a5129f7d 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -529,7 +529,7 @@ static void afs_destroy_inode(struct inode *inode) static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct afs_volume_status vs; - struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); + struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); struct key *key; int ret; diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index d10e619632ab..5b700ef1e59d 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -235,12 +235,12 @@ static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi) static inline u64 autofs4_get_ino(struct autofs_sb_info *sbi) { - return sbi->sb->s_root->d_inode->i_ino; + return d_inode(sbi->sb->s_root)->i_ino; } static inline int simple_positive(struct dentry *dentry) { - return dentry->d_inode && !d_unhashed(dentry); + return d_really_is_positive(dentry) && !d_unhashed(dentry); } static inline void __autofs4_add_expiring(struct dentry *dentry) diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 11dd118f75e2..1cebc3c52fa5 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -374,7 +374,7 @@ static struct dentry *should_expire(struct dentry *dentry, return NULL; } - if (dentry->d_inode && d_is_symlink(dentry)) { + if (d_really_is_positive(dentry) && d_is_symlink(dentry)) { DPRINTK("checking symlink %p %pd", dentry, dentry); /* * A symlink can't be "busy" in the usual sense so diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 1c55388ae633..a3ae0b2aeb5a 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -71,7 +71,7 @@ void autofs4_kill_sb(struct super_block *sb) static int autofs4_show_options(struct seq_file *m, struct dentry *root) { struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb); - struct inode *root_inode = root->d_sb->s_root->d_inode; + struct inode *root_inode = d_inode(root->d_sb->s_root); if (!sbi) return 0; @@ -352,8 +352,8 @@ struct inode *autofs4_get_inode(struct super_block *sb, umode_t mode) inode->i_mode = mode; if (sb->s_root) { - inode->i_uid = sb->s_root->d_inode->i_uid; - inode->i_gid = sb->s_root->d_inode->i_gid; + inode->i_uid = d_inode(sb->s_root)->i_uid; + inode->i_gid = d_inode(sb->s_root)->i_gid; } inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_ino = get_next_ino(); diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 7e44fdd03e2d..c6d7d3dbd52a 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -240,7 +240,7 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry, spin_lock(&expiring->d_lock); /* We've already been dentry_iput or unlinked */ - if (!expiring->d_inode) + if (d_really_is_negative(expiring)) goto next; qstr = &expiring->d_name; @@ -371,7 +371,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path) * having d_mountpoint() true, so there's no need to call back * to the daemon. */ - if (dentry->d_inode && d_is_symlink(dentry)) { + if (d_really_is_positive(dentry) && d_is_symlink(dentry)) { spin_unlock(&sbi->fs_lock); goto done; } @@ -459,7 +459,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk) return 0; if (d_mountpoint(dentry)) return 0; - inode = ACCESS_ONCE(dentry->d_inode); + inode = d_inode_rcu(dentry); if (inode && S_ISLNK(inode->i_mode)) return -EISDIR; if (list_empty(&dentry->d_subdirs)) @@ -485,7 +485,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk) * an incorrect ELOOP error return. */ if ((!d_mountpoint(dentry) && !simple_empty(dentry)) || - (dentry->d_inode && d_is_symlink(dentry))) + (d_really_is_positive(dentry) && d_is_symlink(dentry))) status = -EISDIR; } spin_unlock(&sbi->fs_lock); @@ -625,8 +625,8 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) } dput(ino->dentry); - dentry->d_inode->i_size = 0; - clear_nlink(dentry->d_inode); + d_inode(dentry)->i_size = 0; + clear_nlink(d_inode(dentry)); dir->i_mtime = CURRENT_TIME; @@ -719,8 +719,8 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) atomic_dec(&p_ino->count); } dput(ino->dentry); - dentry->d_inode->i_size = 0; - clear_nlink(dentry->d_inode); + d_inode(dentry)->i_size = 0; + clear_nlink(d_inode(dentry)); if (dir->i_nlink) drop_nlink(dir); @@ -839,7 +839,7 @@ static inline int autofs4_ask_umount(struct vfsmount *mnt, int __user *p) */ int is_autofs4_dentry(struct dentry *dentry) { - return dentry && dentry->d_inode && + return dentry && d_really_is_positive(dentry) && dentry->d_op == &autofs4_dentry_operations && dentry->d_fsdata != NULL; } diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c index 1e8ea192be2b..de58cc7b8076 100644 --- a/fs/autofs4/symlink.c +++ b/fs/autofs4/symlink.c @@ -18,7 +18,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) struct autofs_info *ino = autofs4_dentry_ino(dentry); if (ino && !autofs4_oz_mode(sbi)) ino->last_used = jiffies; - nd_set_link(nd, dentry->d_inode->i_private); + nd_set_link(nd, d_inode(dentry)->i_private); return NULL; } diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 2ad05ab93db8..35b755e79c2d 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -322,7 +322,7 @@ static int validate_request(struct autofs_wait_queue **wait, * continue on and create a new request. */ if (!IS_ROOT(dentry)) { - if (dentry->d_inode && d_unhashed(dentry)) { + if (d_really_is_positive(dentry) && d_unhashed(dentry)) { struct dentry *parent = dentry->d_parent; new = d_lookup(parent, &dentry->d_name); if (new) @@ -364,7 +364,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, if (pid == 0 || tgid == 0) return -ENOENT; - if (!dentry->d_inode) { + if (d_really_is_negative(dentry)) { /* * A wait for a negative dentry is invalid for certain * cases. A direct or offset mount "always" has its mount diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index e089f1985fca..d3cb8774765f 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -472,7 +472,7 @@ static void * befs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct super_block *sb = dentry->d_sb; - befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); + befs_inode_info *befs_ino = BEFS_I(d_inode(dentry)); befs_data_stream *data = &befs_ino->i_data.ds; befs_off_t len = data->size; char *link; @@ -502,7 +502,7 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd) static void * befs_fast_follow_link(struct dentry *dentry, struct nameidata *nd) { - befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); + befs_inode_info *befs_ino = BEFS_I(d_inode(dentry)); nd_set_link(nd, befs_ino->i_data.symlink); return NULL; } diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c index 08063ae0a17c..7efed2ad7eea 100644 --- a/fs/bfs/dir.c +++ b/fs/bfs/dir.c @@ -153,7 +153,7 @@ static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry, static int bfs_link(struct dentry *old, struct inode *dir, struct dentry *new) { - struct inode *inode = old->d_inode; + struct inode *inode = d_inode(old); struct bfs_sb_info *info = BFS_SB(inode->i_sb); int err; @@ -176,7 +176,7 @@ static int bfs_link(struct dentry *old, struct inode *dir, static int bfs_unlink(struct inode *dir, struct dentry *dentry) { int error = -ENOENT; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct buffer_head *bh; struct bfs_dirent *de; struct bfs_sb_info *info = BFS_SB(inode->i_sb); @@ -216,7 +216,7 @@ static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry, int error = -ENOENT; old_bh = new_bh = NULL; - old_inode = old_dentry->d_inode; + old_inode = d_inode(old_dentry); if (S_ISDIR(old_inode->i_mode)) return -EINVAL; @@ -231,7 +231,7 @@ static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto end_rename; error = -EPERM; - new_inode = new_dentry->d_inode; + new_inode = d_inode(new_dentry); new_bh = bfs_find_entry(new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de); diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c index 37d164540c3a..8d052209f473 100644 --- a/fs/btrfs/export.c +++ b/fs/btrfs/export.c @@ -152,7 +152,7 @@ static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh, static struct dentry *btrfs_get_parent(struct dentry *child) { - struct inode *dir = child->d_inode; + struct inode *dir = d_inode(child); struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_path *path; struct extent_buffer *leaf; @@ -220,8 +220,8 @@ fail: static int btrfs_get_name(struct dentry *parent, char *name, struct dentry *child) { - struct inode *inode = child->d_inode; - struct inode *dir = parent->d_inode; + struct inode *inode = d_inode(child); + struct inode *dir = d_inode(parent); struct btrfs_path *path; struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_inode_ref *iref; diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index faa7d390841b..2e57064c3cdf 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1864,7 +1864,7 @@ static int start_ordered_ops(struct inode *inode, loff_t start, loff_t end) int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) { struct dentry *dentry = file->f_path.dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_trans_handle *trans; struct btrfs_log_ctx ctx; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 43192e10cc43..811576346a92 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4016,16 +4016,16 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) { struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_trans_handle *trans; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int ret; trans = __unlink_start_trans(dir); if (IS_ERR(trans)) return PTR_ERR(trans); - btrfs_record_unlink_dir(trans, dir, dentry->d_inode, 0); + btrfs_record_unlink_dir(trans, dir, d_inode(dentry), 0); - ret = btrfs_unlink_inode(trans, root, dir, dentry->d_inode, + ret = btrfs_unlink_inode(trans, root, dir, d_inode(dentry), dentry->d_name.name, dentry->d_name.len); if (ret) goto out; @@ -4124,7 +4124,7 @@ out: static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int err = 0; struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_trans_handle *trans; @@ -4151,7 +4151,7 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) goto out; /* now the directory is empty */ - err = btrfs_unlink_inode(trans, root, dir, dentry->d_inode, + err = btrfs_unlink_inode(trans, root, dir, d_inode(dentry), dentry->d_name.name, dentry->d_name.len); if (!err) btrfs_i_size_write(inode, 0); @@ -4826,7 +4826,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr) static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct btrfs_root *root = BTRFS_I(inode)->root; int err; @@ -5416,10 +5416,10 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) static int btrfs_dentry_delete(const struct dentry *dentry) { struct btrfs_root *root; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); if (!inode && !IS_ROOT(dentry)) - inode = dentry->d_parent->d_inode; + inode = d_inode(dentry->d_parent); if (inode) { root = BTRFS_I(inode)->root; @@ -6226,7 +6226,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, { struct btrfs_trans_handle *trans; struct btrfs_root *root = BTRFS_I(dir)->root; - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); u64 index; int err; int drop_inode = 0; @@ -8875,7 +8875,7 @@ static int btrfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { u64 delalloc_bytes; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); u32 blocksize = inode->i_sb->s_blocksize; generic_fillattr(inode, stat); @@ -8896,8 +8896,8 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct btrfs_trans_handle *trans; struct btrfs_root *root = BTRFS_I(old_dir)->root; struct btrfs_root *dest = BTRFS_I(new_dir)->root; - struct inode *new_inode = new_dentry->d_inode; - struct inode *old_inode = old_dentry->d_inode; + struct inode *new_inode = d_inode(new_dentry); + struct inode *old_inode = d_inode(old_dentry); struct timespec ctime = CURRENT_TIME; u64 index = 0; u64 root_objectid; @@ -9009,7 +9009,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, old_dentry->d_name.len); } else { ret = __btrfs_unlink_inode(trans, root, old_dir, - old_dentry->d_inode, + d_inode(old_dentry), old_dentry->d_name.name, old_dentry->d_name.len); if (!ret) @@ -9033,12 +9033,12 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, BUG_ON(new_inode->i_nlink == 0); } else { ret = btrfs_unlink_inode(trans, dest, new_dir, - new_dentry->d_inode, + d_inode(new_dentry), new_dentry->d_name.name, new_dentry->d_name.len); } if (!ret && new_inode->i_nlink == 0) - ret = btrfs_orphan_add(trans, new_dentry->d_inode); + ret = btrfs_orphan_add(trans, d_inode(new_dentry)); if (ret) { btrfs_abort_transaction(trans, root, ret); goto out_fail; diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 74609b931ba5..20957ed47ce2 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -717,7 +717,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, if (ret) goto fail; - inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry); + inode = btrfs_lookup_dentry(d_inode(dentry->d_parent), dentry); if (IS_ERR(inode)) { ret = PTR_ERR(inode); goto fail; @@ -761,10 +761,10 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir) { int error; - if (!victim->d_inode) + if (d_really_is_negative(victim)) return -ENOENT; - BUG_ON(victim->d_parent->d_inode != dir); + BUG_ON(d_inode(victim->d_parent) != dir); audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); error = inode_permission(dir, MAY_WRITE | MAY_EXEC); @@ -772,8 +772,8 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir) return error; if (IS_APPEND(dir)) return -EPERM; - if (check_sticky(dir, victim->d_inode) || IS_APPEND(victim->d_inode) || - IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode)) + if (check_sticky(dir, d_inode(victim)) || IS_APPEND(d_inode(victim)) || + IS_IMMUTABLE(d_inode(victim)) || IS_SWAPFILE(d_inode(victim))) return -EPERM; if (isdir) { if (!d_is_dir(victim)) @@ -792,7 +792,7 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir) /* copy of may_create in fs/namei.c() */ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) { - if (child->d_inode) + if (d_really_is_positive(child)) return -EEXIST; if (IS_DEADDIR(dir)) return -ENOENT; @@ -810,7 +810,7 @@ static noinline int btrfs_mksubvol(struct path *parent, u64 *async_transid, bool readonly, struct btrfs_qgroup_inherit *inherit) { - struct inode *dir = parent->dentry->d_inode; + struct inode *dir = d_inode(parent->dentry); struct dentry *dentry; int error; @@ -824,7 +824,7 @@ static noinline int btrfs_mksubvol(struct path *parent, goto out_unlock; error = -EEXIST; - if (dentry->d_inode) + if (d_really_is_positive(dentry)) goto out_dput; error = btrfs_may_create(dir, dentry); @@ -2294,7 +2294,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, { struct dentry *parent = file->f_path.dentry; struct dentry *dentry; - struct inode *dir = parent->d_inode; + struct inode *dir = d_inode(parent); struct inode *inode; struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_root *dest = NULL; @@ -2333,12 +2333,12 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, goto out_unlock_dir; } - if (!dentry->d_inode) { + if (d_really_is_negative(dentry)) { err = -ENOENT; goto out_dput; } - inode = dentry->d_inode; + inode = d_inode(dentry); dest = BTRFS_I(inode)->root; if (!capable(CAP_SYS_ADMIN)) { /* diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 05fef198ff94..68ee619fff45 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -916,7 +916,7 @@ setup_root: * a reference to the dentry. We will have already gotten a reference * to the inode in btrfs_fill_super so we're good to go. */ - if (!new && sb->s_root->d_inode == inode) { + if (!new && d_inode(sb->s_root) == inode) { iput(inode); return dget(sb->s_root); } @@ -1221,7 +1221,7 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags, root = mount_subtree(mnt, subvol_name); - if (!IS_ERR(root) && !is_subvolume_inode(root->d_inode)) { + if (!IS_ERR(root) && !is_subvolume_inode(d_inode(root))) { struct super_block *s = root->d_sb; dput(root); root = ERR_PTR(-EINVAL); @@ -1886,8 +1886,8 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_fsid.val[0] = be32_to_cpu(fsid[0]) ^ be32_to_cpu(fsid[2]); buf->f_fsid.val[1] = be32_to_cpu(fsid[1]) ^ be32_to_cpu(fsid[3]); /* Mask in the root object ID too, to disambiguate subvols */ - buf->f_fsid.val[0] ^= BTRFS_I(dentry->d_inode)->root->objectid >> 32; - buf->f_fsid.val[1] ^= BTRFS_I(dentry->d_inode)->root->objectid; + buf->f_fsid.val[0] ^= BTRFS_I(d_inode(dentry))->root->objectid >> 32; + buf->f_fsid.val[1] ^= BTRFS_I(d_inode(dentry))->root->objectid; return 0; } diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index c5b8ba37f88e..25db71be462a 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -4327,9 +4327,9 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans, goto out; if (!S_ISDIR(inode->i_mode)) { - if (!parent || !parent->d_inode || sb != parent->d_inode->i_sb) + if (!parent || d_really_is_negative(parent) || sb != d_inode(parent)->i_sb) goto out; - inode = parent->d_inode; + inode = d_inode(parent); } while (1) { @@ -4355,7 +4355,7 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans, break; } - if (!parent || !parent->d_inode || sb != parent->d_inode->i_sb) + if (!parent || d_really_is_negative(parent) || sb != d_inode(parent)->i_sb) break; if (IS_ROOT(parent)) @@ -4364,7 +4364,7 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans, parent = dget_parent(parent); dput(old_parent); old_parent = parent; - inode = parent->d_inode; + inode = d_inode(parent); } dput(old_parent); @@ -4450,10 +4450,10 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, } while (1) { - if (!parent || !parent->d_inode || sb != parent->d_inode->i_sb) + if (!parent || d_really_is_negative(parent) || sb != d_inode(parent)->i_sb) break; - inode = parent->d_inode; + inode = d_inode(parent); if (root != BTRFS_I(inode)->root) break; @@ -4515,7 +4515,7 @@ int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, struct dentry *parent = dget_parent(dentry); int ret; - ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, + ret = btrfs_log_inode_parent(trans, root, d_inode(dentry), parent, start, end, 0, ctx); dput(parent); diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index 883b93623bc5..4cca14ecb660 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c @@ -261,7 +261,7 @@ out: ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) { struct btrfs_key key, found_key; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_path *path; struct extent_buffer *leaf; @@ -390,13 +390,13 @@ ssize_t btrfs_getxattr(struct dentry *dentry, const char *name, if (!btrfs_is_valid_xattr(name)) return -EOPNOTSUPP; - return __btrfs_getxattr(dentry->d_inode, name, buffer, size); + return __btrfs_getxattr(d_inode(dentry), name, buffer, size); } int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root; + struct btrfs_root *root = BTRFS_I(d_inode(dentry))->root; /* * The permission on security.* and system.* is not checked @@ -417,19 +417,19 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, return -EOPNOTSUPP; if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN)) - return btrfs_set_prop(dentry->d_inode, name, + return btrfs_set_prop(d_inode(dentry), name, value, size, flags); if (size == 0) value = ""; /* empty EA, do not remove */ - return __btrfs_setxattr(NULL, dentry->d_inode, name, value, size, + return __btrfs_setxattr(NULL, d_inode(dentry), name, value, size, flags); } int btrfs_removexattr(struct dentry *dentry, const char *name) { - struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root; + struct btrfs_root *root = BTRFS_I(d_inode(dentry))->root; /* * The permission on security.* and system.* is not checked @@ -450,10 +450,10 @@ int btrfs_removexattr(struct dentry *dentry, const char *name) return -EOPNOTSUPP; if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN)) - return btrfs_set_prop(dentry->d_inode, name, + return btrfs_set_prop(d_inode(dentry), name, NULL, 0, XATTR_REPLACE); - return __btrfs_setxattr(NULL, dentry->d_inode, name, NULL, 0, + return __btrfs_setxattr(NULL, d_inode(dentry), name, NULL, 0, XATTR_REPLACE); } diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 8172775428a0..283cf69c6904 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -3391,7 +3391,7 @@ int ceph_encode_inode_release(void **p, struct inode *inode, int ceph_encode_dentry_release(void **p, struct dentry *dentry, int mds, int drop, int unless) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); struct ceph_mds_request_release *rel = *p; struct ceph_dentry_info *di = ceph_dentry(dentry); int force = 0; diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c index 1b2355109b9f..31f831471ed2 100644 --- a/fs/ceph/debugfs.c +++ b/fs/ceph/debugfs.c @@ -84,7 +84,7 @@ static int mdsc_show(struct seq_file *s, void *p) path = NULL; spin_lock(&req->r_dentry->d_lock); seq_printf(s, " #%llx/%pd (%s)", - ceph_ino(req->r_dentry->d_parent->d_inode), + ceph_ino(d_inode(req->r_dentry->d_parent)), req->r_dentry, path ? path : ""); spin_unlock(&req->r_dentry->d_lock); diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 83e9976f7189..173fc598c7f1 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -49,9 +49,9 @@ int ceph_init_dentry(struct dentry *dentry) goto out_unlock; } - if (ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP) + if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_NOSNAP) d_set_d_op(dentry, &ceph_dentry_ops); - else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR) + else if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_SNAPDIR) d_set_d_op(dentry, &ceph_snapdir_dentry_ops); else d_set_d_op(dentry, &ceph_snap_dentry_ops); @@ -77,7 +77,7 @@ struct inode *ceph_get_dentry_parent_inode(struct dentry *dentry) spin_lock(&dentry->d_lock); if (!IS_ROOT(dentry)) { - inode = dentry->d_parent->d_inode; + inode = d_inode(dentry->d_parent); ihold(inode); } spin_unlock(&dentry->d_lock); @@ -122,7 +122,7 @@ static int __dcache_readdir(struct file *file, struct dir_context *ctx, { struct ceph_file_info *fi = file->private_data; struct dentry *parent = file->f_path.dentry; - struct inode *dir = parent->d_inode; + struct inode *dir = d_inode(parent); struct list_head *p; struct dentry *dentry, *last; struct ceph_dentry_info *di; @@ -161,15 +161,15 @@ more: } spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); if (di->lease_shared_gen == shared_gen && - !d_unhashed(dentry) && dentry->d_inode && - ceph_snap(dentry->d_inode) != CEPH_SNAPDIR && - ceph_ino(dentry->d_inode) != CEPH_INO_CEPH && + !d_unhashed(dentry) && d_really_is_positive(dentry) && + ceph_snap(d_inode(dentry)) != CEPH_SNAPDIR && + ceph_ino(d_inode(dentry)) != CEPH_INO_CEPH && fpos_cmp(ctx->pos, di->offset) <= 0) break; dout(" skipping %p %pd at %llu (%llu)%s%s\n", dentry, dentry, di->offset, ctx->pos, d_unhashed(dentry) ? " unhashed" : "", - !dentry->d_inode ? " null" : ""); + !d_inode(dentry) ? " null" : ""); spin_unlock(&dentry->d_lock); p = p->prev; dentry = list_entry(p, struct dentry, d_child); @@ -189,11 +189,11 @@ more: } dout(" %llu (%llu) dentry %p %pd %p\n", di->offset, ctx->pos, - dentry, dentry, dentry->d_inode); + dentry, dentry, d_inode(dentry)); if (!dir_emit(ctx, dentry->d_name.name, dentry->d_name.len, - ceph_translate_ino(dentry->d_sb, dentry->d_inode->i_ino), - dentry->d_inode->i_mode >> 12)) { + ceph_translate_ino(dentry->d_sb, d_inode(dentry)->i_ino), + d_inode(dentry)->i_mode >> 12)) { if (last) { /* remember our position */ fi->dentry = last; @@ -535,7 +535,7 @@ int ceph_handle_snapdir(struct ceph_mds_request *req, struct dentry *dentry, int err) { struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb); - struct inode *parent = dentry->d_parent->d_inode; /* we hold i_mutex */ + struct inode *parent = d_inode(dentry->d_parent); /* we hold i_mutex */ /* .snap dir? */ if (err == -ENOENT && @@ -571,8 +571,8 @@ struct dentry *ceph_finish_lookup(struct ceph_mds_request *req, err = 0; if (!req->r_reply_info.head->is_dentry) { dout("ENOENT and no trace, dentry %p inode %p\n", - dentry, dentry->d_inode); - if (dentry->d_inode) { + dentry, d_inode(dentry)); + if (d_really_is_positive(dentry)) { d_drop(dentry); err = -ENOENT; } else { @@ -619,7 +619,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, return ERR_PTR(err); /* can we conclude ENOENT locally? */ - if (dentry->d_inode == NULL) { + if (d_really_is_negative(dentry)) { struct ceph_inode_info *ci = ceph_inode(dir); struct ceph_dentry_info *di = ceph_dentry(dentry); @@ -725,7 +725,7 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry, ceph_mdsc_put_request(req); out: if (!err) - ceph_init_inode_acls(dentry->d_inode, &acls); + ceph_init_inode_acls(d_inode(dentry), &acls); else d_drop(dentry); ceph_release_acls_info(&acls); @@ -821,7 +821,7 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ceph_mdsc_put_request(req); out: if (!err) - ceph_init_inode_acls(dentry->d_inode, &acls); + ceph_init_inode_acls(d_inode(dentry), &acls); else d_drop(dentry); ceph_release_acls_info(&acls); @@ -858,8 +858,8 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir, if (err) { d_drop(dentry); } else if (!req->r_reply_info.head->is_dentry) { - ihold(old_dentry->d_inode); - d_instantiate(dentry, old_dentry->d_inode); + ihold(d_inode(old_dentry)); + d_instantiate(dentry, d_inode(old_dentry)); } ceph_mdsc_put_request(req); return err; @@ -892,7 +892,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry) { struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb); struct ceph_mds_client *mdsc = fsc->mdsc; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ceph_mds_request *req; int err = -EROFS; int op; @@ -957,8 +957,8 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry, req->r_dentry_unless = CEPH_CAP_FILE_EXCL; /* release LINK_RDCACHE on source inode (mds will lock it) */ req->r_old_inode_drop = CEPH_CAP_LINK_SHARED; - if (new_dentry->d_inode) - req->r_inode_drop = drop_caps_for_unlink(new_dentry->d_inode); + if (d_really_is_positive(new_dentry)) + req->r_inode_drop = drop_caps_for_unlink(d_inode(new_dentry)); err = ceph_mdsc_do_request(mdsc, old_dir, req); if (!err && !req->r_reply_info.head->is_dentry) { /* @@ -1024,7 +1024,7 @@ static int dentry_lease_is_valid(struct dentry *dentry) if (di->lease_renew_after && time_after(jiffies, di->lease_renew_after)) { /* we should renew */ - dir = dentry->d_parent->d_inode; + dir = d_inode(dentry->d_parent); session = ceph_get_mds_session(s); seq = di->lease_seq; di->lease_renew_after = 0; @@ -1074,22 +1074,22 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags) return -ECHILD; dout("d_revalidate %p '%pd' inode %p offset %lld\n", dentry, - dentry, dentry->d_inode, ceph_dentry(dentry)->offset); + dentry, d_inode(dentry), ceph_dentry(dentry)->offset); dir = ceph_get_dentry_parent_inode(dentry); /* always trust cached snapped dentries, snapdir dentry */ if (ceph_snap(dir) != CEPH_NOSNAP) { dout("d_revalidate %p '%pd' inode %p is SNAPPED\n", dentry, - dentry, dentry->d_inode); + dentry, d_inode(dentry)); valid = 1; - } else if (dentry->d_inode && - ceph_snap(dentry->d_inode) == CEPH_SNAPDIR) { + } else if (d_really_is_positive(dentry) && + ceph_snap(d_inode(dentry)) == CEPH_SNAPDIR) { valid = 1; } else if (dentry_lease_is_valid(dentry) || dir_lease_is_valid(dir, dentry)) { - if (dentry->d_inode) - valid = ceph_is_any_caps(dentry->d_inode); + if (d_really_is_positive(dentry)) + valid = ceph_is_any_caps(d_inode(dentry)); else valid = 1; } @@ -1151,7 +1151,7 @@ static void ceph_d_prune(struct dentry *dentry) * we hold d_lock, so d_parent is stable, and d_fsdata is never * cleared until d_release */ - ceph_dir_clear_complete(dentry->d_parent->d_inode); + ceph_dir_clear_complete(d_inode(dentry->d_parent)); } /* diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 8d7d782f4382..fe02ae7f056a 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -136,8 +136,8 @@ static struct dentry *__get_parent(struct super_block *sb, return ERR_CAST(req); if (child) { - req->r_inode = child->d_inode; - ihold(child->d_inode); + req->r_inode = d_inode(child); + ihold(d_inode(child)); } else { req->r_ino1 = (struct ceph_vino) { .ino = ino, @@ -164,7 +164,7 @@ static struct dentry *__get_parent(struct super_block *sb, return ERR_PTR(err); } dout("__get_parent ino %llx parent %p ino %llx.%llx\n", - child ? ceph_ino(child->d_inode) : ino, + child ? ceph_ino(d_inode(child)) : ino, dentry, ceph_vinop(inode)); return dentry; } @@ -172,11 +172,11 @@ static struct dentry *__get_parent(struct super_block *sb, static struct dentry *ceph_get_parent(struct dentry *child) { /* don't re-export snaps */ - if (ceph_snap(child->d_inode) != CEPH_NOSNAP) + if (ceph_snap(d_inode(child)) != CEPH_NOSNAP) return ERR_PTR(-EINVAL); dout("get_parent %p ino %llx.%llx\n", - child, ceph_vinop(child->d_inode)); + child, ceph_vinop(d_inode(child))); return __get_parent(child->d_sb, child, 0); } @@ -209,32 +209,32 @@ static int ceph_get_name(struct dentry *parent, char *name, struct ceph_mds_request *req; int err; - mdsc = ceph_inode_to_client(child->d_inode)->mdsc; + mdsc = ceph_inode_to_client(d_inode(child))->mdsc; req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME, USE_ANY_MDS); if (IS_ERR(req)) return PTR_ERR(req); - mutex_lock(&parent->d_inode->i_mutex); + mutex_lock(&d_inode(parent)->i_mutex); - req->r_inode = child->d_inode; - ihold(child->d_inode); - req->r_ino2 = ceph_vino(parent->d_inode); - req->r_locked_dir = parent->d_inode; + req->r_inode = d_inode(child); + ihold(d_inode(child)); + req->r_ino2 = ceph_vino(d_inode(parent)); + req->r_locked_dir = d_inode(parent); req->r_num_caps = 2; err = ceph_mdsc_do_request(mdsc, NULL, req); - mutex_unlock(&parent->d_inode->i_mutex); + mutex_unlock(&d_inode(parent)->i_mutex); if (!err) { struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info; memcpy(name, rinfo->dname, rinfo->dname_len); name[rinfo->dname_len] = 0; dout("get_name %p ino %llx.%llx name %s\n", - child, ceph_vinop(child->d_inode), name); + child, ceph_vinop(d_inode(child)), name); } else { dout("get_name %p ino %llx.%llx err %d\n", - child, ceph_vinop(child->d_inode), err); + child, ceph_vinop(d_inode(child)), err); } ceph_mdsc_put_request(req); diff --git a/fs/ceph/file.c b/fs/ceph/file.c index b9b8eb225f66..3b6b522b4b31 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -291,14 +291,14 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, } if (err) goto out_req; - if (dn || dentry->d_inode == NULL || d_is_symlink(dentry)) { + if (dn || d_really_is_negative(dentry) || d_is_symlink(dentry)) { /* make vfs retry on splice, ENOENT, or symlink */ dout("atomic_open finish_no_open on dn %p\n", dn); err = finish_no_open(file, dn); } else { dout("atomic_open finish_open on dn %p\n", dn); if (req->r_op == CEPH_MDS_OP_CREATE && req->r_reply_info.has_create_ino) { - ceph_init_inode_acls(dentry->d_inode, &acls); + ceph_init_inode_acls(d_inode(dentry), &acls); *opened |= FILE_CREATED; } err = finish_open(file, dentry, ceph_open, opened); diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 119c43c80638..e876e1944519 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -940,7 +940,7 @@ static void update_dentry_lease(struct dentry *dentry, dentry, duration, ttl); /* make lease_rdcache_gen match directory */ - dir = dentry->d_parent->d_inode; + dir = d_inode(dentry->d_parent); di->lease_shared_gen = ceph_inode(dir)->i_shared_gen; if (duration == 0) @@ -980,7 +980,7 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, { struct dentry *realdn; - BUG_ON(dn->d_inode); + BUG_ON(d_inode(dn)); /* dn must be unhashed */ if (!d_unhashed(dn)) @@ -998,13 +998,13 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, "inode %p ino %llx.%llx\n", dn, d_count(dn), realdn, d_count(realdn), - realdn->d_inode, ceph_vinop(realdn->d_inode)); + d_inode(realdn), ceph_vinop(d_inode(realdn))); dput(dn); dn = realdn; } else { BUG_ON(!ceph_dentry(dn)); dout("dn %p attached to %p ino %llx.%llx\n", - dn, dn->d_inode, ceph_vinop(dn->d_inode)); + dn, d_inode(dn), ceph_vinop(d_inode(dn))); } if ((!prehash || *prehash) && d_unhashed(dn)) d_rehash(dn); @@ -1125,11 +1125,11 @@ retry_lookup: dput(parent); goto done; } - } else if (dn->d_inode && - (ceph_ino(dn->d_inode) != vino.ino || - ceph_snap(dn->d_inode) != vino.snap)) { + } else if (d_really_is_positive(dn) && + (ceph_ino(d_inode(dn)) != vino.ino || + ceph_snap(d_inode(dn)) != vino.snap)) { dout(" dn %p points to wrong inode %p\n", - dn, dn->d_inode); + dn, d_inode(dn)); d_delete(dn); dput(dn); goto retry_lookup; @@ -1183,7 +1183,7 @@ retry_lookup: BUG_ON(!dn); BUG_ON(!dir); - BUG_ON(dn->d_parent->d_inode != dir); + BUG_ON(d_inode(dn->d_parent) != dir); BUG_ON(ceph_ino(dir) != le64_to_cpu(rinfo->diri.in->ino)); BUG_ON(ceph_snap(dir) != @@ -1235,7 +1235,7 @@ retry_lookup: /* null dentry? */ if (!rinfo->head->is_target) { dout("fill_trace null dentry\n"); - if (dn->d_inode) { + if (d_really_is_positive(dn)) { ceph_dir_clear_ordered(dir); dout("d_delete %p\n", dn); d_delete(dn); @@ -1252,7 +1252,7 @@ retry_lookup: } /* attach proper inode */ - if (!dn->d_inode) { + if (d_really_is_negative(dn)) { ceph_dir_clear_ordered(dir); ihold(in); dn = splice_dentry(dn, in, &have_lease); @@ -1261,9 +1261,9 @@ retry_lookup: goto done; } req->r_dentry = dn; /* may have spliced */ - } else if (dn->d_inode && dn->d_inode != in) { + } else if (d_really_is_positive(dn) && d_inode(dn) != in) { dout(" %p links to %p %llx.%llx, not %llx.%llx\n", - dn, dn->d_inode, ceph_vinop(dn->d_inode), + dn, d_inode(dn), ceph_vinop(d_inode(dn)), ceph_vinop(in)); have_lease = false; } @@ -1363,7 +1363,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, return readdir_prepopulate_inodes_only(req, session); if (le32_to_cpu(rinfo->head->op) == CEPH_MDS_OP_LSSNAP) { - snapdir = ceph_get_snapdir(parent->d_inode); + snapdir = ceph_get_snapdir(d_inode(parent)); parent = d_find_alias(snapdir); dout("readdir_prepopulate %d items under SNAPDIR dn %p\n", rinfo->dir_nr, parent); @@ -1371,7 +1371,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, dout("readdir_prepopulate %d items under dn %p\n", rinfo->dir_nr, parent); if (rinfo->dir_dir) - ceph_fill_dirfrag(parent->d_inode, rinfo->dir_dir); + ceph_fill_dirfrag(d_inode(parent), rinfo->dir_dir); } /* FIXME: release caps/leases if error occurs */ @@ -1405,11 +1405,11 @@ retry_lookup: err = ret; goto out; } - } else if (dn->d_inode && - (ceph_ino(dn->d_inode) != vino.ino || - ceph_snap(dn->d_inode) != vino.snap)) { + } else if (d_really_is_positive(dn) && + (ceph_ino(d_inode(dn)) != vino.ino || + ceph_snap(d_inode(dn)) != vino.snap)) { dout(" dn %p points to wrong inode %p\n", - dn, dn->d_inode); + dn, d_inode(dn)); d_delete(dn); dput(dn); goto retry_lookup; @@ -1423,8 +1423,8 @@ retry_lookup: } /* inode */ - if (dn->d_inode) { - in = dn->d_inode; + if (d_really_is_positive(dn)) { + in = d_inode(dn); } else { in = ceph_get_inode(parent->d_sb, vino); if (IS_ERR(in)) { @@ -1440,13 +1440,13 @@ retry_lookup: req->r_request_started, -1, &req->r_caps_reservation) < 0) { pr_err("fill_inode badness on %p\n", in); - if (!dn->d_inode) + if (d_really_is_negative(dn)) iput(in); d_drop(dn); goto next_item; } - if (!dn->d_inode) { + if (d_really_is_negative(dn)) { struct dentry *realdn = splice_dentry(dn, in, NULL); if (IS_ERR(realdn)) { err = PTR_ERR(realdn); @@ -1693,7 +1693,7 @@ retry: */ static void *ceph_sym_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct ceph_inode_info *ci = ceph_inode(dentry->d_inode); + struct ceph_inode_info *ci = ceph_inode(d_inode(dentry)); nd_set_link(nd, ci->i_symlink); return NULL; } @@ -1714,7 +1714,7 @@ static const struct inode_operations ceph_symlink_iops = { */ int ceph_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ceph_inode_info *ci = ceph_inode(inode); const unsigned int ia_valid = attr->ia_valid; struct ceph_mds_request *req; @@ -1990,7 +1990,7 @@ int ceph_permission(struct inode *inode, int mask) int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ceph_inode_info *ci = ceph_inode(inode); int err; diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 71c073f38e54..a39389092102 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -679,7 +679,7 @@ static struct dentry *get_nonsnap_parent(struct dentry *dentry) * except to resplice to another snapdir, and either the old or new * result is a valid result. */ - while (!IS_ROOT(dentry) && ceph_snap(dentry->d_inode) != CEPH_NOSNAP) + while (!IS_ROOT(dentry) && ceph_snap(d_inode(dentry)) != CEPH_NOSNAP) dentry = dentry->d_parent; return dentry; } @@ -716,20 +716,20 @@ static int __choose_mds(struct ceph_mds_client *mdsc, } else if (req->r_dentry) { /* ignore race with rename; old or new d_parent is okay */ struct dentry *parent = req->r_dentry->d_parent; - struct inode *dir = parent->d_inode; + struct inode *dir = d_inode(parent); if (dir->i_sb != mdsc->fsc->sb) { /* not this fs! */ - inode = req->r_dentry->d_inode; + inode = d_inode(req->r_dentry); } else if (ceph_snap(dir) != CEPH_NOSNAP) { /* direct snapped/virtual snapdir requests * based on parent dir inode */ struct dentry *dn = get_nonsnap_parent(parent); - inode = dn->d_inode; + inode = d_inode(dn); dout("__choose_mds using nonsnap parent %p\n", inode); } else { /* dentry target */ - inode = req->r_dentry->d_inode; + inode = d_inode(req->r_dentry); if (!inode || mode == USE_AUTH_MDS) { /* dir + name */ inode = dir; @@ -1712,7 +1712,7 @@ retry: seq = read_seqbegin(&rename_lock); rcu_read_lock(); for (temp = dentry; !IS_ROOT(temp);) { - struct inode *inode = temp->d_inode; + struct inode *inode = d_inode(temp); if (inode && ceph_snap(inode) == CEPH_SNAPDIR) len++; /* slash only */ else if (stop_on_nosnap && inode && @@ -1736,7 +1736,7 @@ retry: struct inode *inode; spin_lock(&temp->d_lock); - inode = temp->d_inode; + inode = d_inode(temp); if (inode && ceph_snap(inode) == CEPH_SNAPDIR) { dout("build_path path+%d: %p SNAPDIR\n", pos, temp); @@ -1770,7 +1770,7 @@ retry: goto retry; } - *base = ceph_ino(temp->d_inode); + *base = ceph_ino(d_inode(temp)); *plen = len; dout("build_path on %p %d built %llx '%.*s'\n", dentry, d_count(dentry), *base, len, path); @@ -1783,8 +1783,8 @@ static int build_dentry_path(struct dentry *dentry, { char *path; - if (ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP) { - *pino = ceph_ino(dentry->d_parent->d_inode); + if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_NOSNAP) { + *pino = ceph_ino(d_inode(dentry->d_parent)); *ppath = dentry->d_name.name; *ppathlen = dentry->d_name.len; return 0; @@ -1925,7 +1925,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, releases = 0; if (req->r_inode_drop) releases += ceph_encode_inode_release(&p, - req->r_inode ? req->r_inode : req->r_dentry->d_inode, + req->r_inode ? req->r_inode : d_inode(req->r_dentry), mds, req->r_inode_drop, req->r_inode_unless, 0); if (req->r_dentry_drop) releases += ceph_encode_dentry_release(&p, req->r_dentry, @@ -1935,7 +1935,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc, mds, req->r_old_dentry_drop, req->r_old_dentry_unless); if (req->r_old_inode_drop) releases += ceph_encode_inode_release(&p, - req->r_old_dentry->d_inode, + d_inode(req->r_old_dentry), mds, req->r_old_inode_drop, req->r_old_inode_unless, 0); head->num_releases = cpu_to_le16(releases); diff --git a/fs/ceph/super.c b/fs/ceph/super.c index a63997b8bcff..e68591df9942 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -44,7 +44,7 @@ static void ceph_put_super(struct super_block *s) static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct ceph_fs_client *fsc = ceph_inode_to_client(dentry->d_inode); + struct ceph_fs_client *fsc = ceph_inode_to_client(d_inode(dentry)); struct ceph_monmap *monmap = fsc->client->monc.monmap; struct ceph_statfs st; u64 fsid; @@ -976,7 +976,7 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type, if (IS_ERR(res)) goto out_splat; dout("root %p inode %p ino %llx.%llx\n", res, - res->d_inode, ceph_vinop(res->d_inode)); + d_inode(res), ceph_vinop(d_inode(res))); return res; out_splat: diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 5a492caf34cb..e448766ce549 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -776,12 +776,12 @@ ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value, if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) return generic_getxattr(dentry, name, value, size); - return __ceph_getxattr(dentry->d_inode, name, value, size); + return __ceph_getxattr(d_inode(dentry), name, value, size); } ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_vxattr *vxattrs = ceph_inode_vxattrs(inode); u32 vir_namelen = 0; @@ -847,7 +847,7 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name, const char *value, size_t size, int flags) { struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb); - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_mds_request *req; struct ceph_mds_client *mdsc = fsc->mdsc; @@ -901,7 +901,7 @@ out: int __ceph_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ceph_vxattr *vxattr; struct ceph_inode_info *ci = ceph_inode(inode); int issued; @@ -995,7 +995,7 @@ out: int ceph_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - if (ceph_snap(dentry->d_inode) != CEPH_NOSNAP) + if (ceph_snap(d_inode(dentry)) != CEPH_NOSNAP) return -EROFS; if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) @@ -1011,7 +1011,7 @@ static int ceph_send_removexattr(struct dentry *dentry, const char *name) { struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb); struct ceph_mds_client *mdsc = fsc->mdsc; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ceph_mds_request *req; int err; @@ -1032,7 +1032,7 @@ static int ceph_send_removexattr(struct dentry *dentry, const char *name) int __ceph_removexattr(struct dentry *dentry, const char *name) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ceph_vxattr *vxattr; struct ceph_inode_info *ci = ceph_inode(inode); int issued; @@ -1098,7 +1098,7 @@ out: int ceph_removexattr(struct dentry *dentry, const char *name) { - if (ceph_snap(dentry->d_inode) != CEPH_NOSNAP) + if (ceph_snap(d_inode(dentry)) != CEPH_NOSNAP) return -EROFS; if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index b8602f199815..430e0348c99e 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -301,7 +301,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) if (full_path == NULL) goto cdda_exit; - cifs_sb = CIFS_SB(mntpt->d_inode->i_sb); + cifs_sb = CIFS_SB(d_inode(mntpt)->i_sb); tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { mnt = ERR_CAST(tlink); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index eaab4b2a0595..f5089bde3635 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -607,7 +607,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb) p = s = full_path; do { - struct inode *dir = dentry->d_inode; + struct inode *dir = d_inode(dentry); struct dentry *child; if (!dir) { diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index fa13d5e79f64..84650a51c7c4 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1898,7 +1898,7 @@ static void cifs_writev_requeue(struct cifs_writedata *wdata) { int i, rc = 0; - struct inode *inode = wdata->cfile->dentry->d_inode; + struct inode *inode = d_inode(wdata->cfile->dentry); struct TCP_Server_Info *server; unsigned int rest_len; @@ -1981,7 +1981,7 @@ cifs_writev_complete(struct work_struct *work) { struct cifs_writedata *wdata = container_of(work, struct cifs_writedata, work); - struct inode *inode = wdata->cfile->dentry->d_inode; + struct inode *inode = d_inode(wdata->cfile->dentry); int i = 0; if (wdata->result == 0) { diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index b72bc29cba23..338d56936f6a 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -745,13 +745,13 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, goto lookup_out; } - if (direntry->d_inode != NULL) { + if (d_really_is_positive(direntry)) { cifs_dbg(FYI, "non-NULL inode in lookup\n"); } else { cifs_dbg(FYI, "NULL inode in lookup\n"); } cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", - full_path, direntry->d_inode); + full_path, d_inode(direntry)); if (pTcon->unix_ext) { rc = cifs_get_inode_info_unix(&newInode, full_path, @@ -792,7 +792,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags) if (flags & LOOKUP_RCU) return -ECHILD; - if (direntry->d_inode) { + if (d_really_is_positive(direntry)) { if (cifs_revalidate_dentry(direntry)) return 0; else { @@ -803,7 +803,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags) * attributes will have been updated by * cifs_revalidate_dentry(). */ - if (IS_AUTOMOUNT(direntry->d_inode) && + if (IS_AUTOMOUNT(d_inode(direntry)) && !(direntry->d_flags & DCACHE_NEED_AUTOMOUNT)) { spin_lock(&direntry->d_lock); direntry->d_flags |= DCACHE_NEED_AUTOMOUNT; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index ca2bc5406306..cafbf10521d5 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -273,7 +273,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, struct tcon_link *tlink, __u32 oplock) { struct dentry *dentry = file->f_path.dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct cifsInodeInfo *cinode = CIFS_I(inode); struct cifsFileInfo *cfile; struct cifs_fid_locks *fdlocks; @@ -357,7 +357,7 @@ cifsFileInfo_get(struct cifsFileInfo *cifs_file) */ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) { - struct inode *inode = cifs_file->dentry->d_inode; + struct inode *inode = d_inode(cifs_file->dentry); struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink); struct TCP_Server_Info *server = tcon->ses->server; struct cifsInodeInfo *cifsi = CIFS_I(inode); @@ -386,7 +386,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) if (list_empty(&cifsi->openFileList)) { cifs_dbg(FYI, "closing last open instance for inode %p\n", - cifs_file->dentry->d_inode); + d_inode(cifs_file->dentry)); /* * In strict cache mode we need invalidate mapping on the last * close because it may cause a error when we open this file @@ -572,7 +572,7 @@ static int cifs_relock_file(struct cifsFileInfo *cfile) { struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); - struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); + struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); int rc = 0; @@ -620,7 +620,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) return rc; } - inode = cfile->dentry->d_inode; + inode = d_inode(cfile->dentry); cifs_sb = CIFS_SB(inode->i_sb); tcon = tlink_tcon(cfile->tlink); server = tcon->ses->server; @@ -874,7 +874,7 @@ cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, { bool rc = false; struct cifs_fid_locks *cur; - struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); + struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); list_for_each_entry(cur, &cinode->llist, llist) { rc = cifs_find_fid_lock_conflict(cur, offset, length, type, @@ -899,7 +899,7 @@ cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length, { int rc = 0; struct cifsLockInfo *conf_lock; - struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); + struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; bool exist; @@ -927,7 +927,7 @@ cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length, static void cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock) { - struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); + struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); down_write(&cinode->lock_sem); list_add_tail(&lock->llist, &cfile->llist->locks); up_write(&cinode->lock_sem); @@ -944,7 +944,7 @@ cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock, bool wait) { struct cifsLockInfo *conf_lock; - struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); + struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); bool exist; int rc = 0; @@ -1125,7 +1125,7 @@ struct lock_to_push { static int cifs_push_posix_locks(struct cifsFileInfo *cfile) { - struct inode *inode = cfile->dentry->d_inode; + struct inode *inode = d_inode(cfile->dentry); struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); struct file_lock *flock; struct file_lock_context *flctx = inode->i_flctx; @@ -1214,7 +1214,7 @@ static int cifs_push_locks(struct cifsFileInfo *cfile) { struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); - struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); + struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); int rc = 0; @@ -1382,7 +1382,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, unsigned int max_num, num, max_buf; LOCKING_ANDX_RANGE *buf, *cur; struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); - struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); + struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); struct cifsLockInfo *li, *tmp; __u64 length = 1 + flock->fl_end - flock->fl_start; struct list_head tmp_llist; @@ -1488,7 +1488,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); struct TCP_Server_Info *server = tcon->ses->server; - struct inode *inode = cfile->dentry->d_inode; + struct inode *inode = d_inode(cfile->dentry); if (posix_lck) { int posix_lock_type; @@ -1643,7 +1643,7 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data, struct TCP_Server_Info *server; unsigned int xid; struct dentry *dentry = open_file->dentry; - struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode); + struct cifsInodeInfo *cifsi = CIFS_I(d_inode(dentry)); struct cifs_io_parms io_parms; cifs_sb = CIFS_SB(dentry->d_sb); @@ -1676,7 +1676,7 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data, break; } - len = min(server->ops->wp_retry_size(dentry->d_inode), + len = min(server->ops->wp_retry_size(d_inode(dentry)), (unsigned int)write_size - total_written); /* iov[0] is reserved for smb header */ iov[1].iov_base = (char *)write_data + total_written; @@ -1696,9 +1696,9 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data, return rc; } } else { - spin_lock(&dentry->d_inode->i_lock); + spin_lock(&d_inode(dentry)->i_lock); cifs_update_eof(cifsi, *offset, bytes_written); - spin_unlock(&dentry->d_inode->i_lock); + spin_unlock(&d_inode(dentry)->i_lock); *offset += bytes_written; } } @@ -1706,12 +1706,12 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data, cifs_stats_bytes_written(tcon, total_written); if (total_written > 0) { - spin_lock(&dentry->d_inode->i_lock); - if (*offset > dentry->d_inode->i_size) - i_size_write(dentry->d_inode, *offset); - spin_unlock(&dentry->d_inode->i_lock); + spin_lock(&d_inode(dentry)->i_lock); + if (*offset > d_inode(dentry)->i_size) + i_size_write(d_inode(dentry), *offset); + spin_unlock(&d_inode(dentry)->i_lock); } - mark_inode_dirty_sync(dentry->d_inode); + mark_inode_dirty_sync(d_inode(dentry)); free_xid(xid); return total_written; } @@ -2406,7 +2406,7 @@ cifs_uncached_writev_complete(struct work_struct *work) { struct cifs_writedata *wdata = container_of(work, struct cifs_writedata, work); - struct inode *inode = wdata->cfile->dentry->d_inode; + struct inode *inode = d_inode(wdata->cfile->dentry); struct cifsInodeInfo *cifsi = CIFS_I(inode); spin_lock(&inode->i_lock); @@ -3794,7 +3794,7 @@ void cifs_oplock_break(struct work_struct *work) { struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, oplock_break); - struct inode *inode = cfile->dentry->d_inode; + struct inode *inode = d_inode(cfile->dentry); struct cifsInodeInfo *cinode = CIFS_I(inode); struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); struct TCP_Server_Info *server = tcon->ses->server; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 3e126d7bb2ea..55b58112d122 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1067,7 +1067,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, int rc; struct cifs_fid fid; struct cifs_open_parms oparms; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink; @@ -1196,7 +1196,7 @@ cifs_drop_nlink(struct inode *inode) } /* - * If dentry->d_inode is null (usually meaning the cached dentry + * If d_inode(dentry) is null (usually meaning the cached dentry * is a negative dentry) then we would attempt a standard SMB delete, but * if that fails we can not attempt the fall back mechanisms on EACCESS * but will return the EACCESS to the caller. Note that the VFS does not call @@ -1207,7 +1207,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) int rc = 0; unsigned int xid; char *full_path = NULL; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct cifsInodeInfo *cifs_inode; struct super_block *sb = dir->i_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); @@ -1551,13 +1551,13 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) cifs_put_tlink(tlink); if (!rc) { - spin_lock(&direntry->d_inode->i_lock); - i_size_write(direntry->d_inode, 0); - clear_nlink(direntry->d_inode); - spin_unlock(&direntry->d_inode->i_lock); + spin_lock(&d_inode(direntry)->i_lock); + i_size_write(d_inode(direntry), 0); + clear_nlink(d_inode(direntry)); + spin_unlock(&d_inode(direntry)->i_lock); } - cifsInode = CIFS_I(direntry->d_inode); + cifsInode = CIFS_I(d_inode(direntry)); /* force revalidate to go get info when needed */ cifsInode->time = 0; @@ -1568,7 +1568,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) */ cifsInode->time = 0; - direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = + d_inode(direntry)->i_ctime = inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb); rmdir_exit: @@ -1727,7 +1727,7 @@ cifs_rename2(struct inode *source_dir, struct dentry *source_dentry, unlink_target: /* Try unlinking the target dentry if it's not negative */ - if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) { + if (d_really_is_positive(target_dentry) && (rc == -EACCES || rc == -EEXIST)) { if (d_is_dir(target_dentry)) tmprc = cifs_rmdir(target_dir, target_dentry); else @@ -1867,7 +1867,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry) { unsigned int xid; int rc = 0; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct super_block *sb = dentry->d_sb; char *full_path = NULL; @@ -1919,7 +1919,7 @@ int cifs_revalidate_file(struct file *filp) int cifs_revalidate_dentry(struct dentry *dentry) { int rc; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); rc = cifs_revalidate_dentry_attr(dentry); if (rc) @@ -1933,7 +1933,7 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, { struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int rc; /* @@ -2110,7 +2110,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) int rc; unsigned int xid; char *full_path = NULL; - struct inode *inode = direntry->d_inode; + struct inode *inode = d_inode(direntry); struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink; @@ -2251,7 +2251,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) unsigned int xid; kuid_t uid = INVALID_UID; kgid_t gid = INVALID_GID; - struct inode *inode = direntry->d_inode; + struct inode *inode = d_inode(direntry); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifsInodeInfo *cifsInode = CIFS_I(inode); char *full_path = NULL; @@ -2409,7 +2409,7 @@ cifs_setattr_exit: int cifs_setattr(struct dentry *direntry, struct iattr *attrs) { - struct inode *inode = direntry->d_inode; + struct inode *inode = d_inode(direntry); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb); diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 2ec6037f61c7..252e672d5604 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -586,12 +586,12 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, * if source file is cached (oplocked) revalidate will not go to server * until the file is closed or oplock broken so update nlinks locally */ - if (old_file->d_inode) { - cifsInode = CIFS_I(old_file->d_inode); + if (d_really_is_positive(old_file)) { + cifsInode = CIFS_I(d_inode(old_file)); if (rc == 0) { - spin_lock(&old_file->d_inode->i_lock); - inc_nlink(old_file->d_inode); - spin_unlock(&old_file->d_inode->i_lock); + spin_lock(&d_inode(old_file)->i_lock); + inc_nlink(d_inode(old_file)); + spin_unlock(&d_inode(old_file)->i_lock); /* * parent dir timestamps will update from srv within a @@ -629,7 +629,7 @@ cifs_hl_exit: void * cifs_follow_link(struct dentry *direntry, struct nameidata *nd) { - struct inode *inode = direntry->d_inode; + struct inode *inode = d_inode(direntry); int rc = -ENOMEM; unsigned int xid; char *full_path = NULL; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 337946355b29..8442b8b8e0be 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -473,7 +473,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) continue; cifs_dbg(FYI, "file id match, oplock break\n"); - pCifsInode = CIFS_I(netfile->dentry->d_inode); + pCifsInode = CIFS_I(d_inode(netfile->dentry)); set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &pCifsInode->flags); diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index c295338e0a98..b4a47237486b 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -78,7 +78,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, { struct dentry *dentry, *alias; struct inode *inode; - struct super_block *sb = parent->d_inode->i_sb; + struct super_block *sb = d_inode(parent)->i_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); cifs_dbg(FYI, "%s: for %s\n", __func__, name->name); @@ -88,7 +88,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, return; if (dentry) { - inode = dentry->d_inode; + inode = d_inode(dentry); if (inode) { /* * If we're generating inode numbers, then we don't diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index d2979036a4c7..7bfdd6066276 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -722,7 +722,7 @@ cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms, static void cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) { - struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); + struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); cfile->fid.netfid = fid->netfid; cifs_set_oplock_level(cinode, oplock); cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode); diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index 7198eac5dddd..2ab297dae5a7 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c @@ -95,7 +95,7 @@ smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, unsigned int max_num, num = 0, max_buf; struct smb2_lock_element *buf, *cur; struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); - struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); + struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); struct cifsLockInfo *li, *tmp; __u64 length = 1 + flock->fl_end - flock->fl_start; struct list_head tmp_llist; @@ -231,7 +231,7 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile) unsigned int xid; unsigned int max_num, max_buf; struct smb2_lock_element *buf; - struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); + struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); struct cifs_fid_locks *fdlocks; xid = get_xid(); diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 22dfdf17d065..1c5907019045 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -453,7 +453,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, list_for_each(tmp, &tcon->openFileList) { cfile = list_entry(tmp, struct cifsFileInfo, tlist); - cinode = CIFS_I(cfile->dentry->d_inode); + cinode = CIFS_I(d_inode(cfile->dentry)); if (memcmp(cinode->lease_key, rsp->LeaseKey, SMB2_LEASE_KEY_SIZE)) @@ -590,7 +590,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) continue; cifs_dbg(FYI, "file id match, oplock break\n"); - cinode = CIFS_I(cfile->dentry->d_inode); + cinode = CIFS_I(d_inode(cfile->dentry)); if (!CIFS_CACHE_WRITE(cinode) && rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index eab05e1aa587..54daee5ad4c1 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -524,7 +524,7 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon) static void smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) { - struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); + struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; cfile->fid.persistent_fid = fid->persistent_fid; @@ -793,7 +793,7 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon, * If extending file more than one page make sparse. Many Linux fs * make files sparse by default when extending via ftruncate */ - inode = cfile->dentry->d_inode; + inode = d_inode(cfile->dentry); if (!set_alloc && (size > inode->i_size + 8192)) { __u8 set_sparse = 1; @@ -1032,7 +1032,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, xid = get_xid(); - inode = cfile->dentry->d_inode; + inode = d_inode(cfile->dentry); cifsi = CIFS_I(inode); /* if file not oplocked can't be sure whether asking to extend size */ @@ -1083,7 +1083,7 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, xid = get_xid(); - inode = cfile->dentry->d_inode; + inode = d_inode(cfile->dentry); cifsi = CIFS_I(inode); /* Need to make file sparse, if not already, before freeing range. */ @@ -1115,7 +1115,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, xid = get_xid(); - inode = cfile->dentry->d_inode; + inode = d_inode(cfile->dentry); cifsi = CIFS_I(inode); /* if file not oplocked can't be sure whether asking to extend size */ diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 72a4d10653d6..ff9e1f8b16a4 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -50,9 +50,9 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) if (direntry == NULL) return -EIO; - if (direntry->d_inode == NULL) + if (d_really_is_negative(direntry)) return -EIO; - sb = direntry->d_inode->i_sb; + sb = d_inode(direntry)->i_sb; if (sb == NULL) return -EIO; @@ -111,9 +111,9 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, if (direntry == NULL) return -EIO; - if (direntry->d_inode == NULL) + if (d_really_is_negative(direntry)) return -EIO; - sb = direntry->d_inode->i_sb; + sb = d_inode(direntry)->i_sb; if (sb == NULL) return -EIO; @@ -177,12 +177,12 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, memcpy(pacl, ea_value, value_size); if (pTcon->ses->server->ops->set_acl) rc = pTcon->ses->server->ops->set_acl(pacl, - value_size, direntry->d_inode, + value_size, d_inode(direntry), full_path, CIFS_ACL_DACL); else rc = -EOPNOTSUPP; if (rc == 0) /* force revalidate of the inode */ - CIFS_I(direntry->d_inode)->time = 0; + CIFS_I(d_inode(direntry))->time = 0; kfree(pacl); } #else @@ -246,9 +246,9 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, if (direntry == NULL) return -EIO; - if (direntry->d_inode == NULL) + if (d_really_is_negative(direntry)) return -EIO; - sb = direntry->d_inode->i_sb; + sb = d_inode(direntry)->i_sb; if (sb == NULL) return -EIO; @@ -324,7 +324,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, goto get_ea_exit; /* rc already EOPNOTSUPP */ pacl = pTcon->ses->server->ops->get_acl(cifs_sb, - direntry->d_inode, full_path, &acllen); + d_inode(direntry), full_path, &acllen); if (IS_ERR(pacl)) { rc = PTR_ERR(pacl); cifs_dbg(VFS, "%s: error %zd getting sec desc\n", @@ -382,9 +382,9 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) if (direntry == NULL) return -EIO; - if (direntry->d_inode == NULL) + if (d_really_is_negative(direntry)) return -EIO; - sb = direntry->d_inode->i_sb; + sb = d_inode(direntry)->i_sb; if (sb == NULL) return -EIO; diff --git a/fs/coda/cache.c b/fs/coda/cache.c index 46ee6f238985..5bb630a769e0 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c @@ -94,8 +94,8 @@ static void coda_flag_children(struct dentry *parent, int flag) spin_lock(&parent->d_lock); list_for_each_entry(de, &parent->d_subdirs, d_child) { /* don't know what to do with negative dentries */ - if (de->d_inode ) - coda_flag_inode(de->d_inode, flag); + if (d_inode(de) ) + coda_flag_inode(d_inode(de), flag); } spin_unlock(&parent->d_lock); return; diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 60cb88c1dd2b..fda9f4311212 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -201,7 +201,7 @@ err_out: static int coda_link(struct dentry *source_de, struct inode *dir_inode, struct dentry *de) { - struct inode *inode = source_de->d_inode; + struct inode *inode = d_inode(source_de); const char * name = de->d_name.name; int len = de->d_name.len; int error; @@ -266,7 +266,7 @@ static int coda_unlink(struct inode *dir, struct dentry *de) return error; coda_dir_update_mtime(dir); - drop_nlink(de->d_inode); + drop_nlink(d_inode(de)); return 0; } @@ -279,8 +279,8 @@ static int coda_rmdir(struct inode *dir, struct dentry *de) error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len); if (!error) { /* VFS may delete the child */ - if (de->d_inode) - clear_nlink(de->d_inode); + if (d_really_is_positive(de)) + clear_nlink(d_inode(de)); /* fix the link count of the parent */ coda_dir_drop_nlink(dir); @@ -303,14 +303,14 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, coda_i2f(new_dir), old_length, new_length, (const char *) old_name, (const char *)new_name); if (!error) { - if (new_dentry->d_inode) { + if (d_really_is_positive(new_dentry)) { if (d_is_dir(new_dentry)) { coda_dir_drop_nlink(old_dir); coda_dir_inc_nlink(new_dir); } coda_dir_update_mtime(old_dir); coda_dir_update_mtime(new_dir); - coda_flag_inode(new_dentry->d_inode, C_VATTR); + coda_flag_inode(d_inode(new_dentry), C_VATTR); } else { coda_flag_inode(old_dir, C_VATTR); coda_flag_inode(new_dir, C_VATTR); @@ -449,13 +449,13 @@ static int coda_dentry_revalidate(struct dentry *de, unsigned int flags) if (flags & LOOKUP_RCU) return -ECHILD; - inode = de->d_inode; + inode = d_inode(de); if (!inode || is_root_inode(inode)) goto out; if (is_bad_inode(inode)) goto bad; - cii = ITOC(de->d_inode); + cii = ITOC(d_inode(de)); if (!(cii->c_flags & (C_PURGE | C_FLUSH))) goto out; @@ -487,11 +487,11 @@ static int coda_dentry_delete(const struct dentry * dentry) { int flags; - if (!dentry->d_inode) + if (d_really_is_negative(dentry)) return 0; - flags = (ITOC(dentry->d_inode)->c_flags) & C_PURGE; - if (is_bad_inode(dentry->d_inode) || flags) { + flags = (ITOC(d_inode(dentry))->c_flags) & C_PURGE; + if (is_bad_inode(d_inode(dentry)) || flags) { return 1; } return 0; diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 82ec68b59208..cac1390b87a3 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -257,15 +257,15 @@ static void coda_evict_inode(struct inode *inode) int coda_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - int err = coda_revalidate_inode(dentry->d_inode); + int err = coda_revalidate_inode(d_inode(dentry)); if (!err) - generic_fillattr(dentry->d_inode, stat); + generic_fillattr(d_inode(dentry), stat); return err; } int coda_setattr(struct dentry *de, struct iattr *iattr) { - struct inode *inode = de->d_inode; + struct inode *inode = d_inode(de); struct coda_vattr vattr; int error; diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c index 4326d172fc27..f36a4040afb8 100644 --- a/fs/coda/pioctl.c +++ b/fs/coda/pioctl.c @@ -72,7 +72,7 @@ static long coda_pioctl(struct file *filp, unsigned int cmd, if (error) return error; - target_inode = path.dentry->d_inode; + target_inode = d_inode(path.dentry); /* return if it is not a Coda inode */ if (target_inode->i_sb != inode->i_sb) { diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 5bb6e27298a4..9b1ffaa0572e 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -820,8 +820,8 @@ int coda_downcall(struct venus_comm *vcp, int opcode, union outputArgs *out) case CODA_FLUSH: coda_cache_clear_all(sb); shrink_dcache_sb(sb); - if (sb->s_root->d_inode) - coda_flag_inode(sb->s_root->d_inode, C_FLUSH); + if (d_really_is_positive(sb->s_root)) + coda_flag_inode(d_inode(sb->s_root), C_FLUSH); break; case CODA_PURGEUSER: diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index acb3d63bc9dc..c81ce7f200a6 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -289,7 +289,7 @@ static int configfs_create_dir(struct config_item *item, struct dentry *dentry) configfs_set_dir_dirent_depth(p->d_fsdata, dentry->d_fsdata); error = configfs_create(dentry, mode, init_dir); if (!error) { - inc_nlink(p->d_inode); + inc_nlink(d_inode(p)); item->ci_dentry = dentry; } else { struct configfs_dirent *sd = dentry->d_fsdata; @@ -375,8 +375,8 @@ static void remove_dir(struct dentry * d) list_del_init(&sd->s_sibling); spin_unlock(&configfs_dirent_lock); configfs_put(sd); - if (d->d_inode) - simple_rmdir(parent->d_inode,d); + if (d_really_is_positive(d)) + simple_rmdir(d_inode(parent),d); pr_debug(" o %pd removing done (%d)\n", d, d_count(d)); @@ -513,7 +513,7 @@ static int configfs_detach_prep(struct dentry *dentry, struct mutex **wait_mutex /* Abort if racing with mkdir() */ if (sd->s_type & CONFIGFS_USET_IN_MKDIR) { if (wait_mutex) - *wait_mutex = &sd->s_dentry->d_inode->i_mutex; + *wait_mutex = &d_inode(sd->s_dentry)->i_mutex; return -EAGAIN; } @@ -624,13 +624,13 @@ static void detach_groups(struct config_group *group) child = sd->s_dentry; - mutex_lock(&child->d_inode->i_mutex); + mutex_lock(&d_inode(child)->i_mutex); configfs_detach_group(sd->s_element); - child->d_inode->i_flags |= S_DEAD; + d_inode(child)->i_flags |= S_DEAD; dont_mount(child); - mutex_unlock(&child->d_inode->i_mutex); + mutex_unlock(&d_inode(child)->i_mutex); d_delete(child); dput(child); @@ -672,7 +672,7 @@ static int create_default_group(struct config_group *parent_group, sd = child->d_fsdata; sd->s_type |= CONFIGFS_USET_DEFAULT; } else { - BUG_ON(child->d_inode); + BUG_ON(d_inode(child)); d_drop(child); dput(child); } @@ -818,11 +818,11 @@ static int configfs_attach_item(struct config_item *parent_item, * the VFS may already have hit and used them. Thus, * we must lock them as rmdir() would. */ - mutex_lock(&dentry->d_inode->i_mutex); + mutex_lock(&d_inode(dentry)->i_mutex); configfs_remove_dir(item); - dentry->d_inode->i_flags |= S_DEAD; + d_inode(dentry)->i_flags |= S_DEAD; dont_mount(dentry); - mutex_unlock(&dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(dentry)->i_mutex); d_delete(dentry); } } @@ -858,16 +858,16 @@ static int configfs_attach_group(struct config_item *parent_item, * We must also lock the inode to remove it safely in case of * error, as rmdir() would. */ - mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); + mutex_lock_nested(&d_inode(dentry)->i_mutex, I_MUTEX_CHILD); configfs_adjust_dir_dirent_depth_before_populate(sd); ret = populate_groups(to_config_group(item)); if (ret) { configfs_detach_item(item); - dentry->d_inode->i_flags |= S_DEAD; + d_inode(dentry)->i_flags |= S_DEAD; dont_mount(dentry); } configfs_adjust_dir_dirent_depth_after_populate(sd); - mutex_unlock(&dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(dentry)->i_mutex); if (ret) d_delete(dentry); } @@ -1075,7 +1075,7 @@ int configfs_depend_item(struct configfs_subsystem *subsys, * subsystem is really registered, and so we need to lock out * configfs_[un]register_subsystem(). */ - mutex_lock(&root->d_inode->i_mutex); + mutex_lock(&d_inode(root)->i_mutex); root_sd = root->d_fsdata; @@ -1111,7 +1111,7 @@ int configfs_depend_item(struct configfs_subsystem *subsys, out_unlock_dirent_lock: spin_unlock(&configfs_dirent_lock); out_unlock_fs: - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&d_inode(root)->i_mutex); /* * If we succeeded, the fs is pinned via other methods. If not, @@ -1453,11 +1453,11 @@ int configfs_rename_dir(struct config_item * item, const char *new_name) down_write(&configfs_rename_sem); parent = item->parent->dentry; - mutex_lock(&parent->d_inode->i_mutex); + mutex_lock(&d_inode(parent)->i_mutex); new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); if (!IS_ERR(new_dentry)) { - if (!new_dentry->d_inode) { + if (d_really_is_negative(new_dentry)) { error = config_item_set_name(item, "%s", new_name); if (!error) { d_add(new_dentry, NULL); @@ -1469,7 +1469,7 @@ int configfs_rename_dir(struct config_item * item, const char *new_name) error = -EEXIST; dput(new_dentry); } - mutex_unlock(&parent->d_inode->i_mutex); + mutex_unlock(&d_inode(parent)->i_mutex); up_write(&configfs_rename_sem); return error; @@ -1482,7 +1482,7 @@ static int configfs_dir_open(struct inode *inode, struct file *file) struct configfs_dirent * parent_sd = dentry->d_fsdata; int err; - mutex_lock(&dentry->d_inode->i_mutex); + mutex_lock(&d_inode(dentry)->i_mutex); /* * Fake invisibility if dir belongs to a group/default groups hierarchy * being attached @@ -1495,7 +1495,7 @@ static int configfs_dir_open(struct inode *inode, struct file *file) else err = 0; } - mutex_unlock(&dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(dentry)->i_mutex); return err; } @@ -1505,11 +1505,11 @@ static int configfs_dir_close(struct inode *inode, struct file *file) struct dentry * dentry = file->f_path.dentry; struct configfs_dirent * cursor = file->private_data; - mutex_lock(&dentry->d_inode->i_mutex); + mutex_lock(&d_inode(dentry)->i_mutex); spin_lock(&configfs_dirent_lock); list_del_init(&cursor->s_sibling); spin_unlock(&configfs_dirent_lock); - mutex_unlock(&dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(dentry)->i_mutex); release_configfs_dirent(cursor); @@ -1567,7 +1567,7 @@ static int configfs_readdir(struct file *file, struct dir_context *ctx) spin_lock(&configfs_dirent_lock); dentry = next->s_dentry; if (dentry) - inode = dentry->d_inode; + inode = d_inode(dentry); if (inode) ino = inode->i_ino; spin_unlock(&configfs_dirent_lock); @@ -1590,7 +1590,7 @@ static loff_t configfs_dir_lseek(struct file *file, loff_t offset, int whence) { struct dentry * dentry = file->f_path.dentry; - mutex_lock(&dentry->d_inode->i_mutex); + mutex_lock(&d_inode(dentry)->i_mutex); switch (whence) { case 1: offset += file->f_pos; @@ -1598,7 +1598,7 @@ static loff_t configfs_dir_lseek(struct file *file, loff_t offset, int whence) if (offset >= 0) break; default: - mutex_unlock(&dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(dentry)->i_mutex); return -EINVAL; } if (offset != file->f_pos) { @@ -1624,7 +1624,7 @@ static loff_t configfs_dir_lseek(struct file *file, loff_t offset, int whence) spin_unlock(&configfs_dirent_lock); } } - mutex_unlock(&dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(dentry)->i_mutex); return offset; } @@ -1654,7 +1654,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) sd = root->d_fsdata; link_group(to_config_group(sd->s_element), group); - mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&d_inode(root)->i_mutex, I_MUTEX_PARENT); err = -ENOMEM; dentry = d_alloc_name(root, group->cg_item.ci_name); @@ -1664,7 +1664,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) err = configfs_attach_group(sd->s_element, &group->cg_item, dentry); if (err) { - BUG_ON(dentry->d_inode); + BUG_ON(d_inode(dentry)); d_drop(dentry); dput(dentry); } else { @@ -1674,7 +1674,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) } } - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&d_inode(root)->i_mutex); if (err) { unlink_group(group); @@ -1695,9 +1695,9 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys) return; } - mutex_lock_nested(&root->d_inode->i_mutex, + mutex_lock_nested(&d_inode(root)->i_mutex, I_MUTEX_PARENT); - mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); + mutex_lock_nested(&d_inode(dentry)->i_mutex, I_MUTEX_CHILD); mutex_lock(&configfs_symlink_mutex); spin_lock(&configfs_dirent_lock); if (configfs_detach_prep(dentry, NULL)) { @@ -1706,13 +1706,13 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys) spin_unlock(&configfs_dirent_lock); mutex_unlock(&configfs_symlink_mutex); configfs_detach_group(&group->cg_item); - dentry->d_inode->i_flags |= S_DEAD; + d_inode(dentry)->i_flags |= S_DEAD; dont_mount(dentry); - mutex_unlock(&dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(dentry)->i_mutex); d_delete(dentry); - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&d_inode(root)->i_mutex); dput(dentry); diff --git a/fs/configfs/file.c b/fs/configfs/file.c index 56d2cdc9ae0a..403269ffcdf3 100644 --- a/fs/configfs/file.c +++ b/fs/configfs/file.c @@ -326,10 +326,10 @@ int configfs_create_file(struct config_item * item, const struct configfs_attrib umode_t mode = (attr->ca_mode & S_IALLUGO) | S_IFREG; int error = 0; - mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_NORMAL); + mutex_lock_nested(&d_inode(dir)->i_mutex, I_MUTEX_NORMAL); error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode, CONFIGFS_ITEM_ATTR); - mutex_unlock(&dir->d_inode->i_mutex); + mutex_unlock(&d_inode(dir)->i_mutex); return error; } diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 5423a6a6ecc8..8d89f5fd0331 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -56,7 +56,7 @@ static const struct inode_operations configfs_inode_operations ={ int configfs_setattr(struct dentry * dentry, struct iattr * iattr) { - struct inode * inode = dentry->d_inode; + struct inode * inode = d_inode(dentry); struct configfs_dirent * sd = dentry->d_fsdata; struct iattr * sd_iattr; unsigned int ia_valid = iattr->ia_valid; @@ -186,7 +186,7 @@ int configfs_create(struct dentry * dentry, umode_t mode, void (*init)(struct in if (!dentry) return -ENOENT; - if (dentry->d_inode) + if (d_really_is_positive(dentry)) return -EEXIST; sd = dentry->d_fsdata; @@ -194,7 +194,7 @@ int configfs_create(struct dentry * dentry, umode_t mode, void (*init)(struct in if (!inode) return -ENOMEM; - p_inode = dentry->d_parent->d_inode; + p_inode = d_inode(dentry->d_parent); p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; configfs_set_inode_lock_class(sd, inode); @@ -236,11 +236,11 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent) if (dentry) { spin_lock(&dentry->d_lock); - if (!d_unhashed(dentry) && dentry->d_inode) { + if (!d_unhashed(dentry) && d_really_is_positive(dentry)) { dget_dlock(dentry); __d_drop(dentry); spin_unlock(&dentry->d_lock); - simple_unlink(parent->d_inode, dentry); + simple_unlink(d_inode(parent), dentry); } else spin_unlock(&dentry->d_lock); } @@ -251,11 +251,11 @@ void configfs_hash_and_remove(struct dentry * dir, const char * name) struct configfs_dirent * sd; struct configfs_dirent * parent_sd = dir->d_fsdata; - if (dir->d_inode == NULL) + if (d_really_is_negative(dir)) /* no inode means this hasn't been made visible yet */ return; - mutex_lock(&dir->d_inode->i_mutex); + mutex_lock(&d_inode(dir)->i_mutex); list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { if (!sd->s_element) continue; @@ -268,5 +268,5 @@ void configfs_hash_and_remove(struct dentry * dir, const char * name) break; } } - mutex_unlock(&dir->d_inode->i_mutex); + mutex_unlock(&d_inode(dir)->i_mutex); } diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 517e64938438..830a7e76f5c6 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -45,7 +45,7 @@ const struct file_operations debugfs_file_operations = { static void *debugfs_follow_link(struct dentry *dentry, struct nameidata *nd) { - nd_set_link(nd, dentry->d_inode->i_private); + nd_set_link(nd, d_inode(dentry)->i_private); return NULL; } diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 26856ecdea5e..61dfe45fdb68 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -46,7 +46,7 @@ static struct inode *debugfs_get_inode(struct super_block *sb) static inline int debugfs_positive(struct dentry *dentry) { - return dentry->d_inode && !d_unhashed(dentry); + return d_really_is_positive(dentry) && !d_unhashed(dentry); } struct debugfs_mount_opts { @@ -124,7 +124,7 @@ static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts) static int debugfs_apply_options(struct super_block *sb) { struct debugfs_fs_info *fsi = sb->s_fs_info; - struct inode *inode = sb->s_root->d_inode; + struct inode *inode = d_inode(sb->s_root); struct debugfs_mount_opts *opts = &fsi->mount_opts; inode->i_mode &= ~S_IALLUGO; @@ -188,7 +188,7 @@ static struct vfsmount *debugfs_automount(struct path *path) { struct vfsmount *(*f)(void *); f = (struct vfsmount *(*)(void *))path->dentry->d_fsdata; - return f(path->dentry->d_inode->i_private); + return f(d_inode(path->dentry)->i_private); } static const struct dentry_operations debugfs_dops = { @@ -267,20 +267,20 @@ static struct dentry *start_creating(const char *name, struct dentry *parent) if (!parent) parent = debugfs_mount->mnt_root; - mutex_lock(&parent->d_inode->i_mutex); + mutex_lock(&d_inode(parent)->i_mutex); dentry = lookup_one_len(name, parent, strlen(name)); - if (!IS_ERR(dentry) && dentry->d_inode) { + if (!IS_ERR(dentry) && d_really_is_positive(dentry)) { dput(dentry); dentry = ERR_PTR(-EEXIST); } if (IS_ERR(dentry)) - mutex_unlock(&parent->d_inode->i_mutex); + mutex_unlock(&d_inode(parent)->i_mutex); return dentry; } static struct dentry *failed_creating(struct dentry *dentry) { - mutex_unlock(&dentry->d_parent->d_inode->i_mutex); + mutex_unlock(&d_inode(dentry->d_parent)->i_mutex); dput(dentry); simple_release_fs(&debugfs_mount, &debugfs_mount_count); return NULL; @@ -288,7 +288,7 @@ static struct dentry *failed_creating(struct dentry *dentry) static struct dentry *end_creating(struct dentry *dentry) { - mutex_unlock(&dentry->d_parent->d_inode->i_mutex); + mutex_unlock(&d_inode(dentry->d_parent)->i_mutex); return dentry; } @@ -341,7 +341,7 @@ struct dentry *debugfs_create_file(const char *name, umode_t mode, inode->i_fop = fops ? fops : &debugfs_file_operations; inode->i_private = data; d_instantiate(dentry, inode); - fsnotify_create(dentry->d_parent->d_inode, dentry); + fsnotify_create(d_inode(dentry->d_parent), dentry); return end_creating(dentry); } EXPORT_SYMBOL_GPL(debugfs_create_file); @@ -381,7 +381,7 @@ struct dentry *debugfs_create_file_size(const char *name, umode_t mode, struct dentry *de = debugfs_create_file(name, mode, parent, data, fops); if (de) - de->d_inode->i_size = file_size; + d_inode(de)->i_size = file_size; return de; } EXPORT_SYMBOL_GPL(debugfs_create_file_size); @@ -423,8 +423,8 @@ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent) /* directory inodes start off with i_nlink == 2 (for "." entry) */ inc_nlink(inode); d_instantiate(dentry, inode); - inc_nlink(dentry->d_parent->d_inode); - fsnotify_mkdir(dentry->d_parent->d_inode, dentry); + inc_nlink(d_inode(dentry->d_parent)); + fsnotify_mkdir(d_inode(dentry->d_parent), dentry); return end_creating(dentry); } EXPORT_SYMBOL_GPL(debugfs_create_dir); @@ -522,9 +522,9 @@ static int __debugfs_remove(struct dentry *dentry, struct dentry *parent) if (debugfs_positive(dentry)) { dget(dentry); if (d_is_dir(dentry)) - ret = simple_rmdir(parent->d_inode, dentry); + ret = simple_rmdir(d_inode(parent), dentry); else - simple_unlink(parent->d_inode, dentry); + simple_unlink(d_inode(parent), dentry); if (!ret) d_delete(dentry); dput(dentry); @@ -554,12 +554,12 @@ void debugfs_remove(struct dentry *dentry) return; parent = dentry->d_parent; - if (!parent || !parent->d_inode) + if (!parent || d_really_is_negative(parent)) return; - mutex_lock(&parent->d_inode->i_mutex); + mutex_lock(&d_inode(parent)->i_mutex); ret = __debugfs_remove(dentry, parent); - mutex_unlock(&parent->d_inode->i_mutex); + mutex_unlock(&d_inode(parent)->i_mutex); if (!ret) simple_release_fs(&debugfs_mount, &debugfs_mount_count); } @@ -585,12 +585,12 @@ void debugfs_remove_recursive(struct dentry *dentry) return; parent = dentry->d_parent; - if (!parent || !parent->d_inode) + if (!parent || d_really_is_negative(parent)) return; parent = dentry; down: - mutex_lock(&parent->d_inode->i_mutex); + mutex_lock(&d_inode(parent)->i_mutex); loop: /* * The parent->d_subdirs is protected by the d_lock. Outside that @@ -605,7 +605,7 @@ void debugfs_remove_recursive(struct dentry *dentry) /* perhaps simple_empty(child) makes more sense */ if (!list_empty(&child->d_subdirs)) { spin_unlock(&parent->d_lock); - mutex_unlock(&parent->d_inode->i_mutex); + mutex_unlock(&d_inode(parent)->i_mutex); parent = child; goto down; } @@ -626,10 +626,10 @@ void debugfs_remove_recursive(struct dentry *dentry) } spin_unlock(&parent->d_lock); - mutex_unlock(&parent->d_inode->i_mutex); + mutex_unlock(&d_inode(parent)->i_mutex); child = parent; parent = parent->d_parent; - mutex_lock(&parent->d_inode->i_mutex); + mutex_lock(&d_inode(parent)->i_mutex); if (child != dentry) /* go up */ @@ -637,7 +637,7 @@ void debugfs_remove_recursive(struct dentry *dentry) if (!__debugfs_remove(child, parent)) simple_release_fs(&debugfs_mount, &debugfs_mount_count); - mutex_unlock(&parent->d_inode->i_mutex); + mutex_unlock(&d_inode(parent)->i_mutex); } EXPORT_SYMBOL_GPL(debugfs_remove_recursive); @@ -669,27 +669,27 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, trap = lock_rename(new_dir, old_dir); /* Source or destination directories don't exist? */ - if (!old_dir->d_inode || !new_dir->d_inode) + if (d_really_is_negative(old_dir) || d_really_is_negative(new_dir)) goto exit; /* Source does not exist, cyclic rename, or mountpoint? */ - if (!old_dentry->d_inode || old_dentry == trap || + if (d_really_is_negative(old_dentry) || old_dentry == trap || d_mountpoint(old_dentry)) goto exit; dentry = lookup_one_len(new_name, new_dir, strlen(new_name)); /* Lookup failed, cyclic rename or target exists? */ - if (IS_ERR(dentry) || dentry == trap || dentry->d_inode) + if (IS_ERR(dentry) || dentry == trap || d_really_is_positive(dentry)) goto exit; old_name = fsnotify_oldname_init(old_dentry->d_name.name); - error = simple_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, + error = simple_rename(d_inode(old_dir), old_dentry, d_inode(new_dir), dentry); if (error) { fsnotify_oldname_free(old_name); goto exit; } d_move(old_dentry, dentry); - fsnotify_move(old_dir->d_inode, new_dir->d_inode, old_name, + fsnotify_move(d_inode(old_dir), d_inode(new_dir), old_name, d_is_dir(old_dentry), NULL, old_dentry); fsnotify_oldname_free(old_name); diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index cfe8466f7fef..add566303c68 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -253,7 +253,7 @@ static int mknod_ptmx(struct super_block *sb) if (!uid_valid(root_uid) || !gid_valid(root_gid)) return -EINVAL; - mutex_lock(&root->d_inode->i_mutex); + mutex_lock(&d_inode(root)->i_mutex); /* If we have already created ptmx node, return */ if (fsi->ptmx_dentry) { @@ -290,7 +290,7 @@ static int mknod_ptmx(struct super_block *sb) fsi->ptmx_dentry = dentry; rc = 0; out: - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&d_inode(root)->i_mutex); return rc; } @@ -298,7 +298,7 @@ static void update_ptmx_mode(struct pts_fs_info *fsi) { struct inode *inode; if (fsi->ptmx_dentry) { - inode = fsi->ptmx_dentry->d_inode; + inode = d_inode(fsi->ptmx_dentry); inode->i_mode = S_IFCHR|fsi->mount_opts.ptmxmode; } } @@ -602,18 +602,18 @@ struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index, sprintf(s, "%d", index); - mutex_lock(&root->d_inode->i_mutex); + mutex_lock(&d_inode(root)->i_mutex); dentry = d_alloc_name(root, s); if (dentry) { d_add(dentry, inode); - fsnotify_create(root->d_inode, dentry); + fsnotify_create(d_inode(root), dentry); } else { iput(inode); inode = ERR_PTR(-ENOMEM); } - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&d_inode(root)->i_mutex); return inode; } @@ -658,7 +658,7 @@ void devpts_pty_kill(struct inode *inode) BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR)); - mutex_lock(&root->d_inode->i_mutex); + mutex_lock(&d_inode(root)->i_mutex); dentry = d_find_alias(inode); @@ -667,7 +667,7 @@ void devpts_pty_kill(struct inode *inode) dput(dentry); /* d_alloc_name() in devpts_pty_new() */ dput(dentry); /* d_find_alias above */ - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&d_inode(root)->i_mutex); } static int __init init_devpts_fs(void) diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 719e1ce1c609..97315f2f6816 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -1326,7 +1326,7 @@ static int ecryptfs_read_headers_virt(char *page_virt, if (rc) goto out; if (!(crypt_stat->flags & ECRYPTFS_I_SIZE_INITIALIZED)) - ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode); + ecryptfs_i_size_init(page_virt, d_inode(ecryptfs_dentry)); offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES; rc = ecryptfs_process_flags(crypt_stat, (page_virt + offset), &bytes_read); @@ -1425,7 +1425,7 @@ int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry) { int rc; char *page_virt; - struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode; + struct inode *ecryptfs_inode = d_inode(ecryptfs_dentry); struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c index 4000f6b3a750..8db0b464483f 100644 --- a/fs/ecryptfs/dentry.c +++ b/fs/ecryptfs/dentry.c @@ -54,11 +54,11 @@ static int ecryptfs_d_revalidate(struct dentry *dentry, unsigned int flags) return -ECHILD; rc = lower_dentry->d_op->d_revalidate(lower_dentry, flags); - if (dentry->d_inode) { + if (d_really_is_positive(dentry)) { struct inode *lower_inode = - ecryptfs_inode_to_lower(dentry->d_inode); + ecryptfs_inode_to_lower(d_inode(dentry)); - fsstack_copy_attr_all(dentry->d_inode, lower_inode); + fsstack_copy_attr_all(d_inode(dentry), lower_inode); } return rc; } diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index a65786e26b05..72afcc629d7b 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -130,7 +130,7 @@ struct kmem_cache *ecryptfs_file_info_cache; static int read_or_initialize_metadata(struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct ecryptfs_crypt_stat *crypt_stat; int rc; diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index b08b5187f662..fc850b55db67 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -41,13 +41,13 @@ static struct dentry *lock_parent(struct dentry *dentry) struct dentry *dir; dir = dget_parent(dentry); - mutex_lock_nested(&(dir->d_inode->i_mutex), I_MUTEX_PARENT); + mutex_lock_nested(&(d_inode(dir)->i_mutex), I_MUTEX_PARENT); return dir; } static void unlock_dir(struct dentry *dir) { - mutex_unlock(&dir->d_inode->i_mutex); + mutex_unlock(&d_inode(dir)->i_mutex); dput(dir); } @@ -131,7 +131,7 @@ struct inode *ecryptfs_get_inode(struct inode *lower_inode, static int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, struct super_block *sb) { - struct inode *inode = ecryptfs_get_inode(lower_dentry->d_inode, sb); + struct inode *inode = ecryptfs_get_inode(d_inode(lower_dentry), sb); if (IS_ERR(inode)) return PTR_ERR(inode); @@ -189,21 +189,21 @@ ecryptfs_do_create(struct inode *directory_inode, lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); lower_dir_dentry = lock_parent(lower_dentry); - rc = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, true); + rc = vfs_create(d_inode(lower_dir_dentry), lower_dentry, mode, true); if (rc) { printk(KERN_ERR "%s: Failure to create dentry in lower fs; " "rc = [%d]\n", __func__, rc); inode = ERR_PTR(rc); goto out_lock; } - inode = __ecryptfs_get_inode(lower_dentry->d_inode, + inode = __ecryptfs_get_inode(d_inode(lower_dentry), directory_inode->i_sb); if (IS_ERR(inode)) { - vfs_unlink(lower_dir_dentry->d_inode, lower_dentry, NULL); + vfs_unlink(d_inode(lower_dir_dentry), lower_dentry, NULL); goto out_lock; } - fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode); - fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode); + fsstack_copy_attr_times(directory_inode, d_inode(lower_dir_dentry)); + fsstack_copy_inode_size(directory_inode, d_inode(lower_dir_dentry)); out_lock: unlock_dir(lower_dir_dentry); return inode; @@ -332,7 +332,7 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry, struct dentry *lower_dentry, struct inode *dir_inode) { - struct inode *inode, *lower_inode = lower_dentry->d_inode; + struct inode *inode, *lower_inode = d_inode(lower_dentry); struct ecryptfs_dentry_info *dentry_info; struct vfsmount *lower_mnt; int rc = 0; @@ -347,14 +347,14 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry, } lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent)); - fsstack_copy_attr_atime(dir_inode, lower_dentry->d_parent->d_inode); + fsstack_copy_attr_atime(dir_inode, d_inode(lower_dentry->d_parent)); BUG_ON(!d_count(lower_dentry)); ecryptfs_set_dentry_private(dentry, dentry_info); dentry_info->lower_path.mnt = lower_mnt; dentry_info->lower_path.dentry = lower_dentry; - if (!lower_dentry->d_inode) { + if (d_really_is_negative(lower_dentry)) { /* We want to add because we couldn't find in lower */ d_add(dentry, NULL); return 0; @@ -400,11 +400,11 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, int rc = 0; lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); - mutex_lock(&lower_dir_dentry->d_inode->i_mutex); + mutex_lock(&d_inode(lower_dir_dentry)->i_mutex); lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name, lower_dir_dentry, ecryptfs_dentry->d_name.len); - mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(lower_dir_dentry)->i_mutex); if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " @@ -412,7 +412,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, ecryptfs_dentry); goto out; } - if (lower_dentry->d_inode) + if (d_really_is_positive(lower_dentry)) goto interpose; mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; @@ -429,11 +429,11 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, "filename; rc = [%d]\n", __func__, rc); goto out; } - mutex_lock(&lower_dir_dentry->d_inode->i_mutex); + mutex_lock(&d_inode(lower_dir_dentry)->i_mutex); lower_dentry = lookup_one_len(encrypted_and_encoded_name, lower_dir_dentry, encrypted_and_encoded_name_size); - mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(lower_dir_dentry)->i_mutex); if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " @@ -458,24 +458,24 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir, u64 file_size_save; int rc; - file_size_save = i_size_read(old_dentry->d_inode); + file_size_save = i_size_read(d_inode(old_dentry)); lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); dget(lower_old_dentry); dget(lower_new_dentry); lower_dir_dentry = lock_parent(lower_new_dentry); - rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, + rc = vfs_link(lower_old_dentry, d_inode(lower_dir_dentry), lower_new_dentry, NULL); - if (rc || !lower_new_dentry->d_inode) + if (rc || d_really_is_negative(lower_new_dentry)) goto out_lock; rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb); if (rc) goto out_lock; - fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); - fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); - set_nlink(old_dentry->d_inode, - ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink); - i_size_write(new_dentry->d_inode, file_size_save); + fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry)); + fsstack_copy_inode_size(dir, d_inode(lower_dir_dentry)); + set_nlink(d_inode(old_dentry), + ecryptfs_inode_to_lower(d_inode(old_dentry))->i_nlink); + i_size_write(d_inode(new_dentry), file_size_save); out_lock: unlock_dir(lower_dir_dentry); dput(lower_new_dentry); @@ -485,7 +485,7 @@ out_lock: static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry) { - return ecryptfs_do_unlink(dir, dentry, dentry->d_inode); + return ecryptfs_do_unlink(dir, dentry, d_inode(dentry)); } static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, @@ -510,20 +510,20 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, strlen(symname)); if (rc) goto out_lock; - rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry, + rc = vfs_symlink(d_inode(lower_dir_dentry), lower_dentry, encoded_symname); kfree(encoded_symname); - if (rc || !lower_dentry->d_inode) + if (rc || d_really_is_negative(lower_dentry)) goto out_lock; rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); if (rc) goto out_lock; - fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); - fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); + fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry)); + fsstack_copy_inode_size(dir, d_inode(lower_dir_dentry)); out_lock: unlock_dir(lower_dir_dentry); dput(lower_dentry); - if (!dentry->d_inode) + if (d_really_is_negative(dentry)) d_drop(dentry); return rc; } @@ -536,18 +536,18 @@ static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode lower_dentry = ecryptfs_dentry_to_lower(dentry); lower_dir_dentry = lock_parent(lower_dentry); - rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode); - if (rc || !lower_dentry->d_inode) + rc = vfs_mkdir(d_inode(lower_dir_dentry), lower_dentry, mode); + if (rc || d_really_is_negative(lower_dentry)) goto out; rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); if (rc) goto out; - fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); - fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); - set_nlink(dir, lower_dir_dentry->d_inode->i_nlink); + fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry)); + fsstack_copy_inode_size(dir, d_inode(lower_dir_dentry)); + set_nlink(dir, d_inode(lower_dir_dentry)->i_nlink); out: unlock_dir(lower_dir_dentry); - if (!dentry->d_inode) + if (d_really_is_negative(dentry)) d_drop(dentry); return rc; } @@ -562,12 +562,12 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) dget(dentry); lower_dir_dentry = lock_parent(lower_dentry); dget(lower_dentry); - rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); + rc = vfs_rmdir(d_inode(lower_dir_dentry), lower_dentry); dput(lower_dentry); - if (!rc && dentry->d_inode) - clear_nlink(dentry->d_inode); - fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); - set_nlink(dir, lower_dir_dentry->d_inode->i_nlink); + if (!rc && d_really_is_positive(dentry)) + clear_nlink(d_inode(dentry)); + fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry)); + set_nlink(dir, d_inode(lower_dir_dentry)->i_nlink); unlock_dir(lower_dir_dentry); if (!rc) d_drop(dentry); @@ -584,17 +584,17 @@ ecryptfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev lower_dentry = ecryptfs_dentry_to_lower(dentry); lower_dir_dentry = lock_parent(lower_dentry); - rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev); - if (rc || !lower_dentry->d_inode) + rc = vfs_mknod(d_inode(lower_dir_dentry), lower_dentry, mode, dev); + if (rc || d_really_is_negative(lower_dentry)) goto out; rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); if (rc) goto out; - fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); - fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); + fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry)); + fsstack_copy_inode_size(dir, d_inode(lower_dir_dentry)); out: unlock_dir(lower_dir_dentry); - if (!dentry->d_inode) + if (d_really_is_negative(dentry)) d_drop(dentry); return rc; } @@ -617,7 +617,7 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, dget(lower_new_dentry); lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); - target_inode = new_dentry->d_inode; + target_inode = d_inode(new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { @@ -629,17 +629,17 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, rc = -ENOTEMPTY; goto out_lock; } - rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, - lower_new_dir_dentry->d_inode, lower_new_dentry, + rc = vfs_rename(d_inode(lower_old_dir_dentry), lower_old_dentry, + d_inode(lower_new_dir_dentry), lower_new_dentry, NULL, 0); if (rc) goto out_lock; if (target_inode) fsstack_copy_attr_all(target_inode, ecryptfs_inode_to_lower(target_inode)); - fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); + fsstack_copy_attr_all(new_dir, d_inode(lower_new_dir_dentry)); if (new_dir != old_dir) - fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); + fsstack_copy_attr_all(old_dir, d_inode(lower_old_dir_dentry)); out_lock: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_new_dir_dentry); @@ -662,7 +662,7 @@ static char *ecryptfs_readlink_lower(struct dentry *dentry, size_t *bufsiz) return ERR_PTR(-ENOMEM); old_fs = get_fs(); set_fs(get_ds()); - rc = lower_dentry->d_inode->i_op->readlink(lower_dentry, + rc = d_inode(lower_dentry)->i_op->readlink(lower_dentry, (char __user *)lower_buf, PATH_MAX); set_fs(old_fs); @@ -681,8 +681,8 @@ static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd) char *buf = ecryptfs_readlink_lower(dentry, &len); if (IS_ERR(buf)) goto out; - fsstack_copy_attr_atime(dentry->d_inode, - ecryptfs_dentry_to_lower(dentry)->d_inode); + fsstack_copy_attr_atime(d_inode(dentry), + d_inode(ecryptfs_dentry_to_lower(dentry))); buf[len] = '\0'; out: nd_set_link(nd, buf); @@ -738,7 +738,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, struct iattr *lower_ia) { int rc = 0; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ecryptfs_crypt_stat *crypt_stat; loff_t i_size = i_size_read(inode); loff_t lower_size_before_truncate; @@ -751,7 +751,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, rc = ecryptfs_get_lower_file(dentry, inode); if (rc) return rc; - crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; + crypt_stat = &ecryptfs_inode_to_private(d_inode(dentry))->crypt_stat; /* Switch on growing or shrinking file */ if (ia->ia_size > i_size) { char zero[] = { 0x00 }; @@ -858,7 +858,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) struct iattr lower_ia = { .ia_valid = 0 }; int rc; - rc = ecryptfs_inode_newsize_ok(dentry->d_inode, new_length); + rc = ecryptfs_inode_newsize_ok(d_inode(dentry), new_length); if (rc) return rc; @@ -866,9 +866,9 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) if (!rc && lower_ia.ia_valid & ATTR_SIZE) { struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); - mutex_lock(&lower_dentry->d_inode->i_mutex); + mutex_lock(&d_inode(lower_dentry)->i_mutex); rc = notify_change(lower_dentry, &lower_ia, NULL); - mutex_unlock(&lower_dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(lower_dentry)->i_mutex); } return rc; } @@ -900,10 +900,10 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) struct inode *lower_inode; struct ecryptfs_crypt_stat *crypt_stat; - crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; + crypt_stat = &ecryptfs_inode_to_private(d_inode(dentry))->crypt_stat; if (!(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)) ecryptfs_init_crypt_stat(crypt_stat); - inode = dentry->d_inode; + inode = d_inode(dentry); lower_inode = ecryptfs_inode_to_lower(inode); lower_dentry = ecryptfs_dentry_to_lower(dentry); mutex_lock(&crypt_stat->cs_mutex); @@ -967,9 +967,9 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) lower_ia.ia_valid &= ~ATTR_MODE; - mutex_lock(&lower_dentry->d_inode->i_mutex); + mutex_lock(&d_inode(lower_dentry)->i_mutex); rc = notify_change(lower_dentry, &lower_ia, NULL); - mutex_unlock(&lower_dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(lower_dentry)->i_mutex); out: fsstack_copy_attr_all(inode, lower_inode); return rc; @@ -983,7 +983,7 @@ static int ecryptfs_getattr_link(struct vfsmount *mnt, struct dentry *dentry, mount_crypt_stat = &ecryptfs_superblock_to_private( dentry->d_sb)->mount_crypt_stat; - generic_fillattr(dentry->d_inode, stat); + generic_fillattr(d_inode(dentry), stat); if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) { char *target; size_t targetsiz; @@ -1007,9 +1007,9 @@ static int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry, rc = vfs_getattr(ecryptfs_dentry_to_lower_path(dentry), &lower_stat); if (!rc) { - fsstack_copy_attr_all(dentry->d_inode, - ecryptfs_inode_to_lower(dentry->d_inode)); - generic_fillattr(dentry->d_inode, stat); + fsstack_copy_attr_all(d_inode(dentry), + ecryptfs_inode_to_lower(d_inode(dentry))); + generic_fillattr(d_inode(dentry), stat); stat->blocks = lower_stat.blocks; } return rc; @@ -1023,14 +1023,14 @@ ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value, struct dentry *lower_dentry; lower_dentry = ecryptfs_dentry_to_lower(dentry); - if (!lower_dentry->d_inode->i_op->setxattr) { + if (!d_inode(lower_dentry)->i_op->setxattr) { rc = -EOPNOTSUPP; goto out; } rc = vfs_setxattr(lower_dentry, name, value, size, flags); - if (!rc && dentry->d_inode) - fsstack_copy_attr_all(dentry->d_inode, lower_dentry->d_inode); + if (!rc && d_really_is_positive(dentry)) + fsstack_copy_attr_all(d_inode(dentry), d_inode(lower_dentry)); out: return rc; } @@ -1041,14 +1041,14 @@ ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name, { int rc = 0; - if (!lower_dentry->d_inode->i_op->getxattr) { + if (!d_inode(lower_dentry)->i_op->getxattr) { rc = -EOPNOTSUPP; goto out; } - mutex_lock(&lower_dentry->d_inode->i_mutex); - rc = lower_dentry->d_inode->i_op->getxattr(lower_dentry, name, value, + mutex_lock(&d_inode(lower_dentry)->i_mutex); + rc = d_inode(lower_dentry)->i_op->getxattr(lower_dentry, name, value, size); - mutex_unlock(&lower_dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(lower_dentry)->i_mutex); out: return rc; } @@ -1068,13 +1068,13 @@ ecryptfs_listxattr(struct dentry *dentry, char *list, size_t size) struct dentry *lower_dentry; lower_dentry = ecryptfs_dentry_to_lower(dentry); - if (!lower_dentry->d_inode->i_op->listxattr) { + if (!d_inode(lower_dentry)->i_op->listxattr) { rc = -EOPNOTSUPP; goto out; } - mutex_lock(&lower_dentry->d_inode->i_mutex); - rc = lower_dentry->d_inode->i_op->listxattr(lower_dentry, list, size); - mutex_unlock(&lower_dentry->d_inode->i_mutex); + mutex_lock(&d_inode(lower_dentry)->i_mutex); + rc = d_inode(lower_dentry)->i_op->listxattr(lower_dentry, list, size); + mutex_unlock(&d_inode(lower_dentry)->i_mutex); out: return rc; } @@ -1085,13 +1085,13 @@ static int ecryptfs_removexattr(struct dentry *dentry, const char *name) struct dentry *lower_dentry; lower_dentry = ecryptfs_dentry_to_lower(dentry); - if (!lower_dentry->d_inode->i_op->removexattr) { + if (!d_inode(lower_dentry)->i_op->removexattr) { rc = -EOPNOTSUPP; goto out; } - mutex_lock(&lower_dentry->d_inode->i_mutex); - rc = lower_dentry->d_inode->i_op->removexattr(lower_dentry, name); - mutex_unlock(&lower_dentry->d_inode->i_mutex); + mutex_lock(&d_inode(lower_dentry)->i_mutex); + rc = d_inode(lower_dentry)->i_op->removexattr(lower_dentry, name); + mutex_unlock(&d_inode(lower_dentry)->i_mutex); out: return rc; } diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c index f1ea610362c6..866bb18efefe 100644 --- a/fs/ecryptfs/kthread.c +++ b/fs/ecryptfs/kthread.c @@ -144,7 +144,7 @@ int ecryptfs_privileged_open(struct file **lower_file, /* Corresponding dput() and mntput() are done when the * lower file is fput() when all eCryptfs files for the inode are * released. */ - flags |= IS_RDONLY(lower_dentry->d_inode) ? O_RDONLY : O_RDWR; + flags |= IS_RDONLY(d_inode(lower_dentry)) ? O_RDONLY : O_RDWR; (*lower_file) = dentry_open(&req.path, flags, cred); if (!IS_ERR(*lower_file)) goto out; diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index c095d3264259..4f4d0474bee9 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -546,11 +546,11 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags goto out_free; } - if (check_ruid && !uid_eq(path.dentry->d_inode->i_uid, current_uid())) { + if (check_ruid && !uid_eq(d_inode(path.dentry)->i_uid, current_uid())) { rc = -EPERM; printk(KERN_ERR "Mount of device (uid: %d) not owned by " "requested user (uid: %d)\n", - i_uid_read(path.dentry->d_inode), + i_uid_read(d_inode(path.dentry)), from_kuid(&init_user_ns, current_uid())); goto out_free; } @@ -584,7 +584,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags goto out_free; } - inode = ecryptfs_get_inode(path.dentry->d_inode, s); + inode = ecryptfs_get_inode(d_inode(path.dentry), s); rc = PTR_ERR(inode); if (IS_ERR(inode)) goto out_free; diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index 4626976794e7..cf208522998e 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c @@ -420,7 +420,7 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode) void *xattr_virt; struct dentry *lower_dentry = ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_path.dentry; - struct inode *lower_inode = lower_dentry->d_inode; + struct inode *lower_inode = d_inode(lower_dentry); int rc; if (!lower_inode->i_op->getxattr || !lower_inode->i_op->setxattr) { diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c index 07ab49745e31..3381b9da9ee6 100644 --- a/fs/efivarfs/inode.c +++ b/fs/efivarfs/inode.c @@ -145,12 +145,12 @@ out: static int efivarfs_unlink(struct inode *dir, struct dentry *dentry) { - struct efivar_entry *var = dentry->d_inode->i_private; + struct efivar_entry *var = d_inode(dentry)->i_private; if (efivar_entry_delete(var)) return -EINVAL; - drop_nlink(dentry->d_inode); + drop_nlink(d_inode(dentry)); dput(dentry); return 0; }; diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index ddbce42548c9..59fedbcf8798 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -144,7 +144,7 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; - inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0); + inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0); if (!inode) goto fail_name; diff --git a/fs/efs/namei.c b/fs/efs/namei.c index bbee8f063dfa..40ba9cc41bf7 100644 --- a/fs/efs/namei.c +++ b/fs/efs/namei.c @@ -111,9 +111,9 @@ struct dentry *efs_get_parent(struct dentry *child) struct dentry *parent = ERR_PTR(-ENOENT); efs_ino_t ino; - ino = efs_find_entry(child->d_inode, "..", 2); + ino = efs_find_entry(d_inode(child), "..", 2); if (ino) - parent = d_obtain_alias(efs_iget(child->d_inode->i_sb, ino)); + parent = d_obtain_alias(efs_iget(d_inode(child)->i_sb, ino)); return parent; } diff --git a/fs/exofs/dir.c b/fs/exofs/dir.c index d7defd557601..4deb0b05b011 100644 --- a/fs/exofs/dir.c +++ b/fs/exofs/dir.c @@ -379,7 +379,7 @@ ino_t exofs_parent_ino(struct dentry *child) struct exofs_dir_entry *de; ino_t ino; - de = exofs_dotdot(child->d_inode, &page); + de = exofs_dotdot(d_inode(child), &page); if (!de) return 0; @@ -429,7 +429,7 @@ int exofs_set_link(struct inode *dir, struct exofs_dir_entry *de, int exofs_add_link(struct dentry *dentry, struct inode *inode) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); const unsigned char *name = dentry->d_name.name; int namelen = dentry->d_name.len; unsigned chunk_size = exofs_chunk_size(dir); diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index 35073aaec6e0..786e4cc8c889 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -1028,7 +1028,7 @@ static int _do_truncate(struct inode *inode, loff_t newsize) */ int exofs_setattr(struct dentry *dentry, struct iattr *iattr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error; /* if we are about to modify an object, and it hasn't been diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c index 28907460e8fa..5ae25e431191 100644 --- a/fs/exofs/namei.c +++ b/fs/exofs/namei.c @@ -141,7 +141,7 @@ out_fail: static int exofs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); inode->i_ctime = CURRENT_TIME; inode_inc_link_count(inode); @@ -191,7 +191,7 @@ out_dir: static int exofs_unlink(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct exofs_dir_entry *de; struct page *page; int err = -ENOENT; @@ -213,7 +213,7 @@ out: static int exofs_rmdir(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int err = -ENOTEMPTY; if (exofs_empty_dir(inode)) { @@ -230,8 +230,8 @@ static int exofs_rmdir(struct inode *dir, struct dentry *dentry) static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { - struct inode *old_inode = old_dentry->d_inode; - struct inode *new_inode = new_dentry->d_inode; + struct inode *old_inode = d_inode(old_dentry); + struct inode *new_inode = d_inode(new_dentry); struct page *dir_page = NULL; struct exofs_dir_entry *dir_de = NULL; struct page *old_page; diff --git a/fs/exofs/super.c b/fs/exofs/super.c index fcc2e565f540..b795c567b5e1 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c @@ -958,7 +958,7 @@ static struct dentry *exofs_get_parent(struct dentry *child) if (!ino) return ERR_PTR(-ESTALE); - return d_obtain_alias(exofs_iget(child->d_inode->i_sb, ino)); + return d_obtain_alias(exofs_iget(d_inode(child)->i_sb, ino)); } static struct inode *exofs_nfs_get_inode(struct super_block *sb, diff --git a/fs/exofs/symlink.c b/fs/exofs/symlink.c index 832e2624b80b..6f6f3a4c1365 100644 --- a/fs/exofs/symlink.c +++ b/fs/exofs/symlink.c @@ -37,7 +37,7 @@ static void *exofs_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct exofs_i_info *oi = exofs_i(dentry->d_inode); + struct exofs_i_info *oi = exofs_i(d_inode(dentry)); nd_set_link(nd, (char *)oi->i_data); return NULL; diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 6e1d4ab09d72..796b491e6978 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -486,7 +486,7 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, */ int ext2_add_link (struct dentry *dentry, struct inode *inode) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; unsigned chunk_size = ext2_chunk_size(dir); diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 6c14bb8322fa..5c04a0ddea80 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -278,7 +278,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) avefreeb = free_blocks / ngroups; ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter); - if ((parent == sb->s_root->d_inode) || + if ((parent == d_inode(sb->s_root)) || (EXT2_I(parent)->i_flags & EXT2_TOPDIR_FL)) { struct ext2_group_desc *best_desc = NULL; int best_ndir = inodes_per_group; diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index e1abf75e994c..99a747cacf58 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1547,7 +1547,7 @@ int ext2_write_inode(struct inode *inode, struct writeback_control *wbc) int ext2_setattr(struct dentry *dentry, struct iattr *iattr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error; error = inode_change_ok(inode, iattr); diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 148f6e3789ea..eee075d0b0cb 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -79,10 +79,10 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, uns struct dentry *ext2_get_parent(struct dentry *child) { struct qstr dotdot = QSTR_INIT("..", 2); - unsigned long ino = ext2_inode_by_name(child->d_inode, &dotdot); + unsigned long ino = ext2_inode_by_name(d_inode(child), &dotdot); if (!ino) return ERR_PTR(-ENOENT); - return d_obtain_alias(ext2_iget(child->d_inode->i_sb, ino)); + return d_obtain_alias(ext2_iget(d_inode(child)->i_sb, ino)); } /* @@ -214,7 +214,7 @@ out_fail: static int ext2_link (struct dentry * old_dentry, struct inode * dir, struct dentry *dentry) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); int err; dquot_initialize(dir); @@ -281,7 +281,7 @@ out_dir: static int ext2_unlink(struct inode * dir, struct dentry *dentry) { - struct inode * inode = dentry->d_inode; + struct inode * inode = d_inode(dentry); struct ext2_dir_entry_2 * de; struct page * page; int err = -ENOENT; @@ -305,7 +305,7 @@ out: static int ext2_rmdir (struct inode * dir, struct dentry *dentry) { - struct inode * inode = dentry->d_inode; + struct inode * inode = d_inode(dentry); int err = -ENOTEMPTY; if (ext2_empty_dir(inode)) { @@ -322,8 +322,8 @@ static int ext2_rmdir (struct inode * dir, struct dentry *dentry) static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, struct inode * new_dir, struct dentry * new_dentry ) { - struct inode * old_inode = old_dentry->d_inode; - struct inode * new_inode = new_dentry->d_inode; + struct inode * old_inode = d_inode(old_dentry); + struct inode * new_inode = d_inode(new_dentry); struct page * dir_page = NULL; struct ext2_dir_entry_2 * dir_de = NULL; struct page * old_page; diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c index 565cf817bbf1..20608f17c2e5 100644 --- a/fs/ext2/symlink.c +++ b/fs/ext2/symlink.c @@ -23,7 +23,7 @@ static void *ext2_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct ext2_inode_info *ei = EXT2_I(dentry->d_inode); + struct ext2_inode_info *ei = EXT2_I(d_inode(dentry)); nd_set_link(nd, (char *)ei->i_data); return NULL; } diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 91426141c33a..0b6bfd3a398b 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -243,7 +243,7 @@ cleanup: static int ext2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct buffer_head *bh = NULL; struct ext2_xattr_entry *entry; char *end; @@ -319,7 +319,7 @@ cleanup: /* * Inode operation listxattr() * - * dentry->d_inode->i_mutex: don't care + * d_inode(dentry)->i_mutex: don't care */ ssize_t ext2_listxattr(struct dentry *dentry, char *buffer, size_t size) diff --git a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c index c0ebc4db8849..702fc6840246 100644 --- a/fs/ext2/xattr_security.c +++ b/fs/ext2/xattr_security.c @@ -28,7 +28,7 @@ ext2_xattr_security_get(struct dentry *dentry, const char *name, { if (strcmp(name, "") == 0) return -EINVAL; - return ext2_xattr_get(dentry->d_inode, EXT2_XATTR_INDEX_SECURITY, name, + return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_SECURITY, name, buffer, size); } @@ -38,7 +38,7 @@ ext2_xattr_security_set(struct dentry *dentry, const char *name, { if (strcmp(name, "") == 0) return -EINVAL; - return ext2_xattr_set(dentry->d_inode, EXT2_XATTR_INDEX_SECURITY, name, + return ext2_xattr_set(d_inode(dentry), EXT2_XATTR_INDEX_SECURITY, name, value, size, flags); } diff --git a/fs/ext2/xattr_trusted.c b/fs/ext2/xattr_trusted.c index 7e192574c001..42b6e9874bcc 100644 --- a/fs/ext2/xattr_trusted.c +++ b/fs/ext2/xattr_trusted.c @@ -32,7 +32,7 @@ ext2_xattr_trusted_get(struct dentry *dentry, const char *name, { if (strcmp(name, "") == 0) return -EINVAL; - return ext2_xattr_get(dentry->d_inode, EXT2_XATTR_INDEX_TRUSTED, name, + return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_TRUSTED, name, buffer, size); } @@ -42,7 +42,7 @@ ext2_xattr_trusted_set(struct dentry *dentry, const char *name, { if (strcmp(name, "") == 0) return -EINVAL; - return ext2_xattr_set(dentry->d_inode, EXT2_XATTR_INDEX_TRUSTED, name, + return ext2_xattr_set(d_inode(dentry), EXT2_XATTR_INDEX_TRUSTED, name, value, size, flags); } diff --git a/fs/ext2/xattr_user.c b/fs/ext2/xattr_user.c index f470e44c4b8d..ecdc4605192c 100644 --- a/fs/ext2/xattr_user.c +++ b/fs/ext2/xattr_user.c @@ -36,7 +36,7 @@ ext2_xattr_user_get(struct dentry *dentry, const char *name, return -EINVAL; if (!test_opt(dentry->d_sb, XATTR_USER)) return -EOPNOTSUPP; - return ext2_xattr_get(dentry->d_inode, EXT2_XATTR_INDEX_USER, + return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_USER, name, buffer, size); } @@ -49,7 +49,7 @@ ext2_xattr_user_set(struct dentry *dentry, const char *name, if (!test_opt(dentry->d_sb, XATTR_USER)) return -EOPNOTSUPP; - return ext2_xattr_set(dentry->d_inode, EXT2_XATTR_INDEX_USER, + return ext2_xattr_set(d_inode(dentry), EXT2_XATTR_INDEX_USER, name, value, size, flags); } diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index a1b810230cc5..3ad242e5840e 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -210,7 +210,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) avefreeb = freeb / ngroups; ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter); - if ((parent == sb->s_root->d_inode) || + if ((parent == d_inode(sb->s_root)) || (EXT3_I(parent)->i_flags & EXT3_TOPDIR_FL)) { int best_ndir = inodes_per_group; int best_group = -1; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 13c0868c7160..2ee2dc4351d1 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -3240,7 +3240,7 @@ int ext3_write_inode(struct inode *inode, struct writeback_control *wbc) */ int ext3_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error, rc = 0; const unsigned int ia_valid = attr->ia_valid; diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index f197736dccfa..4264b9bd0002 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -1049,19 +1049,19 @@ struct dentry *ext3_get_parent(struct dentry *child) struct ext3_dir_entry_2 * de; struct buffer_head *bh; - bh = ext3_find_entry(child->d_inode, &dotdot, &de); + bh = ext3_find_entry(d_inode(child), &dotdot, &de); if (!bh) return ERR_PTR(-ENOENT); ino = le32_to_cpu(de->inode); brelse(bh); - if (!ext3_valid_inum(child->d_inode->i_sb, ino)) { - ext3_error(child->d_inode->i_sb, "ext3_get_parent", + if (!ext3_valid_inum(d_inode(child)->i_sb, ino)) { + ext3_error(d_inode(child)->i_sb, "ext3_get_parent", "bad inode number: %lu", ino); return ERR_PTR(-EIO); } - return d_obtain_alias(ext3_iget(child->d_inode->i_sb, ino)); + return d_obtain_alias(ext3_iget(d_inode(child)->i_sb, ino)); } #define S_SHIFT 12 @@ -1243,7 +1243,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, struct inode *inode, struct ext3_dir_entry_2 *de, struct buffer_head * bh) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; unsigned long offset = 0; @@ -1330,7 +1330,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, static int make_indexed_dir(handle_t *handle, struct dentry *dentry, struct inode *inode, struct buffer_head *bh) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; struct buffer_head *bh2; @@ -1435,7 +1435,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, static int ext3_add_entry (handle_t *handle, struct dentry *dentry, struct inode *inode) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); struct buffer_head * bh; struct ext3_dir_entry_2 *de; struct super_block * sb; @@ -1489,7 +1489,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, struct dx_entry *entries, *at; struct dx_hash_info hinfo; struct buffer_head * bh; - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); struct super_block * sb = dir->i_sb; struct ext3_dir_entry_2 *de; int err; @@ -2111,7 +2111,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) /* Initialize quotas before so that eventual writes go in * separate transaction */ dquot_initialize(dir); - dquot_initialize(dentry->d_inode); + dquot_initialize(d_inode(dentry)); handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) @@ -2125,7 +2125,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = dentry->d_inode; + inode = d_inode(dentry); retval = -EIO; if (le32_to_cpu(de->inode) != inode->i_ino) @@ -2173,7 +2173,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) /* Initialize quotas before so that eventual writes go * in separate transaction */ dquot_initialize(dir); - dquot_initialize(dentry->d_inode); + dquot_initialize(d_inode(dentry)); handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) @@ -2187,7 +2187,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) if (!bh) goto end_unlink; - inode = dentry->d_inode; + inode = d_inode(dentry); retval = -EIO; if (le32_to_cpu(de->inode) != inode->i_ino) @@ -2328,7 +2328,7 @@ static int ext3_link (struct dentry * old_dentry, struct inode * dir, struct dentry *dentry) { handle_t *handle; - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); int err, retries = 0; if (inode->i_nlink >= EXT3_LINK_MAX) @@ -2391,8 +2391,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, /* Initialize quotas before so that eventual writes go * in separate transaction */ - if (new_dentry->d_inode) - dquot_initialize(new_dentry->d_inode); + if (d_really_is_positive(new_dentry)) + dquot_initialize(d_inode(new_dentry)); handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS(old_dir->i_sb) + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2); @@ -2409,12 +2409,12 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, * and merrily kill the link to whatever was created under the * same name. Goodbye sticky bit ;-< */ - old_inode = old_dentry->d_inode; + old_inode = d_inode(old_dentry); retval = -ENOENT; if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino) goto end_rename; - new_inode = new_dentry->d_inode; + new_inode = d_inode(new_dentry); new_bh = ext3_find_entry(new_dir, &new_dentry->d_name, &new_de); if (new_bh) { if (!new_inode) { diff --git a/fs/ext3/super.c b/fs/ext3/super.c index d4dbf3c259b3..30abbab2c65b 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1170,7 +1170,7 @@ static int parse_options (char *options, struct super_block *sb, return 0; } - journal_inode = path.dentry->d_inode; + journal_inode = d_inode(path.dentry); if (!S_ISBLK(journal_inode->i_mode)) { ext3_msg(sb, KERN_ERR, "error: journal path %s " "is not a block device", journal_path); @@ -2947,7 +2947,7 @@ static int ext3_write_info(struct super_block *sb, int type) handle_t *handle; /* Data block + inode block */ - handle = ext3_journal_start(sb->s_root->d_inode, 2); + handle = ext3_journal_start(d_inode(sb->s_root), 2); if (IS_ERR(handle)) return PTR_ERR(handle); ret = dquot_commit_info(sb, type); @@ -2994,7 +2994,7 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id, * When we journal data on quota file, we have to flush journal to see * all updates to the file when we bypass pagecache... */ - if (ext3_should_journal_data(path->dentry->d_inode)) { + if (ext3_should_journal_data(d_inode(path->dentry))) { /* * We don't need to lock updates but journal_flush() could * otherwise be livelocked... diff --git a/fs/ext3/symlink.c b/fs/ext3/symlink.c index 6b01c3eab1f3..ea96df3c58db 100644 --- a/fs/ext3/symlink.c +++ b/fs/ext3/symlink.c @@ -23,7 +23,7 @@ static void * ext3_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct ext3_inode_info *ei = EXT3_I(dentry->d_inode); + struct ext3_inode_info *ei = EXT3_I(d_inode(dentry)); nd_set_link(nd, (char*)ei->i_data); return NULL; } diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index c6874be6d58b..a5591d721b55 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -137,7 +137,7 @@ ext3_xattr_handler(int name_index) /* * Inode operation listxattr() * - * dentry->d_inode->i_mutex: don't care + * d_inode(dentry)->i_mutex: don't care */ ssize_t ext3_listxattr(struct dentry *dentry, char *buffer, size_t size) @@ -355,7 +355,7 @@ ext3_xattr_list_entries(struct dentry *dentry, struct ext3_xattr_entry *entry, static int ext3_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct buffer_head *bh = NULL; int error; @@ -391,7 +391,7 @@ cleanup: static int ext3_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ext3_xattr_ibody_header *header; struct ext3_inode *raw_inode; struct ext3_iloc iloc; @@ -432,7 +432,7 @@ ext3_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) { int i_error, b_error; - down_read(&EXT3_I(dentry->d_inode)->xattr_sem); + down_read(&EXT3_I(d_inode(dentry))->xattr_sem); i_error = ext3_xattr_ibody_list(dentry, buffer, buffer_size); if (i_error < 0) { b_error = 0; @@ -445,7 +445,7 @@ ext3_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) if (b_error < 0) i_error = 0; } - up_read(&EXT3_I(dentry->d_inode)->xattr_sem); + up_read(&EXT3_I(d_inode(dentry))->xattr_sem); return i_error + b_error; } diff --git a/fs/ext3/xattr_security.c b/fs/ext3/xattr_security.c index 722c2bf9645d..c9506d5e3b13 100644 --- a/fs/ext3/xattr_security.c +++ b/fs/ext3/xattr_security.c @@ -29,7 +29,7 @@ ext3_xattr_security_get(struct dentry *dentry, const char *name, { if (strcmp(name, "") == 0) return -EINVAL; - return ext3_xattr_get(dentry->d_inode, EXT3_XATTR_INDEX_SECURITY, + return ext3_xattr_get(d_inode(dentry), EXT3_XATTR_INDEX_SECURITY, name, buffer, size); } @@ -39,7 +39,7 @@ ext3_xattr_security_set(struct dentry *dentry, const char *name, { if (strcmp(name, "") == 0) return -EINVAL; - return ext3_xattr_set(dentry->d_inode, EXT3_XATTR_INDEX_SECURITY, + return ext3_xattr_set(d_inode(dentry), EXT3_XATTR_INDEX_SECURITY, name, value, size, flags); } diff --git a/fs/ext3/xattr_trusted.c b/fs/ext3/xattr_trusted.c index d75727cc67fa..206cc66dc285 100644 --- a/fs/ext3/xattr_trusted.c +++ b/fs/ext3/xattr_trusted.c @@ -32,7 +32,7 @@ ext3_xattr_trusted_get(struct dentry *dentry, const char *name, { if (strcmp(name, "") == 0) return -EINVAL; - return ext3_xattr_get(dentry->d_inode, EXT3_XATTR_INDEX_TRUSTED, + return ext3_xattr_get(d_inode(dentry), EXT3_XATTR_INDEX_TRUSTED, name, buffer, size); } @@ -42,7 +42,7 @@ ext3_xattr_trusted_set(struct dentry *dentry, const char *name, { if (strcmp(name, "") == 0) return -EINVAL; - return ext3_xattr_set(dentry->d_inode, EXT3_XATTR_INDEX_TRUSTED, name, + return ext3_xattr_set(d_inode(dentry), EXT3_XATTR_INDEX_TRUSTED, name, value, size, flags); } diff --git a/fs/ext3/xattr_user.c b/fs/ext3/xattr_user.c index 5612af3567e0..021508ad1616 100644 --- a/fs/ext3/xattr_user.c +++ b/fs/ext3/xattr_user.c @@ -34,7 +34,7 @@ ext3_xattr_user_get(struct dentry *dentry, const char *name, void *buffer, return -EINVAL; if (!test_opt(dentry->d_sb, XATTR_USER)) return -EOPNOTSUPP; - return ext3_xattr_get(dentry->d_inode, EXT3_XATTR_INDEX_USER, + return ext3_xattr_get(d_inode(dentry), EXT3_XATTR_INDEX_USER, name, buffer, size); } @@ -46,7 +46,7 @@ ext3_xattr_user_set(struct dentry *dentry, const char *name, return -EINVAL; if (!test_opt(dentry->d_sb, XATTR_USER)) return -EOPNOTSUPP; - return ext3_xattr_set(dentry->d_inode, EXT3_XATTR_INDEX_USER, + return ext3_xattr_set(d_inode(dentry), EXT3_XATTR_INDEX_USER, name, value, size, flags); } diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index a8bc47f75fa0..3ceedea099ea 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c @@ -56,7 +56,7 @@ static int ext4_sync_parent(struct inode *inode) dentry = d_find_any_alias(inode); if (!dentry) break; - next = igrab(dentry->d_parent->d_inode); + next = igrab(d_inode(dentry->d_parent)); dput(dentry); if (!next) break; diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index ac644c31ca67..d8d4f2929cbd 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -444,7 +444,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent, ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter); if (S_ISDIR(mode) && - ((parent == sb->s_root->d_inode) || + ((parent == d_inode(sb->s_root)) || (ext4_test_inode_flag(parent, EXT4_INODE_TOPDIR)))) { int best_ndir = inodes_per_group; int ret = -1; diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 4b143febf21f..f696948c548b 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -998,7 +998,7 @@ static int ext4_add_dirent_to_inline(handle_t *handle, struct ext4_iloc *iloc, void *inline_start, int inline_size) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; int err; @@ -1251,7 +1251,7 @@ int ext4_try_add_inline_entry(handle_t *handle, struct dentry *dentry, int ret, inline_size; void *inline_start; struct ext4_iloc iloc; - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); ret = ext4_get_inode_loc(dir, &iloc); if (ret) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 42c942a950e1..063052e4aa8b 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4524,7 +4524,7 @@ static void ext4_wait_for_tail_page_commit(struct inode *inode) */ int ext4_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error, rc = 0; int orphan = 0; const unsigned int ia_valid = attr->ia_valid; @@ -4672,7 +4672,7 @@ int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry, struct inode *inode; unsigned long long delalloc_blocks; - inode = dentry->d_inode; + inode = d_inode(dentry); generic_fillattr(inode, stat); /* diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index 3cb267aee802..b52374e42102 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c @@ -475,7 +475,7 @@ int ext4_ext_migrate(struct inode *inode) EXT4_INODES_PER_GROUP(inode->i_sb)) + 1; owner[0] = i_uid_read(inode); owner[1] = i_gid_read(inode); - tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode, + tmp_inode = ext4_new_inode(handle, d_inode(inode->i_sb->s_root), S_IFREG, NULL, goal, owner); if (IS_ERR(tmp_inode)) { retval = PTR_ERR(tmp_inode); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 28fe71a2904c..e086eebe335e 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1429,7 +1429,7 @@ struct dentry *ext4_get_parent(struct dentry *child) struct ext4_dir_entry_2 * de; struct buffer_head *bh; - bh = ext4_find_entry(child->d_inode, &dotdot, &de, NULL); + bh = ext4_find_entry(d_inode(child), &dotdot, &de, NULL); if (IS_ERR(bh)) return (struct dentry *) bh; if (!bh) @@ -1437,13 +1437,13 @@ struct dentry *ext4_get_parent(struct dentry *child) ino = le32_to_cpu(de->inode); brelse(bh); - if (!ext4_valid_inum(child->d_inode->i_sb, ino)) { - EXT4_ERROR_INODE(child->d_inode, + if (!ext4_valid_inum(d_inode(child)->i_sb, ino)) { + EXT4_ERROR_INODE(d_inode(child), "bad parent inode number: %u", ino); return ERR_PTR(-EIO); } - return d_obtain_alias(ext4_iget_normal(child->d_inode->i_sb, ino)); + return d_obtain_alias(ext4_iget_normal(d_inode(child)->i_sb, ino)); } /* @@ -1676,7 +1676,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, struct inode *inode, struct ext4_dir_entry_2 *de, struct buffer_head *bh) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; unsigned int blocksize = dir->i_sb->s_blocksize; @@ -1732,7 +1732,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, static int make_indexed_dir(handle_t *handle, struct dentry *dentry, struct inode *inode, struct buffer_head *bh) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; struct buffer_head *bh2; @@ -1864,7 +1864,7 @@ out_frames: static int ext4_add_entry(handle_t *handle, struct dentry *dentry, struct inode *inode) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); struct buffer_head *bh; struct ext4_dir_entry_2 *de; struct ext4_dir_entry_tail *t; @@ -1947,7 +1947,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, struct dx_entry *entries, *at; struct dx_hash_info hinfo; struct buffer_head *bh; - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); struct super_block *sb = dir->i_sb; struct ext4_dir_entry_2 *de; int err; @@ -2708,7 +2708,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry) /* Initialize quotas before so that eventual writes go in * separate transaction */ dquot_initialize(dir); - dquot_initialize(dentry->d_inode); + dquot_initialize(d_inode(dentry)); retval = -ENOENT; bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); @@ -2717,7 +2717,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry) if (!bh) goto end_rmdir; - inode = dentry->d_inode; + inode = d_inode(dentry); retval = -EIO; if (le32_to_cpu(de->inode) != inode->i_ino) @@ -2777,7 +2777,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry) /* Initialize quotas before so that eventual writes go * in separate transaction */ dquot_initialize(dir); - dquot_initialize(dentry->d_inode); + dquot_initialize(d_inode(dentry)); retval = -ENOENT; bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); @@ -2786,7 +2786,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry) if (!bh) goto end_unlink; - inode = dentry->d_inode; + inode = d_inode(dentry); retval = -EIO; if (le32_to_cpu(de->inode) != inode->i_ino) @@ -2938,7 +2938,7 @@ static int ext4_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { handle_t *handle; - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); int err, retries = 0; if (inode->i_nlink >= EXT4_LINK_MAX) @@ -3210,12 +3210,12 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, struct ext4_renament old = { .dir = old_dir, .dentry = old_dentry, - .inode = old_dentry->d_inode, + .inode = d_inode(old_dentry), }; struct ext4_renament new = { .dir = new_dir, .dentry = new_dentry, - .inode = new_dentry->d_inode, + .inode = d_inode(new_dentry), }; int force_reread; int retval; @@ -3391,12 +3391,12 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry, struct ext4_renament old = { .dir = old_dir, .dentry = old_dentry, - .inode = old_dentry->d_inode, + .inode = d_inode(old_dentry), }; struct ext4_renament new = { .dir = new_dir, .dentry = new_dentry, - .inode = new_dentry->d_inode, + .inode = d_inode(new_dentry), }; u8 new_file_type; int retval; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index e061e66c8280..386ba41fa17b 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1568,7 +1568,7 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token, return -1; } - journal_inode = path.dentry->d_inode; + journal_inode = d_inode(path.dentry); if (!S_ISBLK(journal_inode->i_mode)) { ext4_msg(sb, KERN_ERR, "error: journal path %s " "is not a block device", journal_path); @@ -5199,7 +5199,7 @@ static int ext4_write_info(struct super_block *sb, int type) handle_t *handle; /* Data block + inode block */ - handle = ext4_journal_start(sb->s_root->d_inode, EXT4_HT_QUOTA, 2); + handle = ext4_journal_start(d_inode(sb->s_root), EXT4_HT_QUOTA, 2); if (IS_ERR(handle)) return PTR_ERR(handle); ret = dquot_commit_info(sb, type); @@ -5247,7 +5247,7 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, * all updates to the file when we bypass pagecache... */ if (EXT4_SB(sb)->s_journal && - ext4_should_journal_data(path->dentry->d_inode)) { + ext4_should_journal_data(d_inode(path->dentry))) { /* * We don't need to lock updates but journal_flush() could * otherwise be livelocked... diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index ff3711932018..57f50091b8d1 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -25,7 +25,7 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct ext4_inode_info *ei = EXT4_I(dentry->d_inode); + struct ext4_inode_info *ei = EXT4_I(d_inode(dentry)); nd_set_link(nd, (char *) ei->i_data); return NULL; } diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 1e09fc77395c..19935320f7b4 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -179,7 +179,7 @@ ext4_xattr_handler(int name_index) /* * Inode operation listxattr() * - * dentry->d_inode->i_mutex: don't care + * d_inode(dentry)->i_mutex: don't care */ ssize_t ext4_listxattr(struct dentry *dentry, char *buffer, size_t size) @@ -424,7 +424,7 @@ ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry, static int ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct buffer_head *bh = NULL; int error; struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); @@ -461,7 +461,7 @@ cleanup: static int ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ext4_xattr_ibody_header *header; struct ext4_inode *raw_inode; struct ext4_iloc iloc; @@ -502,7 +502,7 @@ ext4_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) { int ret, ret2; - down_read(&EXT4_I(dentry->d_inode)->xattr_sem); + down_read(&EXT4_I(d_inode(dentry))->xattr_sem); ret = ret2 = ext4_xattr_ibody_list(dentry, buffer, buffer_size); if (ret < 0) goto errout; @@ -515,7 +515,7 @@ ext4_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) goto errout; ret += ret2; errout: - up_read(&EXT4_I(dentry->d_inode)->xattr_sem); + up_read(&EXT4_I(d_inode(dentry))->xattr_sem); return ret; } diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c index d2a200624af5..95d90e0560f0 100644 --- a/fs/ext4/xattr_security.c +++ b/fs/ext4/xattr_security.c @@ -33,7 +33,7 @@ ext4_xattr_security_get(struct dentry *dentry, const char *name, { if (strcmp(name, "") == 0) return -EINVAL; - return ext4_xattr_get(dentry->d_inode, EXT4_XATTR_INDEX_SECURITY, + return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_SECURITY, name, buffer, size); } @@ -43,7 +43,7 @@ ext4_xattr_security_set(struct dentry *dentry, const char *name, { if (strcmp(name, "") == 0) return -EINVAL; - return ext4_xattr_set(dentry->d_inode, EXT4_XATTR_INDEX_SECURITY, + return ext4_xattr_set(d_inode(dentry), EXT4_XATTR_INDEX_SECURITY, name, value, size, flags); } diff --git a/fs/ext4/xattr_trusted.c b/fs/ext4/xattr_trusted.c index 95f1f4ab59a4..891ee2ddfbd6 100644 --- a/fs/ext4/xattr_trusted.c +++ b/fs/ext4/xattr_trusted.c @@ -36,7 +36,7 @@ ext4_xattr_trusted_get(struct dentry *dentry, const char *name, void *buffer, { if (strcmp(name, "") == 0) return -EINVAL; - return ext4_xattr_get(dentry->d_inode, EXT4_XATTR_INDEX_TRUSTED, + return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_TRUSTED, name, buffer, size); } @@ -46,7 +46,7 @@ ext4_xattr_trusted_set(struct dentry *dentry, const char *name, { if (strcmp(name, "") == 0) return -EINVAL; - return ext4_xattr_set(dentry->d_inode, EXT4_XATTR_INDEX_TRUSTED, + return ext4_xattr_set(d_inode(dentry), EXT4_XATTR_INDEX_TRUSTED, name, value, size, flags); } diff --git a/fs/ext4/xattr_user.c b/fs/ext4/xattr_user.c index 0edb7611ffbe..6ed932b3c043 100644 --- a/fs/ext4/xattr_user.c +++ b/fs/ext4/xattr_user.c @@ -37,7 +37,7 @@ ext4_xattr_user_get(struct dentry *dentry, const char *name, return -EINVAL; if (!test_opt(dentry->d_sb, XATTR_USER)) return -EOPNOTSUPP; - return ext4_xattr_get(dentry->d_inode, EXT4_XATTR_INDEX_USER, + return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_USER, name, buffer, size); } @@ -49,7 +49,7 @@ ext4_xattr_user_set(struct dentry *dentry, const char *name, return -EINVAL; if (!test_opt(dentry->d_sb, XATTR_USER)) return -EOPNOTSUPP; - return ext4_xattr_set(dentry->d_inode, EXT4_XATTR_INDEX_USER, + return ext4_xattr_set(d_inode(dentry), EXT4_XATTR_INDEX_USER, name, value, size, flags); } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 7fa3313ab0e2..02e4ab3e7d4d 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1391,7 +1391,7 @@ bool f2fs_empty_dir(struct inode *); static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode) { - return __f2fs_add_link(dentry->d_parent->d_inode, &dentry->d_name, + return __f2fs_add_link(d_inode(dentry->d_parent), &dentry->d_name, inode); } diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index df6a0596eccf..71a74f1e2bfb 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -562,7 +562,7 @@ void f2fs_truncate(struct inode *inode) int f2fs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); generic_fillattr(inode, stat); stat->blocks <<= 3; return 0; @@ -601,7 +601,7 @@ static void __setattr_copy(struct inode *inode, const struct iattr *attr) int f2fs_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct f2fs_inode_info *fi = F2FS_I(inode); int err; diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index e79639a9787a..ed7404706ca4 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -150,7 +150,7 @@ out: static int f2fs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); struct f2fs_sb_info *sbi = F2FS_I_SB(dir); int err; @@ -181,10 +181,10 @@ out: struct dentry *f2fs_get_parent(struct dentry *child) { struct qstr dotdot = QSTR_INIT("..", 2); - unsigned long ino = f2fs_inode_by_name(child->d_inode, &dotdot); + unsigned long ino = f2fs_inode_by_name(d_inode(child), &dotdot); if (!ino) return ERR_PTR(-ENOENT); - return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino)); + return d_obtain_alias(f2fs_iget(d_inode(child)->i_sb, ino)); } static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, @@ -214,7 +214,7 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, static int f2fs_unlink(struct inode *dir, struct dentry *dentry) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct f2fs_dir_entry *de; struct page *page; int err = -ENOENT; @@ -326,7 +326,7 @@ out_fail: static int f2fs_rmdir(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); if (f2fs_empty_dir(inode)) return f2fs_unlink(dir, dentry); return -ENOTEMPTY; @@ -374,8 +374,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir); - struct inode *old_inode = old_dentry->d_inode; - struct inode *new_inode = new_dentry->d_inode; + struct inode *old_inode = d_inode(old_dentry); + struct inode *new_inode = d_inode(new_dentry); struct page *old_dir_page; struct page *old_page, *new_page; struct f2fs_dir_entry *old_dir_entry = NULL; @@ -501,8 +501,8 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir); - struct inode *old_inode = old_dentry->d_inode; - struct inode *new_inode = new_dentry->d_inode; + struct inode *old_inode = d_inode(old_dentry); + struct inode *new_inode = d_inode(new_dentry); struct page *old_dir_page, *new_dir_page; struct page *old_page, *new_page; struct f2fs_dir_entry *old_dir_entry = NULL, *new_dir_entry = NULL; diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 5072bf9ae0ef..62c82f35087e 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -83,7 +83,7 @@ static int f2fs_xattr_generic_get(struct dentry *dentry, const char *name, } if (strcmp(name, "") == 0) return -EINVAL; - return f2fs_getxattr(dentry->d_inode, type, name, buffer, size, NULL); + return f2fs_getxattr(d_inode(dentry), type, name, buffer, size, NULL); } static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, @@ -108,7 +108,7 @@ static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, if (strcmp(name, "") == 0) return -EINVAL; - return f2fs_setxattr(dentry->d_inode, type, name, + return f2fs_setxattr(d_inode(dentry), type, name, value, size, NULL, flags); } @@ -130,7 +130,7 @@ static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list, static int f2fs_xattr_advise_get(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); if (strcmp(name, "") != 0) return -EINVAL; @@ -142,7 +142,7 @@ static int f2fs_xattr_advise_get(struct dentry *dentry, const char *name, static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); if (strcmp(name, "") != 0) return -EINVAL; @@ -442,7 +442,7 @@ cleanup: ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct f2fs_xattr_entry *entry; void *base_addr; int error = 0; diff --git a/fs/fat/file.c b/fs/fat/file.c index 1e98d333879f..54646829e08e 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -309,7 +309,7 @@ void fat_truncate_blocks(struct inode *inode, loff_t offset) int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); generic_fillattr(inode, stat); stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size; @@ -381,7 +381,7 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) int fat_setattr(struct dentry *dentry, struct iattr *attr) { struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); unsigned int ia_valid; int error; diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index a783b0e1272a..e68e794c71d2 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -310,7 +310,7 @@ out: static int msdos_rmdir(struct inode *dir, struct dentry *dentry) { struct super_block *sb = dir->i_sb; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct fat_slot_info sinfo; int err; @@ -404,7 +404,7 @@ out: /***** Unlink a file */ static int msdos_unlink(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct super_block *sb = inode->i_sb; struct fat_slot_info sinfo; int err; @@ -442,8 +442,8 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, int err, old_attrs, is_dir, update_dotdot, corrupt = 0; old_sinfo.bh = sinfo.bh = dotdot_bh = NULL; - old_inode = old_dentry->d_inode; - new_inode = new_dentry->d_inode; + old_inode = d_inode(old_dentry); + new_inode = d_inode(new_dentry); err = fat_scan(old_dir, old_name, &old_sinfo); if (err) { diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index b8b92c2f9683..af400ab27d48 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -35,7 +35,7 @@ static int vfat_revalidate_shortname(struct dentry *dentry) { int ret = 1; spin_lock(&dentry->d_lock); - if (dentry->d_time != dentry->d_parent->d_inode->i_version) + if (dentry->d_time != d_inode(dentry->d_parent)->i_version) ret = 0; spin_unlock(&dentry->d_lock); return ret; @@ -47,7 +47,7 @@ static int vfat_revalidate(struct dentry *dentry, unsigned int flags) return -ECHILD; /* This is not negative dentry. Always valid. */ - if (dentry->d_inode) + if (d_really_is_positive(dentry)) return 1; return vfat_revalidate_shortname(dentry); } @@ -67,7 +67,7 @@ static int vfat_revalidate_ci(struct dentry *dentry, unsigned int flags) * positive dentry isn't good idea. So it's unsupported like * rename("filename", "FILENAME") for now. */ - if (dentry->d_inode) + if (d_really_is_positive(dentry)) return 1; /* @@ -803,7 +803,7 @@ out: static int vfat_rmdir(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct super_block *sb = dir->i_sb; struct fat_slot_info sinfo; int err; @@ -834,7 +834,7 @@ out: static int vfat_unlink(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct super_block *sb = dir->i_sb; struct fat_slot_info sinfo; int err; @@ -917,8 +917,8 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, struct super_block *sb = old_dir->i_sb; old_sinfo.bh = sinfo.bh = dotdot_bh = NULL; - old_inode = old_dentry->d_inode; - new_inode = new_dentry->d_inode; + old_inode = d_inode(old_dentry); + new_inode = d_inode(new_dentry); mutex_lock(&MSDOS_SB(sb)->s_lock); err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo); if (err) diff --git a/fs/fat/nfs.c b/fs/fat/nfs.c index 93e14933dcb6..eb192656fba2 100644 --- a/fs/fat/nfs.c +++ b/fs/fat/nfs.c @@ -266,7 +266,7 @@ struct inode *fat_rebuild_parent(struct super_block *sb, int parent_logstart) * Find the parent for a directory that is not currently connected to * the filesystem root. * - * On entry, the caller holds child_dir->d_inode->i_mutex. + * On entry, the caller holds d_inode(child_dir)->i_mutex. */ static struct dentry *fat_get_parent(struct dentry *child_dir) { @@ -276,7 +276,7 @@ static struct dentry *fat_get_parent(struct dentry *child_dir) struct inode *parent_inode = NULL; struct msdos_sb_info *sbi = MSDOS_SB(sb); - if (!fat_get_dotdot_entry(child_dir->d_inode, &bh, &de)) { + if (!fat_get_dotdot_entry(d_inode(child_dir), &bh, &de)) { int parent_logstart = fat_get_start(sbi, de); parent_inode = fat_dget(sb, parent_logstart); if (!parent_inode && sbi->options.nfs == FAT_NFS_NOSTALE_RO) diff --git a/fs/freevxfs/vxfs_immed.c b/fs/freevxfs/vxfs_immed.c index c36aeaf92e41..8b9229e2ca5c 100644 --- a/fs/freevxfs/vxfs_immed.c +++ b/fs/freevxfs/vxfs_immed.c @@ -76,7 +76,7 @@ const struct address_space_operations vxfs_immed_aops = { static void * vxfs_immed_follow_link(struct dentry *dp, struct nameidata *np) { - struct vxfs_inode_info *vip = VXFS_INO(dp->d_inode); + struct vxfs_inode_info *vip = VXFS_INO(d_inode(dp)); nd_set_link(np, vip->vii_immed.vi_immed); return NULL; } diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 205e0d5d5307..f863ac6647ac 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -244,7 +244,7 @@ int fuse_ctl_add_conn(struct fuse_conn *fc) return 0; parent = fuse_control_sb->s_root; - inc_nlink(parent->d_inode); + inc_nlink(d_inode(parent)); sprintf(name, "%u", fc->dev); parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2, &simple_dir_inode_operations, @@ -283,11 +283,11 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc) for (i = fc->ctl_ndents - 1; i >= 0; i--) { struct dentry *dentry = fc->ctl_dentry[i]; - dentry->d_inode->i_private = NULL; + d_inode(dentry)->i_private = NULL; d_drop(dentry); dput(dentry); } - drop_nlink(fuse_control_sb->s_root->d_inode); + drop_nlink(d_inode(fuse_control_sb->s_root)); } static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 1545b711ddcf..0572bca49f15 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -192,7 +192,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) struct fuse_inode *fi; int ret; - inode = ACCESS_ONCE(entry->d_inode); + inode = d_inode_rcu(entry); if (inode && is_bad_inode(inode)) goto invalid; else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) || @@ -220,7 +220,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) attr_version = fuse_get_attr_version(fc); parent = dget_parent(entry); - fuse_lookup_init(fc, &args, get_node_id(parent->d_inode), + fuse_lookup_init(fc, &args, get_node_id(d_inode(parent)), &entry->d_name, &outarg); ret = fuse_simple_request(fc, &args); dput(parent); @@ -254,7 +254,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) return -ECHILD; } else if (test_and_clear_bit(FUSE_I_INIT_RDPLUS, &fi->state)) { parent = dget_parent(entry); - fuse_advise_use_readdirplus(parent->d_inode); + fuse_advise_use_readdirplus(d_inode(parent)); dput(parent); } } @@ -487,7 +487,7 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry, entry = res; } - if (!(flags & O_CREAT) || entry->d_inode) + if (!(flags & O_CREAT) || d_really_is_positive(entry)) goto no_open; /* Only creates */ @@ -653,7 +653,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) args.in.args[0].value = entry->d_name.name; err = fuse_simple_request(fc, &args); if (!err) { - struct inode *inode = entry->d_inode; + struct inode *inode = d_inode(entry); struct fuse_inode *fi = get_fuse_inode(inode); spin_lock(&fc->lock); @@ -689,7 +689,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) args.in.args[0].value = entry->d_name.name; err = fuse_simple_request(fc, &args); if (!err) { - clear_nlink(entry->d_inode); + clear_nlink(d_inode(entry)); fuse_invalidate_attr(dir); fuse_invalidate_entry_cache(entry); } else if (err == -EINTR) @@ -721,12 +721,12 @@ static int fuse_rename_common(struct inode *olddir, struct dentry *oldent, err = fuse_simple_request(fc, &args); if (!err) { /* ctime changes */ - fuse_invalidate_attr(oldent->d_inode); - fuse_update_ctime(oldent->d_inode); + fuse_invalidate_attr(d_inode(oldent)); + fuse_update_ctime(d_inode(oldent)); if (flags & RENAME_EXCHANGE) { - fuse_invalidate_attr(newent->d_inode); - fuse_update_ctime(newent->d_inode); + fuse_invalidate_attr(d_inode(newent)); + fuse_update_ctime(d_inode(newent)); } fuse_invalidate_attr(olddir); @@ -734,10 +734,10 @@ static int fuse_rename_common(struct inode *olddir, struct dentry *oldent, fuse_invalidate_attr(newdir); /* newent will end up negative */ - if (!(flags & RENAME_EXCHANGE) && newent->d_inode) { - fuse_invalidate_attr(newent->d_inode); + if (!(flags & RENAME_EXCHANGE) && d_really_is_positive(newent)) { + fuse_invalidate_attr(d_inode(newent)); fuse_invalidate_entry_cache(newent); - fuse_update_ctime(newent->d_inode); + fuse_update_ctime(d_inode(newent)); } } else if (err == -EINTR) { /* If request was interrupted, DEITY only knows if the @@ -746,7 +746,7 @@ static int fuse_rename_common(struct inode *olddir, struct dentry *oldent, directory), then there can be inconsistency between the dcache and the real filesystem. Tough luck. */ fuse_invalidate_entry(oldent); - if (newent->d_inode) + if (d_really_is_positive(newent)) fuse_invalidate_entry(newent); } @@ -788,7 +788,7 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, { int err; struct fuse_link_in inarg; - struct inode *inode = entry->d_inode; + struct inode *inode = d_inode(entry); struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); @@ -961,9 +961,9 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, fuse_invalidate_attr(parent); fuse_invalidate_entry(entry); - if (child_nodeid != 0 && entry->d_inode) { - mutex_lock(&entry->d_inode->i_mutex); - if (get_node_id(entry->d_inode) != child_nodeid) { + if (child_nodeid != 0 && d_really_is_positive(entry)) { + mutex_lock(&d_inode(entry)->i_mutex); + if (get_node_id(d_inode(entry)) != child_nodeid) { err = -ENOENT; goto badentry; } @@ -977,13 +977,13 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, err = -ENOTEMPTY; goto badentry; } - entry->d_inode->i_flags |= S_DEAD; + d_inode(entry)->i_flags |= S_DEAD; } dont_mount(entry); - clear_nlink(entry->d_inode); + clear_nlink(d_inode(entry)); err = 0; badentry: - mutex_unlock(&entry->d_inode->i_mutex); + mutex_unlock(&d_inode(entry)->i_mutex); if (!err) d_delete(entry); } else { @@ -1169,7 +1169,7 @@ static int fuse_direntplus_link(struct file *file, struct qstr name = QSTR_INIT(dirent->name, dirent->namelen); struct dentry *dentry; struct dentry *alias; - struct inode *dir = parent->d_inode; + struct inode *dir = d_inode(parent); struct fuse_conn *fc; struct inode *inode; @@ -1205,7 +1205,7 @@ static int fuse_direntplus_link(struct file *file, name.hash = full_name_hash(name.name, name.len); dentry = d_lookup(parent, &name); if (dentry) { - inode = dentry->d_inode; + inode = d_inode(dentry); if (!inode) { d_drop(dentry); } else if (get_node_id(inode) != o->nodeid || @@ -1367,7 +1367,7 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx) static char *read_link(struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); char *link; @@ -1712,7 +1712,7 @@ error: static int fuse_setattr(struct dentry *entry, struct iattr *attr) { - struct inode *inode = entry->d_inode; + struct inode *inode = d_inode(entry); if (!fuse_allow_current_process(get_fuse_conn(inode))) return -EACCES; @@ -1726,7 +1726,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, struct kstat *stat) { - struct inode *inode = entry->d_inode; + struct inode *inode = d_inode(entry); struct fuse_conn *fc = get_fuse_conn(inode); if (!fuse_allow_current_process(fc)) @@ -1738,7 +1738,7 @@ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, static int fuse_setxattr(struct dentry *entry, const char *name, const void *value, size_t size, int flags) { - struct inode *inode = entry->d_inode; + struct inode *inode = d_inode(entry); struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); struct fuse_setxattr_in inarg; @@ -1774,7 +1774,7 @@ static int fuse_setxattr(struct dentry *entry, const char *name, static ssize_t fuse_getxattr(struct dentry *entry, const char *name, void *value, size_t size) { - struct inode *inode = entry->d_inode; + struct inode *inode = d_inode(entry); struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); struct fuse_getxattr_in inarg; @@ -1815,7 +1815,7 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name, static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) { - struct inode *inode = entry->d_inode; + struct inode *inode = d_inode(entry); struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); struct fuse_getxattr_in inarg; @@ -1857,7 +1857,7 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) static int fuse_removexattr(struct dentry *entry, const char *name) { - struct inode *inode = entry->d_inode; + struct inode *inode = d_inode(entry); struct fuse_conn *fc = get_fuse_conn(inode); FUSE_ARGS(args); int err; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index e8799c11424b..082ac1c97f39 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -421,7 +421,7 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) memset(&outarg, 0, sizeof(outarg)); args.in.numargs = 0; args.in.h.opcode = FUSE_STATFS; - args.in.h.nodeid = get_node_id(dentry->d_inode); + args.in.h.nodeid = get_node_id(d_inode(dentry)); args.out.numargs = 1; args.out.args[0].size = sizeof(outarg); args.out.args[0].value = &outarg; @@ -740,7 +740,7 @@ static struct dentry *fuse_fh_to_parent(struct super_block *sb, static struct dentry *fuse_get_parent(struct dentry *child) { - struct inode *child_inode = child->d_inode; + struct inode *child_inode = d_inode(child); struct fuse_conn *fc = get_fuse_conn(child_inode); struct inode *inode; struct dentry *parent; diff --git a/fs/gfs2/dentry.c b/fs/gfs2/dentry.c index 589f4ea9381c..30822b148f3e 100644 --- a/fs/gfs2/dentry.c +++ b/fs/gfs2/dentry.c @@ -48,9 +48,9 @@ static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags) return -ECHILD; parent = dget_parent(dentry); - sdp = GFS2_SB(parent->d_inode); - dip = GFS2_I(parent->d_inode); - inode = dentry->d_inode; + sdp = GFS2_SB(d_inode(parent)); + dip = GFS2_I(d_inode(parent)); + inode = d_inode(dentry); if (inode) { if (is_bad_inode(inode)) @@ -68,7 +68,7 @@ static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags) goto fail; } - error = gfs2_dir_check(parent->d_inode, &dentry->d_name, ip); + error = gfs2_dir_check(d_inode(parent), &dentry->d_name, ip); switch (error) { case 0: if (!inode) @@ -113,10 +113,10 @@ static int gfs2_dentry_delete(const struct dentry *dentry) { struct gfs2_inode *ginode; - if (!dentry->d_inode) + if (d_really_is_negative(dentry)) return 0; - ginode = GFS2_I(dentry->d_inode); + ginode = GFS2_I(d_inode(dentry)); if (!ginode->i_iopen_gh.gh_gl) return 0; diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index c41d255b6a7b..5d15e9498b48 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c @@ -49,7 +49,7 @@ static int gfs2_encode_fh(struct inode *inode, __u32 *p, int *len, fh[3] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF); *len = GFS2_SMALL_FH_SIZE; - if (!parent || inode == sb->s_root->d_inode) + if (!parent || inode == d_inode(sb->s_root)) return *len; ip = GFS2_I(parent); @@ -88,8 +88,8 @@ static int get_name_filldir(struct dir_context *ctx, const char *name, static int gfs2_get_name(struct dentry *parent, char *name, struct dentry *child) { - struct inode *dir = parent->d_inode; - struct inode *inode = child->d_inode; + struct inode *dir = d_inode(parent); + struct inode *inode = d_inode(child); struct gfs2_inode *dip, *ip; struct get_name_filldir gnfd = { .ctx.actor = get_name_filldir, @@ -128,7 +128,7 @@ static int gfs2_get_name(struct dentry *parent, char *name, static struct dentry *gfs2_get_parent(struct dentry *child) { - return d_obtain_alias(gfs2_lookupi(child->d_inode, &gfs2_qdotdot, 1)); + return d_obtain_alias(gfs2_lookupi(d_inode(child), &gfs2_qdotdot, 1)); } static struct dentry *gfs2_get_dentry(struct super_block *sb, diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 73c72253faac..e301850255d1 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -295,7 +295,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, if ((name->len == 1 && memcmp(name->name, ".", 1) == 0) || (name->len == 2 && memcmp(name->name, "..", 2) == 0 && - dir == sb->s_root->d_inode)) { + dir == d_inode(sb->s_root))) { igrab(dir); return dir; } @@ -687,7 +687,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, } gfs2_set_inode_flags(inode); - if ((GFS2_I(sdp->sd_root_dir->d_inode) == dip) || + if ((GFS2_I(d_inode(sdp->sd_root_dir)) == dip) || (dip->i_diskflags & GFS2_DIF_TOPDIR)) aflags |= GFS2_AF_ORLOV; @@ -888,7 +888,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, { struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder ghs[2]; struct buffer_head *dibh; @@ -1055,7 +1055,7 @@ static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, static int gfs2_unlink_inode(struct gfs2_inode *dip, const struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct gfs2_inode *ip = GFS2_I(inode); int error; @@ -1091,7 +1091,7 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) { struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder ghs[3]; struct gfs2_rgrpd *rgd; @@ -1241,7 +1241,7 @@ static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry, return PTR_ERR(d); if (d != NULL) dentry = d; - if (dentry->d_inode) { + if (d_really_is_positive(dentry)) { if (!(*opened & FILE_OPENED)) return finish_no_open(file, d); dput(d); @@ -1282,7 +1282,7 @@ static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) error = -EINVAL; break; } - if (dir == sb->s_root->d_inode) { + if (dir == d_inode(sb->s_root)) { error = 0; break; } @@ -1321,7 +1321,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, { struct gfs2_inode *odip = GFS2_I(odir); struct gfs2_inode *ndip = GFS2_I(ndir); - struct gfs2_inode *ip = GFS2_I(odentry->d_inode); + struct gfs2_inode *ip = GFS2_I(d_inode(odentry)); struct gfs2_inode *nip = NULL; struct gfs2_sbd *sdp = GFS2_SB(odir); struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }; @@ -1332,8 +1332,8 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, unsigned int x; int error; - if (ndentry->d_inode) { - nip = GFS2_I(ndentry->d_inode); + if (d_really_is_positive(ndentry)) { + nip = GFS2_I(d_inode(ndentry)); if (ip == nip) return 0; } @@ -1457,7 +1457,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, /* Check out the dir to be renamed */ if (dir_rename) { - error = gfs2_permission(odentry->d_inode, MAY_WRITE); + error = gfs2_permission(d_inode(odentry), MAY_WRITE); if (error) goto out_gunlock; } @@ -1550,7 +1550,7 @@ out: static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct gfs2_inode *ip = GFS2_I(dentry->d_inode); + struct gfs2_inode *ip = GFS2_I(d_inode(dentry)); struct gfs2_holder i_gh; struct buffer_head *dibh; unsigned int size; @@ -1740,7 +1740,7 @@ out: static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder i_gh; int error; @@ -1796,7 +1796,7 @@ out: static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder gh; int error; @@ -1819,7 +1819,7 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, static int gfs2_setxattr(struct dentry *dentry, const char *name, const void *data, size_t size, int flags) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder gh; int ret; @@ -1839,7 +1839,7 @@ static int gfs2_setxattr(struct dentry *dentry, const char *name, static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, void *data, size_t size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder gh; int ret; @@ -1860,7 +1860,7 @@ static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, static int gfs2_removexattr(struct dentry *dentry, const char *name) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder gh; int ret; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index efc8e254787c..35b49f44c72f 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -647,7 +647,7 @@ out_unlock: static int init_journal(struct gfs2_sbd *sdp, int undo) { - struct inode *master = sdp->sd_master_dir->d_inode; + struct inode *master = d_inode(sdp->sd_master_dir); struct gfs2_holder ji_gh; struct gfs2_inode *ip; int jindex = 1; @@ -782,7 +782,7 @@ static struct lock_class_key gfs2_quota_imutex_key; static int init_inodes(struct gfs2_sbd *sdp, int undo) { int error = 0; - struct inode *master = sdp->sd_master_dir->d_inode; + struct inode *master = d_inode(sdp->sd_master_dir); if (undo) goto fail_qinode; @@ -848,7 +848,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) char buf[30]; int error = 0; struct gfs2_inode *ip; - struct inode *master = sdp->sd_master_dir->d_inode; + struct inode *master = d_inode(sdp->sd_master_dir); if (sdp->sd_args.ar_spectator) return 0; @@ -1357,7 +1357,7 @@ static struct dentry *gfs2_mount_meta(struct file_system_type *fs_type, return ERR_PTR(error); } s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super, flags, - path.dentry->d_inode->i_sb->s_bdev); + d_inode(path.dentry)->i_sb->s_bdev); path_put(&path); if (IS_ERR(s)) { pr_warn("gfs2 mount does not exist\n"); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 1666382b198d..859c6edbf81a 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1171,7 +1171,7 @@ static int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *s static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct super_block *sb = dentry->d_inode->i_sb; + struct super_block *sb = d_inode(dentry)->i_sb; struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_statfs_change_host sc; int error; diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index 0b81f783f787..40a8e53b2293 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c @@ -420,7 +420,7 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) { - struct gfs2_inode *ip = GFS2_I(dentry->d_inode); + struct gfs2_inode *ip = GFS2_I(d_inode(dentry)); struct gfs2_ea_request er; struct gfs2_holder i_gh; int error; @@ -586,7 +586,7 @@ out: static int gfs2_xattr_get(struct dentry *dentry, const char *name, void *buffer, size_t size, int type) { - struct gfs2_inode *ip = GFS2_I(dentry->d_inode); + struct gfs2_inode *ip = GFS2_I(d_inode(dentry)); struct gfs2_ea_location el; int error; @@ -1230,7 +1230,7 @@ int __gfs2_xattr_set(struct inode *inode, const char *name, static int gfs2_xattr_set(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int type) { - return __gfs2_xattr_set(dentry->d_inode, name, value, + return __gfs2_xattr_set(d_inode(dentry), name, value, size, flags, type); } diff --git a/fs/hfs/attr.c b/fs/hfs/attr.c index e057ec542a6a..8d931b157bbe 100644 --- a/fs/hfs/attr.c +++ b/fs/hfs/attr.c @@ -16,7 +16,7 @@ int hfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct hfs_find_data fd; hfs_cat_rec rec; struct hfs_cat_file *file; @@ -59,7 +59,7 @@ out: ssize_t hfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct hfs_find_data fd; hfs_cat_rec rec; struct hfs_cat_file *file; @@ -105,7 +105,7 @@ out: ssize_t hfs_listxattr(struct dentry *dentry, char *buffer, size_t size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode)) return -EOPNOTSUPP; diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 145566851e7a..eb2bbca945c5 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -253,7 +253,7 @@ static int hfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) */ static int hfs_remove(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int res; if (S_ISDIR(inode->i_mode) && inode->i_size != 2) @@ -285,18 +285,18 @@ static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry, int res; /* Unlink destination if it already exists */ - if (new_dentry->d_inode) { + if (d_really_is_positive(new_dentry)) { res = hfs_remove(new_dir, new_dentry); if (res) return res; } - res = hfs_cat_move(old_dentry->d_inode->i_ino, + res = hfs_cat_move(d_inode(old_dentry)->i_ino, old_dir, &old_dentry->d_name, new_dir, &new_dentry->d_name); if (!res) hfs_cat_build_key(old_dir->i_sb, - (btree_key *)&HFS_I(old_dentry->d_inode)->cat_key, + (btree_key *)&HFS_I(d_inode(old_dentry))->cat_key, new_dir->i_ino, &new_dentry->d_name); return res; } diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 75fd5d873c19..b99ebddb10cb 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -600,7 +600,7 @@ static int hfs_file_release(struct inode *inode, struct file *file) int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct hfs_sb_info *hsb = HFS_SB(inode->i_sb); int error; diff --git a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c index 91b91fd3a901..2875961fdc10 100644 --- a/fs/hfs/sysdep.c +++ b/fs/hfs/sysdep.c @@ -21,7 +21,7 @@ static int hfs_revalidate_dentry(struct dentry *dentry, unsigned int flags) if (flags & LOOKUP_RCU) return -ECHILD; - inode = dentry->d_inode; + inode = d_inode(dentry); if(!inode) return 1; diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index f0235c1640af..e7ef1c72ef3d 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -81,7 +81,7 @@ again: HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)-> create_date || entry.file.create_date == - HFSPLUS_I(sb->s_root->d_inode)-> + HFSPLUS_I(d_inode(sb->s_root))-> create_date) && HFSPLUS_SB(sb)->hidden_dir) { struct qstr str; @@ -296,8 +296,8 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir, struct dentry *dst_dentry) { struct hfsplus_sb_info *sbi = HFSPLUS_SB(dst_dir->i_sb); - struct inode *inode = src_dentry->d_inode; - struct inode *src_dir = src_dentry->d_parent->d_inode; + struct inode *inode = d_inode(src_dentry); + struct inode *src_dir = d_inode(src_dentry->d_parent); struct qstr str; char name[32]; u32 cnid, id; @@ -353,7 +353,7 @@ out: static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) { struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct qstr str; char name[32]; u32 cnid; @@ -410,7 +410,7 @@ out: static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry) { struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int res; if (inode->i_size != 2) @@ -529,7 +529,7 @@ static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry, int res; /* Unlink destination if it already exists */ - if (new_dentry->d_inode) { + if (d_really_is_positive(new_dentry)) { if (d_is_dir(new_dentry)) res = hfsplus_rmdir(new_dir, new_dentry); else diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index a43811f90935..8ad4c594898b 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -243,7 +243,7 @@ static int hfsplus_file_release(struct inode *inode, struct file *file) static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error; error = inode_change_ok(inode, attr); diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index d3ff5cc317d7..ac807073c453 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c @@ -26,7 +26,7 @@ static int hfsplus_ioctl_bless(struct file *file, int __user *user_flags) { struct dentry *dentry = file->f_path.dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); struct hfsplus_vh *vh = sbi->s_vhdr; struct hfsplus_vh *bvh = sbi->s_backup_vhdr; diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c index d98094a9f476..964d922f647e 100644 --- a/fs/hfsplus/xattr.c +++ b/fs/hfsplus/xattr.c @@ -574,7 +574,7 @@ static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry, char *buffer, size_t size) { ssize_t res = 0; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct hfs_find_data fd; u16 entry_type; u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)]; @@ -642,7 +642,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) { ssize_t err; ssize_t res = 0; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct hfs_find_data fd; u16 key_len = 0; struct hfsplus_attr_key attr_key; diff --git a/fs/hfsplus/xattr.h b/fs/hfsplus/xattr.h index 288530cf80b5..a1629cfe37d3 100644 --- a/fs/hfsplus/xattr.h +++ b/fs/hfsplus/xattr.h @@ -24,7 +24,7 @@ int __hfsplus_setxattr(struct inode *inode, const char *name, static inline int hfsplus_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - return __hfsplus_setxattr(dentry->d_inode, name, value, size, flags); + return __hfsplus_setxattr(d_inode(dentry), name, value, size, flags); } ssize_t __hfsplus_getxattr(struct inode *inode, const char *name, @@ -35,7 +35,7 @@ static inline ssize_t hfsplus_getxattr(struct dentry *dentry, void *value, size_t size) { - return __hfsplus_getxattr(dentry->d_inode, name, value, size); + return __hfsplus_getxattr(d_inode(dentry), name, value, size); } ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size); diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index e021188ca110..b827aa4248d4 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -795,7 +795,7 @@ static int hostfs_permission(struct inode *ino, int desired) static int hostfs_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct hostfs_iattr attrs; char *name; int err; diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 7ce4b74234a1..933c73780813 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -257,7 +257,7 @@ void hpfs_write_inode_nolock(struct inode *i) int hpfs_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error = -EINVAL; hpfs_lock(inode->i_sb); diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index bdbc2c3080a4..a0872f239f04 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -359,7 +359,7 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry) unsigned len = dentry->d_name.len; struct quad_buffer_head qbh; struct hpfs_dirent *de; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); dnode_secno dno; int r; int rep = 0; @@ -433,7 +433,7 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) unsigned len = dentry->d_name.len; struct quad_buffer_head qbh; struct hpfs_dirent *de; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); dnode_secno dno; int n_items = 0; int err; @@ -522,8 +522,8 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, unsigned old_len = old_dentry->d_name.len; const unsigned char *new_name = new_dentry->d_name.name; unsigned new_len = new_dentry->d_name.len; - struct inode *i = old_dentry->d_inode; - struct inode *new_inode = new_dentry->d_inode; + struct inode *i = d_inode(old_dentry); + struct inode *new_inode = d_inode(new_dentry); struct quad_buffer_head qbh, qbh1; struct hpfs_dirent *dep, *nde; struct hpfs_dirent de; diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index 043ac9d77262..fa2bd5366ecf 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c @@ -153,9 +153,9 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, return ERR_PTR(-ENOENT); parent = HPPFS_I(ino)->proc_dentry; - mutex_lock(&parent->d_inode->i_mutex); + mutex_lock(&d_inode(parent)->i_mutex); proc_dentry = lookup_one_len(name->name, parent, name->len); - mutex_unlock(&parent->d_inode->i_mutex); + mutex_unlock(&d_inode(parent)->i_mutex); if (IS_ERR(proc_dentry)) return proc_dentry; @@ -637,25 +637,25 @@ static const struct super_operations hppfs_sbops = { static int hppfs_readlink(struct dentry *dentry, char __user *buffer, int buflen) { - struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; - return proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer, + struct dentry *proc_dentry = HPPFS_I(d_inode(dentry))->proc_dentry; + return d_inode(proc_dentry)->i_op->readlink(proc_dentry, buffer, buflen); } static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; + struct dentry *proc_dentry = HPPFS_I(d_inode(dentry))->proc_dentry; - return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd); + return d_inode(proc_dentry)->i_op->follow_link(proc_dentry, nd); } static void hppfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) { - struct dentry *proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; + struct dentry *proc_dentry = HPPFS_I(d_inode(dentry))->proc_dentry; - if (proc_dentry->d_inode->i_op->put_link) - proc_dentry->d_inode->i_op->put_link(proc_dentry, nd, cookie); + if (d_inode(proc_dentry)->i_op->put_link) + d_inode(proc_dentry)->i_op->put_link(proc_dentry, nd, cookie); } static const struct inode_operations hppfs_dir_iops = { @@ -670,7 +670,7 @@ static const struct inode_operations hppfs_link_iops = { static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) { - struct inode *proc_ino = dentry->d_inode; + struct inode *proc_ino = d_inode(dentry); struct inode *inode = new_inode(sb); if (!inode) { diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 8c2dad629e7c..7a20dbfd1e38 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -391,7 +391,7 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct hstate *h = hstate_inode(inode); int error; unsigned int ia_valid = attr->ia_valid; @@ -585,7 +585,7 @@ static int hugetlbfs_migrate_page(struct address_space *mapping, static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb); - struct hstate *h = hstate_inode(dentry->d_inode); + struct hstate *h = hstate_inode(d_inode(dentry)); buf->f_type = HUGETLBFS_MAGIC; buf->f_bsize = huge_page_size(h); diff --git a/fs/isofs/export.c b/fs/isofs/export.c index 12088d8de3fa..0c5f721b4e91 100644 --- a/fs/isofs/export.c +++ b/fs/isofs/export.c @@ -44,7 +44,7 @@ static struct dentry *isofs_export_get_parent(struct dentry *child) { unsigned long parent_block = 0; unsigned long parent_offset = 0; - struct inode *child_inode = child->d_inode; + struct inode *child_inode = d_inode(child); struct iso_inode_info *e_child_inode = ISOFS_I(child_inode); struct iso_directory_record *de = NULL; struct buffer_head * bh = NULL; diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index f21b6fb5e4c4..1ba5c97943b8 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -224,14 +224,14 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) { struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb); struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); - struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(dentry->d_inode); + struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode(dentry)); int ret; uint32_t now = get_seconds(); ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, dentry->d_name.len, dead_f, now); if (dead_f->inocache) - set_nlink(dentry->d_inode, dead_f->inocache->pino_nlink); + set_nlink(d_inode(dentry), dead_f->inocache->pino_nlink); if (!ret) dir_i->i_mtime = dir_i->i_ctime = ITIME(now); return ret; @@ -241,8 +241,8 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) { - struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_inode->i_sb); - struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); + struct jffs2_sb_info *c = JFFS2_SB_INFO(d_inode(old_dentry)->i_sb); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry)); struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); int ret; uint8_t type; @@ -256,7 +256,7 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de return -EPERM; /* XXX: This is ugly */ - type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; + type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12; if (!type) type = DT_REG; now = get_seconds(); @@ -264,11 +264,11 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de if (!ret) { mutex_lock(&f->sem); - set_nlink(old_dentry->d_inode, ++f->inocache->pino_nlink); + set_nlink(d_inode(old_dentry), ++f->inocache->pino_nlink); mutex_unlock(&f->sem); - d_instantiate(dentry, old_dentry->d_inode); + d_instantiate(dentry, d_inode(old_dentry)); dir_i->i_mtime = dir_i->i_ctime = ITIME(now); - ihold(old_dentry->d_inode); + ihold(d_inode(old_dentry)); } return ret; } @@ -585,7 +585,7 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) { struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb); struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); - struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(dentry)); struct jffs2_full_dirent *fd; int ret; uint32_t now = get_seconds(); @@ -599,7 +599,7 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) dentry->d_name.len, f, now); if (!ret) { dir_i->i_mtime = dir_i->i_ctime = ITIME(now); - clear_nlink(dentry->d_inode); + clear_nlink(d_inode(dentry)); drop_nlink(dir_i); } return ret; @@ -770,8 +770,8 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, * the VFS can't check whether the victim is empty. The filesystem * needs to do that for itself. */ - if (new_dentry->d_inode) { - victim_f = JFFS2_INODE_INFO(new_dentry->d_inode); + if (d_really_is_positive(new_dentry)) { + victim_f = JFFS2_INODE_INFO(d_inode(new_dentry)); if (d_is_dir(new_dentry)) { struct jffs2_full_dirent *fd; @@ -794,12 +794,12 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, /* Make a hard link */ /* XXX: This is ugly */ - type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; + type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12; if (!type) type = DT_REG; now = get_seconds(); ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), - old_dentry->d_inode->i_ino, type, + d_inode(old_dentry)->i_ino, type, new_dentry->d_name.name, new_dentry->d_name.len, now); if (ret) @@ -808,9 +808,9 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, if (victim_f) { /* There was a victim. Kill it off nicely */ if (d_is_dir(new_dentry)) - clear_nlink(new_dentry->d_inode); + clear_nlink(d_inode(new_dentry)); else - drop_nlink(new_dentry->d_inode); + drop_nlink(d_inode(new_dentry)); /* Don't oops if the victim was a dirent pointing to an inode which didn't exist. */ if (victim_f->inocache) { @@ -836,9 +836,9 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, if (ret) { /* Oh shit. We really ought to make a single node which can do both atomically */ - struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry)); mutex_lock(&f->sem); - inc_nlink(old_dentry->d_inode); + inc_nlink(d_inode(old_dentry)); if (f->inocache && !d_is_dir(old_dentry)) f->inocache->pino_nlink++; mutex_unlock(&f->sem); @@ -846,8 +846,8 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n", __func__, ret); /* Might as well let the VFS know */ - d_instantiate(new_dentry, old_dentry->d_inode); - ihold(old_dentry->d_inode); + d_instantiate(new_dentry, d_inode(old_dentry)); + ihold(d_inode(old_dentry)); new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now); return ret; } diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 601afd1afddf..fe5ea080b4ec 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -190,7 +190,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int rc; rc = inode_change_ok(inode, iattr); diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c index aca97f35b292..d4b43fb7adb1 100644 --- a/fs/jffs2/security.c +++ b/fs/jffs2/security.c @@ -54,7 +54,7 @@ static int jffs2_security_getxattr(struct dentry *dentry, const char *name, if (!strcmp(name, "")) return -EINVAL; - return do_jffs2_getxattr(dentry->d_inode, JFFS2_XPREFIX_SECURITY, + return do_jffs2_getxattr(d_inode(dentry), JFFS2_XPREFIX_SECURITY, name, buffer, size); } @@ -64,7 +64,7 @@ static int jffs2_security_setxattr(struct dentry *dentry, const char *name, if (!strcmp(name, "")) return -EINVAL; - return do_jffs2_setxattr(dentry->d_inode, JFFS2_XPREFIX_SECURITY, + return do_jffs2_setxattr(d_inode(dentry), JFFS2_XPREFIX_SECURITY, name, buffer, size, flags); } diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 3d76f28a2ba9..d86c5e3176a1 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -140,14 +140,14 @@ static struct dentry *jffs2_get_parent(struct dentry *child) BUG_ON(!d_is_dir(child)); - f = JFFS2_INODE_INFO(child->d_inode); + f = JFFS2_INODE_INFO(d_inode(child)); pino = f->inocache->pino_nlink; JFFS2_DEBUG("Parent of directory ino #%u is #%u\n", f->inocache->ino, pino); - return d_obtain_alias(jffs2_iget(child->d_inode->i_sb, pino)); + return d_obtain_alias(jffs2_iget(d_inode(child)->i_sb, pino)); } static const struct export_operations jffs2_export_ops = { diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index c7c77b0dfccd..1fefa25d0fa5 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c @@ -31,7 +31,7 @@ const struct inode_operations jffs2_symlink_inode_operations = static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(dentry)); char *p = (char *)f->target; /* diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index d72817ac51f6..c4dd342d13a7 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -960,7 +960,7 @@ static const struct xattr_handler *xprefix_to_handler(int xprefix) { ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_inode_cache *ic = f->inocache; diff --git a/fs/jffs2/xattr_trusted.c b/fs/jffs2/xattr_trusted.c index 1c868194c504..ceaf9c693225 100644 --- a/fs/jffs2/xattr_trusted.c +++ b/fs/jffs2/xattr_trusted.c @@ -21,7 +21,7 @@ static int jffs2_trusted_getxattr(struct dentry *dentry, const char *name, { if (!strcmp(name, "")) return -EINVAL; - return do_jffs2_getxattr(dentry->d_inode, JFFS2_XPREFIX_TRUSTED, + return do_jffs2_getxattr(d_inode(dentry), JFFS2_XPREFIX_TRUSTED, name, buffer, size); } @@ -30,7 +30,7 @@ static int jffs2_trusted_setxattr(struct dentry *dentry, const char *name, { if (!strcmp(name, "")) return -EINVAL; - return do_jffs2_setxattr(dentry->d_inode, JFFS2_XPREFIX_TRUSTED, + return do_jffs2_setxattr(d_inode(dentry), JFFS2_XPREFIX_TRUSTED, name, buffer, size, flags); } diff --git a/fs/jffs2/xattr_user.c b/fs/jffs2/xattr_user.c index 916b5c966039..a71391eba514 100644 --- a/fs/jffs2/xattr_user.c +++ b/fs/jffs2/xattr_user.c @@ -21,7 +21,7 @@ static int jffs2_user_getxattr(struct dentry *dentry, const char *name, { if (!strcmp(name, "")) return -EINVAL; - return do_jffs2_getxattr(dentry->d_inode, JFFS2_XPREFIX_USER, + return do_jffs2_getxattr(d_inode(dentry), JFFS2_XPREFIX_USER, name, buffer, size); } @@ -30,7 +30,7 @@ static int jffs2_user_setxattr(struct dentry *dentry, const char *name, { if (!strcmp(name, "")) return -EINVAL; - return do_jffs2_setxattr(dentry->d_inode, JFFS2_XPREFIX_USER, + return do_jffs2_setxattr(d_inode(dentry), JFFS2_XPREFIX_USER, name, buffer, size, flags); } diff --git a/fs/jfs/file.c b/fs/jfs/file.c index ae46788b9723..e98d39d75cf4 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -100,7 +100,7 @@ static int jfs_release(struct inode *inode, struct file *file) int jfs_setattr(struct dentry *dentry, struct iattr *iattr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int rc; rc = inode_change_ok(inode, iattr); diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 38fdc533f4ec..66db7bc0ed10 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -346,7 +346,7 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) { int rc; tid_t tid; /* transaction id */ - struct inode *ip = dentry->d_inode; + struct inode *ip = d_inode(dentry); ino_t ino; struct component_name dname; struct inode *iplist[2]; @@ -472,7 +472,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) { int rc; tid_t tid; /* transaction id */ - struct inode *ip = dentry->d_inode; + struct inode *ip = d_inode(dentry); ino_t ino; struct component_name dname; /* object name */ struct inode *iplist[2]; @@ -791,7 +791,7 @@ static int jfs_link(struct dentry *old_dentry, { int rc; tid_t tid; - struct inode *ip = old_dentry->d_inode; + struct inode *ip = d_inode(old_dentry); ino_t ino; struct component_name dname; struct btstack btstack; @@ -879,7 +879,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, struct component_name dname; int ssize; /* source pathname size */ struct btstack btstack; - struct inode *ip = dentry->d_inode; + struct inode *ip = d_inode(dentry); unchar *i_fastsymlink; s64 xlen = 0; int bmask = 0, xsize; @@ -1086,8 +1086,8 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, dquot_initialize(old_dir); dquot_initialize(new_dir); - old_ip = old_dentry->d_inode; - new_ip = new_dentry->d_inode; + old_ip = d_inode(old_dentry); + new_ip = d_inode(new_dentry); if ((rc = get_UCSname(&old_dname, old_dentry))) goto out1; @@ -1500,9 +1500,9 @@ struct dentry *jfs_get_parent(struct dentry *dentry) unsigned long parent_ino; parent_ino = - le32_to_cpu(JFS_IP(dentry->d_inode)->i_dtroot.header.idotdot); + le32_to_cpu(JFS_IP(d_inode(dentry))->i_dtroot.header.idotdot); - return d_obtain_alias(jfs_iget(dentry->d_inode->i_sb, parent_ino)); + return d_obtain_alias(jfs_iget(d_inode(dentry)->i_sb, parent_ino)); } const struct inode_operations jfs_dir_inode_operations = { @@ -1578,7 +1578,7 @@ static int jfs_ci_revalidate(struct dentry *dentry, unsigned int flags) * positive dentry isn't good idea. So it's unsupported like * rename("filename", "FILENAME") for now. */ - if (dentry->d_inode) + if (d_really_is_positive(dentry)) return 1; /* diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c index 205b946d8e0d..80f42bcc4ef1 100644 --- a/fs/jfs/symlink.c +++ b/fs/jfs/symlink.c @@ -24,7 +24,7 @@ static void *jfs_follow_link(struct dentry *dentry, struct nameidata *nd) { - char *s = JFS_IP(dentry->d_inode)->i_inline; + char *s = JFS_IP(d_inode(dentry))->i_inline; nd_set_link(nd, s); return NULL; } diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index 46325d5c34fc..48b15a6e5558 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -849,7 +849,7 @@ int __jfs_setxattr(tid_t tid, struct inode *inode, const char *name, int jfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t value_len, int flags) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct jfs_inode_info *ji = JFS_IP(inode); int rc; tid_t tid; @@ -872,7 +872,7 @@ int jfs_setxattr(struct dentry *dentry, const char *name, const void *value, tid = txBegin(inode->i_sb, 0); mutex_lock(&ji->commit_mutex); - rc = __jfs_setxattr(tid, dentry->d_inode, name, value, value_len, + rc = __jfs_setxattr(tid, d_inode(dentry), name, value, value_len, flags); if (!rc) rc = txCommit(tid, 1, &inode, 0); @@ -959,7 +959,7 @@ ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data, return -EOPNOTSUPP; } - err = __jfs_getxattr(dentry->d_inode, name, data, buf_size); + err = __jfs_getxattr(d_inode(dentry), name, data, buf_size); return err; } @@ -976,7 +976,7 @@ static inline int can_list(struct jfs_ea *ea) ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); char *buffer; ssize_t size = 0; int xattr_size; @@ -1029,7 +1029,7 @@ ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size) int jfs_removexattr(struct dentry *dentry, const char *name) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct jfs_inode_info *ji = JFS_IP(inode); int rc; tid_t tid; @@ -1047,7 +1047,7 @@ int jfs_removexattr(struct dentry *dentry, const char *name) tid = txBegin(inode->i_sb, 0); mutex_lock(&ji->commit_mutex); - rc = __jfs_setxattr(tid, dentry->d_inode, name, NULL, 0, XATTR_REPLACE); + rc = __jfs_setxattr(tid, d_inode(dentry), name, NULL, 0, XATTR_REPLACE); if (!rc) rc = txCommit(tid, 1, &inode, 0); txEnd(tid); diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 6acc9648f986..f131fc23ffc4 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -444,7 +444,7 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) return -ECHILD; /* Always perform fresh lookup for negatives */ - if (!dentry->d_inode) + if (d_really_is_negative(dentry)) goto out_bad_unlocked; kn = dentry->d_fsdata; diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index 9000874a945b..2da8493a380b 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -111,7 +111,7 @@ int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct kernfs_node *kn = dentry->d_fsdata; int error; @@ -172,11 +172,11 @@ int kernfs_iop_setxattr(struct dentry *dentry, const char *name, if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; - error = security_inode_setsecurity(dentry->d_inode, suffix, + error = security_inode_setsecurity(d_inode(dentry), suffix, value, size, flags); if (error) return error; - error = security_inode_getsecctx(dentry->d_inode, + error = security_inode_getsecctx(d_inode(dentry), &secdata, &secdata_len); if (error) return error; @@ -271,7 +271,7 @@ int kernfs_iop_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct kernfs_node *kn = dentry->d_fsdata; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); mutex_lock(&kernfs_mutex); kernfs_refresh_inode(kn, inode); diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c index 6bdc347008f5..4cf38f118549 100644 --- a/fs/logfs/dir.c +++ b/fs/logfs/dir.c @@ -213,7 +213,7 @@ static void abort_transaction(struct inode *inode, struct logfs_transaction *ta) static int logfs_unlink(struct inode *dir, struct dentry *dentry) { struct logfs_super *super = logfs_super(dir->i_sb); - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct logfs_transaction *ta; struct page *page; pgoff_t index; @@ -271,7 +271,7 @@ static inline int logfs_empty_dir(struct inode *dir) static int logfs_rmdir(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); if (!logfs_empty_dir(inode)) return -ENOTEMPTY; @@ -537,7 +537,7 @@ static int logfs_symlink(struct inode *dir, struct dentry *dentry, static int logfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; ihold(inode); @@ -607,7 +607,7 @@ static int logfs_rename_cross(struct inode *old_dir, struct dentry *old_dentry, /* 2. write target dd */ mutex_lock(&super->s_dirop_mutex); logfs_add_transaction(new_dir, ta); - err = logfs_write_dir(new_dir, new_dentry, old_dentry->d_inode); + err = logfs_write_dir(new_dir, new_dentry, d_inode(old_dentry)); if (!err) err = write_inode(new_dir); @@ -658,8 +658,8 @@ static int logfs_rename_target(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct logfs_super *super = logfs_super(old_dir->i_sb); - struct inode *old_inode = old_dentry->d_inode; - struct inode *new_inode = new_dentry->d_inode; + struct inode *old_inode = d_inode(old_dentry); + struct inode *new_inode = d_inode(new_dentry); int isdir = S_ISDIR(old_inode->i_mode); struct logfs_disk_dentry dd; struct logfs_transaction *ta; @@ -719,7 +719,7 @@ out: static int logfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { - if (new_dentry->d_inode) + if (d_really_is_positive(new_dentry)) return logfs_rename_target(old_dir, old_dentry, new_dir, new_dentry); return logfs_rename_cross(old_dir, old_dentry, new_dir, new_dentry); diff --git a/fs/logfs/file.c b/fs/logfs/file.c index b2c13f739ffa..1a6f0167b16a 100644 --- a/fs/logfs/file.c +++ b/fs/logfs/file.c @@ -241,7 +241,7 @@ int logfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) static int logfs_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int err = 0; err = inode_change_ok(inode, attr); diff --git a/fs/minix/dir.c b/fs/minix/dir.c index dfaf6fa9b7b5..118e4e7bc935 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c @@ -156,7 +156,7 @@ minix_dirent *minix_find_entry(struct dentry *dentry, struct page **res_page) { const char * name = dentry->d_name.name; int namelen = dentry->d_name.len; - struct inode * dir = dentry->d_parent->d_inode; + struct inode * dir = d_inode(dentry->d_parent); struct super_block * sb = dir->i_sb; struct minix_sb_info * sbi = minix_sb(sb); unsigned long n; @@ -203,7 +203,7 @@ found: int minix_add_link(struct dentry *dentry, struct inode *inode) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); const char * name = dentry->d_name.name; int namelen = dentry->d_name.len; struct super_block * sb = dir->i_sb; diff --git a/fs/minix/file.c b/fs/minix/file.c index 6d63e27ec961..94f0eb9a6e2c 100644 --- a/fs/minix/file.c +++ b/fs/minix/file.c @@ -23,7 +23,7 @@ const struct file_operations minix_file_operations = { static int minix_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error; error = inode_change_ok(inode, attr); diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 3f57af196a7d..1182d1e26a9c 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -626,8 +626,8 @@ static int minix_write_inode(struct inode *inode, struct writeback_control *wbc) int minix_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct super_block *sb = dentry->d_sb; - generic_fillattr(dentry->d_inode, stat); - if (INODE_VERSION(dentry->d_inode) == MINIX_V1) + generic_fillattr(d_inode(dentry), stat); + if (INODE_VERSION(d_inode(dentry)) == MINIX_V1) stat->blocks = (BLOCK_SIZE / 512) * V1_minix_blocks(stat->size, sb); else stat->blocks = (sb->s_blocksize / 512) * V2_minix_blocks(stat->size, sb); diff --git a/fs/minix/namei.c b/fs/minix/namei.c index cd950e2331b6..a795a11e50c7 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -104,7 +104,7 @@ out_fail: static int minix_link(struct dentry * old_dentry, struct inode * dir, struct dentry *dentry) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); inode->i_ctime = CURRENT_TIME_SEC; inode_inc_link_count(inode); @@ -151,7 +151,7 @@ out_dir: static int minix_unlink(struct inode * dir, struct dentry *dentry) { int err = -ENOENT; - struct inode * inode = dentry->d_inode; + struct inode * inode = d_inode(dentry); struct page * page; struct minix_dir_entry * de; @@ -171,7 +171,7 @@ end_unlink: static int minix_rmdir(struct inode * dir, struct dentry *dentry) { - struct inode * inode = dentry->d_inode; + struct inode * inode = d_inode(dentry); int err = -ENOTEMPTY; if (minix_empty_dir(inode)) { @@ -187,8 +187,8 @@ static int minix_rmdir(struct inode * dir, struct dentry *dentry) static int minix_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir, struct dentry *new_dentry) { - struct inode * old_inode = old_dentry->d_inode; - struct inode * new_inode = new_dentry->d_inode; + struct inode * old_inode = d_inode(old_dentry); + struct inode * new_inode = d_inode(new_dentry); struct page * dir_page = NULL; struct minix_dir_entry * dir_de = NULL; struct page * old_page; diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index e7ca827d7694..80021c709af9 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -127,7 +127,7 @@ static inline int ncp_case_sensitive(const struct inode *i) static int ncp_hash_dentry(const struct dentry *dentry, struct qstr *this) { - struct inode *inode = ACCESS_ONCE(dentry->d_inode); + struct inode *inode = d_inode_rcu(dentry); if (!inode) return 0; @@ -162,7 +162,7 @@ ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry, if (len != name->len) return 1; - pinode = ACCESS_ONCE(parent->d_inode); + pinode = d_inode_rcu(parent); if (!pinode) return 1; @@ -180,7 +180,7 @@ ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry, static int ncp_delete_dentry(const struct dentry * dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); if (inode) { if (is_bad_inode(inode)) @@ -224,7 +224,7 @@ ncp_force_unlink(struct inode *dir, struct dentry* dentry) memset(&info, 0, sizeof(info)); /* remove the Read-Only flag on the NW server */ - inode = dentry->d_inode; + inode = d_inode(dentry); old_nwattr = NCP_FINFO(inode)->nwattr; info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT); @@ -254,7 +254,7 @@ ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_na { struct nw_modify_dos_info info; int res=0x90,res2; - struct inode *old_inode = old_dentry->d_inode; + struct inode *old_inode = d_inode(old_dentry); __le32 old_nwattr = NCP_FINFO(old_inode)->nwattr; __le32 new_nwattr = 0; /* shut compiler warning */ int old_nwattr_changed = 0; @@ -268,8 +268,8 @@ ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_na res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info); if (!res2) old_nwattr_changed = 1; - if (new_dentry && new_dentry->d_inode) { - new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr; + if (new_dentry && d_really_is_positive(new_dentry)) { + new_nwattr = NCP_FINFO(d_inode(new_dentry))->nwattr; info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info); if (!res2) @@ -324,9 +324,9 @@ ncp_lookup_validate(struct dentry *dentry, unsigned int flags) return -ECHILD; parent = dget_parent(dentry); - dir = parent->d_inode; + dir = d_inode(parent); - if (!dentry->d_inode) + if (d_really_is_negative(dentry)) goto finished; server = NCP_SERVER(dir); @@ -367,7 +367,7 @@ ncp_lookup_validate(struct dentry *dentry, unsigned int flags) * what we remember, it's not valid any more. */ if (!res) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); mutex_lock(&inode->i_mutex); if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) { @@ -388,7 +388,7 @@ finished: static time_t ncp_obtain_mtime(struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ncp_server *server = NCP_SERVER(inode); struct nw_info_struct i; @@ -404,7 +404,7 @@ static time_t ncp_obtain_mtime(struct dentry *dentry) static inline void ncp_invalidate_dircache_entries(struct dentry *parent) { - struct ncp_server *server = NCP_SERVER(parent->d_inode); + struct ncp_server *server = NCP_SERVER(d_inode(parent)); struct dentry *dentry; spin_lock(&parent->d_lock); @@ -418,7 +418,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent) static int ncp_readdir(struct file *file, struct dir_context *ctx) { struct dentry *dentry = file->f_path.dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct page *page = NULL; struct ncp_server *server = NCP_SERVER(inode); union ncp_dir_cache *cache = NULL; @@ -491,13 +491,13 @@ static int ncp_readdir(struct file *file, struct dir_context *ctx) goto invalid_cache; } spin_unlock(&dentry->d_lock); - if (!dent->d_inode) { + if (d_really_is_negative(dent)) { dput(dent); goto invalid_cache; } over = !dir_emit(ctx, dent->d_name.name, dent->d_name.len, - dent->d_inode->i_ino, DT_UNKNOWN); + d_inode(dent)->i_ino, DT_UNKNOWN); dput(dent); if (over) goto finished; @@ -571,7 +571,7 @@ static void ncp_d_prune(struct dentry *dentry) { if (!dentry->d_fsdata) /* not referenced from page cache */ return; - NCP_FINFO(dentry->d_parent->d_inode)->flags &= ~NCPI_DIR_CACHE; + NCP_FINFO(d_inode(dentry->d_parent))->flags &= ~NCPI_DIR_CACHE; } static int @@ -580,7 +580,7 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx, int inval_childs) { struct dentry *newdent, *dentry = file->f_path.dentry; - struct inode *dir = dentry->d_inode; + struct inode *dir = d_inode(dentry); struct ncp_cache_control ctl = *ctrl; struct qstr qname; int valid = 0; @@ -621,7 +621,7 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx, dentry_update_name_case(newdent, &qname); } - if (!newdent->d_inode) { + if (d_really_is_negative(newdent)) { struct inode *inode; entry->opened = 0; @@ -637,7 +637,7 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx, spin_unlock(&dentry->d_lock); } } else { - struct inode *inode = newdent->d_inode; + struct inode *inode = d_inode(newdent); mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); ncp_update_inode2(inode, entry); @@ -659,10 +659,10 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx, ctl.cache = kmap(ctl.page); } if (ctl.cache) { - if (newdent->d_inode) { + if (d_really_is_positive(newdent)) { newdent->d_fsdata = newdent; ctl.cache->dentry[ctl.idx] = newdent; - ino = newdent->d_inode->i_ino; + ino = d_inode(newdent)->i_ino; ncp_new_dentry(newdent); } valid = 1; @@ -807,7 +807,7 @@ int ncp_conn_logged_in(struct super_block *sb) } dent = sb->s_root; if (dent) { - struct inode* ino = dent->d_inode; + struct inode* ino = d_inode(dent); if (ino) { ncp_update_known_namespace(server, volNumber, NULL); NCP_FINFO(ino)->volNumber = volNumber; @@ -815,7 +815,7 @@ int ncp_conn_logged_in(struct super_block *sb) NCP_FINFO(ino)->DosDirNum = DosDirNum; result = 0; } else { - ncp_dbg(1, "sb->s_root->d_inode == NULL!\n"); + ncp_dbg(1, "d_inode(sb->s_root) == NULL!\n"); } } else { ncp_dbg(1, "sb->s_root == NULL!\n"); @@ -1055,7 +1055,7 @@ out: static int ncp_unlink(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ncp_server *server; int error; diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 01a9e16e9782..9605a2f63549 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -812,7 +812,7 @@ static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf) if (!d) { goto dflt; } - i = d->d_inode; + i = d_inode(d); if (!i) { goto dflt; } @@ -865,7 +865,7 @@ dflt:; int ncp_notify_change(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int result = 0; __le32 info_mask; struct nw_modify_dos_info info; @@ -878,7 +878,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) goto out; result = -EPERM; - if (IS_DEADDIR(dentry->d_inode)) + if (IS_DEADDIR(d_inode(dentry))) goto out; /* ageing the dentry to force validation */ diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index cf7e043a9447..79b113048eac 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -376,7 +376,7 @@ static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg struct dentry* dentry = inode->i_sb->s_root; if (dentry) { - struct inode* s_inode = dentry->d_inode; + struct inode* s_inode = d_inode(dentry); if (s_inode) { sr.volNumber = NCP_FINFO(s_inode)->volNumber; @@ -384,7 +384,7 @@ static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg sr.namespace = server->name_space[sr.volNumber]; result = 0; } else - ncp_dbg(1, "s_root->d_inode==NULL\n"); + ncp_dbg(1, "d_inode(s_root)==NULL\n"); } else ncp_dbg(1, "s_root==NULL\n"); } else { @@ -431,7 +431,7 @@ static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg if (result == 0) { dentry = inode->i_sb->s_root; if (dentry) { - struct inode* s_inode = dentry->d_inode; + struct inode* s_inode = d_inode(dentry); if (s_inode) { NCP_FINFO(s_inode)->volNumber = vnum; @@ -439,7 +439,7 @@ static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg NCP_FINFO(s_inode)->DosDirNum = dosde; server->root_setuped = 1; } else { - ncp_dbg(1, "s_root->d_inode==NULL\n"); + ncp_dbg(1, "d_inode(s_root)==NULL\n"); result = -EIO; } } else { diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c index 2b502a0d7941..88dbbc9fcf4d 100644 --- a/fs/ncpfs/ncplib_kernel.c +++ b/fs/ncpfs/ncplib_kernel.c @@ -727,7 +727,7 @@ int ncp_del_file_or_subdir2(struct ncp_server *server, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); __u8 volnum; __le32 dirent; diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c index 1a63bfdb4a65..421b6f91e8ec 100644 --- a/fs/ncpfs/symlink.c +++ b/fs/ncpfs/symlink.c @@ -156,7 +156,7 @@ int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { goto failfree; } - inode=dentry->d_inode; + inode=d_inode(dentry); if (ncp_make_open(inode, O_WRONLY)) goto failfree; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c19e16f0b2d0..1e51ecd61854 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -416,15 +416,14 @@ int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) { struct nfs_inode *nfsi; - if (dentry->d_inode == NULL) - goto different; + if (d_really_is_negative(dentry)) + return 0; - nfsi = NFS_I(dentry->d_inode); + nfsi = NFS_I(d_inode(dentry)); if (entry->fattr->fileid == nfsi->fileid) return 1; if (nfs_compare_fh(entry->fh, &nfsi->fh) == 0) return 1; -different: return 0; } @@ -473,7 +472,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) struct qstr filename = QSTR_INIT(entry->name, entry->len); struct dentry *dentry; struct dentry *alias; - struct inode *dir = parent->d_inode; + struct inode *dir = d_inode(parent); struct inode *inode; int status; @@ -497,9 +496,9 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) goto out; if (nfs_same_file(dentry, entry)) { nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); - status = nfs_refresh_inode(dentry->d_inode, entry->fattr); + status = nfs_refresh_inode(d_inode(dentry), entry->fattr); if (!status) - nfs_setsecurity(dentry->d_inode, entry->fattr, entry->label); + nfs_setsecurity(d_inode(dentry), entry->fattr, entry->label); goto out; } else { d_invalidate(dentry); @@ -870,7 +869,7 @@ static bool nfs_dir_mapping_need_revalidate(struct inode *dir) static int nfs_readdir(struct file *file, struct dir_context *ctx) { struct dentry *dentry = file->f_path.dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); nfs_readdir_descriptor_t my_desc, *desc = &my_desc; struct nfs_open_dir_context *dir_ctx = file->private_data; @@ -1118,15 +1117,15 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) if (flags & LOOKUP_RCU) { parent = ACCESS_ONCE(dentry->d_parent); - dir = ACCESS_ONCE(parent->d_inode); + dir = d_inode_rcu(parent); if (!dir) return -ECHILD; } else { parent = dget_parent(dentry); - dir = parent->d_inode; + dir = d_inode(parent); } nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); - inode = dentry->d_inode; + inode = d_inode(dentry); if (!inode) { if (nfs_neg_need_reval(dir, dentry, flags)) { @@ -1242,7 +1241,7 @@ out_error: } /* - * A weaker form of d_revalidate for revalidating just the dentry->d_inode + * A weaker form of d_revalidate for revalidating just the d_inode(dentry) * when we don't really care about the dentry name. This is called when a * pathwalk ends on a dentry that was not found via a normal lookup in the * parent dir (e.g.: ".", "..", procfs symlinks or mountpoint traversals). @@ -1253,7 +1252,7 @@ out_error: static int nfs_weak_revalidate(struct dentry *dentry, unsigned int flags) { int error; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); /* * I believe we can only get a negative dentry here in the case of a @@ -1287,7 +1286,7 @@ static int nfs_dentry_delete(const struct dentry *dentry) dentry, dentry->d_flags); /* Unhash any dentry with a stale inode */ - if (dentry->d_inode != NULL && NFS_STALE(dentry->d_inode)) + if (d_really_is_positive(dentry) && NFS_STALE(d_inode(dentry))) return 1; if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { @@ -1491,7 +1490,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, int err; /* Expect a negative dentry */ - BUG_ON(dentry->d_inode); + BUG_ON(d_inode(dentry)); dfprintk(VFS, "NFS: atomic_open(%s/%lu), %pd\n", dir->i_sb->s_id, dir->i_ino, dentry); @@ -1587,7 +1586,7 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags) if (NFS_SB(dentry->d_sb)->caps & NFS_CAP_ATOMIC_OPEN_V1) goto no_open; - inode = dentry->d_inode; + inode = d_inode(dentry); /* We can't create new files in nfs_open_revalidate(), so we * optimize away revalidation of negative dentries. @@ -1598,12 +1597,12 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags) if (flags & LOOKUP_RCU) { parent = ACCESS_ONCE(dentry->d_parent); - dir = ACCESS_ONCE(parent->d_inode); + dir = d_inode_rcu(parent); if (!dir) return -ECHILD; } else { parent = dget_parent(dentry); - dir = parent->d_inode; + dir = d_inode(parent); } if (!nfs_neg_need_reval(dir, dentry, flags)) ret = 1; @@ -1643,14 +1642,14 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, struct nfs4_label *label) { struct dentry *parent = dget_parent(dentry); - struct inode *dir = parent->d_inode; + struct inode *dir = d_inode(parent); struct inode *inode; int error = -EACCES; d_drop(dentry); /* We may have been initialized further down */ - if (dentry->d_inode) + if (d_really_is_positive(dentry)) goto out; if (fhandle->size == 0) { error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, NULL); @@ -1768,7 +1767,7 @@ EXPORT_SYMBOL_GPL(nfs_mkdir); static void nfs_dentry_handle_enoent(struct dentry *dentry) { - if (dentry->d_inode != NULL && !d_unhashed(dentry)) + if (d_really_is_positive(dentry) && !d_unhashed(dentry)) d_delete(dentry); } @@ -1780,13 +1779,13 @@ int nfs_rmdir(struct inode *dir, struct dentry *dentry) dir->i_sb->s_id, dir->i_ino, dentry); trace_nfs_rmdir_enter(dir, dentry); - if (dentry->d_inode) { + if (d_really_is_positive(dentry)) { nfs_wait_on_sillyrename(dentry); error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); /* Ensure the VFS deletes this inode */ switch (error) { case 0: - clear_nlink(dentry->d_inode); + clear_nlink(d_inode(dentry)); break; case -ENOENT: nfs_dentry_handle_enoent(dentry); @@ -1808,8 +1807,8 @@ EXPORT_SYMBOL_GPL(nfs_rmdir); */ static int nfs_safe_remove(struct dentry *dentry) { - struct inode *dir = dentry->d_parent->d_inode; - struct inode *inode = dentry->d_inode; + struct inode *dir = d_inode(dentry->d_parent); + struct inode *inode = d_inode(dentry); int error = -EBUSY; dfprintk(VFS, "NFS: safe_remove(%pd2)\n", dentry); @@ -1853,7 +1852,7 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry) if (d_count(dentry) > 1) { spin_unlock(&dentry->d_lock); /* Start asynchronous writeout of the inode */ - write_inode_now(dentry->d_inode, 0); + write_inode_now(d_inode(dentry), 0); error = nfs_sillyrename(dir, dentry); goto out; } @@ -1931,7 +1930,7 @@ int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) * No big deal if we can't add this page to the page cache here. * READLINK will get the missing page from the server if needed. */ - if (!add_to_page_cache_lru(page, dentry->d_inode->i_mapping, 0, + if (!add_to_page_cache_lru(page, d_inode(dentry)->i_mapping, 0, GFP_KERNEL)) { SetPageUptodate(page); unlock_page(page); @@ -1950,7 +1949,7 @@ EXPORT_SYMBOL_GPL(nfs_symlink); int nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); int error; dfprintk(VFS, "NFS: link(%pd2 -> %pd2)\n", @@ -1997,8 +1996,8 @@ EXPORT_SYMBOL_GPL(nfs_link); int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { - struct inode *old_inode = old_dentry->d_inode; - struct inode *new_inode = new_dentry->d_inode; + struct inode *old_inode = d_inode(old_dentry); + struct inode *new_inode = d_inode(new_dentry); struct dentry *dentry = NULL, *rehash = NULL; struct rpc_task *task; int error = -EBUSY; diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 682f65fe09b5..ed0e6031be88 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -403,8 +403,8 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq, bool write) static void nfs_direct_readpage_release(struct nfs_page *req) { dprintk("NFS: direct read done (%s/%llu %d@%lld)\n", - req->wb_context->dentry->d_inode->i_sb->s_id, - (unsigned long long)NFS_FILEID(req->wb_context->dentry->d_inode), + d_inode(req->wb_context->dentry)->i_sb->s_id, + (unsigned long long)NFS_FILEID(d_inode(req->wb_context->dentry)), req->wb_bytes, (long long)req_offset(req)); nfs_release_request(req); diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 9ac3846cb59e..a608ffd28acc 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -56,11 +56,11 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i * This again causes shrink_dcache_for_umount_subtree() to * Oops, since the test for IS_ROOT() will fail. */ - spin_lock(&sb->s_root->d_inode->i_lock); + spin_lock(&d_inode(sb->s_root)->i_lock); spin_lock(&sb->s_root->d_lock); hlist_del_init(&sb->s_root->d_u.d_alias); spin_unlock(&sb->s_root->d_lock); - spin_unlock(&sb->s_root->d_inode->i_lock); + spin_unlock(&d_inode(sb->s_root)->i_lock); } return 0; } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index d42dff6d5e98..3689e95da79a 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -495,7 +495,7 @@ EXPORT_SYMBOL_GPL(nfs_fhget); int nfs_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct nfs_fattr *fattr; int error = -ENOMEM; @@ -621,7 +621,7 @@ static void nfs_request_parent_use_readdirplus(struct dentry *dentry) struct dentry *parent; parent = dget_parent(dentry); - nfs_force_use_readdirplus(parent->d_inode); + nfs_force_use_readdirplus(d_inode(parent)); dput(parent); } @@ -637,7 +637,7 @@ static bool nfs_need_revalidate_inode(struct inode *inode) int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; int err = 0; @@ -708,7 +708,7 @@ static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) { struct nfs_lock_context *res, *new = NULL; - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = d_inode(ctx->dentry); spin_lock(&inode->i_lock); res = __nfs_find_lock_context(ctx); @@ -736,7 +736,7 @@ EXPORT_SYMBOL_GPL(nfs_get_lock_context); void nfs_put_lock_context(struct nfs_lock_context *l_ctx) { struct nfs_open_context *ctx = l_ctx->open_context; - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = d_inode(ctx->dentry); if (!atomic_dec_and_lock(&l_ctx->count, &inode->i_lock)) return; @@ -763,7 +763,7 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync) return; if (!is_sync) return; - inode = ctx->dentry->d_inode; + inode = d_inode(ctx->dentry); if (!list_empty(&NFS_I(inode)->open_files)) return; server = NFS_SERVER(inode); @@ -810,7 +810,7 @@ EXPORT_SYMBOL_GPL(get_nfs_open_context); static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) { - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = d_inode(ctx->dentry); struct super_block *sb = ctx->dentry->d_sb; if (!list_empty(&ctx->list)) { @@ -842,7 +842,7 @@ EXPORT_SYMBOL_GPL(put_nfs_open_context); */ void nfs_inode_attach_open_context(struct nfs_open_context *ctx) { - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = d_inode(ctx->dentry); struct nfs_inode *nfsi = NFS_I(inode); spin_lock(&inode->i_lock); @@ -885,7 +885,7 @@ static void nfs_file_clear_open_context(struct file *filp) struct nfs_open_context *ctx = nfs_file_open_context(filp); if (ctx) { - struct inode *inode = ctx->dentry->d_inode; + struct inode *inode = d_inode(ctx->dentry); filp->private_data = NULL; spin_lock(&inode->i_lock); diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index b5a0afc3ee10..c8162c660c44 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -139,7 +139,7 @@ EXPORT_SYMBOL_GPL(nfs_path); struct vfsmount *nfs_d_automount(struct path *path) { struct vfsmount *mnt; - struct nfs_server *server = NFS_SERVER(path->dentry->d_inode); + struct nfs_server *server = NFS_SERVER(d_inode(path->dentry)); struct nfs_fh *fh = NULL; struct nfs_fattr *fattr = NULL; @@ -180,16 +180,16 @@ out_nofree: static int nfs_namespace_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - if (NFS_FH(dentry->d_inode)->size != 0) + if (NFS_FH(d_inode(dentry))->size != 0) return nfs_getattr(mnt, dentry, stat); - generic_fillattr(dentry->d_inode, stat); + generic_fillattr(d_inode(dentry), stat); return 0; } static int nfs_namespace_setattr(struct dentry *dentry, struct iattr *attr) { - if (NFS_FH(dentry->d_inode)->size != 0) + if (NFS_FH(d_inode(dentry))->size != 0) return nfs_setattr(dentry, attr); return -EACCES; } @@ -279,7 +279,7 @@ struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry, struct dentry *parent = dget_parent(dentry); /* Look it up again to get its attributes */ - err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr, NULL); + err = server->nfs_client->rpc_ops->lookup(d_inode(parent), &dentry->d_name, fh, fattr, NULL); dput(parent); if (err != 0) return ERR_PTR(err); diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 658e586ca438..1ebe2fc7cda2 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -279,7 +279,7 @@ nfs3_list_one_acl(struct inode *inode, int type, const char *name, void *data, ssize_t nfs3_listxattr(struct dentry *dentry, char *data, size_t size) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); ssize_t result = 0; int error; diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 1f11d2533ee4..cb28cceefebe 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -120,7 +120,7 @@ static int nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, struct iattr *sattr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct nfs3_sattrargs arg = { .fh = NFS_FH(inode), .sattr = sattr, @@ -386,13 +386,13 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, * not sure this buys us anything (and I'd have * to revamp the NFSv3 XDR code) */ status = nfs3_proc_setattr(dentry, data->res.fattr, sattr); - nfs_post_op_update_inode(dentry->d_inode, data->res.fattr); + nfs_post_op_update_inode(d_inode(dentry), data->res.fattr); dprintk("NFS reply setattr (post-create): %d\n", status); if (status != 0) goto out_release_acls; } - status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl); + status = nfs3_proc_setacls(d_inode(dentry), acl, default_acl); out_release_acls: posix_acl_release(acl); @@ -570,7 +570,7 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) if (status != 0) goto out_release_acls; - status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl); + status = nfs3_proc_setacls(d_inode(dentry), acl, default_acl); out_release_acls: posix_acl_release(acl); @@ -623,7 +623,7 @@ static int nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, u64 cookie, struct page **pages, unsigned int count, int plus) { - struct inode *dir = dentry->d_inode; + struct inode *dir = d_inode(dentry); __be32 *verf = NFS_I(dir)->cookieverf; struct nfs3_readdirargs arg = { .fh = NFS_FH(dir), @@ -715,7 +715,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, if (status != 0) goto out_release_acls; - status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl); + status = nfs3_proc_setacls(d_inode(dentry), acl, default_acl); out_release_acls: posix_acl_release(acl); diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 86d6214ea022..51c2dbd1e942 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -1130,7 +1130,7 @@ error: */ static int nfs_probe_destination(struct nfs_server *server) { - struct inode *inode = server->super->s_root->d_inode; + struct inode *inode = d_inode(server->super->s_root); struct nfs_fattr *fattr; int error; diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 0181cde1d102..619eca34e70f 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -46,7 +46,7 @@ nfs4_file_open(struct inode *inode, struct file *filp) openflags &= ~(O_CREAT|O_EXCL); parent = dget_parent(dentry); - dir = parent->d_inode; + dir = d_inode(parent); ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode); err = PTR_ERR(ctx); @@ -74,7 +74,7 @@ nfs4_file_open(struct inode *inode, struct file *filp) goto out_drop; } } - if (inode != dentry->d_inode) + if (inode != d_inode(dentry)) goto out_drop; nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 3d83cb1fdc70..f592672373cb 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -375,7 +375,7 @@ static struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry * dprintk("%s: getting locations for %pd2\n", __func__, dentry); - err = nfs4_proc_fs_locations(client, parent->d_inode, &dentry->d_name, fs_locations, page); + err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page); dput(parent); if (err != 0 || fs_locations->nlocations <= 0 || @@ -396,7 +396,7 @@ struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry, { rpc_authflavor_t flavor = server->client->cl_auth->au_flavor; struct dentry *parent = dget_parent(dentry); - struct inode *dir = parent->d_inode; + struct inode *dir = d_inode(parent); struct qstr *name = &dentry->d_name; struct rpc_clnt *client; struct vfsmount *mnt; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 627f37c44456..98e533f2c94a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -293,7 +293,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent *p++ = xdr_one; /* bitmap length */ *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ *p++ = htonl(8); /* attribute buffer length */ - p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode)); + p = xdr_encode_hyper(p, NFS_FILEID(d_inode(dentry))); } *p++ = xdr_one; /* next */ @@ -305,7 +305,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent *p++ = xdr_one; /* bitmap length */ *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ *p++ = htonl(8); /* attribute buffer length */ - p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode)); + p = xdr_encode_hyper(p, NFS_FILEID(d_inode(dentry->d_parent))); readdir->pgbase = (char *)p - (char *)start; readdir->count -= readdir->pgbase; @@ -1004,7 +1004,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, gfp_t gfp_mask) { struct dentry *parent = dget_parent(dentry); - struct inode *dir = parent->d_inode; + struct inode *dir = d_inode(parent); struct nfs_server *server = NFS_SERVER(dir); struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t); struct nfs4_opendata *p; @@ -1057,7 +1057,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, case NFS4_OPEN_CLAIM_FH: case NFS4_OPEN_CLAIM_DELEG_CUR_FH: case NFS4_OPEN_CLAIM_DELEG_PREV_FH: - p->o_arg.fh = NFS_FH(dentry->d_inode); + p->o_arg.fh = NFS_FH(d_inode(dentry)); } if (attrs != NULL && attrs->ia_valid != 0) { __u32 verf[2]; @@ -1794,7 +1794,7 @@ static const struct rpc_call_ops nfs4_open_confirm_ops = { */ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) { - struct nfs_server *server = NFS_SERVER(data->dir->d_inode); + struct nfs_server *server = NFS_SERVER(d_inode(data->dir)); struct rpc_task *task; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], @@ -1951,7 +1951,7 @@ static const struct rpc_call_ops nfs4_open_ops = { static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover) { - struct inode *dir = data->dir->d_inode; + struct inode *dir = d_inode(data->dir); struct nfs_server *server = NFS_SERVER(dir); struct nfs_openargs *o_arg = &data->o_arg; struct nfs_openres *o_res = &data->o_res; @@ -1998,7 +1998,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover) static int _nfs4_recover_proc_open(struct nfs4_opendata *data) { - struct inode *dir = data->dir->d_inode; + struct inode *dir = d_inode(data->dir); struct nfs_openres *o_res = &data->o_res; int status; @@ -2067,7 +2067,7 @@ static int nfs4_opendata_access(struct rpc_cred *cred, */ static int _nfs4_proc_open(struct nfs4_opendata *data) { - struct inode *dir = data->dir->d_inode; + struct inode *dir = d_inode(data->dir); struct nfs_server *server = NFS_SERVER(dir); struct nfs_openargs *o_arg = &data->o_arg; struct nfs_openres *o_res = &data->o_res; @@ -2314,7 +2314,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); dentry = opendata->dentry; - if (dentry->d_inode == NULL) { + if (d_really_is_negative(dentry)) { /* FIXME: Is this d_drop() ever needed? */ d_drop(dentry); dentry = d_add_unique(dentry, igrab(state->inode)); @@ -2325,7 +2325,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, ctx->dentry = dget(dentry); } nfs_set_verifier(dentry, - nfs_save_change_attribute(opendata->dir->d_inode)); + nfs_save_change_attribute(d_inode(opendata->dir))); } ret = nfs4_opendata_access(sp->so_cred, opendata, state, fmode, flags); @@ -2333,7 +2333,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, goto out; ctx->state = state; - if (dentry->d_inode == state->inode) { + if (d_inode(dentry) == state->inode) { nfs_inode_attach_open_context(ctx); if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) nfs4_schedule_stateid_recovery(server, state); @@ -2374,10 +2374,10 @@ static int _nfs4_do_open(struct inode *dir, status = nfs4_recover_expired_lease(server); if (status != 0) goto err_put_state_owner; - if (dentry->d_inode != NULL) - nfs4_return_incompatible_delegation(dentry->d_inode, fmode); + if (d_really_is_positive(dentry)) + nfs4_return_incompatible_delegation(d_inode(dentry), fmode); status = -ENOMEM; - if (dentry->d_inode) + if (d_really_is_positive(dentry)) claim = NFS4_OPEN_CLAIM_FH; opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, label, claim, GFP_KERNEL); @@ -2400,8 +2400,8 @@ static int _nfs4_do_open(struct inode *dir, } opendata->o_arg.open_bitmap = &nfs4_pnfs_open_bitmap[0]; } - if (dentry->d_inode != NULL) - opendata->state = nfs4_get_open_state(dentry->d_inode, sp); + if (d_really_is_positive(dentry)) + opendata->state = nfs4_get_open_state(d_inode(dentry), sp); status = _nfs4_open_and_get_state(opendata, fmode, flags, ctx); if (status != 0) @@ -3254,7 +3254,7 @@ static int nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, struct iattr *sattr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct rpc_cred *cred = NULL; struct nfs4_state *state = NULL; struct nfs4_label *label = NULL; @@ -3871,13 +3871,13 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, u64 cookie, struct page **pages, unsigned int count, int plus) { - struct inode *dir = dentry->d_inode; + struct inode *dir = d_inode(dentry); struct nfs4_readdir_arg args = { .fh = NFS_FH(dir), .pages = pages, .pgbase = 0, .count = count, - .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask, + .bitmask = NFS_SERVER(d_inode(dentry))->attr_bitmask, .plus = plus, }; struct nfs4_readdir_res res; @@ -3914,8 +3914,8 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, do { err = _nfs4_proc_readdir(dentry, cred, cookie, pages, count, plus); - trace_nfs4_readdir(dentry->d_inode, err); - err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode), err, + trace_nfs4_readdir(d_inode(dentry), err); + err = nfs4_handle_exception(NFS_SERVER(d_inode(dentry)), err, &exception); } while (exception.retry); return err; @@ -4830,7 +4830,7 @@ nfs4_set_security_label(struct dentry *dentry, const void *buf, size_t buflen) struct nfs4_label ilabel, *olabel = NULL; struct nfs_fattr fattr; struct rpc_cred *cred; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int status; if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) @@ -5670,7 +5670,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) data->rpc_status = task->tk_status; switch (task->tk_status) { case 0: - renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), + renew_lease(NFS_SERVER(d_inode(data->ctx->dentry)), data->timestamp); if (data->arg.new_lock) { data->fl.fl_flags &= ~(FL_SLEEP | FL_ACCESS); @@ -6112,7 +6112,7 @@ static int nfs4_xattr_set_nfs4_acl(struct dentry *dentry, const char *key, if (strcmp(key, "") != 0) return -EINVAL; - return nfs4_proc_set_acl(dentry->d_inode, buf, buflen); + return nfs4_proc_set_acl(d_inode(dentry), buf, buflen); } static int nfs4_xattr_get_nfs4_acl(struct dentry *dentry, const char *key, @@ -6121,7 +6121,7 @@ static int nfs4_xattr_get_nfs4_acl(struct dentry *dentry, const char *key, if (strcmp(key, "") != 0) return -EINVAL; - return nfs4_proc_get_acl(dentry->d_inode, buf, buflen); + return nfs4_proc_get_acl(d_inode(dentry), buf, buflen); } static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list, @@ -6130,7 +6130,7 @@ static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list, { size_t len = sizeof(XATTR_NAME_NFSV4_ACL); - if (!nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode))) + if (!nfs4_server_supports_acls(NFS_SERVER(d_inode(dentry)))) return 0; if (list && len <= list_len) @@ -6158,7 +6158,7 @@ static int nfs4_xattr_get_nfs4_label(struct dentry *dentry, const char *key, void *buf, size_t buflen, int type) { if (security_ismaclabel(key)) - return nfs4_get_security_label(dentry->d_inode, buf, buflen); + return nfs4_get_security_label(d_inode(dentry), buf, buflen); return -EOPNOTSUPP; } @@ -6168,10 +6168,10 @@ static size_t nfs4_xattr_list_nfs4_label(struct dentry *dentry, char *list, { size_t len = 0; - if (nfs_server_capable(dentry->d_inode, NFS_CAP_SECURITY_LABEL)) { - len = security_inode_listsecurity(dentry->d_inode, NULL, 0); + if (nfs_server_capable(d_inode(dentry), NFS_CAP_SECURITY_LABEL)) { + len = security_inode_listsecurity(d_inode(dentry), NULL, 0); if (list && len <= list_len) - security_inode_listsecurity(dentry->d_inode, list, len); + security_inode_listsecurity(d_inode(dentry), list, len); } return len; } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index f95e3b58bbc3..3b2b20534a3a 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1902,7 +1902,7 @@ static int nfs4_try_migration(struct nfs_server *server, struct rpc_cred *cred) goto out; } - inode = server->super->s_root->d_inode; + inode = d_inode(server->super->s_root); result = nfs4_proc_get_locations(inode, locations, page, cred); if (result) { dprintk("<-- %s: failed to retrieve fs_locations: %d\n", @@ -2021,7 +2021,7 @@ restart: rcu_read_unlock(); - inode = server->super->s_root->d_inode; + inode = d_inode(server->super->s_root); status = nfs4_proc_fsid_present(inode, cred); if (status != -NFS4ERR_MOVED) goto restart; /* wasn't this one */ diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h index 1c32adbe728d..470af1a78bec 100644 --- a/fs/nfs/nfs4trace.h +++ b/fs/nfs/nfs4trace.h @@ -418,7 +418,7 @@ DECLARE_EVENT_CLASS(nfs4_open_event, __entry->fileid = 0; __entry->fhandle = 0; } - __entry->dir = NFS_FILEID(ctx->dentry->d_parent->d_inode); + __entry->dir = NFS_FILEID(d_inode(ctx->dentry->d_parent)); __assign_str(name, ctx->dentry->d_name.name); ), @@ -1110,7 +1110,7 @@ TRACE_EVENT(nfs4_layoutget, ), TP_fast_assign( - const struct inode *inode = ctx->dentry->d_inode; + const struct inode *inode = d_inode(ctx->dentry); __entry->dev = inode->i_sb->s_dev; __entry->fileid = NFS_FILEID(inode); __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode)); diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index d57190a0d533..282b39369510 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -938,7 +938,7 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev, if (prev) { if (!nfs_match_open_context(req->wb_context, prev->wb_context)) return false; - flctx = req->wb_context->dentry->d_inode->i_flctx; + flctx = d_inode(req->wb_context->dentry)->i_flctx; if (flctx != NULL && !(list_empty_careful(&flctx->flc_posix) && list_empty_careful(&flctx->flc_flock)) && diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 635f0865671c..084c9144f86d 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -426,7 +426,7 @@ static inline bool pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg, struct nfs_commit_info *cinfo, u32 ds_commit_idx) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = d_inode(req->wb_context->dentry); struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; if (lseg == NULL || ld->mark_request_commit == NULL) @@ -438,7 +438,7 @@ pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg, static inline bool pnfs_clear_request_commit(struct nfs_page *req, struct nfs_commit_info *cinfo) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = d_inode(req->wb_context->dentry); struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; if (ld == NULL || ld->clear_request_commit == NULL) diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index c63189acd052..b417bbcd9704 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -118,7 +118,7 @@ static int nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, struct iattr *sattr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct nfs_sattrargs arg = { .fh = NFS_FH(inode), .sattr = sattr @@ -487,7 +487,7 @@ static int nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, u64 cookie, struct page **pages, unsigned int count, int plus) { - struct inode *dir = dentry->d_inode; + struct inode *dir = d_inode(dentry); struct nfs_readdirargs arg = { .fh = NFS_FH(dir), .cookie = cookie, diff --git a/fs/nfs/read.c b/fs/nfs/read.c index b8f5c63f77b2..a5b7427c3754 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -117,7 +117,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, static void nfs_readpage_release(struct nfs_page *req) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = d_inode(req->wb_context->dentry); dprintk("NFS: read done (%s/%llu %d@%lld)\n", inode->i_sb->s_id, (unsigned long long)NFS_FILEID(inode), req->wb_bytes, diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 322b2de02988..21f8f52bf37d 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -433,7 +433,7 @@ int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) struct nfs_server *server = NFS_SB(dentry->d_sb); unsigned char blockbits; unsigned long blockres; - struct nfs_fh *fh = NFS_FH(dentry->d_inode); + struct nfs_fh *fh = NFS_FH(d_inode(dentry)); struct nfs_fsstat res; int error = -ENOMEM; @@ -447,7 +447,7 @@ int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) pd_dentry = dget_parent(dentry); if (pd_dentry != NULL) { - nfs_zap_caches(pd_dentry->d_inode); + nfs_zap_caches(d_inode(pd_dentry)); dput(pd_dentry); } } @@ -2526,7 +2526,7 @@ int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, struct nfs_mount_info *mount_info) { /* clone any lsm security options from the parent to the new sb */ - if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) + if (d_inode(mntroot)->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) return -ESTALE; return security_sb_clone_mnt_opts(mount_info->cloned->sb, s); } diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 05c9e02f4153..2d56200655fe 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c @@ -45,7 +45,7 @@ error: static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct page *page; void *err; diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index de54129336c6..fa538b2ba251 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -143,7 +143,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n nfs_free_dname(data); ret = nfs_copy_dname(alias, data); spin_lock(&alias->d_lock); - if (ret == 0 && alias->d_inode != NULL && + if (ret == 0 && d_really_is_positive(alias) && !(alias->d_flags & DCACHE_NFSFS_RENAMED)) { devname_garbage = alias->d_fsdata; alias->d_fsdata = data; @@ -190,7 +190,7 @@ static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data) parent = dget_parent(dentry); if (parent == NULL) goto out_free; - dir = parent->d_inode; + dir = d_inode(parent); /* Non-exclusive lock protects against concurrent lookup() calls */ spin_lock(&dir->i_lock); if (atomic_inc_not_zero(&NFS_I(dir)->silly_count) == 0) { @@ -210,21 +210,21 @@ out_free: void nfs_wait_on_sillyrename(struct dentry *dentry) { - struct nfs_inode *nfsi = NFS_I(dentry->d_inode); + struct nfs_inode *nfsi = NFS_I(d_inode(dentry)); wait_event(nfsi->waitqueue, atomic_read(&nfsi->silly_count) <= 1); } void nfs_block_sillyrename(struct dentry *dentry) { - struct nfs_inode *nfsi = NFS_I(dentry->d_inode); + struct nfs_inode *nfsi = NFS_I(d_inode(dentry)); wait_event(nfsi->waitqueue, atomic_cmpxchg(&nfsi->silly_count, 1, 0) == 1); } void nfs_unblock_sillyrename(struct dentry *dentry) { - struct inode *dir = dentry->d_inode; + struct inode *dir = d_inode(dentry); struct nfs_inode *nfsi = NFS_I(dir); struct nfs_unlinkdata *data; @@ -367,8 +367,8 @@ static void nfs_async_rename_release(void *calldata) struct nfs_renamedata *data = calldata; struct super_block *sb = data->old_dir->i_sb; - if (data->old_dentry->d_inode) - nfs_mark_for_revalidate(data->old_dentry->d_inode); + if (d_really_is_positive(data->old_dentry)) + nfs_mark_for_revalidate(d_inode(data->old_dentry)); dput(data->old_dentry); dput(data->new_dentry); @@ -529,10 +529,10 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) if (dentry->d_flags & DCACHE_NFSFS_RENAMED) goto out; - fileid = NFS_FILEID(dentry->d_inode); + fileid = NFS_FILEID(d_inode(dentry)); /* Return delegation in anticipation of the rename */ - NFS_PROTO(dentry->d_inode)->return_delegation(dentry->d_inode); + NFS_PROTO(d_inode(dentry))->return_delegation(d_inode(dentry)); sdentry = NULL; do { @@ -554,7 +554,7 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) */ if (IS_ERR(sdentry)) goto out; - } while (sdentry->d_inode != NULL); /* need negative lookup */ + } while (d_inode(sdentry) != NULL); /* need negative lookup */ /* queue unlink first. Can't do this from rpc_release as it * has to allocate memory diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 849ed784d6ac..e8f675d4b2fb 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -702,7 +702,7 @@ static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req) */ static void nfs_inode_remove_request(struct nfs_page *req) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = d_inode(req->wb_context->dentry); struct nfs_inode *nfsi = NFS_I(inode); struct nfs_page *head; @@ -861,7 +861,7 @@ static void nfs_clear_request_commit(struct nfs_page *req) { if (test_bit(PG_CLEAN, &req->wb_flags)) { - struct inode *inode = req->wb_context->dentry->d_inode; + struct inode *inode = d_inode(req->wb_context->dentry); struct nfs_commit_info cinfo; nfs_init_cinfo_from_inode(&cinfo, inode); @@ -1591,7 +1591,7 @@ void nfs_init_commit(struct nfs_commit_data *data, struct nfs_commit_info *cinfo) { struct nfs_page *first = nfs_list_entry(head->next); - struct inode *inode = first->wb_context->dentry->d_inode; + struct inode *inode = d_inode(first->wb_context->dentry); /* Set up the RPC argument and reply structs * NB: take care not to mess about with data->commit et al. */ @@ -1690,7 +1690,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) dprintk("NFS: commit (%s/%llu %d@%lld)", req->wb_context->dentry->d_sb->s_id, - (unsigned long long)NFS_FILEID(req->wb_context->dentry->d_inode), + (unsigned long long)NFS_FILEID(d_inode(req->wb_context->dentry)), req->wb_bytes, (long long)req_offset(req)); if (status < 0) { diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index c3e3b6e55ae2..77c4c723534c 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -599,7 +599,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) goto out4; } - err = check_export(exp.ex_path.dentry->d_inode, &exp.ex_flags, + err = check_export(d_inode(exp.ex_path.dentry), &exp.ex_flags, exp.ex_uuid); if (err) goto out4; @@ -891,7 +891,7 @@ exp_rootfh(struct net *net, struct auth_domain *clp, char *name, printk("nfsd: exp_rootfh path not found %s", name); return err; } - inode = path.dentry->d_inode; + inode = d_inode(path.dentry); dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", name, path.dentry, clp->name, diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index ac54ea60b3f6..d54701f6dc78 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -42,7 +42,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, if (nfserr) RETURN_STATUS(nfserr); - inode = fh->fh_dentry->d_inode; + inode = d_inode(fh->fh_dentry); if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) RETURN_STATUS(nfserr_inval); @@ -103,7 +103,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp, if (nfserr) goto out; - inode = fh->fh_dentry->d_inode; + inode = d_inode(fh->fh_dentry); if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) { error = -EOPNOTSUPP; goto out_errno; @@ -266,9 +266,9 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, * nfsd_dispatch actually ensures the following cannot happen. * However, it seems fragile to depend on that. */ - if (dentry == NULL || dentry->d_inode == NULL) + if (dentry == NULL || d_really_is_negative(dentry)) return 0; - inode = dentry->d_inode; + inode = d_inode(dentry); p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat); *p++ = htonl(resp->mask); diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 34cbbab6abd7..882b1a14bc3e 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -39,7 +39,7 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, if (nfserr) RETURN_STATUS(nfserr); - inode = fh->fh_dentry->d_inode; + inode = d_inode(fh->fh_dentry); if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) RETURN_STATUS(nfserr_inval); @@ -94,7 +94,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp, if (nfserr) goto out; - inode = fh->fh_dentry->d_inode; + inode = d_inode(fh->fh_dentry); if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) { error = -EOPNOTSUPP; goto out_errno; @@ -174,8 +174,8 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, struct dentry *dentry = resp->fh.fh_dentry; p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); - if (resp->status == 0 && dentry && dentry->d_inode) { - struct inode *inode = dentry->d_inode; + if (resp->status == 0 && dentry && d_really_is_positive(dentry)) { + struct inode *inode = d_inode(dentry); struct kvec *head = rqstp->rq_res.head; unsigned int base; int n; diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 12f2aab4f614..7b755b7f785c 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -166,7 +166,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, rqstp->rq_vec, argp->vlen, &resp->count); if (nfserr == 0) { - struct inode *inode = resp->fh.fh_dentry->d_inode; + struct inode *inode = d_inode(resp->fh.fh_dentry); resp->eof = (argp->offset + resp->count) >= inode->i_size; } @@ -551,7 +551,7 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, * different read/write sizes for file systems known to have * problems with large blocks */ if (nfserr == 0) { - struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb; + struct super_block *sb = d_inode(argp->fh.fh_dentry)->i_sb; /* Note that we don't care for remote fs's here */ if (sb->s_magic == MSDOS_SUPER_MAGIC) { @@ -587,7 +587,7 @@ nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP); if (nfserr == 0) { - struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb; + struct super_block *sb = d_inode(argp->fh.fh_dentry)->i_sb; /* Note that we don't care for remote fs's here */ switch (sb->s_magic) { diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 39c5eb3ad33a..e4b2b4322553 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -146,7 +146,7 @@ static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp) default: case FSIDSOURCE_DEV: p = xdr_encode_hyper(p, (u64)huge_encode_dev - (fhp->fh_dentry->d_inode->i_sb->s_dev)); + (d_inode(fhp->fh_dentry)->i_sb->s_dev)); break; case FSIDSOURCE_FSID: p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); @@ -203,14 +203,14 @@ static __be32 * encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { struct dentry *dentry = fhp->fh_dentry; - if (dentry && dentry->d_inode) { + if (dentry && d_really_is_positive(dentry)) { __be32 err; struct kstat stat; err = fh_getattr(fhp, &stat); if (!err) { *p++ = xdr_one; /* attributes follow */ - lease_get_mtime(dentry->d_inode, &stat.mtime); + lease_get_mtime(d_inode(dentry), &stat.mtime); return encode_fattr3(rqstp, p, fhp, &stat); } } @@ -233,7 +233,7 @@ encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { struct dentry *dentry = fhp->fh_dentry; - if (dentry && dentry->d_inode && fhp->fh_post_saved) { + if (dentry && d_really_is_positive(dentry) && fhp->fh_post_saved) { if (fhp->fh_pre_saved) { *p++ = xdr_one; p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size); @@ -260,11 +260,11 @@ void fill_post_wcc(struct svc_fh *fhp) printk("nfsd: inode locked twice during operation.\n"); err = fh_getattr(fhp, &fhp->fh_post_attr); - fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version; + fhp->fh_post_change = d_inode(fhp->fh_dentry)->i_version; if (err) { fhp->fh_post_saved = 0; /* Grab the ctime anyway - set_change_info might use it */ - fhp->fh_post_attr.ctime = fhp->fh_dentry->d_inode->i_ctime; + fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime; } else fhp->fh_post_saved = 1; } @@ -628,7 +628,7 @@ nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_attrstat *resp) { if (resp->status == 0) { - lease_get_mtime(resp->fh.fh_dentry->d_inode, + lease_get_mtime(d_inode(resp->fh.fh_dentry), &resp->stat.mtime); p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat); } @@ -828,7 +828,7 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, return rv; if (d_mountpoint(dchild)) goto out; - if (!dchild->d_inode) + if (d_really_is_negative(dchild)) goto out; rv = fh_compose(fhp, exp, dchild, &cd->fh); out: diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 59fd76651781..64466dcc71d1 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -139,7 +139,7 @@ int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error = 0; struct posix_acl *pacl = NULL, *dpacl = NULL; unsigned int flags = 0; @@ -828,7 +828,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, return error; dentry = fhp->fh_dentry; - inode = dentry->d_inode; + inode = d_inode(dentry); if (!inode->i_op->set_acl || !IS_POSIXACL(inode)) return nfserr_attrnotsupp; diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 92b9d97aff4f..000f962d15f1 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -52,7 +52,7 @@ static inline void nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval) { - struct inode *inode = resfh->fh_dentry->d_inode; + struct inode *inode = d_inode(resfh->fh_dentry); int status; mutex_lock(&inode->i_mutex); @@ -110,7 +110,7 @@ check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, * in current environment or not. */ if (bmval[0] & FATTR4_WORD0_ACL) { - if (!IS_POSIXACL(dentry->d_inode)) + if (!IS_POSIXACL(d_inode(dentry))) return nfserr_attrnotsupp; } @@ -209,7 +209,7 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs static __be32 nfsd_check_obj_isreg(struct svc_fh *fh) { - umode_t mode = fh->fh_dentry->d_inode->i_mode; + umode_t mode = d_inode(fh->fh_dentry)->i_mode; if (S_ISREG(mode)) return nfs_ok; @@ -881,7 +881,7 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, &exp, &dentry); if (err) return err; - if (dentry->d_inode == NULL) { + if (d_really_is_negative(dentry)) { exp_put(exp); err = nfserr_noent; } else @@ -1308,7 +1308,7 @@ nfsd4_layoutget(struct svc_rqst *rqstp, if (atomic_read(&ls->ls_stid.sc_file->fi_lo_recalls)) goto out_put_stid; - nfserr = ops->proc_layoutget(current_fh->fh_dentry->d_inode, + nfserr = ops->proc_layoutget(d_inode(current_fh->fh_dentry), current_fh, lgp); if (nfserr) goto out_put_stid; @@ -1342,7 +1342,7 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp, ops = nfsd4_layout_verify(current_fh->fh_export, lcp->lc_layout_type); if (!ops) goto out; - inode = current_fh->fh_dentry->d_inode; + inode = d_inode(current_fh->fh_dentry); nfserr = nfserr_inval; if (new_size <= seg->offset) { diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 1c307f02baa8..d88ea7b9a85c 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -192,14 +192,14 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) dir = nn->rec_file->f_path.dentry; /* lock the parent */ - mutex_lock(&dir->d_inode->i_mutex); + mutex_lock(&d_inode(dir)->i_mutex); dentry = lookup_one_len(dname, dir, HEXDIR_LEN-1); if (IS_ERR(dentry)) { status = PTR_ERR(dentry); goto out_unlock; } - if (dentry->d_inode) + if (d_really_is_positive(dentry)) /* * In the 4.1 case, where we're called from * reclaim_complete(), records from the previous reboot @@ -209,11 +209,11 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) * as well be forgiving and just succeed silently. */ goto out_put; - status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU); + status = vfs_mkdir(d_inode(dir), dentry, S_IRWXU); out_put: dput(dentry); out_unlock: - mutex_unlock(&dir->d_inode->i_mutex); + mutex_unlock(&d_inode(dir)->i_mutex); if (status == 0) { if (nn->in_grace) { crp = nfs4_client_to_reclaim(dname, nn); @@ -285,7 +285,7 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) } status = iterate_dir(nn->rec_file, &ctx.ctx); - mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&d_inode(dir)->i_mutex, I_MUTEX_PARENT); while (!list_empty(&ctx.names)) { struct name_list *entry; entry = list_entry(ctx.names.next, struct name_list, list); @@ -302,7 +302,7 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) list_del(&entry->list); kfree(entry); } - mutex_unlock(&dir->d_inode->i_mutex); + mutex_unlock(&d_inode(dir)->i_mutex); nfs4_reset_creds(original_cred); return status; } @@ -316,20 +316,20 @@ nfsd4_unlink_clid_dir(char *name, int namlen, struct nfsd_net *nn) dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name); dir = nn->rec_file->f_path.dentry; - mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&d_inode(dir)->i_mutex, I_MUTEX_PARENT); dentry = lookup_one_len(name, dir, namlen); if (IS_ERR(dentry)) { status = PTR_ERR(dentry); goto out_unlock; } status = -ENOENT; - if (!dentry->d_inode) + if (d_really_is_negative(dentry)) goto out; - status = vfs_rmdir(dir->d_inode, dentry); + status = vfs_rmdir(d_inode(dir), dentry); out: dput(dentry); out_unlock: - mutex_unlock(&dir->d_inode->i_mutex); + mutex_unlock(&d_inode(dir)->i_mutex); return status; } @@ -385,7 +385,7 @@ purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) if (nfs4_has_reclaimed_state(child->d_name.name, nn)) return 0; - status = vfs_rmdir(parent->d_inode, child); + status = vfs_rmdir(d_inode(parent), child); if (status) printk("failed to remove client recovery directory %pd\n", child); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 8ba1d888f1e6..7e08aabd56e5 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4473,7 +4473,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *stp = NULL; struct nfs4_delegation *dp = NULL; struct svc_fh *current_fh = &cstate->current_fh; - struct inode *ino = current_fh->fh_dentry->d_inode; + struct inode *ino = d_inode(current_fh->fh_dentry); struct nfsd_net *nn = net_generic(net, nfsd_net_id); struct file *file = NULL; __be32 status; @@ -5169,7 +5169,7 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_file *fi = ost->st_stid.sc_file; struct nfs4_openowner *oo = openowner(ost->st_stateowner); struct nfs4_client *cl = oo->oo_owner.so_client; - struct inode *inode = cstate->current_fh.fh_dentry->d_inode; + struct inode *inode = d_inode(cstate->current_fh.fh_dentry); struct nfs4_lockowner *lo; unsigned int strhashval; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 5fb7e78169a6..ff9be0743b88 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2292,7 +2292,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, #ifdef CONFIG_NFSD_V4_SECURITY_LABEL if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) || bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) { - err = security_inode_getsecctx(dentry->d_inode, + err = security_inode_getsecctx(d_inode(dentry), &context, &contextlen); contextsupport = (err == 0); if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { @@ -2384,7 +2384,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; - p = encode_change(p, &stat, dentry->d_inode); + p = encode_change(p, &stat, d_inode(dentry)); } if (bmval0 & FATTR4_WORD0_SIZE) { p = xdr_reserve_space(xdr, 8); @@ -2807,7 +2807,7 @@ nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd, dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); if (IS_ERR(dentry)) return nfserrno(PTR_ERR(dentry)); - if (!dentry->d_inode) { + if (d_really_is_negative(dentry)) { /* * nfsd_buffered_readdir drops the i_mutex between * readdir and calling this callback, leaving a window @@ -3324,7 +3324,7 @@ static __be32 nfsd4_encode_splice_read( } eof = (read->rd_offset + maxcount >= - read->rd_fhp->fh_dentry->d_inode->i_size); + d_inode(read->rd_fhp->fh_dentry)->i_size); *(p++) = htonl(eof); *(p++) = htonl(maxcount); @@ -3401,7 +3401,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3)); eof = (read->rd_offset + maxcount >= - read->rd_fhp->fh_dentry->d_inode->i_size); + d_inode(read->rd_fhp->fh_dentry)->i_size); tmp = htonl(eof); write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4); diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index e9fa966fc37f..350041a40fe5 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -38,7 +38,7 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry) /* make sure parents give x permission to user */ int err; parent = dget_parent(tdentry); - err = inode_permission(parent->d_inode, MAY_EXEC); + err = inode_permission(d_inode(parent), MAY_EXEC); if (err < 0) { dput(parent); break; @@ -340,7 +340,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access) if (error) goto out; - error = nfsd_mode_check(rqstp, dentry->d_inode->i_mode, type); + error = nfsd_mode_check(rqstp, d_inode(dentry)->i_mode, type); if (error) goto out; @@ -412,8 +412,8 @@ static inline void _fh_update_old(struct dentry *dentry, struct svc_export *exp, struct knfsd_fh *fh) { - fh->ofh_ino = ino_t_to_u32(dentry->d_inode->i_ino); - fh->ofh_generation = dentry->d_inode->i_generation; + fh->ofh_ino = ino_t_to_u32(d_inode(dentry)->i_ino); + fh->ofh_generation = d_inode(dentry)->i_generation; if (d_is_dir(dentry) || (exp->ex_flags & NFSEXP_NOSUBTREECHECK)) fh->ofh_dirino = 0; @@ -426,7 +426,7 @@ static bool is_root_export(struct svc_export *exp) static struct super_block *exp_sb(struct svc_export *exp) { - return exp->ex_path.dentry->d_inode->i_sb; + return d_inode(exp->ex_path.dentry)->i_sb; } static bool fsid_type_ok_for_exp(u8 fsid_type, struct svc_export *exp) @@ -520,12 +520,12 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, * */ - struct inode * inode = dentry->d_inode; + struct inode * inode = d_inode(dentry); dev_t ex_dev = exp_sb(exp)->s_dev; dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %pd2, ino=%ld)\n", MAJOR(ex_dev), MINOR(ex_dev), - (long) exp->ex_path.dentry->d_inode->i_ino, + (long) d_inode(exp->ex_path.dentry)->i_ino, dentry, (inode ? inode->i_ino : 0)); @@ -558,7 +558,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, fhp->fh_handle.ofh_dev = old_encode_dev(ex_dev); fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev; fhp->fh_handle.ofh_xino = - ino_t_to_u32(exp->ex_path.dentry->d_inode->i_ino); + ino_t_to_u32(d_inode(exp->ex_path.dentry)->i_ino); fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry)); if (inode) _fh_update_old(dentry, exp, &fhp->fh_handle); @@ -570,7 +570,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, mk_fsid(fhp->fh_handle.fh_fsid_type, fhp->fh_handle.fh_fsid, ex_dev, - exp->ex_path.dentry->d_inode->i_ino, + d_inode(exp->ex_path.dentry)->i_ino, exp->ex_fsid, exp->ex_uuid); if (inode) @@ -597,7 +597,7 @@ fh_update(struct svc_fh *fhp) goto out_bad; dentry = fhp->fh_dentry; - if (!dentry->d_inode) + if (d_really_is_negative(dentry)) goto out_negative; if (fhp->fh_handle.fh_version != 1) { _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle); diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index f22920442172..1e90dad4926b 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -225,7 +225,7 @@ fill_pre_wcc(struct svc_fh *fhp) { struct inode *inode; - inode = fhp->fh_dentry->d_inode; + inode = d_inode(fhp->fh_dentry); if (!fhp->fh_pre_saved) { fhp->fh_pre_mtime = inode->i_mtime; fhp->fh_pre_ctime = inode->i_ctime; @@ -264,7 +264,7 @@ fh_lock_nested(struct svc_fh *fhp, unsigned int subclass) return; } - inode = dentry->d_inode; + inode = d_inode(dentry); mutex_lock_nested(&inode->i_mutex, subclass); fill_pre_wcc(fhp); fhp->fh_locked = 1; @@ -284,7 +284,7 @@ fh_unlock(struct svc_fh *fhp) { if (fhp->fh_locked) { fill_post_wcc(fhp); - mutex_unlock(&fhp->fh_dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(fhp->fh_dentry)->i_mutex); fhp->fh_locked = 0; } } diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index b8680738f588..aecbcd34d336 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -223,7 +223,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, } fh_init(newfhp, NFS_FHSIZE); nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp); - if (!nfserr && !dchild->d_inode) + if (!nfserr && d_really_is_negative(dchild)) nfserr = nfserr_noent; dput(dchild); if (nfserr) { @@ -241,7 +241,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, } } - inode = newfhp->fh_dentry->d_inode; + inode = d_inode(newfhp->fh_dentry); /* Unfudge the mode bits */ if (attr->ia_valid & ATTR_MODE) { diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 412d7061f9e5..79d964aa8079 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -187,7 +187,7 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, *p++ = htonl((u32) stat->ino); *p++ = htonl((u32) stat->atime.tv_sec); *p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0); - lease_get_mtime(dentry->d_inode, &time); + lease_get_mtime(d_inode(dentry), &time); *p++ = htonl((u32) time.tv_sec); *p++ = htonl(time.tv_nsec ? time.tv_nsec / 1000 : 0); *p++ = htonl((u32) stat->ctime.tv_sec); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 368526582429..84d770be056e 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -174,7 +174,7 @@ int nfsd_mountpoint(struct dentry *dentry, struct svc_export *exp) return 1; if (!(exp->ex_flags & NFSEXP_V4ROOT)) return 0; - return dentry->d_inode != NULL; + return d_inode(dentry) != NULL; } __be32 @@ -270,7 +270,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, * dentry may be negative, it may need to be updated. */ err = fh_compose(resfh, exp, dentry, fhp); - if (!err && !dentry->d_inode) + if (!err && d_really_is_negative(dentry)) err = nfserr_noent; out: dput(dentry); @@ -284,7 +284,7 @@ out: static int commit_metadata(struct svc_fh *fhp) { - struct inode *inode = fhp->fh_dentry->d_inode; + struct inode *inode = d_inode(fhp->fh_dentry); const struct export_operations *export_ops = inode->i_sb->s_export_op; if (!EX_ISSYNC(fhp->fh_export)) @@ -364,7 +364,7 @@ static __be32 nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) { - struct inode *inode = fhp->fh_dentry->d_inode; + struct inode *inode = d_inode(fhp->fh_dentry); int host_err; if (iap->ia_size < inode->i_size) { @@ -426,7 +426,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, } dentry = fhp->fh_dentry; - inode = dentry->d_inode; + inode = d_inode(dentry); /* Ignore any mode updates on symlinks */ if (S_ISLNK(inode->i_mode)) @@ -495,7 +495,7 @@ out: */ int nfsd4_is_junction(struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); if (inode == NULL) return 0; @@ -521,9 +521,9 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, dentry = fhp->fh_dentry; - mutex_lock(&dentry->d_inode->i_mutex); + mutex_lock(&d_inode(dentry)->i_mutex); host_error = security_inode_setsecctx(dentry, label->data, label->len); - mutex_unlock(&dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(dentry)->i_mutex); return nfserrno(host_error); } #else @@ -706,7 +706,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, path.mnt = fhp->fh_export->ex_path.mnt; path.dentry = fhp->fh_dentry; - inode = path.dentry->d_inode; + inode = d_inode(path.dentry); /* Disallow write access to files with the append-only bit set * or any access when mandatory locking enabled @@ -1211,7 +1211,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; dentry = fhp->fh_dentry; - dirp = dentry->d_inode; + dirp = d_inode(dentry); err = nfserr_notdir; if (!dirp->i_op->lookup) @@ -1250,7 +1250,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, * Make sure the child dentry is still negative ... */ err = nfserr_exist; - if (dchild->d_inode) { + if (d_really_is_positive(dchild)) { dprintk("nfsd_create: dentry %pd/%pd not negative!\n", dentry, dchild); goto out; @@ -1353,7 +1353,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; dentry = fhp->fh_dentry; - dirp = dentry->d_inode; + dirp = d_inode(dentry); /* Get all the sanity checks out of the way before * we lock the parent. */ @@ -1376,7 +1376,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out_nfserr; /* If file doesn't exist, check for permissions to create one */ - if (!dchild->d_inode) { + if (d_really_is_negative(dchild)) { err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); if (err) goto out; @@ -1397,7 +1397,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, v_atime = verifier[1]&0x7fffffff; } - if (dchild->d_inode) { + if (d_really_is_positive(dchild)) { err = 0; switch (createmode) { @@ -1420,17 +1420,17 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, } break; case NFS3_CREATE_EXCLUSIVE: - if ( dchild->d_inode->i_mtime.tv_sec == v_mtime - && dchild->d_inode->i_atime.tv_sec == v_atime - && dchild->d_inode->i_size == 0 ) { + if ( d_inode(dchild)->i_mtime.tv_sec == v_mtime + && d_inode(dchild)->i_atime.tv_sec == v_atime + && d_inode(dchild)->i_size == 0 ) { if (created) *created = 1; break; } case NFS4_CREATE_EXCLUSIVE4_1: - if ( dchild->d_inode->i_mtime.tv_sec == v_mtime - && dchild->d_inode->i_atime.tv_sec == v_atime - && dchild->d_inode->i_size == 0 ) { + if ( d_inode(dchild)->i_mtime.tv_sec == v_mtime + && d_inode(dchild)->i_atime.tv_sec == v_atime + && d_inode(dchild)->i_size == 0 ) { if (created) *created = 1; goto set_attr; @@ -1513,7 +1513,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) path.mnt = fhp->fh_export->ex_path.mnt; path.dentry = fhp->fh_dentry; - inode = path.dentry->d_inode; + inode = d_inode(path.dentry); err = nfserr_inval; if (!inode->i_op->readlink) @@ -1576,7 +1576,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, if (IS_ERR(dnew)) goto out_nfserr; - host_err = vfs_symlink(dentry->d_inode, dnew, path); + host_err = vfs_symlink(d_inode(dentry), dnew, path); err = nfserrno(host_err); if (!err) err = nfserrno(commit_metadata(fhp)); @@ -1632,7 +1632,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, fh_lock_nested(ffhp, I_MUTEX_PARENT); ddir = ffhp->fh_dentry; - dirp = ddir->d_inode; + dirp = d_inode(ddir); dnew = lookup_one_len(name, ddir, len); host_err = PTR_ERR(dnew); @@ -1642,7 +1642,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, dold = tfhp->fh_dentry; err = nfserr_noent; - if (!dold->d_inode) + if (d_really_is_negative(dold)) goto out_dput; host_err = vfs_link(dold, dirp, dnew, NULL); if (!host_err) { @@ -1689,10 +1689,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, goto out; fdentry = ffhp->fh_dentry; - fdir = fdentry->d_inode; + fdir = d_inode(fdentry); tdentry = tfhp->fh_dentry; - tdir = tdentry->d_inode; + tdir = d_inode(tdentry); err = nfserr_perm; if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen)) @@ -1717,7 +1717,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, goto out_nfserr; host_err = -ENOENT; - if (!odentry->d_inode) + if (d_really_is_negative(odentry)) goto out_dput_old; host_err = -EINVAL; if (odentry == trap) @@ -1790,21 +1790,21 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, fh_lock_nested(fhp, I_MUTEX_PARENT); dentry = fhp->fh_dentry; - dirp = dentry->d_inode; + dirp = d_inode(dentry); rdentry = lookup_one_len(fname, dentry, flen); host_err = PTR_ERR(rdentry); if (IS_ERR(rdentry)) goto out_nfserr; - if (!rdentry->d_inode) { + if (d_really_is_negative(rdentry)) { dput(rdentry); err = nfserr_noent; goto out; } if (!type) - type = rdentry->d_inode->i_mode & S_IFMT; + type = d_inode(rdentry)->i_mode & S_IFMT; if (type != S_IFDIR) host_err = vfs_unlink(dirp, rdentry, NULL); @@ -2015,7 +2015,7 @@ __be32 nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, struct dentry *dentry, int acc) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int err; if ((acc & NFSD_MAY_MASK) == NFSD_MAY_NOP) diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 0bda93e58e1b..056f23a78ffd 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -632,7 +632,7 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) { BUG_ON(!fhp->fh_pre_saved); cinfo->atomic = fhp->fh_post_saved; - cinfo->change_supported = IS_I_VERSION(fhp->fh_dentry->d_inode); + cinfo->change_supported = IS_I_VERSION(d_inode(fhp->fh_dentry)); cinfo->before_change = fhp->fh_pre_change; cinfo->after_change = fhp->fh_post_change; diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c index 197a63e9d102..0ee0bed3649b 100644 --- a/fs/nilfs2/dir.c +++ b/fs/nilfs2/dir.c @@ -435,7 +435,7 @@ void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de, */ int nilfs_add_link(struct dentry *dentry, struct inode *inode) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); const unsigned char *name = dentry->d_name.name; int namelen = dentry->d_name.len; unsigned chunk_size = nilfs_chunk_size(dir); diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 36f057fa8aa3..310d87c51b40 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -834,7 +834,7 @@ void nilfs_evict_inode(struct inode *inode) int nilfs_setattr(struct dentry *dentry, struct iattr *iattr) { struct nilfs_transaction_info ti; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct super_block *sb = inode->i_sb; int err; diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 0f84b257932c..22180836ec22 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -192,7 +192,7 @@ out_fail: static int nilfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); struct nilfs_transaction_info ti; int err; @@ -283,7 +283,7 @@ static int nilfs_do_unlink(struct inode *dir, struct dentry *dentry) if (!de) goto out; - inode = dentry->d_inode; + inode = d_inode(dentry); err = -EIO; if (le64_to_cpu(de->inode) != inode->i_ino) goto out; @@ -318,7 +318,7 @@ static int nilfs_unlink(struct inode *dir, struct dentry *dentry) if (!err) { nilfs_mark_inode_dirty(dir); - nilfs_mark_inode_dirty(dentry->d_inode); + nilfs_mark_inode_dirty(d_inode(dentry)); err = nilfs_transaction_commit(dir->i_sb); } else nilfs_transaction_abort(dir->i_sb); @@ -328,7 +328,7 @@ static int nilfs_unlink(struct inode *dir, struct dentry *dentry) static int nilfs_rmdir(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct nilfs_transaction_info ti; int err; @@ -358,8 +358,8 @@ static int nilfs_rmdir(struct inode *dir, struct dentry *dentry) static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { - struct inode *old_inode = old_dentry->d_inode; - struct inode *new_inode = new_dentry->d_inode; + struct inode *old_inode = d_inode(old_dentry); + struct inode *new_inode = d_inode(new_dentry); struct page *dir_page = NULL; struct nilfs_dir_entry *dir_de = NULL; struct page *old_page; @@ -453,13 +453,13 @@ static struct dentry *nilfs_get_parent(struct dentry *child) struct qstr dotdot = QSTR_INIT("..", 2); struct nilfs_root *root; - ino = nilfs_inode_by_name(child->d_inode, &dotdot); + ino = nilfs_inode_by_name(d_inode(child), &dotdot); if (!ino) return ERR_PTR(-ENOENT); - root = NILFS_I(child->d_inode)->i_root; + root = NILFS_I(d_inode(child))->i_root; - inode = nilfs_iget(child->d_inode->i_sb, root, ino); + inode = nilfs_iget(d_inode(child)->i_sb, root, ino); if (IS_ERR(inode)) return ERR_CAST(inode); diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 5bc2a1cf73c3..282fb1037823 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -610,7 +610,7 @@ static int nilfs_unfreeze(struct super_block *sb) static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; - struct nilfs_root *root = NILFS_I(dentry->d_inode)->i_root; + struct nilfs_root *root = NILFS_I(d_inode(dentry))->i_root; struct the_nilfs *nilfs = root->nilfs; u64 id = huge_encode_dev(sb->s_bdev->bd_dev); unsigned long long blocks; @@ -681,7 +681,7 @@ static int nilfs_show_options(struct seq_file *seq, struct dentry *dentry) { struct super_block *sb = dentry->d_sb; struct the_nilfs *nilfs = sb->s_fs_info; - struct nilfs_root *root = NILFS_I(dentry->d_inode)->i_root; + struct nilfs_root *root = NILFS_I(d_inode(dentry))->i_root; if (!nilfs_test_opt(nilfs, BARRIER)) seq_puts(seq, ",nobarrier"); @@ -1190,7 +1190,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) sb->s_flags &= ~MS_RDONLY; - root = NILFS_I(sb->s_root->d_inode)->i_root; + root = NILFS_I(d_inode(sb->s_root))->i_root; err = nilfs_attach_log_writer(sb, root); if (err) goto restore_opts; diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 1d0c21df0d80..d284f07eda77 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -2889,7 +2889,7 @@ void ntfs_truncate_vfs(struct inode *vi) { */ int ntfs_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *vi = dentry->d_inode; + struct inode *vi = d_inode(dentry); int err; unsigned int ia_valid = attr->ia_valid; diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c index b3973c2fd190..0f35b80d17fe 100644 --- a/fs/ntfs/namei.c +++ b/fs/ntfs/namei.c @@ -292,14 +292,14 @@ const struct inode_operations ntfs_dir_inode_ops = { * The code is based on the ext3 ->get_parent() implementation found in * fs/ext3/namei.c::ext3_get_parent(). * - * Note: ntfs_get_parent() is called with @child_dent->d_inode->i_mutex down. + * Note: ntfs_get_parent() is called with @d_inode(child_dent)->i_mutex down. * * Return the dentry of the parent directory on success or the error code on * error (IS_ERR() is true). */ static struct dentry *ntfs_get_parent(struct dentry *child_dent) { - struct inode *vi = child_dent->d_inode; + struct inode *vi = d_inode(child_dent); ntfs_inode *ni = NTFS_I(vi); MFT_RECORD *mrec; ntfs_attr_search_ctx *ctx; diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c index 4fda7a5f3088..290373024d9d 100644 --- a/fs/ocfs2/dcache.c +++ b/fs/ocfs2/dcache.c @@ -42,8 +42,8 @@ void ocfs2_dentry_attach_gen(struct dentry *dentry) { unsigned long gen = - OCFS2_I(dentry->d_parent->d_inode)->ip_dir_lock_gen; - BUG_ON(dentry->d_inode); + OCFS2_I(d_inode(dentry->d_parent))->ip_dir_lock_gen; + BUG_ON(d_inode(dentry)); dentry->d_fsdata = (void *)gen; } @@ -57,7 +57,7 @@ static int ocfs2_dentry_revalidate(struct dentry *dentry, unsigned int flags) if (flags & LOOKUP_RCU) return -ECHILD; - inode = dentry->d_inode; + inode = d_inode(dentry); osb = OCFS2_SB(dentry->d_sb); trace_ocfs2_dentry_revalidate(dentry, dentry->d_name.len, @@ -71,7 +71,7 @@ static int ocfs2_dentry_revalidate(struct dentry *dentry, unsigned int flags) unsigned long gen = (unsigned long) dentry->d_fsdata; unsigned long pgen; spin_lock(&dentry->d_lock); - pgen = OCFS2_I(dentry->d_parent->d_inode)->ip_dir_lock_gen; + pgen = OCFS2_I(d_inode(dentry->d_parent))->ip_dir_lock_gen; spin_unlock(&dentry->d_lock); trace_ocfs2_dentry_revalidate_negative(dentry->d_name.len, dentry->d_name.name, @@ -146,7 +146,7 @@ static int ocfs2_match_dentry(struct dentry *dentry, if (skip_unhashed && d_unhashed(dentry)) return 0; - parent = dentry->d_parent->d_inode; + parent = d_inode(dentry->d_parent); /* Negative parent dentry? */ if (!parent) return 0; @@ -243,7 +243,7 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry, if (!inode) return 0; - if (!dentry->d_inode && dentry->d_fsdata) { + if (d_really_is_negative(dentry) && dentry->d_fsdata) { /* Converting a negative dentry to positive Clear dentry->d_fsdata */ dentry->d_fsdata = dl = NULL; @@ -446,7 +446,7 @@ void ocfs2_dentry_move(struct dentry *dentry, struct dentry *target, { int ret; struct ocfs2_super *osb = OCFS2_SB(old_dir->i_sb); - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); /* * Move within the same directory, so the actual lock info won't diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h index f0344b75b14d..3d8639f38973 100644 --- a/fs/ocfs2/dir.h +++ b/fs/ocfs2/dir.h @@ -72,7 +72,7 @@ static inline int ocfs2_add_entry(handle_t *handle, struct buffer_head *parent_fe_bh, struct ocfs2_dir_lookup_result *lookup) { - return __ocfs2_add_entry(handle, dentry->d_parent->d_inode, + return __ocfs2_add_entry(handle, d_inode(dentry->d_parent), dentry->d_name.name, dentry->d_name.len, inode, blkno, parent_fe_bh, lookup); } diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index 061ba6a91bf2..b5cf27dcb18a 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c @@ -208,7 +208,7 @@ static int dlmfs_file_release(struct inode *inode, static int dlmfs_file_setattr(struct dentry *dentry, struct iattr *attr) { int error; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); attr->ia_valid &= ~ATTR_SIZE; error = inode_change_ok(inode, attr); @@ -549,7 +549,7 @@ static int dlmfs_unlink(struct inode *dir, struct dentry *dentry) { int status; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); mlog(0, "unlink inode %lu\n", inode->i_ino); diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c index 29651167190d..facf456c481a 100644 --- a/fs/ocfs2/export.c +++ b/fs/ocfs2/export.c @@ -147,7 +147,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) int status; u64 blkno; struct dentry *parent; - struct inode *dir = child->d_inode; + struct inode *dir = d_inode(child); trace_ocfs2_get_parent(child, child->d_name.len, child->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno); diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 913fc250d85a..d8b670cbd909 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1126,7 +1126,7 @@ out: int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) { int status = 0, size_change; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct super_block *sb = inode->i_sb; struct ocfs2_super *osb = OCFS2_SB(sb); struct buffer_head *bh = NULL; @@ -1275,8 +1275,8 @@ int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct inode *inode = dentry->d_inode; - struct super_block *sb = dentry->d_inode->i_sb; + struct inode *inode = d_inode(dentry); + struct super_block *sb = d_inode(dentry)->i_sb; struct ocfs2_super *osb = sb->s_fs_info; int err; @@ -2114,7 +2114,7 @@ static int ocfs2_prepare_inode_for_write(struct file *file, { int ret = 0, meta_level = 0; struct dentry *dentry = file->f_path.dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); loff_t end; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); int full_coherency = !(osb->s_mount_opt & diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 3025c0da6b8a..751736109489 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -1209,7 +1209,7 @@ int ocfs2_drop_inode(struct inode *inode) */ int ocfs2_inode_revalidate(struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int status = 0; trace_ocfs2_inode_revalidate(inode, diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index b5c3a5ea3ee6..c0727037c6f9 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -689,8 +689,8 @@ static int ocfs2_link(struct dentry *old_dentry, struct dentry *dentry) { handle_t *handle; - struct inode *inode = old_dentry->d_inode; - struct inode *old_dir = old_dentry->d_parent->d_inode; + struct inode *inode = d_inode(old_dentry); + struct inode *old_dir = d_inode(old_dentry->d_parent); int err; struct buffer_head *fe_bh = NULL; struct buffer_head *old_dir_bh = NULL; @@ -879,7 +879,7 @@ static int ocfs2_unlink(struct inode *dir, int status; int child_locked = 0; bool is_unlinkable = false; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct inode *orphan_dir = NULL; struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); u64 blkno; @@ -898,7 +898,7 @@ static int ocfs2_unlink(struct inode *dir, dquot_initialize(dir); - BUG_ON(dentry->d_parent->d_inode != dir); + BUG_ON(d_inode(dentry->d_parent) != dir); if (inode == osb->root_inode) return -EPERM; @@ -1209,8 +1209,8 @@ static int ocfs2_rename(struct inode *old_dir, { int status = 0, rename_lock = 0, parents_locked = 0, target_exists = 0; int old_child_locked = 0, new_child_locked = 0, update_dot_dot = 0; - struct inode *old_inode = old_dentry->d_inode; - struct inode *new_inode = new_dentry->d_inode; + struct inode *old_inode = d_inode(old_dentry); + struct inode *new_inode = d_inode(new_dentry); struct inode *orphan_dir = NULL; struct ocfs2_dinode *newfe = NULL; char orphan_name[OCFS2_ORPHAN_NAMELEN + 1]; @@ -1454,7 +1454,7 @@ static int ocfs2_rename(struct inode *old_dir, should_add_orphan = true; } } else { - BUG_ON(new_dentry->d_parent->d_inode != new_dir); + BUG_ON(d_inode(new_dentry->d_parent) != new_dir); status = ocfs2_check_dir_for_entry(new_dir, new_dentry->d_name.name, diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index ee541f92dab4..2dc801255c4d 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -4194,7 +4194,7 @@ static int __ocfs2_reflink(struct dentry *old_dentry, bool preserve) { int ret; - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); struct buffer_head *new_bh = NULL; if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_SYSTEM_FILE) { @@ -4263,7 +4263,7 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, bool preserve) { int error; - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); struct buffer_head *old_bh = NULL; struct inode *new_orphan_inode = NULL; struct posix_acl *default_acl, *acl; @@ -4357,7 +4357,7 @@ out: /* copied from may_create in VFS. */ static inline int ocfs2_may_create(struct inode *dir, struct dentry *child) { - if (child->d_inode) + if (d_really_is_positive(child)) return -EEXIST; if (IS_DEADDIR(dir)) return -ENOENT; @@ -4375,7 +4375,7 @@ static inline int ocfs2_may_create(struct inode *dir, struct dentry *child) static int ocfs2_vfs_reflink(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, bool preserve) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); int error; if (!inode) @@ -4463,7 +4463,7 @@ int ocfs2_reflink_ioctl(struct inode *inode, } error = ocfs2_vfs_reflink(old_path.dentry, - new_path.dentry->d_inode, + d_inode(new_path.dentry), new_dentry, preserve); out_dput: done_path_create(&new_path, new_dentry); diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 85b190dc132f..4bbeb90863b7 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -1020,7 +1020,7 @@ ssize_t ocfs2_listxattr(struct dentry *dentry, int ret = 0, i_ret = 0, b_ret = 0; struct buffer_head *di_bh = NULL; struct ocfs2_dinode *di = NULL; - struct ocfs2_inode_info *oi = OCFS2_I(dentry->d_inode); + struct ocfs2_inode_info *oi = OCFS2_I(d_inode(dentry)); if (!ocfs2_supports_xattr(OCFS2_SB(dentry->d_sb))) return -EOPNOTSUPP; @@ -1028,7 +1028,7 @@ ssize_t ocfs2_listxattr(struct dentry *dentry, if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) return ret; - ret = ocfs2_inode_lock(dentry->d_inode, &di_bh, 0); + ret = ocfs2_inode_lock(d_inode(dentry), &di_bh, 0); if (ret < 0) { mlog_errno(ret); return ret; @@ -1037,7 +1037,7 @@ ssize_t ocfs2_listxattr(struct dentry *dentry, di = (struct ocfs2_dinode *)di_bh->b_data; down_read(&oi->ip_xattr_sem); - i_ret = ocfs2_xattr_ibody_list(dentry->d_inode, di, buffer, size); + i_ret = ocfs2_xattr_ibody_list(d_inode(dentry), di, buffer, size); if (i_ret < 0) b_ret = 0; else { @@ -1045,13 +1045,13 @@ ssize_t ocfs2_listxattr(struct dentry *dentry, buffer += i_ret; size -= i_ret; } - b_ret = ocfs2_xattr_block_list(dentry->d_inode, di, + b_ret = ocfs2_xattr_block_list(d_inode(dentry), di, buffer, size); if (b_ret < 0) i_ret = 0; } up_read(&oi->ip_xattr_sem); - ocfs2_inode_unlock(dentry->d_inode, 0); + ocfs2_inode_unlock(d_inode(dentry), 0); brelse(di_bh); @@ -7249,7 +7249,7 @@ static int ocfs2_xattr_security_get(struct dentry *dentry, const char *name, { if (strcmp(name, "") == 0) return -EINVAL; - return ocfs2_xattr_get(dentry->d_inode, OCFS2_XATTR_INDEX_SECURITY, + return ocfs2_xattr_get(d_inode(dentry), OCFS2_XATTR_INDEX_SECURITY, name, buffer, size); } @@ -7259,7 +7259,7 @@ static int ocfs2_xattr_security_set(struct dentry *dentry, const char *name, if (strcmp(name, "") == 0) return -EINVAL; - return ocfs2_xattr_set(dentry->d_inode, OCFS2_XATTR_INDEX_SECURITY, + return ocfs2_xattr_set(d_inode(dentry), OCFS2_XATTR_INDEX_SECURITY, name, value, size, flags); } @@ -7339,7 +7339,7 @@ static int ocfs2_xattr_trusted_get(struct dentry *dentry, const char *name, { if (strcmp(name, "") == 0) return -EINVAL; - return ocfs2_xattr_get(dentry->d_inode, OCFS2_XATTR_INDEX_TRUSTED, + return ocfs2_xattr_get(d_inode(dentry), OCFS2_XATTR_INDEX_TRUSTED, name, buffer, size); } @@ -7349,7 +7349,7 @@ static int ocfs2_xattr_trusted_set(struct dentry *dentry, const char *name, if (strcmp(name, "") == 0) return -EINVAL; - return ocfs2_xattr_set(dentry->d_inode, OCFS2_XATTR_INDEX_TRUSTED, + return ocfs2_xattr_set(d_inode(dentry), OCFS2_XATTR_INDEX_TRUSTED, name, value, size, flags); } @@ -7391,7 +7391,7 @@ static int ocfs2_xattr_user_get(struct dentry *dentry, const char *name, return -EINVAL; if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) return -EOPNOTSUPP; - return ocfs2_xattr_get(dentry->d_inode, OCFS2_XATTR_INDEX_USER, name, + return ocfs2_xattr_get(d_inode(dentry), OCFS2_XATTR_INDEX_USER, name, buffer, size); } @@ -7405,7 +7405,7 @@ static int ocfs2_xattr_user_set(struct dentry *dentry, const char *name, if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) return -EOPNOTSUPP; - return ocfs2_xattr_set(dentry->d_inode, OCFS2_XATTR_INDEX_USER, + return ocfs2_xattr_set(d_inode(dentry), OCFS2_XATTR_INDEX_USER, name, value, size, flags); } diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c index 1b8e9e8405b2..f833bf8d5792 100644 --- a/fs/omfs/dir.c +++ b/fs/omfs/dir.c @@ -110,7 +110,7 @@ int omfs_make_empty(struct inode *inode, struct super_block *sb) static int omfs_add_link(struct dentry *dentry, struct inode *inode) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; struct omfs_inode *oi; @@ -155,7 +155,7 @@ out: static int omfs_delete_entry(struct dentry *dentry) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); struct inode *dirty; const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; @@ -237,7 +237,7 @@ static int omfs_dir_is_empty(struct inode *inode) static int omfs_remove(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int ret; @@ -373,8 +373,8 @@ static bool omfs_fill_chain(struct inode *dir, struct dir_context *ctx, static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { - struct inode *new_inode = new_dentry->d_inode; - struct inode *old_inode = old_dentry->d_inode; + struct inode *new_inode = d_inode(new_dentry); + struct inode *old_inode = d_inode(old_dentry); int err; if (new_inode) { diff --git a/fs/omfs/file.c b/fs/omfs/file.c index f993be7f2156..d9e26cfbb793 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c @@ -346,7 +346,7 @@ const struct file_operations omfs_file_operations = { static int omfs_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error; error = inode_change_ok(inode, attr); diff --git a/fs/proc/base.c b/fs/proc/base.c index 3f3d7aeb0712..a3d6b559178b 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -169,7 +169,7 @@ static int get_task_root(struct task_struct *task, struct path *root) static int proc_cwd_link(struct dentry *dentry, struct path *path) { - struct task_struct *task = get_proc_task(dentry->d_inode); + struct task_struct *task = get_proc_task(d_inode(dentry)); int result = -ENOENT; if (task) { @@ -186,7 +186,7 @@ static int proc_cwd_link(struct dentry *dentry, struct path *path) static int proc_root_link(struct dentry *dentry, struct path *path) { - struct task_struct *task = get_proc_task(dentry->d_inode); + struct task_struct *task = get_proc_task(d_inode(dentry)); int result = -ENOENT; if (task) { @@ -505,7 +505,7 @@ static int proc_fd_access_allowed(struct inode *inode) int proc_setattr(struct dentry *dentry, struct iattr *attr) { int error; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); if (attr->ia_valid & ATTR_MODE) return -EPERM; @@ -1353,7 +1353,7 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path) struct mm_struct *mm; struct file *exe_file; - task = get_proc_task(dentry->d_inode); + task = get_proc_task(d_inode(dentry)); if (!task) return -ENOENT; mm = get_task_mm(task); @@ -1373,7 +1373,7 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path) static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct path path; int error = -EACCES; @@ -1418,7 +1418,7 @@ static int do_proc_readlink(struct path *path, char __user *buffer, int buflen) static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int buflen) { int error = -EACCES; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct path path; /* Are we allowed to snoop on the tasks file descriptors? */ @@ -1488,7 +1488,7 @@ out_unlock: int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct task_struct *task; const struct cred *cred; struct pid_namespace *pid = dentry->d_sb->s_fs_info; @@ -1545,7 +1545,7 @@ int pid_revalidate(struct dentry *dentry, unsigned int flags) if (flags & LOOKUP_RCU) return -ECHILD; - inode = dentry->d_inode; + inode = d_inode(dentry); task = get_proc_task(inode); if (task) { @@ -1579,7 +1579,7 @@ int pid_delete_dentry(const struct dentry *dentry) * If so, then don't put the dentry on the lru list, * kill it immediately. */ - return proc_inode_is_dead(dentry->d_inode); + return proc_inode_is_dead(d_inode(dentry)); } const struct dentry_operations pid_dentry_operations = @@ -1617,12 +1617,12 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx, child = d_alloc(dir, &qname); if (!child) goto end_instantiate; - if (instantiate(dir->d_inode, child, task, ptr) < 0) { + if (instantiate(d_inode(dir), child, task, ptr) < 0) { dput(child); goto end_instantiate; } } - inode = child->d_inode; + inode = d_inode(child); ino = inode->i_ino; type = inode->i_mode >> 12; dput(child); @@ -1665,7 +1665,7 @@ static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags) goto out_notask; } - inode = dentry->d_inode; + inode = d_inode(dentry); task = get_proc_task(inode); if (!task) goto out_notask; @@ -1718,7 +1718,7 @@ static int proc_map_files_get_link(struct dentry *dentry, struct path *path) int rc; rc = -ENOENT; - task = get_proc_task(dentry->d_inode); + task = get_proc_task(d_inode(dentry)); if (!task) goto out; @@ -2851,13 +2851,13 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx) return 0; if (pos == TGID_OFFSET - 2) { - struct inode *inode = ns->proc_self->d_inode; + struct inode *inode = d_inode(ns->proc_self); if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK)) return 0; ctx->pos = pos = pos + 1; } if (pos == TGID_OFFSET - 1) { - struct inode *inode = ns->proc_thread_self->d_inode; + struct inode *inode = d_inode(ns->proc_thread_self); if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK)) return 0; ctx->pos = pos = pos + 1; @@ -3176,7 +3176,7 @@ static int proc_task_readdir(struct file *file, struct dir_context *ctx) static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct task_struct *p = get_proc_task(inode); generic_fillattr(inode, stat); diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 8e5ad83b629a..a205904a27ae 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -84,7 +84,7 @@ static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) if (flags & LOOKUP_RCU) return -ECHILD; - inode = dentry->d_inode; + inode = d_inode(dentry); task = get_proc_task(inode); fd = proc_fd(inode); @@ -144,14 +144,14 @@ static int proc_fd_link(struct dentry *dentry, struct path *path) struct task_struct *task; int ret = -ENOENT; - task = get_proc_task(dentry->d_inode); + task = get_proc_task(d_inode(dentry)); if (task) { files = get_files_struct(task); put_task_struct(task); } if (files) { - int fd = proc_fd(dentry->d_inode); + int fd = proc_fd(d_inode(dentry)); struct file *fd_file; spin_lock(&files->file_lock); diff --git a/fs/proc/generic.c b/fs/proc/generic.c index be65b2082135..df6327a2b865 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -101,7 +101,7 @@ static bool pde_subdir_insert(struct proc_dir_entry *dir, static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct proc_dir_entry *de = PDE(inode); int error; @@ -120,7 +120,7 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct proc_dir_entry *de = PDE(inode); if (de && de->nlink) set_nlink(inode, de->nlink); diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 7697b6621cfd..8272aaba1bb0 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -396,7 +396,7 @@ static const struct file_operations proc_reg_file_ops_no_compat = { static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct proc_dir_entry *pde = PDE(dentry->d_inode); + struct proc_dir_entry *pde = PDE(d_inode(dentry)); if (unlikely(!use_pde(pde))) return ERR_PTR(-EINVAL); nd_set_link(nd, pde->data); diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index c9eac4563fa8..e512642dbbdc 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -32,7 +32,7 @@ static const struct proc_ns_operations *ns_entries[] = { static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; struct task_struct *task; struct path ns_path; @@ -53,7 +53,7 @@ static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; struct task_struct *task; char name[50]; diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 1bde894bc624..350984a19c83 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -142,7 +142,7 @@ static struct dentry *proc_tgid_net_lookup(struct inode *dir, static int proc_tgid_net_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct net *net; net = get_proc_task_net(inode); diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index f92d5dd578a4..fea2561d773b 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -604,7 +604,7 @@ static bool proc_sys_fill_cache(struct file *file, return false; } } - inode = child->d_inode; + inode = d_inode(child); ino = inode->i_ino; type = inode->i_mode >> 12; dput(child); @@ -710,7 +710,7 @@ static int proc_sys_permission(struct inode *inode, int mask) static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error; if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) @@ -727,7 +727,7 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr) static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ctl_table_header *head = grab_header(inode); struct ctl_table *table = PROC_I(inode)->sysctl_entry; @@ -773,12 +773,12 @@ static int proc_sys_revalidate(struct dentry *dentry, unsigned int flags) { if (flags & LOOKUP_RCU) return -ECHILD; - return !PROC_I(dentry->d_inode)->sysctl->unregistering; + return !PROC_I(d_inode(dentry))->sysctl->unregistering; } static int proc_sys_delete(const struct dentry *dentry) { - return !!PROC_I(dentry->d_inode)->sysctl->unregistering; + return !!PROC_I(d_inode(dentry))->sysctl->unregistering; } static int sysctl_is_seen(struct ctl_table_header *p) @@ -805,7 +805,7 @@ static int proc_sys_compare(const struct dentry *parent, const struct dentry *de /* Although proc doesn't have negative dentries, rcu-walk means * that inode here can be NULL */ /* AV: can it, indeed? */ - inode = ACCESS_ONCE(dentry->d_inode); + inode = d_inode_rcu(dentry); if (!inode) return 1; if (name->len != len) diff --git a/fs/proc/root.c b/fs/proc/root.c index e74ac9f1a2c0..b7fa4bfe896a 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -195,7 +195,7 @@ void __init proc_root_init(void) static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat ) { - generic_fillattr(dentry->d_inode, stat); + generic_fillattr(d_inode(dentry), stat); stat->nlink = proc_root.nlink + nr_processes(); return 0; } diff --git a/fs/proc/self.c b/fs/proc/self.c index 4348bb8907c2..6195b4a7c3b1 100644 --- a/fs/proc/self.c +++ b/fs/proc/self.c @@ -46,7 +46,7 @@ static unsigned self_inum; int proc_setup_self(struct super_block *s) { - struct inode *root_inode = s->s_root->d_inode; + struct inode *root_inode = d_inode(s->s_root); struct pid_namespace *ns = s->s_fs_info; struct dentry *self; diff --git a/fs/proc/thread_self.c b/fs/proc/thread_self.c index 59075b509df3..a8371993b4fb 100644 --- a/fs/proc/thread_self.c +++ b/fs/proc/thread_self.c @@ -47,7 +47,7 @@ static unsigned thread_self_inum; int proc_setup_thread_self(struct super_block *s) { - struct inode *root_inode = s->s_root->d_inode; + struct inode *root_inode = d_inode(s->s_root); struct pid_namespace *ns = s->s_fs_info; struct dentry *thread_self; diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index b32ce53d24ee..9f73797f95a6 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -190,7 +190,7 @@ static const struct file_operations pstore_file_operations = { */ static int pstore_unlink(struct inode *dir, struct dentry *dentry) { - struct pstore_private *p = dentry->d_inode->i_private; + struct pstore_private *p = d_inode(dentry)->i_private; int err; err = pstore_check_syslog_permissions(p); @@ -199,7 +199,7 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry) if (p->psi->erase) p->psi->erase(p->type, p->id, p->count, - dentry->d_inode->i_ctime, p->psi); + d_inode(dentry)->i_ctime, p->psi); else return -EPERM; @@ -373,7 +373,7 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, break; } - mutex_lock(&root->d_inode->i_mutex); + mutex_lock(&d_inode(root)->i_mutex); dentry = d_alloc_name(root, name); if (!dentry) @@ -393,12 +393,12 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, list_add(&private->list, &allpstore); spin_unlock_irqrestore(&allpstore_lock, flags); - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&d_inode(root)->i_mutex); return 0; fail_lockedalloc: - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&d_inode(root)->i_mutex); kfree(private); fail_alloc: iput(inode); diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c index 44e73923670d..32d2e1a9774c 100644 --- a/fs/qnx6/inode.c +++ b/fs/qnx6/inode.c @@ -182,7 +182,7 @@ static const char *qnx6_checkroot(struct super_block *s) static char match_root[2][3] = {".\0\0", "..\0"}; int i, error = 0; struct qnx6_dir_entry *dir_entry; - struct inode *root = s->s_root->d_inode; + struct inode *root = d_inode(s->s_root); struct address_space *mapping = root->i_mapping; struct page *page = read_mapping_page(mapping, 0, NULL); if (IS_ERR(page)) diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index 0b38befa69f3..ba1323a94924 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c @@ -163,7 +163,7 @@ static int ramfs_nommu_resize(struct inode *inode, loff_t newsize, loff_t size) */ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); unsigned int old_ia_valid = ia->ia_valid; int ret = 0; diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c index 0a7dc941aaf4..4a024e2ceb9f 100644 --- a/fs/reiserfs/dir.c +++ b/fs/reiserfs/dir.c @@ -53,8 +53,8 @@ static int reiserfs_dir_fsync(struct file *filp, loff_t start, loff_t end, static inline bool is_privroot_deh(struct inode *dir, struct reiserfs_de_head *deh) { struct dentry *privroot = REISERFS_SB(dir->i_sb)->priv_root; - return (privroot->d_inode && - deh->deh_objectid == INODE_PKEY(privroot->d_inode)->k_objectid); + return (d_really_is_positive(privroot) && + deh->deh_objectid == INODE_PKEY(d_inode(privroot))->k_objectid); } int reiserfs_readdir_inode(struct inode *inode, struct dir_context *ctx) diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 742242b60972..f6f2fbad9777 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -3308,7 +3308,7 @@ static ssize_t reiserfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); unsigned int ia_valid; int error; diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index cd11358b10c7..b55a074653d7 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -400,7 +400,7 @@ struct dentry *reiserfs_get_parent(struct dentry *child) struct inode *inode = NULL; struct reiserfs_dir_entry de; INITIALIZE_PATH(path_to_entry); - struct inode *dir = child->d_inode; + struct inode *dir = d_inode(child); if (dir->i_nlink == 0) { return ERR_PTR(-ENOENT); @@ -917,7 +917,7 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry) goto end_rmdir; } - inode = dentry->d_inode; + inode = d_inode(dentry); reiserfs_update_inode_transaction(inode); reiserfs_update_inode_transaction(dir); @@ -987,7 +987,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry) dquot_initialize(dir); - inode = dentry->d_inode; + inode = d_inode(dentry); /* * in this transaction we can be doing at max two balancings and @@ -1174,7 +1174,7 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { int retval; - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); struct reiserfs_transaction_handle th; /* * We need blocks for transaction + update of quotas for @@ -1311,8 +1311,8 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, dquot_initialize(old_dir); dquot_initialize(new_dir); - old_inode = old_dentry->d_inode; - new_dentry_inode = new_dentry->d_inode; + old_inode = d_inode(old_dentry); + new_dentry_inode = d_inode(new_dentry); /* * make sure that oldname still exists and points to an object we diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 71fbbe3e2dab..558ef2ce1bdd 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1687,7 +1687,7 @@ static __u32 find_hash_out(struct super_block *s) __u32 hash = DEFAULT_HASH; __u32 deh_hashval, teahash, r5hash, yurahash; - inode = s->s_root->d_inode; + inode = d_inode(s->s_root); make_cpu_key(&key, inode, ~0, TYPE_DIRENTRY, 3); retval = search_by_entry_key(s, &key, &path, &de); @@ -2347,7 +2347,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, err = -EXDEV; goto out; } - inode = path->dentry->d_inode; + inode = d_inode(path->dentry); /* * We must not pack tails for quota files on reiserfs for quota * IO to work diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 4e781e697c90..e87f9b52bf06 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -87,9 +87,9 @@ static int xattr_unlink(struct inode *dir, struct dentry *dentry) BUG_ON(!mutex_is_locked(&dir->i_mutex)); - mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); + mutex_lock_nested(&d_inode(dentry)->i_mutex, I_MUTEX_CHILD); error = dir->i_op->unlink(dir, dentry); - mutex_unlock(&dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(dentry)->i_mutex); if (!error) d_delete(dentry); @@ -102,11 +102,11 @@ static int xattr_rmdir(struct inode *dir, struct dentry *dentry) BUG_ON(!mutex_is_locked(&dir->i_mutex)); - mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); + mutex_lock_nested(&d_inode(dentry)->i_mutex, I_MUTEX_CHILD); error = dir->i_op->rmdir(dir, dentry); if (!error) - dentry->d_inode->i_flags |= S_DEAD; - mutex_unlock(&dentry->d_inode->i_mutex); + d_inode(dentry)->i_flags |= S_DEAD; + mutex_unlock(&d_inode(dentry)->i_mutex); if (!error) d_delete(dentry); @@ -120,26 +120,26 @@ static struct dentry *open_xa_root(struct super_block *sb, int flags) struct dentry *privroot = REISERFS_SB(sb)->priv_root; struct dentry *xaroot; - if (!privroot->d_inode) + if (d_really_is_negative(privroot)) return ERR_PTR(-ENODATA); - mutex_lock_nested(&privroot->d_inode->i_mutex, I_MUTEX_XATTR); + mutex_lock_nested(&d_inode(privroot)->i_mutex, I_MUTEX_XATTR); xaroot = dget(REISERFS_SB(sb)->xattr_root); if (!xaroot) xaroot = ERR_PTR(-ENODATA); - else if (!xaroot->d_inode) { + else if (d_really_is_negative(xaroot)) { int err = -ENODATA; if (xattr_may_create(flags)) - err = xattr_mkdir(privroot->d_inode, xaroot, 0700); + err = xattr_mkdir(d_inode(privroot), xaroot, 0700); if (err) { dput(xaroot); xaroot = ERR_PTR(err); } } - mutex_unlock(&privroot->d_inode->i_mutex); + mutex_unlock(&d_inode(privroot)->i_mutex); return xaroot; } @@ -156,21 +156,21 @@ static struct dentry *open_xa_dir(const struct inode *inode, int flags) le32_to_cpu(INODE_PKEY(inode)->k_objectid), inode->i_generation); - mutex_lock_nested(&xaroot->d_inode->i_mutex, I_MUTEX_XATTR); + mutex_lock_nested(&d_inode(xaroot)->i_mutex, I_MUTEX_XATTR); xadir = lookup_one_len(namebuf, xaroot, strlen(namebuf)); - if (!IS_ERR(xadir) && !xadir->d_inode) { + if (!IS_ERR(xadir) && d_really_is_negative(xadir)) { int err = -ENODATA; if (xattr_may_create(flags)) - err = xattr_mkdir(xaroot->d_inode, xadir, 0700); + err = xattr_mkdir(d_inode(xaroot), xadir, 0700); if (err) { dput(xadir); xadir = ERR_PTR(err); } } - mutex_unlock(&xaroot->d_inode->i_mutex); + mutex_unlock(&d_inode(xaroot)->i_mutex); dput(xaroot); return xadir; } @@ -195,7 +195,7 @@ fill_with_dentries(struct dir_context *ctx, const char *name, int namelen, container_of(ctx, struct reiserfs_dentry_buf, ctx); struct dentry *dentry; - WARN_ON_ONCE(!mutex_is_locked(&dbuf->xadir->d_inode->i_mutex)); + WARN_ON_ONCE(!mutex_is_locked(&d_inode(dbuf->xadir)->i_mutex)); if (dbuf->count == ARRAY_SIZE(dbuf->dentries)) return -ENOSPC; @@ -207,7 +207,7 @@ fill_with_dentries(struct dir_context *ctx, const char *name, int namelen, dentry = lookup_one_len(name, dbuf->xadir, namelen); if (IS_ERR(dentry)) { return PTR_ERR(dentry); - } else if (!dentry->d_inode) { + } else if (d_really_is_negative(dentry)) { /* A directory entry exists, but no file? */ reiserfs_error(dentry->d_sb, "xattr-20003", "Corrupted directory: xattr %pd listed but " @@ -249,16 +249,16 @@ static int reiserfs_for_each_xattr(struct inode *inode, if (IS_ERR(dir)) { err = PTR_ERR(dir); goto out; - } else if (!dir->d_inode) { + } else if (d_really_is_negative(dir)) { err = 0; goto out_dir; } - mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); + mutex_lock_nested(&d_inode(dir)->i_mutex, I_MUTEX_XATTR); buf.xadir = dir; while (1) { - err = reiserfs_readdir_inode(dir->d_inode, &buf.ctx); + err = reiserfs_readdir_inode(d_inode(dir), &buf.ctx); if (err) break; if (!buf.count) @@ -276,7 +276,7 @@ static int reiserfs_for_each_xattr(struct inode *inode, break; buf.count = 0; } - mutex_unlock(&dir->d_inode->i_mutex); + mutex_unlock(&d_inode(dir)->i_mutex); cleanup_dentry_buf(&buf); @@ -298,13 +298,13 @@ static int reiserfs_for_each_xattr(struct inode *inode, if (!err) { int jerror; - mutex_lock_nested(&dir->d_parent->d_inode->i_mutex, + mutex_lock_nested(&d_inode(dir->d_parent)->i_mutex, I_MUTEX_XATTR); err = action(dir, data); reiserfs_write_lock(inode->i_sb); jerror = journal_end(&th); reiserfs_write_unlock(inode->i_sb); - mutex_unlock(&dir->d_parent->d_inode->i_mutex); + mutex_unlock(&d_inode(dir->d_parent)->i_mutex); err = jerror ?: err; } } @@ -319,7 +319,7 @@ out: static int delete_one_xattr(struct dentry *dentry, void *data) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); /* This is the xattr dir, handle specially. */ if (d_is_dir(dentry)) @@ -384,27 +384,27 @@ static struct dentry *xattr_lookup(struct inode *inode, const char *name, if (IS_ERR(xadir)) return ERR_CAST(xadir); - mutex_lock_nested(&xadir->d_inode->i_mutex, I_MUTEX_XATTR); + mutex_lock_nested(&d_inode(xadir)->i_mutex, I_MUTEX_XATTR); xafile = lookup_one_len(name, xadir, strlen(name)); if (IS_ERR(xafile)) { err = PTR_ERR(xafile); goto out; } - if (xafile->d_inode && (flags & XATTR_CREATE)) + if (d_really_is_positive(xafile) && (flags & XATTR_CREATE)) err = -EEXIST; - if (!xafile->d_inode) { + if (d_really_is_negative(xafile)) { err = -ENODATA; if (xattr_may_create(flags)) - err = xattr_create(xadir->d_inode, xafile, + err = xattr_create(d_inode(xadir), xafile, 0700|S_IFREG); } if (err) dput(xafile); out: - mutex_unlock(&xadir->d_inode->i_mutex); + mutex_unlock(&d_inode(xadir)->i_mutex); dput(xadir); if (err) return ERR_PTR(err); @@ -469,21 +469,21 @@ static int lookup_and_delete_xattr(struct inode *inode, const char *name) if (IS_ERR(xadir)) return PTR_ERR(xadir); - mutex_lock_nested(&xadir->d_inode->i_mutex, I_MUTEX_XATTR); + mutex_lock_nested(&d_inode(xadir)->i_mutex, I_MUTEX_XATTR); dentry = lookup_one_len(name, xadir, strlen(name)); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); goto out_dput; } - if (dentry->d_inode) { - err = xattr_unlink(xadir->d_inode, dentry); + if (d_really_is_positive(dentry)) { + err = xattr_unlink(d_inode(xadir), dentry); update_ctime(inode); } dput(dentry); out_dput: - mutex_unlock(&xadir->d_inode->i_mutex); + mutex_unlock(&d_inode(xadir)->i_mutex); dput(xadir); return err; } @@ -533,7 +533,7 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th, else chunk = buffer_size - buffer_pos; - page = reiserfs_get_page(dentry->d_inode, file_pos); + page = reiserfs_get_page(d_inode(dentry), file_pos); if (IS_ERR(page)) { err = PTR_ERR(page); goto out_unlock; @@ -573,18 +573,18 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th, } new_size = buffer_size + sizeof(struct reiserfs_xattr_header); - if (!err && new_size < i_size_read(dentry->d_inode)) { + if (!err && new_size < i_size_read(d_inode(dentry))) { struct iattr newattrs = { .ia_ctime = current_fs_time(inode->i_sb), .ia_size = new_size, .ia_valid = ATTR_SIZE | ATTR_CTIME, }; - mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR); - inode_dio_wait(dentry->d_inode); + mutex_lock_nested(&d_inode(dentry)->i_mutex, I_MUTEX_XATTR); + inode_dio_wait(d_inode(dentry)); err = reiserfs_setattr(dentry, &newattrs); - mutex_unlock(&dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(dentry)->i_mutex); } else update_ctime(inode); out_unlock: @@ -657,7 +657,7 @@ reiserfs_xattr_get(struct inode *inode, const char *name, void *buffer, down_read(&REISERFS_I(inode)->i_xattr_sem); - isize = i_size_read(dentry->d_inode); + isize = i_size_read(d_inode(dentry)); /* Just return the size needed */ if (buffer == NULL) { @@ -680,7 +680,7 @@ reiserfs_xattr_get(struct inode *inode, const char *name, void *buffer, else chunk = isize - file_pos; - page = reiserfs_get_page(dentry->d_inode, file_pos); + page = reiserfs_get_page(d_inode(dentry), file_pos); if (IS_ERR(page)) { err = PTR_ERR(page); goto out_unlock; @@ -775,7 +775,7 @@ reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer, handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name); - if (!handler || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) + if (!handler || get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1) return -EOPNOTSUPP; return handler->get(dentry, name, buffer, size, handler->flags); @@ -784,7 +784,7 @@ reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer, /* * Inode operation setxattr() * - * dentry->d_inode->i_mutex down + * d_inode(dentry)->i_mutex down */ int reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value, @@ -794,7 +794,7 @@ reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value, handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name); - if (!handler || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) + if (!handler || get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1) return -EOPNOTSUPP; return handler->set(dentry, name, value, size, flags, handler->flags); @@ -803,7 +803,7 @@ reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value, /* * Inode operation removexattr() * - * dentry->d_inode->i_mutex down + * d_inode(dentry)->i_mutex down */ int reiserfs_removexattr(struct dentry *dentry, const char *name) { @@ -811,7 +811,7 @@ int reiserfs_removexattr(struct dentry *dentry, const char *name) handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name); - if (!handler || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) + if (!handler || get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1) return -EOPNOTSUPP; return handler->set(dentry, name, NULL, 0, XATTR_REPLACE, handler->flags); @@ -875,14 +875,14 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) .size = buffer ? size : 0, }; - if (!dentry->d_inode) + if (d_really_is_negative(dentry)) return -EINVAL; if (!dentry->d_sb->s_xattr || - get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) + get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1) return -EOPNOTSUPP; - dir = open_xa_dir(dentry->d_inode, XATTR_REPLACE); + dir = open_xa_dir(d_inode(dentry), XATTR_REPLACE); if (IS_ERR(dir)) { err = PTR_ERR(dir); if (err == -ENODATA) @@ -890,9 +890,9 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) goto out; } - mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); - err = reiserfs_readdir_inode(dir->d_inode, &buf.ctx); - mutex_unlock(&dir->d_inode->i_mutex); + mutex_lock_nested(&d_inode(dir)->i_mutex, I_MUTEX_XATTR); + err = reiserfs_readdir_inode(d_inode(dir), &buf.ctx); + mutex_unlock(&d_inode(dir)->i_mutex); if (!err) err = buf.pos; @@ -905,12 +905,12 @@ out: static int create_privroot(struct dentry *dentry) { int err; - struct inode *inode = dentry->d_parent->d_inode; + struct inode *inode = d_inode(dentry->d_parent); WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex)); err = xattr_mkdir(inode, dentry, 0700); - if (err || !dentry->d_inode) { + if (err || d_really_is_negative(dentry)) { reiserfs_warning(dentry->d_sb, "jdm-20006", "xattrs/ACLs enabled and couldn't " "find/create .reiserfs_priv. " @@ -918,7 +918,7 @@ static int create_privroot(struct dentry *dentry) return -EOPNOTSUPP; } - dentry->d_inode->i_flags |= S_PRIVATE; + d_inode(dentry)->i_flags |= S_PRIVATE; reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr " "storage.\n", PRIVROOT_NAME); @@ -997,17 +997,17 @@ int reiserfs_lookup_privroot(struct super_block *s) int err = 0; /* If we don't have the privroot located yet - go find it */ - mutex_lock(&s->s_root->d_inode->i_mutex); + mutex_lock(&d_inode(s->s_root)->i_mutex); dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, strlen(PRIVROOT_NAME)); if (!IS_ERR(dentry)) { REISERFS_SB(s)->priv_root = dentry; d_set_d_op(dentry, &xattr_lookup_poison_ops); - if (dentry->d_inode) - dentry->d_inode->i_flags |= S_PRIVATE; + if (d_really_is_positive(dentry)) + d_inode(dentry)->i_flags |= S_PRIVATE; } else err = PTR_ERR(dentry); - mutex_unlock(&s->s_root->d_inode->i_mutex); + mutex_unlock(&d_inode(s->s_root)->i_mutex); return err; } @@ -1026,15 +1026,15 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags) if (err) goto error; - if (!privroot->d_inode && !(mount_flags & MS_RDONLY)) { - mutex_lock(&s->s_root->d_inode->i_mutex); + if (d_really_is_negative(privroot) && !(mount_flags & MS_RDONLY)) { + mutex_lock(&d_inode(s->s_root)->i_mutex); err = create_privroot(REISERFS_SB(s)->priv_root); - mutex_unlock(&s->s_root->d_inode->i_mutex); + mutex_unlock(&d_inode(s->s_root)->i_mutex); } - if (privroot->d_inode) { + if (d_really_is_positive(privroot)) { s->s_xattr = reiserfs_xattr_handlers; - mutex_lock(&privroot->d_inode->i_mutex); + mutex_lock(&d_inode(privroot)->i_mutex); if (!REISERFS_SB(s)->xattr_root) { struct dentry *dentry; @@ -1045,7 +1045,7 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags) else err = PTR_ERR(dentry); } - mutex_unlock(&privroot->d_inode->i_mutex); + mutex_unlock(&d_inode(privroot)->i_mutex); } error: diff --git a/fs/reiserfs/xattr.h b/fs/reiserfs/xattr.h index f620e9678dd5..15dde6262c00 100644 --- a/fs/reiserfs/xattr.h +++ b/fs/reiserfs/xattr.h @@ -78,7 +78,7 @@ static inline size_t reiserfs_xattr_jcreate_nblocks(struct inode *inode) if ((REISERFS_I(inode)->i_flags & i_has_xattr_dir) == 0) { nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); - if (!REISERFS_SB(inode->i_sb)->xattr_root->d_inode) + if (d_really_is_negative(REISERFS_SB(inode->i_sb)->xattr_root)) nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); } diff --git a/fs/reiserfs/xattr_security.c b/fs/reiserfs/xattr_security.c index e7f8939a4cb5..9a3b0616f283 100644 --- a/fs/reiserfs/xattr_security.c +++ b/fs/reiserfs/xattr_security.c @@ -15,10 +15,10 @@ security_get(struct dentry *dentry, const char *name, void *buffer, size_t size, if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX)) return -EINVAL; - if (IS_PRIVATE(dentry->d_inode)) + if (IS_PRIVATE(d_inode(dentry))) return -EPERM; - return reiserfs_xattr_get(dentry->d_inode, name, buffer, size); + return reiserfs_xattr_get(d_inode(dentry), name, buffer, size); } static int @@ -28,10 +28,10 @@ security_set(struct dentry *dentry, const char *name, const void *buffer, if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX)) return -EINVAL; - if (IS_PRIVATE(dentry->d_inode)) + if (IS_PRIVATE(d_inode(dentry))) return -EPERM; - return reiserfs_xattr_set(dentry->d_inode, name, buffer, size, flags); + return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags); } static size_t security_list(struct dentry *dentry, char *list, size_t list_len, @@ -39,7 +39,7 @@ static size_t security_list(struct dentry *dentry, char *list, size_t list_len, { const size_t len = namelen + 1; - if (IS_PRIVATE(dentry->d_inode)) + if (IS_PRIVATE(d_inode(dentry))) return 0; if (list && len <= list_len) { diff --git a/fs/reiserfs/xattr_trusted.c b/fs/reiserfs/xattr_trusted.c index 5eeb0c48ba46..e4f1343714e0 100644 --- a/fs/reiserfs/xattr_trusted.c +++ b/fs/reiserfs/xattr_trusted.c @@ -14,10 +14,10 @@ trusted_get(struct dentry *dentry, const char *name, void *buffer, size_t size, if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX)) return -EINVAL; - if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(dentry->d_inode)) + if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(d_inode(dentry))) return -EPERM; - return reiserfs_xattr_get(dentry->d_inode, name, buffer, size); + return reiserfs_xattr_get(d_inode(dentry), name, buffer, size); } static int @@ -27,10 +27,10 @@ trusted_set(struct dentry *dentry, const char *name, const void *buffer, if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX)) return -EINVAL; - if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(dentry->d_inode)) + if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(d_inode(dentry))) return -EPERM; - return reiserfs_xattr_set(dentry->d_inode, name, buffer, size, flags); + return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags); } static size_t trusted_list(struct dentry *dentry, char *list, size_t list_size, @@ -38,7 +38,7 @@ static size_t trusted_list(struct dentry *dentry, char *list, size_t list_size, { const size_t len = name_len + 1; - if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(dentry->d_inode)) + if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(d_inode(dentry))) return 0; if (list && len <= list_size) { diff --git a/fs/reiserfs/xattr_user.c b/fs/reiserfs/xattr_user.c index e50eab046471..d0b08d3e5689 100644 --- a/fs/reiserfs/xattr_user.c +++ b/fs/reiserfs/xattr_user.c @@ -15,7 +15,7 @@ user_get(struct dentry *dentry, const char *name, void *buffer, size_t size, return -EINVAL; if (!reiserfs_xattrs_user(dentry->d_sb)) return -EOPNOTSUPP; - return reiserfs_xattr_get(dentry->d_inode, name, buffer, size); + return reiserfs_xattr_get(d_inode(dentry), name, buffer, size); } static int @@ -27,7 +27,7 @@ user_set(struct dentry *dentry, const char *name, const void *buffer, if (!reiserfs_xattrs_user(dentry->d_sb)) return -EOPNOTSUPP; - return reiserfs_xattr_set(dentry->d_inode, name, buffer, size, flags); + return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags); } static size_t user_list(struct dentry *dentry, char *list, size_t list_size, diff --git a/fs/squashfs/export.c b/fs/squashfs/export.c index 5e1101ff276f..8073b6532cf0 100644 --- a/fs/squashfs/export.c +++ b/fs/squashfs/export.c @@ -110,7 +110,7 @@ static struct dentry *squashfs_fh_to_parent(struct super_block *sb, static struct dentry *squashfs_get_parent(struct dentry *child) { - struct inode *inode = child->d_inode; + struct inode *inode = d_inode(child); unsigned int parent_ino = squashfs_i(inode)->parent; return squashfs_export_iget(inode->i_sb, parent_ino); diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c index 92fcde7b4d61..e5e0ddf5b143 100644 --- a/fs/squashfs/xattr.c +++ b/fs/squashfs/xattr.c @@ -39,7 +39,7 @@ static const struct xattr_handler *squashfs_xattr_handler(int); ssize_t squashfs_listxattr(struct dentry *d, char *buffer, size_t buffer_size) { - struct inode *inode = d->d_inode; + struct inode *inode = d_inode(d); struct super_block *sb = inode->i_sb; struct squashfs_sb_info *msblk = sb->s_fs_info; u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr) @@ -229,7 +229,7 @@ static int squashfs_user_get(struct dentry *d, const char *name, void *buffer, if (name[0] == '\0') return -EINVAL; - return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_USER, name, + return squashfs_xattr_get(d_inode(d), SQUASHFS_XATTR_USER, name, buffer, size); } @@ -259,7 +259,7 @@ static int squashfs_trusted_get(struct dentry *d, const char *name, if (name[0] == '\0') return -EINVAL; - return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_TRUSTED, name, + return squashfs_xattr_get(d_inode(d), SQUASHFS_XATTR_TRUSTED, name, buffer, size); } @@ -286,7 +286,7 @@ static int squashfs_security_get(struct dentry *d, const char *name, if (name[0] == '\0') return -EINVAL; - return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_SECURITY, name, + return squashfs_xattr_get(d_inode(d), SQUASHFS_XATTR_SECURITY, name, buffer, size); } diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index d42291d08215..8f3555f00c54 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c @@ -132,7 +132,7 @@ struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_ { const char * name = dentry->d_name.name; int namelen = dentry->d_name.len; - struct inode * dir = dentry->d_parent->d_inode; + struct inode * dir = d_inode(dentry->d_parent); unsigned long start, n; unsigned long npages = dir_pages(dir); struct page *page = NULL; @@ -176,7 +176,7 @@ found: int sysv_add_link(struct dentry *dentry, struct inode *inode) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); const char * name = dentry->d_name.name; int namelen = dentry->d_name.len; struct page *page = NULL; diff --git a/fs/sysv/file.c b/fs/sysv/file.c index a48e30410ad1..82ddc09061e2 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c @@ -30,7 +30,7 @@ const struct file_operations sysv_file_operations = { static int sysv_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error; error = inode_change_ok(inode, attr); diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c index 66bc316927e8..2fde40acf024 100644 --- a/fs/sysv/itree.c +++ b/fs/sysv/itree.c @@ -443,7 +443,7 @@ static unsigned sysv_nblocks(struct super_block *s, loff_t size) int sysv_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct super_block *s = dentry->d_sb; - generic_fillattr(dentry->d_inode, stat); + generic_fillattr(d_inode(dentry), stat); stat->blocks = (s->s_blocksize / 512) * sysv_nblocks(s, stat->size); stat->blksize = s->s_blocksize; return 0; diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index 731b2bbcaab3..11e83ed0b4bf 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -118,7 +118,7 @@ out_fail: static int sysv_link(struct dentry * old_dentry, struct inode * dir, struct dentry * dentry) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); inode->i_ctime = CURRENT_TIME_SEC; inode_inc_link_count(inode); @@ -166,7 +166,7 @@ out_dir: static int sysv_unlink(struct inode * dir, struct dentry * dentry) { - struct inode * inode = dentry->d_inode; + struct inode * inode = d_inode(dentry); struct page * page; struct sysv_dir_entry * de; int err = -ENOENT; @@ -187,7 +187,7 @@ out: static int sysv_rmdir(struct inode * dir, struct dentry * dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int err = -ENOTEMPTY; if (sysv_empty_dir(inode)) { @@ -208,8 +208,8 @@ static int sysv_rmdir(struct inode * dir, struct dentry * dentry) static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry, struct inode * new_dir, struct dentry * new_dentry) { - struct inode * old_inode = old_dentry->d_inode; - struct inode * new_inode = new_dentry->d_inode; + struct inode * old_inode = d_inode(old_dentry); + struct inode * new_inode = d_inode(new_dentry); struct page * dir_page = NULL; struct sysv_dir_entry * dir_de = NULL; struct page * old_page; diff --git a/fs/sysv/symlink.c b/fs/sysv/symlink.c index 00d2f8a43e4e..d3fa0d703314 100644 --- a/fs/sysv/symlink.c +++ b/fs/sysv/symlink.c @@ -10,7 +10,7 @@ static void *sysv_follow_link(struct dentry *dentry, struct nameidata *nd) { - nd_set_link(nd, (char *)SYSV_I(dentry->d_inode)->i_data); + nd_set_link(nd, (char *)SYSV_I(d_inode(dentry))->i_data); return NULL; } diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 0fa6c803992e..20ae94d37acd 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -498,7 +498,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *dir_ui = ubifs_inode(dir); int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); @@ -553,7 +553,7 @@ out_cancel: static int ubifs_unlink(struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ubifs_inode *dir_ui = ubifs_inode(dir); int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, budgeted = 1; @@ -645,7 +645,7 @@ static int check_dir_empty(struct ubifs_info *c, struct inode *dir) static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, budgeted = 1; struct ubifs_inode *dir_ui = ubifs_inode(dir); @@ -661,7 +661,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) inode->i_ino, dir->i_ino); ubifs_assert(mutex_is_locked(&dir->i_mutex)); ubifs_assert(mutex_is_locked(&inode->i_mutex)); - err = check_dir_empty(c, dentry->d_inode); + err = check_dir_empty(c, d_inode(dentry)); if (err) return err; @@ -967,8 +967,8 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct ubifs_info *c = old_dir->i_sb->s_fs_info; - struct inode *old_inode = old_dentry->d_inode; - struct inode *new_inode = new_dentry->d_inode; + struct inode *old_inode = d_inode(old_dentry); + struct inode *new_inode = d_inode(new_dentry); struct ubifs_inode *old_inode_ui = ubifs_inode(old_inode); int err, release, sync = 0, move = (new_dir != old_dir); int is_dir = S_ISDIR(old_inode->i_mode); @@ -1133,7 +1133,7 @@ int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { loff_t size; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ubifs_inode *ui = ubifs_inode(inode); mutex_lock(&ui->ui_mutex); diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 475b15635f11..b5c69414e694 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1256,7 +1256,7 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode, int ubifs_setattr(struct dentry *dentry, struct iattr *attr) { int err; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct ubifs_info *c = inode->i_sb->s_fs_info; dbg_gen("ino %lu, mode %#x, ia_valid %#x", @@ -1301,7 +1301,7 @@ static void ubifs_invalidatepage(struct page *page, unsigned int offset, static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct ubifs_inode *ui = ubifs_inode(dentry->d_inode); + struct ubifs_inode *ui = ubifs_inode(d_inode(dentry)); nd_set_link(nd, ui->data); return NULL; diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index f6ac3f29323c..4f657e15c46e 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -930,8 +930,8 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, union ubifs_key key; struct ubifs_dent_node *dent, *dent2; int err, dlen1, dlen2, ilen, lnum, offs, len; - const struct inode *old_inode = old_dentry->d_inode; - const struct inode *new_inode = new_dentry->d_inode; + const struct inode *old_inode = d_inode(old_dentry); + const struct inode *new_inode = d_inode(new_dentry); int aligned_dlen1, aligned_dlen2, plen = UBIFS_INO_NODE_SZ; int last_reference = !!(new_inode && new_inode->i_nlink == 0); int move = (old_dir != new_dir); diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c index a92be244a6fb..dd2d872189da 100644 --- a/fs/ubifs/xattr.c +++ b/fs/ubifs/xattr.c @@ -364,15 +364,15 @@ int ubifs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { dbg_gen("xattr '%s', host ino %lu ('%pd'), size %zd", - name, dentry->d_inode->i_ino, dentry, size); + name, d_inode(dentry)->i_ino, dentry, size); - return setxattr(dentry->d_inode, name, value, size, flags); + return setxattr(d_inode(dentry), name, value, size, flags); } ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, size_t size) { - struct inode *inode, *host = dentry->d_inode; + struct inode *inode, *host = d_inode(dentry); struct ubifs_info *c = host->i_sb->s_fs_info; struct qstr nm = QSTR_INIT(name, strlen(name)); struct ubifs_inode *ui; @@ -432,7 +432,7 @@ out_unlock: ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) { union ubifs_key key; - struct inode *host = dentry->d_inode; + struct inode *host = d_inode(dentry); struct ubifs_info *c = host->i_sb->s_fs_info; struct ubifs_inode *host_ui = ubifs_inode(host); struct ubifs_dent_node *xent, *pxent = NULL; @@ -535,7 +535,7 @@ out_cancel: int ubifs_removexattr(struct dentry *dentry, const char *name) { - struct inode *inode, *host = dentry->d_inode; + struct inode *inode, *host = d_inode(dentry); struct ubifs_info *c = host->i_sb->s_fs_info; struct qstr nm = QSTR_INIT(name, strlen(name)); struct ubifs_dent_node *xent; diff --git a/fs/udf/file.c b/fs/udf/file.c index 3de2edafff73..a84cdd2ef618 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -250,7 +250,7 @@ const struct file_operations udf_file_operations = { static int udf_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error; error = inode_change_ok(inode, attr); diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 33b246b82c98..b159b769bf51 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -552,7 +552,7 @@ static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi, static int udf_add_nondir(struct dentry *dentry, struct inode *inode) { struct udf_inode_info *iinfo = UDF_I(inode); - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); struct udf_fileident_bh fibh; struct fileIdentDesc cfi, *fi; int err; @@ -767,7 +767,7 @@ static int empty_dir(struct inode *dir) static int udf_rmdir(struct inode *dir, struct dentry *dentry) { int retval; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct udf_fileident_bh fibh; struct fileIdentDesc *fi, cfi; struct kernel_lb_addr tloc; @@ -809,7 +809,7 @@ out: static int udf_unlink(struct inode *dir, struct dentry *dentry) { int retval; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct udf_fileident_bh fibh; struct fileIdentDesc *fi; struct fileIdentDesc cfi; @@ -999,7 +999,7 @@ out_no_entry: static int udf_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); struct udf_fileident_bh fibh; struct fileIdentDesc cfi, *fi; int err; @@ -1036,8 +1036,8 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir, static int udf_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { - struct inode *old_inode = old_dentry->d_inode; - struct inode *new_inode = new_dentry->d_inode; + struct inode *old_inode = d_inode(old_dentry); + struct inode *new_inode = d_inode(new_dentry); struct udf_fileident_bh ofibh, nfibh; struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL; struct fileIdentDesc ocfi, ncfi; @@ -1175,7 +1175,7 @@ static struct dentry *udf_get_parent(struct dentry *child) struct fileIdentDesc cfi; struct udf_fileident_bh fibh; - if (!udf_find_entry(child->d_inode, &dotdot, &fibh, &cfi)) + if (!udf_find_entry(d_inode(child), &dotdot, &fibh, &cfi)) return ERR_PTR(-EACCES); if (fibh.sbh != fibh.ebh) @@ -1183,7 +1183,7 @@ static struct dentry *udf_get_parent(struct dentry *child) brelse(fibh.sbh); tloc = lelb_to_cpu(cfi.icb.extLocation); - inode = udf_iget(child->d_inode->i_sb, &tloc); + inode = udf_iget(d_inode(child)->i_sb, &tloc); if (IS_ERR(inode)) return ERR_CAST(inode); diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index 0ecc2cebed8f..1bfe8cabff0f 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c @@ -311,7 +311,7 @@ found: */ int ufs_add_link(struct dentry *dentry, struct inode *inode) { - struct inode *dir = dentry->d_parent->d_inode; + struct inode *dir = d_inode(dentry->d_parent); const unsigned char *name = dentry->d_name.name; int namelen = dentry->d_name.len; struct super_block *sb = dir->i_sb; diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index fd65deb4b5f0..e491a93a7e9a 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -165,7 +165,7 @@ out_fail: static int ufs_link (struct dentry * old_dentry, struct inode * dir, struct dentry *dentry) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); int error; lock_ufs(dir->i_sb); @@ -222,7 +222,7 @@ out_fail: static int ufs_unlink(struct inode *dir, struct dentry *dentry) { - struct inode * inode = dentry->d_inode; + struct inode * inode = d_inode(dentry); struct ufs_dir_entry *de; struct page *page; int err = -ENOENT; @@ -244,7 +244,7 @@ out: static int ufs_rmdir (struct inode * dir, struct dentry *dentry) { - struct inode * inode = dentry->d_inode; + struct inode * inode = d_inode(dentry); int err= -ENOTEMPTY; lock_ufs(dir->i_sb); @@ -263,8 +263,8 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry) static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { - struct inode *old_inode = old_dentry->d_inode; - struct inode *new_inode = new_dentry->d_inode; + struct inode *old_inode = d_inode(old_dentry); + struct inode *new_inode = d_inode(new_dentry); struct page *dir_page = NULL; struct ufs_dir_entry * dir_de = NULL; struct page *old_page; diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 8092d3759a5e..b3bc3e7ae79d 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -144,10 +144,10 @@ static struct dentry *ufs_get_parent(struct dentry *child) struct qstr dot_dot = QSTR_INIT("..", 2); ino_t ino; - ino = ufs_inode_by_name(child->d_inode, &dot_dot); + ino = ufs_inode_by_name(d_inode(child), &dot_dot); if (!ino) return ERR_PTR(-ENOENT); - return d_obtain_alias(ufs_iget(child->d_inode->i_sb, ino)); + return d_obtain_alias(ufs_iget(d_inode(child)->i_sb, ino)); } static const struct export_operations ufs_export_ops = { diff --git a/fs/ufs/symlink.c b/fs/ufs/symlink.c index d283628b4778..5b537e2fdda3 100644 --- a/fs/ufs/symlink.c +++ b/fs/ufs/symlink.c @@ -34,7 +34,7 @@ static void *ufs_follow_link(struct dentry *dentry, struct nameidata *nd) { - struct ufs_inode_info *p = UFS_I(dentry->d_inode); + struct ufs_inode_info *p = UFS_I(d_inode(dentry)); nd_set_link(nd, (char*)p->i_u1.i_symlink); return NULL; } diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index f04f89fbd4d9..21154704c168 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -492,7 +492,7 @@ out: int ufs_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); unsigned int ia_valid = attr->ia_valid; int error; diff --git a/fs/xfs/xfs_export.c b/fs/xfs/xfs_export.c index b97359ba2648..652cd3c5b58c 100644 --- a/fs/xfs/xfs_export.c +++ b/fs/xfs/xfs_export.c @@ -215,7 +215,7 @@ xfs_fs_get_parent( int error; struct xfs_inode *cip; - error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip, NULL); + error = xfs_lookup(XFS_I(d_inode(child)), &xfs_name_dotdot, &cip, NULL); if (unlikely(error)) return ERR_PTR(error); diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c index a2e86e8a0fea..22807e1e9cca 100644 --- a/fs/xfs/xfs_filestream.c +++ b/fs/xfs/xfs_filestream.c @@ -294,7 +294,7 @@ xfs_filestream_get_parent( if (!parent) goto out_dput; - dir = igrab(parent->d_inode); + dir = igrab(d_inode(parent)); dput(parent); out_dput: diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index ac4feae45eb3..ed97bd48cf32 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -82,7 +82,7 @@ xfs_find_handle( error = user_lpath((const char __user *)hreq->path, &path); if (error) return error; - inode = path.dentry->d_inode; + inode = d_inode(path.dentry); } ip = XFS_I(inode); @@ -210,7 +210,7 @@ xfs_open_by_handle( dentry = xfs_handlereq_to_dentry(parfilp, hreq); if (IS_ERR(dentry)) return PTR_ERR(dentry); - inode = dentry->d_inode; + inode = d_inode(dentry); /* Restrict xfs_open_by_handle to directories & regular files. */ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { @@ -303,7 +303,7 @@ xfs_readlink_by_handle( goto out_dput; } - error = xfs_readlink(XFS_I(dentry->d_inode), link); + error = xfs_readlink(XFS_I(d_inode(dentry)), link); if (error) goto out_kfree; error = readlink_copy(hreq->ohandle, olen, link); @@ -376,7 +376,7 @@ xfs_fssetdm_by_handle( return PTR_ERR(dentry); } - if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode)) { + if (IS_IMMUTABLE(d_inode(dentry)) || IS_APPEND(d_inode(dentry))) { error = -EPERM; goto out; } @@ -386,7 +386,7 @@ xfs_fssetdm_by_handle( goto out; } - error = xfs_set_dmattrs(XFS_I(dentry->d_inode), fsd.fsd_dmevmask, + error = xfs_set_dmattrs(XFS_I(d_inode(dentry)), fsd.fsd_dmevmask, fsd.fsd_dmstate); out: @@ -429,7 +429,7 @@ xfs_attrlist_by_handle( goto out_dput; cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; - error = xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen, + error = xfs_attr_list(XFS_I(d_inode(dentry)), kbuf, al_hreq.buflen, al_hreq.flags, cursor); if (error) goto out_kfree; @@ -559,7 +559,7 @@ xfs_attrmulti_by_handle( switch (ops[i].am_opcode) { case ATTR_OP_GET: ops[i].am_error = xfs_attrmulti_attr_get( - dentry->d_inode, attr_name, + d_inode(dentry), attr_name, ops[i].am_attrvalue, &ops[i].am_length, ops[i].am_flags); break; @@ -568,7 +568,7 @@ xfs_attrmulti_by_handle( if (ops[i].am_error) break; ops[i].am_error = xfs_attrmulti_attr_set( - dentry->d_inode, attr_name, + d_inode(dentry), attr_name, ops[i].am_attrvalue, ops[i].am_length, ops[i].am_flags); mnt_drop_write_file(parfilp); @@ -578,7 +578,7 @@ xfs_attrmulti_by_handle( if (ops[i].am_error) break; ops[i].am_error = xfs_attrmulti_attr_remove( - dentry->d_inode, attr_name, + d_inode(dentry), attr_name, ops[i].am_flags); mnt_drop_write_file(parfilp); break; diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c index bfc7c7c8a0c8..b88bdc85dd3d 100644 --- a/fs/xfs/xfs_ioctl32.c +++ b/fs/xfs/xfs_ioctl32.c @@ -375,7 +375,7 @@ xfs_compat_attrlist_by_handle( goto out_dput; cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; - error = xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen, + error = xfs_attr_list(XFS_I(d_inode(dentry)), kbuf, al_hreq.buflen, al_hreq.flags, cursor); if (error) goto out_kfree; @@ -445,7 +445,7 @@ xfs_compat_attrmulti_by_handle( switch (ops[i].am_opcode) { case ATTR_OP_GET: ops[i].am_error = xfs_attrmulti_attr_get( - dentry->d_inode, attr_name, + d_inode(dentry), attr_name, compat_ptr(ops[i].am_attrvalue), &ops[i].am_length, ops[i].am_flags); break; @@ -454,7 +454,7 @@ xfs_compat_attrmulti_by_handle( if (ops[i].am_error) break; ops[i].am_error = xfs_attrmulti_attr_set( - dentry->d_inode, attr_name, + d_inode(dentry), attr_name, compat_ptr(ops[i].am_attrvalue), ops[i].am_length, ops[i].am_flags); mnt_drop_write_file(parfilp); @@ -464,7 +464,7 @@ xfs_compat_attrmulti_by_handle( if (ops[i].am_error) break; ops[i].am_error = xfs_attrmulti_attr_remove( - dentry->d_inode, attr_name, + d_inode(dentry), attr_name, ops[i].am_flags); mnt_drop_write_file(parfilp); break; @@ -504,7 +504,7 @@ xfs_compat_fssetdm_by_handle( if (IS_ERR(dentry)) return PTR_ERR(dentry); - if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode)) { + if (IS_IMMUTABLE(d_inode(dentry)) || IS_APPEND(d_inode(dentry))) { error = -EPERM; goto out; } @@ -514,7 +514,7 @@ xfs_compat_fssetdm_by_handle( goto out; } - error = xfs_set_dmattrs(XFS_I(dentry->d_inode), fsd.fsd_dmevmask, + error = xfs_set_dmattrs(XFS_I(d_inode(dentry)), fsd.fsd_dmevmask, fsd.fsd_dmstate); out: diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index e53a90331422..54b95232d946 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -301,7 +301,7 @@ xfs_vn_link( struct inode *dir, struct dentry *dentry) { - struct inode *inode = old_dentry->d_inode; + struct inode *inode = d_inode(old_dentry); struct xfs_name name; int error; @@ -326,7 +326,7 @@ xfs_vn_unlink( xfs_dentry_to_name(&name, dentry, 0); - error = xfs_remove(XFS_I(dir), &name, XFS_I(dentry->d_inode)); + error = xfs_remove(XFS_I(dir), &name, XFS_I(d_inode(dentry))); if (error) return error; @@ -384,7 +384,7 @@ xfs_vn_rename( struct dentry *ndentry, unsigned int flags) { - struct inode *new_inode = ndentry->d_inode; + struct inode *new_inode = d_inode(ndentry); int omode = 0; struct xfs_name oname; struct xfs_name nname; @@ -394,12 +394,12 @@ xfs_vn_rename( /* if we are exchanging files, we need to set i_mode of both files */ if (flags & RENAME_EXCHANGE) - omode = ndentry->d_inode->i_mode; + omode = d_inode(ndentry)->i_mode; xfs_dentry_to_name(&oname, odentry, omode); - xfs_dentry_to_name(&nname, ndentry, odentry->d_inode->i_mode); + xfs_dentry_to_name(&nname, ndentry, d_inode(odentry)->i_mode); - return xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode), + return xfs_rename(XFS_I(odir), &oname, XFS_I(d_inode(odentry)), XFS_I(ndir), &nname, new_inode ? XFS_I(new_inode) : NULL, flags); } @@ -421,7 +421,7 @@ xfs_vn_follow_link( if (!link) goto out_err; - error = xfs_readlink(XFS_I(dentry->d_inode), link); + error = xfs_readlink(XFS_I(d_inode(dentry)), link); if (unlikely(error)) goto out_kfree; @@ -441,7 +441,7 @@ xfs_vn_getattr( struct dentry *dentry, struct kstat *stat) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; @@ -968,14 +968,14 @@ xfs_vn_setattr( struct dentry *dentry, struct iattr *iattr) { - struct xfs_inode *ip = XFS_I(dentry->d_inode); + struct xfs_inode *ip = XFS_I(d_inode(dentry)); int error; if (iattr->ia_valid & ATTR_SIZE) { uint iolock = XFS_IOLOCK_EXCL; xfs_ilock(ip, iolock); - error = xfs_break_layouts(dentry->d_inode, &iolock); + error = xfs_break_layouts(d_inode(dentry), &iolock); if (!error) error = xfs_setattr_size(ip, iattr); xfs_iunlock(ip, iolock); diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 8fcc4ccc5c79..72e97e31d3b1 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1083,7 +1083,7 @@ xfs_fs_statfs( { struct xfs_mount *mp = XFS_M(dentry->d_sb); xfs_sb_t *sbp = &mp->m_sb; - struct xfs_inode *ip = XFS_I(dentry->d_inode); + struct xfs_inode *ip = XFS_I(d_inode(dentry)); __uint64_t fakeinos, id; xfs_extlen_t lsize; __int64_t ffree; diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index 69f6e475de97..c036815183cb 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -35,7 +35,7 @@ static int xfs_xattr_get(struct dentry *dentry, const char *name, void *value, size_t size, int xflags) { - struct xfs_inode *ip = XFS_I(dentry->d_inode); + struct xfs_inode *ip = XFS_I(d_inode(dentry)); int error, asize = size; if (strcmp(name, "") == 0) @@ -57,7 +57,7 @@ static int xfs_xattr_set(struct dentry *dentry, const char *name, const void *value, size_t size, int flags, int xflags) { - struct xfs_inode *ip = XFS_I(dentry->d_inode); + struct xfs_inode *ip = XFS_I(d_inode(dentry)); if (strcmp(name, "") == 0) return -EINVAL; @@ -197,7 +197,7 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size) { struct xfs_attr_list_context context; struct attrlist_cursor_kern cursor = { 0 }; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); int error; /* diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index 1faecea101f3..9134bba9f218 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h @@ -407,10 +407,10 @@ TRACE_EVENT(btrfs_sync_file, TP_fast_assign( struct dentry *dentry = file->f_path.dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); __entry->ino = inode->i_ino; - __entry->parent = dentry->d_parent->d_inode->i_ino; + __entry->parent = d_inode(dentry->d_parent)->i_ino; __entry->datasync = datasync; __entry->root_objectid = BTRFS_I(inode)->root->root_key.objectid; diff --git a/include/trace/events/ext3.h b/include/trace/events/ext3.h index 6797b9de90ed..4a633258cab6 100644 --- a/include/trace/events/ext3.h +++ b/include/trace/events/ext3.h @@ -439,10 +439,10 @@ TRACE_EVENT(ext3_sync_file_enter, TP_fast_assign( struct dentry *dentry = file->f_path.dentry; - __entry->dev = dentry->d_inode->i_sb->s_dev; - __entry->ino = dentry->d_inode->i_ino; + __entry->dev = d_inode(dentry)->i_sb->s_dev; + __entry->ino = d_inode(dentry)->i_ino; __entry->datasync = datasync; - __entry->parent = dentry->d_parent->d_inode->i_ino; + __entry->parent = d_inode(dentry->d_parent)->i_ino; ), TP_printk("dev %d,%d ino %lu parent %ld datasync %d ", @@ -710,9 +710,9 @@ TRACE_EVENT(ext3_unlink_enter, TP_fast_assign( __entry->parent = parent->i_ino; - __entry->ino = dentry->d_inode->i_ino; - __entry->size = dentry->d_inode->i_size; - __entry->dev = dentry->d_inode->i_sb->s_dev; + __entry->ino = d_inode(dentry)->i_ino; + __entry->size = d_inode(dentry)->i_size; + __entry->dev = d_inode(dentry)->i_sb->s_dev; ), TP_printk("dev %d,%d ino %lu size %lld parent %ld", @@ -734,8 +734,8 @@ TRACE_EVENT(ext3_unlink_exit, ), TP_fast_assign( - __entry->ino = dentry->d_inode->i_ino; - __entry->dev = dentry->d_inode->i_sb->s_dev; + __entry->ino = d_inode(dentry)->i_ino; + __entry->dev = d_inode(dentry)->i_sb->s_dev; __entry->ret = ret; ), diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index 6e5abd6d38a2..68d2a677c04c 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -872,10 +872,10 @@ TRACE_EVENT(ext4_sync_file_enter, TP_fast_assign( struct dentry *dentry = file->f_path.dentry; - __entry->dev = dentry->d_inode->i_sb->s_dev; - __entry->ino = dentry->d_inode->i_ino; + __entry->dev = d_inode(dentry)->i_sb->s_dev; + __entry->ino = d_inode(dentry)->i_ino; __entry->datasync = datasync; - __entry->parent = dentry->d_parent->d_inode->i_ino; + __entry->parent = d_inode(dentry->d_parent)->i_ino; ), TP_printk("dev %d,%d ino %lu parent %lu datasync %d ", @@ -1453,10 +1453,10 @@ TRACE_EVENT(ext4_unlink_enter, ), TP_fast_assign( - __entry->dev = dentry->d_inode->i_sb->s_dev; - __entry->ino = dentry->d_inode->i_ino; + __entry->dev = d_inode(dentry)->i_sb->s_dev; + __entry->ino = d_inode(dentry)->i_ino; __entry->parent = parent->i_ino; - __entry->size = dentry->d_inode->i_size; + __entry->size = d_inode(dentry)->i_size; ), TP_printk("dev %d,%d ino %lu size %lld parent %lu", @@ -1477,8 +1477,8 @@ TRACE_EVENT(ext4_unlink_exit, ), TP_fast_assign( - __entry->dev = dentry->d_inode->i_sb->s_dev; - __entry->ino = dentry->d_inode->i_ino; + __entry->dev = d_inode(dentry)->i_sb->s_dev; + __entry->ino = d_inode(dentry)->i_ino; __entry->ret = ret; ), -- cgit v1.2.3 From 773af94e4e3984d4055c332602de5d0d2ee3d840 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Tue, 3 Mar 2015 10:54:48 +0200 Subject: net/mlx4_core: Manage alias GUID per VF Manages alias GUIDs per VF per port in the core layer. This is a pre-step for managing alias GUIDs in a mode that the admin GUID is returned via ib_query_gid() regardless of whether the SM has approved it or not. Signed-off-by: Yishai Hadas Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: Doug Ledford --- drivers/net/ethernet/mellanox/mlx4/main.c | 16 ++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/mlx4.h | 1 + include/linux/mlx4/device.h | 3 +++ 3 files changed, 20 insertions(+) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index acceb75e8c44..9162a6dd7823 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2260,6 +2260,22 @@ void mlx4_counter_free(struct mlx4_dev *dev, u32 idx) } EXPORT_SYMBOL_GPL(mlx4_counter_free); +void mlx4_set_admin_guid(struct mlx4_dev *dev, __be64 guid, int entry, int port) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + priv->mfunc.master.vf_admin[entry].vport[port].guid = guid; +} +EXPORT_SYMBOL_GPL(mlx4_set_admin_guid); + +__be64 mlx4_get_admin_guid(struct mlx4_dev *dev, int entry, int port) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + return priv->mfunc.master.vf_admin[entry].vport[port].guid; +} +EXPORT_SYMBOL_GPL(mlx4_get_admin_guid); + static int mlx4_setup_hca(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index f30eeb730a86..502d3dd2c888 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -499,6 +499,7 @@ struct mlx4_vport_state { bool spoofchk; u32 link_state; u8 qos_vport; + __be64 guid; }; struct mlx4_vf_admin_state { diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index f9ce34bec45b..39a91b0c5d5c 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -1345,6 +1345,9 @@ int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port); int mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx); void mlx4_counter_free(struct mlx4_dev *dev, u32 idx); +void mlx4_set_admin_guid(struct mlx4_dev *dev, __be64 guid, int entry, + int port); +__be64 mlx4_get_admin_guid(struct mlx4_dev *dev, int entry, int port); int mlx4_flow_attach(struct mlx4_dev *dev, struct mlx4_net_trans_rule *rule, u64 *reg_id); int mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id); -- cgit v1.2.3 From fb517a4f03041c5eaed394bd57ee518b44301f1a Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Tue, 3 Mar 2015 11:23:32 +0200 Subject: net/mlx4_core: Set initial admin GUIDs for VFs To have out of the box experience, the PF generates random GUIDs who serve as the initial admin values. Signed-off-by: Yishai Hadas Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: Doug Ledford --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 1 + drivers/net/ethernet/mellanox/mlx4/main.c | 15 +++++++++++++++ include/linux/mlx4/device.h | 1 + 3 files changed, 17 insertions(+) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index f0fbb4ade85d..50ce67d4abfc 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -2350,6 +2350,7 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) oper_vport->qos_vport = MLX4_VPP_DEFAULT_VPORT; vf_oper->vport[port].vlan_idx = NO_INDX; vf_oper->vport[port].mac_idx = NO_INDX; + mlx4_set_random_admin_guid(dev, i, port); } spin_lock_init(&s_state->lock); } diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 9162a6dd7823..ced5ecab5aa7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2276,6 +2276,21 @@ __be64 mlx4_get_admin_guid(struct mlx4_dev *dev, int entry, int port) } EXPORT_SYMBOL_GPL(mlx4_get_admin_guid); +void mlx4_set_random_admin_guid(struct mlx4_dev *dev, int entry, int port) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + __be64 guid; + + /* hw GUID */ + if (entry == 0) + return; + + get_random_bytes((char *)&guid, sizeof(guid)); + guid &= ~(cpu_to_be64(1ULL << 56)); + guid |= cpu_to_be64(1ULL << 57); + priv->mfunc.master.vf_admin[entry].vport[port].guid = guid; +} + static int mlx4_setup_hca(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 39a91b0c5d5c..83e80ab94500 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -1348,6 +1348,7 @@ void mlx4_counter_free(struct mlx4_dev *dev, u32 idx); void mlx4_set_admin_guid(struct mlx4_dev *dev, __be64 guid, int entry, int port); __be64 mlx4_get_admin_guid(struct mlx4_dev *dev, int entry, int port); +void mlx4_set_random_admin_guid(struct mlx4_dev *dev, int entry, int port); int mlx4_flow_attach(struct mlx4_dev *dev, struct mlx4_net_trans_rule *rule, u64 *reg_id); int mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id); -- cgit v1.2.3 From 1527781d228cd88af6c2f78c13a9cb43b3f69f30 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 16 Apr 2015 12:33:51 +0930 Subject: cpumask: resurrect CPU_MASK_CPU0 We removed it in 2f0f267ea072 (cpumask: remove deprecated functions.), but grep shows it still used by MIPS, and not unreasonably. Signed-off-by: Rusty Russell --- include/linux/cpumask.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 89558d0b56ac..27e285b92b5f 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -814,4 +814,9 @@ cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask) [0 ... BITS_TO_LONGS(NR_CPUS)-1] = 0UL \ } } +#define CPU_MASK_CPU0 \ +(cpumask_t) { { \ + [0] = 1UL \ +} } + #endif /* __LINUX_CPUMASK_H */ -- cgit v1.2.3 From bffb5128f91e820fd8804307a6431607c2c840a4 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 14 Apr 2015 11:52:22 -0700 Subject: target: Ensure sess_prot_type is saved across session restart The following incremental patch saves the current sess_prot_type into se_node_acl, and will always reset sess_prot_type if a previous saved value exists. So the PI setting for the fabric's session with backend devices not supporting PI is persistent across session restart. (Fix se_node_acl dereference for discovery sessions - DanCarpenter) Reviewed-by: Martin Petersen Reviewed-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 22 +++++++++++++++------- include/target/target_core_base.h | 1 + 2 files changed, 16 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 4edb183cf8df..14e324991c34 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -327,13 +327,6 @@ void __transport_register_session( se_sess->se_tpg = se_tpg; se_sess->fabric_sess_ptr = fabric_sess_ptr; - /* - * Determine if fabric allows for T10-PI feature bits to be exposed - * to initiators for device backends with !dev->dev_attrib.pi_prot_type - */ - if (tfo->tpg_check_prot_fabric_only) - se_sess->sess_prot_type = tfo->tpg_check_prot_fabric_only(se_tpg); - /* * Used by struct se_node_acl's under ConfigFS to locate active se_session-t * @@ -341,6 +334,21 @@ void __transport_register_session( * eg: *NOT* discovery sessions. */ if (se_nacl) { + /* + * + * Determine if fabric allows for T10-PI feature bits exposed to + * initiators for device backends with !dev->dev_attrib.pi_prot_type. + * + * If so, then always save prot_type on a per se_node_acl node + * basis and re-instate the previous sess_prot_type to avoid + * disabling PI from below any previously initiator side + * registered LUNs. + */ + if (se_nacl->saved_prot_type) + se_sess->sess_prot_type = se_nacl->saved_prot_type; + else if (tfo->tpg_check_prot_fabric_only) + se_sess->sess_prot_type = se_nacl->saved_prot_type = + tfo->tpg_check_prot_fabric_only(se_tpg); /* * If the fabric module supports an ISID based TransportID, * save this value in binary from the fabric I_T Nexus now. diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index e1de142b7b07..480e9f82dfea 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -589,6 +589,7 @@ struct se_node_acl { bool acl_stop:1; u32 queue_depth; u32 acl_index; + enum target_prot_type saved_prot_type; #define MAX_ACL_TAG_SIZE 64 char acl_tag[MAX_ACL_TAG_SIZE]; /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ -- cgit v1.2.3 From 10027551ccf5459cc771c31ac8bc8e5cc8db45f8 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 9 Apr 2015 17:03:53 -0700 Subject: f2fs: pass checkpoint reason on roll-forward recovery This patch adds CP_RECOVERY to remain recovery information for checkpoint. And, it makes sure writing checkpoint in this case. Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 6 +++++- fs/f2fs/f2fs.h | 1 + fs/f2fs/recovery.c | 2 +- include/trace/events/f2fs.h | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 384bfc4c36c3..a5e17a2a0781 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -1051,7 +1051,7 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) mutex_lock(&sbi->cp_mutex); if (!is_sbi_flag_set(sbi, SBI_IS_DIRTY) && - cpc->reason != CP_DISCARD && cpc->reason != CP_UMOUNT) + (cpc->reason == CP_FASTBOOT || cpc->reason == CP_SYNC)) goto out; if (unlikely(f2fs_cp_error(sbi))) goto out; @@ -1086,6 +1086,10 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) unblock_operations(sbi); stat_inc_cp_count(sbi->stat_info); + + if (cpc->reason == CP_RECOVERY) + f2fs_msg(sbi->sb, KERN_NOTICE, + "checkpoint: version = %llx", ckpt_ver); out: mutex_unlock(&sbi->cp_mutex); trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint"); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 053361ace0ec..c06a25e5cec3 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -103,6 +103,7 @@ enum { CP_UMOUNT, CP_FASTBOOT, CP_SYNC, + CP_RECOVERY, CP_DISCARD, }; diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 4b742c96c223..8d8ea99f2156 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -564,7 +564,7 @@ out: mutex_unlock(&sbi->cp_mutex); } else if (need_writecp) { struct cp_control cpc = { - .reason = CP_SYNC, + .reason = CP_RECOVERY, }; mutex_unlock(&sbi->cp_mutex); write_checkpoint(sbi, &cpc); diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 75724bd28356..8804f22a08d1 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -78,6 +78,7 @@ { CP_UMOUNT, "Umount" }, \ { CP_FASTBOOT, "Fastboot" }, \ { CP_SYNC, "Sync" }, \ + { CP_RECOVERY, "Recovery" }, \ { CP_DISCARD, "Discard" }) struct victim_sel_policy; -- cgit v1.2.3 From 96541bac0b4e62efa42e7900d9b32e6baa9a214c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2015 13:06:12 +0200 Subject: Revert "mmc: core: Convert mmc_driver to device_driver" This reverts commit 6685ac62b2f0 ("mmc: core: Convert mmc_driver to device_driver") The reverted commit went too far in simplifing the device driver parts for mmc. Let's restore the old mmc_driver to enable driver core to sooner or later to remove the ->probe(), ->remove() and ->shutdown() callbacks from the struct device_driver. Note that, the old ->suspend|resume() callbacks in the struct mmc_driver don't need to be restored, since the mmc block layer has converted to the modern system PM ops. Fixes: 6685ac62b2f0 ("mmc: core: Convert mmc_driver to device_driver") Signed-off-by: Ulf Hansson Acked-by: Jaehoon Chung --- drivers/mmc/card/block.c | 34 +++++++++++++++++----------------- drivers/mmc/card/mmc_test.c | 18 +++++++----------- drivers/mmc/core/bus.c | 41 +++++++++++++++++++++++++++++++++-------- include/linux/mmc/card.h | 14 ++++++++++++-- 4 files changed, 69 insertions(+), 38 deletions(-) (limited to 'include') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 2fc426926574..2c25271f8c41 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -2418,9 +2418,8 @@ static const struct mmc_fixup blk_fixups[] = END_FIXUP }; -static int mmc_blk_probe(struct device *dev) +static int mmc_blk_probe(struct mmc_card *card) { - struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_blk_data *md, *part_md; char cap_str[10]; @@ -2445,7 +2444,7 @@ static int mmc_blk_probe(struct device *dev) if (mmc_blk_alloc_parts(card, md)) goto out; - dev_set_drvdata(dev, md); + dev_set_drvdata(&card->dev, md); if (mmc_add_disk(md)) goto out; @@ -2475,10 +2474,9 @@ static int mmc_blk_probe(struct device *dev) return 0; } -static int mmc_blk_remove(struct device *dev) +static void mmc_blk_remove(struct mmc_card *card) { - struct mmc_card *card = mmc_dev_to_card(dev); - struct mmc_blk_data *md = dev_get_drvdata(dev); + struct mmc_blk_data *md = dev_get_drvdata(&card->dev); mmc_blk_remove_parts(card, md); pm_runtime_get_sync(&card->dev); @@ -2489,15 +2487,13 @@ static int mmc_blk_remove(struct device *dev) pm_runtime_disable(&card->dev); pm_runtime_put_noidle(&card->dev); mmc_blk_remove_req(md); - dev_set_drvdata(dev, NULL); - - return 0; + dev_set_drvdata(&card->dev, NULL); } -static int _mmc_blk_suspend(struct device *dev) +static int _mmc_blk_suspend(struct mmc_card *card) { struct mmc_blk_data *part_md; - struct mmc_blk_data *md = dev_get_drvdata(dev); + struct mmc_blk_data *md = dev_get_drvdata(&card->dev); if (md) { mmc_queue_suspend(&md->queue); @@ -2508,15 +2504,17 @@ static int _mmc_blk_suspend(struct device *dev) return 0; } -static void mmc_blk_shutdown(struct device *dev) +static void mmc_blk_shutdown(struct mmc_card *card) { - _mmc_blk_suspend(dev); + _mmc_blk_suspend(card); } #ifdef CONFIG_PM_SLEEP static int mmc_blk_suspend(struct device *dev) { - return _mmc_blk_suspend(dev); + struct mmc_card *card = mmc_dev_to_card(dev); + + return _mmc_blk_suspend(card); } static int mmc_blk_resume(struct device *dev) @@ -2541,9 +2539,11 @@ static int mmc_blk_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(mmc_blk_pm_ops, mmc_blk_suspend, mmc_blk_resume); -static struct device_driver mmc_driver = { - .name = "mmcblk", - .pm = &mmc_blk_pm_ops, +static struct mmc_driver mmc_driver = { + .drv = { + .name = "mmcblk", + .pm = &mmc_blk_pm_ops, + }, .probe = mmc_blk_probe, .remove = mmc_blk_remove, .shutdown = mmc_blk_shutdown, diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 7dac4695163b..53b741398b93 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include /* For nr_free_buffer_pages() */ @@ -2996,9 +2995,8 @@ err: return ret; } -static int mmc_test_probe(struct device *dev) +static int mmc_test_probe(struct mmc_card *card) { - struct mmc_card *card = mmc_dev_to_card(dev); int ret; if (!mmc_card_mmc(card) && !mmc_card_sd(card)) @@ -3013,22 +3011,20 @@ static int mmc_test_probe(struct device *dev) return 0; } -static int mmc_test_remove(struct device *dev) +static void mmc_test_remove(struct mmc_card *card) { - struct mmc_card *card = mmc_dev_to_card(dev); - mmc_test_free_result(card); mmc_test_free_dbgfs_file(card); - - return 0; } -static void mmc_test_shutdown(struct device *dev) +static void mmc_test_shutdown(struct mmc_card *card) { } -static struct device_driver mmc_driver = { - .name = "mmc_test", +static struct mmc_driver mmc_driver = { + .drv = { + .name = "mmc_test", + }, .probe = mmc_test_probe, .remove = mmc_test_remove, .shutdown = mmc_test_shutdown, diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index c5ef10065a4a..972ff844cf5a 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -26,6 +26,8 @@ #include "sdio_cis.h" #include "bus.h" +#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) + static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -105,14 +107,33 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) return retval; } +static int mmc_bus_probe(struct device *dev) +{ + struct mmc_driver *drv = to_mmc_driver(dev->driver); + struct mmc_card *card = mmc_dev_to_card(dev); + + return drv->probe(card); +} + +static int mmc_bus_remove(struct device *dev) +{ + struct mmc_driver *drv = to_mmc_driver(dev->driver); + struct mmc_card *card = mmc_dev_to_card(dev); + + drv->remove(card); + + return 0; +} + static void mmc_bus_shutdown(struct device *dev) { + struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; int ret; - if (dev->driver && dev->driver->shutdown) - dev->driver->shutdown(dev); + if (dev->driver && drv->shutdown) + drv->shutdown(card); if (host->bus_ops->shutdown) { ret = host->bus_ops->shutdown(host); @@ -181,6 +202,8 @@ static struct bus_type mmc_bus_type = { .dev_groups = mmc_dev_groups, .match = mmc_bus_match, .uevent = mmc_bus_uevent, + .probe = mmc_bus_probe, + .remove = mmc_bus_remove, .shutdown = mmc_bus_shutdown, .pm = &mmc_bus_pm_ops, }; @@ -199,22 +222,24 @@ void mmc_unregister_bus(void) * mmc_register_driver - register a media driver * @drv: MMC media driver */ -int mmc_register_driver(struct device_driver *drv) +int mmc_register_driver(struct mmc_driver *drv) { - drv->bus = &mmc_bus_type; - return driver_register(drv); + drv->drv.bus = &mmc_bus_type; + return driver_register(&drv->drv); } + EXPORT_SYMBOL(mmc_register_driver); /** * mmc_unregister_driver - unregister a media driver * @drv: MMC media driver */ -void mmc_unregister_driver(struct device_driver *drv) +void mmc_unregister_driver(struct mmc_driver *drv) { - drv->bus = &mmc_bus_type; - driver_unregister(drv); + drv->drv.bus = &mmc_bus_type; + driver_unregister(&drv->drv); } + EXPORT_SYMBOL(mmc_unregister_driver); static void mmc_release_card(struct device *dev) diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index a6cf4c063e4e..19f0175c0afa 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -512,8 +512,18 @@ static inline int mmc_card_broken_irq_polling(const struct mmc_card *c) #define mmc_dev_to_card(d) container_of(d, struct mmc_card, dev) -extern int mmc_register_driver(struct device_driver *); -extern void mmc_unregister_driver(struct device_driver *); +/* + * MMC device driver (e.g., Flash card, I/O card...) + */ +struct mmc_driver { + struct device_driver drv; + int (*probe)(struct mmc_card *); + void (*remove)(struct mmc_card *); + void (*shutdown)(struct mmc_card *); +}; + +extern int mmc_register_driver(struct mmc_driver *); +extern void mmc_unregister_driver(struct mmc_driver *); extern void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table); -- cgit v1.2.3 From e60841b441e1b3d176f235f36c79158dd2ed3ed8 Mon Sep 17 00:00:00 2001 From: Kedareswara rao Appana Date: Mon, 30 Mar 2015 18:48:29 +0530 Subject: dmaengine: vdma: Fix compilation warnings This patch fixes the following compilation warnings. In file included from drivers/dma/xilinx/xilinx_vdma.c:26:0: include/linux/dmapool.h:18:4: warning: 'struct device' declared inside parameter list size_t size, size_t align, size_t allocation); ^ include/linux/dmapool.h:18:4: warning: its scope is only this definition or declaration, which is probably not what you want include/linux/dmapool.h:31:7: warning: 'struct device' declared inside parameter list size_t size, size_t align, size_t allocation); ^ drivers/dma/xilinx/xilinx_vdma.c: In function 'xilinx_vdma_alloc_chan_resources': drivers/dma/xilinx/xilinx_vdma.c:501:20: warning: passing argument 2 of 'dma_pool_create' from incompatible pointer type chan->desc_pool = dma_pool_create("xilinx_vdma_desc_pool", ^ In file included from drivers/dma/xilinx/xilinx_vdma.c:26:0: include/linux/dmapool.h:17:18: note: expected 'struct device *' but argument is of type 'struct device *' struct dma_pool *dma_pool_create(const char *name, struct device *dev, . Signed-off-by: Kedareswara rao Appana Signed-off-by: Vinod Koul --- include/linux/dmapool.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/dmapool.h b/include/linux/dmapool.h index 022e34fcbd1b..52456aa566a0 100644 --- a/include/linux/dmapool.h +++ b/include/linux/dmapool.h @@ -14,6 +14,8 @@ #include #include +struct device; + struct dma_pool *dma_pool_create(const char *name, struct device *dev, size_t size, size_t align, size_t allocation); -- cgit v1.2.3 From 43c499dc2778b96e21ed14e1a71e7b117a0b406f Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 17 Apr 2015 22:53:32 +0530 Subject: ALSA: asound.h - use SNDRV_CTL_ELEM_ID_NAME_MAXLEN we have defined SNDRV_CTL_ELEM_ID_NAME_MAXLEN as size of name array so use this define instead of numeric value Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai --- include/uapi/sound/asound.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 46145a5277fe..a45be6bdcf5b 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -864,7 +864,7 @@ struct snd_ctl_elem_id { snd_ctl_elem_iface_t iface; /* interface identifier */ unsigned int device; /* device/client number */ unsigned int subdevice; /* subdevice (substream) number */ - unsigned char name[44]; /* ASCII name of item */ + unsigned char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* ASCII name of item */ unsigned int index; /* index of item */ }; -- cgit v1.2.3 From c12f048ffdf3a5802239426dc290290929268dc9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 18 Apr 2015 12:31:25 -0700 Subject: sparc: Revert generic IOMMU allocator. I applied the wrong version of this patch series, V4 instead of V10, due to a patchwork bundling snafu. Signed-off-by: David S. Miller --- arch/sparc/include/asm/iommu_64.h | 7 +- arch/sparc/kernel/iommu.c | 188 +++++++++++++++++++++----------- arch/sparc/kernel/iommu_common.h | 8 ++ arch/sparc/kernel/ldc.c | 185 +++++++++++++++---------------- arch/sparc/kernel/pci_sun4v.c | 193 ++++++++++++++++---------------- include/linux/iommu-common.h | 55 ---------- lib/Makefile | 2 +- lib/iommu-common.c | 224 -------------------------------------- 8 files changed, 325 insertions(+), 537 deletions(-) delete mode 100644 include/linux/iommu-common.h delete mode 100644 lib/iommu-common.c (limited to 'include') diff --git a/arch/sparc/include/asm/iommu_64.h b/arch/sparc/include/asm/iommu_64.h index e3cd4493d81d..2b9321ab064d 100644 --- a/arch/sparc/include/asm/iommu_64.h +++ b/arch/sparc/include/asm/iommu_64.h @@ -16,7 +16,6 @@ #define IOPTE_WRITE 0x0000000000000002UL #define IOMMU_NUM_CTXS 4096 -#include struct iommu_arena { unsigned long *map; @@ -25,10 +24,11 @@ struct iommu_arena { }; struct iommu { - struct iommu_table tbl; spinlock_t lock; - u32 dma_addr_mask; + struct iommu_arena arena; + void (*flush_all)(struct iommu *); iopte_t *page_table; + u32 page_table_map_base; unsigned long iommu_control; unsigned long iommu_tsbbase; unsigned long iommu_flush; @@ -40,6 +40,7 @@ struct iommu { unsigned long dummy_page_pa; unsigned long ctx_lowest_free; DECLARE_BITMAP(ctx_bitmap, IOMMU_NUM_CTXS); + u32 dma_addr_mask; }; struct strbuf { diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c index 9b16b341b6ae..bfa4d0c2df42 100644 --- a/arch/sparc/kernel/iommu.c +++ b/arch/sparc/kernel/iommu.c @@ -13,15 +13,11 @@ #include #include #include -#include -#include #ifdef CONFIG_PCI #include #endif -static DEFINE_PER_CPU(unsigned int, iommu_pool_hash); - #include #include "iommu_common.h" @@ -49,9 +45,8 @@ static DEFINE_PER_CPU(unsigned int, iommu_pool_hash); "i" (ASI_PHYS_BYPASS_EC_E)) /* Must be invoked under the IOMMU lock. */ -static void iommu_flushall(struct iommu_table *iommu_table) +static void iommu_flushall(struct iommu *iommu) { - struct iommu *iommu = container_of(iommu_table, struct iommu, tbl); if (iommu->iommu_flushinv) { iommu_write(iommu->iommu_flushinv, ~(u64)0); } else { @@ -92,22 +87,93 @@ static inline void iopte_make_dummy(struct iommu *iommu, iopte_t *iopte) iopte_val(*iopte) = val; } -static struct iommu_tbl_ops iommu_sparc_ops = { - .reset = iommu_flushall -}; - -static void setup_iommu_pool_hash(void) +/* Based almost entirely upon the ppc64 iommu allocator. If you use the 'handle' + * facility it must all be done in one pass while under the iommu lock. + * + * On sun4u platforms, we only flush the IOMMU once every time we've passed + * over the entire page table doing allocations. Therefore we only ever advance + * the hint and cannot backtrack it. + */ +unsigned long iommu_range_alloc(struct device *dev, + struct iommu *iommu, + unsigned long npages, + unsigned long *handle) { - unsigned int i; - static bool do_once; + unsigned long n, end, start, limit, boundary_size; + struct iommu_arena *arena = &iommu->arena; + int pass = 0; - if (do_once) - return; - do_once = true; - for_each_possible_cpu(i) - per_cpu(iommu_pool_hash, i) = hash_32(i, IOMMU_POOL_HASHBITS); + /* This allocator was derived from x86_64's bit string search */ + + /* Sanity check */ + if (unlikely(npages == 0)) { + if (printk_ratelimit()) + WARN_ON(1); + return DMA_ERROR_CODE; + } + + if (handle && *handle) + start = *handle; + else + start = arena->hint; + + limit = arena->limit; + + /* The case below can happen if we have a small segment appended + * to a large, or when the previous alloc was at the very end of + * the available space. If so, go back to the beginning and flush. + */ + if (start >= limit) { + start = 0; + if (iommu->flush_all) + iommu->flush_all(iommu); + } + + again: + + if (dev) + boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, + 1 << IO_PAGE_SHIFT); + else + boundary_size = ALIGN(1UL << 32, 1 << IO_PAGE_SHIFT); + + n = iommu_area_alloc(arena->map, limit, start, npages, + iommu->page_table_map_base >> IO_PAGE_SHIFT, + boundary_size >> IO_PAGE_SHIFT, 0); + if (n == -1) { + if (likely(pass < 1)) { + /* First failure, rescan from the beginning. */ + start = 0; + if (iommu->flush_all) + iommu->flush_all(iommu); + pass++; + goto again; + } else { + /* Second failure, give up */ + return DMA_ERROR_CODE; + } + } + + end = n + npages; + + arena->hint = end; + + /* Update handle for SG allocations */ + if (handle) + *handle = end; + + return n; } +void iommu_range_free(struct iommu *iommu, dma_addr_t dma_addr, unsigned long npages) +{ + struct iommu_arena *arena = &iommu->arena; + unsigned long entry; + + entry = (dma_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT; + + bitmap_clear(arena->map, entry, npages); +} int iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask, @@ -121,22 +187,22 @@ int iommu_table_init(struct iommu *iommu, int tsbsize, /* Setup initial software IOMMU state. */ spin_lock_init(&iommu->lock); iommu->ctx_lowest_free = 1; - iommu->tbl.page_table_map_base = dma_offset; + iommu->page_table_map_base = dma_offset; iommu->dma_addr_mask = dma_addr_mask; /* Allocate and initialize the free area map. */ sz = num_tsb_entries / 8; sz = (sz + 7UL) & ~7UL; - iommu->tbl.map = kmalloc_node(sz, GFP_KERNEL, numa_node); - if (!iommu->tbl.map) + iommu->arena.map = kmalloc_node(sz, GFP_KERNEL, numa_node); + if (!iommu->arena.map) { + printk(KERN_ERR "IOMMU: Error, kmalloc(arena.map) failed.\n"); return -ENOMEM; - memset(iommu->tbl.map, 0, sz); - if (tlb_type != hypervisor) - iommu_sparc_ops.reset = NULL; /* not needed on on sun4v */ + } + memset(iommu->arena.map, 0, sz); + iommu->arena.limit = num_tsb_entries; - setup_iommu_pool_hash(); - iommu_tbl_pool_init(&iommu->tbl, num_tsb_entries, IO_PAGE_SHIFT, - &iommu_sparc_ops, false, 1); + if (tlb_type != hypervisor) + iommu->flush_all = iommu_flushall; /* Allocate and initialize the dummy page which we * set inactive IO PTEs to point to. @@ -169,20 +235,18 @@ out_free_dummy_page: iommu->dummy_page = 0UL; out_free_map: - kfree(iommu->tbl.map); - iommu->tbl.map = NULL; + kfree(iommu->arena.map); + iommu->arena.map = NULL; return -ENOMEM; } -static inline iopte_t *alloc_npages(struct device *dev, - struct iommu *iommu, +static inline iopte_t *alloc_npages(struct device *dev, struct iommu *iommu, unsigned long npages) { unsigned long entry; - entry = iommu_tbl_range_alloc(dev, &iommu->tbl, npages, NULL, - __this_cpu_read(iommu_pool_hash)); + entry = iommu_range_alloc(dev, iommu, npages, NULL); if (unlikely(entry == DMA_ERROR_CODE)) return NULL; @@ -220,7 +284,7 @@ static void *dma_4u_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp, struct dma_attrs *attrs) { - unsigned long order, first_page; + unsigned long flags, order, first_page; struct iommu *iommu; struct page *page; int npages, nid; @@ -242,14 +306,16 @@ static void *dma_4u_alloc_coherent(struct device *dev, size_t size, iommu = dev->archdata.iommu; + spin_lock_irqsave(&iommu->lock, flags); iopte = alloc_npages(dev, iommu, size >> IO_PAGE_SHIFT); + spin_unlock_irqrestore(&iommu->lock, flags); if (unlikely(iopte == NULL)) { free_pages(first_page, order); return NULL; } - *dma_addrp = (iommu->tbl.page_table_map_base + + *dma_addrp = (iommu->page_table_map_base + ((iopte - iommu->page_table) << IO_PAGE_SHIFT)); ret = (void *) first_page; npages = size >> IO_PAGE_SHIFT; @@ -270,12 +336,16 @@ static void dma_4u_free_coherent(struct device *dev, size_t size, struct dma_attrs *attrs) { struct iommu *iommu; - unsigned long order, npages; + unsigned long flags, order, npages; npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; iommu = dev->archdata.iommu; - iommu_tbl_range_free(&iommu->tbl, dvma, npages, false, NULL); + spin_lock_irqsave(&iommu->lock, flags); + + iommu_range_free(iommu, dvma, npages); + + spin_unlock_irqrestore(&iommu->lock, flags); order = get_order(size); if (order < 10) @@ -305,8 +375,8 @@ static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page, npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; - base = alloc_npages(dev, iommu, npages); spin_lock_irqsave(&iommu->lock, flags); + base = alloc_npages(dev, iommu, npages); ctx = 0; if (iommu->iommu_ctxflush) ctx = iommu_alloc_ctx(iommu); @@ -315,7 +385,7 @@ static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page, if (unlikely(!base)) goto bad; - bus_addr = (iommu->tbl.page_table_map_base + + bus_addr = (iommu->page_table_map_base + ((base - iommu->page_table) << IO_PAGE_SHIFT)); ret = bus_addr | (oaddr & ~IO_PAGE_MASK); base_paddr = __pa(oaddr & IO_PAGE_MASK); @@ -426,7 +496,7 @@ static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr, npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; base = iommu->page_table + - ((bus_addr - iommu->tbl.page_table_map_base) >> IO_PAGE_SHIFT); + ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); bus_addr &= IO_PAGE_MASK; spin_lock_irqsave(&iommu->lock, flags); @@ -445,11 +515,11 @@ static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr, for (i = 0; i < npages; i++) iopte_make_dummy(iommu, base + i); + iommu_range_free(iommu, bus_addr, npages); + iommu_free_ctx(iommu, ctx); - spin_unlock_irqrestore(&iommu->lock, flags); - iommu_tbl_range_free(&iommu->tbl, bus_addr, npages, - false, NULL); + spin_unlock_irqrestore(&iommu->lock, flags); } static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, @@ -497,7 +567,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, max_seg_size = dma_get_max_seg_size(dev); seg_boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, IO_PAGE_SIZE) >> IO_PAGE_SHIFT; - base_shift = iommu->tbl.page_table_map_base >> IO_PAGE_SHIFT; + base_shift = iommu->page_table_map_base >> IO_PAGE_SHIFT; for_each_sg(sglist, s, nelems, i) { unsigned long paddr, npages, entry, out_entry = 0, slen; iopte_t *base; @@ -511,8 +581,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, /* Allocate iommu entries for that segment */ paddr = (unsigned long) SG_ENT_PHYS_ADDRESS(s); npages = iommu_num_pages(paddr, slen, IO_PAGE_SIZE); - entry = iommu_tbl_range_alloc(dev, &iommu->tbl, npages, &handle, - __this_cpu_read(iommu_pool_hash)); + entry = iommu_range_alloc(dev, iommu, npages, &handle); /* Handle failure */ if (unlikely(entry == DMA_ERROR_CODE)) { @@ -525,7 +594,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, base = iommu->page_table + entry; /* Convert entry to a dma_addr_t */ - dma_addr = iommu->tbl.page_table_map_base + + dma_addr = iommu->page_table_map_base + (entry << IO_PAGE_SHIFT); dma_addr |= (s->offset & ~IO_PAGE_MASK); @@ -585,17 +654,15 @@ iommu_map_failed: vaddr = s->dma_address & IO_PAGE_MASK; npages = iommu_num_pages(s->dma_address, s->dma_length, IO_PAGE_SIZE); + iommu_range_free(iommu, vaddr, npages); - entry = (vaddr - iommu->tbl.page_table_map_base) + entry = (vaddr - iommu->page_table_map_base) >> IO_PAGE_SHIFT; base = iommu->page_table + entry; for (j = 0; j < npages; j++) iopte_make_dummy(iommu, base + j); - iommu_tbl_range_free(&iommu->tbl, vaddr, npages, - false, NULL); - s->dma_address = DMA_ERROR_CODE; s->dma_length = 0; } @@ -610,19 +677,17 @@ iommu_map_failed: /* If contexts are being used, they are the same in all of the mappings * we make for a particular SG. */ -static unsigned long fetch_sg_ctx(struct iommu *iommu, - struct scatterlist *sg) +static unsigned long fetch_sg_ctx(struct iommu *iommu, struct scatterlist *sg) { unsigned long ctx = 0; if (iommu->iommu_ctxflush) { iopte_t *base; u32 bus_addr; - struct iommu_table *tbl = &iommu->tbl; bus_addr = sg->dma_address & IO_PAGE_MASK; base = iommu->page_table + - ((bus_addr - tbl->page_table_map_base) >> IO_PAGE_SHIFT); + ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; } @@ -658,8 +723,9 @@ static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist, if (!len) break; npages = iommu_num_pages(dma_handle, len, IO_PAGE_SIZE); + iommu_range_free(iommu, dma_handle, npages); - entry = ((dma_handle - iommu->tbl.page_table_map_base) + entry = ((dma_handle - iommu->page_table_map_base) >> IO_PAGE_SHIFT); base = iommu->page_table + entry; @@ -671,8 +737,6 @@ static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist, for (i = 0; i < npages; i++) iopte_make_dummy(iommu, base + i); - iommu_tbl_range_free(&iommu->tbl, dma_handle, npages, false, - NULL); sg = sg_next(sg); } @@ -706,10 +770,9 @@ static void dma_4u_sync_single_for_cpu(struct device *dev, if (iommu->iommu_ctxflush && strbuf->strbuf_ctxflush) { iopte_t *iopte; - struct iommu_table *tbl = &iommu->tbl; iopte = iommu->page_table + - ((bus_addr - tbl->page_table_map_base)>>IO_PAGE_SHIFT); + ((bus_addr - iommu->page_table_map_base)>>IO_PAGE_SHIFT); ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; } @@ -742,10 +805,9 @@ static void dma_4u_sync_sg_for_cpu(struct device *dev, if (iommu->iommu_ctxflush && strbuf->strbuf_ctxflush) { iopte_t *iopte; - struct iommu_table *tbl = &iommu->tbl; - iopte = iommu->page_table + ((sglist[0].dma_address - - tbl->page_table_map_base) >> IO_PAGE_SHIFT); + iopte = iommu->page_table + + ((sglist[0].dma_address - iommu->page_table_map_base) >> IO_PAGE_SHIFT); ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; } diff --git a/arch/sparc/kernel/iommu_common.h b/arch/sparc/kernel/iommu_common.h index f4be0d724fc6..1ec0de4156e7 100644 --- a/arch/sparc/kernel/iommu_common.h +++ b/arch/sparc/kernel/iommu_common.h @@ -48,4 +48,12 @@ static inline int is_span_boundary(unsigned long entry, return iommu_is_span_boundary(entry, nr, shift, boundary_size); } +unsigned long iommu_range_alloc(struct device *dev, + struct iommu *iommu, + unsigned long npages, + unsigned long *handle); +void iommu_range_free(struct iommu *iommu, + dma_addr_t dma_addr, + unsigned long npages); + #endif /* _IOMMU_COMMON_H */ diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index d485697c37c0..274a9f59d95c 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -15,8 +15,6 @@ #include #include #include -#include -#include #include #include @@ -29,11 +27,6 @@ #define DRV_MODULE_VERSION "1.1" #define DRV_MODULE_RELDATE "July 22, 2008" -#define COOKIE_PGSZ_CODE 0xf000000000000000ULL -#define COOKIE_PGSZ_CODE_SHIFT 60ULL - -static DEFINE_PER_CPU(unsigned int, ldc_pool_hash); - static char version[] = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; #define LDC_PACKET_SIZE 64 @@ -105,10 +98,10 @@ static const struct ldc_mode_ops stream_ops; int ldom_domaining_enabled; struct ldc_iommu { - /* Protects ldc_unmap. */ + /* Protects arena alloc/free. */ spinlock_t lock; + struct iommu_arena arena; struct ldc_mtable_entry *page_table; - struct iommu_table iommu_table; }; struct ldc_channel { @@ -1005,85 +998,31 @@ static void free_queue(unsigned long num_entries, struct ldc_packet *q) free_pages((unsigned long)q, order); } -static unsigned long ldc_cookie_to_index(u64 cookie, void *arg) -{ - u64 szcode = cookie >> COOKIE_PGSZ_CODE_SHIFT; - /* struct ldc_iommu *ldc_iommu = (struct ldc_iommu *)arg; */ - - cookie &= ~COOKIE_PGSZ_CODE; - - return (cookie >> (13ULL + (szcode * 3ULL))); -} - -struct ldc_demap_arg { - struct ldc_iommu *ldc_iommu; - u64 cookie; - unsigned long id; -}; - -static void ldc_demap(void *arg, unsigned long entry, unsigned long npages) -{ - struct ldc_demap_arg *ldc_demap_arg = arg; - struct ldc_iommu *iommu = ldc_demap_arg->ldc_iommu; - unsigned long id = ldc_demap_arg->id; - u64 cookie = ldc_demap_arg->cookie; - struct ldc_mtable_entry *base; - unsigned long i, shift; - - shift = (cookie >> COOKIE_PGSZ_CODE_SHIFT) * 3; - base = iommu->page_table + entry; - for (i = 0; i < npages; i++) { - if (base->cookie) - sun4v_ldc_revoke(id, cookie + (i << shift), - base->cookie); - base->mte = 0; - } -} - /* XXX Make this configurable... XXX */ #define LDC_IOTABLE_SIZE (8 * 1024) -struct iommu_tbl_ops ldc_iommu_ops = { - .cookie_to_index = ldc_cookie_to_index, - .demap = ldc_demap, -}; - -static void setup_ldc_pool_hash(void) -{ - unsigned int i; - static bool do_once; - - if (do_once) - return; - do_once = true; - for_each_possible_cpu(i) - per_cpu(ldc_pool_hash, i) = hash_32(i, IOMMU_POOL_HASHBITS); -} - - -static int ldc_iommu_init(const char *name, struct ldc_channel *lp) +static int ldc_iommu_init(struct ldc_channel *lp) { unsigned long sz, num_tsb_entries, tsbsize, order; - struct ldc_iommu *ldc_iommu = &lp->iommu; - struct iommu_table *iommu = &ldc_iommu->iommu_table; + struct ldc_iommu *iommu = &lp->iommu; struct ldc_mtable_entry *table; unsigned long hv_err; int err; num_tsb_entries = LDC_IOTABLE_SIZE; tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry); - setup_ldc_pool_hash(); - spin_lock_init(&ldc_iommu->lock); + + spin_lock_init(&iommu->lock); sz = num_tsb_entries / 8; sz = (sz + 7UL) & ~7UL; - iommu->map = kzalloc(sz, GFP_KERNEL); - if (!iommu->map) { + iommu->arena.map = kzalloc(sz, GFP_KERNEL); + if (!iommu->arena.map) { printk(KERN_ERR PFX "Alloc of arena map failed, sz=%lu\n", sz); return -ENOMEM; } - iommu_tbl_pool_init(iommu, num_tsb_entries, PAGE_SHIFT, - &ldc_iommu_ops, false, 1); + + iommu->arena.limit = num_tsb_entries; order = get_order(tsbsize); @@ -1098,7 +1037,7 @@ static int ldc_iommu_init(const char *name, struct ldc_channel *lp) memset(table, 0, PAGE_SIZE << order); - ldc_iommu->page_table = table; + iommu->page_table = table; hv_err = sun4v_ldc_set_map_table(lp->id, __pa(table), num_tsb_entries); @@ -1110,32 +1049,31 @@ static int ldc_iommu_init(const char *name, struct ldc_channel *lp) out_free_table: free_pages((unsigned long) table, order); - ldc_iommu->page_table = NULL; + iommu->page_table = NULL; out_free_map: - kfree(iommu->map); - iommu->map = NULL; + kfree(iommu->arena.map); + iommu->arena.map = NULL; return err; } static void ldc_iommu_release(struct ldc_channel *lp) { - struct ldc_iommu *ldc_iommu = &lp->iommu; - struct iommu_table *iommu = &ldc_iommu->iommu_table; + struct ldc_iommu *iommu = &lp->iommu; unsigned long num_tsb_entries, tsbsize, order; (void) sun4v_ldc_set_map_table(lp->id, 0, 0); - num_tsb_entries = iommu->poolsize * iommu->nr_pools; + num_tsb_entries = iommu->arena.limit; tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry); order = get_order(tsbsize); - free_pages((unsigned long) ldc_iommu->page_table, order); - ldc_iommu->page_table = NULL; + free_pages((unsigned long) iommu->page_table, order); + iommu->page_table = NULL; - kfree(iommu->map); - iommu->map = NULL; + kfree(iommu->arena.map); + iommu->arena.map = NULL; } struct ldc_channel *ldc_alloc(unsigned long id, @@ -1202,7 +1140,7 @@ struct ldc_channel *ldc_alloc(unsigned long id, lp->id = id; - err = ldc_iommu_init(name, lp); + err = ldc_iommu_init(lp); if (err) goto out_free_ldc; @@ -1947,6 +1885,40 @@ int ldc_read(struct ldc_channel *lp, void *buf, unsigned int size) } EXPORT_SYMBOL(ldc_read); +static long arena_alloc(struct ldc_iommu *iommu, unsigned long npages) +{ + struct iommu_arena *arena = &iommu->arena; + unsigned long n, start, end, limit; + int pass; + + limit = arena->limit; + start = arena->hint; + pass = 0; + +again: + n = bitmap_find_next_zero_area(arena->map, limit, start, npages, 0); + end = n + npages; + if (unlikely(end >= limit)) { + if (likely(pass < 1)) { + limit = start; + start = 0; + pass++; + goto again; + } else { + /* Scanned the whole thing, give up. */ + return -1; + } + } + bitmap_set(arena->map, n, npages); + + arena->hint = end; + + return n; +} + +#define COOKIE_PGSZ_CODE 0xf000000000000000ULL +#define COOKIE_PGSZ_CODE_SHIFT 60ULL + static u64 pagesize_code(void) { switch (PAGE_SIZE) { @@ -1973,14 +1945,23 @@ static u64 make_cookie(u64 index, u64 pgsz_code, u64 page_offset) page_offset); } +static u64 cookie_to_index(u64 cookie, unsigned long *shift) +{ + u64 szcode = cookie >> COOKIE_PGSZ_CODE_SHIFT; + + cookie &= ~COOKIE_PGSZ_CODE; + + *shift = szcode * 3; + + return (cookie >> (13ULL + (szcode * 3ULL))); +} static struct ldc_mtable_entry *alloc_npages(struct ldc_iommu *iommu, unsigned long npages) { long entry; - entry = iommu_tbl_range_alloc(NULL, &iommu->iommu_table, npages, - NULL, __this_cpu_read(ldc_pool_hash)); + entry = arena_alloc(iommu, npages); if (unlikely(entry < 0)) return NULL; @@ -2109,7 +2090,7 @@ int ldc_map_sg(struct ldc_channel *lp, struct ldc_trans_cookie *cookies, int ncookies, unsigned int map_perm) { - unsigned long i, npages; + unsigned long i, npages, flags; struct ldc_mtable_entry *base; struct cookie_state state; struct ldc_iommu *iommu; @@ -2128,7 +2109,9 @@ int ldc_map_sg(struct ldc_channel *lp, iommu = &lp->iommu; + spin_lock_irqsave(&iommu->lock, flags); base = alloc_npages(iommu, npages); + spin_unlock_irqrestore(&iommu->lock, flags); if (!base) return -ENOMEM; @@ -2153,7 +2136,7 @@ int ldc_map_single(struct ldc_channel *lp, struct ldc_trans_cookie *cookies, int ncookies, unsigned int map_perm) { - unsigned long npages, pa; + unsigned long npages, pa, flags; struct ldc_mtable_entry *base; struct cookie_state state; struct ldc_iommu *iommu; @@ -2169,7 +2152,9 @@ int ldc_map_single(struct ldc_channel *lp, iommu = &lp->iommu; + spin_lock_irqsave(&iommu->lock, flags); base = alloc_npages(iommu, npages); + spin_unlock_irqrestore(&iommu->lock, flags); if (!base) return -ENOMEM; @@ -2187,29 +2172,35 @@ int ldc_map_single(struct ldc_channel *lp, } EXPORT_SYMBOL(ldc_map_single); - static void free_npages(unsigned long id, struct ldc_iommu *iommu, u64 cookie, u64 size) { - unsigned long npages; - struct ldc_demap_arg demap_arg; - - demap_arg.ldc_iommu = iommu; - demap_arg.cookie = cookie; - demap_arg.id = id; + struct iommu_arena *arena = &iommu->arena; + unsigned long i, shift, index, npages; + struct ldc_mtable_entry *base; npages = PAGE_ALIGN(((cookie & ~PAGE_MASK) + size)) >> PAGE_SHIFT; - iommu_tbl_range_free(&iommu->iommu_table, cookie, npages, true, - &demap_arg); + index = cookie_to_index(cookie, &shift); + base = iommu->page_table + index; + + BUG_ON(index > arena->limit || + (index + npages) > arena->limit); + for (i = 0; i < npages; i++) { + if (base->cookie) + sun4v_ldc_revoke(id, cookie + (i << shift), + base->cookie); + base->mte = 0; + __clear_bit(index + i, arena->map); + } } void ldc_unmap(struct ldc_channel *lp, struct ldc_trans_cookie *cookies, int ncookies) { struct ldc_iommu *iommu = &lp->iommu; - int i; unsigned long flags; + int i; spin_lock_irqsave(&iommu->lock, flags); for (i = 0; i < ncookies; i++) { diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index 9b76b9d639e1..47ddbd496a1e 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -15,8 +15,6 @@ #include #include #include -#include -#include #include #include @@ -30,7 +28,6 @@ #define DRIVER_NAME "pci_sun4v" #define PFX DRIVER_NAME ": " -static DEFINE_PER_CPU(unsigned int, iommu_pool_hash); static unsigned long vpci_major = 1; static unsigned long vpci_minor = 1; @@ -158,13 +155,14 @@ static void *dma_4v_alloc_coherent(struct device *dev, size_t size, iommu = dev->archdata.iommu; - entry = iommu_tbl_range_alloc(dev, &iommu->tbl, npages, NULL, - __this_cpu_read(iommu_pool_hash)); + spin_lock_irqsave(&iommu->lock, flags); + entry = iommu_range_alloc(dev, iommu, npages, NULL); + spin_unlock_irqrestore(&iommu->lock, flags); if (unlikely(entry == DMA_ERROR_CODE)) goto range_alloc_fail; - *dma_addrp = (iommu->tbl.page_table_map_base + + *dma_addrp = (iommu->page_table_map_base + (entry << IO_PAGE_SHIFT)); ret = (void *) first_page; first_page = __pa(first_page); @@ -190,46 +188,45 @@ static void *dma_4v_alloc_coherent(struct device *dev, size_t size, return ret; iommu_map_fail: - iommu_tbl_range_free(&iommu->tbl, *dma_addrp, npages, false, NULL); + /* Interrupts are disabled. */ + spin_lock(&iommu->lock); + iommu_range_free(iommu, *dma_addrp, npages); + spin_unlock_irqrestore(&iommu->lock, flags); range_alloc_fail: free_pages(first_page, order); return NULL; } -static void dma_4v_iommu_demap(void *demap_arg, unsigned long entry, - unsigned long npages) -{ - u32 devhandle = *(u32 *)demap_arg; - unsigned long num, flags; - - local_irq_save(flags); - do { - num = pci_sun4v_iommu_demap(devhandle, - HV_PCI_TSBID(0, entry), - npages); - - entry += num; - npages -= num; - } while (npages != 0); - local_irq_restore(flags); -} - static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu, dma_addr_t dvma, struct dma_attrs *attrs) { struct pci_pbm_info *pbm; struct iommu *iommu; - unsigned long order, npages, entry; + unsigned long flags, order, npages, entry; u32 devhandle; npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; iommu = dev->archdata.iommu; pbm = dev->archdata.host_controller; devhandle = pbm->devhandle; - entry = ((dvma - iommu->tbl.page_table_map_base) >> IO_PAGE_SHIFT); - dma_4v_iommu_demap(&devhandle, entry, npages); - iommu_tbl_range_free(&iommu->tbl, dvma, npages, false, NULL); + entry = ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + + spin_lock_irqsave(&iommu->lock, flags); + + iommu_range_free(iommu, dvma, npages); + + do { + unsigned long num; + + num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry), + npages); + entry += num; + npages -= num; + } while (npages != 0); + + spin_unlock_irqrestore(&iommu->lock, flags); + order = get_order(size); if (order < 10) free_pages((unsigned long)cpu, order); @@ -256,13 +253,14 @@ static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page, npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; - entry = iommu_tbl_range_alloc(dev, &iommu->tbl, npages, NULL, - __this_cpu_read(iommu_pool_hash)); + spin_lock_irqsave(&iommu->lock, flags); + entry = iommu_range_alloc(dev, iommu, npages, NULL); + spin_unlock_irqrestore(&iommu->lock, flags); if (unlikely(entry == DMA_ERROR_CODE)) goto bad; - bus_addr = (iommu->tbl.page_table_map_base + + bus_addr = (iommu->page_table_map_base + (entry << IO_PAGE_SHIFT)); ret = bus_addr | (oaddr & ~IO_PAGE_MASK); base_paddr = __pa(oaddr & IO_PAGE_MASK); @@ -292,7 +290,11 @@ bad: return DMA_ERROR_CODE; iommu_map_fail: - iommu_tbl_range_free(&iommu->tbl, bus_addr, npages, false, NULL); + /* Interrupts are disabled. */ + spin_lock(&iommu->lock); + iommu_range_free(iommu, bus_addr, npages); + spin_unlock_irqrestore(&iommu->lock, flags); + return DMA_ERROR_CODE; } @@ -302,7 +304,7 @@ static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr, { struct pci_pbm_info *pbm; struct iommu *iommu; - unsigned long npages; + unsigned long flags, npages; long entry; u32 devhandle; @@ -319,9 +321,22 @@ static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr, npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); npages >>= IO_PAGE_SHIFT; bus_addr &= IO_PAGE_MASK; - entry = (bus_addr - iommu->tbl.page_table_map_base) >> IO_PAGE_SHIFT; - dma_4v_iommu_demap(&devhandle, entry, npages); - iommu_tbl_range_free(&iommu->tbl, bus_addr, npages, false, NULL); + + spin_lock_irqsave(&iommu->lock, flags); + + iommu_range_free(iommu, bus_addr, npages); + + entry = (bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT; + do { + unsigned long num; + + num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry), + npages); + entry += num; + npages -= num; + } while (npages != 0); + + spin_unlock_irqrestore(&iommu->lock, flags); } static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, @@ -356,14 +371,14 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, /* Init first segment length for backout at failure */ outs->dma_length = 0; - local_irq_save(flags); + spin_lock_irqsave(&iommu->lock, flags); iommu_batch_start(dev, prot, ~0UL); max_seg_size = dma_get_max_seg_size(dev); seg_boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, IO_PAGE_SIZE) >> IO_PAGE_SHIFT; - base_shift = iommu->tbl.page_table_map_base >> IO_PAGE_SHIFT; + base_shift = iommu->page_table_map_base >> IO_PAGE_SHIFT; for_each_sg(sglist, s, nelems, i) { unsigned long paddr, npages, entry, out_entry = 0, slen; @@ -376,8 +391,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, /* Allocate iommu entries for that segment */ paddr = (unsigned long) SG_ENT_PHYS_ADDRESS(s); npages = iommu_num_pages(paddr, slen, IO_PAGE_SIZE); - entry = iommu_tbl_range_alloc(dev, &iommu->tbl, npages, &handle, - __this_cpu_read(iommu_pool_hash)); + entry = iommu_range_alloc(dev, iommu, npages, &handle); /* Handle failure */ if (unlikely(entry == DMA_ERROR_CODE)) { @@ -390,7 +404,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, iommu_batch_new_entry(entry); /* Convert entry to a dma_addr_t */ - dma_addr = iommu->tbl.page_table_map_base + + dma_addr = iommu->page_table_map_base + (entry << IO_PAGE_SHIFT); dma_addr |= (s->offset & ~IO_PAGE_MASK); @@ -437,7 +451,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, if (unlikely(err < 0L)) goto iommu_map_failed; - local_irq_restore(flags); + spin_unlock_irqrestore(&iommu->lock, flags); if (outcount < incount) { outs = sg_next(outs); @@ -455,8 +469,7 @@ iommu_map_failed: vaddr = s->dma_address & IO_PAGE_MASK; npages = iommu_num_pages(s->dma_address, s->dma_length, IO_PAGE_SIZE); - iommu_tbl_range_free(&iommu->tbl, vaddr, npages, - false, NULL); + iommu_range_free(iommu, vaddr, npages); /* XXX demap? XXX */ s->dma_address = DMA_ERROR_CODE; s->dma_length = 0; @@ -464,7 +477,7 @@ iommu_map_failed: if (s == outs) break; } - local_irq_restore(flags); + spin_unlock_irqrestore(&iommu->lock, flags); return 0; } @@ -476,7 +489,7 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist, struct pci_pbm_info *pbm; struct scatterlist *sg; struct iommu *iommu; - unsigned long flags, entry; + unsigned long flags; u32 devhandle; BUG_ON(direction == DMA_NONE); @@ -485,27 +498,33 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist, pbm = dev->archdata.host_controller; devhandle = pbm->devhandle; - local_irq_save(flags); + spin_lock_irqsave(&iommu->lock, flags); sg = sglist; while (nelems--) { dma_addr_t dma_handle = sg->dma_address; unsigned int len = sg->dma_length; - unsigned long npages; - struct iommu_table *tbl = &iommu->tbl; - unsigned long shift = IO_PAGE_SHIFT; + unsigned long npages, entry; if (!len) break; npages = iommu_num_pages(dma_handle, len, IO_PAGE_SIZE); - entry = ((dma_handle - tbl->page_table_map_base) >> shift); - dma_4v_iommu_demap(&devhandle, entry, npages); - iommu_tbl_range_free(&iommu->tbl, dma_handle, npages, - false, NULL); + iommu_range_free(iommu, dma_handle, npages); + + entry = ((dma_handle - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + while (npages) { + unsigned long num; + + num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry), + npages); + entry += num; + npages -= num; + } + sg = sg_next(sg); } - local_irq_restore(flags); + spin_unlock_irqrestore(&iommu->lock, flags); } static struct dma_map_ops sun4v_dma_ops = { @@ -517,8 +536,6 @@ static struct dma_map_ops sun4v_dma_ops = { .unmap_sg = dma_4v_unmap_sg, }; -static struct iommu_tbl_ops dma_4v_iommu_ops; - static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm, struct device *parent) { struct property *prop; @@ -533,33 +550,30 @@ static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm, struct device *parent) } static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, - struct iommu_table *iommu) + struct iommu *iommu) { - struct iommu_pool *pool; - unsigned long i, pool_nr, cnt = 0; + struct iommu_arena *arena = &iommu->arena; + unsigned long i, cnt = 0; u32 devhandle; devhandle = pbm->devhandle; - for (pool_nr = 0; pool_nr < iommu->nr_pools; pool_nr++) { - pool = &(iommu->arena_pool[pool_nr]); - for (i = pool->start; i <= pool->end; i++) { - unsigned long ret, io_attrs, ra; - - ret = pci_sun4v_iommu_getmap(devhandle, - HV_PCI_TSBID(0, i), - &io_attrs, &ra); - if (ret == HV_EOK) { - if (page_in_phys_avail(ra)) { - pci_sun4v_iommu_demap(devhandle, - HV_PCI_TSBID(0, - i), 1); - } else { - cnt++; - __set_bit(i, iommu->map); - } + for (i = 0; i < arena->limit; i++) { + unsigned long ret, io_attrs, ra; + + ret = pci_sun4v_iommu_getmap(devhandle, + HV_PCI_TSBID(0, i), + &io_attrs, &ra); + if (ret == HV_EOK) { + if (page_in_phys_avail(ra)) { + pci_sun4v_iommu_demap(devhandle, + HV_PCI_TSBID(0, i), 1); + } else { + cnt++; + __set_bit(i, arena->map); } } } + return cnt; } @@ -587,22 +601,22 @@ static int pci_sun4v_iommu_init(struct pci_pbm_info *pbm) dma_offset = vdma[0]; /* Setup initial software IOMMU state. */ + spin_lock_init(&iommu->lock); iommu->ctx_lowest_free = 1; - iommu->tbl.page_table_map_base = dma_offset; + iommu->page_table_map_base = dma_offset; iommu->dma_addr_mask = dma_mask; /* Allocate and initialize the free area map. */ sz = (num_tsb_entries + 7) / 8; sz = (sz + 7UL) & ~7UL; - iommu->tbl.map = kzalloc(sz, GFP_KERNEL); - if (!iommu->tbl.map) { + iommu->arena.map = kzalloc(sz, GFP_KERNEL); + if (!iommu->arena.map) { printk(KERN_ERR PFX "Error, kmalloc(arena.map) failed.\n"); return -ENOMEM; } - iommu_tbl_pool_init(&iommu->tbl, num_tsb_entries, IO_PAGE_SHIFT, - &dma_4v_iommu_ops, false /* no large_pool */, - 0 /* default npools */); - sz = probe_existing_entries(pbm, &iommu->tbl); + iommu->arena.limit = num_tsb_entries; + + sz = probe_existing_entries(pbm, iommu); if (sz) printk("%s: Imported %lu TSB entries from OBP\n", pbm->name, sz); @@ -1001,17 +1015,8 @@ static struct platform_driver pci_sun4v_driver = { .probe = pci_sun4v_probe, }; -static void setup_iommu_pool_hash(void) -{ - unsigned int i; - - for_each_possible_cpu(i) - per_cpu(iommu_pool_hash, i) = hash_32(i, IOMMU_POOL_HASHBITS); -} - static int __init pci_sun4v_init(void) { - setup_iommu_pool_hash(); return platform_driver_register(&pci_sun4v_driver); } diff --git a/include/linux/iommu-common.h b/include/linux/iommu-common.h deleted file mode 100644 index 6be5c863f329..000000000000 --- a/include/linux/iommu-common.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _LINUX_IOMMU_COMMON_H -#define _LINUX_IOMMU_COMMON_H - -#include -#include -#include - -#define IOMMU_POOL_HASHBITS 4 -#define IOMMU_NR_POOLS (1 << IOMMU_POOL_HASHBITS) - -struct iommu_pool { - unsigned long start; - unsigned long end; - unsigned long hint; - spinlock_t lock; -}; - -struct iommu_table; - -struct iommu_tbl_ops { - unsigned long (*cookie_to_index)(u64, void *); - void (*demap)(void *, unsigned long, unsigned long); - void (*reset)(struct iommu_table *); -}; - -struct iommu_table { - unsigned long page_table_map_base; - unsigned long page_table_shift; - unsigned long nr_pools; - const struct iommu_tbl_ops *iommu_tbl_ops; - unsigned long poolsize; - struct iommu_pool arena_pool[IOMMU_NR_POOLS]; - u32 flags; -#define IOMMU_HAS_LARGE_POOL 0x00000001 - struct iommu_pool large_pool; - unsigned long *map; -}; - -extern void iommu_tbl_pool_init(struct iommu_table *iommu, - unsigned long num_entries, - u32 page_table_shift, - const struct iommu_tbl_ops *iommu_tbl_ops, - bool large_pool, u32 npools); - -extern unsigned long iommu_tbl_range_alloc(struct device *dev, - struct iommu_table *iommu, - unsigned long npages, - unsigned long *handle, - unsigned int pool_hash); - -extern void iommu_tbl_range_free(struct iommu_table *iommu, - u64 dma_addr, unsigned long npages, - bool do_demap, void *demap_arg); - -#endif diff --git a/lib/Makefile b/lib/Makefile index 6c37933336a0..da6116b21555 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -106,7 +106,7 @@ obj-$(CONFIG_AUDIT_GENERIC) += audit.o obj-$(CONFIG_AUDIT_COMPAT_GENERIC) += compat_audit.o obj-$(CONFIG_SWIOTLB) += swiotlb.o -obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o iommu-common.o +obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o obj-$(CONFIG_NOTIFIER_ERROR_INJECTION) += notifier-error-inject.o obj-$(CONFIG_CPU_NOTIFIER_ERROR_INJECT) += cpu-notifier-error-inject.o diff --git a/lib/iommu-common.c b/lib/iommu-common.c deleted file mode 100644 index fac4f35250c9..000000000000 --- a/lib/iommu-common.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * IOMMU mmap management and range allocation functions. - * Based almost entirely upon the powerpc iommu allocator. - */ - -#include -#include -#include -#include -#include -#include - -#ifndef DMA_ERROR_CODE -#define DMA_ERROR_CODE (~(dma_addr_t)0x0) -#endif - -#define IOMMU_LARGE_ALLOC 15 - -/* - * Initialize iommu_pool entries for the iommu_table. `num_entries' - * is the number of table entries. If `large_pool' is set to true, - * the top 1/4 of the table will be set aside for pool allocations - * of more than IOMMU_LARGE_ALLOC pages. - */ -extern void iommu_tbl_pool_init(struct iommu_table *iommu, - unsigned long num_entries, - u32 page_table_shift, - const struct iommu_tbl_ops *iommu_tbl_ops, - bool large_pool, u32 npools) -{ - unsigned int start, i; - struct iommu_pool *p = &(iommu->large_pool); - - if (npools == 0) - iommu->nr_pools = IOMMU_NR_POOLS; - else - iommu->nr_pools = npools; - BUG_ON(npools > IOMMU_NR_POOLS); - - iommu->page_table_shift = page_table_shift; - iommu->iommu_tbl_ops = iommu_tbl_ops; - start = 0; - if (large_pool) - iommu->flags |= IOMMU_HAS_LARGE_POOL; - - if (!large_pool) - iommu->poolsize = num_entries/iommu->nr_pools; - else - iommu->poolsize = (num_entries * 3 / 4)/iommu->nr_pools; - for (i = 0; i < iommu->nr_pools; i++) { - spin_lock_init(&(iommu->arena_pool[i].lock)); - iommu->arena_pool[i].start = start; - iommu->arena_pool[i].hint = start; - start += iommu->poolsize; /* start for next pool */ - iommu->arena_pool[i].end = start - 1; - } - if (!large_pool) - return; - /* initialize large_pool */ - spin_lock_init(&(p->lock)); - p->start = start; - p->hint = p->start; - p->end = num_entries; -} -EXPORT_SYMBOL(iommu_tbl_pool_init); - -unsigned long iommu_tbl_range_alloc(struct device *dev, - struct iommu_table *iommu, - unsigned long npages, - unsigned long *handle, - unsigned int pool_hash) -{ - unsigned long n, end, start, limit, boundary_size; - struct iommu_pool *arena; - int pass = 0; - unsigned int pool_nr; - unsigned int npools = iommu->nr_pools; - unsigned long flags; - bool large_pool = ((iommu->flags & IOMMU_HAS_LARGE_POOL) != 0); - bool largealloc = (large_pool && npages > IOMMU_LARGE_ALLOC); - unsigned long shift; - - /* Sanity check */ - if (unlikely(npages == 0)) { - printk_ratelimited("npages == 0\n"); - return DMA_ERROR_CODE; - } - - if (largealloc) { - arena = &(iommu->large_pool); - spin_lock_irqsave(&arena->lock, flags); - pool_nr = 0; /* to keep compiler happy */ - } else { - /* pick out pool_nr */ - pool_nr = pool_hash & (npools - 1); - arena = &(iommu->arena_pool[pool_nr]); - - /* find first available unlocked pool */ - while (!spin_trylock_irqsave(&(arena->lock), flags)) { - pool_nr = (pool_nr + 1) & (iommu->nr_pools - 1); - arena = &(iommu->arena_pool[pool_nr]); - } - } - - again: - if (pass == 0 && handle && *handle && - (*handle >= arena->start) && (*handle < arena->end)) - start = *handle; - else - start = arena->hint; - - limit = arena->end; - - /* The case below can happen if we have a small segment appended - * to a large, or when the previous alloc was at the very end of - * the available space. If so, go back to the beginning and flush. - */ - if (start >= limit) { - start = arena->start; - if (iommu->iommu_tbl_ops->reset != NULL) - iommu->iommu_tbl_ops->reset(iommu); - } - - if (dev) - boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, - 1 << iommu->page_table_shift); - else - boundary_size = ALIGN(1ULL << 32, 1 << iommu->page_table_shift); - - shift = iommu->page_table_map_base >> iommu->page_table_shift; - boundary_size = boundary_size >> iommu->page_table_shift; - /* - * if the iommu has a non-trivial cookie <-> index mapping, we set - * things up so that iommu_is_span_boundary() merely checks if the - * (index + npages) < num_tsb_entries - */ - if (iommu->iommu_tbl_ops->cookie_to_index != NULL) { - shift = 0; - boundary_size = iommu->poolsize * iommu->nr_pools; - } - n = iommu_area_alloc(iommu->map, limit, start, npages, shift, - boundary_size, 0); - if (n == -1) { - if (likely(pass == 0)) { - /* First failure, rescan from the beginning. */ - arena->hint = arena->start; - if (iommu->iommu_tbl_ops->reset != NULL) - iommu->iommu_tbl_ops->reset(iommu); - pass++; - goto again; - } else if (!largealloc && pass <= iommu->nr_pools) { - spin_unlock(&(arena->lock)); - pool_nr = (pool_nr + 1) & (iommu->nr_pools - 1); - arena = &(iommu->arena_pool[pool_nr]); - while (!spin_trylock(&(arena->lock))) { - pool_nr = (pool_nr + 1) & (iommu->nr_pools - 1); - arena = &(iommu->arena_pool[pool_nr]); - } - arena->hint = arena->start; - pass++; - goto again; - } else { - /* give up */ - spin_unlock_irqrestore(&(arena->lock), flags); - return DMA_ERROR_CODE; - } - } - - end = n + npages; - - arena->hint = end; - - /* Update handle for SG allocations */ - if (handle) - *handle = end; - spin_unlock_irqrestore(&(arena->lock), flags); - - return n; -} -EXPORT_SYMBOL(iommu_tbl_range_alloc); - -static struct iommu_pool *get_pool(struct iommu_table *tbl, - unsigned long entry) -{ - struct iommu_pool *p; - unsigned long largepool_start = tbl->large_pool.start; - bool large_pool = ((tbl->flags & IOMMU_HAS_LARGE_POOL) != 0); - - /* The large pool is the last pool at the top of the table */ - if (large_pool && entry >= largepool_start) { - p = &tbl->large_pool; - } else { - unsigned int pool_nr = entry / tbl->poolsize; - - BUG_ON(pool_nr >= tbl->nr_pools); - p = &tbl->arena_pool[pool_nr]; - } - return p; -} - -void iommu_tbl_range_free(struct iommu_table *iommu, u64 dma_addr, - unsigned long npages, bool do_demap, void *demap_arg) -{ - unsigned long entry; - struct iommu_pool *pool; - unsigned long flags; - unsigned long shift = iommu->page_table_shift; - - if (iommu->iommu_tbl_ops->cookie_to_index != NULL) { - entry = (*iommu->iommu_tbl_ops->cookie_to_index)(dma_addr, - demap_arg); - } else { - entry = (dma_addr - iommu->page_table_map_base) >> shift; - } - pool = get_pool(iommu, entry); - - spin_lock_irqsave(&(pool->lock), flags); - if (do_demap && iommu->iommu_tbl_ops->demap != NULL) - (*iommu->iommu_tbl_ops->demap)(demap_arg, entry, npages); - - bitmap_clear(iommu->map, entry, npages); - spin_unlock_irqrestore(&(pool->lock), flags); -} -EXPORT_SYMBOL(iommu_tbl_range_free); -- cgit v1.2.3 From ff7d37a502022149655c18035b99a53391be0383 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Thu, 9 Apr 2015 15:33:30 -0400 Subject: Break up monolithic iommu table/lock into finer graularity pools and lock Investigation of multithreaded iperf experiments on an ethernet interface show the iommu->lock as the hottest lock identified by lockstat, with something of the order of 21M contentions out of 27M acquisitions, and an average wait time of 26 us for the lock. This is not efficient. A more scalable design is to follow the ppc model, where the iommu_map_table has multiple pools, each stretching over a segment of the map, and with a separate lock for each pool. This model allows for better parallelization of the iommu map search. This patch adds the iommu range alloc/free function infrastructure. Signed-off-by: Sowmini Varadhan Acked-by: Benjamin Herrenschmidt Signed-off-by: David S. Miller --- include/linux/iommu-common.h | 51 +++++++++ lib/Makefile | 2 +- lib/iommu-common.c | 266 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 include/linux/iommu-common.h create mode 100644 lib/iommu-common.c (limited to 'include') diff --git a/include/linux/iommu-common.h b/include/linux/iommu-common.h new file mode 100644 index 000000000000..bbced83b32ee --- /dev/null +++ b/include/linux/iommu-common.h @@ -0,0 +1,51 @@ +#ifndef _LINUX_IOMMU_COMMON_H +#define _LINUX_IOMMU_COMMON_H + +#include +#include +#include + +#define IOMMU_POOL_HASHBITS 4 +#define IOMMU_NR_POOLS (1 << IOMMU_POOL_HASHBITS) + +struct iommu_pool { + unsigned long start; + unsigned long end; + unsigned long hint; + spinlock_t lock; +}; + +struct iommu_map_table { + unsigned long table_map_base; + unsigned long table_shift; + unsigned long nr_pools; + void (*lazy_flush)(struct iommu_map_table *); + unsigned long poolsize; + struct iommu_pool pools[IOMMU_NR_POOLS]; + u32 flags; +#define IOMMU_HAS_LARGE_POOL 0x00000001 +#define IOMMU_NO_SPAN_BOUND 0x00000002 +#define IOMMU_NEED_FLUSH 0x00000004 + struct iommu_pool large_pool; + unsigned long *map; +}; + +extern void iommu_tbl_pool_init(struct iommu_map_table *iommu, + unsigned long num_entries, + u32 table_shift, + void (*lazy_flush)(struct iommu_map_table *), + bool large_pool, u32 npools, + bool skip_span_boundary_check); + +extern unsigned long iommu_tbl_range_alloc(struct device *dev, + struct iommu_map_table *iommu, + unsigned long npages, + unsigned long *handle, + unsigned long mask, + unsigned int align_order); + +extern void iommu_tbl_range_free(struct iommu_map_table *iommu, + u64 dma_addr, unsigned long npages, + unsigned long entry); + +#endif diff --git a/lib/Makefile b/lib/Makefile index da6116b21555..6c37933336a0 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -106,7 +106,7 @@ obj-$(CONFIG_AUDIT_GENERIC) += audit.o obj-$(CONFIG_AUDIT_COMPAT_GENERIC) += compat_audit.o obj-$(CONFIG_SWIOTLB) += swiotlb.o -obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o +obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o iommu-common.o obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o obj-$(CONFIG_NOTIFIER_ERROR_INJECTION) += notifier-error-inject.o obj-$(CONFIG_CPU_NOTIFIER_ERROR_INJECT) += cpu-notifier-error-inject.o diff --git a/lib/iommu-common.c b/lib/iommu-common.c new file mode 100644 index 000000000000..b99f1d744a8d --- /dev/null +++ b/lib/iommu-common.c @@ -0,0 +1,266 @@ +/* + * IOMMU mmap management and range allocation functions. + * Based almost entirely upon the powerpc iommu allocator. + */ + +#include +#include +#include +#include +#include +#include +#include + +unsigned long iommu_large_alloc = 15; + +static DEFINE_PER_CPU(unsigned int, iommu_pool_hash); + +static inline bool need_flush(struct iommu_map_table *iommu) +{ + return (iommu->lazy_flush != NULL && + (iommu->flags & IOMMU_NEED_FLUSH) != 0); +} + +static inline void set_flush(struct iommu_map_table *iommu) +{ + iommu->flags |= IOMMU_NEED_FLUSH; +} + +static inline void clear_flush(struct iommu_map_table *iommu) +{ + iommu->flags &= ~IOMMU_NEED_FLUSH; +} + +static void setup_iommu_pool_hash(void) +{ + unsigned int i; + static bool do_once; + + if (do_once) + return; + do_once = true; + for_each_possible_cpu(i) + per_cpu(iommu_pool_hash, i) = hash_32(i, IOMMU_POOL_HASHBITS); +} + +/* + * Initialize iommu_pool entries for the iommu_map_table. `num_entries' + * is the number of table entries. If `large_pool' is set to true, + * the top 1/4 of the table will be set aside for pool allocations + * of more than iommu_large_alloc pages. + */ +extern void iommu_tbl_pool_init(struct iommu_map_table *iommu, + unsigned long num_entries, + u32 table_shift, + void (*lazy_flush)(struct iommu_map_table *), + bool large_pool, u32 npools, + bool skip_span_boundary_check) +{ + unsigned int start, i; + struct iommu_pool *p = &(iommu->large_pool); + + setup_iommu_pool_hash(); + if (npools == 0) + iommu->nr_pools = IOMMU_NR_POOLS; + else + iommu->nr_pools = npools; + BUG_ON(npools > IOMMU_NR_POOLS); + + iommu->table_shift = table_shift; + iommu->lazy_flush = lazy_flush; + start = 0; + if (skip_span_boundary_check) + iommu->flags |= IOMMU_NO_SPAN_BOUND; + if (large_pool) + iommu->flags |= IOMMU_HAS_LARGE_POOL; + + if (!large_pool) + iommu->poolsize = num_entries/iommu->nr_pools; + else + iommu->poolsize = (num_entries * 3 / 4)/iommu->nr_pools; + for (i = 0; i < iommu->nr_pools; i++) { + spin_lock_init(&(iommu->pools[i].lock)); + iommu->pools[i].start = start; + iommu->pools[i].hint = start; + start += iommu->poolsize; /* start for next pool */ + iommu->pools[i].end = start - 1; + } + if (!large_pool) + return; + /* initialize large_pool */ + spin_lock_init(&(p->lock)); + p->start = start; + p->hint = p->start; + p->end = num_entries; +} +EXPORT_SYMBOL(iommu_tbl_pool_init); + +unsigned long iommu_tbl_range_alloc(struct device *dev, + struct iommu_map_table *iommu, + unsigned long npages, + unsigned long *handle, + unsigned long mask, + unsigned int align_order) +{ + unsigned int pool_hash = __this_cpu_read(iommu_pool_hash); + unsigned long n, end, start, limit, boundary_size; + struct iommu_pool *pool; + int pass = 0; + unsigned int pool_nr; + unsigned int npools = iommu->nr_pools; + unsigned long flags; + bool large_pool = ((iommu->flags & IOMMU_HAS_LARGE_POOL) != 0); + bool largealloc = (large_pool && npages > iommu_large_alloc); + unsigned long shift; + unsigned long align_mask = 0; + + if (align_order > 0) + align_mask = 0xffffffffffffffffl >> (64 - align_order); + + /* Sanity check */ + if (unlikely(npages == 0)) { + WARN_ON_ONCE(1); + return DMA_ERROR_CODE; + } + + if (largealloc) { + pool = &(iommu->large_pool); + pool_nr = 0; /* to keep compiler happy */ + } else { + /* pick out pool_nr */ + pool_nr = pool_hash & (npools - 1); + pool = &(iommu->pools[pool_nr]); + } + spin_lock_irqsave(&pool->lock, flags); + + again: + if (pass == 0 && handle && *handle && + (*handle >= pool->start) && (*handle < pool->end)) + start = *handle; + else + start = pool->hint; + + limit = pool->end; + + /* The case below can happen if we have a small segment appended + * to a large, or when the previous alloc was at the very end of + * the available space. If so, go back to the beginning. If a + * flush is needed, it will get done based on the return value + * from iommu_area_alloc() below. + */ + if (start >= limit) + start = pool->start; + shift = iommu->table_map_base >> iommu->table_shift; + if (limit + shift > mask) { + limit = mask - shift + 1; + /* If we're constrained on address range, first try + * at the masked hint to avoid O(n) search complexity, + * but on second pass, start at 0 in pool 0. + */ + if ((start & mask) >= limit || pass > 0) { + spin_unlock(&(pool->lock)); + pool = &(iommu->pools[0]); + spin_lock(&(pool->lock)); + start = pool->start; + } else { + start &= mask; + } + } + + if (dev) + boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, + 1 << iommu->table_shift); + else + boundary_size = ALIGN(1UL << 32, 1 << iommu->table_shift); + + boundary_size = boundary_size >> iommu->table_shift; + /* + * if the skip_span_boundary_check had been set during init, we set + * things up so that iommu_is_span_boundary() merely checks if the + * (index + npages) < num_tsb_entries + */ + if ((iommu->flags & IOMMU_NO_SPAN_BOUND) != 0) { + shift = 0; + boundary_size = iommu->poolsize * iommu->nr_pools; + } + n = iommu_area_alloc(iommu->map, limit, start, npages, shift, + boundary_size, align_mask); + if (n == -1) { + if (likely(pass == 0)) { + /* First failure, rescan from the beginning. */ + pool->hint = pool->start; + set_flush(iommu); + pass++; + goto again; + } else if (!largealloc && pass <= iommu->nr_pools) { + spin_unlock(&(pool->lock)); + pool_nr = (pool_nr + 1) & (iommu->nr_pools - 1); + pool = &(iommu->pools[pool_nr]); + spin_lock(&(pool->lock)); + pool->hint = pool->start; + set_flush(iommu); + pass++; + goto again; + } else { + /* give up */ + n = DMA_ERROR_CODE; + goto bail; + } + } + if (n < pool->hint || need_flush(iommu)) { + clear_flush(iommu); + iommu->lazy_flush(iommu); + } + + end = n + npages; + pool->hint = end; + + /* Update handle for SG allocations */ + if (handle) + *handle = end; +bail: + spin_unlock_irqrestore(&(pool->lock), flags); + + return n; +} +EXPORT_SYMBOL(iommu_tbl_range_alloc); + +static struct iommu_pool *get_pool(struct iommu_map_table *tbl, + unsigned long entry) +{ + struct iommu_pool *p; + unsigned long largepool_start = tbl->large_pool.start; + bool large_pool = ((tbl->flags & IOMMU_HAS_LARGE_POOL) != 0); + + /* The large pool is the last pool at the top of the table */ + if (large_pool && entry >= largepool_start) { + p = &tbl->large_pool; + } else { + unsigned int pool_nr = entry / tbl->poolsize; + + BUG_ON(pool_nr >= tbl->nr_pools); + p = &tbl->pools[pool_nr]; + } + return p; +} + +/* Caller supplies the index of the entry into the iommu map table + * itself when the mapping from dma_addr to the entry is not the + * default addr->entry mapping below. + */ +void iommu_tbl_range_free(struct iommu_map_table *iommu, u64 dma_addr, + unsigned long npages, unsigned long entry) +{ + struct iommu_pool *pool; + unsigned long flags; + unsigned long shift = iommu->table_shift; + + if (entry == DMA_ERROR_CODE) /* use default addr->entry mapping */ + entry = (dma_addr - iommu->table_map_base) >> shift; + pool = get_pool(iommu, entry); + + spin_lock_irqsave(&(pool->lock), flags); + bitmap_clear(iommu->map, entry, npages); + spin_unlock_irqrestore(&(pool->lock), flags); +} +EXPORT_SYMBOL(iommu_tbl_range_free); -- cgit v1.2.3 From aae013d646aae8787b76255d1a1cadd7f64a47dd Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Sun, 19 Apr 2015 09:45:48 +0800 Subject: ASoC: add static inline funcs to fix a compiling issue When CONFIG_PM_SLEEP is not selected, calling funcs snd_soc_suspend and _resume will generate a compiling issue. Here add static inline stub functions to fix it. Signed-off-by: Jie Yang Signed-off-by: Mark Brown --- include/sound/soc.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index 0d1ade195628..cd8a12508f16 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -387,8 +387,20 @@ int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, int snd_soc_register_card(struct snd_soc_card *card); int snd_soc_unregister_card(struct snd_soc_card *card); int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card); +#ifdef CONFIG_PM_SLEEP int snd_soc_suspend(struct device *dev); int snd_soc_resume(struct device *dev); +#else +static inline int snd_soc_suspend(struct device *dev) +{ + return 0; +} + +static inline int snd_soc_resume(struct device *dev) +{ + return 0; +} +#endif int snd_soc_poweroff(struct device *dev); int snd_soc_register_platform(struct device *dev, const struct snd_soc_platform_driver *platform_drv); -- cgit v1.2.3 From cec32a47010647e8b0603726ebb75b990a4057a4 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 17 Apr 2015 19:12:41 +0200 Subject: media-bus: Fixup RGB444_1X12, RGB565_1X16, and YUV8_1X24 media bus format Change the constant values for RGB444_1X12, RGB565_1X16, and YUV8_1X24 media bus formats in anticipation of a merge conflict with the media tree, where the old values are already taken by RBG888_1X24, RGB888_1X32_PADHI, and VUY8_1X24, respectively. Signed-off-by: Philipp Zabel Signed-off-by: Dave Airlie --- Documentation/DocBook/media/v4l/subdev-formats.xml | 6 +++--- include/uapi/linux/media-bus-format.h | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index 18b71aff48c9..553a38024745 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -196,7 +196,7 @@ see . MEDIA_BUS_FMT_RGB444_1X12 - 0x100e + 0x1016 &dash-ent-20; r3 @@ -326,7 +326,7 @@ see . MEDIA_BUS_FMT_RGB565_1X16 - 0x100f + 0x1017 &dash-ent-16; r4 @@ -3049,7 +3049,7 @@ see . MEDIA_BUS_FMT_YUV8_1X24 - 0x2024 + 0x2025 - - diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index 83ea46f4be51..73c78f18a328 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -33,13 +33,13 @@ #define MEDIA_BUS_FMT_FIXED 0x0001 -/* RGB - next is 0x1016 */ -#define MEDIA_BUS_FMT_RGB444_1X12 0x100e +/* RGB - next is 0x1018 */ +#define MEDIA_BUS_FMT_RGB444_1X12 0x1016 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 #define MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE 0x1003 #define MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE 0x1004 -#define MEDIA_BUS_FMT_RGB565_1X16 0x100f +#define MEDIA_BUS_FMT_RGB565_1X16 0x1017 #define MEDIA_BUS_FMT_BGR565_2X8_BE 0x1005 #define MEDIA_BUS_FMT_BGR565_2X8_LE 0x1006 #define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007 @@ -56,7 +56,7 @@ #define MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA 0x1012 #define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d -/* YUV (including grey) - next is 0x2025 */ +/* YUV (including grey) - next is 0x2026 */ #define MEDIA_BUS_FMT_Y8_1X8 0x2001 #define MEDIA_BUS_FMT_UV8_1X8 0x2015 #define MEDIA_BUS_FMT_UYVY8_1_5X8 0x2002 @@ -82,7 +82,7 @@ #define MEDIA_BUS_FMT_VYUY10_1X20 0x201b #define MEDIA_BUS_FMT_YUYV10_1X20 0x200d #define MEDIA_BUS_FMT_YVYU10_1X20 0x200e -#define MEDIA_BUS_FMT_YUV8_1X24 0x2024 +#define MEDIA_BUS_FMT_YUV8_1X24 0x2025 #define MEDIA_BUS_FMT_YUV10_1X30 0x2016 #define MEDIA_BUS_FMT_AYUV8_1X32 0x2017 #define MEDIA_BUS_FMT_UYVY12_2X12 0x201c -- cgit v1.2.3 From 0ad46af8a618fc38e0cdc3927cfa9f7b42cc9423 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Tue, 14 Apr 2015 17:30:04 -0700 Subject: target: Version 2 of TCMU ABI The initial version of TCMU (in 3.18) does not properly handle bidirectional SCSI commands -- those with both an in and out buffer. In looking to fix this it also became clear that TCMU's support for adding new types of entries (opcodes) to the command ring was broken. We need to fix this now, so that future issues can be handled properly by adding new opcodes. We make the most of this ABI break by enabling bidi cmd handling within TCMP_OP_CMD opcode. Add an iov_bidi_cnt field to tcmu_cmd_entry.req. This enables TCMU to describe bidi commands, but further kernel work is needed for full bidi support. Enlarge tcmu_cmd_entry_hdr by 32 bits by pulling in cmd_id and __pad1. Turn __pad1 into two 8 bit flags fields, for kernel-set and userspace-set flags, "kflags" and "uflags" respectively. Update version fields so userspace can tell the interface is changed. Update tcmu-design.txt with details of how new stuff works: - Specify an additional requirement for userspace to set UNKNOWN_OP (bit 0) in hdr.uflags for unknown/unhandled opcodes. - Define how Data-In and Data-Out fields are described in req.iov[] Changed in v2: - Change name of SKIPPED bit to UNKNOWN bit - PAD op does not set the bit any more - Change len_op helper functions to take just len_op, not the whole struct - Change version to 2 in missed spots, and use defines - Add 16 unused bytes to cmd_entry.req, in case additional SAM cmd parameters need to be included - Add iov_dif_cnt field to specify buffers used for DIF info in iov[] - Rearrange fields to naturally align cdb_off - Handle if userspace sets UNKNOWN_OP by indicating failure of the cmd - Wrap some overly long UPDATE_HEAD lines (Add missing req.iov_bidi_cnt + req.iov_dif_cnt zeroing - Ilias) Signed-off-by: Andy Grover Reviewed-by: Ilias Tsitsimpis Signed-off-by: Nicholas Bellinger --- Documentation/target/tcmu-design.txt | 43 ++++++++++++++++++++------------ drivers/target/target_core_user.c | 46 ++++++++++++++++++++++++++--------- include/uapi/linux/target_core_user.h | 44 ++++++++++++++++++++------------- 3 files changed, 89 insertions(+), 44 deletions(-) (limited to 'include') diff --git a/Documentation/target/tcmu-design.txt b/Documentation/target/tcmu-design.txt index 5518465290bf..43e94ea6d2ca 100644 --- a/Documentation/target/tcmu-design.txt +++ b/Documentation/target/tcmu-design.txt @@ -138,27 +138,40 @@ signals the kernel via a 4-byte write(). When cmd_head equals cmd_tail, the ring is empty -- no commands are currently waiting to be processed by userspace. -TCMU commands start with a common header containing "len_op", a 32-bit -value that stores the length, as well as the opcode in the lowest -unused bits. Currently only two opcodes are defined, TCMU_OP_PAD and -TCMU_OP_CMD. When userspace encounters a command with PAD opcode, it -should skip ahead by the bytes in "length". (The kernel inserts PAD -entries to ensure each CMD entry fits contigously into the circular -buffer.) - -When userspace handles a CMD, it finds the SCSI CDB (Command Data -Block) via tcmu_cmd_entry.req.cdb_off. This is an offset from the -start of the overall shared memory region, not the entry. The data -in/out buffers are accessible via tht req.iov[] array. Note that -each iov.iov_base is also an offset from the start of the region. - -TCMU currently does not support BIDI operations. +TCMU commands are 8-byte aligned. They start with a common header +containing "len_op", a 32-bit value that stores the length, as well as +the opcode in the lowest unused bits. It also contains cmd_id and +flags fields for setting by the kernel (kflags) and userspace +(uflags). + +Currently only two opcodes are defined, TCMU_OP_CMD and TCMU_OP_PAD. + +When the opcode is CMD, the entry in the command ring is a struct +tcmu_cmd_entry. Userspace finds the SCSI CDB (Command Data Block) via +tcmu_cmd_entry.req.cdb_off. This is an offset from the start of the +overall shared memory region, not the entry. The data in/out buffers +are accessible via tht req.iov[] array. iov_cnt contains the number of +entries in iov[] needed to describe either the Data-In or Data-Out +buffers. For bidirectional commands, iov_cnt specifies how many iovec +entries cover the Data-Out area, and iov_bidi_count specifies how many +iovec entries immediately after that in iov[] cover the Data-In +area. Just like other fields, iov.iov_base is an offset from the start +of the region. When completing a command, userspace sets rsp.scsi_status, and rsp.sense_buffer if necessary. Userspace then increments mailbox.cmd_tail by entry.hdr.length (mod cmdr_size) and signals the kernel via the UIO method, a 4-byte write to the file descriptor. +When the opcode is PAD, userspace only updates cmd_tail as above -- +it's a no-op. (The kernel inserts PAD entries to ensure each CMD entry +is contiguous within the command ring.) + +More opcodes may be added in the future. If userspace encounters an +opcode it does not handle, it must set UNKNOWN_OP bit (bit 0) in +hdr.uflags, update cmd_tail, and proceed with processing additional +commands, if any. + The Data Area: This is shared-memory space after the command ring. The organization diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 1fbf304a9491..dbc872a6c981 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -344,8 +344,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) entry = (void *) mb + CMDR_OFF + cmd_head; tcmu_flush_dcache_range(entry, sizeof(*entry)); - tcmu_hdr_set_op(&entry->hdr, TCMU_OP_PAD); - tcmu_hdr_set_len(&entry->hdr, pad_size); + tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_PAD); + tcmu_hdr_set_len(&entry->hdr.len_op, pad_size); + entry->hdr.cmd_id = 0; /* not used for PAD */ + entry->hdr.kflags = 0; + entry->hdr.uflags = 0; UPDATE_HEAD(mb->cmd_head, pad_size, udev->cmdr_size); @@ -355,9 +358,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) entry = (void *) mb + CMDR_OFF + cmd_head; tcmu_flush_dcache_range(entry, sizeof(*entry)); - tcmu_hdr_set_op(&entry->hdr, TCMU_OP_CMD); - tcmu_hdr_set_len(&entry->hdr, command_size); - entry->cmd_id = tcmu_cmd->cmd_id; + tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_CMD); + tcmu_hdr_set_len(&entry->hdr.len_op, command_size); + entry->hdr.cmd_id = tcmu_cmd->cmd_id; + entry->hdr.kflags = 0; + entry->hdr.uflags = 0; /* * Fix up iovecs, and handle if allocation in data ring wrapped. @@ -407,6 +412,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) kunmap_atomic(from); } entry->req.iov_cnt = iov_cnt; + entry->req.iov_bidi_cnt = 0; + entry->req.iov_dif_cnt = 0; /* All offsets relative to mb_addr, not start of entry! */ cdb_off = CMDR_OFF + cmd_head + base_command_size; @@ -464,6 +471,17 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * return; } + if (entry->hdr.uflags & TCMU_UFLAG_UNKNOWN_OP) { + UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size); + pr_warn("TCMU: Userspace set UNKNOWN_OP flag on se_cmd %p\n", + cmd->se_cmd); + transport_generic_request_failure(cmd->se_cmd, + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE); + cmd->se_cmd = NULL; + kmem_cache_free(tcmu_cmd_cache, cmd); + return; + } + if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) { memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer, se_cmd->scsi_sense_length); @@ -542,14 +560,16 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev) tcmu_flush_dcache_range(entry, sizeof(*entry)); - if (tcmu_hdr_get_op(&entry->hdr) == TCMU_OP_PAD) { - UPDATE_HEAD(udev->cmdr_last_cleaned, tcmu_hdr_get_len(&entry->hdr), udev->cmdr_size); + if (tcmu_hdr_get_op(entry->hdr.len_op) == TCMU_OP_PAD) { + UPDATE_HEAD(udev->cmdr_last_cleaned, + tcmu_hdr_get_len(entry->hdr.len_op), + udev->cmdr_size); continue; } - WARN_ON(tcmu_hdr_get_op(&entry->hdr) != TCMU_OP_CMD); + WARN_ON(tcmu_hdr_get_op(entry->hdr.len_op) != TCMU_OP_CMD); spin_lock(&udev->commands_lock); - cmd = idr_find(&udev->commands, entry->cmd_id); + cmd = idr_find(&udev->commands, entry->hdr.cmd_id); if (cmd) idr_remove(&udev->commands, cmd->cmd_id); spin_unlock(&udev->commands_lock); @@ -562,7 +582,9 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev) tcmu_handle_completion(cmd, entry); - UPDATE_HEAD(udev->cmdr_last_cleaned, tcmu_hdr_get_len(&entry->hdr), udev->cmdr_size); + UPDATE_HEAD(udev->cmdr_last_cleaned, + tcmu_hdr_get_len(entry->hdr.len_op), + udev->cmdr_size); handled++; } @@ -840,14 +862,14 @@ static int tcmu_configure_device(struct se_device *dev) udev->data_size = TCMU_RING_SIZE - CMDR_SIZE; mb = udev->mb_addr; - mb->version = 1; + mb->version = TCMU_MAILBOX_VERSION; mb->cmdr_off = CMDR_OFF; mb->cmdr_size = udev->cmdr_size; WARN_ON(!PAGE_ALIGNED(udev->data_off)); WARN_ON(udev->data_size % PAGE_SIZE); - info->version = "1"; + info->version = xstr(TCMU_MAILBOX_VERSION); info->mem[0].name = "tcm-user command & data buffer"; info->mem[0].addr = (phys_addr_t) udev->mb_addr; diff --git a/include/uapi/linux/target_core_user.h b/include/uapi/linux/target_core_user.h index b483d1909d3e..b67f99d3c520 100644 --- a/include/uapi/linux/target_core_user.h +++ b/include/uapi/linux/target_core_user.h @@ -6,7 +6,7 @@ #include #include -#define TCMU_VERSION "1.0" +#define TCMU_VERSION "2.0" /* * Ring Design @@ -39,9 +39,13 @@ * should process the next packet the same way, and so on. */ -#define TCMU_MAILBOX_VERSION 1 +#define TCMU_MAILBOX_VERSION 2 #define ALIGN_SIZE 64 /* Should be enough for most CPUs */ +/* See https://gcc.gnu.org/onlinedocs/cpp/Stringification.html */ +#define xstr(s) str(s) +#define str(s) #s + struct tcmu_mailbox { __u16 version; __u16 flags; @@ -64,31 +68,36 @@ enum tcmu_opcode { * Only a few opcodes, and length is 8-byte aligned, so use low bits for opcode. */ struct tcmu_cmd_entry_hdr { - __u32 len_op; + __u32 len_op; + __u16 cmd_id; + __u8 kflags; +#define TCMU_UFLAG_UNKNOWN_OP 0x1 + __u8 uflags; + } __packed; #define TCMU_OP_MASK 0x7 -static inline enum tcmu_opcode tcmu_hdr_get_op(struct tcmu_cmd_entry_hdr *hdr) +static inline enum tcmu_opcode tcmu_hdr_get_op(__u32 len_op) { - return hdr->len_op & TCMU_OP_MASK; + return len_op & TCMU_OP_MASK; } -static inline void tcmu_hdr_set_op(struct tcmu_cmd_entry_hdr *hdr, enum tcmu_opcode op) +static inline void tcmu_hdr_set_op(__u32 *len_op, enum tcmu_opcode op) { - hdr->len_op &= ~TCMU_OP_MASK; - hdr->len_op |= (op & TCMU_OP_MASK); + *len_op &= ~TCMU_OP_MASK; + *len_op |= (op & TCMU_OP_MASK); } -static inline __u32 tcmu_hdr_get_len(struct tcmu_cmd_entry_hdr *hdr) +static inline __u32 tcmu_hdr_get_len(__u32 len_op) { - return hdr->len_op & ~TCMU_OP_MASK; + return len_op & ~TCMU_OP_MASK; } -static inline void tcmu_hdr_set_len(struct tcmu_cmd_entry_hdr *hdr, __u32 len) +static inline void tcmu_hdr_set_len(__u32 *len_op, __u32 len) { - hdr->len_op &= TCMU_OP_MASK; - hdr->len_op |= len; + *len_op &= TCMU_OP_MASK; + *len_op |= len; } /* Currently the same as SCSI_SENSE_BUFFERSIZE */ @@ -97,13 +106,14 @@ static inline void tcmu_hdr_set_len(struct tcmu_cmd_entry_hdr *hdr, __u32 len) struct tcmu_cmd_entry { struct tcmu_cmd_entry_hdr hdr; - uint16_t cmd_id; - uint16_t __pad1; - union { struct { + uint32_t iov_cnt; + uint32_t iov_bidi_cnt; + uint32_t iov_dif_cnt; uint64_t cdb_off; - uint64_t iov_cnt; + uint64_t __pad1; + uint64_t __pad2; struct iovec iov[0]; } req; struct { -- cgit v1.2.3 From 3ef650d3989677bd460497f9c3b0d58caaba0116 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 23 Mar 2015 13:35:03 -0700 Subject: libceph: osdmap.h: Add missing format newlines To avoid possible interleaving, add missing '\n' to formats. Convert pr_warning to pr_warn while there. Signed-off-by: Joe Perches Signed-off-by: Ilya Dryomov --- include/linux/ceph/osdmap.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/ceph/osdmap.h b/include/linux/ceph/osdmap.h index 561ea896c657..e55c08bc3a96 100644 --- a/include/linux/ceph/osdmap.h +++ b/include/linux/ceph/osdmap.h @@ -175,13 +175,12 @@ static inline int ceph_decode_pgid(void **p, void *end, struct ceph_pg *pgid) __u8 version; if (!ceph_has_room(p, end, 1 + 8 + 4 + 4)) { - pr_warning("incomplete pg encoding"); - + pr_warn("incomplete pg encoding\n"); return -EINVAL; } version = ceph_decode_8(p); if (version > 1) { - pr_warning("do not understand pg encoding %d > 1", + pr_warn("do not understand pg encoding %d > 1\n", (int)version); return -EINVAL; } -- cgit v1.2.3 From ff40f9ae95917b72b6acb6057471c99054b6ee24 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Wed, 25 Mar 2015 21:02:16 +0300 Subject: libceph, ceph: split ceph_show_options() Split ceph_show_options() into two pieces and move the piece responsible for printing client (libceph) options into net/ceph. This way people adding a libceph option wouldn't have to remember to update code in fs/ceph. Signed-off-by: Ilya Dryomov --- fs/ceph/super.c | 40 +++++++++++++++------------------------- include/linux/ceph/libceph.h | 1 + net/ceph/ceph_common.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 9f035ccb6191..34a779edd421 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -411,31 +411,20 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) { struct ceph_fs_client *fsc = ceph_sb_to_client(root->d_sb); struct ceph_mount_options *fsopt = fsc->mount_options; - struct ceph_options *opt = fsc->client->options; - - if (opt->flags & CEPH_OPT_FSID) - seq_printf(m, ",fsid=%pU", &opt->fsid); - if (opt->flags & CEPH_OPT_NOSHARE) - seq_puts(m, ",noshare"); - if (opt->flags & CEPH_OPT_NOCRC) - seq_puts(m, ",nocrc"); - if (opt->flags & CEPH_OPT_NOMSGAUTH) - seq_puts(m, ",nocephx_require_signatures"); - if ((opt->flags & CEPH_OPT_TCP_NODELAY) == 0) - seq_puts(m, ",notcp_nodelay"); - - if (opt->name) - seq_printf(m, ",name=%s", opt->name); - if (opt->key) - seq_puts(m, ",secret="); - - if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT) - seq_printf(m, ",mount_timeout=%d", opt->mount_timeout); - if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT) - seq_printf(m, ",osd_idle_ttl=%d", opt->osd_idle_ttl); - if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT) - seq_printf(m, ",osdkeepalivetimeout=%d", - opt->osd_keepalive_timeout); + size_t pos; + int ret; + + /* a comma between MNT/MS and client options */ + seq_putc(m, ','); + pos = m->count; + + ret = ceph_print_client_options(m, fsc->client); + if (ret) + return ret; + + /* retract our comma if no client options */ + if (m->count == pos) + m->count--; if (fsopt->flags & CEPH_MOUNT_OPT_DIRSTAT) seq_puts(m, ",dirstat"); @@ -482,6 +471,7 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) seq_printf(m, ",readdir_max_bytes=%d", fsopt->max_readdir_bytes); if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT)) seq_printf(m, ",snapdirname=%s", fsopt->snapdir_name); + return 0; } diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index 16fff9608848..303be6ef7f94 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -191,6 +191,7 @@ extern struct ceph_options *ceph_parse_options(char *options, const char *dev_name, const char *dev_name_end, int (*parse_extra_token)(char *c, void *private), void *private); +int ceph_print_client_options(struct seq_file *m, struct ceph_client *client); extern void ceph_destroy_options(struct ceph_options *opt); extern int ceph_compare_options(struct ceph_options *new_opt, struct ceph_client *client); diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index ec565508e904..79e8f71aef5b 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -490,6 +490,43 @@ out: } EXPORT_SYMBOL(ceph_parse_options); +int ceph_print_client_options(struct seq_file *m, struct ceph_client *client) +{ + struct ceph_options *opt = client->options; + size_t pos = m->count; + + if (opt->name) + seq_printf(m, "name=%s,", opt->name); + if (opt->key) + seq_puts(m, "secret=,"); + + if (opt->flags & CEPH_OPT_FSID) + seq_printf(m, "fsid=%pU,", &opt->fsid); + if (opt->flags & CEPH_OPT_NOSHARE) + seq_puts(m, "noshare,"); + if (opt->flags & CEPH_OPT_NOCRC) + seq_puts(m, "nocrc,"); + if (opt->flags & CEPH_OPT_NOMSGAUTH) + seq_puts(m, "nocephx_require_signatures,"); + if ((opt->flags & CEPH_OPT_TCP_NODELAY) == 0) + seq_puts(m, "notcp_nodelay,"); + + if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT) + seq_printf(m, "mount_timeout=%d,", opt->mount_timeout); + if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT) + seq_printf(m, "osd_idle_ttl=%d,", opt->osd_idle_ttl); + if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT) + seq_printf(m, "osdkeepalivetimeout=%d,", + opt->osd_keepalive_timeout); + + /* drop redundant comma */ + if (m->count != pos) + m->count--; + + return 0; +} +EXPORT_SYMBOL(ceph_print_client_options); + u64 ceph_client_id(struct ceph_client *client) { return client->monc.auth->global_id; -- cgit v1.2.3 From 5cf7bd30120ead3db43ef9074be38018d9acf22f Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Wed, 25 Mar 2015 21:07:41 +0300 Subject: libceph: expose client options through debugfs Add a client_options attribute for showing libceph options. Signed-off-by: Ilya Dryomov --- include/linux/ceph/libceph.h | 1 + net/ceph/debugfs.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'include') diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index 303be6ef7f94..30f92cefaa72 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -135,6 +135,7 @@ struct ceph_client { struct dentry *debugfs_dir; struct dentry *debugfs_monmap; struct dentry *debugfs_osdmap; + struct dentry *debugfs_options; #endif }; diff --git a/net/ceph/debugfs.c b/net/ceph/debugfs.c index 14d9995097cc..593dc2eabcc8 100644 --- a/net/ceph/debugfs.c +++ b/net/ceph/debugfs.c @@ -22,6 +22,7 @@ * .../monmap - current monmap * .../osdc - active osd requests * .../monc - mon client state + * .../client_options - libceph-only (i.e. not rbd or cephfs) options * .../dentry_lru - dump contents of dentry lru * .../caps - expose cap (reservation) stats * .../bdi - symlink to ../../bdi/something @@ -177,10 +178,24 @@ static int osdc_show(struct seq_file *s, void *pp) return 0; } +static int client_options_show(struct seq_file *s, void *p) +{ + struct ceph_client *client = s->private; + int ret; + + ret = ceph_print_client_options(s, client); + if (ret) + return ret; + + seq_putc(s, '\n'); + return 0; +} + CEPH_DEFINE_SHOW_FUNC(monmap_show) CEPH_DEFINE_SHOW_FUNC(osdmap_show) CEPH_DEFINE_SHOW_FUNC(monc_show) CEPH_DEFINE_SHOW_FUNC(osdc_show) +CEPH_DEFINE_SHOW_FUNC(client_options_show) int ceph_debugfs_init(void) { @@ -242,6 +257,14 @@ int ceph_debugfs_client_init(struct ceph_client *client) if (!client->debugfs_osdmap) goto out; + client->debugfs_options = debugfs_create_file("client_options", + 0600, + client->debugfs_dir, + client, + &client_options_show_fops); + if (!client->debugfs_options) + goto out; + return 0; out: @@ -252,6 +275,7 @@ out: void ceph_debugfs_client_cleanup(struct ceph_client *client) { dout("ceph_debugfs_client_cleanup %p\n", client); + debugfs_remove(client->debugfs_options); debugfs_remove(client->debugfs_osdmap); debugfs_remove(client->debugfs_monmap); debugfs_remove(client->osdc.debugfs_file); -- cgit v1.2.3 From 9571eb4f9617e89b3f979a3856b1296eba277bb1 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Wed, 25 Mar 2015 21:15:17 +0300 Subject: libceph: simplify our debugfs attr macro No need to do single_open()'s job ourselves. Signed-off-by: Ilya Dryomov --- include/linux/ceph/debugfs.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/ceph/debugfs.h b/include/linux/ceph/debugfs.h index 1df086d7882d..29cf897cc5cd 100644 --- a/include/linux/ceph/debugfs.h +++ b/include/linux/ceph/debugfs.h @@ -7,13 +7,7 @@ #define CEPH_DEFINE_SHOW_FUNC(name) \ static int name##_open(struct inode *inode, struct file *file) \ { \ - struct seq_file *sf; \ - int ret; \ - \ - ret = single_open(file, name, NULL); \ - sf = file->private_data; \ - sf->private = inode->i_private; \ - return ret; \ + return single_open(file, name, inode->i_private); \ } \ \ static const struct file_operations name##_fops = { \ -- cgit v1.2.3 From f4d03bd143c628b00f66cc2ec2c013767bdd1518 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 20 Apr 2015 09:08:49 -0700 Subject: smp: don't use 16-bit words for atomic accesses Yes, it should work, but it's a bad idea. Not only did ARM64 not have the 16-bit access code (there's a separate patch to add it), it's just not a good atomic type. Some architectures fundamentally don't do atomic accesses in them (alpha), and it's not like it saves any space here anyway because of structure packing issues. We normally should aim for flags to be "unsigned int" or "unsigned long". And if space is at a premium, use a single byte (although that causes problems on alpha again). There might be very special cases where a 16-byte entity is really wanted, but this is not one of them. Signed-off-by: Linus Torvalds --- include/linux/smp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/smp.h b/include/linux/smp.h index be91db2a7017..c4414074bd88 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -18,7 +18,7 @@ struct call_single_data { struct llist_node llist; smp_call_func_t func; void *info; - u16 flags; + unsigned int flags; }; /* total number of cpus in this system (may exceed NR_CPUS) */ -- cgit v1.2.3 From 4e18b9adf2f910ec4d30b811a74a5b626e6c6125 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Mon, 20 Apr 2015 14:10:04 -0700 Subject: net: add skb_checksum_complete_unset This function changes ip_summed to CHECKSUM_NONE if CHECKSUM_COMPLETE is set. This is called to discard checksum-complete when packet is being modified and checksum is not pulled for headers in a layer. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/skbuff.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 0991259643d6..06793b598f44 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3016,6 +3016,18 @@ static inline bool __skb_checksum_validate_needed(struct sk_buff *skb, */ #define CHECKSUM_BREAK 76 +/* Unset checksum-complete + * + * Unset checksum complete can be done when packet is being modified + * (uncompressed for instance) and checksum-complete value is + * invalidated. + */ +static inline void skb_checksum_complete_unset(struct sk_buff *skb) +{ + if (skb->ip_summed == CHECKSUM_COMPLETE) + skb->ip_summed = CHECKSUM_NONE; +} + /* Validate (init) checksum based on checksum complete. * * Return values: -- cgit v1.2.3 From d8fbe341beb617ebb22b98fb893e4aa32ae2d864 Mon Sep 17 00:00:00 2001 From: Sumit Semwal Date: Fri, 23 Jan 2015 12:53:43 +0530 Subject: dma-buf: cleanup dma_buf_export() to make it easily extensible At present, dma_buf_export() takes a series of parameters, which makes it difficult to add any new parameters for exporters, if required. Make it simpler by moving all these parameters into a struct, and pass the struct * as parameter to dma_buf_export(). While at it, unite dma_buf_export_named() with dma_buf_export(), and change all callers accordingly. Reviewed-by: Maarten Lankhorst Reviewed-by: Daniel Thompson Acked-by: Mauro Carvalho Chehab Acked-by: Dave Airlie Signed-off-by: Sumit Semwal --- Documentation/dma-buf-sharing.txt | 23 +++++++------ drivers/dma-buf/dma-buf.c | 47 ++++++++++++-------------- drivers/gpu/drm/armada/armada_gem.c | 10 ++++-- drivers/gpu/drm/drm_prime.c | 12 ++++--- drivers/gpu/drm/exynos/exynos_drm_dmabuf.c | 9 +++-- drivers/gpu/drm/i915/i915_gem_dmabuf.c | 10 ++++-- drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c | 9 ++++- drivers/gpu/drm/tegra/gem.c | 10 ++++-- drivers/gpu/drm/ttm/ttm_object.c | 9 +++-- drivers/gpu/drm/udl/udl_dmabuf.c | 9 ++++- drivers/media/v4l2-core/videobuf2-dma-contig.c | 8 ++++- drivers/media/v4l2-core/videobuf2-dma-sg.c | 8 ++++- drivers/media/v4l2-core/videobuf2-vmalloc.c | 8 ++++- drivers/staging/android/ion/ion.c | 9 +++-- include/linux/dma-buf.h | 34 +++++++++++++++---- 15 files changed, 152 insertions(+), 63 deletions(-) (limited to 'include') diff --git a/Documentation/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt index bb9753b635a3..480c8de3c2c4 100644 --- a/Documentation/dma-buf-sharing.txt +++ b/Documentation/dma-buf-sharing.txt @@ -49,25 +49,26 @@ The dma_buf buffer sharing API usage contains the following steps: The buffer exporter announces its wish to export a buffer. In this, it connects its own private buffer data, provides implementation for operations that can be performed on the exported dma_buf, and flags for the file - associated with this buffer. + associated with this buffer. All these fields are filled in struct + dma_buf_export_info, defined via the DEFINE_DMA_BUF_EXPORT_INFO macro. Interface: - struct dma_buf *dma_buf_export_named(void *priv, struct dma_buf_ops *ops, - size_t size, int flags, - const char *exp_name) + DEFINE_DMA_BUF_EXPORT_INFO(exp_info) + struct dma_buf *dma_buf_export(struct dma_buf_export_info *exp_info) - If this succeeds, dma_buf_export_named allocates a dma_buf structure, and + If this succeeds, dma_buf_export allocates a dma_buf structure, and returns a pointer to the same. It also associates an anonymous file with this buffer, so it can be exported. On failure to allocate the dma_buf object, it returns NULL. - 'exp_name' is the name of exporter - to facilitate information while - debugging. + 'exp_name' in struct dma_buf_export_info is the name of exporter - to + facilitate information while debugging. It is set to KBUILD_MODNAME by + default, so exporters don't have to provide a specific name, if they don't + wish to. + + DEFINE_DMA_BUF_EXPORT_INFO macro defines the struct dma_buf_export_info, + zeroes it out and pre-populates exp_name in it. - Exporting modules which do not wish to provide any specific name may use the - helper define 'dma_buf_export()', with the same arguments as above, but - without the last argument; a KBUILD_MODNAME pre-processor directive will be - inserted in place of 'exp_name' instead. 2. Userspace gets a handle to pass around to potential buffer-users diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 5be225c2ba98..c5a9138a6a8d 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -265,43 +265,40 @@ static inline int is_dma_buf_file(struct file *file) } /** - * dma_buf_export_named - Creates a new dma_buf, and associates an anon file + * dma_buf_export - Creates a new dma_buf, and associates an anon file * with this buffer, so it can be exported. * Also connect the allocator specific data and ops to the buffer. * Additionally, provide a name string for exporter; useful in debugging. * - * @priv: [in] Attach private data of allocator to this buffer - * @ops: [in] Attach allocator-defined dma buf ops to the new buffer. - * @size: [in] Size of the buffer - * @flags: [in] mode flags for the file. - * @exp_name: [in] name of the exporting module - useful for debugging. - * @resv: [in] reservation-object, NULL to allocate default one. + * @exp_info: [in] holds all the export related information provided + * by the exporter. see struct dma_buf_export_info + * for further details. * * Returns, on success, a newly created dma_buf object, which wraps the * supplied private data and operations for dma_buf_ops. On either missing * ops, or error in allocating struct dma_buf, will return negative error. * */ -struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops, - size_t size, int flags, const char *exp_name, - struct reservation_object *resv) +struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) { struct dma_buf *dmabuf; + struct reservation_object *resv = exp_info->resv; struct file *file; size_t alloc_size = sizeof(struct dma_buf); - if (!resv) + if (!exp_info->resv) alloc_size += sizeof(struct reservation_object); else /* prevent &dma_buf[1] == dma_buf->resv */ alloc_size += 1; - if (WARN_ON(!priv || !ops - || !ops->map_dma_buf - || !ops->unmap_dma_buf - || !ops->release - || !ops->kmap_atomic - || !ops->kmap - || !ops->mmap)) { + if (WARN_ON(!exp_info->priv + || !exp_info->ops + || !exp_info->ops->map_dma_buf + || !exp_info->ops->unmap_dma_buf + || !exp_info->ops->release + || !exp_info->ops->kmap_atomic + || !exp_info->ops->kmap + || !exp_info->ops->mmap)) { return ERR_PTR(-EINVAL); } @@ -309,10 +306,10 @@ struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops, if (dmabuf == NULL) return ERR_PTR(-ENOMEM); - dmabuf->priv = priv; - dmabuf->ops = ops; - dmabuf->size = size; - dmabuf->exp_name = exp_name; + dmabuf->priv = exp_info->priv; + dmabuf->ops = exp_info->ops; + dmabuf->size = exp_info->size; + dmabuf->exp_name = exp_info->exp_name; init_waitqueue_head(&dmabuf->poll); dmabuf->cb_excl.poll = dmabuf->cb_shared.poll = &dmabuf->poll; dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0; @@ -323,7 +320,8 @@ struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops, } dmabuf->resv = resv; - file = anon_inode_getfile("dmabuf", &dma_buf_fops, dmabuf, flags); + file = anon_inode_getfile("dmabuf", &dma_buf_fops, dmabuf, + exp_info->flags); if (IS_ERR(file)) { kfree(dmabuf); return ERR_CAST(file); @@ -341,8 +339,7 @@ struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops, return dmabuf; } -EXPORT_SYMBOL_GPL(dma_buf_export_named); - +EXPORT_SYMBOL_GPL(dma_buf_export); /** * dma_buf_fd - returns a file descriptor for the given dma_buf diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c index ef5feeecec84..580e10acaa3a 100644 --- a/drivers/gpu/drm/armada/armada_gem.c +++ b/drivers/gpu/drm/armada/armada_gem.c @@ -538,8 +538,14 @@ struct dma_buf * armada_gem_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) { - return dma_buf_export(obj, &armada_gem_prime_dmabuf_ops, obj->size, - O_RDWR, NULL); + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &armada_gem_prime_dmabuf_ops; + exp_info.size = obj->size; + exp_info.flags = O_RDWR; + exp_info.priv = obj; + + return dma_buf_export(&exp_info); } struct drm_gem_object * diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 7482b06cd08f..7fec191b45f7 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -339,13 +339,17 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = { struct dma_buf *drm_gem_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) { - struct reservation_object *robj = NULL; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &drm_gem_prime_dmabuf_ops; + exp_info.size = obj->size; + exp_info.flags = flags; + exp_info.priv = obj; if (dev->driver->gem_prime_res_obj) - robj = dev->driver->gem_prime_res_obj(obj); + exp_info.resv = dev->driver->gem_prime_res_obj(obj); - return dma_buf_export(obj, &drm_gem_prime_dmabuf_ops, obj->size, - flags, robj); + return dma_buf_export(&exp_info); } EXPORT_SYMBOL(drm_gem_prime_export); diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c index 3833bf8ca025..cd485c091b30 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c @@ -185,9 +185,14 @@ struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev, struct drm_gem_object *obj, int flags) { struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); - return dma_buf_export(obj, &exynos_dmabuf_ops, - exynos_gem_obj->base.size, flags, NULL); + exp_info.ops = &exynos_dmabuf_ops; + exp_info.size = exynos_gem_obj->base.size; + exp_info.flags = flags; + exp_info.priv = obj; + + return dma_buf_export(&exp_info); } struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev, diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c index 82a1f4b57778..7998da27c500 100644 --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c @@ -230,6 +230,13 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev, struct drm_gem_object *gem_obj, int flags) { struct drm_i915_gem_object *obj = to_intel_bo(gem_obj); + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &i915_dmabuf_ops; + exp_info.size = gem_obj->size; + exp_info.flags = flags; + exp_info.priv = gem_obj; + if (obj->ops->dmabuf_export) { int ret = obj->ops->dmabuf_export(obj); @@ -237,8 +244,7 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev, return ERR_PTR(ret); } - return dma_buf_export(gem_obj, &i915_dmabuf_ops, gem_obj->size, flags, - NULL); + return dma_buf_export(&exp_info); } static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj) diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index b46dabd9faf7..344fd789170d 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -171,7 +171,14 @@ static struct dma_buf_ops omap_dmabuf_ops = { struct dma_buf *omap_gem_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) { - return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, flags, NULL); + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &omap_dmabuf_ops; + exp_info.size = obj->size; + exp_info.flags = flags; + exp_info.priv = obj; + + return dma_buf_export(&exp_info); } struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index cfb481943b6b..1217272a51f2 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -627,8 +627,14 @@ struct dma_buf *tegra_gem_prime_export(struct drm_device *drm, struct drm_gem_object *gem, int flags) { - return dma_buf_export(gem, &tegra_gem_prime_dmabuf_ops, gem->size, - flags, NULL); + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &tegra_gem_prime_dmabuf_ops; + exp_info.size = gem->size; + exp_info.flags = flags; + exp_info.priv = gem; + + return dma_buf_export(&exp_info); } struct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm, diff --git a/drivers/gpu/drm/ttm/ttm_object.c b/drivers/gpu/drm/ttm/ttm_object.c index 12c87110db3a..4f5fa8d65fe9 100644 --- a/drivers/gpu/drm/ttm/ttm_object.c +++ b/drivers/gpu/drm/ttm/ttm_object.c @@ -683,6 +683,12 @@ int ttm_prime_handle_to_fd(struct ttm_object_file *tfile, dma_buf = prime->dma_buf; if (!dma_buf || !get_dma_buf_unless_doomed(dma_buf)) { + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &tdev->ops; + exp_info.size = prime->size; + exp_info.flags = flags; + exp_info.priv = prime; /* * Need to create a new dma_buf, with memory accounting. @@ -694,8 +700,7 @@ int ttm_prime_handle_to_fd(struct ttm_object_file *tfile, goto out_unref; } - dma_buf = dma_buf_export(prime, &tdev->ops, - prime->size, flags, NULL); + dma_buf = dma_buf_export(&exp_info); if (IS_ERR(dma_buf)) { ret = PTR_ERR(dma_buf); ttm_mem_global_free(tdev->mem_glob, diff --git a/drivers/gpu/drm/udl/udl_dmabuf.c b/drivers/gpu/drm/udl/udl_dmabuf.c index ac8a66b4dfc2..e2243edd1ce3 100644 --- a/drivers/gpu/drm/udl/udl_dmabuf.c +++ b/drivers/gpu/drm/udl/udl_dmabuf.c @@ -202,7 +202,14 @@ static struct dma_buf_ops udl_dmabuf_ops = { struct dma_buf *udl_gem_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) { - return dma_buf_export(obj, &udl_dmabuf_ops, obj->size, flags, NULL); + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &udl_dmabuf_ops; + exp_info.size = obj->size; + exp_info.flags = flags; + exp_info.priv = obj; + + return dma_buf_export(&exp_info); } static int udl_prime_create(struct drm_device *dev, diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 69e0483adfee..644dec73d220 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -402,6 +402,12 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, unsigned long flags) { struct vb2_dc_buf *buf = buf_priv; struct dma_buf *dbuf; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &vb2_dc_dmabuf_ops; + exp_info.size = buf->size; + exp_info.flags = flags; + exp_info.priv = buf; if (!buf->sgt_base) buf->sgt_base = vb2_dc_get_base_sgt(buf); @@ -409,7 +415,7 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, unsigned long flags) if (WARN_ON(!buf->sgt_base)) return NULL; - dbuf = dma_buf_export(buf, &vb2_dc_dmabuf_ops, buf->size, flags, NULL); + dbuf = dma_buf_export(&exp_info); if (IS_ERR(dbuf)) return NULL; diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index b1838abb6d00..45c708e463b9 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c @@ -583,11 +583,17 @@ static struct dma_buf *vb2_dma_sg_get_dmabuf(void *buf_priv, unsigned long flags { struct vb2_dma_sg_buf *buf = buf_priv; struct dma_buf *dbuf; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &vb2_dma_sg_dmabuf_ops; + exp_info.size = buf->size; + exp_info.flags = flags; + exp_info.priv = buf; if (WARN_ON(!buf->dma_sgt)) return NULL; - dbuf = dma_buf_export(buf, &vb2_dma_sg_dmabuf_ops, buf->size, flags, NULL); + dbuf = dma_buf_export(&exp_info); if (IS_ERR(dbuf)) return NULL; diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index bcde88572429..657ab302a5cf 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -368,11 +368,17 @@ static struct dma_buf *vb2_vmalloc_get_dmabuf(void *buf_priv, unsigned long flag { struct vb2_vmalloc_buf *buf = buf_priv; struct dma_buf *dbuf; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &vb2_vmalloc_dmabuf_ops; + exp_info.size = buf->size; + exp_info.flags = flags; + exp_info.priv = buf; if (WARN_ON(!buf->vaddr)) return NULL; - dbuf = dma_buf_export(buf, &vb2_vmalloc_dmabuf_ops, buf->size, flags, NULL); + dbuf = dma_buf_export(&exp_info); if (IS_ERR(dbuf)) return NULL; diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 0e3d8c7add24..b94d69feff46 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1106,6 +1106,12 @@ struct dma_buf *ion_share_dma_buf(struct ion_client *client, struct ion_buffer *buffer; struct dma_buf *dmabuf; bool valid_handle; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &dma_buf_ops; + exp_info.size = buffer->size; + exp_info.flags = O_RDWR; + exp_info.priv = buffer; mutex_lock(&client->lock); valid_handle = ion_handle_validate(client, handle); @@ -1118,8 +1124,7 @@ struct dma_buf *ion_share_dma_buf(struct ion_client *client, ion_buffer_get(buffer); mutex_unlock(&client->lock); - dmabuf = dma_buf_export(buffer, &dma_buf_ops, buffer->size, O_RDWR, - NULL); + dmabuf = dma_buf_export(&exp_info); if (IS_ERR(dmabuf)) { ion_buffer_put(buffer); return dmabuf; diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 694e1fe1c4b4..2f0b431b73e0 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -162,6 +162,33 @@ struct dma_buf_attachment { void *priv; }; +/** + * struct dma_buf_export_info - holds information needed to export a dma_buf + * @exp_name: name of the exporting module - useful for debugging. + * @ops: Attach allocator-defined dma buf ops to the new buffer + * @size: Size of the buffer + * @flags: mode flags for the file + * @resv: reservation-object, NULL to allocate default one + * @priv: Attach private data of allocator to this buffer + * + * This structure holds the information required to export the buffer. Used + * with dma_buf_export() only. + */ +struct dma_buf_export_info { + const char *exp_name; + const struct dma_buf_ops *ops; + size_t size; + int flags; + struct reservation_object *resv; + void *priv; +}; + +/** + * helper macro for exporters; zeros and fills in most common values + */ +#define DEFINE_DMA_BUF_EXPORT_INFO(a) \ + struct dma_buf_export_info a = { .exp_name = KBUILD_MODNAME } + /** * get_dma_buf - convenience wrapper for get_file. * @dmabuf: [in] pointer to dma_buf @@ -181,12 +208,7 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *dmabuf_attach); -struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops, - size_t size, int flags, const char *, - struct reservation_object *); - -#define dma_buf_export(priv, ops, size, flags, resv) \ - dma_buf_export_named(priv, ops, size, flags, KBUILD_MODNAME, resv) +struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info); int dma_buf_fd(struct dma_buf *dmabuf, int flags); struct dma_buf *dma_buf_get(int fd); -- cgit v1.2.3 From e928e9cb3601ce240189bfea05b67ebd391c85ae Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 20 Mar 2015 20:39:41 +1100 Subject: KVM: PPC: Book3S HV: Add fast real-mode H_RANDOM implementation. Some PowerNV systems include a hardware random-number generator. This HWRNG is present on POWER7+ and POWER8 chips and is capable of generating one 64-bit random number every microsecond. The random numbers are produced by sampling a set of 64 unstable high-frequency oscillators and are almost completely entropic. PAPR defines an H_RANDOM hypercall which guests can use to obtain one 64-bit random sample from the HWRNG. This adds a real-mode implementation of the H_RANDOM hypercall. This hypercall was implemented in real mode because the latency of reading the HWRNG is generally small compared to the latency of a guest exit and entry for all the threads in the same virtual core. Userspace can detect the presence of the HWRNG and the H_RANDOM implementation by querying the KVM_CAP_PPC_HWRNG capability. The H_RANDOM hypercall implementation will only be invoked when the guest does an H_RANDOM hypercall if userspace first enables the in-kernel H_RANDOM implementation using the KVM_CAP_PPC_ENABLE_HCALL capability. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras Signed-off-by: Alexander Graf --- Documentation/virtual/kvm/api.txt | 17 +++++ arch/powerpc/include/asm/archrandom.h | 11 ++- arch/powerpc/include/asm/kvm_ppc.h | 2 + arch/powerpc/kvm/book3s_hv_builtin.c | 15 +++++ arch/powerpc/kvm/book3s_hv_rmhandlers.S | 115 ++++++++++++++++++++++++++++++++ arch/powerpc/kvm/powerpc.c | 3 + arch/powerpc/platforms/powernv/rng.c | 29 ++++++++ include/uapi/linux/kvm.h | 1 + 8 files changed, 191 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index bc9f6fe44e27..9fa2bf8c3f6f 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3573,3 +3573,20 @@ struct { @ar - access register number KVM handlers should exit to userspace with rc = -EREMOTE. + + +8. Other capabilities. +---------------------- + +This section lists capabilities that give information about other +features of the KVM implementation. + +8.1 KVM_CAP_PPC_HWRNG + +Architectures: ppc + +This capability, if KVM_CHECK_EXTENSION indicates that it is +available, means that that the kernel has an implementation of the +H_RANDOM hypercall backed by a hardware random-number generator. +If present, the kernel H_RANDOM handler can be enabled for guest use +with the KVM_CAP_PPC_ENABLE_HCALL capability. diff --git a/arch/powerpc/include/asm/archrandom.h b/arch/powerpc/include/asm/archrandom.h index bde531103638..0cc6eedc4780 100644 --- a/arch/powerpc/include/asm/archrandom.h +++ b/arch/powerpc/include/asm/archrandom.h @@ -30,8 +30,6 @@ static inline int arch_has_random(void) return !!ppc_md.get_random_long; } -int powernv_get_random_long(unsigned long *v); - static inline int arch_get_random_seed_long(unsigned long *v) { return 0; @@ -47,4 +45,13 @@ static inline int arch_has_random_seed(void) #endif /* CONFIG_ARCH_RANDOM */ +#ifdef CONFIG_PPC_POWERNV +int powernv_hwrng_present(void); +int powernv_get_random_long(unsigned long *v); +int powernv_get_random_real_mode(unsigned long *v); +#else +static inline int powernv_hwrng_present(void) { return 0; } +static inline int powernv_get_random_real_mode(unsigned long *v) { return 0; } +#endif + #endif /* _ASM_POWERPC_ARCHRANDOM_H */ diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 46bf652c9169..b8475daad884 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -302,6 +302,8 @@ static inline bool is_kvmppc_hv_enabled(struct kvm *kvm) return kvm->arch.kvm_ops == kvmppc_hv_ops; } +extern int kvmppc_hwrng_present(void); + /* * Cuts out inst bits with ordering according to spec. * That means the leftmost bit is zero. All given bits are included. diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c index 1f083ff8a61a..1954a1c4b1f9 100644 --- a/arch/powerpc/kvm/book3s_hv_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_builtin.c @@ -21,6 +21,7 @@ #include #include #include +#include #define KVM_CMA_CHUNK_ORDER 18 @@ -169,3 +170,17 @@ int kvmppc_hcall_impl_hv_realmode(unsigned long cmd) return 0; } EXPORT_SYMBOL_GPL(kvmppc_hcall_impl_hv_realmode); + +int kvmppc_hwrng_present(void) +{ + return powernv_hwrng_present(); +} +EXPORT_SYMBOL_GPL(kvmppc_hwrng_present); + +long kvmppc_h_random(struct kvm_vcpu *vcpu) +{ + if (powernv_get_random_real_mode(&vcpu->arch.gpr[4])) + return H_SUCCESS; + + return H_HARDWARE; +} diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 6cbf1630cb70..0814ca122fcd 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1839,6 +1839,121 @@ hcall_real_table: .long 0 /* 0x12c */ .long 0 /* 0x130 */ .long DOTSYM(kvmppc_h_set_xdabr) - hcall_real_table + .long 0 /* 0x138 */ + .long 0 /* 0x13c */ + .long 0 /* 0x140 */ + .long 0 /* 0x144 */ + .long 0 /* 0x148 */ + .long 0 /* 0x14c */ + .long 0 /* 0x150 */ + .long 0 /* 0x154 */ + .long 0 /* 0x158 */ + .long 0 /* 0x15c */ + .long 0 /* 0x160 */ + .long 0 /* 0x164 */ + .long 0 /* 0x168 */ + .long 0 /* 0x16c */ + .long 0 /* 0x170 */ + .long 0 /* 0x174 */ + .long 0 /* 0x178 */ + .long 0 /* 0x17c */ + .long 0 /* 0x180 */ + .long 0 /* 0x184 */ + .long 0 /* 0x188 */ + .long 0 /* 0x18c */ + .long 0 /* 0x190 */ + .long 0 /* 0x194 */ + .long 0 /* 0x198 */ + .long 0 /* 0x19c */ + .long 0 /* 0x1a0 */ + .long 0 /* 0x1a4 */ + .long 0 /* 0x1a8 */ + .long 0 /* 0x1ac */ + .long 0 /* 0x1b0 */ + .long 0 /* 0x1b4 */ + .long 0 /* 0x1b8 */ + .long 0 /* 0x1bc */ + .long 0 /* 0x1c0 */ + .long 0 /* 0x1c4 */ + .long 0 /* 0x1c8 */ + .long 0 /* 0x1cc */ + .long 0 /* 0x1d0 */ + .long 0 /* 0x1d4 */ + .long 0 /* 0x1d8 */ + .long 0 /* 0x1dc */ + .long 0 /* 0x1e0 */ + .long 0 /* 0x1e4 */ + .long 0 /* 0x1e8 */ + .long 0 /* 0x1ec */ + .long 0 /* 0x1f0 */ + .long 0 /* 0x1f4 */ + .long 0 /* 0x1f8 */ + .long 0 /* 0x1fc */ + .long 0 /* 0x200 */ + .long 0 /* 0x204 */ + .long 0 /* 0x208 */ + .long 0 /* 0x20c */ + .long 0 /* 0x210 */ + .long 0 /* 0x214 */ + .long 0 /* 0x218 */ + .long 0 /* 0x21c */ + .long 0 /* 0x220 */ + .long 0 /* 0x224 */ + .long 0 /* 0x228 */ + .long 0 /* 0x22c */ + .long 0 /* 0x230 */ + .long 0 /* 0x234 */ + .long 0 /* 0x238 */ + .long 0 /* 0x23c */ + .long 0 /* 0x240 */ + .long 0 /* 0x244 */ + .long 0 /* 0x248 */ + .long 0 /* 0x24c */ + .long 0 /* 0x250 */ + .long 0 /* 0x254 */ + .long 0 /* 0x258 */ + .long 0 /* 0x25c */ + .long 0 /* 0x260 */ + .long 0 /* 0x264 */ + .long 0 /* 0x268 */ + .long 0 /* 0x26c */ + .long 0 /* 0x270 */ + .long 0 /* 0x274 */ + .long 0 /* 0x278 */ + .long 0 /* 0x27c */ + .long 0 /* 0x280 */ + .long 0 /* 0x284 */ + .long 0 /* 0x288 */ + .long 0 /* 0x28c */ + .long 0 /* 0x290 */ + .long 0 /* 0x294 */ + .long 0 /* 0x298 */ + .long 0 /* 0x29c */ + .long 0 /* 0x2a0 */ + .long 0 /* 0x2a4 */ + .long 0 /* 0x2a8 */ + .long 0 /* 0x2ac */ + .long 0 /* 0x2b0 */ + .long 0 /* 0x2b4 */ + .long 0 /* 0x2b8 */ + .long 0 /* 0x2bc */ + .long 0 /* 0x2c0 */ + .long 0 /* 0x2c4 */ + .long 0 /* 0x2c8 */ + .long 0 /* 0x2cc */ + .long 0 /* 0x2d0 */ + .long 0 /* 0x2d4 */ + .long 0 /* 0x2d8 */ + .long 0 /* 0x2dc */ + .long 0 /* 0x2e0 */ + .long 0 /* 0x2e4 */ + .long 0 /* 0x2e8 */ + .long 0 /* 0x2ec */ + .long 0 /* 0x2f0 */ + .long 0 /* 0x2f4 */ + .long 0 /* 0x2f8 */ + .long 0 /* 0x2fc */ + .long DOTSYM(kvmppc_h_random) - hcall_real_table .globl hcall_real_table_end hcall_real_table_end: diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 24bfe401373e..55a4763d6d11 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -529,6 +529,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_PPC_RMA: r = 0; break; + case KVM_CAP_PPC_HWRNG: + r = kvmppc_hwrng_present(); + break; #endif case KVM_CAP_SYNC_MMU: #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE diff --git a/arch/powerpc/platforms/powernv/rng.c b/arch/powerpc/platforms/powernv/rng.c index 80db43944afe..6eb808ff637e 100644 --- a/arch/powerpc/platforms/powernv/rng.c +++ b/arch/powerpc/platforms/powernv/rng.c @@ -24,12 +24,22 @@ struct powernv_rng { void __iomem *regs; + void __iomem *regs_real; unsigned long mask; }; static DEFINE_PER_CPU(struct powernv_rng *, powernv_rng); +int powernv_hwrng_present(void) +{ + struct powernv_rng *rng; + + rng = get_cpu_var(powernv_rng); + put_cpu_var(rng); + return rng != NULL; +} + static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val) { unsigned long parity; @@ -46,6 +56,17 @@ static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val) return val; } +int powernv_get_random_real_mode(unsigned long *v) +{ + struct powernv_rng *rng; + + rng = raw_cpu_read(powernv_rng); + + *v = rng_whiten(rng, in_rm64(rng->regs_real)); + + return 1; +} + int powernv_get_random_long(unsigned long *v) { struct powernv_rng *rng; @@ -80,12 +101,20 @@ static __init void rng_init_per_cpu(struct powernv_rng *rng, static __init int rng_create(struct device_node *dn) { struct powernv_rng *rng; + struct resource res; unsigned long val; rng = kzalloc(sizeof(*rng), GFP_KERNEL); if (!rng) return -ENOMEM; + if (of_address_to_resource(dn, 0, &res)) { + kfree(rng); + return -ENXIO; + } + + rng->regs_real = (void __iomem *)res.start; + rng->regs = of_iomap(dn, 0); if (!rng->regs) { kfree(rng); diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index f574d7be7631..4b60056776d1 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -813,6 +813,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_MIPS_MSA 112 #define KVM_CAP_S390_INJECT_IRQ 113 #define KVM_CAP_S390_IRQ_STATE 114 +#define KVM_CAP_PPC_HWRNG 115 #ifdef KVM_CAP_IRQ_ROUTING -- cgit v1.2.3 From 135dd002c23054aaa056ea3162c1e0356905c195 Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Mon, 6 Apr 2015 09:46:00 -0400 Subject: nfsd: eliminate NFSD_DEBUG Commit f895b252d4edf ("sunrpc: eliminate RPC_DEBUG") introduced use of IS_ENABLED() in a uapi header which leads to a build failure for userspace apps trying to use : linux/nfsd/debug.h:18:15: error: missing binary operator before token "(" #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) ^ Since this was only used to define NFSD_DEBUG if CONFIG_SUNRPC_DEBUG is enabled, replace instances of NFSD_DEBUG with CONFIG_SUNRPC_DEBUG. Cc: stable@vger.kernel.org Fixes: f895b252d4edf "sunrpc: eliminate RPC_DEBUG" Signed-off-by: Mark Salter Reviewed-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/lockd/svcsubs.c | 2 +- fs/nfsd/nfs4state.c | 2 +- fs/nfsd/nfsd.h | 2 +- include/uapi/linux/nfsd/debug.h | 8 -------- 4 files changed, 3 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 665ef5a05183..a563ddbc19e6 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -31,7 +31,7 @@ static struct hlist_head nlm_files[FILE_NRHASH]; static DEFINE_MUTEX(nlm_file_mutex); -#ifdef NFSD_DEBUG +#ifdef CONFIG_SUNRPC_DEBUG static inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f) { u32 *fhp = (u32*)f->data; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index fd875b6107ba..693495551bb2 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1139,7 +1139,7 @@ hash_sessionid(struct nfs4_sessionid *sessionid) return sid->sequence % SESSION_HASH_SIZE; } -#ifdef NFSD_DEBUG +#ifdef CONFIG_SUNRPC_DEBUG static inline void dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) { diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 565c4da1a9eb..cf980523898b 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -24,7 +24,7 @@ #include "export.h" #undef ifdebug -#ifdef NFSD_DEBUG +#ifdef CONFIG_SUNRPC_DEBUG # define ifdebug(flag) if (nfsd_debug & NFSDDBG_##flag) #else # define ifdebug(flag) if (0) diff --git a/include/uapi/linux/nfsd/debug.h b/include/uapi/linux/nfsd/debug.h index 0bf130a1c58d..28ec6c9c421a 100644 --- a/include/uapi/linux/nfsd/debug.h +++ b/include/uapi/linux/nfsd/debug.h @@ -11,14 +11,6 @@ #include -/* - * Enable debugging for nfsd. - * Requires RPC_DEBUG. - */ -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) -# define NFSD_DEBUG 1 -#endif - /* * knfsd debug flags */ -- cgit v1.2.3 From bff175238a2416110e2258989c462234baeb5f46 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 27 Mar 2015 17:50:00 +0100 Subject: uapi: Remove kernel internal declaration The enum nfs4_acl_whotype is only used in nfs4d's internal nfs4 acl representation. No longer expose it to user space. Signed-off-by: Andreas Gruenbacher Signed-off-by: J. Bruce Fields --- include/linux/nfs4.h | 7 +++++++ include/uapi/linux/nfs4.h | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index ed43cb74b11d..32201c269890 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -16,6 +16,13 @@ #include #include +enum nfs4_acl_whotype { + NFS4_ACL_WHO_NAMED = 0, + NFS4_ACL_WHO_OWNER, + NFS4_ACL_WHO_GROUP, + NFS4_ACL_WHO_EVERYONE, +}; + struct nfs4_ace { uint32_t type; uint32_t flag; diff --git a/include/uapi/linux/nfs4.h b/include/uapi/linux/nfs4.h index 35f5f4c6c260..adc0aff83fbb 100644 --- a/include/uapi/linux/nfs4.h +++ b/include/uapi/linux/nfs4.h @@ -162,13 +162,6 @@ */ #define NFS4_MAX_BACK_CHANNEL_OPS 2 -enum nfs4_acl_whotype { - NFS4_ACL_WHO_NAMED = 0, - NFS4_ACL_WHO_OWNER, - NFS4_ACL_WHO_GROUP, - NFS4_ACL_WHO_EVERYONE, -}; - #endif /* _UAPI_LINUX_NFS4_H */ /* -- cgit v1.2.3 From fe5cbc6e06c7d8b3a86f6f5491d74766bb5c2827 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Mon, 15 Dec 2014 12:57:04 +1100 Subject: md/raid6 algorithms: delta syndrome functions v3: s-o-b comment, explanation of performance and descision for the start/stop implementation Implementing rmw functionality for RAID6 requires optimized syndrome calculation. Up to now we can only generate a complete syndrome. The target P/Q pages are always overwritten. With this patch we provide a framework for inplace P/Q modification. In the first place simply fill those functions with NULL values. xor_syndrome() has two additional parameters: start & stop. These will indicate the first and last page that are changing during a rmw run. That makes it possible to avoid several unneccessary loops and speed up calculation. The caller needs to implement the following logic to make the functions work. 1) xor_syndrome(disks, start, stop, ...): "Remove" all data of source blocks inside P/Q between (and including) start and end. 2) modify any block with start <= block <= stop 3) xor_syndrome(disks, start, stop, ...): "Reinsert" all data of source blocks into P/Q between (and including) start and end. Pages between start and stop that won't be changed should be filled with a pointer to the kernel zero page. The reasons for not taking NULL pages are: 1) Algorithms cross the whole source data line by line. Thus avoid additional branches. 2) Having a NULL page avoids calculating the XOR P parity but still need calulation steps for the Q parity. Depending on the algorithm unrolling that might be only a difference of 2 instructions per loop. The benchmark numbers of the gen_syndrome() functions are displayed in the kernel log. Do the same for the xor_syndrome() functions. This will help to analyze performance problems and give an rough estimate how well the algorithm works. The choice of the fastest algorithm will still depend on the gen_syndrome() performance. With the start/stop page implementation the speed can vary a lot in real life. E.g. a change of page 0 & page 15 on a stripe will be harder to compute than the case where page 0 & page 1 are XOR candidates. To be not to enthusiatic about the expected speeds we will run a worse case test that simulates a change on the upper half of the stripe. So we do: 1) calculation of P/Q for the upper pages 2) continuation of Q for the lower (empty) pages Signed-off-by: Markus Stockhausen Signed-off-by: NeilBrown --- include/linux/raid/pq.h | 1 + lib/raid6/algos.c | 41 ++++++++++++++++++++++++++++++++++------- lib/raid6/altivec.uc | 1 + lib/raid6/avx2.c | 3 +++ lib/raid6/int.uc | 3 ++- lib/raid6/mmx.c | 2 ++ lib/raid6/neon.c | 1 + lib/raid6/sse1.c | 2 ++ lib/raid6/sse2.c | 3 +++ lib/raid6/tilegx.uc | 1 + 10 files changed, 50 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h index 73069cb6c54a..a7a06d1dcf9c 100644 --- a/include/linux/raid/pq.h +++ b/include/linux/raid/pq.h @@ -72,6 +72,7 @@ extern const char raid6_empty_zero_page[PAGE_SIZE]; /* Routine choices */ struct raid6_calls { void (*gen_syndrome)(int, size_t, void **); + void (*xor_syndrome)(int, int, int, size_t, void **); int (*valid)(void); /* Returns 1 if this routine set is usable */ const char *name; /* Name of this routine set */ int prefer; /* Has special performance attribute */ diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c index dbef2314901e..975c6e0434bd 100644 --- a/lib/raid6/algos.c +++ b/lib/raid6/algos.c @@ -131,11 +131,12 @@ static inline const struct raid6_recov_calls *raid6_choose_recov(void) static inline const struct raid6_calls *raid6_choose_gen( void *(*const dptrs)[(65536/PAGE_SIZE)+2], const int disks) { - unsigned long perf, bestperf, j0, j1; + unsigned long perf, bestgenperf, bestxorperf, j0, j1; + int start = (disks>>1)-1, stop = disks-3; /* work on the second half of the disks */ const struct raid6_calls *const *algo; const struct raid6_calls *best; - for (bestperf = 0, best = NULL, algo = raid6_algos; *algo; algo++) { + for (bestgenperf = 0, bestxorperf = 0, best = NULL, algo = raid6_algos; *algo; algo++) { if (!best || (*algo)->prefer >= best->prefer) { if ((*algo)->valid && !(*algo)->valid()) continue; @@ -153,19 +154,45 @@ static inline const struct raid6_calls *raid6_choose_gen( } preempt_enable(); - if (perf > bestperf) { - bestperf = perf; + if (perf > bestgenperf) { + bestgenperf = perf; best = *algo; } - pr_info("raid6: %-8s %5ld MB/s\n", (*algo)->name, + pr_info("raid6: %-8s gen() %5ld MB/s\n", (*algo)->name, (perf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2)); + + if (!(*algo)->xor_syndrome) + continue; + + perf = 0; + + preempt_disable(); + j0 = jiffies; + while ((j1 = jiffies) == j0) + cpu_relax(); + while (time_before(jiffies, + j1 + (1<xor_syndrome(disks, start, stop, + PAGE_SIZE, *dptrs); + perf++; + } + preempt_enable(); + + if (best == *algo) + bestxorperf = perf; + + pr_info("raid6: %-8s xor() %5ld MB/s\n", (*algo)->name, + (perf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2+1)); } } if (best) { - pr_info("raid6: using algorithm %s (%ld MB/s)\n", + pr_info("raid6: using algorithm %s gen() %ld MB/s\n", best->name, - (bestperf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2)); + (bestgenperf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2)); + if (best->xor_syndrome) + pr_info("raid6: .... xor() %ld MB/s, rmw enabled\n", + (bestxorperf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2+1)); raid6_call = *best; } else pr_err("raid6: Yikes! No algorithm found!\n"); diff --git a/lib/raid6/altivec.uc b/lib/raid6/altivec.uc index 7cc12b532e95..bec27fce7501 100644 --- a/lib/raid6/altivec.uc +++ b/lib/raid6/altivec.uc @@ -119,6 +119,7 @@ int raid6_have_altivec(void) const struct raid6_calls raid6_altivec$# = { raid6_altivec$#_gen_syndrome, + NULL, /* XOR not yet implemented */ raid6_have_altivec, "altivecx$#", 0 diff --git a/lib/raid6/avx2.c b/lib/raid6/avx2.c index bc3b1dd436eb..76734004358d 100644 --- a/lib/raid6/avx2.c +++ b/lib/raid6/avx2.c @@ -89,6 +89,7 @@ static void raid6_avx21_gen_syndrome(int disks, size_t bytes, void **ptrs) const struct raid6_calls raid6_avx2x1 = { raid6_avx21_gen_syndrome, + NULL, /* XOR not yet implemented */ raid6_have_avx2, "avx2x1", 1 /* Has cache hints */ @@ -150,6 +151,7 @@ static void raid6_avx22_gen_syndrome(int disks, size_t bytes, void **ptrs) const struct raid6_calls raid6_avx2x2 = { raid6_avx22_gen_syndrome, + NULL, /* XOR not yet implemented */ raid6_have_avx2, "avx2x2", 1 /* Has cache hints */ @@ -242,6 +244,7 @@ static void raid6_avx24_gen_syndrome(int disks, size_t bytes, void **ptrs) const struct raid6_calls raid6_avx2x4 = { raid6_avx24_gen_syndrome, + NULL, /* XOR not yet implemented */ raid6_have_avx2, "avx2x4", 1 /* Has cache hints */ diff --git a/lib/raid6/int.uc b/lib/raid6/int.uc index 5b50f8dfc5d2..5ca60bee1388 100644 --- a/lib/raid6/int.uc +++ b/lib/raid6/int.uc @@ -109,7 +109,8 @@ static void raid6_int$#_gen_syndrome(int disks, size_t bytes, void **ptrs) const struct raid6_calls raid6_intx$# = { raid6_int$#_gen_syndrome, - NULL, /* always valid */ + NULL, /* XOR not yet implemented */ + NULL, /* always valid */ "int" NSTRING "x$#", 0 }; diff --git a/lib/raid6/mmx.c b/lib/raid6/mmx.c index 590c71c9e200..b3b0e1fcd3af 100644 --- a/lib/raid6/mmx.c +++ b/lib/raid6/mmx.c @@ -76,6 +76,7 @@ static void raid6_mmx1_gen_syndrome(int disks, size_t bytes, void **ptrs) const struct raid6_calls raid6_mmxx1 = { raid6_mmx1_gen_syndrome, + NULL, /* XOR not yet implemented */ raid6_have_mmx, "mmxx1", 0 @@ -134,6 +135,7 @@ static void raid6_mmx2_gen_syndrome(int disks, size_t bytes, void **ptrs) const struct raid6_calls raid6_mmxx2 = { raid6_mmx2_gen_syndrome, + NULL, /* XOR not yet implemented */ raid6_have_mmx, "mmxx2", 0 diff --git a/lib/raid6/neon.c b/lib/raid6/neon.c index 36ad4705df1a..d9ad6ee284f4 100644 --- a/lib/raid6/neon.c +++ b/lib/raid6/neon.c @@ -42,6 +42,7 @@ } \ struct raid6_calls const raid6_neonx ## _n = { \ raid6_neon ## _n ## _gen_syndrome, \ + NULL, /* XOR not yet implemented */ \ raid6_have_neon, \ "neonx" #_n, \ 0 \ diff --git a/lib/raid6/sse1.c b/lib/raid6/sse1.c index f76297139445..9025b8ca9aa3 100644 --- a/lib/raid6/sse1.c +++ b/lib/raid6/sse1.c @@ -92,6 +92,7 @@ static void raid6_sse11_gen_syndrome(int disks, size_t bytes, void **ptrs) const struct raid6_calls raid6_sse1x1 = { raid6_sse11_gen_syndrome, + NULL, /* XOR not yet implemented */ raid6_have_sse1_or_mmxext, "sse1x1", 1 /* Has cache hints */ @@ -154,6 +155,7 @@ static void raid6_sse12_gen_syndrome(int disks, size_t bytes, void **ptrs) const struct raid6_calls raid6_sse1x2 = { raid6_sse12_gen_syndrome, + NULL, /* XOR not yet implemented */ raid6_have_sse1_or_mmxext, "sse1x2", 1 /* Has cache hints */ diff --git a/lib/raid6/sse2.c b/lib/raid6/sse2.c index 85b82c85f28e..31acd59a0ef7 100644 --- a/lib/raid6/sse2.c +++ b/lib/raid6/sse2.c @@ -90,6 +90,7 @@ static void raid6_sse21_gen_syndrome(int disks, size_t bytes, void **ptrs) const struct raid6_calls raid6_sse2x1 = { raid6_sse21_gen_syndrome, + NULL, /* XOR not yet implemented */ raid6_have_sse2, "sse2x1", 1 /* Has cache hints */ @@ -152,6 +153,7 @@ static void raid6_sse22_gen_syndrome(int disks, size_t bytes, void **ptrs) const struct raid6_calls raid6_sse2x2 = { raid6_sse22_gen_syndrome, + NULL, /* XOR not yet implemented */ raid6_have_sse2, "sse2x2", 1 /* Has cache hints */ @@ -250,6 +252,7 @@ static void raid6_sse24_gen_syndrome(int disks, size_t bytes, void **ptrs) const struct raid6_calls raid6_sse2x4 = { raid6_sse24_gen_syndrome, + NULL, /* XOR not yet implemented */ raid6_have_sse2, "sse2x4", 1 /* Has cache hints */ diff --git a/lib/raid6/tilegx.uc b/lib/raid6/tilegx.uc index e7c29459cbcd..2dd291a11264 100644 --- a/lib/raid6/tilegx.uc +++ b/lib/raid6/tilegx.uc @@ -80,6 +80,7 @@ void raid6_tilegx$#_gen_syndrome(int disks, size_t bytes, void **ptrs) const struct raid6_calls raid6_tilegx$# = { raid6_tilegx$#_gen_syndrome, + NULL, /* XOR not yet implemented */ NULL, "tilegx$#", 0 -- cgit v1.2.3 From 584acdd49cd2472ca0f5a06adbe979db82d0b4af Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Mon, 15 Dec 2014 12:57:05 +1100 Subject: md/raid5: activate raid6 rmw feature Glue it altogehter. The raid6 rmw path should work the same as the already existing raid5 logic. So emulate the prexor handling/flags and split functions as needed. 1) Enable xor_syndrome() in the async layer. 2) Split ops_run_prexor() into RAID4/5 and RAID6 logic. Xor the syndrome at the start of a rmw run as we did it before for the single parity. 3) Take care of rmw run in ops_run_reconstruct6(). Again process only the changed pages to get syndrome back into sync. 4) Enhance set_syndrome_sources() to fill NULL pages if we are in a rmw run. The lower layers will calculate start & end pages from that and call the xor_syndrome() correspondingly. 5) Adapt the several places where we ignored Q handling up to now. Performance numbers for a single E5630 system with a mix of 10 7200k desktop/server disks. 300 seconds random write with 8 threads onto a 3,2TB (10*400GB) RAID6 64K chunk without spare (group_thread_cnt=4) bsize rmw_level=1 rmw_level=0 rmw_level=1 rmw_level=0 skip_copy=1 skip_copy=1 skip_copy=0 skip_copy=0 4K 115 KB/s 141 KB/s 165 KB/s 140 KB/s 8K 225 KB/s 275 KB/s 324 KB/s 274 KB/s 16K 434 KB/s 536 KB/s 640 KB/s 534 KB/s 32K 751 KB/s 1,051 KB/s 1,234 KB/s 1,045 KB/s 64K 1,339 KB/s 1,958 KB/s 2,282 KB/s 1,962 KB/s 128K 2,673 KB/s 3,862 KB/s 4,113 KB/s 3,898 KB/s 256K 7,685 KB/s 7,539 KB/s 7,557 KB/s 7,638 KB/s 512K 19,556 KB/s 19,558 KB/s 19,652 KB/s 19,688 Kb/s Signed-off-by: Markus Stockhausen Signed-off-by: NeilBrown --- crypto/async_tx/async_pq.c | 19 +++++++-- drivers/md/raid5.c | 104 +++++++++++++++++++++++++++++++++------------ drivers/md/raid5.h | 19 ++++++++- include/linux/async_tx.h | 3 ++ 4 files changed, 115 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c index d05327caf69d..5d355e0c2633 100644 --- a/crypto/async_tx/async_pq.c +++ b/crypto/async_tx/async_pq.c @@ -124,6 +124,7 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks, { void **srcs; int i; + int start = -1, stop = disks - 3; if (submit->scribble) srcs = submit->scribble; @@ -134,10 +135,21 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks, if (blocks[i] == NULL) { BUG_ON(i > disks - 3); /* P or Q can't be zero */ srcs[i] = (void*)raid6_empty_zero_page; - } else + } else { srcs[i] = page_address(blocks[i]) + offset; + if (i < disks - 2) { + stop = i; + if (start == -1) + start = i; + } + } } - raid6_call.gen_syndrome(disks, len, srcs); + if (submit->flags & ASYNC_TX_PQ_XOR_DST) { + BUG_ON(!raid6_call.xor_syndrome); + if (start >= 0) + raid6_call.xor_syndrome(disks, start, stop, len, srcs); + } else + raid6_call.gen_syndrome(disks, len, srcs); async_tx_sync_epilog(submit); } @@ -178,7 +190,8 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks, if (device) unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOIO); - if (unmap && + /* XORing P/Q is only implemented in software */ + if (unmap && !(submit->flags & ASYNC_TX_PQ_XOR_DST) && (src_cnt <= dma_maxpq(device, 0) || dma_maxpq(device, DMA_PREP_CONTINUE) > 0) && is_dma_pq_aligned(device, offset, 0, len)) { diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 3ae097d50b51..c82ce1fd8723 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1317,7 +1317,9 @@ ops_run_compute5(struct stripe_head *sh, struct raid5_percpu *percpu) * destination buffer is recorded in srcs[count] and the Q destination * is recorded in srcs[count+1]]. */ -static int set_syndrome_sources(struct page **srcs, struct stripe_head *sh) +static int set_syndrome_sources(struct page **srcs, + struct stripe_head *sh, + int srctype) { int disks = sh->disks; int syndrome_disks = sh->ddf_layout ? disks : (disks - 2); @@ -1332,8 +1334,15 @@ static int set_syndrome_sources(struct page **srcs, struct stripe_head *sh) i = d0_idx; do { int slot = raid6_idx_to_slot(i, sh, &count, syndrome_disks); + struct r5dev *dev = &sh->dev[i]; - srcs[slot] = sh->dev[i].page; + if (i == sh->qd_idx || i == sh->pd_idx || + (srctype == SYNDROME_SRC_ALL) || + (srctype == SYNDROME_SRC_WANT_DRAIN && + test_bit(R5_Wantdrain, &dev->flags)) || + (srctype == SYNDROME_SRC_WRITTEN && + dev->written)) + srcs[slot] = sh->dev[i].page; i = raid6_next_disk(i, disks); } while (i != d0_idx); @@ -1373,7 +1382,7 @@ ops_run_compute6_1(struct stripe_head *sh, struct raid5_percpu *percpu) atomic_inc(&sh->count); if (target == qd_idx) { - count = set_syndrome_sources(blocks, sh); + count = set_syndrome_sources(blocks, sh, SYNDROME_SRC_ALL); blocks[count] = NULL; /* regenerating p is not necessary */ BUG_ON(blocks[count+1] != dest); /* q should already be set */ init_async_submit(&submit, ASYNC_TX_FENCE, NULL, @@ -1481,7 +1490,7 @@ ops_run_compute6_2(struct stripe_head *sh, struct raid5_percpu *percpu) tx = async_xor(dest, blocks, 0, count, STRIPE_SIZE, &submit); - count = set_syndrome_sources(blocks, sh); + count = set_syndrome_sources(blocks, sh, SYNDROME_SRC_ALL); init_async_submit(&submit, ASYNC_TX_FENCE, tx, ops_complete_compute, sh, to_addr_conv(sh, percpu, 0)); @@ -1515,8 +1524,8 @@ static void ops_complete_prexor(void *stripe_head_ref) } static struct dma_async_tx_descriptor * -ops_run_prexor(struct stripe_head *sh, struct raid5_percpu *percpu, - struct dma_async_tx_descriptor *tx) +ops_run_prexor5(struct stripe_head *sh, struct raid5_percpu *percpu, + struct dma_async_tx_descriptor *tx) { int disks = sh->disks; struct page **xor_srcs = to_addr_page(percpu, 0); @@ -1544,6 +1553,26 @@ ops_run_prexor(struct stripe_head *sh, struct raid5_percpu *percpu, return tx; } +static struct dma_async_tx_descriptor * +ops_run_prexor6(struct stripe_head *sh, struct raid5_percpu *percpu, + struct dma_async_tx_descriptor *tx) +{ + struct page **blocks = to_addr_page(percpu, 0); + int count; + struct async_submit_ctl submit; + + pr_debug("%s: stripe %llu\n", __func__, + (unsigned long long)sh->sector); + + count = set_syndrome_sources(blocks, sh, SYNDROME_SRC_WANT_DRAIN); + + init_async_submit(&submit, ASYNC_TX_FENCE|ASYNC_TX_PQ_XOR_DST, tx, + ops_complete_prexor, sh, to_addr_conv(sh, percpu, 0)); + tx = async_gen_syndrome(blocks, 0, count+2, STRIPE_SIZE, &submit); + + return tx; +} + static struct dma_async_tx_descriptor * ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx) { @@ -1746,6 +1775,8 @@ ops_run_reconstruct6(struct stripe_head *sh, struct raid5_percpu *percpu, int count, i, j = 0; struct stripe_head *head_sh = sh; int last_stripe; + int synflags; + unsigned long txflags; pr_debug("%s: stripe %llu\n", __func__, (unsigned long long)sh->sector); @@ -1765,14 +1796,23 @@ ops_run_reconstruct6(struct stripe_head *sh, struct raid5_percpu *percpu, again: blocks = to_addr_page(percpu, j); - count = set_syndrome_sources(blocks, sh); + + if (sh->reconstruct_state == reconstruct_state_prexor_drain_run) { + synflags = SYNDROME_SRC_WRITTEN; + txflags = ASYNC_TX_ACK | ASYNC_TX_PQ_XOR_DST; + } else { + synflags = SYNDROME_SRC_ALL; + txflags = ASYNC_TX_ACK; + } + + count = set_syndrome_sources(blocks, sh, synflags); last_stripe = !head_sh->batch_head || list_first_entry(&sh->batch_list, struct stripe_head, batch_list) == head_sh; if (last_stripe) { atomic_inc(&head_sh->count); - init_async_submit(&submit, ASYNC_TX_ACK, tx, ops_complete_reconstruct, + init_async_submit(&submit, txflags, tx, ops_complete_reconstruct, head_sh, to_addr_conv(sh, percpu, j)); } else init_async_submit(&submit, 0, tx, NULL, NULL, @@ -1843,7 +1883,7 @@ static void ops_run_check_pq(struct stripe_head *sh, struct raid5_percpu *percpu (unsigned long long)sh->sector, checkp); BUG_ON(sh->batch_head); - count = set_syndrome_sources(srcs, sh); + count = set_syndrome_sources(srcs, sh, SYNDROME_SRC_ALL); if (!checkp) srcs[count] = NULL; @@ -1884,8 +1924,12 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) async_tx_ack(tx); } - if (test_bit(STRIPE_OP_PREXOR, &ops_request)) - tx = ops_run_prexor(sh, percpu, tx); + if (test_bit(STRIPE_OP_PREXOR, &ops_request)) { + if (level < 6) + tx = ops_run_prexor5(sh, percpu, tx); + else + tx = ops_run_prexor6(sh, percpu, tx); + } if (test_bit(STRIPE_OP_BIODRAIN, &ops_request)) { tx = ops_run_biodrain(sh, tx); @@ -2770,7 +2814,7 @@ static void schedule_reconstruction(struct stripe_head *sh, struct stripe_head_state *s, int rcw, int expand) { - int i, pd_idx = sh->pd_idx, disks = sh->disks; + int i, pd_idx = sh->pd_idx, qd_idx = sh->qd_idx, disks = sh->disks; struct r5conf *conf = sh->raid_conf; int level = conf->level; @@ -2806,13 +2850,15 @@ schedule_reconstruction(struct stripe_head *sh, struct stripe_head_state *s, if (!test_and_set_bit(STRIPE_FULL_WRITE, &sh->state)) atomic_inc(&conf->pending_full_writes); } else { - BUG_ON(level == 6); BUG_ON(!(test_bit(R5_UPTODATE, &sh->dev[pd_idx].flags) || test_bit(R5_Wantcompute, &sh->dev[pd_idx].flags))); + BUG_ON(level == 6 && + (!(test_bit(R5_UPTODATE, &sh->dev[qd_idx].flags) || + test_bit(R5_Wantcompute, &sh->dev[qd_idx].flags)))); for (i = disks; i--; ) { struct r5dev *dev = &sh->dev[i]; - if (i == pd_idx) + if (i == pd_idx || i == qd_idx) continue; if (dev->towrite && @@ -3476,28 +3522,27 @@ static void handle_stripe_dirtying(struct r5conf *conf, int rmw = 0, rcw = 0, i; sector_t recovery_cp = conf->mddev->recovery_cp; - /* RAID6 requires 'rcw' in current implementation. - * Otherwise, check whether resync is now happening or should start. + /* Check whether resync is now happening or should start. * If yes, then the array is dirty (after unclean shutdown or * initial creation), so parity in some stripes might be inconsistent. * In this case, we need to always do reconstruct-write, to ensure * that in case of drive failure or read-error correction, we * generate correct data from the parity. */ - if (conf->max_degraded == 2 || + if (conf->rmw_level == PARITY_DISABLE_RMW || (recovery_cp < MaxSector && sh->sector >= recovery_cp && s->failed == 0)) { /* Calculate the real rcw later - for now make it * look like rcw is cheaper */ rcw = 1; rmw = 2; - pr_debug("force RCW max_degraded=%u, recovery_cp=%llu sh->sector=%llu\n", - conf->max_degraded, (unsigned long long)recovery_cp, + pr_debug("force RCW rmw_level=%u, recovery_cp=%llu sh->sector=%llu\n", + conf->rmw_level, (unsigned long long)recovery_cp, (unsigned long long)sh->sector); } else for (i = disks; i--; ) { /* would I have to read this buffer for read_modify_write */ struct r5dev *dev = &sh->dev[i]; - if ((dev->towrite || i == sh->pd_idx) && + if ((dev->towrite || i == sh->pd_idx || i == sh->qd_idx) && !test_bit(R5_LOCKED, &dev->flags) && !(test_bit(R5_UPTODATE, &dev->flags) || test_bit(R5_Wantcompute, &dev->flags))) { @@ -3507,7 +3552,8 @@ static void handle_stripe_dirtying(struct r5conf *conf, rmw += 2*disks; /* cannot read it */ } /* Would I have to read this buffer for reconstruct_write */ - if (!test_bit(R5_OVERWRITE, &dev->flags) && i != sh->pd_idx && + if (!test_bit(R5_OVERWRITE, &dev->flags) && + i != sh->pd_idx && i != sh->qd_idx && !test_bit(R5_LOCKED, &dev->flags) && !(test_bit(R5_UPTODATE, &dev->flags) || test_bit(R5_Wantcompute, &dev->flags))) { @@ -3520,7 +3566,7 @@ static void handle_stripe_dirtying(struct r5conf *conf, pr_debug("for sector %llu, rmw=%d rcw=%d\n", (unsigned long long)sh->sector, rmw, rcw); set_bit(STRIPE_HANDLE, &sh->state); - if (rmw < rcw && rmw > 0) { + if ((rmw < rcw || (rmw == rcw && conf->rmw_level == PARITY_ENABLE_RMW)) && rmw > 0) { /* prefer read-modify-write, but need to get some data */ if (conf->mddev->queue) blk_add_trace_msg(conf->mddev->queue, @@ -3528,7 +3574,7 @@ static void handle_stripe_dirtying(struct r5conf *conf, (unsigned long long)sh->sector, rmw); for (i = disks; i--; ) { struct r5dev *dev = &sh->dev[i]; - if ((dev->towrite || i == sh->pd_idx) && + if ((dev->towrite || i == sh->pd_idx || i == sh->qd_idx) && !test_bit(R5_LOCKED, &dev->flags) && !(test_bit(R5_UPTODATE, &dev->flags) || test_bit(R5_Wantcompute, &dev->flags)) && @@ -3547,7 +3593,7 @@ static void handle_stripe_dirtying(struct r5conf *conf, } } } - if (rcw <= rmw && rcw > 0) { + if ((rcw < rmw || (rcw == rmw && conf->rmw_level != PARITY_ENABLE_RMW)) && rcw > 0) { /* want reconstruct write, but need to get some data */ int qread =0; rcw = 0; @@ -6344,10 +6390,16 @@ static struct r5conf *setup_conf(struct mddev *mddev) } conf->level = mddev->new_level; - if (conf->level == 6) + if (conf->level == 6) { conf->max_degraded = 2; - else + if (raid6_call.xor_syndrome) + conf->rmw_level = PARITY_ENABLE_RMW; + else + conf->rmw_level = PARITY_DISABLE_RMW; + } else { conf->max_degraded = 1; + conf->rmw_level = PARITY_ENABLE_RMW; + } conf->algorithm = mddev->new_layout; conf->reshape_progress = mddev->reshape_position; if (conf->reshape_progress != MaxSector) { diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index ee65ed844d3f..57fef9ba36fa 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -355,6 +355,23 @@ enum { STRIPE_OP_RECONSTRUCT, STRIPE_OP_CHECK, }; + +/* + * RAID parity calculation preferences + */ +enum { + PARITY_DISABLE_RMW = 0, + PARITY_ENABLE_RMW, +}; + +/* + * Pages requested from set_syndrome_sources() + */ +enum { + SYNDROME_SRC_ALL, + SYNDROME_SRC_WANT_DRAIN, + SYNDROME_SRC_WRITTEN, +}; /* * Plugging: * @@ -411,7 +428,7 @@ struct r5conf { spinlock_t hash_locks[NR_STRIPE_HASH_LOCKS]; struct mddev *mddev; int chunk_sectors; - int level, algorithm; + int level, algorithm, rmw_level; int max_degraded; int raid_disks; int max_nr_stripes; diff --git a/include/linux/async_tx.h b/include/linux/async_tx.h index 179b38ffd351..388574ea38ed 100644 --- a/include/linux/async_tx.h +++ b/include/linux/async_tx.h @@ -60,12 +60,15 @@ struct dma_chan_ref { * dependency chain * @ASYNC_TX_FENCE: specify that the next operation in the dependency * chain uses this operation's result as an input + * @ASYNC_TX_PQ_XOR_DST: do not overwrite the syndrome but XOR it with the + * input data. Required for rmw case. */ enum async_tx_flags { ASYNC_TX_XOR_ZERO_DST = (1 << 0), ASYNC_TX_XOR_DROP_DST = (1 << 1), ASYNC_TX_ACK = (1 << 2), ASYNC_TX_FENCE = (1 << 3), + ASYNC_TX_PQ_XOR_DST = (1 << 4), }; /** -- cgit v1.2.3 From 0140e6141e4f1d4b15fb469e6912b0e71b7d1cc2 Mon Sep 17 00:00:00 2001 From: Sonny Rao Date: Tue, 21 Apr 2015 12:33:11 -0700 Subject: perf/x86/intel/uncore: Move PCI IDs for IMC to uncore driver This keeps all the related PCI IDs together in the driver where they are used. Signed-off-by: Sonny Rao Acked-by: Bjorn Helgaas Cc: Arnaldo Carvalho de Melo Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1429644791-25724-1-git-send-email-sonnyrao@chromium.org Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c | 6 +++++- include/linux/pci_ids.h | 4 ---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c index ca75e70865ef..4562e9e22c60 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c @@ -1,7 +1,11 @@ /* Nehalem/SandBridge/Haswell uncore support */ #include "perf_event_intel_uncore.h" -/* Uncore IMC PCI Id */ +/* Uncore IMC PCI IDs */ +#define PCI_DEVICE_ID_INTEL_SNB_IMC 0x0100 +#define PCI_DEVICE_ID_INTEL_IVB_IMC 0x0154 +#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC 0x0150 +#define PCI_DEVICE_ID_INTEL_HSW_IMC 0x0c00 #define PCI_DEVICE_ID_INTEL_HSW_U_IMC 0x0a04 /* SNB event control */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index e63c02a93f6b..a59385852233 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2539,10 +2539,6 @@ #define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_DEVICE_ID_INTEL_EESSC 0x0008 -#define PCI_DEVICE_ID_INTEL_SNB_IMC 0x0100 -#define PCI_DEVICE_ID_INTEL_IVB_IMC 0x0154 -#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC 0x0150 -#define PCI_DEVICE_ID_INTEL_HSW_IMC 0x0c00 #define PCI_DEVICE_ID_INTEL_PXHD_0 0x0320 #define PCI_DEVICE_ID_INTEL_PXHD_1 0x0321 #define PCI_DEVICE_ID_INTEL_PXH_0 0x0329 -- cgit v1.2.3 From 0ea611a3bc5fb8f6a0bb1a76fe2dbf8ebe4bdf77 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 7 Apr 2015 15:36:32 +0800 Subject: ceph: rename snapshot support Signed-off-by: Yan, Zheng --- fs/ceph/dir.c | 13 +++++++++---- fs/ceph/strings.c | 1 + include/linux/ceph/ceph_fs.h | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 98c71e895e81..e729b79812b4 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -947,16 +947,20 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry, struct ceph_fs_client *fsc = ceph_sb_to_client(old_dir->i_sb); struct ceph_mds_client *mdsc = fsc->mdsc; struct ceph_mds_request *req; + int op = CEPH_MDS_OP_RENAME; int err; if (ceph_snap(old_dir) != ceph_snap(new_dir)) return -EXDEV; - if (ceph_snap(old_dir) != CEPH_NOSNAP || - ceph_snap(new_dir) != CEPH_NOSNAP) - return -EROFS; + if (ceph_snap(old_dir) != CEPH_NOSNAP) { + if (old_dir == new_dir && ceph_snap(old_dir) == CEPH_SNAPDIR) + op = CEPH_MDS_OP_RENAMESNAP; + else + return -EROFS; + } dout("rename dir %p dentry %p to dir %p dentry %p\n", old_dir, old_dentry, new_dir, new_dentry); - req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_RENAME, USE_AUTH_MDS); + req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS); if (IS_ERR(req)) return PTR_ERR(req); ihold(old_dir); @@ -1387,6 +1391,7 @@ const struct inode_operations ceph_snapdir_iops = { .getattr = ceph_getattr, .mkdir = ceph_mkdir, .rmdir = ceph_unlink, + .rename = ceph_rename, }; const struct dentry_operations ceph_dentry_ops = { diff --git a/fs/ceph/strings.c b/fs/ceph/strings.c index 51cc23e48111..89e6bc321df3 100644 --- a/fs/ceph/strings.c +++ b/fs/ceph/strings.c @@ -75,6 +75,7 @@ const char *ceph_mds_op_name(int op) case CEPH_MDS_OP_LSSNAP: return "lssnap"; case CEPH_MDS_OP_MKSNAP: return "mksnap"; case CEPH_MDS_OP_RMSNAP: return "rmsnap"; + case CEPH_MDS_OP_RENAMESNAP: return "renamesnap"; case CEPH_MDS_OP_SETFILELOCK: return "setfilelock"; case CEPH_MDS_OP_GETFILELOCK: return "getfilelock"; } diff --git a/include/linux/ceph/ceph_fs.h b/include/linux/ceph/ceph_fs.h index 31eb03d0c766..d7d072a25c27 100644 --- a/include/linux/ceph/ceph_fs.h +++ b/include/linux/ceph/ceph_fs.h @@ -323,6 +323,7 @@ enum { CEPH_MDS_OP_MKSNAP = 0x01400, CEPH_MDS_OP_RMSNAP = 0x01401, CEPH_MDS_OP_LSSNAP = 0x00402, + CEPH_MDS_OP_RENAMESNAP = 0x01403, }; extern const char *ceph_mds_op_name(int op); -- cgit v1.2.3 From 958a27658d94cf212caeb0ffb04ee0b0bc89cc40 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 14 Apr 2015 16:54:52 +0300 Subject: crush: straw2 bucket type with an efficient 64-bit crush_ln() This is an improved straw bucket that correctly avoids any data movement between items A and B when neither A nor B's weights are changed. Said differently, if we adjust the weight of item C (including adding it anew or removing it completely), we will only see inputs move to or from C, never between other items in the bucket. Notably, there is not intermediate scaling factor that needs to be calculated. The mapping function is a simple function of the item weights. The below commits were squashed together into this one (mostly to avoid adding and then yanking a ~6000 lines worth of crush_ln_table): - crush: add a straw2 bucket type - crush: add crush_ln to calculate nature log efficently - crush: improve straw2 adjustment slightly - crush: change crush_ln to provide 32 more digits - crush: fix crush_get_bucket_item_weight and bucket destroy for straw2 - crush/mapper: fix divide-by-0 in straw2 (with div64_s64() for draw = ln / w and INT64_MIN -> S64_MIN - need to create a proper compat.h in ceph.git) Reflects ceph.git commits 242293c908e923d474910f2b8203fa3b41eb5a53, 32a1ead92efcd351822d22a5fc37d159c65c1338, 6289912418c4a3597a11778bcf29ed5415117ad9, 35fcb04e2945717cf5cfe150b9fa89cb3d2303a1, 6445d9ee7290938de1e4ee9563912a6ab6d8ee5f, b5921d55d16796e12d66ad2c4add7305f9ce2353. Signed-off-by: Ilya Dryomov --- include/linux/crush/crush.h | 12 ++- net/ceph/crush/crush.c | 14 ++++ net/ceph/crush/crush_ln_table.h | 166 ++++++++++++++++++++++++++++++++++++++++ net/ceph/crush/mapper.c | 101 ++++++++++++++++++++++++ net/ceph/osdmap.c | 25 ++++++ 5 files changed, 316 insertions(+), 2 deletions(-) create mode 100644 net/ceph/crush/crush_ln_table.h (limited to 'include') diff --git a/include/linux/crush/crush.h b/include/linux/crush/crush.h index 4fad5f8ee01d..48a1a7d100f1 100644 --- a/include/linux/crush/crush.h +++ b/include/linux/crush/crush.h @@ -96,13 +96,15 @@ struct crush_rule { * uniform O(1) poor poor * list O(n) optimal poor * tree O(log n) good good - * straw O(n) optimal optimal + * straw O(n) better better + * straw2 O(n) optimal optimal */ enum { CRUSH_BUCKET_UNIFORM = 1, CRUSH_BUCKET_LIST = 2, CRUSH_BUCKET_TREE = 3, - CRUSH_BUCKET_STRAW = 4 + CRUSH_BUCKET_STRAW = 4, + CRUSH_BUCKET_STRAW2 = 5, }; extern const char *crush_bucket_alg_name(int alg); @@ -149,6 +151,11 @@ struct crush_bucket_straw { __u32 *straws; /* 16-bit fixed point */ }; +struct crush_bucket_straw2 { + struct crush_bucket h; + __u32 *item_weights; /* 16-bit fixed point */ +}; + /* @@ -189,6 +196,7 @@ extern void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b); extern void crush_destroy_bucket_list(struct crush_bucket_list *b); extern void crush_destroy_bucket_tree(struct crush_bucket_tree *b); extern void crush_destroy_bucket_straw(struct crush_bucket_straw *b); +extern void crush_destroy_bucket_straw2(struct crush_bucket_straw2 *b); extern void crush_destroy_bucket(struct crush_bucket *b); extern void crush_destroy_rule(struct crush_rule *r); extern void crush_destroy(struct crush_map *map); diff --git a/net/ceph/crush/crush.c b/net/ceph/crush/crush.c index 16bc199d9a62..9d84ce4ea0df 100644 --- a/net/ceph/crush/crush.c +++ b/net/ceph/crush/crush.c @@ -17,6 +17,7 @@ const char *crush_bucket_alg_name(int alg) case CRUSH_BUCKET_LIST: return "list"; case CRUSH_BUCKET_TREE: return "tree"; case CRUSH_BUCKET_STRAW: return "straw"; + case CRUSH_BUCKET_STRAW2: return "straw2"; default: return "unknown"; } } @@ -40,6 +41,8 @@ int crush_get_bucket_item_weight(const struct crush_bucket *b, int p) return ((struct crush_bucket_tree *)b)->node_weights[crush_calc_tree_node(p)]; case CRUSH_BUCKET_STRAW: return ((struct crush_bucket_straw *)b)->item_weights[p]; + case CRUSH_BUCKET_STRAW2: + return ((struct crush_bucket_straw2 *)b)->item_weights[p]; } return 0; } @@ -77,6 +80,14 @@ void crush_destroy_bucket_straw(struct crush_bucket_straw *b) kfree(b); } +void crush_destroy_bucket_straw2(struct crush_bucket_straw2 *b) +{ + kfree(b->item_weights); + kfree(b->h.perm); + kfree(b->h.items); + kfree(b); +} + void crush_destroy_bucket(struct crush_bucket *b) { switch (b->alg) { @@ -92,6 +103,9 @@ void crush_destroy_bucket(struct crush_bucket *b) case CRUSH_BUCKET_STRAW: crush_destroy_bucket_straw((struct crush_bucket_straw *)b); break; + case CRUSH_BUCKET_STRAW2: + crush_destroy_bucket_straw2((struct crush_bucket_straw2 *)b); + break; } } diff --git a/net/ceph/crush/crush_ln_table.h b/net/ceph/crush/crush_ln_table.h new file mode 100644 index 000000000000..6192c7fc958c --- /dev/null +++ b/net/ceph/crush/crush_ln_table.h @@ -0,0 +1,166 @@ +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2015 Intel Corporation All Rights Reserved + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#if defined(__linux__) +#include +#elif defined(__FreeBSD__) +#include +#endif + +#ifndef CEPH_CRUSH_LN_H +#define CEPH_CRUSH_LN_H + + +// RH_LH_tbl[2*k] = 2^48/(1.0+k/128.0) +// RH_LH_tbl[2*k+1] = 2^48*log2(1.0+k/128.0) + +static int64_t __RH_LH_tbl[128*2+2] = { + 0x0001000000000000ll, 0x0000000000000000ll, 0x0000fe03f80fe040ll, 0x000002dfca16dde1ll, + 0x0000fc0fc0fc0fc1ll, 0x000005b9e5a170b4ll, 0x0000fa232cf25214ll, 0x0000088e68ea899all, + 0x0000f83e0f83e0f9ll, 0x00000b5d69bac77ell, 0x0000f6603d980f67ll, 0x00000e26fd5c8555ll, + 0x0000f4898d5f85bcll, 0x000010eb389fa29fll, 0x0000f2b9d6480f2cll, 0x000013aa2fdd27f1ll, + 0x0000f0f0f0f0f0f1ll, 0x00001663f6fac913ll, 0x0000ef2eb71fc435ll, 0x00001918a16e4633ll, + 0x0000ed7303b5cc0fll, 0x00001bc84240adabll, 0x0000ebbdb2a5c162ll, 0x00001e72ec117fa5ll, + 0x0000ea0ea0ea0ea1ll, 0x00002118b119b4f3ll, 0x0000e865ac7b7604ll, 0x000023b9a32eaa56ll, + 0x0000e6c2b4481cd9ll, 0x00002655d3c4f15cll, 0x0000e525982af70dll, 0x000028ed53f307eell, + 0x0000e38e38e38e39ll, 0x00002b803473f7adll, 0x0000e1fc780e1fc8ll, 0x00002e0e85a9de04ll, + 0x0000e070381c0e08ll, 0x0000309857a05e07ll, 0x0000dee95c4ca038ll, 0x0000331dba0efce1ll, + 0x0000dd67c8a60dd7ll, 0x0000359ebc5b69d9ll, 0x0000dbeb61eed19dll, 0x0000381b6d9bb29bll, + 0x0000da740da740dbll, 0x00003a93dc9864b2ll, 0x0000d901b2036407ll, 0x00003d0817ce9cd4ll, + 0x0000d79435e50d7all, 0x00003f782d7204d0ll, 0x0000d62b80d62b81ll, 0x000041e42b6ec0c0ll, + 0x0000d4c77b03531ell, 0x0000444c1f6b4c2dll, 0x0000d3680d3680d4ll, 0x000046b016ca47c1ll, + 0x0000d20d20d20d21ll, 0x000049101eac381cll, 0x0000d0b69fcbd259ll, 0x00004b6c43f1366all, + 0x0000cf6474a8819fll, 0x00004dc4933a9337ll, 0x0000ce168a772509ll, 0x0000501918ec6c11ll, + 0x0000cccccccccccdll, 0x00005269e12f346ell, 0x0000cb8727c065c4ll, 0x000054b6f7f1325all, + 0x0000ca4587e6b750ll, 0x0000570068e7ef5all, 0x0000c907da4e8712ll, 0x000059463f919deell, + 0x0000c7ce0c7ce0c8ll, 0x00005b8887367433ll, 0x0000c6980c6980c7ll, 0x00005dc74ae9fbecll, + 0x0000c565c87b5f9ell, 0x00006002958c5871ll, 0x0000c4372f855d83ll, 0x0000623a71cb82c8ll, + 0x0000c30c30c30c31ll, 0x0000646eea247c5cll, 0x0000c1e4bbd595f7ll, 0x000066a008e4788cll, + 0x0000c0c0c0c0c0c1ll, 0x000068cdd829fd81ll, 0x0000bfa02fe80bfbll, 0x00006af861e5fc7dll, + 0x0000be82fa0be830ll, 0x00006d1fafdce20all, 0x0000bd6910470767ll, 0x00006f43cba79e40ll, + 0x0000bc52640bc527ll, 0x00007164beb4a56dll, 0x0000bb3ee721a54ell, 0x000073829248e961ll, + 0x0000ba2e8ba2e8bbll, 0x0000759d4f80cba8ll, 0x0000b92143fa36f6ll, 0x000077b4ff5108d9ll, + 0x0000b81702e05c0cll, 0x000079c9aa879d53ll, 0x0000b70fbb5a19bfll, 0x00007bdb59cca388ll, + 0x0000b60b60b60b61ll, 0x00007dea15a32c1bll, 0x0000b509e68a9b95ll, 0x00007ff5e66a0ffell, + 0x0000b40b40b40b41ll, 0x000081fed45cbccbll, 0x0000b30f63528918ll, 0x00008404e793fb81ll, + 0x0000b21642c8590cll, 0x000086082806b1d5ll, 0x0000b11fd3b80b12ll, 0x000088089d8a9e47ll, + 0x0000b02c0b02c0b1ll, 0x00008a064fd50f2all, 0x0000af3addc680b0ll, 0x00008c01467b94bbll, + 0x0000ae4c415c9883ll, 0x00008df988f4ae80ll, 0x0000ad602b580ad7ll, 0x00008fef1e987409ll, + 0x0000ac7691840ac8ll, 0x000091e20ea1393ell, 0x0000ab8f69e2835all, 0x000093d2602c2e5fll, + 0x0000aaaaaaaaaaabll, 0x000095c01a39fbd6ll, 0x0000a9c84a47a080ll, 0x000097ab43af59f9ll, + 0x0000a8e83f5717c1ll, 0x00009993e355a4e5ll, 0x0000a80a80a80a81ll, 0x00009b79ffdb6c8bll, + 0x0000a72f0539782all, 0x00009d5d9fd5010bll, 0x0000a655c4392d7cll, 0x00009f3ec9bcfb80ll, + 0x0000a57eb50295fbll, 0x0000a11d83f4c355ll, 0x0000a4a9cf1d9684ll, 0x0000a2f9d4c51039ll, + 0x0000a3d70a3d70a4ll, 0x0000a4d3c25e68dcll, 0x0000a3065e3fae7dll, 0x0000a6ab52d99e76ll, + 0x0000a237c32b16d0ll, 0x0000a8808c384547ll, 0x0000a16b312ea8fdll, 0x0000aa5374652a1cll, + 0x0000a0a0a0a0a0a1ll, 0x0000ac241134c4e9ll, 0x00009fd809fd80a0ll, 0x0000adf26865a8a1ll, + 0x00009f1165e72549ll, 0x0000afbe7fa0f04dll, 0x00009e4cad23dd60ll, 0x0000b1885c7aa982ll, + 0x00009d89d89d89d9ll, 0x0000b35004723c46ll, 0x00009cc8e160c3fcll, 0x0000b5157cf2d078ll, + 0x00009c09c09c09c1ll, 0x0000b6d8cb53b0call, 0x00009b4c6f9ef03bll, 0x0000b899f4d8ab63ll, + 0x00009a90e7d95bc7ll, 0x0000ba58feb2703all, 0x000099d722dabde6ll, 0x0000bc15edfeed32ll, + 0x0000991f1a515886ll, 0x0000bdd0c7c9a817ll, 0x00009868c809868dll, 0x0000bf89910c1678ll, + 0x000097b425ed097cll, 0x0000c1404eadf383ll, 0x000097012e025c05ll, 0x0000c2f5058593d9ll, + 0x0000964fda6c0965ll, 0x0000c4a7ba58377cll, 0x000095a02568095bll, 0x0000c65871da59ddll, + 0x000094f2094f2095ll, 0x0000c80730b00016ll, 0x0000944580944581ll, 0x0000c9b3fb6d0559ll, + 0x0000939a85c4093all, 0x0000cb5ed69565afll, 0x000092f113840498ll, 0x0000cd07c69d8702ll, + 0x0000924924924925ll, 0x0000ceaecfea8085ll, 0x000091a2b3c4d5e7ll, 0x0000d053f6d26089ll, + 0x000090fdbc090fdcll, 0x0000d1f73f9c70c0ll, 0x0000905a38633e07ll, 0x0000d398ae817906ll, + 0x00008fb823ee08fcll, 0x0000d53847ac00a6ll, 0x00008f1779d9fdc4ll, 0x0000d6d60f388e41ll, + 0x00008e78356d1409ll, 0x0000d8720935e643ll, 0x00008dda5202376all, 0x0000da0c39a54804ll, + 0x00008d3dcb08d3ddll, 0x0000dba4a47aa996ll, 0x00008ca29c046515ll, 0x0000dd3b4d9cf24bll, + 0x00008c08c08c08c1ll, 0x0000ded038e633f3ll, 0x00008b70344a139cll, 0x0000e0636a23e2eell, + 0x00008ad8f2fba939ll, 0x0000e1f4e5170d02ll, 0x00008a42f870566all, 0x0000e384ad748f0ell, + 0x000089ae4089ae41ll, 0x0000e512c6e54998ll, 0x0000891ac73ae982ll, 0x0000e69f35065448ll, + 0x0000888888888889ll, 0x0000e829fb693044ll, 0x000087f78087f781ll, 0x0000e9b31d93f98ell, + 0x00008767ab5f34e5ll, 0x0000eb3a9f019750ll, 0x000086d905447a35ll, 0x0000ecc08321eb30ll, + 0x0000864b8a7de6d2ll, 0x0000ee44cd59ffabll, 0x000085bf37612cefll, 0x0000efc781043579ll, + 0x0000853408534086ll, 0x0000f148a170700all, 0x000084a9f9c8084bll, 0x0000f2c831e44116ll, + 0x0000842108421085ll, 0x0000f446359b1353ll, 0x0000839930523fbfll, 0x0000f5c2afc65447ll, + 0x000083126e978d50ll, 0x0000f73da38d9d4all, 0x0000828cbfbeb9a1ll, 0x0000f8b7140edbb1ll, + 0x0000820820820821ll, 0x0000fa2f045e7832ll, 0x000081848da8faf1ll, 0x0000fba577877d7dll, + 0x0000810204081021ll, 0x0000fd1a708bbe11ll, 0x0000808080808081ll, 0x0000fe8df263f957ll, + 0x0000800000000000ll, 0x0000ffff00000000ll, + }; + + + // LL_tbl[k] = 2^48*log2(1.0+k/2^15); +static int64_t __LL_tbl[256] = { + 0x0000000000000000ull, 0x00000002e2a60a00ull, 0x000000070cb64ec5ull, 0x00000009ef50ce67ull, + 0x0000000cd1e588fdull, 0x0000000fb4747e9cull, 0x0000001296fdaf5eull, 0x0000001579811b58ull, + 0x000000185bfec2a1ull, 0x0000001b3e76a552ull, 0x0000001e20e8c380ull, 0x0000002103551d43ull, + 0x00000023e5bbb2b2ull, 0x00000026c81c83e4ull, 0x00000029aa7790f0ull, 0x0000002c8cccd9edull, + 0x0000002f6f1c5ef2ull, 0x0000003251662017ull, 0x0000003533aa1d71ull, 0x0000003815e8571aull, + 0x0000003af820cd26ull, 0x0000003dda537faeull, 0x00000040bc806ec8ull, 0x000000439ea79a8cull, + 0x0000004680c90310ull, 0x0000004962e4a86cull, 0x0000004c44fa8ab6ull, 0x0000004f270aaa06ull, + 0x0000005209150672ull, 0x00000054eb19a013ull, 0x00000057cd1876fdull, 0x0000005aaf118b4aull, + 0x0000005d9104dd0full, 0x0000006072f26c64ull, 0x0000006354da3960ull, 0x0000006636bc441aull, + 0x0000006918988ca8ull, 0x0000006bfa6f1322ull, 0x0000006edc3fd79full, 0x00000071be0ada35ull, + 0x000000749fd01afdull, 0x00000077818f9a0cull, 0x0000007a6349577aull, 0x0000007d44fd535eull, + 0x0000008026ab8dceull, 0x00000083085406e3ull, 0x00000085e9f6beb2ull, 0x00000088cb93b552ull, + 0x0000008bad2aeadcull, 0x0000008e8ebc5f65ull, 0x0000009170481305ull, 0x0000009451ce05d3ull, + 0x00000097334e37e5ull, 0x0000009a14c8a953ull, 0x0000009cf63d5a33ull, 0x0000009fd7ac4a9dull, + 0x000000a2b07f3458ull, 0x000000a59a78ea6aull, 0x000000a87bd699fbull, 0x000000ab5d2e8970ull, + 0x000000ae3e80b8e3ull, 0x000000b11fcd2869ull, 0x000000b40113d818ull, 0x000000b6e254c80aull, + 0x000000b9c38ff853ull, 0x000000bca4c5690cull, 0x000000bf85f51a4aull, 0x000000c2671f0c26ull, + 0x000000c548433eb6ull, 0x000000c82961b211ull, 0x000000cb0a7a664dull, 0x000000cdeb8d5b82ull, + 0x000000d0cc9a91c8ull, 0x000000d3ada20933ull, 0x000000d68ea3c1ddull, 0x000000d96f9fbbdbull, + 0x000000dc5095f744ull, 0x000000df31867430ull, 0x000000e2127132b5ull, 0x000000e4f35632eaull, + 0x000000e7d43574e6ull, 0x000000eab50ef8c1ull, 0x000000ed95e2be90ull, 0x000000f076b0c66cull, + 0x000000f35779106aull, 0x000000f6383b9ca2ull, 0x000000f918f86b2aull, 0x000000fbf9af7c1aull, + 0x000000feda60cf88ull, 0x00000101bb0c658cull, 0x000001049bb23e3cull, 0x000001077c5259afull, + 0x0000010a5cecb7fcull, 0x0000010d3d81593aull, 0x000001101e103d7full, 0x00000112fe9964e4ull, + 0x00000115df1ccf7eull, 0x00000118bf9a7d64ull, 0x0000011ba0126eadull, 0x0000011e8084a371ull, + 0x0000012160f11bc6ull, 0x000001244157d7c3ull, 0x0000012721b8d77full, 0x0000012a02141b10ull, + 0x0000012ce269a28eull, 0x0000012fc2b96e0full, 0x00000132a3037daaull, 0x000001358347d177ull, + 0x000001386386698cull, 0x0000013b43bf45ffull, 0x0000013e23f266e9ull, 0x00000141041fcc5eull, + 0x00000143e4477678ull, 0x00000146c469654bull, 0x00000149a48598f0ull, 0x0000014c849c117cull, + 0x0000014f64accf08ull, 0x0000015244b7d1a9ull, 0x0000015524bd1976ull, 0x0000015804bca687ull, + 0x0000015ae4b678f2ull, 0x0000015dc4aa90ceull, 0x00000160a498ee31ull, 0x0000016384819134ull, + 0x00000166646479ecull, 0x000001694441a870ull, 0x0000016c24191cd7ull, 0x0000016df6ca19bdull, + 0x00000171e3b6d7aaull, 0x00000174c37d1e44ull, 0x00000177a33dab1cull, 0x0000017a82f87e49ull, + 0x0000017d62ad97e2ull, 0x00000180425cf7feull, 0x00000182b07f3458ull, 0x0000018601aa8c19ull, + 0x00000188e148c046ull, 0x0000018bc0e13b52ull, 0x0000018ea073fd52ull, 0x000001918001065dull, + 0x000001945f88568bull, 0x000001973f09edf2ull, 0x0000019a1e85ccaaull, 0x0000019cfdfbf2c8ull, + 0x0000019fdd6c6063ull, 0x000001a2bcd71593ull, 0x000001a59c3c126eull, 0x000001a87b9b570bull, + 0x000001ab5af4e380ull, 0x000001ae3a48b7e5ull, 0x000001b11996d450ull, 0x000001b3f8df38d9ull, + 0x000001b6d821e595ull, 0x000001b9b75eda9bull, 0x000001bc96961803ull, 0x000001bf75c79de3ull, + 0x000001c254f36c51ull, 0x000001c534198365ull, 0x000001c81339e336ull, 0x000001caf2548bd9ull, + 0x000001cdd1697d67ull, 0x000001d0b078b7f5ull, 0x000001d38f823b9aull, 0x000001d66e86086dull, + 0x000001d94d841e86ull, 0x000001dc2c7c7df9ull, 0x000001df0b6f26dfull, 0x000001e1ea5c194eull, + 0x000001e4c943555dull, 0x000001e7a824db23ull, 0x000001ea8700aab5ull, 0x000001ed65d6c42bull, + 0x000001f044a7279dull, 0x000001f32371d51full, 0x000001f60236cccaull, 0x000001f8e0f60eb3ull, + 0x000001fbbfaf9af3ull, 0x000001fe9e63719eull, 0x000002017d1192ccull, 0x000002045bb9fe94ull, + 0x000002073a5cb50dull, 0x00000209c06e6212ull, 0x0000020cf791026aull, 0x0000020fd622997cull, + 0x00000212b07f3458ull, 0x000002159334a8d8ull, 0x0000021871b52150ull, 0x0000021b502fe517ull, + 0x0000021d6a73a78full, 0x000002210d144eeeull, 0x00000223eb7df52cull, 0x00000226c9e1e713ull, + 0x00000229a84024bbull, 0x0000022c23679b4eull, 0x0000022f64eb83a8ull, 0x000002324338a51bull, + 0x00000235218012a9ull, 0x00000237ffc1cc69ull, 0x0000023a2c3b0ea4ull, 0x0000023d13ee805bull, + 0x0000024035e9221full, 0x00000243788faf25ull, 0x0000024656b4e735ull, 0x00000247ed646bfeull, + 0x0000024c12ee3d98ull, 0x0000024ef1025c1aull, 0x00000251cf10c799ull, 0x0000025492644d65ull, + 0x000002578b1c85eeull, 0x0000025a6919d8f0ull, 0x0000025d13ee805bull, 0x0000026025036716ull, + 0x0000026296453882ull, 0x00000265e0d62b53ull, 0x00000268beb701f3ull, 0x0000026b9c92265eull, + 0x0000026d32f798a9ull, 0x00000271583758ebull, 0x000002743601673bull, 0x0000027713c5c3b0ull, + 0x00000279f1846e5full, 0x0000027ccf3d6761ull, 0x0000027e6580aecbull, 0x000002828a9e44b3ull, + 0x0000028568462932ull, 0x00000287bdbf5255ull, 0x0000028b2384de4aull, 0x0000028d13ee805bull, + 0x0000029035e9221full, 0x0000029296453882ull, 0x0000029699bdfb61ull, 0x0000029902a37aabull, + 0x0000029c54b864c9ull, 0x0000029deabd1083ull, 0x000002a20f9c0bb5ull, 0x000002a4c7605d61ull, + 0x000002a7bdbf5255ull, 0x000002a96056dafcull, 0x000002ac3daf14efull, 0x000002af1b019ecaull, + 0x000002b296453882ull, 0x000002b5d022d80full, 0x000002b8fa471cb3ull, 0x000002ba9012e713ull, + 0x000002bd6d4901ccull, 0x000002c04a796cf6ull, 0x000002c327a428a6ull, 0x000002c61a5e8f4cull, + 0x000002c8e1e891f6ull, 0x000002cbbf023fc2ull, 0x000002ce9c163e6eull, 0x000002d179248e13ull, + 0x000002d4562d2ec6ull, 0x000002d73330209dull, 0x000002da102d63b0ull, 0x000002dced24f814ull, +}; + + + + +#endif diff --git a/net/ceph/crush/mapper.c b/net/ceph/crush/mapper.c index 91c41fe83113..5b47736d27d9 100644 --- a/net/ceph/crush/mapper.c +++ b/net/ceph/crush/mapper.c @@ -20,6 +20,7 @@ #include #include +#include "crush_ln_table.h" /* * Implement the core CRUSH mapping algorithm. @@ -237,6 +238,102 @@ static int bucket_straw_choose(struct crush_bucket_straw *bucket, return bucket->h.items[high]; } +// compute 2^44*log2(input+1) +uint64_t crush_ln(unsigned xin) +{ + unsigned x=xin, x1; + int iexpon, index1, index2; + uint64_t RH, LH, LL, xl64, result; + + x++; + + // normalize input + iexpon = 15; + while(!(x&0x18000)) { x<<=1; iexpon--; } + + index1 = (x>>8)<<1; + // RH ~ 2^56/index1 + RH = __RH_LH_tbl[index1 - 256]; + // LH ~ 2^48 * log2(index1/256) + LH = __RH_LH_tbl[index1 + 1 - 256]; + + // RH*x ~ 2^48 * (2^15 + xf), xf<2^8 + xl64 = (int64_t)x * RH; + xl64 >>= 48; + x1 = xl64; + + result = iexpon; + result <<= (12 + 32); + + index2 = x1 & 0xff; + // LL ~ 2^48*log2(1.0+index2/2^15) + LL = __LL_tbl[index2]; + + LH = LH + LL; + + LH >>= (48-12 - 32); + result += LH; + + return result; +} + + +/* + * straw2 + * + * for reference, see: + * + * http://en.wikipedia.org/wiki/Exponential_distribution#Distribution_of_the_minimum_of_exponential_random_variables + * + */ + +static int bucket_straw2_choose(struct crush_bucket_straw2 *bucket, + int x, int r) +{ + unsigned i, high = 0; + unsigned u; + unsigned w; + __s64 ln, draw, high_draw = 0; + + for (i = 0; i < bucket->h.size; i++) { + w = bucket->item_weights[i]; + if (w) { + u = crush_hash32_3(bucket->h.hash, x, + bucket->h.items[i], r); + u &= 0xffff; + + /* + * for some reason slightly less than 0x10000 produces + * a slightly more accurate distribution... probably a + * rounding effect. + * + * the natural log lookup table maps [0,0xffff] + * (corresponding to real numbers [1/0x10000, 1] to + * [0, 0xffffffffffff] (corresponding to real numbers + * [-11.090355,0]). + */ + ln = crush_ln(u) - 0x1000000000000ll; + + /* + * divide by 16.16 fixed-point weight. note + * that the ln value is negative, so a larger + * weight means a larger (less negative) value + * for draw. + */ + draw = div64_s64(ln, w); + } else { + draw = S64_MIN; + } + + if (i == 0 || draw > high_draw) { + high = i; + high_draw = draw; + } + } + return bucket->h.items[high]; +} + + static int crush_bucket_choose(struct crush_bucket *in, int x, int r) { dprintk(" crush_bucket_choose %d x=%d r=%d\n", in->id, x, r); @@ -254,12 +351,16 @@ static int crush_bucket_choose(struct crush_bucket *in, int x, int r) case CRUSH_BUCKET_STRAW: return bucket_straw_choose((struct crush_bucket_straw *)in, x, r); + case CRUSH_BUCKET_STRAW2: + return bucket_straw2_choose((struct crush_bucket_straw2 *)in, + x, r); default: dprintk("unknown bucket %d alg %d\n", in->id, in->alg); return in->items[0]; } } + /* * true if device is marked "out" (failed, fully offloaded) * of the cluster diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index b8c3fde5b04f..15796696d64e 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -122,6 +122,22 @@ bad: return -EINVAL; } +static int crush_decode_straw2_bucket(void **p, void *end, + struct crush_bucket_straw2 *b) +{ + int j; + dout("crush_decode_straw2_bucket %p to %p\n", *p, end); + b->item_weights = kcalloc(b->h.size, sizeof(u32), GFP_NOFS); + if (b->item_weights == NULL) + return -ENOMEM; + ceph_decode_need(p, end, b->h.size * sizeof(u32), bad); + for (j = 0; j < b->h.size; j++) + b->item_weights[j] = ceph_decode_32(p); + return 0; +bad: + return -EINVAL; +} + static int skip_name_map(void **p, void *end) { int len; @@ -204,6 +220,9 @@ static struct crush_map *crush_decode(void *pbyval, void *end) case CRUSH_BUCKET_STRAW: size = sizeof(struct crush_bucket_straw); break; + case CRUSH_BUCKET_STRAW2: + size = sizeof(struct crush_bucket_straw2); + break; default: err = -EINVAL; goto bad; @@ -261,6 +280,12 @@ static struct crush_map *crush_decode(void *pbyval, void *end) if (err < 0) goto bad; break; + case CRUSH_BUCKET_STRAW2: + err = crush_decode_straw2_bucket(p, end, + (struct crush_bucket_straw2 *)b); + if (err < 0) + goto bad; + break; } } -- cgit v1.2.3 From 7c1c4747f28f59f2939687168203863f7e095d10 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 14 Apr 2015 23:13:31 +0300 Subject: libceph: announce support for straw2 buckets Sync up feature bits and enable CEPH_FEATURE_CRUSH_V4. Signed-off-by: Ilya Dryomov --- include/linux/ceph/ceph_features.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/ceph/ceph_features.h b/include/linux/ceph/ceph_features.h index 71e05bbf8ceb..4763ad64e832 100644 --- a/include/linux/ceph/ceph_features.h +++ b/include/linux/ceph/ceph_features.h @@ -50,6 +50,19 @@ #define CEPH_FEATURE_MDS_INLINE_DATA (1ULL<<40) #define CEPH_FEATURE_CRUSH_TUNABLES3 (1ULL<<41) #define CEPH_FEATURE_OSD_PRIMARY_AFFINITY (1ULL<<41) /* overlap w/ tunables3 */ +#define CEPH_FEATURE_MSGR_KEEPALIVE2 (1ULL<<42) +#define CEPH_FEATURE_OSD_POOLRESEND (1ULL<<43) +#define CEPH_FEATURE_ERASURE_CODE_PLUGINS_V2 (1ULL<<44) +#define CEPH_FEATURE_OSD_SET_ALLOC_HINT (1ULL<<45) +#define CEPH_FEATURE_OSD_FADVISE_FLAGS (1ULL<<46) +#define CEPH_FEATURE_OSD_REPOP (1ULL<<46) /* overlap with fadvise */ +#define CEPH_FEATURE_OSD_OBJECT_DIGEST (1ULL<<46) /* overlap with fadvise */ +#define CEPH_FEATURE_OSD_TRANSACTION_MAY_LAYOUT (1ULL<<46) /* overlap w/ fadvise */ +#define CEPH_FEATURE_MDS_QUOTA (1ULL<<47) +#define CEPH_FEATURE_CRUSH_V4 (1ULL<<48) /* straw2 buckets */ +#define CEPH_FEATURE_OSD_MIN_SIZE_RECOVERY (1ULL<<49) +// duplicated since it was introduced at the same time as MIN_SIZE_RECOVERY +#define CEPH_FEATURE_OSD_PROXY_FEATURES (1ULL<<49) /* overlap w/ above */ /* * The introduction of CEPH_FEATURE_OSD_SNAPMAPPER caused the feature @@ -93,7 +106,8 @@ static inline u64 ceph_sanitize_features(u64 features) CEPH_FEATURE_EXPORT_PEER | \ CEPH_FEATURE_OSDMAP_ENC | \ CEPH_FEATURE_CRUSH_TUNABLES3 | \ - CEPH_FEATURE_OSD_PRIMARY_AFFINITY) + CEPH_FEATURE_OSD_PRIMARY_AFFINITY | \ + CEPH_FEATURE_CRUSH_V4) #define CEPH_FEATURES_REQUIRED_DEFAULT \ (CEPH_FEATURE_NOSRCADDR | \ -- cgit v1.2.3 From f3ca10dde49043fbbb055854278b26954b549b36 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 22 Apr 2015 09:44:36 -0700 Subject: Revert "mm: avoid tail page refcounting on non-THP compound pages" This reverts commit 8d63d99a5dfbdb997d12dd3c07b2070ca723db3b. It causes in VM mapping refcount errors: page:ffffea0010a15040 count:0 mapcount:1 mapping: (null) index:0x0 flags: 0x8000000000008014(referenced|dirty|tail) page dumped because: VM_BUG_ON_PAGE(page_mapcount(page) != 0) ------------[ cut here ]------------ kernel BUG at mm/swap.c:134! as reported by Borislav Petkov Reported-and-tested-by: Borislav Petkov Cc: Kirill A. Shutemov Cc: Hugh Dickins Cc: Andrea Arcangeli Cc: Andrew Morton Cc: linux-mm@kvack.org Signed-off-by: Linus Torvalds --- include/linux/mm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/mm.h b/include/linux/mm.h index 8b086070c3a5..0755b9fd03a7 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -499,7 +499,7 @@ static inline int page_count(struct page *page) static inline bool __compound_tail_refcounted(struct page *page) { - return PageAnon(page) && !PageSlab(page) && !PageHeadHuge(page); + return !PageSlab(page) && !PageHeadHuge(page); } /* -- cgit v1.2.3 From 03c57747a7020a28a200e7e920fb48ecdc9b0fb8 Mon Sep 17 00:00:00 2001 From: Robert Shearman Date: Wed, 22 Apr 2015 11:14:37 +0100 Subject: mpls: Per-device MPLS state Add per-device MPLS state to supported interfaces. Use the presence of this state in mpls_route_add to determine that this is a supported interface. Use the presence of mpls_dev to drop packets that arrived on an unsupported interface - previously they were allowed through. Cc: "Eric W. Biederman" Signed-off-by: Robert Shearman Reviewed-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- include/linux/netdevice.h | 4 ++++ net/mpls/af_mpls.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-- net/mpls/internal.h | 3 +++ 3 files changed, 55 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index bcbde799ec69..dae106a3a998 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -60,6 +60,7 @@ struct phy_device; struct wireless_dev; /* 802.15.4 specific */ struct wpan_dev; +struct mpls_dev; void netdev_set_default_ethtool_ops(struct net_device *dev, const struct ethtool_ops *ops); @@ -1627,6 +1628,9 @@ struct net_device { void *ax25_ptr; struct wireless_dev *ieee80211_ptr; struct wpan_dev *ieee802154_ptr; +#if IS_ENABLED(CONFIG_MPLS_ROUTING) + struct mpls_dev __rcu *mpls_ptr; +#endif /* * Cache lines mostly used on receive path (including eth_type_trans()) diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index db8a2ea6d4de..ad45017eed99 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -53,6 +53,11 @@ static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index) return rt; } +static inline struct mpls_dev *mpls_dev_get(const struct net_device *dev) +{ + return rcu_dereference_rtnl(dev->mpls_ptr); +} + static bool mpls_output_possible(const struct net_device *dev) { return dev && (dev->flags & IFF_UP) && netif_carrier_ok(dev); @@ -136,6 +141,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev, struct mpls_route *rt; struct mpls_entry_decoded dec; struct net_device *out_dev; + struct mpls_dev *mdev; unsigned int hh_len; unsigned int new_header_size; unsigned int mtu; @@ -143,6 +149,10 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev, /* Careful this entire function runs inside of an rcu critical section */ + mdev = mpls_dev_get(dev); + if (!mdev) + goto drop; + if (skb->pkt_type != PACKET_HOST) goto drop; @@ -352,9 +362,9 @@ static int mpls_route_add(struct mpls_route_config *cfg) if (!dev) goto errout; - /* For now just support ethernet devices */ + /* Ensure this is a supported device */ err = -EINVAL; - if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK)) + if (!mpls_dev_get(dev)) goto errout; err = -EINVAL; @@ -428,10 +438,27 @@ errout: return err; } +static struct mpls_dev *mpls_add_dev(struct net_device *dev) +{ + struct mpls_dev *mdev; + int err = -ENOMEM; + + ASSERT_RTNL(); + + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + if (!mdev) + return ERR_PTR(err); + + rcu_assign_pointer(dev->mpls_ptr, mdev); + + return mdev; +} + static void mpls_ifdown(struct net_device *dev) { struct mpls_route __rcu **platform_label; struct net *net = dev_net(dev); + struct mpls_dev *mdev; unsigned index; platform_label = rtnl_dereference(net->mpls.platform_label); @@ -443,14 +470,33 @@ static void mpls_ifdown(struct net_device *dev) continue; rt->rt_dev = NULL; } + + mdev = mpls_dev_get(dev); + if (!mdev) + return; + + RCU_INIT_POINTER(dev->mpls_ptr, NULL); + + kfree(mdev); } static int mpls_dev_notify(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct mpls_dev *mdev; switch(event) { + case NETDEV_REGISTER: + /* For now just support ethernet devices */ + if ((dev->type == ARPHRD_ETHER) || + (dev->type == ARPHRD_LOOPBACK)) { + mdev = mpls_add_dev(dev); + if (IS_ERR(mdev)) + return notifier_from_errno(PTR_ERR(mdev)); + } + break; + case NETDEV_UNREGISTER: mpls_ifdown(dev); break; diff --git a/net/mpls/internal.h b/net/mpls/internal.h index fb6de92052c4..8090cb3099b4 100644 --- a/net/mpls/internal.h +++ b/net/mpls/internal.h @@ -22,6 +22,9 @@ struct mpls_entry_decoded { u8 bos; }; +struct mpls_dev { +}; + struct sk_buff; static inline struct mpls_shim_hdr *mpls_hdr(const struct sk_buff *skb) -- cgit v1.2.3 From a2d97723cb3a7741af81868427b36bba274b681b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 22 Apr 2015 13:58:47 +0100 Subject: ASoC: dapm: Enable autodisable on SOC_DAPM_SINGLE_TLV_AUTODISABLE Correct small copy and paste error where autodisable was not being enabled for the SOC_DAPM_SINGLE_TLV_AUTODISABLE control. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- include/sound/soc-dapm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 8d7416e46861..15355892a0ff 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -287,7 +287,7 @@ struct device; .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ .tlv.p = (tlv_array), \ .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ - .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } + .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) } #define SOC_DAPM_SINGLE_TLV_VIRT(xname, max, tlv_array) \ SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0, tlv_array) #define SOC_DAPM_ENUM(xname, xenum) \ -- cgit v1.2.3 From 7e01b5acd88b3f3108d8c4ce44e3205d67437202 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 16 Apr 2015 14:47:33 +0200 Subject: kexec: allocate the kexec control page with KEXEC_CONTROL_MEMORY_GFP Introduce KEXEC_CONTROL_MEMORY_GFP to allow the architecture code to override the gfp flags of the allocation for the kexec control page. The loop in kimage_alloc_normal_control_pages allocates pages with GFP_KERNEL until a page is found that happens to have an address smaller than the KEXEC_CONTROL_MEMORY_LIMIT. On systems with a large memory size but a small KEXEC_CONTROL_MEMORY_LIMIT the loop will keep allocating memory until the oom killer steps in. Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/kexec.h | 3 +++ include/linux/kexec.h | 4 ++++ kernel/kexec.c | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/s390/include/asm/kexec.h b/arch/s390/include/asm/kexec.h index 694bcd6bd927..2f924bc30e35 100644 --- a/arch/s390/include/asm/kexec.h +++ b/arch/s390/include/asm/kexec.h @@ -26,6 +26,9 @@ /* Not more than 2GB */ #define KEXEC_CONTROL_MEMORY_LIMIT (1UL<<31) +/* Allocate control page with GFP_DMA */ +#define KEXEC_CONTROL_MEMORY_GFP GFP_DMA + /* Maximum address we can use for the crash control pages */ #define KEXEC_CRASH_CONTROL_MEMORY_LIMIT (-1UL) diff --git a/include/linux/kexec.h b/include/linux/kexec.h index e60a745ac198..e804306ef5e8 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -40,6 +40,10 @@ #error KEXEC_CONTROL_MEMORY_LIMIT not defined #endif +#ifndef KEXEC_CONTROL_MEMORY_GFP +#define KEXEC_CONTROL_MEMORY_GFP GFP_KERNEL +#endif + #ifndef KEXEC_CONTROL_PAGE_SIZE #error KEXEC_CONTROL_PAGE_SIZE not defined #endif diff --git a/kernel/kexec.c b/kernel/kexec.c index 38c25b1f2fd5..7a36fdcca5bf 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -707,7 +707,7 @@ static struct page *kimage_alloc_normal_control_pages(struct kimage *image, do { unsigned long pfn, epfn, addr, eaddr; - pages = kimage_alloc_pages(GFP_KERNEL, order); + pages = kimage_alloc_pages(KEXEC_CONTROL_MEMORY_GFP, order); if (!pages) break; pfn = page_to_pfn(pages); -- cgit v1.2.3 From ec65aafb9e3f316ff9167289e288856a7d528773 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Apr 2015 12:06:30 +0200 Subject: netdev_alloc_pcpu_stats: use less common iterator variable With the CPU iteration variable called 'i', it's relatively easy to have variable shadowing which sparse will warn about. Avoid that by renaming the variable to __cpu which is less likely to be used in the surrounding context. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/linux/netdevice.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index dae106a3a998..dbad4d728b4b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2025,10 +2025,10 @@ struct pcpu_sw_netstats { ({ \ typeof(type) __percpu *pcpu_stats = alloc_percpu(type); \ if (pcpu_stats) { \ - int i; \ - for_each_possible_cpu(i) { \ + int __cpu; \ + for_each_possible_cpu(__cpu) { \ typeof(type) *stat; \ - stat = per_cpu_ptr(pcpu_stats, i); \ + stat = per_cpu_ptr(pcpu_stats, __cpu); \ u64_stats_init(&stat->syncp); \ } \ } \ -- cgit v1.2.3 From 9a51940bf65bf9fdc93027d70bdecdfc403c5b24 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Mon, 16 Mar 2015 14:06:23 -0400 Subject: NFS: Don't zap caches on fallocate() This patch adds a GETATTR to the end of ALLOCATE and DEALLOCATE operations so we can set the updated inode size and change attribute directly. DEALLOCATE will still need to release pagecache pages, so nfs42_proc_deallocate() now calls truncate_pagecache_range() before contacting the server. Signed-off-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 1 - fs/nfs/nfs42proc.c | 23 +++++++++++++++++++---- fs/nfs/nfs42xdr.c | 20 ++++++++++++++++---- fs/nfs/nfs4file.c | 1 - include/linux/nfs_xdr.h | 4 ++++ 5 files changed, 39 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 0c3be2658546..83743a133204 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -199,7 +199,6 @@ void nfs_zap_caches(struct inode *inode) nfs_zap_caches_locked(inode); spin_unlock(&inode->i_lock); } -EXPORT_SYMBOL_GPL(nfs_zap_caches); void nfs_zap_mapping(struct inode *inode, struct address_space *mapping) { diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index cb170722769c..b9aa6bbcc8ed 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c @@ -36,13 +36,16 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, loff_t offset, loff_t len) { struct inode *inode = file_inode(filep); + struct nfs_server *server = NFS_SERVER(inode); struct nfs42_falloc_args args = { .falloc_fh = NFS_FH(inode), .falloc_offset = offset, .falloc_length = len, + .falloc_bitmask = server->cache_consistency_bitmask, + }; + struct nfs42_falloc_res res = { + .falloc_server = server, }; - struct nfs42_falloc_res res; - struct nfs_server *server = NFS_SERVER(inode); int status; msg->rpc_argp = &args; @@ -52,8 +55,17 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, if (status) return status; - return nfs4_call_sync(server->client, server, msg, - &args.seq_args, &res.seq_res, 0); + res.falloc_fattr = nfs_alloc_fattr(); + if (!res.falloc_fattr) + return -ENOMEM; + + status = nfs4_call_sync(server->client, server, msg, + &args.seq_args, &res.seq_res, 0); + if (status == 0) + status = nfs_post_op_update_inode(inode, res.falloc_fattr); + + kfree(res.falloc_fattr); + return status; } static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, @@ -101,7 +113,10 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len) if (!nfs_server_capable(inode, NFS_CAP_DEALLOCATE)) return -EOPNOTSUPP; + nfs_wb_all(inode); err = nfs42_proc_fallocate(&msg, filep, offset, len); + if (err == 0) + truncate_pagecache_range(inode, offset, (offset + len) -1); if (err == -EOPNOTSUPP) NFS_SERVER(inode)->caps &= ~NFS_CAP_DEALLOCATE; return err; diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c index 038a7e1521fa..1a25b27248f2 100644 --- a/fs/nfs/nfs42xdr.c +++ b/fs/nfs/nfs42xdr.c @@ -25,16 +25,20 @@ #define NFS4_enc_allocate_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_allocate_maxsz) + encode_allocate_maxsz + \ + encode_getattr_maxsz) #define NFS4_dec_allocate_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - decode_allocate_maxsz) + decode_allocate_maxsz + \ + decode_getattr_maxsz) #define NFS4_enc_deallocate_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_deallocate_maxsz) + encode_deallocate_maxsz + \ + encode_getattr_maxsz) #define NFS4_dec_deallocate_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - decode_deallocate_maxsz) + decode_deallocate_maxsz + \ + decode_getattr_maxsz) #define NFS4_enc_seek_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_seek_maxsz) @@ -92,6 +96,7 @@ static void nfs4_xdr_enc_allocate(struct rpc_rqst *req, encode_sequence(xdr, &args->seq_args, &hdr); encode_putfh(xdr, args->falloc_fh, &hdr); encode_allocate(xdr, args, &hdr); + encode_getfattr(xdr, args->falloc_bitmask, &hdr); encode_nops(&hdr); } @@ -110,6 +115,7 @@ static void nfs4_xdr_enc_deallocate(struct rpc_rqst *req, encode_sequence(xdr, &args->seq_args, &hdr); encode_putfh(xdr, args->falloc_fh, &hdr); encode_deallocate(xdr, args, &hdr); + encode_getfattr(xdr, args->falloc_bitmask, &hdr); encode_nops(&hdr); } @@ -183,6 +189,9 @@ static int nfs4_xdr_dec_allocate(struct rpc_rqst *rqstp, if (status) goto out; status = decode_allocate(xdr, res); + if (status) + goto out; + decode_getfattr(xdr, res->falloc_fattr, res->falloc_server); out: return status; } @@ -207,6 +216,9 @@ static int nfs4_xdr_dec_deallocate(struct rpc_rqst *rqstp, if (status) goto out; status = decode_deallocate(xdr, res); + if (status) + goto out; + decode_getfattr(xdr, res->falloc_fattr, res->falloc_server); out: return status; } diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 866842b048ef..151ddff624d4 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -165,7 +165,6 @@ static long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t ret = nfs42_proc_allocate(filep, offset, len); mutex_unlock(&inode->i_mutex); - nfs_zap_caches(inode); return ret; } #endif /* CONFIG_NFS_V4_2 */ diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 3d88908fd140..93ab6071bbe9 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1273,11 +1273,15 @@ struct nfs42_falloc_args { nfs4_stateid falloc_stateid; u64 falloc_offset; u64 falloc_length; + const u32 *falloc_bitmask; }; struct nfs42_falloc_res { struct nfs4_sequence_res seq_res; unsigned int status; + + struct nfs_fattr *falloc_fattr; + const struct nfs_server *falloc_server; }; struct nfs42_seek_args { -- cgit v1.2.3 From 3f9400981691f6845e5c22b962500742b80a5484 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 31 Mar 2015 12:03:28 -0400 Subject: sunrpc: make debugfs file creation failure non-fatal v2: gracefully handle the case where some dentry pointers end up NULL and be more dilligent about zeroing out dentry pointers We currently have a problem that SELinux policy is being enforced when creating debugfs files. If a debugfs file is created as a side effect of doing some syscall, then that creation can fail if the SELinux policy for that process prevents it. This seems wrong. We don't do that for files under /proc, for instance, so Bruce has proposed a patch to fix that. While discussing that patch however, Greg K.H. stated: "No kernel code should care / fail if a debugfs function fails, so please fix up the sunrpc code first." This patch converts all of the sunrpc debugfs setup code to be void return functins, and the callers to not look for errors from those functions. This should allow rpc_clnt and rpc_xprt creation to work, even if the kernel fails to create debugfs files for some reason. Cc: Greg Kroah-Hartman Acked-by: "J. Bruce Fields" Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust --- include/linux/sunrpc/debug.h | 18 +++++++-------- net/sunrpc/clnt.c | 4 +--- net/sunrpc/debugfs.c | 52 ++++++++++++++++++++++++-------------------- net/sunrpc/sunrpc_syms.c | 7 +----- net/sunrpc/xprt.c | 7 +----- 5 files changed, 41 insertions(+), 47 deletions(-) (limited to 'include') diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h index c57d8ea0716c..59a7889e15db 100644 --- a/include/linux/sunrpc/debug.h +++ b/include/linux/sunrpc/debug.h @@ -60,17 +60,17 @@ struct rpc_xprt; #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) void rpc_register_sysctl(void); void rpc_unregister_sysctl(void); -int sunrpc_debugfs_init(void); +void sunrpc_debugfs_init(void); void sunrpc_debugfs_exit(void); -int rpc_clnt_debugfs_register(struct rpc_clnt *); +void rpc_clnt_debugfs_register(struct rpc_clnt *); void rpc_clnt_debugfs_unregister(struct rpc_clnt *); -int rpc_xprt_debugfs_register(struct rpc_xprt *); +void rpc_xprt_debugfs_register(struct rpc_xprt *); void rpc_xprt_debugfs_unregister(struct rpc_xprt *); #else -static inline int +static inline void sunrpc_debugfs_init(void) { - return 0; + return; } static inline void @@ -79,10 +79,10 @@ sunrpc_debugfs_exit(void) return; } -static inline int +static inline void rpc_clnt_debugfs_register(struct rpc_clnt *clnt) { - return 0; + return; } static inline void @@ -91,10 +91,10 @@ rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt) return; } -static inline int +static inline void rpc_xprt_debugfs_register(struct rpc_xprt *xprt) { - return 0; + return; } static inline void diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 612aa73bbc60..e6ce1517367f 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -303,9 +303,7 @@ static int rpc_client_register(struct rpc_clnt *clnt, struct super_block *pipefs_sb; int err; - err = rpc_clnt_debugfs_register(clnt); - if (err) - return err; + rpc_clnt_debugfs_register(clnt); pipefs_sb = rpc_get_sb_net(net); if (pipefs_sb) { diff --git a/net/sunrpc/debugfs.c b/net/sunrpc/debugfs.c index e811f390f9f6..82962f7e6e88 100644 --- a/net/sunrpc/debugfs.c +++ b/net/sunrpc/debugfs.c @@ -129,48 +129,52 @@ static const struct file_operations tasks_fops = { .release = tasks_release, }; -int +void rpc_clnt_debugfs_register(struct rpc_clnt *clnt) { - int len, err; + int len; char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */ + struct rpc_xprt *xprt; /* Already registered? */ - if (clnt->cl_debugfs) - return 0; + if (clnt->cl_debugfs || !rpc_clnt_dir) + return; len = snprintf(name, sizeof(name), "%x", clnt->cl_clid); if (len >= sizeof(name)) - return -EINVAL; + return; /* make the per-client dir */ clnt->cl_debugfs = debugfs_create_dir(name, rpc_clnt_dir); if (!clnt->cl_debugfs) - return -ENOMEM; + return; /* make tasks file */ - err = -ENOMEM; if (!debugfs_create_file("tasks", S_IFREG | S_IRUSR, clnt->cl_debugfs, clnt, &tasks_fops)) goto out_err; - err = -EINVAL; rcu_read_lock(); + xprt = rcu_dereference(clnt->cl_xprt); + /* no "debugfs" dentry? Don't bother with the symlink. */ + if (!xprt->debugfs) { + rcu_read_unlock(); + return; + } len = snprintf(name, sizeof(name), "../../rpc_xprt/%s", - rcu_dereference(clnt->cl_xprt)->debugfs->d_name.name); + xprt->debugfs->d_name.name); rcu_read_unlock(); + if (len >= sizeof(name)) goto out_err; - err = -ENOMEM; if (!debugfs_create_symlink("xprt", clnt->cl_debugfs, name)) goto out_err; - return 0; + return; out_err: debugfs_remove_recursive(clnt->cl_debugfs); clnt->cl_debugfs = NULL; - return err; } void @@ -226,33 +230,33 @@ static const struct file_operations xprt_info_fops = { .release = xprt_info_release, }; -int +void rpc_xprt_debugfs_register(struct rpc_xprt *xprt) { int len, id; static atomic_t cur_id; char name[9]; /* 8 hex digits + NULL term */ + if (!rpc_xprt_dir) + return; + id = (unsigned int)atomic_inc_return(&cur_id); len = snprintf(name, sizeof(name), "%x", id); if (len >= sizeof(name)) - return -EINVAL; + return; /* make the per-client dir */ xprt->debugfs = debugfs_create_dir(name, rpc_xprt_dir); if (!xprt->debugfs) - return -ENOMEM; + return; /* make tasks file */ if (!debugfs_create_file("info", S_IFREG | S_IRUSR, xprt->debugfs, xprt, &xprt_info_fops)) { debugfs_remove_recursive(xprt->debugfs); xprt->debugfs = NULL; - return -ENOMEM; } - - return 0; } void @@ -266,14 +270,17 @@ void __exit sunrpc_debugfs_exit(void) { debugfs_remove_recursive(topdir); + topdir = NULL; + rpc_clnt_dir = NULL; + rpc_xprt_dir = NULL; } -int __init +void __init sunrpc_debugfs_init(void) { topdir = debugfs_create_dir("sunrpc", NULL); if (!topdir) - goto out; + return; rpc_clnt_dir = debugfs_create_dir("rpc_clnt", topdir); if (!rpc_clnt_dir) @@ -283,10 +290,9 @@ sunrpc_debugfs_init(void) if (!rpc_xprt_dir) goto out_remove; - return 0; + return; out_remove: debugfs_remove_recursive(topdir); topdir = NULL; -out: - return -ENOMEM; + rpc_clnt_dir = NULL; } diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index e37fbed87956..ee5d3d253102 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -98,10 +98,7 @@ init_sunrpc(void) if (err) goto out4; - err = sunrpc_debugfs_init(); - if (err) - goto out5; - + sunrpc_debugfs_init(); #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) rpc_register_sysctl(); #endif @@ -109,8 +106,6 @@ init_sunrpc(void) init_socket_xprt(); /* clnt sock transport */ return 0; -out5: - unregister_rpc_pipefs(); out4: unregister_pernet_subsys(&sunrpc_net_ops); out3: diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index e3015aede0d9..9949722d99ce 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1331,7 +1331,6 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net) */ struct rpc_xprt *xprt_create_transport(struct xprt_create *args) { - int err; struct rpc_xprt *xprt; struct xprt_class *t; @@ -1372,11 +1371,7 @@ found: return ERR_PTR(-ENOMEM); } - err = rpc_xprt_debugfs_register(xprt); - if (err) { - xprt_destroy(xprt); - return ERR_PTR(err); - } + rpc_xprt_debugfs_register(xprt); dprintk("RPC: created transport %p with %u slots\n", xprt, xprt->max_reqs); -- cgit v1.2.3 From f9ebd61855253078fe8b07bacaf516337f8078e8 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Wed, 15 Apr 2015 13:00:04 -0400 Subject: NFS: Remove CONFIG_NFS_V4 checks from nfs_idmap.h The idmapper is completely internal to the NFS v4 module, so this macro will always evaluate to true. This patch also removes unnecessary includes of this file from the generic NFS client. Signed-off-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 1 - fs/nfs/super.c | 1 - include/linux/nfs_idmap.h | 11 ----------- 3 files changed, 13 deletions(-) (limited to 'include') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 19874151e95c..892aefff3630 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 322b2de02988..5cc3da9d9314 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff --git a/include/linux/nfs_idmap.h b/include/linux/nfs_idmap.h index 333844e38f66..daaf3ea5e9d8 100644 --- a/include/linux/nfs_idmap.h +++ b/include/linux/nfs_idmap.h @@ -46,19 +46,8 @@ struct nfs_server; struct nfs_fattr; struct nfs4_string; -#if IS_ENABLED(CONFIG_NFS_V4) int nfs_idmap_init(void); void nfs_idmap_quit(void); -#else -static inline int nfs_idmap_init(void) -{ - return 0; -} - -static inline void nfs_idmap_quit(void) -{} -#endif - int nfs_idmap_new(struct nfs_client *); void nfs_idmap_delete(struct nfs_client *); -- cgit v1.2.3 From 40c64c26a43494ba9982fd1b87dc54e3819566fc Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Wed, 15 Apr 2015 13:00:05 -0400 Subject: NFS: Move nfs_idmap.h into fs/nfs/ This file is only used internally to the NFS v4 module, so it doesn't need to be in the global include path. I also renamed it from nfs_idmap.h to nfs4idmap.h to emphasize that it's an NFSv4-only include file. Signed-off-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayout.c | 2 +- fs/nfs/idmap.c | 2 +- fs/nfs/nfs4client.c | 2 +- fs/nfs/nfs4idmap.h | 68 ++++++++++++++++++++++++++++++++++ fs/nfs/nfs4proc.c | 2 +- fs/nfs/nfs4state.c | 2 +- fs/nfs/nfs4super.c | 2 +- fs/nfs/nfs4sysctl.c | 2 +- fs/nfs/nfs4xdr.c | 2 +- include/linux/nfs_idmap.h | 68 ---------------------------------- include/uapi/linux/nfs_idmap.h | 2 +- 11 files changed, 77 insertions(+), 77 deletions(-) create mode 100644 fs/nfs/nfs4idmap.h delete mode 100644 include/linux/nfs_idmap.h (limited to 'include') diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index f3ff66e4fb6a..7d05089e52d6 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -11,10 +11,10 @@ #include #include -#include #include "flexfilelayout.h" #include "../nfs4session.h" +#include "../nfs4idmap.h" #include "../internal.h" #include "../delegation.h" #include "../nfs4trace.h" diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 857e2a99acc8..2e1737c40a29 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -49,6 +48,7 @@ #include "internal.h" #include "netns.h" +#include "nfs4idmap.h" #include "nfs4trace.h" #define NFS_UINT_MAXLEN 11 diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 86d6214ea022..43ca5a7ac1da 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -4,7 +4,6 @@ */ #include #include -#include #include #include #include @@ -15,6 +14,7 @@ #include "callback.h" #include "delegation.h" #include "nfs4session.h" +#include "nfs4idmap.h" #include "pnfs.h" #include "netns.h" diff --git a/fs/nfs/nfs4idmap.h b/fs/nfs/nfs4idmap.h new file mode 100644 index 000000000000..de44d7330ab3 --- /dev/null +++ b/fs/nfs/nfs4idmap.h @@ -0,0 +1,68 @@ +/* + * fs/nfs/nfs4idmap.h + * + * UID and GID to name mapping for clients. + * + * Copyright (c) 2002 The Regents of the University of Michigan. + * All rights reserved. + * + * Marius Aamodt Eriksen + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef NFS_IDMAP_H +#define NFS_IDMAP_H + +#include +#include + + +/* Forward declaration to make this header independent of others */ +struct nfs_client; +struct nfs_server; +struct nfs_fattr; +struct nfs4_string; + +int nfs_idmap_init(void); +void nfs_idmap_quit(void); +int nfs_idmap_new(struct nfs_client *); +void nfs_idmap_delete(struct nfs_client *); + +void nfs_fattr_init_names(struct nfs_fattr *fattr, + struct nfs4_string *owner_name, + struct nfs4_string *group_name); +void nfs_fattr_free_names(struct nfs_fattr *); +void nfs_fattr_map_and_free_names(struct nfs_server *, struct nfs_fattr *); + +int nfs_map_name_to_uid(const struct nfs_server *, const char *, size_t, kuid_t *); +int nfs_map_group_to_gid(const struct nfs_server *, const char *, size_t, kgid_t *); +int nfs_map_uid_to_name(const struct nfs_server *, kuid_t, char *, size_t); +int nfs_map_gid_to_group(const struct nfs_server *, kgid_t, char *, size_t); + +int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res); + +extern unsigned int nfs_idmap_cache_timeout; +#endif /* NFS_IDMAP_H */ diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6d48f37cfe8a..60396330044f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -51,7 +51,6 @@ #include #include #include -#include #include #include #include @@ -63,6 +62,7 @@ #include "callback.h" #include "pnfs.h" #include "netns.h" +#include "nfs4idmap.h" #include "nfs4session.h" #include "fscache.h" diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index f95e3b58bbc3..935a6ffe8643 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -57,6 +56,7 @@ #include "callback.h" #include "delegation.h" #include "internal.h" +#include "nfs4idmap.h" #include "nfs4session.h" #include "pnfs.h" #include "netns.h" diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index d91898193b2f..6fb7cb6b3f4b 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c @@ -3,12 +3,12 @@ */ #include #include -#include #include #include #include "delegation.h" #include "internal.h" #include "nfs4_fs.h" +#include "nfs4idmap.h" #include "dns_resolve.h" #include "pnfs.h" #include "nfs.h" diff --git a/fs/nfs/nfs4sysctl.c b/fs/nfs/nfs4sysctl.c index b6ebe7e445f6..0fbd3ab1be22 100644 --- a/fs/nfs/nfs4sysctl.c +++ b/fs/nfs/nfs4sysctl.c @@ -6,10 +6,10 @@ * Copyright (c) 2006 Trond Myklebust */ #include -#include #include #include "nfs4_fs.h" +#include "nfs4idmap.h" #include "callback.h" static const int nfs_set_port_min = 0; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index a26880cb8ce8..0aea97841d30 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -52,10 +52,10 @@ #include #include #include -#include #include "nfs4_fs.h" #include "internal.h" +#include "nfs4idmap.h" #include "nfs4session.h" #include "pnfs.h" #include "netns.h" diff --git a/include/linux/nfs_idmap.h b/include/linux/nfs_idmap.h deleted file mode 100644 index daaf3ea5e9d8..000000000000 --- a/include/linux/nfs_idmap.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * include/linux/nfs_idmap.h - * - * UID and GID to name mapping for clients. - * - * Copyright (c) 2002 The Regents of the University of Michigan. - * All rights reserved. - * - * Marius Aamodt Eriksen - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef NFS_IDMAP_H -#define NFS_IDMAP_H - -#include -#include - - -/* Forward declaration to make this header independent of others */ -struct nfs_client; -struct nfs_server; -struct nfs_fattr; -struct nfs4_string; - -int nfs_idmap_init(void); -void nfs_idmap_quit(void); -int nfs_idmap_new(struct nfs_client *); -void nfs_idmap_delete(struct nfs_client *); - -void nfs_fattr_init_names(struct nfs_fattr *fattr, - struct nfs4_string *owner_name, - struct nfs4_string *group_name); -void nfs_fattr_free_names(struct nfs_fattr *); -void nfs_fattr_map_and_free_names(struct nfs_server *, struct nfs_fattr *); - -int nfs_map_name_to_uid(const struct nfs_server *, const char *, size_t, kuid_t *); -int nfs_map_group_to_gid(const struct nfs_server *, const char *, size_t, kgid_t *); -int nfs_map_uid_to_name(const struct nfs_server *, kuid_t, char *, size_t); -int nfs_map_gid_to_group(const struct nfs_server *, kgid_t, char *, size_t); - -int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res); - -extern unsigned int nfs_idmap_cache_timeout; -#endif /* NFS_IDMAP_H */ diff --git a/include/uapi/linux/nfs_idmap.h b/include/uapi/linux/nfs_idmap.h index 8d4b1c7b24d4..038e36c96669 100644 --- a/include/uapi/linux/nfs_idmap.h +++ b/include/uapi/linux/nfs_idmap.h @@ -1,5 +1,5 @@ /* - * include/linux/nfs_idmap.h + * include/uapi/linux/nfs_idmap.h * * UID and GID to name mapping for clients. * -- cgit v1.2.3 From 1d8dc3d3c8f1d8ee1da9d54c5d7c8694419ade42 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Apr 2015 16:38:43 +0200 Subject: rhashtable: don't attempt to grow when at max_size The conversion of mac80211's station table to rhashtable had a bug that I found by accident in code review, that hadn't been found as rhashtable apparently managed to have a maximum hash chain length of one (!) in all our testing. In order to test the bug and verify the fix I set my rhashtable's max_size very low (4) in order to force getting hash collisions. At that point, rhashtable WARNed in rhashtable_insert_rehash() but didn't actually reject the hash table insertion. This caused it to lose insertions - my master list of stations would have 9 entries, but the rhashtable only had 5. This may warrant a deeper look, but that WARN_ON() just shouldn't happen. Fix this by not returning true from rht_grow_above_100() when the rhashtable's max_size has been reached - in this case the user is explicitly configuring it to be at most that big, so even if it's now above 100% it shouldn't attempt to resize. This fixes the "lost insertion" issue and consequently allows my code to display its error (and verify my fix for it.) Signed-off-by: Johannes Berg Acked-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/rhashtable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/rhashtable.h b/include/linux/rhashtable.h index e23d242d1230..dbcbcc59aa92 100644 --- a/include/linux/rhashtable.h +++ b/include/linux/rhashtable.h @@ -282,7 +282,8 @@ static inline bool rht_shrink_below_30(const struct rhashtable *ht, static inline bool rht_grow_above_100(const struct rhashtable *ht, const struct bucket_table *tbl) { - return atomic_read(&ht->nelems) > tbl->size; + return atomic_read(&ht->nelems) > tbl->size && + (!ht->p.max_size || tbl->size < ht->p.max_size); } /* The bucket lock is selected based on the hash and protects mutations -- cgit v1.2.3 From b357a364c57c940ddb932224542494363df37378 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 23 Apr 2015 18:03:44 -0700 Subject: inet: fix possible panic in reqsk_queue_unlink() [ 3897.923145] BUG: unable to handle kernel NULL pointer dereference at 0000000000000080 [ 3897.931025] IP: [] reqsk_timer_handler+0x1a6/0x243 There is a race when reqsk_timer_handler() and tcp_check_req() call inet_csk_reqsk_queue_unlink() on the same req at the same time. Before commit fa76ce7328b2 ("inet: get rid of central tcp/dccp listener timer"), listener spinlock was held and race could not happen. To solve this bug, we change reqsk_queue_unlink() to not assume req must be found, and we return a status, to conditionally release a refcount on the request sock. This also means tcp_check_req() in non fastopen case might or not consume req refcount, so tcp_v6_hnd_req() & tcp_v4_hnd_req() have to properly handle this. (Same remark for dccp_check_req() and its callers) inet_csk_reqsk_queue_drop() is now too big to be inlined, as it is called 4 times in tcp and 3 times in dccp. Fixes: fa76ce7328b2 ("inet: get rid of central tcp/dccp listener timer") Signed-off-by: Eric Dumazet Reported-by: Yuchung Cheng Signed-off-by: David S. Miller --- include/net/inet_connection_sock.h | 20 +------------------- include/net/request_sock.h | 18 ------------------ net/dccp/ipv4.c | 3 ++- net/dccp/ipv6.c | 3 ++- net/dccp/minisocks.c | 3 +-- net/ipv4/inet_connection_sock.c | 34 ++++++++++++++++++++++++++++++++++ net/ipv4/tcp_ipv4.c | 3 ++- net/ipv4/tcp_minisocks.c | 7 ++++--- net/ipv6/tcp_ipv6.c | 3 ++- 9 files changed, 48 insertions(+), 46 deletions(-) (limited to 'include') diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index 7b5887cd1172..48a815823587 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -279,12 +279,6 @@ static inline void inet_csk_reqsk_queue_add(struct sock *sk, void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req, unsigned long timeout); -static inline void inet_csk_reqsk_queue_removed(struct sock *sk, - struct request_sock *req) -{ - reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req); -} - static inline void inet_csk_reqsk_queue_added(struct sock *sk, const unsigned long timeout) { @@ -306,19 +300,7 @@ static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk) return reqsk_queue_is_full(&inet_csk(sk)->icsk_accept_queue); } -static inline void inet_csk_reqsk_queue_unlink(struct sock *sk, - struct request_sock *req) -{ - reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req); -} - -static inline void inet_csk_reqsk_queue_drop(struct sock *sk, - struct request_sock *req) -{ - inet_csk_reqsk_queue_unlink(sk, req); - inet_csk_reqsk_queue_removed(sk, req); - reqsk_put(req); -} +void inet_csk_reqsk_queue_drop(struct sock *sk, struct request_sock *req); void inet_csk_destroy_sock(struct sock *sk); void inet_csk_prepare_forced_close(struct sock *sk); diff --git a/include/net/request_sock.h b/include/net/request_sock.h index fe41f3ceb008..9f4265ce8892 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -212,24 +212,6 @@ static inline int reqsk_queue_empty(struct request_sock_queue *queue) return queue->rskq_accept_head == NULL; } -static inline void reqsk_queue_unlink(struct request_sock_queue *queue, - struct request_sock *req) -{ - struct listen_sock *lopt = queue->listen_opt; - struct request_sock **prev; - - spin_lock(&queue->syn_wait_lock); - - prev = &lopt->syn_table[req->rsk_hash]; - while (*prev != req) - prev = &(*prev)->dl_next; - *prev = req->dl_next; - - spin_unlock(&queue->syn_wait_lock); - if (del_timer(&req->rsk_timer)) - reqsk_put(req); -} - static inline void reqsk_queue_add(struct request_sock_queue *queue, struct request_sock *req, struct sock *parent, diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 2b4f21d34df6..ccf4c5629b3c 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -453,7 +453,8 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) iph->saddr, iph->daddr); if (req) { nsk = dccp_check_req(sk, skb, req); - reqsk_put(req); + if (!nsk) + reqsk_put(req); return nsk; } nsk = inet_lookup_established(sock_net(sk), &dccp_hashinfo, diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 9d0551092c6c..5165571f397a 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -301,7 +301,8 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) &iph->daddr, inet6_iif(skb)); if (req) { nsk = dccp_check_req(sk, skb, req); - reqsk_put(req); + if (!nsk) + reqsk_put(req); return nsk; } nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo, diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 5f566663e47f..30addee2dd03 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -186,8 +186,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, if (child == NULL) goto listen_overflow; - inet_csk_reqsk_queue_unlink(sk, req); - inet_csk_reqsk_queue_removed(sk, req); + inet_csk_reqsk_queue_drop(sk, req); inet_csk_reqsk_queue_add(sk, req, child); out: return child; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 5c3dd6267ed3..8976ca423a07 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -564,6 +564,40 @@ int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req) } EXPORT_SYMBOL(inet_rtx_syn_ack); +/* return true if req was found in the syn_table[] */ +static bool reqsk_queue_unlink(struct request_sock_queue *queue, + struct request_sock *req) +{ + struct listen_sock *lopt = queue->listen_opt; + struct request_sock **prev; + bool found = false; + + spin_lock(&queue->syn_wait_lock); + + for (prev = &lopt->syn_table[req->rsk_hash]; *prev != NULL; + prev = &(*prev)->dl_next) { + if (*prev == req) { + *prev = req->dl_next; + found = true; + break; + } + } + + spin_unlock(&queue->syn_wait_lock); + if (del_timer(&req->rsk_timer)) + reqsk_put(req); + return found; +} + +void inet_csk_reqsk_queue_drop(struct sock *sk, struct request_sock *req) +{ + if (reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req)) { + reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req); + reqsk_put(req); + } +} +EXPORT_SYMBOL(inet_csk_reqsk_queue_drop); + static void reqsk_timer_handler(unsigned long data) { struct request_sock *req = (struct request_sock *)data; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 3571f2be4470..fc1c658ec6c1 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1348,7 +1348,8 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) req = inet_csk_search_req(sk, th->source, iph->saddr, iph->daddr); if (req) { nsk = tcp_check_req(sk, skb, req, false); - reqsk_put(req); + if (!nsk) + reqsk_put(req); return nsk; } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 63d6311b5365..e5d7649136fc 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -755,10 +755,11 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, if (!child) goto listen_overflow; - inet_csk_reqsk_queue_unlink(sk, req); - inet_csk_reqsk_queue_removed(sk, req); - + inet_csk_reqsk_queue_drop(sk, req); inet_csk_reqsk_queue_add(sk, req, child); + /* Warning: caller must not call reqsk_put(req); + * child stole last reference on it. + */ return child; listen_overflow: diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index ad51df85aa00..b6575d665568 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -946,7 +946,8 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb) &ipv6_hdr(skb)->daddr, tcp_v6_iif(skb)); if (req) { nsk = tcp_check_req(sk, skb, req, false); - reqsk_put(req); + if (!nsk) + reqsk_put(req); return nsk; } nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo, -- cgit v1.2.3 From 547c4b547e07dcc60874b6ef6252dd49ff74aec1 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 20 Apr 2015 12:35:47 +0200 Subject: netfilter: bridge: fix NULL deref in physin/out ifindex helpers Might not have an outdev yet. We'll oops when iface goes down while skbs are still nfqueue'd: RIP: 0010:[] [] dev_cmp+0x4f/0x80 nfqnl_rcv_dev_event+0xe2/0x150 notifier_call_chain+0x53/0xa0 Fixes: c737b7c4510026 ("netfilter: bridge: add helpers for fetching physin/outdev") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter_bridge.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h index ab8f76dba668..f2fdb5a52070 100644 --- a/include/linux/netfilter_bridge.h +++ b/include/linux/netfilter_bridge.h @@ -39,12 +39,24 @@ static inline void br_drop_fake_rtable(struct sk_buff *skb) static inline int nf_bridge_get_physinif(const struct sk_buff *skb) { - return skb->nf_bridge ? skb->nf_bridge->physindev->ifindex : 0; + struct nf_bridge_info *nf_bridge; + + if (skb->nf_bridge == NULL) + return 0; + + nf_bridge = skb->nf_bridge; + return nf_bridge->physindev ? nf_bridge->physindev->ifindex : 0; } static inline int nf_bridge_get_physoutif(const struct sk_buff *skb) { - return skb->nf_bridge ? skb->nf_bridge->physoutdev->ifindex : 0; + struct nf_bridge_info *nf_bridge; + + if (skb->nf_bridge == NULL) + return 0; + + nf_bridge = skb->nf_bridge; + return nf_bridge->physoutdev ? nf_bridge->physoutdev->ifindex : 0; } static inline struct net_device * -- cgit v1.2.3 From 1dcc73d7bb0429994c54d33b40c5fb82b741a791 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 22 Apr 2015 18:20:04 +0100 Subject: irqchip: gic: Drop support for gic_arch_extn Now that the users of gic_arch_extn have been fixed, drop the "feature" for good. This leads to the removal of some now useless locking. Signed-off-by: Marc Zyngier Cc: linux-arm-kernel@lists.infradead.org Cc: Jason Cooper Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic.c | 71 +---------------------------------------- include/linux/irqchip/arm-gic.h | 2 -- 2 files changed, 1 insertion(+), 72 deletions(-) (limited to 'include') diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index a6ce3476834e..dd989148e689 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -80,19 +80,6 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock); #define NR_GIC_CPU_IF 8 static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly; -/* - * Supported arch specific GIC irq extension. - * Default make them NULL. - */ -struct irq_chip gic_arch_extn = { - .irq_eoi = NULL, - .irq_mask = NULL, - .irq_unmask = NULL, - .irq_retrigger = NULL, - .irq_set_type = NULL, - .irq_set_wake = NULL, -}; - #ifndef MAX_GIC_NR #define MAX_GIC_NR 1 #endif @@ -165,34 +152,16 @@ static int gic_peek_irq(struct irq_data *d, u32 offset) static void gic_mask_irq(struct irq_data *d) { - unsigned long flags; - - raw_spin_lock_irqsave(&irq_controller_lock, flags); gic_poke_irq(d, GIC_DIST_ENABLE_CLEAR); - if (gic_arch_extn.irq_mask) - gic_arch_extn.irq_mask(d); - raw_spin_unlock_irqrestore(&irq_controller_lock, flags); } static void gic_unmask_irq(struct irq_data *d) { - unsigned long flags; - - raw_spin_lock_irqsave(&irq_controller_lock, flags); - if (gic_arch_extn.irq_unmask) - gic_arch_extn.irq_unmask(d); gic_poke_irq(d, GIC_DIST_ENABLE_SET); - raw_spin_unlock_irqrestore(&irq_controller_lock, flags); } static void gic_eoi_irq(struct irq_data *d) { - if (gic_arch_extn.irq_eoi) { - raw_spin_lock(&irq_controller_lock); - gic_arch_extn.irq_eoi(d); - raw_spin_unlock(&irq_controller_lock); - } - writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); } @@ -249,8 +218,6 @@ static int gic_set_type(struct irq_data *d, unsigned int type) { void __iomem *base = gic_dist_base(d); unsigned int gicirq = gic_irq(d); - unsigned long flags; - int ret; /* Interrupt configuration for SGIs can't be changed */ if (gicirq < 16) @@ -261,25 +228,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) type != IRQ_TYPE_EDGE_RISING) return -EINVAL; - raw_spin_lock_irqsave(&irq_controller_lock, flags); - - if (gic_arch_extn.irq_set_type) - gic_arch_extn.irq_set_type(d, type); - - ret = gic_configure_irq(gicirq, type, base, NULL); - - raw_spin_unlock_irqrestore(&irq_controller_lock, flags); - - return ret; -} - -static int gic_retrigger(struct irq_data *d) -{ - if (gic_arch_extn.irq_retrigger) - return gic_arch_extn.irq_retrigger(d); - - /* the genirq layer expects 0 if we can't retrigger in hardware */ - return 0; + return gic_configure_irq(gicirq, type, base, NULL); } #ifdef CONFIG_SMP @@ -310,21 +259,6 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, } #endif -#ifdef CONFIG_PM -static int gic_set_wake(struct irq_data *d, unsigned int on) -{ - int ret = -ENXIO; - - if (gic_arch_extn.irq_set_wake) - ret = gic_arch_extn.irq_set_wake(d, on); - - return ret; -} - -#else -#define gic_set_wake NULL -#endif - static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) { u32 irqstat, irqnr; @@ -383,11 +317,9 @@ static struct irq_chip gic_chip = { .irq_unmask = gic_unmask_irq, .irq_eoi = gic_eoi_irq, .irq_set_type = gic_set_type, - .irq_retrigger = gic_retrigger, #ifdef CONFIG_SMP .irq_set_affinity = gic_set_affinity, #endif - .irq_set_wake = gic_set_wake, .irq_get_irqchip_state = gic_irq_get_irqchip_state, .irq_set_irqchip_state = gic_irq_set_irqchip_state, }; @@ -1053,7 +985,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, set_handle_irq(gic_handle_irq); } - gic_chip.flags |= gic_arch_extn.flags; gic_dist_init(gic); gic_cpu_init(gic); gic_pm_init(gic); diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 36ec4ae74634..9de976b4f9a7 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -95,8 +95,6 @@ struct device_node; -extern struct irq_chip gic_arch_extn; - void gic_set_irqchip_flags(unsigned long flags); void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *, u32 offset, struct device_node *); -- cgit v1.2.3 From fe0f07d08ee35fb13d2cb048970072fe4f71ad14 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 15 Apr 2015 17:05:48 -0600 Subject: direct-io: only inc/dec inode->i_dio_count for file systems do_blockdev_direct_IO() increments and decrements the inode ->i_dio_count for each IO operation. It does this to protect against truncate of a file. Block devices don't need this sort of protection. For a capable multiqueue setup, this atomic int is the only shared state between applications accessing the device for O_DIRECT, and it presents a scaling wall for that. In my testing, as much as 30% of system time is spent incrementing and decrementing this value. A mixed read/write workload improved from ~2.5M IOPS to ~9.6M IOPS, with better latencies too. Before: clat percentiles (usec): | 1.00th=[ 33], 5.00th=[ 34], 10.00th=[ 34], 20.00th=[ 34], | 30.00th=[ 34], 40.00th=[ 34], 50.00th=[ 35], 60.00th=[ 35], | 70.00th=[ 35], 80.00th=[ 35], 90.00th=[ 37], 95.00th=[ 80], | 99.00th=[ 98], 99.50th=[ 151], 99.90th=[ 155], 99.95th=[ 155], | 99.99th=[ 165] After: clat percentiles (usec): | 1.00th=[ 95], 5.00th=[ 108], 10.00th=[ 129], 20.00th=[ 149], | 30.00th=[ 155], 40.00th=[ 161], 50.00th=[ 167], 60.00th=[ 171], | 70.00th=[ 177], 80.00th=[ 185], 90.00th=[ 201], 95.00th=[ 270], | 99.00th=[ 390], 99.50th=[ 398], 99.90th=[ 418], 99.95th=[ 422], | 99.99th=[ 438] In other setups, Robert Elliott reported seeing good performance improvements: https://lkml.org/lkml/2015/4/3/557 The more applications accessing the device, the worse it gets. Add a new direct-io flags, DIO_SKIP_DIO_COUNT, which tells do_blockdev_direct_IO() that it need not worry about incrementing or decrementing the inode i_dio_count for this caller. Cc: Andrew Morton Cc: Christoph Hellwig Cc: Theodore Ts'o Cc: Elliott, Robert (Server Storage) Cc: Al Viro Signed-off-by: Jens Axboe Signed-off-by: Al Viro --- fs/block_dev.c | 3 ++- fs/btrfs/inode.c | 6 +++--- fs/dax.c | 4 ++-- fs/direct-io.c | 7 +++++-- fs/ext4/indirect.c | 6 +++--- fs/ext4/inode.c | 4 ++-- fs/inode.c | 14 -------------- fs/nfs/direct.c | 10 +++++----- include/linux/fs.h | 29 ++++++++++++++++++++++++++++- 9 files changed, 50 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/fs/block_dev.c b/fs/block_dev.c index 79b4fa3b391d..c7e4163ede87 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -152,7 +152,8 @@ blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset) struct inode *inode = file->f_mapping->host; return __blockdev_direct_IO(iocb, inode, I_BDEV(inode), iter, offset, - blkdev_get_block, NULL, NULL, 0); + blkdev_get_block, NULL, NULL, + DIO_SKIP_DIO_COUNT); } int __sync_blockdev(struct block_device *bdev, int wait) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 811576346a92..9b774a0c9ca6 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8129,7 +8129,7 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, if (check_direct_IO(BTRFS_I(inode)->root, iocb, iter, offset)) return 0; - atomic_inc(&inode->i_dio_count); + inode_dio_begin(inode); smp_mb__after_atomic(); /* @@ -8169,7 +8169,7 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, current->journal_info = &outstanding_extents; } else if (test_bit(BTRFS_INODE_READDIO_NEED_LOCK, &BTRFS_I(inode)->runtime_flags)) { - inode_dio_done(inode); + inode_dio_end(inode); flags = DIO_LOCKING | DIO_SKIP_HOLES; wakeup = false; } @@ -8188,7 +8188,7 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter, } out: if (wakeup) - inode_dio_done(inode); + inode_dio_end(inode); if (relock) mutex_lock(&inode->i_mutex); diff --git a/fs/dax.c b/fs/dax.c index a27846946525..cdde2b354e47 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -209,7 +209,7 @@ ssize_t dax_do_io(struct kiocb *iocb, struct inode *inode, } /* Protects against truncate */ - atomic_inc(&inode->i_dio_count); + inode_dio_begin(inode); retval = dax_io(inode, iter, pos, end, get_block, &bh); @@ -219,7 +219,7 @@ ssize_t dax_do_io(struct kiocb *iocb, struct inode *inode, if ((retval > 0) && end_io) end_io(iocb, pos, retval, bh.b_private); - inode_dio_done(inode); + inode_dio_end(inode); out: return retval; } diff --git a/fs/direct-io.c b/fs/direct-io.c index c3b560b24a46..745d2342651a 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -253,7 +253,9 @@ static ssize_t dio_complete(struct dio *dio, loff_t offset, ssize_t ret, if (dio->end_io && dio->result) dio->end_io(dio->iocb, offset, transferred, dio->private); - inode_dio_done(dio->inode); + if (!(dio->flags & DIO_SKIP_DIO_COUNT)) + inode_dio_end(dio->inode); + if (is_async) { if (dio->rw & WRITE) { int err; @@ -1195,7 +1197,8 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, /* * Will be decremented at I/O completion time. */ - atomic_inc(&inode->i_dio_count); + if (!(dio->flags & DIO_SKIP_DIO_COUNT)) + inode_dio_begin(inode); retval = 0; sdio.blkbits = blkbits; diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index 3580629e42d3..958824019509 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c @@ -682,11 +682,11 @@ retry: * via ext4_inode_block_unlocked_dio(). Check inode's state * while holding extra i_dio_count ref. */ - atomic_inc(&inode->i_dio_count); + inode_dio_begin(inode); smp_mb(); if (unlikely(ext4_test_inode_state(inode, EXT4_STATE_DIOREAD_LOCK))) { - inode_dio_done(inode); + inode_dio_end(inode); goto locked; } if (IS_DAX(inode)) @@ -697,7 +697,7 @@ retry: inode->i_sb->s_bdev, iter, offset, ext4_get_block, NULL, NULL, 0); - inode_dio_done(inode); + inode_dio_end(inode); } else { locked: if (IS_DAX(inode)) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 063052e4aa8b..bccec41fb94b 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2977,7 +2977,7 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter, * overwrite DIO as i_dio_count needs to be incremented under i_mutex. */ if (iov_iter_rw(iter) == WRITE) - atomic_inc(&inode->i_dio_count); + inode_dio_begin(inode); /* If we do a overwrite dio, i_mutex locking can be released */ overwrite = *((int *)iocb->private); @@ -3079,7 +3079,7 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter, retake_lock: if (iov_iter_rw(iter) == WRITE) - inode_dio_done(inode); + inode_dio_end(inode); /* take i_mutex locking again if we do a ovewrite dio */ if (overwrite) { up_read(&EXT4_I(inode)->i_data_sem); diff --git a/fs/inode.c b/fs/inode.c index 94886f9fbb06..ea37cd17b53f 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1945,20 +1945,6 @@ void inode_dio_wait(struct inode *inode) } EXPORT_SYMBOL(inode_dio_wait); -/* - * inode_dio_done - signal finish of a direct I/O requests - * @inode: inode the direct I/O happens on - * - * This is called once we've finished processing a direct I/O request, - * and is used to wake up callers waiting for direct I/O to be quiesced. - */ -void inode_dio_done(struct inode *inode) -{ - if (atomic_dec_and_test(&inode->i_dio_count)) - wake_up_bit(&inode->i_state, __I_DIO_WAKEUP); -} -EXPORT_SYMBOL(inode_dio_done); - /* * inode_set_flags - atomically set some inode flags * diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index ed0e6031be88..b2cbc3a6cdd9 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -386,7 +386,7 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq, bool write) if (write) nfs_zap_mapping(inode, inode->i_mapping); - inode_dio_done(inode); + inode_dio_end(inode); if (dreq->iocb) { long res = (long) dreq->error; @@ -486,7 +486,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, &nfs_direct_read_completion_ops); get_dreq(dreq); desc.pg_dreq = dreq; - atomic_inc(&inode->i_dio_count); + inode_dio_begin(inode); while (iov_iter_count(iter)) { struct page **pagevec; @@ -538,7 +538,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, * generic layer handle the completion. */ if (requested_bytes == 0) { - inode_dio_done(inode); + inode_dio_end(inode); nfs_direct_req_release(dreq); return result < 0 ? result : -EIO; } @@ -872,7 +872,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, &nfs_direct_write_completion_ops); desc.pg_dreq = dreq; get_dreq(dreq); - atomic_inc(&inode->i_dio_count); + inode_dio_begin(inode); NFS_I(inode)->write_io += iov_iter_count(iter); while (iov_iter_count(iter)) { @@ -928,7 +928,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, * generic layer handle the completion. */ if (requested_bytes == 0) { - inode_dio_done(inode); + inode_dio_end(inode); nfs_direct_req_release(dreq); return result < 0 ? result : -EIO; } diff --git a/include/linux/fs.h b/include/linux/fs.h index b1d7db28c13c..9055eefa92c7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2635,6 +2635,9 @@ enum { /* filesystem can handle aio writes beyond i_size */ DIO_ASYNC_EXTEND = 0x04, + + /* inode/fs/bdev does not need truncate protection */ + DIO_SKIP_DIO_COUNT = 0x08, }; void dio_end_io(struct bio *bio, int error); @@ -2657,7 +2660,31 @@ static inline ssize_t blockdev_direct_IO(struct kiocb *iocb, #endif void inode_dio_wait(struct inode *inode); -void inode_dio_done(struct inode *inode); + +/* + * inode_dio_begin - signal start of a direct I/O requests + * @inode: inode the direct I/O happens on + * + * This is called once we've finished processing a direct I/O request, + * and is used to wake up callers waiting for direct I/O to be quiesced. + */ +static inline void inode_dio_begin(struct inode *inode) +{ + atomic_inc(&inode->i_dio_count); +} + +/* + * inode_dio_end - signal finish of a direct I/O requests + * @inode: inode the direct I/O happens on + * + * This is called once we've finished processing a direct I/O request, + * and is used to wake up callers waiting for direct I/O to be quiesced. + */ +static inline void inode_dio_end(struct inode *inode) +{ + if (atomic_dec_and_test(&inode->i_dio_count)) + wake_up_bit(&inode->i_state, __I_DIO_WAKEUP); +} extern void inode_set_flags(struct inode *inode, unsigned int flags, unsigned int mask); -- cgit v1.2.3 From ac74d8d65c83d8061034d0908e1eab6a0c24f923 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Thu, 16 Apr 2015 15:04:56 -0500 Subject: fix I_DIO_WAKEUP definition I_DIO_WAKEUP is never directly used, but fix it up anyway. Signed-off-by: Eric Sandeen Signed-off-by: Al Viro --- include/linux/fs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/fs.h b/include/linux/fs.h index 9055eefa92c7..43565607088e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1812,7 +1812,7 @@ struct super_operations { #define I_SYNC (1 << __I_SYNC) #define I_REFERENCED (1 << 8) #define __I_DIO_WAKEUP 9 -#define I_DIO_WAKEUP (1 << I_DIO_WAKEUP) +#define I_DIO_WAKEUP (1 << __I_DIO_WAKEUP) #define I_LINKABLE (1 << 10) #define I_DIRTY_TIME (1 << 11) #define __I_DIRTY_TIME_EXPIRED 12 -- cgit v1.2.3 From 2ea2f62c8bda242433809c7f4e9eae1c52c40bbe Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 24 Apr 2015 16:05:01 -0700 Subject: net: fix crash in build_skb() When I added pfmemalloc support in build_skb(), I forgot netlink was using build_skb() with a vmalloc() area. In this patch I introduce __build_skb() for netlink use, and build_skb() is a wrapper handling both skb->head_frag and skb->pfmemalloc This means netlink no longer has to hack skb->head_frag [ 1567.700067] kernel BUG at arch/x86/mm/physaddr.c:26! [ 1567.700067] invalid opcode: 0000 [#1] PREEMPT SMP KASAN [ 1567.700067] Dumping ftrace buffer: [ 1567.700067] (ftrace buffer empty) [ 1567.700067] Modules linked in: [ 1567.700067] CPU: 9 PID: 16186 Comm: trinity-c182 Not tainted 4.0.0-next-20150424-sasha-00037-g4796e21 #2167 [ 1567.700067] task: ffff880127efb000 ti: ffff880246770000 task.ti: ffff880246770000 [ 1567.700067] RIP: __phys_addr (arch/x86/mm/physaddr.c:26 (discriminator 3)) [ 1567.700067] RSP: 0018:ffff8802467779d8 EFLAGS: 00010202 [ 1567.700067] RAX: 000041000ed8e000 RBX: ffffc9008ed8e000 RCX: 000000000000002c [ 1567.700067] RDX: 0000000000000004 RSI: 0000000000000000 RDI: ffffffffb3fd6049 [ 1567.700067] RBP: ffff8802467779f8 R08: 0000000000000019 R09: ffff8801d0168000 [ 1567.700067] R10: ffff8801d01680c7 R11: ffffed003a02d019 R12: ffffc9000ed8e000 [ 1567.700067] R13: 0000000000000f40 R14: 0000000000001180 R15: ffffc9000ed8e000 [ 1567.700067] FS: 00007f2a7da3f700(0000) GS:ffff8801d1000000(0000) knlGS:0000000000000000 [ 1567.700067] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 1567.700067] CR2: 0000000000738308 CR3: 000000022e329000 CR4: 00000000000007e0 [ 1567.700067] Stack: [ 1567.700067] ffffc9000ed8e000 ffff8801d0168000 ffffc9000ed8e000 ffff8801d0168000 [ 1567.700067] ffff880246777a28 ffffffffad7c0a21 0000000000001080 ffff880246777c08 [ 1567.700067] ffff88060d302e68 ffff880246777b58 ffff880246777b88 ffffffffad9a6821 [ 1567.700067] Call Trace: [ 1567.700067] build_skb (include/linux/mm.h:508 net/core/skbuff.c:316) [ 1567.700067] netlink_sendmsg (net/netlink/af_netlink.c:1633 net/netlink/af_netlink.c:2329) [ 1567.774369] ? sched_clock_cpu (kernel/sched/clock.c:311) [ 1567.774369] ? netlink_unicast (net/netlink/af_netlink.c:2273) [ 1567.774369] ? netlink_unicast (net/netlink/af_netlink.c:2273) [ 1567.774369] sock_sendmsg (net/socket.c:614 net/socket.c:623) [ 1567.774369] sock_write_iter (net/socket.c:823) [ 1567.774369] ? sock_sendmsg (net/socket.c:806) [ 1567.774369] __vfs_write (fs/read_write.c:479 fs/read_write.c:491) [ 1567.774369] ? get_lock_stats (kernel/locking/lockdep.c:249) [ 1567.774369] ? default_llseek (fs/read_write.c:487) [ 1567.774369] ? vtime_account_user (kernel/sched/cputime.c:701) [ 1567.774369] ? rw_verify_area (fs/read_write.c:406 (discriminator 4)) [ 1567.774369] vfs_write (fs/read_write.c:539) [ 1567.774369] SyS_write (fs/read_write.c:586 fs/read_write.c:577) [ 1567.774369] ? SyS_read (fs/read_write.c:577) [ 1567.774369] ? __this_cpu_preempt_check (lib/smp_processor_id.c:63) [ 1567.774369] ? trace_hardirqs_on_caller (kernel/locking/lockdep.c:2594 kernel/locking/lockdep.c:2636) [ 1567.774369] ? trace_hardirqs_on_thunk (arch/x86/lib/thunk_64.S:42) [ 1567.774369] system_call_fastpath (arch/x86/kernel/entry_64.S:261) Fixes: 79930f5892e ("net: do not deplete pfmemalloc reserve") Signed-off-by: Eric Dumazet Reported-by: Sasha Levin Signed-off-by: David S. Miller --- include/linux/skbuff.h | 1 + net/core/skbuff.c | 31 ++++++++++++++++++++++--------- net/netlink/af_netlink.c | 6 ++---- 3 files changed, 25 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 06793b598f44..66e374d62f64 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -773,6 +773,7 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from, struct sk_buff *__alloc_skb(unsigned int size, gfp_t priority, int flags, int node); +struct sk_buff *__build_skb(void *data, unsigned int frag_size); struct sk_buff *build_skb(void *data, unsigned int frag_size); static inline struct sk_buff *alloc_skb(unsigned int size, gfp_t priority) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 456ead534e10..3cfff2a3d651 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -280,13 +280,14 @@ nodata: EXPORT_SYMBOL(__alloc_skb); /** - * build_skb - build a network buffer + * __build_skb - build a network buffer * @data: data buffer provided by caller - * @frag_size: size of fragment, or 0 if head was kmalloced + * @frag_size: size of data, or 0 if head was kmalloced * * Allocate a new &sk_buff. Caller provides space holding head and * skb_shared_info. @data must have been allocated by kmalloc() only if - * @frag_size is 0, otherwise data should come from the page allocator. + * @frag_size is 0, otherwise data should come from the page allocator + * or vmalloc() * The return is the new skb buffer. * On a failure the return is %NULL, and @data is not freed. * Notes : @@ -297,7 +298,7 @@ EXPORT_SYMBOL(__alloc_skb); * before giving packet to stack. * RX rings only contains data buffers, not full skbs. */ -struct sk_buff *build_skb(void *data, unsigned int frag_size) +struct sk_buff *__build_skb(void *data, unsigned int frag_size) { struct skb_shared_info *shinfo; struct sk_buff *skb; @@ -311,11 +312,6 @@ struct sk_buff *build_skb(void *data, unsigned int frag_size) memset(skb, 0, offsetof(struct sk_buff, tail)); skb->truesize = SKB_TRUESIZE(size); - if (frag_size) { - skb->head_frag = 1; - if (virt_to_head_page(data)->pfmemalloc) - skb->pfmemalloc = 1; - } atomic_set(&skb->users, 1); skb->head = data; skb->data = data; @@ -332,6 +328,23 @@ struct sk_buff *build_skb(void *data, unsigned int frag_size) return skb; } + +/* build_skb() is wrapper over __build_skb(), that specifically + * takes care of skb->head and skb->pfmemalloc + * This means that if @frag_size is not zero, then @data must be backed + * by a page fragment, not kmalloc() or vmalloc() + */ +struct sk_buff *build_skb(void *data, unsigned int frag_size) +{ + struct sk_buff *skb = __build_skb(data, frag_size); + + if (skb && frag_size) { + skb->head_frag = 1; + if (virt_to_head_page(data)->pfmemalloc) + skb->pfmemalloc = 1; + } + return skb; +} EXPORT_SYMBOL(build_skb); struct netdev_alloc_cache { diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 19909d0786a2..ec4adbdcb9b4 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1629,13 +1629,11 @@ static struct sk_buff *netlink_alloc_large_skb(unsigned int size, if (data == NULL) return NULL; - skb = build_skb(data, size); + skb = __build_skb(data, size); if (skb == NULL) vfree(data); - else { - skb->head_frag = 0; + else skb->destructor = netlink_skb_destructor; - } return skb; } -- cgit v1.2.3 From 8393b811f38acdf7fd8da2028708edad3e68ce1f Mon Sep 17 00:00:00 2001 From: Gabriele Mazzotta Date: Sat, 25 Apr 2015 19:52:36 +0200 Subject: libata: Add helper to determine when PHY events should be ignored This is a preparation commit that will allow to add other criteria according to which PHY events should be dropped. Signed-off-by: Gabriele Mazzotta Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org --- drivers/ata/libahci.c | 3 +-- drivers/ata/libata-core.c | 19 +++++++++++++++++++ include/linux/libata.h | 1 + 3 files changed, 21 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 61a9c07e0dff..287c4ba0219f 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1707,8 +1707,7 @@ static void ahci_handle_port_interrupt(struct ata_port *ap, if (unlikely(resetting)) status &= ~PORT_IRQ_BAD_PMP; - /* if LPM is enabled, PHYRDY doesn't mean anything */ - if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) { + if (sata_lpm_ignore_phy_events(&ap->link)) { status &= ~PORT_IRQ_PHYRDY; ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG); } diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f6cb1f1b30b7..12adcf78f94b 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6752,6 +6752,25 @@ u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val, return tmp; } +/** + * sata_lpm_ignore_phy_events - test if PHY event should be ignored + * @link: Link receiving the event + * + * Test whether the received PHY event has to be ignored or not. + * + * LOCKING: + * None: + * + * RETURNS: + * True if the event has to be ignored. + */ +bool sata_lpm_ignore_phy_events(struct ata_link *link) +{ + /* if LPM is enabled, PHYRDY doesn't mean anything */ + return !!(link->lpm_policy > ATA_LPM_MAX_POWER); +} +EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events); + /* * Dummy port_ops */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 8dad4a307bb8..6138d87277af 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1201,6 +1201,7 @@ extern struct ata_device *ata_dev_pair(struct ata_device *adev); extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap); extern void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, struct list_head *eh_q); +extern bool sata_lpm_ignore_phy_events(struct ata_link *link); extern int ata_cable_40wire(struct ata_port *ap); extern int ata_cable_80wire(struct ata_port *ap); -- cgit v1.2.3 From 09c5b4803a80a5451d950d6a539d2eb311dc0fb1 Mon Sep 17 00:00:00 2001 From: Gabriele Mazzotta Date: Sat, 25 Apr 2015 19:52:37 +0200 Subject: libata: Ignore spurious PHY event on LPM policy change When the LPM policy is set to ATA_LPM_MAX_POWER, the device might generate a spurious PHY event that cuases errors on the link. Ignore this event if it occured within 10s after the policy change. The timeout was chosen observing that on a Dell XPS13 9333 these spurious events can occur up to roughly 6s after the policy change. Link: http://lkml.kernel.org/g/3352987.ugV1Ipy7Z5@xps13 Signed-off-by: Gabriele Mazzotta Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org --- drivers/ata/libata-core.c | 15 ++++++++++++++- drivers/ata/libata-eh.c | 3 +++ include/linux/libata.h | 9 +++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 12adcf78f94b..85e659945c12 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6766,8 +6766,21 @@ u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val, */ bool sata_lpm_ignore_phy_events(struct ata_link *link) { + unsigned long lpm_timeout = link->last_lpm_change + + msecs_to_jiffies(ATA_TMOUT_SPURIOUS_PHY); + /* if LPM is enabled, PHYRDY doesn't mean anything */ - return !!(link->lpm_policy > ATA_LPM_MAX_POWER); + if (link->lpm_policy > ATA_LPM_MAX_POWER) + return true; + + /* ignore the first PHY event after the LPM policy changed + * as it is might be spurious + */ + if ((link->flags & ATA_LFLAG_CHANGED) && + time_before(jiffies, lpm_timeout)) + return true; + + return false; } EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 07f41be38fbe..cf0022ec07f2 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3597,6 +3597,9 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, } } + link->last_lpm_change = jiffies; + link->flags |= ATA_LFLAG_CHANGED; + return 0; fail: diff --git a/include/linux/libata.h b/include/linux/libata.h index 6138d87277af..28aeae46f355 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -205,6 +205,7 @@ enum { ATA_LFLAG_SW_ACTIVITY = (1 << 7), /* keep activity stats */ ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */ ATA_LFLAG_RST_ONCE = (1 << 9), /* limit recovery to one reset */ + ATA_LFLAG_CHANGED = (1 << 10), /* LPM state changed on this link */ /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ @@ -309,6 +310,12 @@ enum { */ ATA_TMOUT_PMP_SRST_WAIT = 5000, + /* When the LPM policy is set to ATA_LPM_MAX_POWER, there might + * be a spurious PHY event, so ignore the first PHY event that + * occurs within 10s after the policy change. + */ + ATA_TMOUT_SPURIOUS_PHY = 10000, + /* ATA bus states */ BUS_UNKNOWN = 0, BUS_DMA = 1, @@ -788,6 +795,8 @@ struct ata_link { struct ata_eh_context eh_context; struct ata_device device[ATA_MAX_DEVICES]; + + unsigned long last_lpm_change; /* when last LPM change happened */ }; #define ATA_LINK_CLEAR_BEGIN offsetof(struct ata_link, active_tag) #define ATA_LINK_CLEAR_END offsetof(struct ata_link, device[0]) -- cgit v1.2.3 From 73b5a6f2a7a1cb78ccdec3900afc8657e11bc6bf Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Sun, 26 Apr 2015 15:55:57 +0300 Subject: net/bonding: Make DRV macros private The bonding modules currently defines four macros with general names that pollute the global namespace: DRV_VERSION DRV_RELDATE DRV_NAME DRV_DESCRIPTION Fixing that by defining a private bonding_priv.h header files which includes those defines. Signed-off-by: Matan Barak Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 ++ drivers/net/bonding/bond_procfs.c | 1 + drivers/net/bonding/bonding_priv.h | 25 +++++++++++++++++++++++++ include/net/bonding.h | 7 ------- 4 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 drivers/net/bonding/bonding_priv.h (limited to 'include') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 78dde56ae6e6..3a10551d64cf 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -82,6 +82,8 @@ #include #include +#include "bonding_priv.h" + /*---------------------------- Module parameters ----------------------------*/ /* monitor all links that often (in milliseconds). <=0 disables monitoring */ diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index 62694cfc05b6..b20b35acb47d 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -4,6 +4,7 @@ #include #include +#include "bonding_priv.h" static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) __acquires(RCU) diff --git a/drivers/net/bonding/bonding_priv.h b/drivers/net/bonding/bonding_priv.h new file mode 100644 index 000000000000..5a4d81a9437c --- /dev/null +++ b/drivers/net/bonding/bonding_priv.h @@ -0,0 +1,25 @@ +/* + * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'. + * + * Portions are (c) Copyright 1995 Simon "Guru Aleph-Null" Janes + * NCM: Network and Communications Management, Inc. + * + * BUT, I'm the one who modified it for ethernet, so: + * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + */ + +#ifndef _BONDING_PRIV_H +#define _BONDING_PRIV_H + +#define DRV_VERSION "3.7.1" +#define DRV_RELDATE "April 27, 2011" +#define DRV_NAME "bonding" +#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" + +#define bond_version DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n" + +#endif diff --git a/include/net/bonding.h b/include/net/bonding.h index fda6feeb6c1f..78ed135e9dea 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -30,13 +30,6 @@ #include #include -#define DRV_VERSION "3.7.1" -#define DRV_RELDATE "April 27, 2011" -#define DRV_NAME "bonding" -#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" - -#define bond_version DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n" - #define BOND_MAX_ARP_TARGETS 16 #define BOND_DEFAULT_MIIMON 100 -- cgit v1.2.3 From b44166cd46e28dd608d5baa5873047a40f32919c Mon Sep 17 00:00:00 2001 From: Bob Liu Date: Fri, 3 Apr 2015 14:42:59 +0800 Subject: xen/grant: introduce func gnttab_unmap_refs_sync() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are several place using gnttab async unmap and wait for completion, so move the common code to a function gnttab_unmap_refs_sync(). Signed-off-by: Bob Liu Acked-by: Roger Pau Monné Acked-by: Konrad Rzeszutek Wilk Signed-off-by: David Vrabel --- drivers/block/xen-blkback/blkback.c | 31 +++---------------------------- drivers/xen/gntdev.c | 28 +++------------------------- drivers/xen/grant-table.c | 28 ++++++++++++++++++++++++++++ include/xen/grant_table.h | 1 + 4 files changed, 35 insertions(+), 53 deletions(-) (limited to 'include') diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 48e98f2712b5..713fc9ff1149 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -265,17 +265,6 @@ static void put_persistent_gnt(struct xen_blkif *blkif, atomic_dec(&blkif->persistent_gnt_in_use); } -static void free_persistent_gnts_unmap_callback(int result, - struct gntab_unmap_queue_data *data) -{ - struct completion *c = data->data; - - /* BUG_ON used to reproduce existing behaviour, - but is this the best way to deal with this? */ - BUG_ON(result); - complete(c); -} - static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, unsigned int num) { @@ -285,12 +274,7 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, struct rb_node *n; int segs_to_unmap = 0; struct gntab_unmap_queue_data unmap_data; - struct completion unmap_completion; - - init_completion(&unmap_completion); - unmap_data.data = &unmap_completion; - unmap_data.done = &free_persistent_gnts_unmap_callback; unmap_data.pages = pages; unmap_data.unmap_ops = unmap; unmap_data.kunmap_ops = NULL; @@ -310,8 +294,7 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, !rb_next(&persistent_gnt->node)) { unmap_data.count = segs_to_unmap; - gnttab_unmap_refs_async(&unmap_data); - wait_for_completion(&unmap_completion); + BUG_ON(gnttab_unmap_refs_sync(&unmap_data)); put_free_pages(blkif, pages, segs_to_unmap); segs_to_unmap = 0; @@ -332,12 +315,7 @@ void xen_blkbk_unmap_purged_grants(struct work_struct *work) int segs_to_unmap = 0; struct xen_blkif *blkif = container_of(work, typeof(*blkif), persistent_purge_work); struct gntab_unmap_queue_data unmap_data; - struct completion unmap_completion; - init_completion(&unmap_completion); - - unmap_data.data = &unmap_completion; - unmap_data.done = &free_persistent_gnts_unmap_callback; unmap_data.pages = pages; unmap_data.unmap_ops = unmap; unmap_data.kunmap_ops = NULL; @@ -357,9 +335,7 @@ void xen_blkbk_unmap_purged_grants(struct work_struct *work) if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST) { unmap_data.count = segs_to_unmap; - gnttab_unmap_refs_async(&unmap_data); - wait_for_completion(&unmap_completion); - + BUG_ON(gnttab_unmap_refs_sync(&unmap_data)); put_free_pages(blkif, pages, segs_to_unmap); segs_to_unmap = 0; } @@ -367,8 +343,7 @@ void xen_blkbk_unmap_purged_grants(struct work_struct *work) } if (segs_to_unmap > 0) { unmap_data.count = segs_to_unmap; - gnttab_unmap_refs_async(&unmap_data); - wait_for_completion(&unmap_completion); + BUG_ON(gnttab_unmap_refs_sync(&unmap_data)); put_free_pages(blkif, pages, segs_to_unmap); } } diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index d5bb1a33d0a3..89274850741b 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -327,30 +327,10 @@ static int map_grant_pages(struct grant_map *map) return err; } -struct unmap_grant_pages_callback_data -{ - struct completion completion; - int result; -}; - -static void unmap_grant_callback(int result, - struct gntab_unmap_queue_data *data) -{ - struct unmap_grant_pages_callback_data* d = data->data; - - d->result = result; - complete(&d->completion); -} - static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) { int i, err = 0; struct gntab_unmap_queue_data unmap_data; - struct unmap_grant_pages_callback_data data; - - init_completion(&data.completion); - unmap_data.data = &data; - unmap_data.done= &unmap_grant_callback; if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) { int pgno = (map->notify.addr >> PAGE_SHIFT); @@ -367,11 +347,9 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) unmap_data.pages = map->pages + offset; unmap_data.count = pages; - gnttab_unmap_refs_async(&unmap_data); - - wait_for_completion(&data.completion); - if (data.result) - return data.result; + err = gnttab_unmap_refs_sync(&unmap_data); + if (err) + return err; for (i = 0; i < pages; i++) { if (map->unmap_ops[offset+i].status) diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 17972fbacddc..b1c7170e5c9e 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -123,6 +123,11 @@ struct gnttab_ops { int (*query_foreign_access)(grant_ref_t ref); }; +struct unmap_refs_callback_data { + struct completion completion; + int result; +}; + static struct gnttab_ops *gnttab_interface; static int grant_table_version; @@ -863,6 +868,29 @@ void gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item) } EXPORT_SYMBOL_GPL(gnttab_unmap_refs_async); +static void unmap_refs_callback(int result, + struct gntab_unmap_queue_data *data) +{ + struct unmap_refs_callback_data *d = data->data; + + d->result = result; + complete(&d->completion); +} + +int gnttab_unmap_refs_sync(struct gntab_unmap_queue_data *item) +{ + struct unmap_refs_callback_data data; + + init_completion(&data.completion); + item->data = &data; + item->done = &unmap_refs_callback; + gnttab_unmap_refs_async(item); + wait_for_completion(&data.completion); + + return data.result; +} +EXPORT_SYMBOL_GPL(gnttab_unmap_refs_sync); + static int gnttab_map_frames_v1(xen_pfn_t *frames, unsigned int nr_gframes) { int rc; diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h index 143ca5ffab7a..4478f4b4aae2 100644 --- a/include/xen/grant_table.h +++ b/include/xen/grant_table.h @@ -191,6 +191,7 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, struct gnttab_unmap_grant_ref *kunmap_ops, struct page **pages, unsigned int count); void gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item); +int gnttab_unmap_refs_sync(struct gntab_unmap_queue_data *item); /* Perform a batch of grant map/copy operations. Retry every batch slot -- cgit v1.2.3 From 73459e2a1ada09a68c02cc5b73f3116fc8194b3d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 23 Apr 2015 13:20:18 +0200 Subject: x86: pvclock: Really remove the sched notifier for cross-cpu migrations This reverts commits 0a4e6be9ca17c54817cf814b4b5aa60478c6df27 and 80f7fdb1c7f0f9266421f823964fd1962681f6ce. The task migration notifier was originally introduced in order to support the pvclock vsyscall with non-synchronized TSC, but KVM only supports it with synchronized TSC. Hence, on KVM the race condition is only needed due to a bad implementation on the host side, and even then it's so rare that it's mostly theoretical. As far as KVM is concerned it's possible to fix the host, avoiding the additional complexity in the vDSO and the (re)introduction of the task migration notifier. Xen, on the other hand, hasn't yet implemented vsyscall support at all, so we do not care about its plans for non-synchronized TSC. Reported-by: Peter Zijlstra Suggested-by: Marcelo Tosatti Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/pvclock.h | 1 - arch/x86/kernel/pvclock.c | 44 ------------------------------------------ arch/x86/vdso/vclock_gettime.c | 34 ++++++++++++++------------------ include/linux/sched.h | 8 -------- kernel/sched/core.c | 15 -------------- 5 files changed, 15 insertions(+), 87 deletions(-) (limited to 'include') diff --git a/arch/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h index 25b1cc07d496..d6b078e9fa28 100644 --- a/arch/x86/include/asm/pvclock.h +++ b/arch/x86/include/asm/pvclock.h @@ -95,7 +95,6 @@ unsigned __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src, struct pvclock_vsyscall_time_info { struct pvclock_vcpu_time_info pvti; - u32 migrate_count; } __attribute__((__aligned__(SMP_CACHE_BYTES))); #define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info) diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c index e5ecd20e72dd..2f355d229a58 100644 --- a/arch/x86/kernel/pvclock.c +++ b/arch/x86/kernel/pvclock.c @@ -141,46 +141,7 @@ void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock, set_normalized_timespec(ts, now.tv_sec, now.tv_nsec); } -static struct pvclock_vsyscall_time_info *pvclock_vdso_info; - -static struct pvclock_vsyscall_time_info * -pvclock_get_vsyscall_user_time_info(int cpu) -{ - if (!pvclock_vdso_info) { - BUG(); - return NULL; - } - - return &pvclock_vdso_info[cpu]; -} - -struct pvclock_vcpu_time_info *pvclock_get_vsyscall_time_info(int cpu) -{ - return &pvclock_get_vsyscall_user_time_info(cpu)->pvti; -} - #ifdef CONFIG_X86_64 -static int pvclock_task_migrate(struct notifier_block *nb, unsigned long l, - void *v) -{ - struct task_migration_notifier *mn = v; - struct pvclock_vsyscall_time_info *pvti; - - pvti = pvclock_get_vsyscall_user_time_info(mn->from_cpu); - - /* this is NULL when pvclock vsyscall is not initialized */ - if (unlikely(pvti == NULL)) - return NOTIFY_DONE; - - pvti->migrate_count++; - - return NOTIFY_DONE; -} - -static struct notifier_block pvclock_migrate = { - .notifier_call = pvclock_task_migrate, -}; - /* * Initialize the generic pvclock vsyscall state. This will allocate * a/some page(s) for the per-vcpu pvclock information, set up a @@ -194,17 +155,12 @@ int __init pvclock_init_vsyscall(struct pvclock_vsyscall_time_info *i, WARN_ON (size != PVCLOCK_VSYSCALL_NR_PAGES*PAGE_SIZE); - pvclock_vdso_info = i; - for (idx = 0; idx <= (PVCLOCK_FIXMAP_END-PVCLOCK_FIXMAP_BEGIN); idx++) { __set_fixmap(PVCLOCK_FIXMAP_BEGIN + idx, __pa(i) + (idx*PAGE_SIZE), PAGE_KERNEL_VVAR); } - - register_task_migration_notifier(&pvclock_migrate); - return 0; } #endif diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c index 40d2473836c9..9793322751e0 100644 --- a/arch/x86/vdso/vclock_gettime.c +++ b/arch/x86/vdso/vclock_gettime.c @@ -82,15 +82,18 @@ static notrace cycle_t vread_pvclock(int *mode) cycle_t ret; u64 last; u32 version; - u32 migrate_count; u8 flags; unsigned cpu, cpu1; /* - * When looping to get a consistent (time-info, tsc) pair, we - * also need to deal with the possibility we can switch vcpus, - * so make sure we always re-fetch time-info for the current vcpu. + * Note: hypervisor must guarantee that: + * 1. cpu ID number maps 1:1 to per-CPU pvclock time info. + * 2. that per-CPU pvclock time info is updated if the + * underlying CPU changes. + * 3. that version is increased whenever underlying CPU + * changes. + * */ do { cpu = __getcpu() & VGETCPU_CPU_MASK; @@ -99,27 +102,20 @@ static notrace cycle_t vread_pvclock(int *mode) * __getcpu() calls (Gleb). */ - /* Make sure migrate_count will change if we leave the VCPU. */ - do { - pvti = get_pvti(cpu); - migrate_count = pvti->migrate_count; - - cpu1 = cpu; - cpu = __getcpu() & VGETCPU_CPU_MASK; - } while (unlikely(cpu != cpu1)); + pvti = get_pvti(cpu); version = __pvclock_read_cycles(&pvti->pvti, &ret, &flags); /* * Test we're still on the cpu as well as the version. - * - We must read TSC of pvti's VCPU. - * - KVM doesn't follow the versioning protocol, so data could - * change before version if we left the VCPU. + * We could have been migrated just after the first + * vgetcpu but before fetching the version, so we + * wouldn't notice a version change. */ - smp_rmb(); - } while (unlikely((pvti->pvti.version & 1) || - pvti->pvti.version != version || - pvti->migrate_count != migrate_count)); + cpu1 = __getcpu() & VGETCPU_CPU_MASK; + } while (unlikely(cpu != cpu1 || + (pvti->pvti.version & 1) || + pvti->pvti.version != version)); if (unlikely(!(flags & PVCLOCK_TSC_STABLE_BIT))) *mode = VCLOCK_NONE; diff --git a/include/linux/sched.h b/include/linux/sched.h index 8222ae40ecb0..26a2e6122734 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -175,14 +175,6 @@ extern void get_iowait_load(unsigned long *nr_waiters, unsigned long *load); extern void calc_global_load(unsigned long ticks); extern void update_cpu_load_nohz(void); -/* Notifier for when a task gets migrated to a new CPU */ -struct task_migration_notifier { - struct task_struct *task; - int from_cpu; - int to_cpu; -}; -extern void register_task_migration_notifier(struct notifier_block *n); - extern unsigned long get_parent_ip(unsigned long addr); extern void dump_cpu_task(int cpu); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index f9123a82cbb6..fe22f7510bce 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1016,13 +1016,6 @@ void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags) rq_clock_skip_update(rq, true); } -static ATOMIC_NOTIFIER_HEAD(task_migration_notifier); - -void register_task_migration_notifier(struct notifier_block *n) -{ - atomic_notifier_chain_register(&task_migration_notifier, n); -} - #ifdef CONFIG_SMP void set_task_cpu(struct task_struct *p, unsigned int new_cpu) { @@ -1053,18 +1046,10 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu) trace_sched_migrate_task(p, new_cpu); if (task_cpu(p) != new_cpu) { - struct task_migration_notifier tmn; - if (p->sched_class->migrate_task_rq) p->sched_class->migrate_task_rq(p, new_cpu); p->se.nr_migrations++; perf_sw_event_sched(PERF_COUNT_SW_CPU_MIGRATIONS, 1, 0); - - tmn.task = p; - tmn.from_cpu = task_cpu(p); - tmn.to_cpu = new_cpu; - - atomic_notifier_call_chain(&task_migration_notifier, 0, &tmn); } __set_task_cpu(p, new_cpu); -- cgit v1.2.3 From 35e9a9f93994d7f7d12afa41169c7ba05513721b Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 20 Apr 2015 22:42:24 -0500 Subject: SCSI: add 1024 max sectors black list flag This works around a issue with qnap iscsi targets not handling large IOs very well. The target returns: VPD INQUIRY: Block limits page (SBC) Maximum compare and write length: 1 blocks Optimal transfer length granularity: 1 blocks Maximum transfer length: 4294967295 blocks Optimal transfer length: 4294967295 blocks Maximum prefetch, xdread, xdwrite transfer length: 0 blocks Maximum unmap LBA count: 8388607 Maximum unmap block descriptor count: 1 Optimal unmap granularity: 16383 Unmap granularity alignment valid: 0 Unmap granularity alignment: 0 Maximum write same length: 0xffffffff blocks Maximum atomic transfer length: 0 Atomic alignment: 0 Atomic transfer length granularity: 0 and it is *sometimes* able to handle at least one IO of size up to 8 MB. We have seen in traces where it will sometimes work, but other times it looks like it fails and it looks like it returns failures if we send multiple large IOs sometimes. Also it looks like it can return 2 different errors. It will sometimes send iscsi reject errors indicating out of resources or it will send invalid cdb illegal requests check conditions. And then when it sends iscsi rejects it does not seem to handle retries when there are command sequence holes, so I could not just add code to try and gracefully handle that error code. The problem is that we do not have a good contact for the company, so we are not able to determine under what conditions it returns which error and why it sometimes works. So, this patch just adds a new black list flag to set targets like this to the old max safe sectors of 1024. The max_hw_sectors changes added in 3.19 caused this regression, so I also ccing stable. Reported-by: Christian Hesse Signed-off-by: Mike Christie Cc: stable@vger.kernel.org Reviewed-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 1 + drivers/scsi/scsi_scan.c | 6 ++++++ include/scsi/scsi_devinfo.h | 1 + 3 files changed, 8 insertions(+) (limited to 'include') diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 262ab837a704..9f77d23239a2 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -226,6 +226,7 @@ static struct { {"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"Promise", "VTrak E610f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC}, {"Promise", "", NULL, BLIST_SPARSELUN}, + {"QNAP", "iSCSI Storage", NULL, BLIST_MAX_1024}, {"QUANTUM", "XP34301", "1071", BLIST_NOTQ}, {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN}, {"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN}, diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 60aae01caa89..6efab1c455e1 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -897,6 +897,12 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, */ if (*bflags & BLIST_MAX_512) blk_queue_max_hw_sectors(sdev->request_queue, 512); + /* + * Max 1024 sector transfer length for targets that report incorrect + * max/optimal lengths and relied on the old block layer safe default + */ + else if (*bflags & BLIST_MAX_1024) + blk_queue_max_hw_sectors(sdev->request_queue, 1024); /* * Some devices may not want to have a start command automatically diff --git a/include/scsi/scsi_devinfo.h b/include/scsi/scsi_devinfo.h index 183eaab7c380..96e3f56519e7 100644 --- a/include/scsi/scsi_devinfo.h +++ b/include/scsi/scsi_devinfo.h @@ -36,5 +36,6 @@ for sequential scan */ #define BLIST_TRY_VPD_PAGES 0x10000000 /* Attempt to read VPD pages */ #define BLIST_NO_RSOC 0x20000000 /* don't try to issue RSOC */ +#define BLIST_MAX_1024 0x40000000 /* maximum 1024 sector cdb length */ #endif -- cgit v1.2.3 From ee136af4a064c2f61e2025873584d2c7ec93f4ae Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Apr 2015 11:20:31 +0200 Subject: uas: Add US_FL_MAX_SECTORS_240 flag The usb-storage driver sets max_sectors = 240 in its scsi-host template, for uas we do not want to do that for all devices, but testing has shown that some devices need it. This commit adds a US_FL_MAX_SECTORS_240 flag for such devices, and implements support for it in uas.c, while at it it also adds support for US_FL_MAX_SECTORS_64 to uas.c. Cc: stable@vger.kernel.org # 3.16 Signed-off-by: Hans de Goede Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 2 ++ drivers/usb/storage/uas.c | 10 +++++++++- drivers/usb/storage/usb.c | 6 +++++- include/linux/usb_usual.h | 2 ++ 4 files changed, 18 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index f6befa9855c1..61ab1628a057 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3787,6 +3787,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. READ_CAPACITY_16 command); f = NO_REPORT_OPCODES (don't use report opcodes command, uas only); + g = MAX_SECTORS_240 (don't transfer more than + 240 sectors at a time, uas only); h = CAPACITY_HEURISTICS (decrease the reported device capacity by one sector if the number is odd); diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index c6109c111aab..6d3122afeed3 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -759,7 +759,10 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd) static int uas_slave_alloc(struct scsi_device *sdev) { - sdev->hostdata = (void *)sdev->host->hostdata; + struct uas_dev_info *devinfo = + (struct uas_dev_info *)sdev->host->hostdata; + + sdev->hostdata = devinfo; /* USB has unusual DMA-alignment requirements: Although the * starting address of each scatter-gather element doesn't matter, @@ -778,6 +781,11 @@ static int uas_slave_alloc(struct scsi_device *sdev) */ blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); + if (devinfo->flags & US_FL_MAX_SECTORS_64) + blk_queue_max_hw_sectors(sdev->request_queue, 64); + else if (devinfo->flags & US_FL_MAX_SECTORS_240) + blk_queue_max_hw_sectors(sdev->request_queue, 240); + return 0; } diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index db6f6b5ec745..6c10c888f35f 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -479,7 +479,8 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags) US_FL_SINGLE_LUN | US_FL_NO_WP_DETECT | US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 | US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE | - US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES); + US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES | + US_FL_MAX_SECTORS_240); p = quirks; while (*p) { @@ -520,6 +521,9 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags) case 'f': f |= US_FL_NO_REPORT_OPCODES; break; + case 'g': + f |= US_FL_MAX_SECTORS_240; + break; case 'h': f |= US_FL_CAPACITY_HEURISTICS; break; diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h index a7f2604c5f25..7f5f78bd15ad 100644 --- a/include/linux/usb_usual.h +++ b/include/linux/usb_usual.h @@ -77,6 +77,8 @@ /* Cannot handle ATA_12 or ATA_16 CDBs */ \ US_FLAG(NO_REPORT_OPCODES, 0x04000000) \ /* Cannot handle MI_REPORT_SUPPORTED_OPERATION_CODES */ \ + US_FLAG(MAX_SECTORS_240, 0x08000000) \ + /* Sets max_sectors to 240 */ \ #define US_FLAG(name, value) US_FL_##name = value , enum { US_DO_ALL_FLAGS }; -- cgit v1.2.3 From b00f5c2dc01450bed9fed1a41a637fa917e03c5c Mon Sep 17 00:00:00 2001 From: Frederic Danis Date: Fri, 10 Apr 2015 15:13:05 +0200 Subject: tty: Re-add external interface for tty_set_termios() This is needed by Bluetooth hci_uart module to be able to change speed of Bluetooth controller and local UART. Signed-off-by: Frederic Danis Reviewed-by: Peter Hurley Cc: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ioctl.c | 3 ++- include/linux/tty.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 632fc8152061..8e53fe469664 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -536,7 +536,7 @@ EXPORT_SYMBOL(tty_termios_hw_change); * Locking: termios_rwsem */ -static int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) +int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) { struct ktermios old_termios; struct tty_ldisc *ld; @@ -569,6 +569,7 @@ static int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) up_write(&tty->termios_rwsem); return 0; } +EXPORT_SYMBOL_GPL(tty_set_termios); /** * set_termios - set termios values for a tty diff --git a/include/linux/tty.h b/include/linux/tty.h index 358a337af598..fe5623c9af71 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -491,6 +491,7 @@ static inline speed_t tty_get_baud_rate(struct tty_struct *tty) extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old); extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b); +extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt); extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *); extern void tty_ldisc_deref(struct tty_ldisc *); -- cgit v1.2.3 From 9d7dd6cd2a1d0d307be6bf783e40e7fda17d6dba Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Date: Tue, 28 Apr 2015 11:30:08 +0530 Subject: ASoC: Update email-id of Rajeev Kumar rajeev-dlh.kumar@st.com email-id doesn't exist anymore as I have left the company. Replace ST's id with Rajeev Kumar Signed-off-by: Rajeev Kumar Signed-off-by: Mark Brown --- include/sound/designware_i2s.h | 2 +- include/sound/spear_dma.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/sound/designware_i2s.h b/include/sound/designware_i2s.h index 26f406e0f673..3a8fca9409a7 100644 --- a/include/sound/designware_i2s.h +++ b/include/sound/designware_i2s.h @@ -1,5 +1,5 @@ /* - * Copyright (ST) 2012 Rajeev Kumar (rajeev-dlh.kumar@st.com) + * Copyright (ST) 2012 Rajeev Kumar (rajeevkumar.linux@gmail.com) * * 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 diff --git a/include/sound/spear_dma.h b/include/sound/spear_dma.h index 65aca51fe255..e290de4e7e82 100644 --- a/include/sound/spear_dma.h +++ b/include/sound/spear_dma.h @@ -1,7 +1,7 @@ /* * linux/spear_dma.h * -* Copyright (ST) 2012 Rajeev Kumar (rajeev-dlh.kumar@st.com) +* Copyright (ST) 2012 Rajeev Kumar (rajeevkumar.linux@gmail.com) * * 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 -- cgit v1.2.3 From 9e9d55e69a95f8583283d9f01b04562d1278c95d Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Tue, 28 Apr 2015 16:54:04 +0200 Subject: ACPICA: remove duplicate u8 typedef During commit e252652fb266 ("ACPICA: acpidump: Remove integer types translation protection.") two 'unsigned char' types got converted to 'u8'. The result does not compile with gcc-4.5, it can not cope with duplicate typedefs. Signed-off-by: Olaf Hering Signed-off-by: Rafael J. Wysocki --- include/acpi/actypes.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index f5ca0e989bba..1c3002e1db20 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -123,7 +123,6 @@ #ifndef ACPI_USE_SYSTEM_INTTYPES -typedef unsigned char u8; typedef unsigned char u8; typedef unsigned short u16; typedef short s16; -- cgit v1.2.3 From 7241ea558c6715501e777396b5fc312c372e11d9 Mon Sep 17 00:00:00 2001 From: Peter Zubaj Date: Tue, 28 Apr 2015 21:57:29 +0200 Subject: ALSA: emu10k1: Emu10k2 32 bit DMA mode Looks like audigy emu10k2 (probably emu10k1 - sb live too) support two modes for DMA. Second mode is useful for 64 bit os with more then 2 GB of ram (fixes problems with big soundfont loading) 1) 32MB from 2 GB address space using 8192 pages (used now as default) 2) 16MB from 4 GB address space using 4096 pages Mode is set using HCFG_EXPANDED_MEM flag in HCFG register. Also format of emu10k2 page table is then different. Signed-off-by: Peter Zubaj Tested-by: Takashi Iwai Cc: Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 14 +++++++++----- sound/pci/emu10k1/emu10k1_callback.c | 4 ++-- sound/pci/emu10k1/emu10k1_main.c | 17 ++++++++++++----- sound/pci/emu10k1/emupcm.c | 2 +- sound/pci/emu10k1/memory.c | 11 ++++++----- 5 files changed, 30 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 0de95ccb92cf..5bd134651f5e 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -41,7 +41,8 @@ #define EMUPAGESIZE 4096 #define MAXREQVOICES 8 -#define MAXPAGES 8192 +#define MAXPAGES0 4096 /* 32 bit mode */ +#define MAXPAGES1 8192 /* 31 bit mode */ #define RESERVED 0 #define NUM_MIDI 16 #define NUM_G 64 /* use all channels */ @@ -50,8 +51,7 @@ /* FIXME? - according to the OSS driver the EMU10K1 needs a 29 bit DMA mask */ #define EMU10K1_DMA_MASK 0x7fffffffUL /* 31bit */ -#define AUDIGY_DMA_MASK 0x7fffffffUL /* 31bit FIXME - 32 should work? */ - /* See ALSA bug #1276 - rlrevell */ +#define AUDIGY_DMA_MASK 0xffffffffUL /* 32bit mode */ #define TMEMSIZE 256*1024 #define TMEMSIZEREG 4 @@ -466,8 +466,11 @@ #define MAPB 0x0d /* Cache map B */ -#define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */ -#define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */ +#define MAP_PTE_MASK0 0xfffff000 /* The 20 MSBs of the PTE indexed by the PTI */ +#define MAP_PTI_MASK0 0x00000fff /* The 12 bit index to one of the 4096 PTE dwords */ + +#define MAP_PTE_MASK1 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */ +#define MAP_PTI_MASK1 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */ /* 0x0e, 0x0f: Not used */ @@ -1704,6 +1707,7 @@ struct snd_emu10k1 { unsigned short model; /* subsystem id */ unsigned int card_type; /* EMU10K1_CARD_* */ unsigned int ecard_ctrl; /* ecard control bits */ + unsigned int address_mode; /* address mode */ unsigned long dma_mask; /* PCI DMA mask */ unsigned int delay_pcm_irq; /* in samples */ int max_cache_pages; /* max memory size / PAGE_SIZE */ diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index 874cd76c7b7f..d2c7ea3a7610 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c @@ -415,7 +415,7 @@ start_voice(struct snd_emux_voice *vp) snd_emu10k1_ptr_write(hw, Z2, ch, 0); /* invalidate maps */ - temp = (hw->silent_page.addr << 1) | MAP_PTI_MASK; + temp = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); snd_emu10k1_ptr_write(hw, MAPA, ch, temp); snd_emu10k1_ptr_write(hw, MAPB, ch, temp); #if 0 @@ -436,7 +436,7 @@ start_voice(struct snd_emux_voice *vp) snd_emu10k1_ptr_write(hw, CDF, ch, sample); /* invalidate maps */ - temp = ((unsigned int)hw->silent_page.addr << 1) | MAP_PTI_MASK; + temp = ((unsigned int)hw->silent_page.addr << hw_address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); snd_emu10k1_ptr_write(hw, MAPA, ch, temp); snd_emu10k1_ptr_write(hw, MAPB, ch, temp); diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 4f8cf5e7e45f..a4548147c621 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -282,7 +282,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ - silent_page = (emu->silent_page.addr << 1) | MAP_PTI_MASK; + silent_page = (emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); for (ch = 0; ch < NUM_G; ch++) { snd_emu10k1_ptr_write(emu, MAPA, ch, silent_page); snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); @@ -348,6 +348,11 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); } + if (emu->address_mode == 0) { + /* use 16M in 4G */ + outl(inl(emu->port + HCFG) | HCFG_EXPANDED_MEM, emu->port + HCFG); + } + return 0; } @@ -1902,8 +1907,10 @@ int snd_emu10k1_create(struct snd_card *card, is_audigy = emu->audigy = c->emu10k2_chip; + /* set addressing mode */ + emu->address_mode = is_audigy ? 0 : 1; /* set the DMA transfer mask */ - emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK; + emu->dma_mask = emu->address_mode ? EMU10K1_DMA_MASK : AUDIGY_DMA_MASK; if (pci_set_dma_mask(pci, emu->dma_mask) < 0 || pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) { dev_err(card->dev, @@ -1928,7 +1935,7 @@ int snd_emu10k1_create(struct snd_card *card, emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT; if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - 32 * 1024, &emu->ptb_pages) < 0) { + (emu->address_mode ? 32 : 16) * 1024, &emu->ptb_pages) < 0) { err = -ENOMEM; goto error; } @@ -2027,8 +2034,8 @@ int snd_emu10k1_create(struct snd_card *card, /* Clear silent pages and set up pointers */ memset(emu->silent_page.area, 0, PAGE_SIZE); - silent_page = emu->silent_page.addr << 1; - for (idx = 0; idx < MAXPAGES; idx++) + silent_page = emu->silent_page.addr << emu->address_mode; + for (idx = 0; idx < (emu->address_mode ? MAXPAGES1 : MAXPAGES0); idx++) ((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx); /* set up voice indices */ diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 0dc07385af0e..14a305bd8a98 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -380,7 +380,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, snd_emu10k1_ptr_write(emu, Z1, voice, 0); snd_emu10k1_ptr_write(emu, Z2, voice, 0); /* invalidate maps */ - silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK; + silent_page = ((unsigned int)emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); /* modulation envelope */ diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index c68e6dd2fa67..4f1f69be1865 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -34,10 +34,11 @@ * aligned pages in others */ #define __set_ptb_entry(emu,page,addr) \ - (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << 1) | (page))) + (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << (emu->address_mode)) | (page))) #define UNIT_PAGES (PAGE_SIZE / EMUPAGESIZE) -#define MAX_ALIGN_PAGES (MAXPAGES / UNIT_PAGES) +#define MAX_ALIGN_PAGES0 (MAXPAGES0 / UNIT_PAGES) +#define MAX_ALIGN_PAGES1 (MAXPAGES1 / UNIT_PAGES) /* get aligned page from offset address */ #define get_aligned_page(offset) ((offset) >> PAGE_SHIFT) /* get offset address from aligned page */ @@ -124,7 +125,7 @@ static int search_empty_map_area(struct snd_emu10k1 *emu, int npages, struct lis } page = blk->mapped_page + blk->pages; } - size = MAX_ALIGN_PAGES - page; + size = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0) - page; if (size >= max_size) { *nextp = pos; return page; @@ -181,7 +182,7 @@ static int unmap_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) q = get_emu10k1_memblk(p, mapped_link); end_page = q->mapped_page; } else - end_page = MAX_ALIGN_PAGES; + end_page = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0); /* remove links */ list_del(&blk->mapped_link); @@ -307,7 +308,7 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst if (snd_BUG_ON(!emu)) return NULL; if (snd_BUG_ON(runtime->dma_bytes <= 0 || - runtime->dma_bytes >= MAXPAGES * EMUPAGESIZE)) + runtime->dma_bytes >= (emu->address_mode ? MAXPAGES1 : MAXPAGES0) * EMUPAGESIZE)) return NULL; hdr = emu->memhdr; if (snd_BUG_ON(!hdr)) -- cgit v1.2.3 From 2b953a5e994ce279904ec70220f7d4f31d380a0a Mon Sep 17 00:00:00 2001 From: Boris Ostrovsky Date: Tue, 28 Apr 2015 18:46:20 -0400 Subject: xen: Suspend ticks on all CPUs during suspend Commit 77e32c89a711 ("clockevents: Manage device's state separately for the core") decouples clockevent device's modes from states. With this change when a Xen guest tries to resume, it won't be calling its set_mode op which needs to be done on each VCPU in order to make the hypervisor aware that we are in oneshot mode. This happens because clockevents_tick_resume() (which is an intermediate step of resuming ticks on a processor) doesn't call clockevents_set_state() anymore and because during suspend clockevent devices on all VCPUs (except for the one doing the suspend) are left in ONESHOT state. As result, during resume the clockevents state machine will assume that device is already where it should be and doesn't need to be updated. To avoid this problem we should suspend ticks on all VCPUs during suspend. Signed-off-by: Boris Ostrovsky Signed-off-by: David Vrabel --- arch/x86/xen/suspend.c | 10 ++++++++++ drivers/xen/manage.c | 9 ++++++--- include/xen/xen-ops.h | 1 + 3 files changed, 17 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c index d9497698645a..53b4c0811f4f 100644 --- a/arch/x86/xen/suspend.c +++ b/arch/x86/xen/suspend.c @@ -88,7 +88,17 @@ static void xen_vcpu_notify_restore(void *data) tick_resume_local(); } +static void xen_vcpu_notify_suspend(void *data) +{ + tick_suspend_local(); +} + void xen_arch_resume(void) { on_each_cpu(xen_vcpu_notify_restore, NULL, 1); } + +void xen_arch_suspend(void) +{ + on_each_cpu(xen_vcpu_notify_suspend, NULL, 1); +} diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index bf1940706422..9e6a85104a20 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -131,6 +131,8 @@ static void do_suspend(void) goto out_resume; } + xen_arch_suspend(); + si.cancelled = 1; err = stop_machine(xen_suspend, &si, cpumask_of(0)); @@ -148,11 +150,12 @@ static void do_suspend(void) si.cancelled = 1; } + xen_arch_resume(); + out_resume: - if (!si.cancelled) { - xen_arch_resume(); + if (!si.cancelled) xs_resume(); - } else + else xs_suspend_cancel(); dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE); diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index c643e6a94c9a..0ce4f32017ea 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -13,6 +13,7 @@ void xen_arch_post_suspend(int suspend_cancelled); void xen_timer_resume(void); void xen_arch_resume(void); +void xen_arch_suspend(void); void xen_resume_notifier_register(struct notifier_block *nb); void xen_resume_notifier_unregister(struct notifier_block *nb); -- cgit v1.2.3 From 46c264daaaa569e24f8aba877d0fd8167c42a9a4 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 28 Apr 2015 18:33:49 +0200 Subject: bridge/nl: remove wrong use of NLM_F_MULTI NLM_F_MULTI must be used only when a NLMSG_DONE message is sent. In fact, it is sent only at the end of a dump. Libraries like libnl will wait forever for NLMSG_DONE. Fixes: e5a55a898720 ("net: create generic bridge ops") Fixes: 815cccbf10b2 ("ixgbe: add setlink, getlink support to ixgbe and ixgbevf") CC: John Fastabend CC: Sathya Perla CC: Subbu Seetharaman CC: Ajit Khaparde CC: Jeff Kirsher CC: intel-wired-lan@lists.osuosl.org CC: Jiri Pirko CC: Scott Feldman CC: Stephen Hemminger CC: bridge@lists.linux-foundation.org Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 5 +++-- drivers/net/ethernet/intel/i40e/i40e_main.c | 7 ++++--- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 ++-- drivers/net/ethernet/rocker/rocker.c | 5 +++-- include/linux/netdevice.h | 6 ++++-- include/linux/rtnetlink.h | 2 +- net/bridge/br_netlink.c | 4 ++-- net/bridge/br_private.h | 2 +- net/core/rtnetlink.c | 12 +++++++----- 9 files changed, 27 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index fb0bc3c3620e..a6dcbf850c1f 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -4846,7 +4846,8 @@ err: } static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, - struct net_device *dev, u32 filter_mask) + struct net_device *dev, u32 filter_mask, + int nlflags) { struct be_adapter *adapter = netdev_priv(dev); int status = 0; @@ -4868,7 +4869,7 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, return ndo_dflt_bridge_getlink(skb, pid, seq, dev, hsw_mode == PORT_FWD_TYPE_VEPA ? BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB, - 0, 0); + 0, 0, nlflags); } #ifdef CONFIG_BE2NET_VXLAN diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 24481cd7e59a..a54c14491e3b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -8053,10 +8053,10 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev, #ifdef HAVE_BRIDGE_FILTER static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, - u32 __always_unused filter_mask) + u32 __always_unused filter_mask, int nlflags) #else static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, - struct net_device *dev) + struct net_device *dev, int nlflags) #endif /* HAVE_BRIDGE_FILTER */ { struct i40e_netdev_priv *np = netdev_priv(dev); @@ -8078,7 +8078,8 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, if (!veb) return 0; - return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode); + return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode, + nlflags); } #endif /* HAVE_BRIDGE_ATTRIBS */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index d3f4b0ceb3f7..5be12a00e1f4 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -8044,7 +8044,7 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev, static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, - u32 filter_mask) + u32 filter_mask, int nlflags) { struct ixgbe_adapter *adapter = netdev_priv(dev); @@ -8052,7 +8052,7 @@ static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, return 0; return ndo_dflt_bridge_getlink(skb, pid, seq, dev, - adapter->bridge_mode, 0, 0); + adapter->bridge_mode, 0, 0, nlflags); } static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev) diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index a570a60533be..ec251531bd9f 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4176,14 +4176,15 @@ static int rocker_port_bridge_setlink(struct net_device *dev, static int rocker_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, - u32 filter_mask) + u32 filter_mask, int nlflags) { struct rocker_port *rocker_port = netdev_priv(dev); u16 mode = BRIDGE_MODE_UNDEF; u32 mask = BR_LEARNING | BR_LEARNING_SYNC; return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, - rocker_port->brport_flags, mask); + rocker_port->brport_flags, mask, + nlflags); } static int rocker_port_get_phys_port_name(struct net_device *dev, diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index dbad4d728b4b..1899c74a7127 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -977,7 +977,8 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev, * int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh, * u16 flags) * int (*ndo_bridge_getlink)(struct sk_buff *skb, u32 pid, u32 seq, - * struct net_device *dev, u32 filter_mask) + * struct net_device *dev, u32 filter_mask, + * int nlflags) * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh, * u16 flags); * @@ -1173,7 +1174,8 @@ struct net_device_ops { int (*ndo_bridge_getlink)(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, - u32 filter_mask); + u32 filter_mask, + int nlflags); int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh, u16 flags); diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 2da5d1081ad9..7b8e260c4a27 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -122,5 +122,5 @@ extern int ndo_dflt_fdb_del(struct ndmsg *ndm, extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, u16 mode, - u32 flags, u32 mask); + u32 flags, u32 mask, int nlflags); #endif /* __LINUX_RTNETLINK_H */ diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 0e4ddb81610d..4b5c236998ff 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -394,7 +394,7 @@ errout: * Dump information about all ports, in response to GETLINK */ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, - struct net_device *dev, u32 filter_mask) + struct net_device *dev, u32 filter_mask, int nlflags) { struct net_bridge_port *port = br_port_get_rtnl(dev); @@ -402,7 +402,7 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) return 0; - return br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI, + return br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, nlflags, filter_mask, dev); } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 6ca0251cb478..3362c29400f1 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -828,7 +828,7 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port); int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg, u16 flags); int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg, u16 flags); int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, - u32 filter_mask); + u32 filter_mask, int nlflags); #ifdef CONFIG_SYSFS /* br_sysfs_if.c */ diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 358d52a38533..666e0928ba40 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2854,7 +2854,7 @@ static int brport_nla_put_flag(struct sk_buff *skb, u32 flags, u32 mask, int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, u16 mode, - u32 flags, u32 mask) + u32 flags, u32 mask, int nlflags) { struct nlmsghdr *nlh; struct ifinfomsg *ifm; @@ -2863,7 +2863,7 @@ int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; struct net_device *br_dev = netdev_master_upper_dev_get(dev); - nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*ifm), NLM_F_MULTI); + nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*ifm), nlflags); if (nlh == NULL) return -EMSGSIZE; @@ -2969,7 +2969,8 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb) if (br_dev && br_dev->netdev_ops->ndo_bridge_getlink) { if (idx >= cb->args[0] && br_dev->netdev_ops->ndo_bridge_getlink( - skb, portid, seq, dev, filter_mask) < 0) + skb, portid, seq, dev, filter_mask, + NLM_F_MULTI) < 0) break; idx++; } @@ -2977,7 +2978,8 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb) if (ops->ndo_bridge_getlink) { if (idx >= cb->args[0] && ops->ndo_bridge_getlink(skb, portid, seq, dev, - filter_mask) < 0) + filter_mask, + NLM_F_MULTI) < 0) break; idx++; } @@ -3018,7 +3020,7 @@ static int rtnl_bridge_notify(struct net_device *dev) goto errout; } - err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0); + err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0, 0); if (err < 0) goto errout; -- cgit v1.2.3 From 0df48c26d8418c5c9fba63fac15b660d70ca2f1c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 28 Apr 2015 15:28:17 -0700 Subject: tcp: add tcpi_bytes_acked to tcp_info This patch tracks total number of bytes acked for a TCP socket. This is the sum of all changes done to tp->snd_una, and allows for precise tracking of delivered data. RFC4898 named this : tcpEStatsAppHCThruOctetsAcked This is a 64bit field, and can be fetched both from TCP_INFO getsockopt() if one has a handle on a TCP socket, or from inet_diag netlink facility (iproute2/ss patch will follow) Note that tp->bytes_acked was placed near tp->snd_una for best data locality and minimal performance impact. Signed-off-by: Eric Dumazet Acked-by: Yuchung Cheng Cc: Matt Mathis Cc: Eric Salo Cc: Martin Lau Cc: Chris Rapier Signed-off-by: David S. Miller --- include/linux/tcp.h | 4 ++++ include/net/tcp.h | 2 +- include/uapi/linux/tcp.h | 1 + net/ipv4/tcp.c | 6 +++++- net/ipv4/tcp_input.c | 13 +++++++++++-- 5 files changed, 22 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 0caa3a2d4106..0f73b43171da 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -150,6 +150,10 @@ struct tcp_sock { u32 rcv_wup; /* rcv_nxt on last window update sent */ u32 snd_nxt; /* Next sequence we send */ + u64 bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked + * sum(delta(snd_una)), or how many bytes + * were acked. + */ u32 snd_una; /* First byte we want an ack for */ u32 snd_sml; /* Last byte of the most recently transmitted small packet */ u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 051dc5c2802d..dd7b4ea6a10c 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -576,7 +576,7 @@ static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize) } /* tcp.c */ -void tcp_get_info(const struct sock *, struct tcp_info *); +void tcp_get_info(struct sock *, struct tcp_info *); /* Read 'sendfile()'-style from a TCP socket */ typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h index 3b9718328d8b..6666e98a0af9 100644 --- a/include/uapi/linux/tcp.h +++ b/include/uapi/linux/tcp.h @@ -189,6 +189,7 @@ struct tcp_info { __u64 tcpi_pacing_rate; __u64 tcpi_max_pacing_rate; + __u64 tcpi_bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked */ }; /* for TCP_MD5SIG socket option */ diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 8c5cd9efebbc..4bf0e8ca7b5b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2592,7 +2592,7 @@ EXPORT_SYMBOL(compat_tcp_setsockopt); #endif /* Return information about state of tcp endpoint in API format. */ -void tcp_get_info(const struct sock *sk, struct tcp_info *info) +void tcp_get_info(struct sock *sk, struct tcp_info *info) { const struct tcp_sock *tp = tcp_sk(sk); const struct inet_connection_sock *icsk = inet_csk(sk); @@ -2663,6 +2663,10 @@ void tcp_get_info(const struct sock *sk, struct tcp_info *info) rate = READ_ONCE(sk->sk_max_pacing_rate); info->tcpi_max_pacing_rate = rate != ~0U ? rate : ~0ULL; + + spin_lock_bh(&sk->sk_lock.slock); + info->tcpi_bytes_acked = tp->bytes_acked; + spin_unlock_bh(&sk->sk_lock.slock); } EXPORT_SYMBOL_GPL(tcp_get_info); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3a4d9b34bed4..378d3f4d4dc3 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3280,6 +3280,15 @@ static inline bool tcp_may_update_window(const struct tcp_sock *tp, (ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd); } +/* If we update tp->snd_una, also update tp->bytes_acked */ +static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack) +{ + u32 delta = ack - tp->snd_una; + + tp->bytes_acked += delta; + tp->snd_una = ack; +} + /* Update our send window. * * Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2 @@ -3315,7 +3324,7 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 } } - tp->snd_una = ack; + tcp_snd_una_update(tp, ack); return flag; } @@ -3497,7 +3506,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) * Note, we use the fact that SND.UNA>=SND.WL2. */ tcp_update_wl(tp, ack_seq); - tp->snd_una = ack; + tcp_snd_una_update(tp, ack); flag |= FLAG_WIN_UPDATE; tcp_in_ack_event(sk, CA_ACK_WIN_UPDATE); -- cgit v1.2.3 From bdd1f9edacb5f5835d1e6276571bbbe5b88ded48 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 28 Apr 2015 15:28:18 -0700 Subject: tcp: add tcpi_bytes_received to tcp_info This patch tracks total number of payload bytes received on a TCP socket. This is the sum of all changes done to tp->rcv_nxt RFC4898 named this : tcpEStatsAppHCThruOctetsReceived This is a 64bit field, and can be fetched both from TCP_INFO getsockopt() if one has a handle on a TCP socket, or from inet_diag netlink facility (iproute2/ss patch will follow) Note that tp->bytes_received was placed near tp->rcv_nxt for best data locality and minimal performance impact. Signed-off-by: Eric Dumazet Cc: Yuchung Cheng Cc: Matt Mathis Cc: Eric Salo Cc: Martin Lau Cc: Chris Rapier Acked-by: Yuchung Cheng Signed-off-by: David S. Miller --- include/linux/tcp.h | 4 ++++ include/uapi/linux/tcp.h | 1 + net/ipv4/tcp.c | 1 + net/ipv4/tcp_fastopen.c | 1 + net/ipv4/tcp_input.c | 17 +++++++++++++---- 5 files changed, 20 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 0f73b43171da..3b2911502a8c 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -145,6 +145,10 @@ struct tcp_sock { * read the code and the spec side by side (and laugh ...) * See RFC793 and RFC1122. The RFC writes these in capitals. */ + u64 bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived + * sum(delta(rcv_nxt)), or how many bytes + * were acked. + */ u32 rcv_nxt; /* What we want to receive next */ u32 copied_seq; /* Head of yet unread data */ u32 rcv_wup; /* rcv_nxt on last window update sent */ diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h index 6666e98a0af9..a48f93f3207b 100644 --- a/include/uapi/linux/tcp.h +++ b/include/uapi/linux/tcp.h @@ -190,6 +190,7 @@ struct tcp_info { __u64 tcpi_pacing_rate; __u64 tcpi_max_pacing_rate; __u64 tcpi_bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked */ + __u64 tcpi_bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived */ }; /* for TCP_MD5SIG socket option */ diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 4bf0e8ca7b5b..99fcc0b22c92 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2666,6 +2666,7 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) spin_lock_bh(&sk->sk_lock.slock); info->tcpi_bytes_acked = tp->bytes_acked; + info->tcpi_bytes_received = tp->bytes_received; spin_unlock_bh(&sk->sk_lock.slock); } EXPORT_SYMBOL_GPL(tcp_get_info); diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index e3d87aca6be8..3c673d5e6cff 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c @@ -206,6 +206,7 @@ static bool tcp_fastopen_create_child(struct sock *sk, skb_set_owner_r(skb2, child); __skb_queue_tail(&child->sk_receive_queue, skb2); tp->syn_data_acked = 1; + tp->bytes_received = end_seq - TCP_SKB_CB(skb)->seq - 1; } else { end_seq = TCP_SKB_CB(skb)->seq + 1; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 378d3f4d4dc3..7e6962bcfc30 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3289,6 +3289,15 @@ static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack) tp->snd_una = ack; } +/* If we update tp->rcv_nxt, also update tp->bytes_received */ +static void tcp_rcv_nxt_update(struct tcp_sock *tp, u32 seq) +{ + u32 delta = seq - tp->rcv_nxt; + + tp->bytes_received += delta; + tp->rcv_nxt = seq; +} + /* Update our send window. * * Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2 @@ -4245,7 +4254,7 @@ static void tcp_ofo_queue(struct sock *sk) tail = skb_peek_tail(&sk->sk_receive_queue); eaten = tail && tcp_try_coalesce(sk, tail, skb, &fragstolen); - tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); if (!eaten) __skb_queue_tail(&sk->sk_receive_queue, skb); if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) @@ -4413,7 +4422,7 @@ static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int __skb_pull(skb, hdrlen); eaten = (tail && tcp_try_coalesce(sk, tail, skb, fragstolen)) ? 1 : 0; - tcp_sk(sk)->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tcp_rcv_nxt_update(tcp_sk(sk), TCP_SKB_CB(skb)->end_seq); if (!eaten) { __skb_queue_tail(&sk->sk_receive_queue, skb); skb_set_owner_r(skb, sk); @@ -4506,7 +4515,7 @@ queue_and_out: eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen); } - tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); if (skb->len) tcp_event_data_recv(sk, skb); if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) @@ -5254,7 +5263,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb, tcp_rcv_rtt_measure_ts(sk, skb); __skb_pull(skb, tcp_header_len); - tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPHITSTOUSER); eaten = 1; } -- cgit v1.2.3 From 64f40ff5bbdb1b679fb3c4dbc8230d6517d2b8dc Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 28 Apr 2015 16:23:48 -0700 Subject: tcp: prepare CC get_info() access from getsockopt() We would like that optional info provided by Congestion Control modules using netlink can also be read using getsockopt() This patch changes get_info() to put this information in a buffer, instead of skb, like tcp_get_info(), so that following patch can reuse this common infrastructure. Signed-off-by: Eric Dumazet Cc: Yuchung Cheng Cc: Neal Cardwell Acked-by: Neal Cardwell Acked-by: Daniel Borkmann Acked-by: Yuchung Cheng Signed-off-by: David S. Miller --- include/net/tcp.h | 5 ++++- include/uapi/linux/inet_diag.h | 4 ++++ net/ipv4/inet_diag.c | 8 +++++--- net/ipv4/tcp_dctcp.c | 20 ++++++++++---------- net/ipv4/tcp_illinois.c | 21 +++++++++++---------- net/ipv4/tcp_vegas.c | 19 ++++++++++--------- net/ipv4/tcp_vegas.h | 3 ++- 7 files changed, 46 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index dd7b4ea6a10c..6d204f3f9df8 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -804,6 +804,8 @@ enum tcp_ca_ack_event_flags { /* Requires ECN/ECT set on all packets */ #define TCP_CONG_NEEDS_ECN 0x2 +union tcp_cc_info; + struct tcp_congestion_ops { struct list_head list; u32 key; @@ -829,7 +831,8 @@ struct tcp_congestion_ops { /* hook for packet ack accounting (optional) */ void (*pkts_acked)(struct sock *sk, u32 num_acked, s32 rtt_us); /* get info for inet_diag (optional) */ - int (*get_info)(struct sock *sk, u32 ext, struct sk_buff *skb); + size_t (*get_info)(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info); char name[TCP_CA_NAME_MAX]; struct module *owner; diff --git a/include/uapi/linux/inet_diag.h b/include/uapi/linux/inet_diag.h index d65c0a09efd3..c7093c75bdd6 100644 --- a/include/uapi/linux/inet_diag.h +++ b/include/uapi/linux/inet_diag.h @@ -143,4 +143,8 @@ struct tcp_dctcp_info { __u32 dctcp_ab_tot; }; +union tcp_cc_info { + struct tcpvegas_info vegas; + struct tcp_dctcp_info dctcp; +}; #endif /* _UAPI_INET_DIAG_H_ */ diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index bb77ebdae3b3..4d32262c7502 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -224,14 +224,16 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, handler->idiag_get_info(sk, r, info); if (sk->sk_state < TCP_TIME_WAIT) { - int err = 0; + union tcp_cc_info info; + size_t sz = 0; + int attr; rcu_read_lock(); ca_ops = READ_ONCE(icsk->icsk_ca_ops); if (ca_ops && ca_ops->get_info) - err = ca_ops->get_info(sk, ext, skb); + sz = ca_ops->get_info(sk, ext, &attr, &info); rcu_read_unlock(); - if (err < 0) + if (sz && nla_put(skb, attr, sz, &info) < 0) goto errout; } diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index 4376016f7fa5..4c41c1287197 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -277,7 +277,8 @@ static void dctcp_cwnd_event(struct sock *sk, enum tcp_ca_event ev) } } -static int dctcp_get_info(struct sock *sk, u32 ext, struct sk_buff *skb) +static size_t dctcp_get_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info) { const struct dctcp *ca = inet_csk_ca(sk); @@ -286,18 +287,17 @@ static int dctcp_get_info(struct sock *sk, u32 ext, struct sk_buff *skb) */ if (ext & (1 << (INET_DIAG_DCTCPINFO - 1)) || ext & (1 << (INET_DIAG_VEGASINFO - 1))) { - struct tcp_dctcp_info info; - - memset(&info, 0, sizeof(info)); + memset(info, 0, sizeof(struct tcp_dctcp_info)); if (inet_csk(sk)->icsk_ca_ops != &dctcp_reno) { - info.dctcp_enabled = 1; - info.dctcp_ce_state = (u16) ca->ce_state; - info.dctcp_alpha = ca->dctcp_alpha; - info.dctcp_ab_ecn = ca->acked_bytes_ecn; - info.dctcp_ab_tot = ca->acked_bytes_total; + info->dctcp.dctcp_enabled = 1; + info->dctcp.dctcp_ce_state = (u16) ca->ce_state; + info->dctcp.dctcp_alpha = ca->dctcp_alpha; + info->dctcp.dctcp_ab_ecn = ca->acked_bytes_ecn; + info->dctcp.dctcp_ab_tot = ca->acked_bytes_total; } - return nla_put(skb, INET_DIAG_DCTCPINFO, sizeof(info), &info); + *attr = INET_DIAG_DCTCPINFO; + return sizeof(*info); } return 0; } diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c index 67476f085e48..f71002e4db0b 100644 --- a/net/ipv4/tcp_illinois.c +++ b/net/ipv4/tcp_illinois.c @@ -300,24 +300,25 @@ static u32 tcp_illinois_ssthresh(struct sock *sk) } /* Extract info for Tcp socket info provided via netlink. */ -static int tcp_illinois_info(struct sock *sk, u32 ext, struct sk_buff *skb) +static size_t tcp_illinois_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info) { const struct illinois *ca = inet_csk_ca(sk); if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) { - struct tcpvegas_info info = { - .tcpv_enabled = 1, - .tcpv_rttcnt = ca->cnt_rtt, - .tcpv_minrtt = ca->base_rtt, - }; + info->vegas.tcpv_enabled = 1; + info->vegas.tcpv_rttcnt = ca->cnt_rtt; + info->vegas.tcpv_minrtt = ca->base_rtt; + info->vegas.tcpv_rtt = 0; - if (info.tcpv_rttcnt > 0) { + if (info->vegas.tcpv_rttcnt > 0) { u64 t = ca->sum_rtt; - do_div(t, info.tcpv_rttcnt); - info.tcpv_rtt = t; + do_div(t, info->vegas.tcpv_rttcnt); + info->vegas.tcpv_rtt = t; } - return nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info); + *attr = INET_DIAG_VEGASINFO; + return sizeof(struct tcpvegas_info); } return 0; } diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index c71a1b8f7bde..a6cea1d5e20d 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c @@ -286,18 +286,19 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) } /* Extract info for Tcp socket info provided via netlink. */ -int tcp_vegas_get_info(struct sock *sk, u32 ext, struct sk_buff *skb) +size_t tcp_vegas_get_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info) { const struct vegas *ca = inet_csk_ca(sk); + if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) { - struct tcpvegas_info info = { - .tcpv_enabled = ca->doing_vegas_now, - .tcpv_rttcnt = ca->cntRTT, - .tcpv_rtt = ca->baseRTT, - .tcpv_minrtt = ca->minRTT, - }; - - return nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info); + info->vegas.tcpv_enabled = ca->doing_vegas_now, + info->vegas.tcpv_rttcnt = ca->cntRTT, + info->vegas.tcpv_rtt = ca->baseRTT, + info->vegas.tcpv_minrtt = ca->minRTT, + + *attr = INET_DIAG_VEGASINFO; + return sizeof(struct tcpvegas_info); } return 0; } diff --git a/net/ipv4/tcp_vegas.h b/net/ipv4/tcp_vegas.h index e8a6b33cc61d..ef9da5306c68 100644 --- a/net/ipv4/tcp_vegas.h +++ b/net/ipv4/tcp_vegas.h @@ -19,6 +19,7 @@ void tcp_vegas_init(struct sock *sk); void tcp_vegas_state(struct sock *sk, u8 ca_state); void tcp_vegas_pkts_acked(struct sock *sk, u32 cnt, s32 rtt_us); void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event); -int tcp_vegas_get_info(struct sock *sk, u32 ext, struct sk_buff *skb); +size_t tcp_vegas_get_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info); #endif /* __TCP_VEGAS_H */ -- cgit v1.2.3 From 6e9250f59ef9efb932c84850cd221f22c2a03c4a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 28 Apr 2015 16:23:49 -0700 Subject: tcp: add TCP_CC_INFO socket option Some Congestion Control modules can provide per flow information, but current way to get this information is to use netlink. Like TCP_INFO, let's add TCP_CC_INFO so that applications can issue a getsockopt() if they have a socket file descriptor, instead of playing complex netlink games. Sample usage would be : union tcp_cc_info info; socklen_t len = sizeof(info); if (getsockopt(fd, SOL_TCP, TCP_CC_INFO, &info, &len) == -1) Signed-off-by: Eric Dumazet Cc: Yuchung Cheng Cc: Neal Cardwell Acked-by: Neal Cardwell Acked-by: Daniel Borkmann Acked-by: Yuchung Cheng Signed-off-by: David S. Miller --- include/uapi/linux/tcp.h | 1 + net/ipv4/tcp.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h index a48f93f3207b..faa72f4fa547 100644 --- a/include/uapi/linux/tcp.h +++ b/include/uapi/linux/tcp.h @@ -112,6 +112,7 @@ enum { #define TCP_FASTOPEN 23 /* Enable FastOpen on listeners */ #define TCP_TIMESTAMP 24 #define TCP_NOTSENT_LOWAT 25 /* limit number of unsent bytes in write queue */ +#define TCP_CC_INFO 26 /* Get Congestion Control (optional) info */ struct tcp_repair_opt { __u32 opt_code; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 99fcc0b22c92..46efa03d2b11 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -252,6 +252,7 @@ #include #include #include +#include #include #include #include @@ -2739,6 +2740,26 @@ static int do_tcp_getsockopt(struct sock *sk, int level, return -EFAULT; return 0; } + case TCP_CC_INFO: { + const struct tcp_congestion_ops *ca_ops; + union tcp_cc_info info; + size_t sz = 0; + int attr; + + if (get_user(len, optlen)) + return -EFAULT; + + ca_ops = icsk->icsk_ca_ops; + if (ca_ops && ca_ops->get_info) + sz = ca_ops->get_info(sk, ~0U, &attr, &info); + + len = min_t(unsigned int, len, sz); + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &info, len)) + return -EFAULT; + return 0; + } case TCP_QUICKACK: val = !icsk->icsk_ack.pingpong; break; -- cgit v1.2.3 From 42fb23e2f57accbed69804e6d72ea3a88b8a84c4 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Thu, 30 Apr 2015 17:44:52 +0200 Subject: mac802154: add description to mac802154 APIs This patch adds the proper description to the mac802154 core APIs. Signed-off-by: Varka Bhadram Acked-by: Alexander Aring Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/mac802154.h | 94 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/mac802154.h b/include/net/mac802154.h index e18e7fd43f47..7df28a4c23f9 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -247,19 +247,109 @@ static inline void ieee802154_le64_to_be64(void *be64_dst, const void *le64_src) __put_unaligned_memmove64(swab64p(le64_src), be64_dst); } -/* Basic interface to register ieee802154 device */ +/** + * ieee802154_alloc_hw - Allocate a new hardware device + * + * This must be called once for each hardware device. The returned pointer + * must be used to refer to this device when calling other functions. + * mac802154 allocates a private data area for the driver pointed to by + * @priv in &struct ieee802154_hw, the size of this area is given as + * @priv_data_len. + * + * @priv_data_len: length of private data + * @ops: callbacks for this device + * + * Return: A pointer to the new hardware device, or %NULL on error. + */ struct ieee802154_hw * ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops); + +/** + * ieee802154_free_hw - free hardware descriptor + * + * This function frees everything that was allocated, including the + * private data for the driver. You must call ieee802154_unregister_hw() + * before calling this function. + * + * @hw: the hardware to free + */ void ieee802154_free_hw(struct ieee802154_hw *hw); + +/** + * ieee802154_register_hw - Register hardware device + * + * You must call this function before any other functions in + * mac802154. Note that before a hardware can be registered, you + * need to fill the contained wpan_phy's information. + * + * @hw: the device to register as returned by ieee802154_alloc_hw() + * + * Return: 0 on success. An error code otherwise. + */ int ieee802154_register_hw(struct ieee802154_hw *hw); + +/** + * ieee802154_unregister_hw - Unregister a hardware device + * + * This function instructs mac802154 to free allocated resources + * and unregister netdevices from the networking subsystem. + * + * @hw: the hardware to unregister + */ void ieee802154_unregister_hw(struct ieee802154_hw *hw); +/** + * ieee802154_rx - receive frame + * + * Use this function to hand received frames to mac802154. The receive + * buffer in @skb must start with an IEEE 802.15.4 header. In case of a + * paged @skb is used, the driver is recommended to put the ieee802154 + * header of the frame on the linear part of the @skb to avoid memory + * allocation and/or memcpy by the stack. + * + * This function may not be called in IRQ context. Calls to this function + * for a single hardware must be synchronized against each other. + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac802154 after this call + */ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb); + +/** + * ieee802154_rx_irqsafe - receive frame + * + * Like ieee802154_rx() but can be called in IRQ context + * (internally defers to a tasklet.) + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac802154 after this call + * @lqi: link quality indicator + */ void ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi); - +/** + * ieee802154_wake_queue - wake ieee802154 queue + * @hw: pointer as obtained from ieee802154_alloc_hw(). + * + * Drivers should use this function instead of netif_wake_queue. + */ void ieee802154_wake_queue(struct ieee802154_hw *hw); + +/** + * ieee802154_stop_queue - stop ieee802154 queue + * @hw: pointer as obtained from ieee802154_alloc_hw(). + * + * Drivers should use this function instead of netif_stop_queue. + */ void ieee802154_stop_queue(struct ieee802154_hw *hw); + +/** + * ieee802154_xmit_complete - frame transmission complete + * + * @hw: pointer as obtained from ieee802154_alloc_hw(). + * @skb: buffer for transmission + * @ifs_handling: indicate interframe space handling + */ void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb, bool ifs_handling); -- cgit v1.2.3 From 5b4a10390460cccf17a9fac739e153d68cf25ef5 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Thu, 30 Apr 2015 17:44:57 +0200 Subject: cfg802154: pass name_assign_type to rdev_add_virtual_intf() This code is based on commit 6bab2e19c5ffd ("cfg80211: pass name_assign_type to rdev_add_virtual_intf()") This will expose in sysfs whether the ifname of a IEEE-802.15.4 device is set by userspace or generated by the kernel. We are using two types of name_assign_types o NET_NAME_ENUM: Default interface name provided by kernel o NET_NAME_USER: Interface name provided by user. Signed-off-by: Varka Bhadram Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 2 ++ net/ieee802154/nl-phy.c | 5 ++++- net/ieee802154/nl802154.c | 2 +- net/ieee802154/rdev-ops.h | 10 +++++++--- net/mac802154/cfg.c | 9 ++++++--- net/mac802154/ieee802154_i.h | 3 ++- net/mac802154/iface.c | 5 +++-- net/mac802154/main.c | 3 ++- 8 files changed, 27 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index eeda67652766..6ea16c84293b 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -30,11 +30,13 @@ struct wpan_phy_cca; struct cfg802154_ops { struct net_device * (*add_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, const char *name, + unsigned char name_assign_type, int type); void (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, struct net_device *dev); int (*add_virtual_intf)(struct wpan_phy *wpan_phy, const char *name, + unsigned char name_assign_type, enum nl802154_iftype type, __le64 extended_addr); int (*del_virtual_intf)(struct wpan_phy *wpan_phy, diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index 1b9d25f6e898..346c6665d25e 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c @@ -175,6 +175,7 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) int rc = -ENOBUFS; struct net_device *dev; int type = __IEEE802154_DEV_INVALID; + unsigned char name_assign_type; pr_debug("%s\n", __func__); @@ -190,8 +191,10 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0') return -EINVAL; /* phy name should be null-terminated */ + name_assign_type = NET_NAME_USER; } else { devname = "wpan%d"; + name_assign_type = NET_NAME_ENUM; } if (strlen(devname) >= IFNAMSIZ) @@ -221,7 +224,7 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) } dev = rdev_add_virtual_intf_deprecated(wpan_phy_to_rdev(phy), devname, - type); + name_assign_type, type); if (IS_ERR(dev)) { rc = PTR_ERR(dev); goto nla_put_failure; diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index a4daf91b8d0a..f3c12f6a4a39 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -589,7 +589,7 @@ static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info) return rdev_add_virtual_intf(rdev, nla_data(info->attrs[NL802154_ATTR_IFNAME]), - type, extended_addr); + NET_NAME_USER, type, extended_addr); } static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info) diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 624413ee095f..7b5a9dd94fe5 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -8,10 +8,12 @@ static inline struct net_device * rdev_add_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, - const char *name, int type) + const char *name, + unsigned char name_assign_type, + int type) { return rdev->ops->add_virtual_intf_deprecated(&rdev->wpan_phy, name, - type); + name_assign_type, type); } static inline void @@ -23,13 +25,15 @@ rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, static inline int rdev_add_virtual_intf(struct cfg802154_registered_device *rdev, char *name, + unsigned char name_assign_type, enum nl802154_iftype type, __le64 extended_addr) { int ret; trace_802154_rdev_add_virtual_intf(&rdev->wpan_phy, name, type, extended_addr); - ret = rdev->ops->add_virtual_intf(&rdev->wpan_phy, name, type, + ret = rdev->ops->add_virtual_intf(&rdev->wpan_phy, name, + name_assign_type, type, extended_addr); trace_802154_rdev_return_int(&rdev->wpan_phy, ret); return ret; diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 5d9f68c75e5f..70be9c799f8a 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -22,13 +22,14 @@ static struct net_device * ieee802154_add_iface_deprecated(struct wpan_phy *wpan_phy, - const char *name, int type) + const char *name, + unsigned char name_assign_type, int type) { struct ieee802154_local *local = wpan_phy_priv(wpan_phy); struct net_device *dev; rtnl_lock(); - dev = ieee802154_if_add(local, name, type, + dev = ieee802154_if_add(local, name, name_assign_type, type, cpu_to_le64(0x0000000000000000ULL)); rtnl_unlock(); @@ -45,12 +46,14 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy, static int ieee802154_add_iface(struct wpan_phy *phy, const char *name, + unsigned char name_assign_type, enum nl802154_iftype type, __le64 extended_addr) { struct ieee802154_local *local = wpan_phy_priv(phy); struct net_device *err; - err = ieee802154_if_add(local, name, type, extended_addr); + err = ieee802154_if_add(local, name, name_assign_type, type, + extended_addr); return PTR_ERR_OR_ZERO(err); } diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index bebd70ffc7a3..127ba18386fc 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -182,7 +182,8 @@ void ieee802154_iface_exit(void); void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata); struct net_device * ieee802154_if_add(struct ieee802154_local *local, const char *name, - enum nl802154_iftype type, __le64 extended_addr); + unsigned char name_assign_type, enum nl802154_iftype type, + __le64 extended_addr); void ieee802154_remove_interfaces(struct ieee802154_local *local); #endif /* __IEEE802154_I_H */ diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index 38b56f9d9386..91b75abbd1a1 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -522,7 +522,8 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, struct net_device * ieee802154_if_add(struct ieee802154_local *local, const char *name, - enum nl802154_iftype type, __le64 extended_addr) + unsigned char name_assign_type, enum nl802154_iftype type, + __le64 extended_addr) { struct net_device *ndev = NULL; struct ieee802154_sub_if_data *sdata = NULL; @@ -531,7 +532,7 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name, ASSERT_RTNL(); ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name, - NET_NAME_UNKNOWN, ieee802154_if_setup); + name_assign_type, ieee802154_if_setup); if (!ndev) return ERR_PTR(-ENOMEM); diff --git a/net/mac802154/main.c b/net/mac802154/main.c index 8500378c8318..68b9667323ec 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -161,7 +161,8 @@ int ieee802154_register_hw(struct ieee802154_hw *hw) rtnl_lock(); - dev = ieee802154_if_add(local, "wpan%d", NL802154_IFTYPE_NODE, + dev = ieee802154_if_add(local, "wpan%d", NET_NAME_ENUM, + NL802154_IFTYPE_NODE, cpu_to_le64(0x0000000000000000ULL)); if (IS_ERR(dev)) { rtnl_unlock(); -- cgit v1.2.3 From 4b32b5ad31a68a661f761c76dfd0d076636d3ae9 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Tue, 28 Apr 2015 13:03:06 -0700 Subject: ipv6: Stop rt6_info from using inet_peer's metrics inet_peer is indexed by the dst address alone. However, the fib6 tree could have multiple routing entries (rt6_info) for the same dst. For example, 1. A /128 dst via multiple gateways. 2. A RTF_CACHE route cloned from a /128 route. In the above cases, all of them will share the same metrics and step on each other. This patch will steer away from inet_peer's metrics and use dst_cow_metrics_generic() for everything. Change Highlights: 1. Remove rt6_cow_metrics() which currently acquires metrics from inet_peer for DST_HOST route (i.e. /128 route). 2. Add rt6i_pmtu to take care of the pmtu update to avoid creating a full size metrics just to override the RTAX_MTU. 3. After (2), the RTF_CACHE route can also share the metrics with its dst.from route, by: dst_init_metrics(&cache_rt->dst, dst_metrics_ptr(cache_rt->dst.from), true); 4. Stop creating RTF_CACHE route by cloning another RTF_CACHE route. Instead, directly clone from rt->dst. [ Currently, cloning from another RTF_CACHE is only possible during rt6_do_redirect(). Also, the old clone is removed from the tree immediately after the new clone is added. ] In case of cloning from an older redirect RTF_CACHE, it should work as before. In case of cloning from an older pmtu RTF_CACHE, this patch will forget the pmtu and re-learn it (if there is any) from the redirected route. The _rt6i_peer and DST_METRICS_FORCE_OVERWRITE will be removed in the next cleanup patch. Signed-off-by: Martin KaFai Lau Reviewed-by: Hannes Frederic Sowa Cc: Steffen Klassert Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 10 +---- net/ipv6/route.c | 102 +++++++++++++++++++++++++++++--------------------- 2 files changed, 60 insertions(+), 52 deletions(-) (limited to 'include') diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 20e80fa7bbdd..7383a8cc8f84 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -124,6 +124,7 @@ struct rt6_info { unsigned long _rt6i_peer; u32 rt6i_metric; + u32 rt6i_pmtu; /* more non-fragment space at head required */ unsigned short rt6i_nfheader_len; u8 rt6i_protocol; @@ -189,15 +190,6 @@ static inline void rt6_update_expires(struct rt6_info *rt0, int timeout) rt0->rt6i_flags |= RTF_EXPIRES; } -static inline void rt6_set_from(struct rt6_info *rt, struct rt6_info *from) -{ - struct dst_entry *new = (struct dst_entry *) from; - - rt->rt6i_flags &= ~RTF_EXPIRES; - dst_hold(new); - rt->dst.from = new; -} - static inline void ip6_rt_put(struct rt6_info *rt) { /* dst_release() accepts a NULL parameter. diff --git a/net/ipv6/route.c b/net/ipv6/route.c index aa4cfdd13f28..4d6eb5d90cb4 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -92,6 +92,7 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb, u32 mtu); static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb); +static void rt6_dst_from_metrics_check(struct rt6_info *rt); static int rt6_score_route(struct rt6_info *rt, int oif, int strict); #ifdef CONFIG_IPV6_ROUTE_INFO @@ -136,33 +137,12 @@ static struct inet_peer *rt6_get_peer_create(struct rt6_info *rt) static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) { - struct rt6_info *rt = (struct rt6_info *) dst; - struct inet_peer *peer; - u32 *p = NULL; + struct rt6_info *rt = (struct rt6_info *)dst; - if (!(rt->dst.flags & DST_HOST)) + if (rt->rt6i_flags & RTF_CACHE) + return NULL; + else return dst_cow_metrics_generic(dst, old); - - peer = rt6_get_peer_create(rt); - if (peer) { - u32 *old_p = __DST_METRICS_PTR(old); - unsigned long prev, new; - - p = peer->metrics; - if (inet_metrics_new(peer) || - (old & DST_METRICS_FORCE_OVERWRITE)) - memcpy(p, old_p, sizeof(u32) * RTAX_MAX); - - new = (unsigned long) p; - prev = cmpxchg(&dst->_metrics, old, new); - - if (prev != old) { - p = __DST_METRICS_PTR(prev); - if (prev & DST_METRICS_READ_ONLY) - p = NULL; - } - } - return p; } static inline const void *choose_neigh_daddr(struct rt6_info *rt, @@ -323,8 +303,7 @@ static void ip6_dst_destroy(struct dst_entry *dst) struct inet6_dev *idev = rt->rt6i_idev; struct dst_entry *from = dst->from; - if (!(rt->dst.flags & DST_HOST)) - dst_destroy_metrics_generic(dst); + dst_destroy_metrics_generic(dst); if (idev) { rt->rt6i_idev = NULL; @@ -333,11 +312,6 @@ static void ip6_dst_destroy(struct dst_entry *dst) dst->from = NULL; dst_release(from); - - if (rt6_has_peer(rt)) { - struct inet_peer *peer = rt6_peer_ptr(rt); - inet_putpeer(peer); - } } static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, @@ -1003,6 +977,7 @@ redo_rt6_select: goto redo_fib6_lookup_lock; out2: + rt6_dst_from_metrics_check(rt); rt->dst.lastuse = jiffies; rt->dst.__use++; @@ -1111,6 +1086,13 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori * Destination cache support functions */ +static void rt6_dst_from_metrics_check(struct rt6_info *rt) +{ + if (rt->dst.from && + dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from)) + dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true); +} + static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) { struct rt6_info *rt; @@ -1127,6 +1109,8 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) if (rt6_check_expired(rt)) return NULL; + rt6_dst_from_metrics_check(rt); + return dst; } @@ -1179,7 +1163,7 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU; - dst_metric_set(dst, RTAX_MTU, mtu); + rt6->rt6i_pmtu = mtu; rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires); } } @@ -1359,9 +1343,14 @@ static unsigned int ip6_default_advmss(const struct dst_entry *dst) static unsigned int ip6_mtu(const struct dst_entry *dst) { + const struct rt6_info *rt = (const struct rt6_info *)dst; + unsigned int mtu = rt->rt6i_pmtu; struct inet6_dev *idev; - unsigned int mtu = dst_metric_raw(dst, RTAX_MTU); + if (mtu) + goto out; + + mtu = dst_metric_raw(dst, RTAX_MTU); if (mtu) goto out; @@ -1947,12 +1936,27 @@ out: * Misc support functions */ +static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from) +{ + BUG_ON(from->dst.from); + + rt->rt6i_flags &= ~RTF_EXPIRES; + dst_hold(&from->dst); + rt->dst.from = &from->dst; + dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true); +} + static struct rt6_info *ip6_rt_copy(struct rt6_info *ort, const struct in6_addr *dest) { struct net *net = dev_net(ort->dst.dev); - struct rt6_info *rt = ip6_dst_alloc(net, ort->dst.dev, 0, - ort->rt6i_table); + struct rt6_info *rt; + + if (ort->rt6i_flags & RTF_CACHE) + ort = (struct rt6_info *)ort->dst.from; + + rt = ip6_dst_alloc(net, ort->dst.dev, 0, + ort->rt6i_table); if (rt) { rt->dst.input = ort->dst.input; @@ -1961,7 +1965,6 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort, rt->rt6i_dst.addr = *dest; rt->rt6i_dst.plen = 128; - dst_copy_metrics(&rt->dst, &ort->dst); rt->dst.error = ort->dst.error; rt->rt6i_idev = ort->rt6i_idev; if (rt->rt6i_idev) @@ -2393,11 +2396,20 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) PMTU discouvery. */ if (rt->dst.dev == arg->dev && - !dst_metric_locked(&rt->dst, RTAX_MTU) && - (dst_mtu(&rt->dst) >= arg->mtu || - (dst_mtu(&rt->dst) < arg->mtu && - dst_mtu(&rt->dst) == idev->cnf.mtu6))) { - dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu); + !dst_metric_locked(&rt->dst, RTAX_MTU)) { + if (rt->rt6i_flags & RTF_CACHE) { + /* For RTF_CACHE with rt6i_pmtu == 0 + * (i.e. a redirected route), + * the metrics of its rt->dst.from has already + * been updated. + */ + if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu) + rt->rt6i_pmtu = arg->mtu; + } else if (dst_mtu(&rt->dst) >= arg->mtu || + (dst_mtu(&rt->dst) < arg->mtu && + dst_mtu(&rt->dst) == idev->cnf.mtu6)) { + dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu); + } } return 0; } @@ -2627,6 +2639,7 @@ static int rt6_fill_node(struct net *net, int iif, int type, u32 portid, u32 seq, int prefix, int nowait, unsigned int flags) { + u32 metrics[RTAX_MAX]; struct rtmsg *rtm; struct nlmsghdr *nlh; long expires; @@ -2740,7 +2753,10 @@ static int rt6_fill_node(struct net *net, goto nla_put_failure; } - if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) + memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics)); + if (rt->rt6i_pmtu) + metrics[RTAX_MTU - 1] = rt->rt6i_pmtu; + if (rtnetlink_put_metrics(skb, metrics) < 0) goto nla_put_failure; if (rt->rt6i_flags & RTF_GATEWAY) { -- cgit v1.2.3 From afc4eef80c92b199357db3570d3c9c7631d699ff Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Tue, 28 Apr 2015 13:03:07 -0700 Subject: ipv6: Remove DST_METRICS_FORCE_OVERWRITE and _rt6i_peer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _rt6i_peer is no longer needed after the last patch, 'ipv6: Stop rt6_info from using inet_peer's metrics'. DST_METRICS_FORCE_OVERWRITE is added by commit e5fd387ad5b3 ("ipv6: do not overwrite inetpeer metrics prematurely"). Since inetpeer is no longer used for metrics, this bit is also not needed. Signed-off-by: Martin KaFai Lau Reviewed-by: Hannes Frederic Sowa Cc: Michal Kubeček Cc: Steffen Klassert Signed-off-by: David S. Miller --- include/net/dst.h | 6 ------ include/net/ip6_fib.h | 31 ------------------------------- net/ipv6/route.c | 36 +----------------------------------- net/ipv6/xfrm6_policy.c | 14 -------------- 4 files changed, 1 insertion(+), 86 deletions(-) (limited to 'include') diff --git a/include/net/dst.h b/include/net/dst.h index 0fb99a26e973..22aa93f165f1 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -109,7 +109,6 @@ u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old); extern const u32 dst_default_metrics[]; #define DST_METRICS_READ_ONLY 0x1UL -#define DST_METRICS_FORCE_OVERWRITE 0x2UL #define DST_METRICS_FLAGS 0x3UL #define __DST_METRICS_PTR(Y) \ ((u32 *)((Y) & ~DST_METRICS_FLAGS)) @@ -120,11 +119,6 @@ static inline bool dst_metrics_read_only(const struct dst_entry *dst) return dst->_metrics & DST_METRICS_READ_ONLY; } -static inline void dst_metrics_set_force_overwrite(struct dst_entry *dst) -{ - dst->_metrics |= DST_METRICS_FORCE_OVERWRITE; -} - void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old); static inline void dst_destroy_metrics_generic(struct dst_entry *dst) diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 7383a8cc8f84..e00018011028 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -121,7 +121,6 @@ struct rt6_info { struct rt6key rt6i_prefsrc; struct inet6_dev *rt6i_idev; - unsigned long _rt6i_peer; u32 rt6i_metric; u32 rt6i_pmtu; @@ -130,36 +129,6 @@ struct rt6_info { u8 rt6i_protocol; }; -static inline struct inet_peer *rt6_peer_ptr(struct rt6_info *rt) -{ - return inetpeer_ptr(rt->_rt6i_peer); -} - -static inline bool rt6_has_peer(struct rt6_info *rt) -{ - return inetpeer_ptr_is_peer(rt->_rt6i_peer); -} - -static inline void __rt6_set_peer(struct rt6_info *rt, struct inet_peer *peer) -{ - __inetpeer_ptr_set_peer(&rt->_rt6i_peer, peer); -} - -static inline bool rt6_set_peer(struct rt6_info *rt, struct inet_peer *peer) -{ - return inetpeer_ptr_set_peer(&rt->_rt6i_peer, peer); -} - -static inline void rt6_init_peer(struct rt6_info *rt, struct inet_peer_base *base) -{ - inetpeer_init_ptr(&rt->_rt6i_peer, base); -} - -static inline void rt6_transfer_peer(struct rt6_info *rt, struct rt6_info *ort) -{ - inetpeer_transfer_peer(&rt->_rt6i_peer, &ort->_rt6i_peer); -} - static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) { return ((struct rt6_info *)dst)->rt6i_idev; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 4d6eb5d90cb4..352271154ddb 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -105,36 +105,6 @@ static struct rt6_info *rt6_get_route_info(struct net *net, const struct in6_addr *gwaddr, int ifindex); #endif -static void rt6_bind_peer(struct rt6_info *rt, int create) -{ - struct inet_peer_base *base; - struct inet_peer *peer; - - base = inetpeer_base_ptr(rt->_rt6i_peer); - if (!base) - return; - - peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create); - if (peer) { - if (!rt6_set_peer(rt, peer)) - inet_putpeer(peer); - } -} - -static struct inet_peer *__rt6_get_peer(struct rt6_info *rt, int create) -{ - if (rt6_has_peer(rt)) - return rt6_peer_ptr(rt); - - rt6_bind_peer(rt, create); - return (rt6_has_peer(rt) ? rt6_peer_ptr(rt) : NULL); -} - -static struct inet_peer *rt6_get_peer_create(struct rt6_info *rt) -{ - return __rt6_get_peer(rt, 1); -} - static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) { struct rt6_info *rt = (struct rt6_info *)dst; @@ -291,7 +261,6 @@ static inline struct rt6_info *ip6_dst_alloc(struct net *net, struct dst_entry *dst = &rt->dst; memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst)); - rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers); INIT_LIST_HEAD(&rt->rt6i_siblings); } return rt; @@ -1052,7 +1021,6 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori new = &rt->dst; memset(new + 1, 0, sizeof(*rt) - sizeof(*new)); - rt6_init_peer(rt, net->ipv6.peers); new->__use = 1; new->input = dst_discard; @@ -1597,10 +1565,8 @@ int ip6_route_add(struct fib6_config *cfg) ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); rt->rt6i_dst.plen = cfg->fc_dst_len; - if (rt->rt6i_dst.plen == 128) { + if (rt->rt6i_dst.plen == 128) rt->dst.flags |= DST_HOST; - dst_metrics_set_force_overwrite(&rt->dst); - } #ifdef CONFIG_IPV6_SUBTREES ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index f337a908a76a..6ae256b4c55a 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -71,13 +71,6 @@ static int xfrm6_get_tos(const struct flowi *fl) return 0; } -static void xfrm6_init_dst(struct net *net, struct xfrm_dst *xdst) -{ - struct rt6_info *rt = (struct rt6_info *)xdst; - - rt6_init_peer(rt, net->ipv6.peers); -} - static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst, int nfheader_len) { @@ -106,8 +99,6 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, return -ENODEV; } - rt6_transfer_peer(&xdst->u.rt6, rt); - /* Sheit... I remember I did this right. Apparently, * it was magically lost, so this code needs audit */ xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | @@ -255,10 +246,6 @@ static void xfrm6_dst_destroy(struct dst_entry *dst) if (likely(xdst->u.rt6.rt6i_idev)) in6_dev_put(xdst->u.rt6.rt6i_idev); dst_destroy_metrics_generic(dst); - if (rt6_has_peer(&xdst->u.rt6)) { - struct inet_peer *peer = rt6_peer_ptr(&xdst->u.rt6); - inet_putpeer(peer); - } xfrm_dst_destroy(xdst); } @@ -308,7 +295,6 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { .get_saddr = xfrm6_get_saddr, .decode_session = _decode_session6, .get_tos = xfrm6_get_tos, - .init_dst = xfrm6_init_dst, .init_path = xfrm6_init_path, .fill_dst = xfrm6_fill_dst, .blackhole_route = ip6_blackhole_route, -- cgit v1.2.3 From e412d3a32badcf17541d7443b033769fdf39b545 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sat, 2 May 2015 08:42:29 +0930 Subject: virtio: fix typo in vring_need_event() doc comment Here the "other side" refers to the guest or host. Signed-off-by: Stefan Hajnoczi Signed-off-by: Rusty Russell Signed-off-by: Linus Torvalds --- include/uapi/linux/virtio_ring.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/virtio_ring.h b/include/uapi/linux/virtio_ring.h index a3318f31e8e7..915980ac68df 100644 --- a/include/uapi/linux/virtio_ring.h +++ b/include/uapi/linux/virtio_ring.h @@ -155,7 +155,7 @@ static inline unsigned vring_size(unsigned int num, unsigned long align) } /* The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX */ -/* Assuming a given event_idx value from the other size, if +/* Assuming a given event_idx value from the other side, if * we have just incremented index from old to new_idx, * should we trigger an event? */ static inline int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old) -- cgit v1.2.3 From 4749c3ef854e3a5d3dd3cc0ccd2dcb7e05d583bd Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 30 Apr 2015 12:12:00 +0200 Subject: net: sched: remove TC_MUNGED bits Not used. pedit sets TC_MUNGED when packet content was altered, but all the core does is unset MUNGED again and then set OK2MUNGE. And the latter isn't tested anywhere. So lets remove both TC_MUNGED and TC_OK2MUNGE. Signed-off-by: Florian Westphal Acked-by: Alexei Starovoitov Acked-by: Daniel Borkmann Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- Documentation/networking/tc-actions-env-rules.txt | 2 -- include/net/sch_generic.h | 2 -- include/uapi/linux/pkt_cls.h | 3 +++ net/sched/act_api.c | 5 ----- net/sched/act_pedit.c | 5 +---- 5 files changed, 4 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/Documentation/networking/tc-actions-env-rules.txt b/Documentation/networking/tc-actions-env-rules.txt index 70d6cf608251..95c71716b2e2 100644 --- a/Documentation/networking/tc-actions-env-rules.txt +++ b/Documentation/networking/tc-actions-env-rules.txt @@ -14,8 +14,6 @@ resets them for you, so invoke skb_act_clone() rather than skb_clone(). 2) If you munge any packet thou shalt call pskb_expand_head in the case someone else is referencing the skb. After that you "own" the skb. -You must also tell us if it is ok to munge the packet (TC_OK2MUNGE), -this way any action downstream can stomp on the packet. 3) Dropping packets you don't own is a no-no. You simply return TC_ACT_SHOT to the caller and they will drop it. diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 6d778efcfdfd..994b5a092f33 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -755,8 +755,6 @@ static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask, if (n) { n->tc_verd = SET_TC_VERD(n->tc_verd, 0); - n->tc_verd = CLR_TC_OK2MUNGE(n->tc_verd); - n->tc_verd = CLR_TC_MUNGED(n->tc_verd); } return n; } diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index bf08e76bf505..6810ca43a80a 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -35,6 +35,8 @@ bits 9,10,11: redirect counter - redirect TTL. Loop avoidance * * */ +#ifndef __KERNEL__ +/* backwards compat for userspace only */ #define TC_MUNGED _TC_MAKEMASK1(0) #define SET_TC_MUNGED(v) ( TC_MUNGED | (v & ~TC_MUNGED)) #define CLR_TC_MUNGED(v) ( v & ~TC_MUNGED) @@ -42,6 +44,7 @@ bits 9,10,11: redirect counter - redirect TTL. Loop avoidance #define TC_OK2MUNGE _TC_MAKEMASK1(1) #define SET_TC_OK2MUNGE(v) ( TC_OK2MUNGE | (v & ~TC_OK2MUNGE)) #define CLR_TC_OK2MUNGE(v) ( v & ~TC_OK2MUNGE) +#endif #define S_TC_VERD _TC_MAKE32(2) #define M_TC_VERD _TC_MAKEMASK(4,S_TC_VERD) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 3d43e4979f27..af427a3dbcba 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -392,11 +392,6 @@ int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions, list_for_each_entry(a, actions, list) { repeat: ret = a->ops->act(skb, a, res); - if (TC_MUNGED & skb->tc_verd) { - /* copied already, allow trampling */ - skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd); - skb->tc_verd = CLR_TC_MUNGED(skb->tc_verd); - } if (ret == TC_ACT_REPEAT) goto repeat; /* we need a ttl - JHS */ if (ret != TC_ACT_PIPE) diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 59649d588d79..17e6d6669c7f 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -108,7 +108,7 @@ static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) { struct tcf_pedit *p = a->priv; - int i, munged = 0; + int i; unsigned int off; if (skb_unclone(skb, GFP_ATOMIC)) @@ -156,11 +156,8 @@ static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a, *ptr = ((*ptr & tkey->mask) ^ tkey->val); if (ptr == &_data) skb_store_bits(skb, off + offset, ptr, 4); - munged++; } - if (munged) - skb->tc_verd = SET_TC_MUNGED(skb->tc_verd); goto done; } else WARN(1, "pedit BUG: index %d\n", p->tcf_index); -- cgit v1.2.3 From 82a584b7cd366511a22e37675b029cf2fb58e291 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Wed, 29 Apr 2015 15:33:21 -0700 Subject: ipv6: Flow label state ranges This patch divides the IPv6 flow label space into two ranges: 0-7ffff is reserved for flow label manager, 80000-fffff will be used for creating auto flow labels (per RFC6438). This only affects how labels are set on transmit, it does not affect receive. This range split can be disbaled by systcl. Background: IPv6 flow labels have been an unmitigated disappointment thus far in the lifetime of IPv6. Support in HW devices to use them for ECMP is lacking, and OSes don't turn them on by default. If we had these we could get much better hashing in IPv6 networks without resorting to DPI, possibly eliminating some of the motivations to to define new encaps in UDP just for getting ECMP. Unfortunately, the initial specfications of IPv6 did not clarify how they are to be used. There has always been a vague concept that these can be used for ECMP, flow hashing, etc. and we do now have a good standard how to this in RFC6438. The problem is that flow labels can be either stateful or stateless (as in RFC6438), and we are presented with the possibility that a stateless label may collide with a stateful one. Attempts to split the flow label space were rejected in IETF. When we added support in Linux for RFC6438, we could not turn on flow labels by default due to this conflict. This patch splits the flow label space and should give us a path to enabling auto flow labels by default for all IPv6 packets. This is an API change so we need to consider compatibility with existing deployment. The stateful range is chosen to be the lower values in hopes that most uses would have chosen small numbers. Once we resolve the stateless/stateful issue, we can proceed to look at enabling RFC6438 flow labels by default (starting with scaled testing). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 8 ++++++++ include/net/ipv6.h | 9 +++++++-- include/net/netns/ipv6.h | 1 + net/ipv6/af_inet6.c | 1 + net/ipv6/ip6_flowlabel.c | 4 ++++ net/ipv6/sysctl_net_ipv6.c | 8 ++++++++ 6 files changed, 29 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 071fb18dc57c..5095c63e50ed 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1213,6 +1213,14 @@ auto_flowlabels - BOOLEAN FALSE: disabled Default: false +flowlabel_state_ranges - BOOLEAN + Split the flow label number space into two ranges. 0-0x7FFFF is + reserved for the IPv6 flow manager facility, 0x80000-0xFFFFF + is reserved for stateless flow labels as described in RFC6437. + TRUE: enabled + FALSE: disabled + Default: true + anycast_src_echo_reply - BOOLEAN Controls the use of anycast addresses as source addresses for ICMPv6 echo reply diff --git a/include/net/ipv6.h b/include/net/ipv6.h index eec8ad3c9843..53d25ef1699a 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -239,8 +239,10 @@ struct ip6_flowlabel { struct net *fl_net; }; -#define IPV6_FLOWINFO_MASK cpu_to_be32(0x0FFFFFFF) -#define IPV6_FLOWLABEL_MASK cpu_to_be32(0x000FFFFF) +#define IPV6_FLOWINFO_MASK cpu_to_be32(0x0FFFFFFF) +#define IPV6_FLOWLABEL_MASK cpu_to_be32(0x000FFFFF) +#define IPV6_FLOWLABEL_STATELESS_FLAG cpu_to_be32(0x00080000) + #define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK) #define IPV6_TCLASS_SHIFT 20 @@ -719,6 +721,9 @@ static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, hash ^= hash >> 12; flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK; + + if (net->ipv6.sysctl.flowlabel_state_ranges) + flowlabel |= IPV6_FLOWLABEL_STATELESS_FLAG; } return flowlabel; diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index d2527bf81142..8d93544a2d2b 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -34,6 +34,7 @@ struct netns_sysctl_ipv6 { int fwmark_reflect; int idgen_retries; int idgen_delay; + int flowlabel_state_ranges; }; struct netns_ipv6 { diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index eef63b394c5a..4632afa57e05 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -768,6 +768,7 @@ static int __net_init inet6_net_init(struct net *net) net->ipv6.sysctl.auto_flowlabels = 0; net->ipv6.sysctl.idgen_retries = 3; net->ipv6.sysctl.idgen_delay = 1 * HZ; + net->ipv6.sysctl.flowlabel_state_ranges = 1; atomic_set(&net->ipv6.fib6_sernum, 1); err = ipv6_init_mibs(net); diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index d491125011c4..1f9ebe3cbb4a 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -595,6 +595,10 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) if (freq.flr_label & ~IPV6_FLOWLABEL_MASK) return -EINVAL; + if (net->ipv6.sysctl.flowlabel_state_ranges && + (freq.flr_label & IPV6_FLOWLABEL_STATELESS_FLAG)) + return -ERANGE; + fl = fl_create(net, sk, &freq, optval, optlen, &err); if (!fl) return err; diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index abcc79f649b3..4e705add4f18 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -68,6 +68,13 @@ static struct ctl_table ipv6_table_template[] = { .mode = 0644, .proc_handler = proc_dointvec_jiffies, }, + { + .procname = "flowlabel_state_ranges", + .data = &init_net.ipv6.sysctl.flowlabel_state_ranges, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, { } }; @@ -109,6 +116,7 @@ static int __net_init ipv6_sysctl_net_init(struct net *net) ipv6_table[4].data = &net->ipv6.sysctl.fwmark_reflect; ipv6_table[5].data = &net->ipv6.sysctl.idgen_retries; ipv6_table[6].data = &net->ipv6.sysctl.idgen_delay; + ipv6_table[7].data = &net->ipv6.sysctl.flowlabel_state_ranges; ipv6_route_table = ipv6_route_sysctl_init(net); if (!ipv6_route_table) -- cgit v1.2.3 From a5d28090405038ca1f40c13f38d6d4285456efee Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 30 Apr 2015 09:40:40 -0700 Subject: codel: fix maxpacket/mtu confusion Under presence of TSO/GSO/GRO packets, codel at low rates can be quite useless. In following example, not a single packet was ever dropped, while average delay in codel queue is ~100 ms ! qdisc codel 0: parent 1:12 limit 16000p target 5.0ms interval 100.0ms Sent 134376498 bytes 88797 pkt (dropped 0, overlimits 0 requeues 0) backlog 13626b 3p requeues 0 count 0 lastcount 0 ldelay 96.9ms drop_next 0us maxpacket 9084 ecn_mark 0 drop_overlimit 0 This comes from a confusion of what should be the minimal backlog. It is pretty clear it is not 64KB or whatever max GSO packet ever reached the qdisc. codel intent was to use MTU of the device. After the fix, we finally drop some packets, and rtt/cwnd of my single TCP flow are meeting our expectations. qdisc codel 0: parent 1:12 limit 16000p target 5.0ms interval 100.0ms Sent 102798497 bytes 67912 pkt (dropped 1365, overlimits 0 requeues 0) backlog 6056b 3p requeues 0 count 1 lastcount 1 ldelay 36.3ms drop_next 0us maxpacket 10598 ecn_mark 0 drop_overlimit 0 Signed-off-by: Eric Dumazet Cc: Kathleen Nichols Cc: Dave Taht Cc: Van Jacobson Signed-off-by: David S. Miller --- include/net/codel.h | 10 +++++++--- net/sched/sch_codel.c | 2 +- net/sched/sch_fq_codel.c | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/net/codel.h b/include/net/codel.h index aeee28081245..1e18005f7f65 100644 --- a/include/net/codel.h +++ b/include/net/codel.h @@ -120,11 +120,13 @@ static inline u32 codel_time_to_us(codel_time_t val) * struct codel_params - contains codel parameters * @target: target queue size (in time units) * @interval: width of moving time window + * @mtu: device mtu, or minimal queue backlog in bytes. * @ecn: is Explicit Congestion Notification enabled */ struct codel_params { codel_time_t target; codel_time_t interval; + u32 mtu; bool ecn; }; @@ -166,10 +168,12 @@ struct codel_stats { u32 ecn_mark; }; -static void codel_params_init(struct codel_params *params) +static void codel_params_init(struct codel_params *params, + const struct Qdisc *sch) { params->interval = MS2TIME(100); params->target = MS2TIME(5); + params->mtu = psched_mtu(qdisc_dev(sch)); params->ecn = false; } @@ -180,7 +184,7 @@ static void codel_vars_init(struct codel_vars *vars) static void codel_stats_init(struct codel_stats *stats) { - stats->maxpacket = 256; + stats->maxpacket = 0; } /* @@ -234,7 +238,7 @@ static bool codel_should_drop(const struct sk_buff *skb, stats->maxpacket = qdisc_pkt_len(skb); if (codel_time_before(vars->ldelay, params->target) || - sch->qstats.backlog <= stats->maxpacket) { + sch->qstats.backlog <= params->mtu) { /* went below - stay below for at least interval */ vars->first_above_time = 0; return false; diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c index de28f8e968e8..7a0bdb16ac92 100644 --- a/net/sched/sch_codel.c +++ b/net/sched/sch_codel.c @@ -164,7 +164,7 @@ static int codel_init(struct Qdisc *sch, struct nlattr *opt) sch->limit = DEFAULT_CODEL_LIMIT; - codel_params_init(&q->params); + codel_params_init(&q->params, sch); codel_vars_init(&q->vars); codel_stats_init(&q->stats); diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 1e52decb7b59..c244c45b78d7 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -391,7 +391,7 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt) q->perturbation = prandom_u32(); INIT_LIST_HEAD(&q->new_flows); INIT_LIST_HEAD(&q->old_flows); - codel_params_init(&q->cparams); + codel_params_init(&q->cparams, sch); codel_stats_init(&q->cstats); q->cparams.ecn = true; -- cgit v1.2.3 From d54385ce68cd18ab002b46f61246ad197cec92de Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 30 Apr 2015 14:53:54 -0700 Subject: etherdev: Process is_multicast_ether_addr at same size as other operations This change makes it so that we process the address in is_multicast_ether_addr at the same size as the other calls. This allows us to avoid duplicate reads when used with other calls such as is_zero_ether_addr or eth_addr_copy. In addition I have added a 64 bit version of the function so in eth_type_trans we can process the destination address as a 64 bit value throughout. Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- include/linux/etherdevice.h | 24 +++++++++++++++++++++++- net/ethernet/eth.c | 2 +- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 606563ef8a72..c4a10f991fe0 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -110,7 +110,29 @@ static inline bool is_zero_ether_addr(const u8 *addr) */ static inline bool is_multicast_ether_addr(const u8 *addr) { - return 0x01 & addr[0]; +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + u32 a = *(const u32 *)addr; +#else + u16 a = *(const u16 *)addr; +#endif +#ifdef __BIG_ENDIAN + return 0x01 & (a >> ((sizeof(a) * 8) - 8)); +#else + return 0x01 & a; +#endif +} + +static inline bool is_multicast_ether_addr_64bits(const u8 addr[6+2]) +{ +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 +#ifdef __BIG_ENDIAN + return 0x01 & ((*(const u64 *)addr) >> 56); +#else + return 0x01 & (*(const u64 *)addr); +#endif +#else + return is_multicast_ether_addr(addr); +#endif } /** diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 60069318d5d1..21c211e9fd5a 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -159,7 +159,7 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) skb_pull_inline(skb, ETH_HLEN); eth = eth_hdr(skb); - if (unlikely(is_multicast_ether_addr(eth->h_dest))) { + if (unlikely(is_multicast_ether_addr_64bits(eth->h_dest))) { if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast)) skb->pkt_type = PACKET_BROADCAST; else -- cgit v1.2.3 From 50fb799289501c2eab9f43fc9af513027e1e994f Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Fri, 1 May 2015 11:30:12 -0700 Subject: net: Add skb_get_hash_perturb This calls flow_disect and __skb_get_hash to procure a hash for a packet. Input includes a key to initialize jhash. This function does not set skb->hash. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/skbuff.h | 2 ++ net/core/flow_dissector.c | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 66e374d62f64..acb83e249e3f 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -927,6 +927,8 @@ static inline __u32 skb_get_hash(struct sk_buff *skb) return skb->hash; } +__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb); + static inline __u32 skb_get_hash_raw(const struct sk_buff *skb) { return skb->hash; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 2c35c02a931e..b1df995ef06c 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -267,13 +267,12 @@ static __always_inline void __flow_hash_secret_init(void) net_get_random_once(&hashrnd, sizeof(hashrnd)); } -static __always_inline u32 __flow_hash_3words(u32 a, u32 b, u32 c) +static __always_inline u32 __flow_hash_3words(u32 a, u32 b, u32 c, u32 keyval) { - __flow_hash_secret_init(); - return jhash_3words(a, b, c, hashrnd); + return jhash_3words(a, b, c, keyval); } -static inline u32 __flow_hash_from_keys(struct flow_keys *keys) +static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) { u32 hash; @@ -287,7 +286,8 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys) hash = __flow_hash_3words((__force u32)keys->dst, (__force u32)keys->src, - (__force u32)keys->ports); + (__force u32)keys->ports, + keyval); if (!hash) hash = 1; @@ -296,10 +296,20 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys) u32 flow_hash_from_keys(struct flow_keys *keys) { - return __flow_hash_from_keys(keys); + __flow_hash_secret_init(); + return __flow_hash_from_keys(keys, hashrnd); } EXPORT_SYMBOL(flow_hash_from_keys); +static inline u32 ___skb_get_hash(const struct sk_buff *skb, + struct flow_keys *keys, u32 keyval) +{ + if (!skb_flow_dissect(skb, keys)) + return 0; + + return __flow_hash_from_keys(keys, keyval); +} + /* * __skb_get_hash: calculate a flow hash based on src/dst addresses * and src/dst port numbers. Sets hash in skb to non-zero hash value @@ -309,8 +319,12 @@ EXPORT_SYMBOL(flow_hash_from_keys); void __skb_get_hash(struct sk_buff *skb) { struct flow_keys keys; + u32 hash; - if (!skb_flow_dissect(skb, &keys)) + __flow_hash_secret_init(); + + hash = ___skb_get_hash(skb, &keys, hashrnd); + if (!hash) return; if (keys.ports) @@ -318,10 +332,18 @@ void __skb_get_hash(struct sk_buff *skb) skb->sw_hash = 1; - skb->hash = __flow_hash_from_keys(&keys); + skb->hash = hash; } EXPORT_SYMBOL(__skb_get_hash); +__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb) +{ + struct flow_keys keys; + + return ___skb_get_hash(skb, &keys, perturb); +} +EXPORT_SYMBOL(skb_get_hash_perturb); + /* * Returns a Tx hash based on the given packet descriptor a Tx queues' number * to be used as a distribution range. -- cgit v1.2.3 From 2f59e1ebaa7f762c8825871b5486b5f5b4fa952f Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Fri, 1 May 2015 11:30:17 -0700 Subject: net: Add flow_keys digest Some users of flow keys (well just sch_choke now) need to pass flow_keys in skbuff cb, and use them for exact comparisons of flows so that skb->hash is not sufficient. In order to increase size of the flow_keys structure, we introduce another structure for the purpose of passing flow keys in skbuff cb. We limit this structure to sixteen bytes, and we will technically treat this as a digest of flow_keys struct hence its name flow_keys_digest. In the first incaranation we just copy the flow_keys structure up to 16 bytes-- this is the same information previously passed in the cb. In the future, we'll adapt this for larger flow_keys and could use something like SHA-1 over the whole flow_keys to improve the quality of the digest. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_keys.h | 16 ++++++++++++++++ net/core/flow_dissector.c | 27 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) (limited to 'include') diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h index dc8fd81412bf..6d6ef626811a 100644 --- a/include/net/flow_keys.h +++ b/include/net/flow_keys.h @@ -42,4 +42,20 @@ static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 u32 flow_hash_from_keys(struct flow_keys *keys); unsigned int flow_get_hlen(const unsigned char *data, unsigned int max_len, __be16 protocol); + +/* struct flow_keys_digest: + * + * This structure is used to hold a digest of the full flow keys. This is a + * larger "hash" of a flow to allow definitively matching specific flows where + * the 32 bit skb->hash is not large enough. The size is limited to 16 bytes so + * that it can by used in CB of skb (see sch_choke for an example). + */ +#define FLOW_KEYS_DIGEST_LEN 16 +struct flow_keys_digest { + u8 data[FLOW_KEYS_DIGEST_LEN]; +}; + +void make_flow_keys_digest(struct flow_keys_digest *digest, + const struct flow_keys *flow); + #endif diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index b1df995ef06c..d3acc4dff4ae 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -310,6 +310,33 @@ static inline u32 ___skb_get_hash(const struct sk_buff *skb, return __flow_hash_from_keys(keys, keyval); } +struct _flow_keys_digest_data { + __be16 n_proto; + u8 ip_proto; + u8 padding; + __be32 ports; + __be32 src; + __be32 dst; +}; + +void make_flow_keys_digest(struct flow_keys_digest *digest, + const struct flow_keys *flow) +{ + struct _flow_keys_digest_data *data = + (struct _flow_keys_digest_data *)digest; + + BUILD_BUG_ON(sizeof(*data) > sizeof(*digest)); + + memset(digest, 0, sizeof(*digest)); + + data->n_proto = flow->n_proto; + data->ip_proto = flow->ip_proto; + data->ports = flow->ports; + data->src = flow->src; + data->dst = flow->dst; +} +EXPORT_SYMBOL(make_flow_keys_digest); + /* * __skb_get_hash: calculate a flow hash based on src/dst addresses * and src/dst port numbers. Sets hash in skb to non-zero hash value -- cgit v1.2.3 From 7829fb09a2b4268b30dd9bc782fa5ebee278b137 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 30 Apr 2015 04:13:52 +0200 Subject: lib: make memzero_explicit more robust against dead store elimination In commit 0b053c951829 ("lib: memzero_explicit: use barrier instead of OPTIMIZER_HIDE_VAR"), we made memzero_explicit() more robust in case LTO would decide to inline memzero_explicit() and eventually find out it could be elimiated as dead store. While using barrier() works well for the case of gcc, recent efforts from LLVMLinux people suggest to use llvm as an alternative to gcc, and there, Stephan found in a simple stand-alone user space example that llvm could nevertheless optimize and thus elimitate the memset(). A similar issue has been observed in the referenced llvm bug report, which is regarded as not-a-bug. Based on some experiments, icc is a bit special on its own, while it doesn't seem to eliminate the memset(), it could do so with an own implementation, and then result in similar findings as with llvm. The fix in this patch now works for all three compilers (also tested with more aggressive optimization levels). Arguably, in the current kernel tree it's more of a theoretical issue, but imho, it's better to be pedantic about it. It's clearly visible with gcc/llvm though, with the below code: if we would have used barrier() only here, llvm would have omitted clearing, not so with barrier_data() variant: static inline void memzero_explicit(void *s, size_t count) { memset(s, 0, count); barrier_data(s); } int main(void) { char buff[20]; memzero_explicit(buff, sizeof(buff)); return 0; } $ gcc -O2 test.c $ gdb a.out (gdb) disassemble main Dump of assembler code for function main: 0x0000000000400400 <+0>: lea -0x28(%rsp),%rax 0x0000000000400405 <+5>: movq $0x0,-0x28(%rsp) 0x000000000040040e <+14>: movq $0x0,-0x20(%rsp) 0x0000000000400417 <+23>: movl $0x0,-0x18(%rsp) 0x000000000040041f <+31>: xor %eax,%eax 0x0000000000400421 <+33>: retq End of assembler dump. $ clang -O2 test.c $ gdb a.out (gdb) disassemble main Dump of assembler code for function main: 0x00000000004004f0 <+0>: xorps %xmm0,%xmm0 0x00000000004004f3 <+3>: movaps %xmm0,-0x18(%rsp) 0x00000000004004f8 <+8>: movl $0x0,-0x8(%rsp) 0x0000000000400500 <+16>: lea -0x18(%rsp),%rax 0x0000000000400505 <+21>: xor %eax,%eax 0x0000000000400507 <+23>: retq End of assembler dump. As gcc, clang, but also icc defines __GNUC__, it's sufficient to define this in compiler-gcc.h only to be picked up. For a fallback or otherwise unsupported compiler, we define it as a barrier. Similarly, for ecc which does not support gcc inline asm. Reference: https://llvm.org/bugs/show_bug.cgi?id=15495 Reported-by: Stephan Mueller Tested-by: Stephan Mueller Signed-off-by: Daniel Borkmann Cc: Theodore Ts'o Cc: Stephan Mueller Cc: Hannes Frederic Sowa Cc: mancha security Cc: Mark Charlebois Cc: Behan Webster Signed-off-by: Herbert Xu --- include/linux/compiler-gcc.h | 16 +++++++++++++++- include/linux/compiler-intel.h | 3 +++ include/linux/compiler.h | 4 ++++ lib/string.c | 2 +- 4 files changed, 23 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index cdf13ca7cac3..371e560d13cf 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -9,10 +9,24 @@ + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) - /* Optimization barrier */ + /* The "volatile" is due to gcc bugs */ #define barrier() __asm__ __volatile__("": : :"memory") +/* + * This version is i.e. to prevent dead stores elimination on @ptr + * where gcc and llvm may behave differently when otherwise using + * normal barrier(): while gcc behavior gets along with a normal + * barrier(), llvm needs an explicit input variable to be assumed + * clobbered. The issue is as follows: while the inline asm might + * access any memory it wants, the compiler could have fit all of + * @ptr into memory registers instead, and since @ptr never escaped + * from that, it proofed that the inline asm wasn't touching any of + * it. This version works well with both compilers, i.e. we're telling + * the compiler that the inline asm absolutely may see the contents + * of @ptr. See also: https://llvm.org/bugs/show_bug.cgi?id=15495 + */ +#define barrier_data(ptr) __asm__ __volatile__("": :"r"(ptr) :"memory") /* * This macro obfuscates arithmetic on a variable address so that gcc diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h index ba147a1727e6..0c9a2f2c2802 100644 --- a/include/linux/compiler-intel.h +++ b/include/linux/compiler-intel.h @@ -13,9 +13,12 @@ /* Intel ECC compiler doesn't support gcc specific asm stmts. * It uses intrinsics to do the equivalent things. */ +#undef barrier_data #undef RELOC_HIDE #undef OPTIMIZER_HIDE_VAR +#define barrier_data(ptr) barrier() + #define RELOC_HIDE(ptr, off) \ ({ unsigned long __ptr; \ __ptr = (unsigned long) (ptr); \ diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 0e41ca0e5927..867722591be2 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -169,6 +169,10 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); # define barrier() __memory_barrier() #endif +#ifndef barrier_data +# define barrier_data(ptr) barrier() +#endif + /* Unreachable code */ #ifndef unreachable # define unreachable() do { } while (1) diff --git a/lib/string.c b/lib/string.c index a5792019193c..bb3d4b6993c4 100644 --- a/lib/string.c +++ b/lib/string.c @@ -607,7 +607,7 @@ EXPORT_SYMBOL(memset); void memzero_explicit(void *s, size_t count) { memset(s, 0, count); - barrier(); + barrier_data(s); } EXPORT_SYMBOL(memzero_explicit); -- cgit v1.2.3 From ff419b3f95ab7a97c5f72876b53f12a249dacc2a Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 26 Apr 2015 20:13:34 -0700 Subject: mac80211: fix 90 kernel-doc warnings Eliminate 90 of these warnings: Warning(..//include/net/mac80211.h:1682): No description found for parameter 'drv_priv[0]' Signed-off-by: Randy Dunlap Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index b4bef1152c05..8e3668b44c29 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1666,6 +1666,8 @@ struct ieee80211_tx_control { * @sta: station table entry, %NULL for per-vif queue * @tid: the TID for this queue (unused for per-vif queue) * @ac: the AC for this queue + * @drv_priv: data area for driver use, will always be aligned to + * sizeof(void *). * * The driver can obtain packets from this queue by calling * ieee80211_tx_dequeue(). -- cgit v1.2.3 From c19ae86a510cf4332af64caab04718bc853d3184 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Fri, 1 May 2015 22:19:43 -0700 Subject: tc: remove unused redirect ttl improves ingress+u32 performance from 22.4 Mpps to 22.9 Mpps Signed-off-by: Jamal Hadi Salim Signed-off-by: Alexei Starovoitov Acked-by: Florian Westphal Acked-by: Daniel Borkmann Acked-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- include/uapi/linux/pkt_cls.h | 2 ++ net/core/dev.c | 9 --------- 2 files changed, 2 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 6810ca43a80a..596ffa0c7084 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -65,11 +65,13 @@ bits 9,10,11: redirect counter - redirect TTL. Loop avoidance #define SET_TC_NCLS(v) ( TC_NCLS | (v & ~TC_NCLS)) #define CLR_TC_NCLS(v) ( v & ~TC_NCLS) +#ifndef __KERNEL__ #define S_TC_RTTL _TC_MAKE32(9) #define M_TC_RTTL _TC_MAKEMASK(3,S_TC_RTTL) #define G_TC_RTTL(x) _TC_GETVALUE(x,S_TC_RTTL,M_TC_RTTL) #define V_TC_RTTL(x) _TC_MAKEVALUE(x,S_TC_RTTL) #define SET_TC_RTTL(v,n) ((V_TC_RTTL(n)) | (v & ~M_TC_RTTL)) +#endif #define S_TC_AT _TC_MAKE32(12) #define M_TC_AT _TC_MAKEMASK(2,S_TC_AT) diff --git a/net/core/dev.c b/net/core/dev.c index 74a5b62f7568..862875ec8f2f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3531,18 +3531,9 @@ EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook); */ static int ing_filter(struct sk_buff *skb, struct netdev_queue *rxq) { - struct net_device *dev = skb->dev; - u32 ttl = G_TC_RTTL(skb->tc_verd); int result = TC_ACT_OK; struct Qdisc *q; - if (unlikely(MAX_RED_LOOP < ttl++)) { - net_warn_ratelimited("Redir loop detected Dropping packet (%d->%d)\n", - skb->skb_iif, dev->ifindex); - return TC_ACT_SHOT; - } - - skb->tc_verd = SET_TC_RTTL(skb->tc_verd, ttl); skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS); q = rcu_dereference(rxq->qdisc); -- cgit v1.2.3 From 9afd85c9e4552b276e2f4cfefd622bdeeffbbf26 Mon Sep 17 00:00:00 2001 From: Linus Lüssing Date: Sat, 2 May 2015 14:01:07 +0200 Subject: net: Export IGMP/MLD message validation code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this patch, the IGMP and MLD message validation functions are moved from the bridge code to IPv4/IPv6 multicast files. Some small refactoring was done to enhance readibility and to iron out some differences in behaviour between the IGMP and MLD parsing code (e.g. the skb-cloning of MLD messages is now only done if necessary, just like the IGMP part always did). Finally, these IGMP and MLD message validation functions are exported so that not only the bridge can use it but batman-adv later, too. Signed-off-by: Linus Lüssing Signed-off-by: David S. Miller --- include/linux/igmp.h | 1 + include/linux/skbuff.h | 3 + include/net/addrconf.h | 1 + net/bridge/br_multicast.c | 218 +++++++--------------------------------------- net/core/skbuff.c | 87 ++++++++++++++++++ net/ipv4/igmp.c | 162 ++++++++++++++++++++++++++++++++++ net/ipv6/Makefile | 1 + net/ipv6/mcast_snoop.c | 213 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 498 insertions(+), 188 deletions(-) create mode 100644 net/ipv6/mcast_snoop.c (limited to 'include') diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 2c677afeea47..193ad488d3e2 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -130,5 +130,6 @@ extern void ip_mc_unmap(struct in_device *); extern void ip_mc_remap(struct in_device *); extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr); extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr); +int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed); #endif diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index acb83e249e3f..9c2f793573fa 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3419,6 +3419,9 @@ static inline void skb_checksum_none_assert(const struct sk_buff *skb) bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off); int skb_checksum_setup(struct sk_buff *skb, bool recalculate); +struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb, + unsigned int transport_len, + __sum16(*skb_chkf)(struct sk_buff *skb)); u32 skb_get_poff(const struct sk_buff *skb); u32 __skb_get_poff(const struct sk_buff *skb, void *data, diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 80456f72d70a..def59d3a34d5 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -142,6 +142,7 @@ void ipv6_mc_unmap(struct inet6_dev *idev); void ipv6_mc_remap(struct inet6_dev *idev); void ipv6_mc_init_dev(struct inet6_dev *idev); void ipv6_mc_destroy_dev(struct inet6_dev *idev); +int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed); void addrconf_dad_failure(struct inet6_ifaddr *ifp); bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index b52f4cb8aee9..2d69d5cab52f 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -975,9 +975,6 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br, int err = 0; __be32 group; - if (!pskb_may_pull(skb, sizeof(*ih))) - return -EINVAL; - ih = igmpv3_report_hdr(skb); num = ntohs(ih->ngrec); len = sizeof(*ih); @@ -1248,25 +1245,14 @@ static int br_ip4_multicast_query(struct net_bridge *br, max_delay = 10 * HZ; group = 0; } - } else { - if (!pskb_may_pull(skb, sizeof(struct igmpv3_query))) { - err = -EINVAL; - goto out; - } - + } else if (skb->len >= sizeof(*ih3)) { ih3 = igmpv3_query_hdr(skb); if (ih3->nsrcs) goto out; max_delay = ih3->code ? IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1; - } - - /* RFC2236+RFC3376 (IGMPv2+IGMPv3) require the multicast link layer - * all-systems destination addresses (224.0.0.1) for general queries - */ - if (!group && iph->daddr != htonl(INADDR_ALLHOSTS_GROUP)) { - err = -EINVAL; + } else { goto out; } @@ -1329,12 +1315,6 @@ static int br_ip6_multicast_query(struct net_bridge *br, (port && port->state == BR_STATE_DISABLED)) goto out; - /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */ - if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) { - err = -EINVAL; - goto out; - } - if (skb->len == sizeof(*mld)) { if (!pskb_may_pull(skb, sizeof(*mld))) { err = -EINVAL; @@ -1358,14 +1338,6 @@ static int br_ip6_multicast_query(struct net_bridge *br, is_general_query = group && ipv6_addr_any(group); - /* RFC2710+RFC3810 (MLDv1+MLDv2) require the multicast link layer - * all-nodes destination address (ff02::1) for general queries - */ - if (is_general_query && !ipv6_addr_is_ll_all_nodes(&ip6h->daddr)) { - err = -EINVAL; - goto out; - } - if (is_general_query) { saddr.proto = htons(ETH_P_IPV6); saddr.u.ip6 = ip6h->saddr; @@ -1557,66 +1529,22 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br, struct sk_buff *skb, u16 vid) { - struct sk_buff *skb2 = skb; - const struct iphdr *iph; + struct sk_buff *skb_trimmed = NULL; struct igmphdr *ih; - unsigned int len; - unsigned int offset; int err; - /* We treat OOM as packet loss for now. */ - if (!pskb_may_pull(skb, sizeof(*iph))) - return -EINVAL; - - iph = ip_hdr(skb); - - if (iph->ihl < 5 || iph->version != 4) - return -EINVAL; - - if (!pskb_may_pull(skb, ip_hdrlen(skb))) - return -EINVAL; - - iph = ip_hdr(skb); + err = ip_mc_check_igmp(skb, &skb_trimmed); - if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) - return -EINVAL; - - if (iph->protocol != IPPROTO_IGMP) { - if (!ipv4_is_local_multicast(iph->daddr)) + if (err == -ENOMSG) { + if (!ipv4_is_local_multicast(ip_hdr(skb)->daddr)) BR_INPUT_SKB_CB(skb)->mrouters_only = 1; return 0; + } else if (err < 0) { + return err; } - len = ntohs(iph->tot_len); - if (skb->len < len || len < ip_hdrlen(skb)) - return -EINVAL; - - if (skb->len > len) { - skb2 = skb_clone(skb, GFP_ATOMIC); - if (!skb2) - return -ENOMEM; - - err = pskb_trim_rcsum(skb2, len); - if (err) - goto err_out; - } - - len -= ip_hdrlen(skb2); - offset = skb_network_offset(skb2) + ip_hdrlen(skb2); - __skb_pull(skb2, offset); - skb_reset_transport_header(skb2); - - err = -EINVAL; - if (!pskb_may_pull(skb2, sizeof(*ih))) - goto out; - - if (skb_checksum_simple_validate(skb2)) - goto out; - - err = 0; - BR_INPUT_SKB_CB(skb)->igmp = 1; - ih = igmp_hdr(skb2); + ih = igmp_hdr(skb); switch (ih->type) { case IGMP_HOST_MEMBERSHIP_REPORT: @@ -1625,21 +1553,19 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br, err = br_ip4_multicast_add_group(br, port, ih->group, vid); break; case IGMPV3_HOST_MEMBERSHIP_REPORT: - err = br_ip4_multicast_igmp3_report(br, port, skb2, vid); + err = br_ip4_multicast_igmp3_report(br, port, skb_trimmed, vid); break; case IGMP_HOST_MEMBERSHIP_QUERY: - err = br_ip4_multicast_query(br, port, skb2, vid); + err = br_ip4_multicast_query(br, port, skb_trimmed, vid); break; case IGMP_HOST_LEAVE_MESSAGE: br_ip4_multicast_leave_group(br, port, ih->group, vid); break; } -out: - __skb_push(skb2, offset); -err_out: - if (skb2 != skb) - kfree_skb(skb2); + if (skb_trimmed) + kfree_skb(skb_trimmed); + return err; } @@ -1649,126 +1575,42 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, struct sk_buff *skb, u16 vid) { - struct sk_buff *skb2; - const struct ipv6hdr *ip6h; - u8 icmp6_type; - u8 nexthdr; - __be16 frag_off; - unsigned int len; - int offset; + struct sk_buff *skb_trimmed = NULL; + struct mld_msg *mld; int err; - if (!pskb_may_pull(skb, sizeof(*ip6h))) - return -EINVAL; + err = ipv6_mc_check_mld(skb, &skb_trimmed); - ip6h = ipv6_hdr(skb); - - /* - * We're interested in MLD messages only. - * - Version is 6 - * - MLD has always Router Alert hop-by-hop option - * - But we do not support jumbrograms. - */ - if (ip6h->version != 6) - return 0; - - /* Prevent flooding this packet if there is no listener present */ - if (!ipv6_addr_is_ll_all_nodes(&ip6h->daddr)) - BR_INPUT_SKB_CB(skb)->mrouters_only = 1; - - if (ip6h->nexthdr != IPPROTO_HOPOPTS || - ip6h->payload_len == 0) - return 0; - - len = ntohs(ip6h->payload_len) + sizeof(*ip6h); - if (skb->len < len) - return -EINVAL; - - nexthdr = ip6h->nexthdr; - offset = ipv6_skip_exthdr(skb, sizeof(*ip6h), &nexthdr, &frag_off); - - if (offset < 0 || nexthdr != IPPROTO_ICMPV6) + if (err == -ENOMSG) { + if (!ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr)) + BR_INPUT_SKB_CB(skb)->mrouters_only = 1; return 0; - - /* Okay, we found ICMPv6 header */ - skb2 = skb_clone(skb, GFP_ATOMIC); - if (!skb2) - return -ENOMEM; - - err = -EINVAL; - if (!pskb_may_pull(skb2, offset + sizeof(struct icmp6hdr))) - goto out; - - len -= offset - skb_network_offset(skb2); - - __skb_pull(skb2, offset); - skb_reset_transport_header(skb2); - skb_postpull_rcsum(skb2, skb_network_header(skb2), - skb_network_header_len(skb2)); - - icmp6_type = icmp6_hdr(skb2)->icmp6_type; - - switch (icmp6_type) { - case ICMPV6_MGM_QUERY: - case ICMPV6_MGM_REPORT: - case ICMPV6_MGM_REDUCTION: - case ICMPV6_MLD2_REPORT: - break; - default: - err = 0; - goto out; - } - - /* Okay, we found MLD message. Check further. */ - if (skb2->len > len) { - err = pskb_trim_rcsum(skb2, len); - if (err) - goto out; - err = -EINVAL; + } else if (err < 0) { + return err; } - ip6h = ipv6_hdr(skb2); - - if (skb_checksum_validate(skb2, IPPROTO_ICMPV6, ip6_compute_pseudo)) - goto out; - - err = 0; - BR_INPUT_SKB_CB(skb)->igmp = 1; + mld = (struct mld_msg *)skb_transport_header(skb); - switch (icmp6_type) { + switch (mld->mld_type) { case ICMPV6_MGM_REPORT: - { - struct mld_msg *mld; - if (!pskb_may_pull(skb2, sizeof(*mld))) { - err = -EINVAL; - goto out; - } - mld = (struct mld_msg *)skb_transport_header(skb2); BR_INPUT_SKB_CB(skb)->mrouters_only = 1; err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid); break; - } case ICMPV6_MLD2_REPORT: - err = br_ip6_multicast_mld2_report(br, port, skb2, vid); + err = br_ip6_multicast_mld2_report(br, port, skb_trimmed, vid); break; case ICMPV6_MGM_QUERY: - err = br_ip6_multicast_query(br, port, skb2, vid); + err = br_ip6_multicast_query(br, port, skb_trimmed, vid); break; case ICMPV6_MGM_REDUCTION: - { - struct mld_msg *mld; - if (!pskb_may_pull(skb2, sizeof(*mld))) { - err = -EINVAL; - goto out; - } - mld = (struct mld_msg *)skb_transport_header(skb2); br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid); - } + break; } -out: - kfree_skb(skb2); + if (skb_trimmed) + kfree_skb(skb_trimmed); + return err; } #endif diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 3cfff2a3d651..1e4278a4dd7e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4030,6 +4030,93 @@ int skb_checksum_setup(struct sk_buff *skb, bool recalculate) } EXPORT_SYMBOL(skb_checksum_setup); +/** + * skb_checksum_maybe_trim - maybe trims the given skb + * @skb: the skb to check + * @transport_len: the data length beyond the network header + * + * Checks whether the given skb has data beyond the given transport length. + * If so, returns a cloned skb trimmed to this transport length. + * Otherwise returns the provided skb. Returns NULL in error cases + * (e.g. transport_len exceeds skb length or out-of-memory). + * + * Caller needs to set the skb transport header and release the returned skb. + * Provided skb is consumed. + */ +static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb, + unsigned int transport_len) +{ + struct sk_buff *skb_chk; + unsigned int len = skb_transport_offset(skb) + transport_len; + int ret; + + if (skb->len < len) { + kfree_skb(skb); + return NULL; + } else if (skb->len == len) { + return skb; + } + + skb_chk = skb_clone(skb, GFP_ATOMIC); + kfree_skb(skb); + + if (!skb_chk) + return NULL; + + ret = pskb_trim_rcsum(skb_chk, len); + if (ret) { + kfree_skb(skb_chk); + return NULL; + } + + return skb_chk; +} + +/** + * skb_checksum_trimmed - validate checksum of an skb + * @skb: the skb to check + * @transport_len: the data length beyond the network header + * @skb_chkf: checksum function to use + * + * Applies the given checksum function skb_chkf to the provided skb. + * Returns a checked and maybe trimmed skb. Returns NULL on error. + * + * If the skb has data beyond the given transport length, then a + * trimmed & cloned skb is checked and returned. + * + * Caller needs to set the skb transport header and release the returned skb. + * Provided skb is consumed. + */ +struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb, + unsigned int transport_len, + __sum16(*skb_chkf)(struct sk_buff *skb)) +{ + struct sk_buff *skb_chk; + unsigned int offset = skb_transport_offset(skb); + int ret; + + skb_chk = skb_checksum_maybe_trim(skb, transport_len); + if (!skb_chk) + return NULL; + + if (!pskb_may_pull(skb_chk, offset)) { + kfree_skb(skb_chk); + return NULL; + } + + __skb_pull(skb_chk, offset); + ret = skb_chkf(skb_chk); + __skb_push(skb_chk, offset); + + if (ret) { + kfree_skb(skb_chk); + return NULL; + } + + return skb_chk; +} +EXPORT_SYMBOL(skb_checksum_trimmed); + void __skb_warn_lro_forwarding(const struct sk_buff *skb) { net_warn_ratelimited("%s: received packets cannot be forwarded while LRO is enabled\n", diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index a3a697f5ffba..651cdf648ec4 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1339,6 +1339,168 @@ out: } EXPORT_SYMBOL(ip_mc_inc_group); +static int ip_mc_check_iphdr(struct sk_buff *skb) +{ + const struct iphdr *iph; + unsigned int len; + unsigned int offset = skb_network_offset(skb) + sizeof(*iph); + + if (!pskb_may_pull(skb, offset)) + return -EINVAL; + + iph = ip_hdr(skb); + + if (iph->version != 4 || ip_hdrlen(skb) < sizeof(*iph)) + return -EINVAL; + + offset += ip_hdrlen(skb) - sizeof(*iph); + + if (!pskb_may_pull(skb, offset)) + return -EINVAL; + + iph = ip_hdr(skb); + + if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) + return -EINVAL; + + len = skb_network_offset(skb) + ntohs(iph->tot_len); + if (skb->len < len || len < offset) + return -EINVAL; + + skb_set_transport_header(skb, offset); + + return 0; +} + +static int ip_mc_check_igmp_reportv3(struct sk_buff *skb) +{ + unsigned int len = skb_transport_offset(skb); + + len += sizeof(struct igmpv3_report); + + return pskb_may_pull(skb, len) ? 0 : -EINVAL; +} + +static int ip_mc_check_igmp_query(struct sk_buff *skb) +{ + unsigned int len = skb_transport_offset(skb); + + len += sizeof(struct igmphdr); + if (skb->len < len) + return -EINVAL; + + /* IGMPv{1,2}? */ + if (skb->len != len) { + /* or IGMPv3? */ + len += sizeof(struct igmpv3_query) - sizeof(struct igmphdr); + if (skb->len < len || !pskb_may_pull(skb, len)) + return -EINVAL; + } + + /* RFC2236+RFC3376 (IGMPv2+IGMPv3) require the multicast link layer + * all-systems destination addresses (224.0.0.1) for general queries + */ + if (!igmp_hdr(skb)->group && + ip_hdr(skb)->daddr != htonl(INADDR_ALLHOSTS_GROUP)) + return -EINVAL; + + return 0; +} + +static int ip_mc_check_igmp_msg(struct sk_buff *skb) +{ + switch (igmp_hdr(skb)->type) { + case IGMP_HOST_LEAVE_MESSAGE: + case IGMP_HOST_MEMBERSHIP_REPORT: + case IGMPV2_HOST_MEMBERSHIP_REPORT: + /* fall through */ + return 0; + case IGMPV3_HOST_MEMBERSHIP_REPORT: + return ip_mc_check_igmp_reportv3(skb); + case IGMP_HOST_MEMBERSHIP_QUERY: + return ip_mc_check_igmp_query(skb); + default: + return -ENOMSG; + } +} + +static inline __sum16 ip_mc_validate_checksum(struct sk_buff *skb) +{ + return skb_checksum_simple_validate(skb); +} + +static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed) + +{ + struct sk_buff *skb_chk; + unsigned int transport_len; + unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr); + int ret; + + transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb); + + skb_get(skb); + skb_chk = skb_checksum_trimmed(skb, transport_len, + ip_mc_validate_checksum); + if (!skb_chk) + return -EINVAL; + + if (!pskb_may_pull(skb_chk, len)) { + kfree_skb(skb_chk); + return -EINVAL; + } + + ret = ip_mc_check_igmp_msg(skb_chk); + if (ret) { + kfree_skb(skb_chk); + return ret; + } + + if (skb_trimmed) + *skb_trimmed = skb_chk; + else + kfree_skb(skb_chk); + + return 0; +} + +/** + * ip_mc_check_igmp - checks whether this is a sane IGMP packet + * @skb: the skb to validate + * @skb_trimmed: to store an skb pointer trimmed to IPv4 packet tail (optional) + * + * Checks whether an IPv4 packet is a valid IGMP packet. If so sets + * skb network and transport headers accordingly and returns zero. + * + * -EINVAL: A broken packet was detected, i.e. it violates some internet + * standard + * -ENOMSG: IP header validation succeeded but it is not an IGMP packet. + * -ENOMEM: A memory allocation failure happened. + * + * Optionally, an skb pointer might be provided via skb_trimmed (or set it + * to NULL): After parsing an IGMP packet successfully it will point to + * an skb which has its tail aligned to the IP packet end. This might + * either be the originally provided skb or a trimmed, cloned version if + * the skb frame had data beyond the IP packet. A cloned skb allows us + * to leave the original skb and its full frame unchanged (which might be + * desirable for layer 2 frame jugglers). + * + * The caller needs to release a reference count from any returned skb_trimmed. + */ +int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed) +{ + int ret = ip_mc_check_iphdr(skb); + + if (ret < 0) + return ret; + + if (ip_hdr(skb)->protocol != IPPROTO_IGMP) + return -ENOMSG; + + return __ip_mc_check_igmp(skb, skb_trimmed); +} +EXPORT_SYMBOL(ip_mc_check_igmp); + /* * Resend IGMP JOIN report; used by netdev notifier. */ diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 2e8c06108ab9..0f3f1999719a 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -48,4 +48,5 @@ obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o ifneq ($(CONFIG_IPV6),) obj-$(CONFIG_NET_UDP_TUNNEL) += ip6_udp_tunnel.o +obj-y += mcast_snoop.o endif diff --git a/net/ipv6/mcast_snoop.c b/net/ipv6/mcast_snoop.c new file mode 100644 index 000000000000..1a2cbc13a7d3 --- /dev/null +++ b/net/ipv6/mcast_snoop.c @@ -0,0 +1,213 @@ +/* Copyright (C) 2010: YOSHIFUJI Hideaki + * Copyright (C) 2015: Linus Lüssing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * + * Based on the MLD support added to br_multicast.c by YOSHIFUJI Hideaki. + */ + +#include +#include +#include +#include +#include + +static int ipv6_mc_check_ip6hdr(struct sk_buff *skb) +{ + const struct ipv6hdr *ip6h; + unsigned int len; + unsigned int offset = skb_network_offset(skb) + sizeof(*ip6h); + + if (!pskb_may_pull(skb, offset)) + return -EINVAL; + + ip6h = ipv6_hdr(skb); + + if (ip6h->version != 6) + return -EINVAL; + + len = offset + ntohs(ip6h->payload_len); + if (skb->len < len || len <= offset) + return -EINVAL; + + return 0; +} + +static int ipv6_mc_check_exthdrs(struct sk_buff *skb) +{ + const struct ipv6hdr *ip6h; + unsigned int offset; + u8 nexthdr; + __be16 frag_off; + + ip6h = ipv6_hdr(skb); + + if (ip6h->nexthdr != IPPROTO_HOPOPTS) + return -ENOMSG; + + nexthdr = ip6h->nexthdr; + offset = skb_network_offset(skb) + sizeof(*ip6h); + offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off); + + if (offset < 0) + return -EINVAL; + + if (nexthdr != IPPROTO_ICMPV6) + return -ENOMSG; + + skb_set_transport_header(skb, offset); + + return 0; +} + +static int ipv6_mc_check_mld_reportv2(struct sk_buff *skb) +{ + unsigned int len = skb_transport_offset(skb); + + len += sizeof(struct mld2_report); + + return pskb_may_pull(skb, len) ? 0 : -EINVAL; +} + +static int ipv6_mc_check_mld_query(struct sk_buff *skb) +{ + struct mld_msg *mld; + unsigned int len = skb_transport_offset(skb); + + /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */ + if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) + return -EINVAL; + + len += sizeof(struct mld_msg); + if (skb->len < len) + return -EINVAL; + + /* MLDv1? */ + if (skb->len != len) { + /* or MLDv2? */ + len += sizeof(struct mld2_query) - sizeof(struct mld_msg); + if (skb->len < len || !pskb_may_pull(skb, len)) + return -EINVAL; + } + + mld = (struct mld_msg *)skb_transport_header(skb); + + /* RFC2710+RFC3810 (MLDv1+MLDv2) require the multicast link layer + * all-nodes destination address (ff02::1) for general queries + */ + if (ipv6_addr_any(&mld->mld_mca) && + !ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr)) + return -EINVAL; + + return 0; +} + +static int ipv6_mc_check_mld_msg(struct sk_buff *skb) +{ + struct mld_msg *mld = (struct mld_msg *)skb_transport_header(skb); + + switch (mld->mld_type) { + case ICMPV6_MGM_REDUCTION: + case ICMPV6_MGM_REPORT: + /* fall through */ + return 0; + case ICMPV6_MLD2_REPORT: + return ipv6_mc_check_mld_reportv2(skb); + case ICMPV6_MGM_QUERY: + return ipv6_mc_check_mld_query(skb); + default: + return -ENOMSG; + } +} + +static inline __sum16 ipv6_mc_validate_checksum(struct sk_buff *skb) +{ + return skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo); +} + +static int __ipv6_mc_check_mld(struct sk_buff *skb, + struct sk_buff **skb_trimmed) + +{ + struct sk_buff *skb_chk = NULL; + unsigned int transport_len; + unsigned int len = skb_transport_offset(skb) + sizeof(struct mld_msg); + int ret; + + transport_len = ntohs(ipv6_hdr(skb)->payload_len); + transport_len -= skb_transport_offset(skb) - sizeof(struct ipv6hdr); + + skb_get(skb); + skb_chk = skb_checksum_trimmed(skb, transport_len, + ipv6_mc_validate_checksum); + if (!skb_chk) + return -EINVAL; + + if (!pskb_may_pull(skb_chk, len)) { + kfree_skb(skb_chk); + return -EINVAL; + } + + ret = ipv6_mc_check_mld_msg(skb_chk); + if (ret) { + kfree_skb(skb_chk); + return ret; + } + + if (skb_trimmed) + *skb_trimmed = skb_chk; + else + kfree_skb(skb_chk); + + return 0; +} + +/** + * ipv6_mc_check_mld - checks whether this is a sane MLD packet + * @skb: the skb to validate + * @skb_trimmed: to store an skb pointer trimmed to IPv6 packet tail (optional) + * + * Checks whether an IPv6 packet is a valid MLD packet. If so sets + * skb network and transport headers accordingly and returns zero. + * + * -EINVAL: A broken packet was detected, i.e. it violates some internet + * standard + * -ENOMSG: IP header validation succeeded but it is not an MLD packet. + * -ENOMEM: A memory allocation failure happened. + * + * Optionally, an skb pointer might be provided via skb_trimmed (or set it + * to NULL): After parsing an MLD packet successfully it will point to + * an skb which has its tail aligned to the IP packet end. This might + * either be the originally provided skb or a trimmed, cloned version if + * the skb frame had data beyond the IP packet. A cloned skb allows us + * to leave the original skb and its full frame unchanged (which might be + * desirable for layer 2 frame jugglers). + * + * The caller needs to release a reference count from any returned skb_trimmed. + */ +int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed) +{ + int ret; + + ret = ipv6_mc_check_ip6hdr(skb); + if (ret < 0) + return ret; + + ret = ipv6_mc_check_exthdrs(skb); + if (ret < 0) + return ret; + + return __ipv6_mc_check_mld(skb, skb_trimmed); +} +EXPORT_SYMBOL(ipv6_mc_check_mld); -- cgit v1.2.3 From b2387ddcced8de3e6471a2fb16a409577063016f Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Fri, 1 May 2015 09:59:44 -0700 Subject: blk-mq: fix FUA request hang When a FUA request enters its DATA stage of flush pipeline, the request is added to mq requeue list, the request will then be added to ctx->rq_list. blk_mq_attempt_merge() might merge the request with a bio. Later when the request is finished the flush pipeline, the request->__data_len is 0. Then I only saw the bio gets endio called, the original request never finish. Adding REQ_FLUSH_SEQ into REQ_NOMERGE_FLAGS looks an easy fix. stable: 3.15+ Signed-off-by: Shaohua Li Signed-off-by: Jens Axboe --- include/linux/blk_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index a1b25e35ea5f..b7299febc4b4 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -220,7 +220,7 @@ enum rq_flag_bits { /* This mask is used for both bio and request merge checking */ #define REQ_NOMERGE_FLAGS \ - (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA) + (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA | REQ_FLUSH_SEQ) #define REQ_RAHEAD (1ULL << __REQ_RAHEAD) #define REQ_THROTTLED (1ULL << __REQ_THROTTLED) -- cgit v1.2.3 From 6eec177461751f0fe191cf9977cde692b9481d0a Mon Sep 17 00:00:00 2001 From: Tatyana Nikolova Date: Tue, 21 Apr 2015 16:28:10 -0400 Subject: RDMA/core: Enable the iWarp Port Mapper to provide the actual address of the connecting peer to its clients Add functionality to enable the port mapper on the passive side to provide to its clients the actual (non-mapped) ip/tcp address information of the connecting peer 1) Adding remote_info_cb() to process the address info of the connecting peer The address info is provided by the user space port mapper service when the connection is initiated by the peer 2) Adding a hash list to store the remote address info 3) Adding functionality to add/remove the remote address info After the info has been provided to the port mapper client, it is removed from the hash list Signed-off-by: Tatyana Nikolova Reviewed-by: Steve Wise Signed-off-by: Doug Ledford --- drivers/infiniband/core/iwpm_msg.c | 73 ++++++++++++- drivers/infiniband/core/iwpm_util.c | 208 ++++++++++++++++++++++++++++++------ drivers/infiniband/core/iwpm_util.h | 15 +++ include/rdma/iw_portmap.h | 25 +++++ include/uapi/rdma/rdma_netlink.h | 1 + 5 files changed, 288 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c index b85ddbc979e0..ab081702566f 100644 --- a/drivers/infiniband/core/iwpm_msg.c +++ b/drivers/infiniband/core/iwpm_msg.c @@ -468,7 +468,8 @@ add_mapping_response_exit: } EXPORT_SYMBOL(iwpm_add_mapping_cb); -/* netlink attribute policy for the response to add and query mapping request */ +/* netlink attribute policy for the response to add and query mapping request + * and response with remote address info */ static const struct nla_policy resp_query_policy[IWPM_NLA_RQUERY_MAPPING_MAX] = { [IWPM_NLA_QUERY_MAPPING_SEQ] = { .type = NLA_U32 }, [IWPM_NLA_QUERY_LOCAL_ADDR] = { .len = sizeof(struct sockaddr_storage) }, @@ -559,6 +560,76 @@ query_mapping_response_exit: } EXPORT_SYMBOL(iwpm_add_and_query_mapping_cb); +/* + * iwpm_remote_info_cb - Process a port mapper message, containing + * the remote connecting peer address info + */ +int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX]; + struct sockaddr_storage *local_sockaddr, *remote_sockaddr; + struct sockaddr_storage *mapped_loc_sockaddr, *mapped_rem_sockaddr; + struct iwpm_remote_info *rem_info; + const char *msg_type; + u8 nl_client; + int ret = -EINVAL; + + msg_type = "Remote Mapping info"; + if (iwpm_parse_nlmsg(cb, IWPM_NLA_RQUERY_MAPPING_MAX, + resp_query_policy, nltb, msg_type)) + return ret; + + nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type); + if (!iwpm_valid_client(nl_client)) { + pr_info("%s: Invalid port mapper client = %d\n", + __func__, nl_client); + return ret; + } + atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); + + local_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_QUERY_LOCAL_ADDR]); + remote_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_QUERY_REMOTE_ADDR]); + mapped_loc_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]); + mapped_rem_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]); + + if (mapped_loc_sockaddr->ss_family != local_sockaddr->ss_family || + mapped_rem_sockaddr->ss_family != remote_sockaddr->ss_family) { + pr_info("%s: Sockaddr family doesn't match the requested one\n", + __func__); + return ret; + } + rem_info = kzalloc(sizeof(struct iwpm_remote_info), GFP_ATOMIC); + if (!rem_info) { + pr_err("%s: Unable to allocate a remote info\n", __func__); + ret = -ENOMEM; + return ret; + } + memcpy(&rem_info->mapped_loc_sockaddr, mapped_loc_sockaddr, + sizeof(struct sockaddr_storage)); + memcpy(&rem_info->remote_sockaddr, remote_sockaddr, + sizeof(struct sockaddr_storage)); + memcpy(&rem_info->mapped_rem_sockaddr, mapped_rem_sockaddr, + sizeof(struct sockaddr_storage)); + rem_info->nl_client = nl_client; + + iwpm_add_remote_info(rem_info); + + iwpm_print_sockaddr(local_sockaddr, + "remote_info: Local sockaddr:"); + iwpm_print_sockaddr(mapped_loc_sockaddr, + "remote_info: Mapped local sockaddr:"); + iwpm_print_sockaddr(remote_sockaddr, + "remote_info: Remote sockaddr:"); + iwpm_print_sockaddr(mapped_rem_sockaddr, + "remote_info: Mapped remote sockaddr:"); + return ret; +} +EXPORT_SYMBOL(iwpm_remote_info_cb); + /* netlink attribute policy for the received request for mapping info */ static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = { [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING, diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c index 69e9f84c1605..a626795bf9c7 100644 --- a/drivers/infiniband/core/iwpm_util.c +++ b/drivers/infiniband/core/iwpm_util.c @@ -33,8 +33,10 @@ #include "iwpm_util.h" -#define IWPM_HASH_BUCKET_SIZE 512 -#define IWPM_HASH_BUCKET_MASK (IWPM_HASH_BUCKET_SIZE - 1) +#define IWPM_MAPINFO_HASH_SIZE 512 +#define IWPM_MAPINFO_HASH_MASK (IWPM_MAPINFO_HASH_SIZE - 1) +#define IWPM_REMINFO_HASH_SIZE 64 +#define IWPM_REMINFO_HASH_MASK (IWPM_REMINFO_HASH_SIZE - 1) static LIST_HEAD(iwpm_nlmsg_req_list); static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock); @@ -42,31 +44,49 @@ static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock); static struct hlist_head *iwpm_hash_bucket; static DEFINE_SPINLOCK(iwpm_mapinfo_lock); +static struct hlist_head *iwpm_reminfo_bucket; +static DEFINE_SPINLOCK(iwpm_reminfo_lock); + static DEFINE_MUTEX(iwpm_admin_lock); static struct iwpm_admin_data iwpm_admin; int iwpm_init(u8 nl_client) { + int ret = 0; if (iwpm_valid_client(nl_client)) return -EINVAL; mutex_lock(&iwpm_admin_lock); if (atomic_read(&iwpm_admin.refcount) == 0) { - iwpm_hash_bucket = kzalloc(IWPM_HASH_BUCKET_SIZE * + iwpm_hash_bucket = kzalloc(IWPM_MAPINFO_HASH_SIZE * sizeof(struct hlist_head), GFP_KERNEL); if (!iwpm_hash_bucket) { - mutex_unlock(&iwpm_admin_lock); + ret = -ENOMEM; pr_err("%s Unable to create mapinfo hash table\n", __func__); - return -ENOMEM; + goto init_exit; + } + iwpm_reminfo_bucket = kzalloc(IWPM_REMINFO_HASH_SIZE * + sizeof(struct hlist_head), GFP_KERNEL); + if (!iwpm_reminfo_bucket) { + kfree(iwpm_hash_bucket); + ret = -ENOMEM; + pr_err("%s Unable to create reminfo hash table\n", __func__); + goto init_exit; } } atomic_inc(&iwpm_admin.refcount); +init_exit: mutex_unlock(&iwpm_admin_lock); - iwpm_set_valid(nl_client, 1); - return 0; + if (!ret) { + iwpm_set_valid(nl_client, 1); + pr_debug("%s: Mapinfo and reminfo tables are created\n", + __func__); + } + return ret; } EXPORT_SYMBOL(iwpm_init); static void free_hash_bucket(void); +static void free_reminfo_bucket(void); int iwpm_exit(u8 nl_client) { @@ -81,7 +101,8 @@ int iwpm_exit(u8 nl_client) } if (atomic_dec_and_test(&iwpm_admin.refcount)) { free_hash_bucket(); - pr_debug("%s: Mapinfo hash table is destroyed\n", __func__); + free_reminfo_bucket(); + pr_debug("%s: Resources are destroyed\n", __func__); } mutex_unlock(&iwpm_admin_lock); iwpm_set_valid(nl_client, 0); @@ -89,7 +110,7 @@ int iwpm_exit(u8 nl_client) } EXPORT_SYMBOL(iwpm_exit); -static struct hlist_head *get_hash_bucket_head(struct sockaddr_storage *, +static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage *, struct sockaddr_storage *); int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr, @@ -99,9 +120,10 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr, struct hlist_head *hash_bucket_head; struct iwpm_mapping_info *map_info; unsigned long flags; + int ret = -EINVAL; if (!iwpm_valid_client(nl_client)) - return -EINVAL; + return ret; map_info = kzalloc(sizeof(struct iwpm_mapping_info), GFP_KERNEL); if (!map_info) { pr_err("%s: Unable to allocate a mapping info\n", __func__); @@ -115,13 +137,16 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr, spin_lock_irqsave(&iwpm_mapinfo_lock, flags); if (iwpm_hash_bucket) { - hash_bucket_head = get_hash_bucket_head( + hash_bucket_head = get_mapinfo_hash_bucket( &map_info->local_sockaddr, &map_info->mapped_sockaddr); - hlist_add_head(&map_info->hlist_node, hash_bucket_head); + if (hash_bucket_head) { + hlist_add_head(&map_info->hlist_node, hash_bucket_head); + ret = 0; + } } spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags); - return 0; + return ret; } EXPORT_SYMBOL(iwpm_create_mapinfo); @@ -136,9 +161,12 @@ int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr, spin_lock_irqsave(&iwpm_mapinfo_lock, flags); if (iwpm_hash_bucket) { - hash_bucket_head = get_hash_bucket_head( + hash_bucket_head = get_mapinfo_hash_bucket( local_sockaddr, mapped_local_addr); + if (!hash_bucket_head) + goto remove_mapinfo_exit; + hlist_for_each_entry_safe(map_info, tmp_hlist_node, hash_bucket_head, hlist_node) { @@ -152,6 +180,7 @@ int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr, } } } +remove_mapinfo_exit: spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags); return ret; } @@ -166,7 +195,7 @@ static void free_hash_bucket(void) /* remove all the mapinfo data from the list */ spin_lock_irqsave(&iwpm_mapinfo_lock, flags); - for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) { + for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) { hlist_for_each_entry_safe(map_info, tmp_hlist_node, &iwpm_hash_bucket[i], hlist_node) { @@ -180,6 +209,96 @@ static void free_hash_bucket(void) spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags); } +static void free_reminfo_bucket(void) +{ + struct hlist_node *tmp_hlist_node; + struct iwpm_remote_info *rem_info; + unsigned long flags; + int i; + + /* remove all the remote info from the list */ + spin_lock_irqsave(&iwpm_reminfo_lock, flags); + for (i = 0; i < IWPM_REMINFO_HASH_SIZE; i++) { + hlist_for_each_entry_safe(rem_info, tmp_hlist_node, + &iwpm_reminfo_bucket[i], hlist_node) { + + hlist_del_init(&rem_info->hlist_node); + kfree(rem_info); + } + } + /* free the hash list */ + kfree(iwpm_reminfo_bucket); + iwpm_reminfo_bucket = NULL; + spin_unlock_irqrestore(&iwpm_reminfo_lock, flags); +} + +static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage *, + struct sockaddr_storage *); + +void iwpm_add_remote_info(struct iwpm_remote_info *rem_info) +{ + struct hlist_head *hash_bucket_head; + unsigned long flags; + + spin_lock_irqsave(&iwpm_reminfo_lock, flags); + if (iwpm_reminfo_bucket) { + hash_bucket_head = get_reminfo_hash_bucket( + &rem_info->mapped_loc_sockaddr, + &rem_info->mapped_rem_sockaddr); + if (hash_bucket_head) + hlist_add_head(&rem_info->hlist_node, hash_bucket_head); + } + spin_unlock_irqrestore(&iwpm_reminfo_lock, flags); +} + +int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr, + struct sockaddr_storage *mapped_rem_addr, + struct sockaddr_storage *remote_addr, + u8 nl_client) +{ + struct hlist_node *tmp_hlist_node; + struct hlist_head *hash_bucket_head; + struct iwpm_remote_info *rem_info = NULL; + unsigned long flags; + int ret = -EINVAL; + + if (!iwpm_valid_client(nl_client)) { + pr_info("%s: Invalid client = %d\n", __func__, nl_client); + return ret; + } + spin_lock_irqsave(&iwpm_reminfo_lock, flags); + if (iwpm_reminfo_bucket) { + hash_bucket_head = get_reminfo_hash_bucket( + mapped_loc_addr, + mapped_rem_addr); + if (!hash_bucket_head) + goto get_remote_info_exit; + hlist_for_each_entry_safe(rem_info, tmp_hlist_node, + hash_bucket_head, hlist_node) { + + if (!iwpm_compare_sockaddr(&rem_info->mapped_loc_sockaddr, + mapped_loc_addr) && + !iwpm_compare_sockaddr(&rem_info->mapped_rem_sockaddr, + mapped_rem_addr)) { + + memcpy(remote_addr, &rem_info->remote_sockaddr, + sizeof(struct sockaddr_storage)); + iwpm_print_sockaddr(remote_addr, + "get_remote_info: Remote sockaddr:"); + + hlist_del_init(&rem_info->hlist_node); + kfree(rem_info); + ret = 0; + break; + } + } + } +get_remote_info_exit: + spin_unlock_irqrestore(&iwpm_reminfo_lock, flags); + return ret; +} +EXPORT_SYMBOL(iwpm_get_remote_info); + struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq, u8 nl_client, gfp_t gfp) { @@ -409,31 +528,54 @@ static u32 iwpm_ipv4_jhash(struct sockaddr_in *ipv4_sockaddr) return hash; } -static struct hlist_head *get_hash_bucket_head(struct sockaddr_storage - *local_sockaddr, - struct sockaddr_storage - *mapped_sockaddr) +static int get_hash_bucket(struct sockaddr_storage *a_sockaddr, + struct sockaddr_storage *b_sockaddr, u32 *hash) { - u32 local_hash, mapped_hash, hash; + u32 a_hash, b_hash; - if (local_sockaddr->ss_family == AF_INET) { - local_hash = iwpm_ipv4_jhash((struct sockaddr_in *) local_sockaddr); - mapped_hash = iwpm_ipv4_jhash((struct sockaddr_in *) mapped_sockaddr); + if (a_sockaddr->ss_family == AF_INET) { + a_hash = iwpm_ipv4_jhash((struct sockaddr_in *) a_sockaddr); + b_hash = iwpm_ipv4_jhash((struct sockaddr_in *) b_sockaddr); - } else if (local_sockaddr->ss_family == AF_INET6) { - local_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) local_sockaddr); - mapped_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) mapped_sockaddr); + } else if (a_sockaddr->ss_family == AF_INET6) { + a_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) a_sockaddr); + b_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) b_sockaddr); } else { pr_err("%s: Invalid sockaddr family\n", __func__); - return NULL; + return -EINVAL; } - if (local_hash == mapped_hash) /* if port mapper isn't available */ - hash = local_hash; + if (a_hash == b_hash) /* if port mapper isn't available */ + *hash = a_hash; else - hash = jhash_2words(local_hash, mapped_hash, 0); + *hash = jhash_2words(a_hash, b_hash, 0); + return 0; +} + +static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage + *local_sockaddr, struct sockaddr_storage + *mapped_sockaddr) +{ + u32 hash; + int ret; - return &iwpm_hash_bucket[hash & IWPM_HASH_BUCKET_MASK]; + ret = get_hash_bucket(local_sockaddr, mapped_sockaddr, &hash); + if (ret) + return NULL; + return &iwpm_hash_bucket[hash & IWPM_MAPINFO_HASH_MASK]; +} + +static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage + *mapped_loc_sockaddr, struct sockaddr_storage + *mapped_rem_sockaddr) +{ + u32 hash; + int ret; + + ret = get_hash_bucket(mapped_loc_sockaddr, mapped_rem_sockaddr, &hash); + if (ret) + return NULL; + return &iwpm_reminfo_bucket[hash & IWPM_REMINFO_HASH_MASK]; } static int send_mapinfo_num(u32 mapping_num, u8 nl_client, int iwpm_pid) @@ -512,7 +654,7 @@ int iwpm_send_mapinfo(u8 nl_client, int iwpm_pid) } skb_num++; spin_lock_irqsave(&iwpm_mapinfo_lock, flags); - for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) { + for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) { hlist_for_each_entry(map_info, &iwpm_hash_bucket[i], hlist_node) { if (map_info->nl_client != nl_client) @@ -595,7 +737,7 @@ int iwpm_mapinfo_available(void) spin_lock_irqsave(&iwpm_mapinfo_lock, flags); if (iwpm_hash_bucket) { - for (i = 0; i < IWPM_HASH_BUCKET_SIZE; i++) { + for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) { if (!hlist_empty(&iwpm_hash_bucket[i])) { full_bucket = 1; break; diff --git a/drivers/infiniband/core/iwpm_util.h b/drivers/infiniband/core/iwpm_util.h index 9777c869a140..ee2d9ff095be 100644 --- a/drivers/infiniband/core/iwpm_util.h +++ b/drivers/infiniband/core/iwpm_util.h @@ -76,6 +76,14 @@ struct iwpm_mapping_info { u8 nl_client; }; +struct iwpm_remote_info { + struct hlist_node hlist_node; + struct sockaddr_storage remote_sockaddr; + struct sockaddr_storage mapped_loc_sockaddr; + struct sockaddr_storage mapped_rem_sockaddr; + u8 nl_client; +}; + struct iwpm_admin_data { atomic_t refcount; atomic_t nlmsg_seq; @@ -127,6 +135,13 @@ int iwpm_wait_complete_req(struct iwpm_nlmsg_request *nlmsg_request); */ int iwpm_get_nlmsg_seq(void); +/** + * iwpm_add_reminfo - Add remote address info of the connecting peer + * to the remote info hash table + * @reminfo: The remote info to be added + */ +void iwpm_add_remote_info(struct iwpm_remote_info *reminfo); + /** * iwpm_valid_client - Check if the port mapper client is valid * @nl_client: The index of the netlink client diff --git a/include/rdma/iw_portmap.h b/include/rdma/iw_portmap.h index 928b2775e992..fda31673a562 100644 --- a/include/rdma/iw_portmap.h +++ b/include/rdma/iw_portmap.h @@ -147,6 +147,16 @@ int iwpm_add_mapping_cb(struct sk_buff *, struct netlink_callback *); */ int iwpm_add_and_query_mapping_cb(struct sk_buff *, struct netlink_callback *); +/** + * iwpm_remote_info_cb - Process remote connecting peer address info, which + * the port mapper has received from the connecting peer + * + * @cb: Contains the received message (payload and netlink header) + * + * Stores the IPv4/IPv6 address info in a hash table + */ +int iwpm_remote_info_cb(struct sk_buff *, struct netlink_callback *); + /** * iwpm_mapping_error_cb - Process port mapper notification for error * @@ -174,6 +184,21 @@ int iwpm_mapping_info_cb(struct sk_buff *, struct netlink_callback *); */ int iwpm_ack_mapping_info_cb(struct sk_buff *, struct netlink_callback *); +/** + * iwpm_get_remote_info - Get the remote connecting peer address info + * + * @mapped_loc_addr: Mapped local address of the listening peer + * @mapped_rem_addr: Mapped remote address of the connecting peer + * @remote_addr: To store the remote address of the connecting peer + * @nl_client: The index of the netlink client + * + * The remote address info is retrieved and provided to the client in + * the remote_addr. After that it is removed from the hash table + */ +int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr, + struct sockaddr_storage *mapped_rem_addr, + struct sockaddr_storage *remote_addr, u8 nl_client); + /** * iwpm_create_mapinfo - Store local and mapped IPv4/IPv6 address * info in a hash table diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h index de69170a30ce..6e4bb4270ca2 100644 --- a/include/uapi/rdma/rdma_netlink.h +++ b/include/uapi/rdma/rdma_netlink.h @@ -37,6 +37,7 @@ enum { RDMA_NL_IWPM_ADD_MAPPING, RDMA_NL_IWPM_QUERY_MAPPING, RDMA_NL_IWPM_REMOVE_MAPPING, + RDMA_NL_IWPM_REMOTE_INFO, RDMA_NL_IWPM_HANDLE_ERR, RDMA_NL_IWPM_MAPINFO, RDMA_NL_IWPM_MAPINFO_NUM, -- cgit v1.2.3 From 471e70583217728955436a3fa6e5201e5c8c296a Mon Sep 17 00:00:00 2001 From: Honggang LI Date: Wed, 29 Apr 2015 17:40:44 +0800 Subject: IB/core: change rdma_gid2ip into void function as it always return zero Signed-off-by: Honggang Li Acked-by: Sean Hefty Signed-off-by: Doug Ledford --- drivers/infiniband/core/addr.c | 13 +++---------- include/rdma/ib_addr.h | 3 +-- 2 files changed, 4 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index f80da50d84a5..38339d220d7f 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -472,13 +472,8 @@ int rdma_addr_find_dmac_by_grh(union ib_gid *sgid, union ib_gid *dgid, u8 *dmac, } sgid_addr, dgid_addr; - ret = rdma_gid2ip(&sgid_addr._sockaddr, sgid); - if (ret) - return ret; - - ret = rdma_gid2ip(&dgid_addr._sockaddr, dgid); - if (ret) - return ret; + rdma_gid2ip(&sgid_addr._sockaddr, sgid); + rdma_gid2ip(&dgid_addr._sockaddr, dgid); memset(&dev_addr, 0, sizeof(dev_addr)); @@ -512,10 +507,8 @@ int rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id) struct sockaddr_in6 _sockaddr_in6; } gid_addr; - ret = rdma_gid2ip(&gid_addr._sockaddr, sgid); + rdma_gid2ip(&gid_addr._sockaddr, sgid); - if (ret) - return ret; memset(&dev_addr, 0, sizeof(dev_addr)); ret = rdma_translate_ip(&gid_addr._sockaddr, &dev_addr, vlan_id); if (ret) diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h index ce55906b54a0..ac54c27a2bfd 100644 --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -160,7 +160,7 @@ static inline int rdma_ip2gid(struct sockaddr *addr, union ib_gid *gid) } /* Important - sockaddr should be a union of sockaddr_in and sockaddr_in6 */ -static inline int rdma_gid2ip(struct sockaddr *out, union ib_gid *gid) +static inline void rdma_gid2ip(struct sockaddr *out, union ib_gid *gid) { if (ipv6_addr_v4mapped((struct in6_addr *)gid)) { struct sockaddr_in *out_in = (struct sockaddr_in *)out; @@ -173,7 +173,6 @@ static inline int rdma_gid2ip(struct sockaddr *out, union ib_gid *gid) out_in->sin6_family = AF_INET6; memcpy(&out_in->sin6_addr.s6_addr, gid->raw, 16); } - return 0; } static inline void iboe_addr_get_sgid(struct rdma_dev_addr *dev_addr, -- cgit v1.2.3 From 0d0f738f6a11856a704dcd8fd3a008b200f17625 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 3 May 2015 09:48:26 -0400 Subject: IB/core: Fix unaligned accesses Addresses the following kernel logs seen during boot of sparc systems: Kernel unaligned access at TPC[103bce50] cm_find_listen+0x34/0xf8 [ib_cm] Kernel unaligned access at TPC[103bce50] cm_find_listen+0x34/0xf8 [ib_cm] Kernel unaligned access at TPC[103bce50] cm_find_listen+0x34/0xf8 [ib_cm] Kernel unaligned access at TPC[103bce50] cm_find_listen+0x34/0xf8 [ib_cm] Kernel unaligned access at TPC[103bce50] cm_find_listen+0x34/0xf8 [ib_cm] Signed-off-by: David Ahern Signed-off-by: Doug Ledford --- drivers/infiniband/core/cm.c | 23 +++++++++++------------ drivers/infiniband/core/cm_msgs.h | 4 ++-- include/rdma/ib_cm.h | 7 ++++--- 3 files changed, 17 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index e28a494e2a3a..0c1419105ff0 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -437,39 +437,38 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id) return cm_id_priv; } -static void cm_mask_copy(u8 *dst, u8 *src, u8 *mask) +static void cm_mask_copy(u32 *dst, const u32 *src, const u32 *mask) { int i; - for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++) - ((unsigned long *) dst)[i] = ((unsigned long *) src)[i] & - ((unsigned long *) mask)[i]; + for (i = 0; i < IB_CM_COMPARE_SIZE; i++) + dst[i] = src[i] & mask[i]; } static int cm_compare_data(struct ib_cm_compare_data *src_data, struct ib_cm_compare_data *dst_data) { - u8 src[IB_CM_COMPARE_SIZE]; - u8 dst[IB_CM_COMPARE_SIZE]; + u32 src[IB_CM_COMPARE_SIZE]; + u32 dst[IB_CM_COMPARE_SIZE]; if (!src_data || !dst_data) return 0; cm_mask_copy(src, src_data->data, dst_data->mask); cm_mask_copy(dst, dst_data->data, src_data->mask); - return memcmp(src, dst, IB_CM_COMPARE_SIZE); + return memcmp(src, dst, sizeof(src)); } -static int cm_compare_private_data(u8 *private_data, +static int cm_compare_private_data(u32 *private_data, struct ib_cm_compare_data *dst_data) { - u8 src[IB_CM_COMPARE_SIZE]; + u32 src[IB_CM_COMPARE_SIZE]; if (!dst_data) return 0; cm_mask_copy(src, private_data, dst_data->mask); - return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE); + return memcmp(src, dst_data->data, sizeof(src)); } /* @@ -538,7 +537,7 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) static struct cm_id_private * cm_find_listen(struct ib_device *device, __be64 service_id, - u8 *private_data) + u32 *private_data) { struct rb_node *node = cm.listen_service_table.rb_node; struct cm_id_private *cm_id_priv; @@ -953,7 +952,7 @@ int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, cm_mask_copy(cm_id_priv->compare_data->data, compare_data->data, compare_data->mask); memcpy(cm_id_priv->compare_data->mask, compare_data->mask, - IB_CM_COMPARE_SIZE); + sizeof(compare_data->mask)); } cm_id->state = IB_CM_LISTEN; diff --git a/drivers/infiniband/core/cm_msgs.h b/drivers/infiniband/core/cm_msgs.h index be068f47e47e..8b76f0ef965e 100644 --- a/drivers/infiniband/core/cm_msgs.h +++ b/drivers/infiniband/core/cm_msgs.h @@ -103,7 +103,7 @@ struct cm_req_msg { /* local ACK timeout:5, rsvd:3 */ u8 alt_offset139; - u8 private_data[IB_CM_REQ_PRIVATE_DATA_SIZE]; + u32 private_data[IB_CM_REQ_PRIVATE_DATA_SIZE / sizeof(u32)]; } __attribute__ ((packed)); @@ -801,7 +801,7 @@ struct cm_sidr_req_msg { __be16 rsvd; __be64 service_id; - u8 private_data[IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE]; + u32 private_data[IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE / sizeof(u32)]; } __attribute__ ((packed)); struct cm_sidr_rep_msg { diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index 0e3ff30647d5..39ed2d2fbd51 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -105,7 +105,8 @@ enum ib_cm_data_size { IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE = 216, IB_CM_SIDR_REP_PRIVATE_DATA_SIZE = 136, IB_CM_SIDR_REP_INFO_LENGTH = 72, - IB_CM_COMPARE_SIZE = 64 + /* compare done u32 at a time */ + IB_CM_COMPARE_SIZE = (64 / sizeof(u32)) }; struct ib_cm_id; @@ -337,8 +338,8 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id); #define IB_SDP_SERVICE_ID_MASK cpu_to_be64(0xFFFFFFFFFFFF0000ULL) struct ib_cm_compare_data { - u8 data[IB_CM_COMPARE_SIZE]; - u8 mask[IB_CM_COMPARE_SIZE]; + u32 data[IB_CM_COMPARE_SIZE]; + u32 mask[IB_CM_COMPARE_SIZE]; }; /** -- cgit v1.2.3 From cd8ae85299d54155702a56811b2e035e63064d3d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 3 May 2015 21:34:46 -0700 Subject: tcp: provide SYN headers for passive connections This patch allows a server application to get the TCP SYN headers for its passive connections. This is useful if the server is doing fingerprinting of clients based on SYN packet contents. Two socket options are added: TCP_SAVE_SYN and TCP_SAVED_SYN. The first is used on a socket to enable saving the SYN headers for child connections. This can be set before or after the listen() call. The latter is used to retrieve the SYN headers for passive connections, if the parent listener has enabled TCP_SAVE_SYN. TCP_SAVED_SYN is read once, it frees the saved SYN headers. The data returned in TCP_SAVED_SYN are network (IPv4/IPv6) and TCP headers. Original patch was written by Tom Herbert, I changed it to not hold a full skb (and associated dst and conntracking reference). We have used such patch for about 3 years at Google. Signed-off-by: Eric Dumazet Acked-by: Neal Cardwell Tested-by: Neal Cardwell Signed-off-by: David S. Miller --- include/linux/tcp.h | 8 ++++++++ include/net/request_sock.h | 4 +++- include/uapi/linux/tcp.h | 2 ++ net/ipv4/tcp.c | 35 +++++++++++++++++++++++++++++++++++ net/ipv4/tcp_input.c | 18 ++++++++++++++++++ net/ipv4/tcp_ipv4.c | 1 + net/ipv4/tcp_minisocks.c | 3 +++ 7 files changed, 70 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 3b2911502a8c..e6fb5df22db1 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -199,6 +199,7 @@ struct tcp_sock { syn_fastopen:1, /* SYN includes Fast Open option */ syn_fastopen_exp:1,/* SYN includes Fast Open exp. option */ syn_data_acked:1,/* data in SYN is acked by SYN-ACK */ + save_syn:1, /* Save headers of SYN packet */ is_cwnd_limited:1;/* forward progress limited by snd_cwnd? */ u32 tlp_high_seq; /* snd_nxt at the time of TLP retransmit. */ @@ -326,6 +327,7 @@ struct tcp_sock { * socket. Used to retransmit SYNACKs etc. */ struct request_sock *fastopen_rsk; + u32 *saved_syn; }; enum tsq_flags { @@ -393,4 +395,10 @@ static inline int fastopen_init_queue(struct sock *sk, int backlog) return 0; } +static inline void tcp_saved_syn_free(struct tcp_sock *tp) +{ + kfree(tp->saved_syn); + tp->saved_syn = NULL; +} + #endif /* _LINUX_TCP_H */ diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 9f4265ce8892..87935cad2f7b 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -64,6 +64,7 @@ struct request_sock { struct timer_list rsk_timer; const struct request_sock_ops *rsk_ops; struct sock *sk; + u32 *saved_syn; u32 secid; u32 peer_secid; }; @@ -77,7 +78,7 @@ reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk_listener) req->rsk_ops = ops; sock_hold(sk_listener); req->rsk_listener = sk_listener; - + req->saved_syn = NULL; /* Following is temporary. It is coupled with debugging * helpers in reqsk_put() & reqsk_free() */ @@ -104,6 +105,7 @@ static inline void reqsk_free(struct request_sock *req) req->rsk_ops->destructor(req); if (req->rsk_listener) sock_put(req->rsk_listener); + kfree(req->saved_syn); kmem_cache_free(req->rsk_ops->slab, req); } diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h index faa72f4fa547..51ebedba577f 100644 --- a/include/uapi/linux/tcp.h +++ b/include/uapi/linux/tcp.h @@ -113,6 +113,8 @@ enum { #define TCP_TIMESTAMP 24 #define TCP_NOTSENT_LOWAT 25 /* limit number of unsent bytes in write queue */ #define TCP_CC_INFO 26 /* Get Congestion Control (optional) info */ +#define TCP_SAVE_SYN 27 /* Record SYN headers for new connections */ +#define TCP_SAVED_SYN 28 /* Get SYN headers recorded for connection */ struct tcp_repair_opt { __u32 opt_code; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 46efa03d2b11..ecccfdc50d76 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2482,6 +2482,13 @@ static int do_tcp_setsockopt(struct sock *sk, int level, icsk->icsk_syn_retries = val; break; + case TCP_SAVE_SYN: + if (val < 0 || val > 1) + err = -EINVAL; + else + tp->save_syn = val; + break; + case TCP_LINGER2: if (val < 0) tp->linger2 = -1; @@ -2818,6 +2825,34 @@ static int do_tcp_getsockopt(struct sock *sk, int level, case TCP_NOTSENT_LOWAT: val = tp->notsent_lowat; break; + case TCP_SAVE_SYN: + val = tp->save_syn; + break; + case TCP_SAVED_SYN: { + if (get_user(len, optlen)) + return -EFAULT; + + lock_sock(sk); + if (tp->saved_syn) { + len = min_t(unsigned int, tp->saved_syn[0], len); + if (put_user(len, optlen)) { + release_sock(sk); + return -EFAULT; + } + if (copy_to_user(optval, tp->saved_syn + 1, len)) { + release_sock(sk); + return -EFAULT; + } + tcp_saved_syn_free(tp); + release_sock(sk); + } else { + release_sock(sk); + len = 0; + if (put_user(len, optlen)) + return -EFAULT; + } + return 0; + } default: return -ENOPROTOOPT; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 09bdc4abfcbb..df2ca615cd0c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -6060,6 +6060,23 @@ static bool tcp_syn_flood_action(struct sock *sk, return want_cookie; } +static void tcp_reqsk_record_syn(const struct sock *sk, + struct request_sock *req, + const struct sk_buff *skb) +{ + if (tcp_sk(sk)->save_syn) { + u32 len = skb_network_header_len(skb) + tcp_hdrlen(skb); + u32 *copy; + + copy = kmalloc(len + sizeof(u32), GFP_ATOMIC); + if (copy) { + copy[0] = len; + memcpy(©[1], skb_network_header(skb), len); + req->saved_syn = copy; + } + } +} + int tcp_conn_request(struct request_sock_ops *rsk_ops, const struct tcp_request_sock_ops *af_ops, struct sock *sk, struct sk_buff *skb) @@ -6192,6 +6209,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, tcp_rsk(req)->tfo_listener = false; af_ops->queue_hash_add(sk, req, TCP_TIMEOUT_INIT); } + tcp_reqsk_record_syn(sk, req, skb); return 0; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index fc1c658ec6c1..91cb4768a860 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1802,6 +1802,7 @@ void tcp_v4_destroy_sock(struct sock *sk) /* If socket is aborted during connect operation */ tcp_free_fastopen_req(tp); + tcp_saved_syn_free(tp); sk_sockets_allocated_dec(sk); sock_release_memcg(sk); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index e5d7649136fc..ebe2ab2596ed 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -536,6 +536,9 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, newtp->fastopen_rsk = NULL; newtp->syn_data_acked = 0; + newtp->saved_syn = req->saved_syn; + req->saved_syn = NULL; + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_PASSIVEOPENS); } return newsk; -- cgit v1.2.3 From 2c7a88c252bf3381958cf716f31b6b2e0f2f3fa7 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 4 May 2015 14:33:48 -0700 Subject: etherdev: Fix sparse error, make test usable by other functions This change does two things. First it fixes a sparse error for the fact that the __be16 degrades to an integer. Since that is actually what I am kind of doing I am simply working around that by forcing both sides of the comparison to u16. Also I realized on some compilers I was generating another instruction for big endian systems such as PowerPC since it was masking the value before doing the comparison. So to resolve that I have simply pulled the mask out and wrapped it in an #ifndef __BIG_ENDIAN. Lastly I pulled this all out into its own function. I notices there are similar checks in a number of other places so this function can be reused there to help reduce overhead in these paths as well. Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- include/linux/etherdevice.h | 18 ++++++++++++++++++ net/ethernet/eth.c | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index c4a10f991fe0..9012f8775208 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -190,6 +190,24 @@ static inline bool is_valid_ether_addr(const u8 *addr) return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr); } +/** + * eth_proto_is_802_3 - Determine if a given Ethertype/length is a protocol + * @proto: Ethertype/length value to be tested + * + * Check that the value from the Ethertype/length field is a valid Ethertype. + * + * Return true if the valid is an 802.3 supported Ethertype. + */ +static inline bool eth_proto_is_802_3(__be16 proto) +{ +#ifndef __BIG_ENDIAN + /* if CPU is little endian mask off bits representing LSB */ + proto &= htons(0xFF00); +#endif + /* cast both to u16 and compare since LSB can be ignored */ + return (__force u16)proto >= (__force u16)htons(ETH_P_802_3_MIN); +} + /** * eth_random_addr - Generate software assigned random Ethernet address * @addr: Pointer to a six-byte array containing the Ethernet address diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 314e4c5a5a5e..9045e2a1108f 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -179,7 +179,7 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) if (unlikely(netdev_uses_dsa(dev))) return htons(ETH_P_XDSA); - if (likely((eth->h_proto & htons(0xFF00)) >= htons(ETH_P_802_3_MIN))) + if (likely(eth_proto_is_802_3(eth->h_proto))) return eth->h_proto; /* -- cgit v1.2.3 From 9545b22da647cf6fbbac9c5a48c50fd72d892b11 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Mon, 4 May 2015 14:34:10 -0700 Subject: vlan: Use eth_proto_is_802_3 Replace "ntohs(proto) >= ETH_P_802_3_MIN" w/ eth_proto_is_802_3(proto). Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- include/linux/if_vlan.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 920e4457ce6e..b9ab677c0c0a 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -539,7 +539,7 @@ static inline void vlan_set_encap_proto(struct sk_buff *skb, */ proto = vhdr->h_vlan_encapsulated_proto; - if (ntohs(proto) >= ETH_P_802_3_MIN) { + if (eth_proto_is_802_3(proto)) { skb->protocol = proto; return; } -- cgit v1.2.3 From c967a0873a7836c7a77bf611f1c7d3f47c554c45 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 5 May 2015 09:06:30 -0700 Subject: mpls: Move reserved label definitions Move to include/uapi/linux/mpls.h to be externally visibile. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/uapi/linux/mpls.h | 10 ++++++++++ net/mpls/af_mpls.c | 18 +++++++++--------- net/mpls/internal.h | 10 ---------- 3 files changed, 19 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/mpls.h b/include/uapi/linux/mpls.h index bc9abfe88c9a..0fe6ea5a41d5 100644 --- a/include/uapi/linux/mpls.h +++ b/include/uapi/linux/mpls.h @@ -31,4 +31,14 @@ struct mpls_label { #define MPLS_LS_TTL_MASK 0x000000FF #define MPLS_LS_TTL_SHIFT 0 +/* Reserved labels */ +#define MPLS_LABEL_IPV4_EXPLICIT_NULL 0 /* RFC3032 */ +#define MPLS_LABEL_ROUTER_ALERT 1 /* RFC3032 */ +#define MPLS_LABEL_IPV6_EXPLICIT_NULL 2 /* RFC3032 */ +#define MPLS_LABEL_IMPLICIT_NULL 3 /* RFC3032 */ +#define MPLS_LABEL_ENTROPY_INDICATOR 7 /* RFC6790 */ +#define MPLS_LABEL_GAL 13 /* RFC5586 */ +#define MPLS_LABEL_OAM_ALERT 14 /* RFC3429 */ +#define MPLS_LABEL_EXTENSION 15 /* RFC7274 */ + #endif /* _UAPI_MPLS_H */ diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 954810c76a86..b6eb7615960a 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -647,7 +647,7 @@ int nla_get_labels(const struct nlattr *nla, return -EINVAL; switch (dec.label) { - case LABEL_IMPLICIT_NULL: + case MPLS_LABEL_IMPLICIT_NULL: /* RFC3032: This is a label that an LSR may * assign and distribute, but which never * actually appears in the encapsulation. @@ -935,7 +935,7 @@ static int resize_platform_label_table(struct net *net, size_t limit) } /* In case the predefined labels need to be populated */ - if (limit > LABEL_IPV4_EXPLICIT_NULL) { + if (limit > MPLS_LABEL_IPV4_EXPLICIT_NULL) { struct net_device *lo = net->loopback_dev; rt0 = mpls_rt_alloc(lo->addr_len); if (!rt0) @@ -945,7 +945,7 @@ static int resize_platform_label_table(struct net *net, size_t limit) rt0->rt_via_table = NEIGH_LINK_TABLE; memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len); } - if (limit > LABEL_IPV6_EXPLICIT_NULL) { + if (limit > MPLS_LABEL_IPV6_EXPLICIT_NULL) { struct net_device *lo = net->loopback_dev; rt2 = mpls_rt_alloc(lo->addr_len); if (!rt2) @@ -973,15 +973,15 @@ static int resize_platform_label_table(struct net *net, size_t limit) memcpy(labels, old, cp_size); /* If needed set the predefined labels */ - if ((old_limit <= LABEL_IPV6_EXPLICIT_NULL) && - (limit > LABEL_IPV6_EXPLICIT_NULL)) { - RCU_INIT_POINTER(labels[LABEL_IPV6_EXPLICIT_NULL], rt2); + if ((old_limit <= MPLS_LABEL_IPV6_EXPLICIT_NULL) && + (limit > MPLS_LABEL_IPV6_EXPLICIT_NULL)) { + RCU_INIT_POINTER(labels[MPLS_LABEL_IPV6_EXPLICIT_NULL], rt2); rt2 = NULL; } - if ((old_limit <= LABEL_IPV4_EXPLICIT_NULL) && - (limit > LABEL_IPV4_EXPLICIT_NULL)) { - RCU_INIT_POINTER(labels[LABEL_IPV4_EXPLICIT_NULL], rt0); + if ((old_limit <= MPLS_LABEL_IPV4_EXPLICIT_NULL) && + (limit > MPLS_LABEL_IPV4_EXPLICIT_NULL)) { + RCU_INIT_POINTER(labels[MPLS_LABEL_IPV4_EXPLICIT_NULL], rt0); rt0 = NULL; } diff --git a/net/mpls/internal.h b/net/mpls/internal.h index 693877d69606..b064c345042c 100644 --- a/net/mpls/internal.h +++ b/net/mpls/internal.h @@ -1,16 +1,6 @@ #ifndef MPLS_INTERNAL_H #define MPLS_INTERNAL_H -#define LABEL_IPV4_EXPLICIT_NULL 0 /* RFC3032 */ -#define LABEL_ROUTER_ALERT_LABEL 1 /* RFC3032 */ -#define LABEL_IPV6_EXPLICIT_NULL 2 /* RFC3032 */ -#define LABEL_IMPLICIT_NULL 3 /* RFC3032 */ -#define LABEL_ENTROPY_INDICATOR 7 /* RFC6790 */ -#define LABEL_GAL 13 /* RFC5586 */ -#define LABEL_OAM_ALERT 14 /* RFC3429 */ -#define LABEL_EXTENSION 15 /* RFC7274 */ - - struct mpls_shim_hdr { __be32 label_stack_entry; }; -- cgit v1.2.3 From 05836c378c7af9527b98a83746f32c7289a5f3c8 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 5 May 2015 16:23:57 -0700 Subject: util_macros.h: have array pointer point to array of constants Using the new find_closest() macro can result in the following sparse warnings. drivers/hwmon/lm85.c:194:16: warning: incorrect type in initializer (different modifiers) drivers/hwmon/lm85.c:194:16: expected int *__fc_a drivers/hwmon/lm85.c:194:16: got int static const [toplevel] * drivers/hwmon/lm85.c:210:16: warning: incorrect type in initializer (different modifiers) drivers/hwmon/lm85.c:210:16: expected int *__fc_a drivers/hwmon/lm85.c:210:16: got int const *map This is because the array passed to find_closest() will typically be declared as array of constants, but the macro declares a non-constant pointer to it. Signed-off-by: Guenter Roeck Cc: Bartosz Golaszewski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/util_macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/util_macros.h b/include/linux/util_macros.h index d5f4fb69dba3..f9b2ce58039b 100644 --- a/include/linux/util_macros.h +++ b/include/linux/util_macros.h @@ -5,7 +5,7 @@ ({ \ typeof(as) __fc_i, __fc_as = (as) - 1; \ typeof(x) __fc_x = (x); \ - typeof(*a) *__fc_a = (a); \ + typeof(*a) const *__fc_a = (a); \ for (__fc_i = 0; __fc_i < __fc_as; __fc_i++) { \ if (__fc_x op DIV_ROUND_CLOSEST(__fc_a[__fc_i] + \ __fc_a[__fc_i + 1], 2)) \ -- cgit v1.2.3 From d8fd150fe3935e1692bf57c66691e17409ebb9c1 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Tue, 5 May 2015 16:24:00 -0700 Subject: nilfs2: fix sanity check of btree level in nilfs_btree_root_broken() The range check for b-tree level parameter in nilfs_btree_root_broken() is wrong; it accepts the case of "level == NILFS_BTREE_LEVEL_MAX" even though the level is limited to values in the range of 0 to (NILFS_BTREE_LEVEL_MAX - 1). Since the level parameter is read from storage device and used to index nilfs_btree_path array whose element count is NILFS_BTREE_LEVEL_MAX, it can cause memory overrun during btree operations if the boundary value is set to the level parameter on device. This fixes the broken sanity check and adds a comment to clarify that the upper bound NILFS_BTREE_LEVEL_MAX is exclusive. Signed-off-by: Ryusuke Konishi Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nilfs2/btree.c | 2 +- include/linux/nilfs2_fs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 059f37137f9a..919fd5bb14a8 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -388,7 +388,7 @@ static int nilfs_btree_root_broken(const struct nilfs_btree_node *node, nchildren = nilfs_btree_node_get_nchildren(node); if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN || - level > NILFS_BTREE_LEVEL_MAX || + level >= NILFS_BTREE_LEVEL_MAX || nchildren < 0 || nchildren > NILFS_BTREE_ROOT_NCHILDREN_MAX)) { pr_crit("NILFS: bad btree root (inode number=%lu): level = %d, flags = 0x%x, nchildren = %d\n", diff --git a/include/linux/nilfs2_fs.h b/include/linux/nilfs2_fs.h index ff3fea3194c6..9abb763e4b86 100644 --- a/include/linux/nilfs2_fs.h +++ b/include/linux/nilfs2_fs.h @@ -460,7 +460,7 @@ struct nilfs_btree_node { /* level */ #define NILFS_BTREE_LEVEL_DATA 0 #define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1) -#define NILFS_BTREE_LEVEL_MAX 14 +#define NILFS_BTREE_LEVEL_MAX 14 /* Max level (exclusive) */ /** * struct nilfs_palloc_group_desc - block group descriptor -- cgit v1.2.3 From a2f11835994ed5bcd6d66c7205947cc482231b08 Mon Sep 17 00:00:00 2001 From: Shawn Landden Date: Tue, 5 May 2015 09:07:16 -0700 Subject: can.h: make padding given by gcc explicit The current definition of struct can_frame has a 16-byte size, with 8-byte alignment, but the 3 bytes of padding are not explicit like the similar 2 bytes of padding of struct canfd_frame. Make it explicit so it is easier to read. Signed-off-by: Shawn Landden Acked-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- Documentation/networking/can.txt | 3 +++ include/uapi/linux/can.h | 6 ++++++ 2 files changed, 9 insertions(+) (limited to 'include') diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt index 5abad1e921ca..b48d4a149411 100644 --- a/Documentation/networking/can.txt +++ b/Documentation/networking/can.txt @@ -268,6 +268,9 @@ solution for a couple of reasons: struct can_frame { canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ __u8 can_dlc; /* frame payload length in byte (0 .. 8) */ + __u8 __pad; /* padding */ + __u8 __res0; /* reserved / padding */ + __u8 __res1; /* reserved / padding */ __u8 data[8] __attribute__((aligned(8))); }; diff --git a/include/uapi/linux/can.h b/include/uapi/linux/can.h index 41892f720057..9692cda5f8fc 100644 --- a/include/uapi/linux/can.h +++ b/include/uapi/linux/can.h @@ -95,11 +95,17 @@ typedef __u32 can_err_mask_t; * @can_dlc: frame payload length in byte (0 .. 8) aka data length code * N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1 * mapping of the 'data length code' to the real payload length + * @__pad: padding + * @__res0: reserved / padding + * @__res1: reserved / padding * @data: CAN frame payload (up to 8 byte) */ struct can_frame { canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ __u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */ + __u8 __pad; /* padding */ + __u8 __res0; /* reserved / padding */ + __u8 __res1; /* reserved / padding */ __u8 data[CAN_MAX_DLEN] __attribute__((aligned(8))); }; -- cgit v1.2.3 From ac01ce1410fc2c7b5f3af5e9c972e6a412eee54f Mon Sep 17 00:00:00 2001 From: Alex Bennée Date: Wed, 29 Apr 2015 16:18:46 +0100 Subject: tracing: Make ftrace_print_array_seq compute buf_len MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only caller to this function (__print_array) was getting it wrong by passing the array length instead of buffer length. As the element size was already being passed for other reasons it seems reasonable to push the calculation of buffer length into the function. Link: http://lkml.kernel.org/r/1430320727-14582-1-git-send-email-alex.bennee@linaro.org Signed-off-by: Alex Bennée Signed-off-by: Steven Rostedt --- include/linux/ftrace_event.h | 2 +- kernel/trace/trace_output.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 46e83c2156c6..f9ecf63d47f1 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -46,7 +46,7 @@ const char *ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int len); const char *ftrace_print_array_seq(struct trace_seq *p, - const void *buf, int buf_len, + const void *buf, int count, size_t el_size); struct trace_iterator; diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 692bf7184c8c..25a086bcb700 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -178,12 +178,13 @@ ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len) EXPORT_SYMBOL(ftrace_print_hex_seq); const char * -ftrace_print_array_seq(struct trace_seq *p, const void *buf, int buf_len, +ftrace_print_array_seq(struct trace_seq *p, const void *buf, int count, size_t el_size) { const char *ret = trace_seq_buffer_ptr(p); const char *prefix = ""; void *ptr = (void *)buf; + size_t buf_len = count * el_size; trace_seq_putc(p, '{'); -- cgit v1.2.3 From 0782e63bc6fe7e2d3408d250df11d388b7799c6b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 5 May 2015 19:49:49 +0200 Subject: sched: Handle priority boosted tasks proper in setscheduler() Ronny reported that the following scenario is not handled correctly: T1 (prio = 10) lock(rtmutex); T2 (prio = 20) lock(rtmutex) boost T1 T1 (prio = 20) sys_set_scheduler(prio = 30) T1 prio = 30 .... sys_set_scheduler(prio = 10) T1 prio = 30 The last step is wrong as T1 should now be back at prio 20. Commit c365c292d059 ("sched: Consider pi boosting in setscheduler()") only handles the case where a boosted tasks tries to lower its priority. Fix it by taking the new effective priority into account for the decision whether a change of the priority is required. Reported-by: Ronny Meeus Tested-by: Steven Rostedt Signed-off-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Steven Rostedt Cc: Cc: Borislav Petkov Cc: H. Peter Anvin Cc: Mike Galbraith Fixes: c365c292d059 ("sched: Consider pi boosting in setscheduler()") Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1505051806060.4225@nanos Signed-off-by: Ingo Molnar --- include/linux/sched/rt.h | 7 ++++--- kernel/locking/rtmutex.c | 12 +++++++----- kernel/sched/core.c | 26 ++++++++++++++------------ 3 files changed, 25 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/include/linux/sched/rt.h b/include/linux/sched/rt.h index 6341f5be6e24..a30b172df6e1 100644 --- a/include/linux/sched/rt.h +++ b/include/linux/sched/rt.h @@ -18,7 +18,7 @@ static inline int rt_task(struct task_struct *p) #ifdef CONFIG_RT_MUTEXES extern int rt_mutex_getprio(struct task_struct *p); extern void rt_mutex_setprio(struct task_struct *p, int prio); -extern int rt_mutex_check_prio(struct task_struct *task, int newprio); +extern int rt_mutex_get_effective_prio(struct task_struct *task, int newprio); extern struct task_struct *rt_mutex_get_top_task(struct task_struct *task); extern void rt_mutex_adjust_pi(struct task_struct *p); static inline bool tsk_is_pi_blocked(struct task_struct *tsk) @@ -31,9 +31,10 @@ static inline int rt_mutex_getprio(struct task_struct *p) return p->normal_prio; } -static inline int rt_mutex_check_prio(struct task_struct *task, int newprio) +static inline int rt_mutex_get_effective_prio(struct task_struct *task, + int newprio) { - return 0; + return newprio; } static inline struct task_struct *rt_mutex_get_top_task(struct task_struct *task) diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index b73279367087..b025295f4966 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -265,15 +265,17 @@ struct task_struct *rt_mutex_get_top_task(struct task_struct *task) } /* - * Called by sched_setscheduler() to check whether the priority change - * is overruled by a possible priority boosting. + * Called by sched_setscheduler() to get the priority which will be + * effective after the change. */ -int rt_mutex_check_prio(struct task_struct *task, int newprio) +int rt_mutex_get_effective_prio(struct task_struct *task, int newprio) { if (!task_has_pi_waiters(task)) - return 0; + return newprio; - return task_top_pi_waiter(task)->task->prio <= newprio; + if (task_top_pi_waiter(task)->task->prio <= newprio) + return task_top_pi_waiter(task)->task->prio; + return newprio; } /* diff --git a/kernel/sched/core.c b/kernel/sched/core.c index fe22f7510bce..34db9bf892a3 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3300,15 +3300,18 @@ static void __setscheduler_params(struct task_struct *p, /* Actually do priority change: must hold pi & rq lock. */ static void __setscheduler(struct rq *rq, struct task_struct *p, - const struct sched_attr *attr) + const struct sched_attr *attr, bool keep_boost) { __setscheduler_params(p, attr); /* - * If we get here, there was no pi waiters boosting the - * task. It is safe to use the normal prio. + * Keep a potential priority boosting if called from + * sched_setscheduler(). */ - p->prio = normal_prio(p); + if (keep_boost) + p->prio = rt_mutex_get_effective_prio(p, normal_prio(p)); + else + p->prio = normal_prio(p); if (dl_prio(p->prio)) p->sched_class = &dl_sched_class; @@ -3408,7 +3411,7 @@ static int __sched_setscheduler(struct task_struct *p, int newprio = dl_policy(attr->sched_policy) ? MAX_DL_PRIO - 1 : MAX_RT_PRIO - 1 - attr->sched_priority; int retval, oldprio, oldpolicy = -1, queued, running; - int policy = attr->sched_policy; + int new_effective_prio, policy = attr->sched_policy; unsigned long flags; const struct sched_class *prev_class; struct rq *rq; @@ -3590,15 +3593,14 @@ change: oldprio = p->prio; /* - * Special case for priority boosted tasks. - * - * If the new priority is lower or equal (user space view) - * than the current (boosted) priority, we just store the new + * Take priority boosted tasks into account. If the new + * effective priority is unchanged, we just store the new * normal parameters and do not touch the scheduler class and * the runqueue. This will be done when the task deboost * itself. */ - if (rt_mutex_check_prio(p, newprio)) { + new_effective_prio = rt_mutex_get_effective_prio(p, newprio); + if (new_effective_prio == oldprio) { __setscheduler_params(p, attr); task_rq_unlock(rq, p, &flags); return 0; @@ -3612,7 +3614,7 @@ change: put_prev_task(rq, p); prev_class = p->sched_class; - __setscheduler(rq, p, attr); + __setscheduler(rq, p, attr, true); if (running) p->sched_class->set_curr_task(rq); @@ -7346,7 +7348,7 @@ static void normalize_task(struct rq *rq, struct task_struct *p) queued = task_on_rq_queued(p); if (queued) dequeue_task(rq, p, 0); - __setscheduler(rq, p, &attr); + __setscheduler(rq, p, &attr, false); if (queued) { enqueue_task(rq, p, 0); resched_curr(rq); -- cgit v1.2.3 From 0cd3be6e9a46f84ef7a42e1a5645d32ad547b12e Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Mon, 4 May 2015 23:04:16 +0200 Subject: clk: si5351: Do not pass struct clk in platform_data When registering clk-si5351 by platform_data, we should not pass struct clk for the reference clocks. Drop struct clk from platform_data and rework the driver to use devm_clk_get of named clock references. While at it, check for at least one valid input clock and properly prepare/ enable valid reference clocks. Signed-off-by: Sebastian Hesselbarth Reported-by: Michael Welling Reported-by: Jean-Francois Moine Reported-by: Russell King Tested-by: Michael Welling Tested-by: Jean-Francois Moine Signed-off-by: Michael Turquette --- drivers/clk/clk-si5351.c | 63 +++++++++++++++++++++++++----------- include/linux/platform_data/si5351.h | 4 --- 2 files changed, 45 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index 44ea107cfc67..30335d3b99af 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -1128,13 +1128,6 @@ static int si5351_dt_parse(struct i2c_client *client, if (!pdata) return -ENOMEM; - pdata->clk_xtal = of_clk_get(np, 0); - if (!IS_ERR(pdata->clk_xtal)) - clk_put(pdata->clk_xtal); - pdata->clk_clkin = of_clk_get(np, 1); - if (!IS_ERR(pdata->clk_clkin)) - clk_put(pdata->clk_clkin); - /* * property silabs,pll-source : , [<..>] * allow to selectively set pll source @@ -1328,8 +1321,22 @@ static int si5351_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, drvdata); drvdata->client = client; drvdata->variant = variant; - drvdata->pxtal = pdata->clk_xtal; - drvdata->pclkin = pdata->clk_clkin; + drvdata->pxtal = devm_clk_get(&client->dev, "xtal"); + drvdata->pclkin = devm_clk_get(&client->dev, "clkin"); + + if (PTR_ERR(drvdata->pxtal) == -EPROBE_DEFER || + PTR_ERR(drvdata->pclkin) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + /* + * Check for valid parent clock: VARIANT_A and VARIANT_B need XTAL, + * VARIANT_C can have CLKIN instead. + */ + if (IS_ERR(drvdata->pxtal) && + (drvdata->variant != SI5351_VARIANT_C || IS_ERR(drvdata->pclkin))) { + dev_err(&client->dev, "missing parent clock\n"); + return -EINVAL; + } drvdata->regmap = devm_regmap_init_i2c(client, &si5351_regmap_config); if (IS_ERR(drvdata->regmap)) { @@ -1393,6 +1400,11 @@ static int si5351_i2c_probe(struct i2c_client *client, } } + if (!IS_ERR(drvdata->pxtal)) + clk_prepare_enable(drvdata->pxtal); + if (!IS_ERR(drvdata->pclkin)) + clk_prepare_enable(drvdata->pclkin); + /* register xtal input clock gate */ memset(&init, 0, sizeof(init)); init.name = si5351_input_names[0]; @@ -1407,7 +1419,8 @@ static int si5351_i2c_probe(struct i2c_client *client, clk = devm_clk_register(&client->dev, &drvdata->xtal); if (IS_ERR(clk)) { dev_err(&client->dev, "unable to register %s\n", init.name); - return PTR_ERR(clk); + ret = PTR_ERR(clk); + goto err_clk; } /* register clkin input clock gate */ @@ -1425,7 +1438,8 @@ static int si5351_i2c_probe(struct i2c_client *client, if (IS_ERR(clk)) { dev_err(&client->dev, "unable to register %s\n", init.name); - return PTR_ERR(clk); + ret = PTR_ERR(clk); + goto err_clk; } } @@ -1447,7 +1461,8 @@ static int si5351_i2c_probe(struct i2c_client *client, clk = devm_clk_register(&client->dev, &drvdata->pll[0].hw); if (IS_ERR(clk)) { dev_err(&client->dev, "unable to register %s\n", init.name); - return -EINVAL; + ret = PTR_ERR(clk); + goto err_clk; } /* register PLLB or VXCO (Si5351B) */ @@ -1471,7 +1486,8 @@ static int si5351_i2c_probe(struct i2c_client *client, clk = devm_clk_register(&client->dev, &drvdata->pll[1].hw); if (IS_ERR(clk)) { dev_err(&client->dev, "unable to register %s\n", init.name); - return -EINVAL; + ret = PTR_ERR(clk); + goto err_clk; } /* register clk multisync and clk out divider */ @@ -1492,8 +1508,10 @@ static int si5351_i2c_probe(struct i2c_client *client, num_clocks * sizeof(*drvdata->onecell.clks), GFP_KERNEL); if (WARN_ON(!drvdata->msynth || !drvdata->clkout || - !drvdata->onecell.clks)) - return -ENOMEM; + !drvdata->onecell.clks)) { + ret = -ENOMEM; + goto err_clk; + } for (n = 0; n < num_clocks; n++) { drvdata->msynth[n].num = n; @@ -1511,7 +1529,8 @@ static int si5351_i2c_probe(struct i2c_client *client, if (IS_ERR(clk)) { dev_err(&client->dev, "unable to register %s\n", init.name); - return -EINVAL; + ret = PTR_ERR(clk); + goto err_clk; } } @@ -1538,7 +1557,8 @@ static int si5351_i2c_probe(struct i2c_client *client, if (IS_ERR(clk)) { dev_err(&client->dev, "unable to register %s\n", init.name); - return -EINVAL; + ret = PTR_ERR(clk); + goto err_clk; } drvdata->onecell.clks[n] = clk; @@ -1557,10 +1577,17 @@ static int si5351_i2c_probe(struct i2c_client *client, &drvdata->onecell); if (ret) { dev_err(&client->dev, "unable to add clk provider\n"); - return ret; + goto err_clk; } return 0; + +err_clk: + if (!IS_ERR(drvdata->pxtal)) + clk_disable_unprepare(drvdata->pxtal); + if (!IS_ERR(drvdata->pclkin)) + clk_disable_unprepare(drvdata->pclkin); + return ret; } static const struct i2c_device_id si5351_i2c_ids[] = { diff --git a/include/linux/platform_data/si5351.h b/include/linux/platform_data/si5351.h index a947ab8b441a..533d9807e543 100644 --- a/include/linux/platform_data/si5351.h +++ b/include/linux/platform_data/si5351.h @@ -5,8 +5,6 @@ #ifndef __LINUX_PLATFORM_DATA_SI5351_H__ #define __LINUX_PLATFORM_DATA_SI5351_H__ -struct clk; - /** * enum si5351_pll_src - Si5351 pll clock source * @SI5351_PLL_SRC_DEFAULT: default, do not change eeprom config @@ -107,8 +105,6 @@ struct si5351_clkout_config { * @clkout: array of clkout configuration */ struct si5351_platform_data { - struct clk *clk_xtal; - struct clk *clk_clkin; enum si5351_pll_src pll_src[2]; struct si5351_clkout_config clkout[8]; }; -- cgit v1.2.3 From 21c8fe9915276d923f8c1e43434fd6d37a3b9aef Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 6 May 2015 14:26:24 -0700 Subject: tcp: adjust window probe timers to safer values With the advent of small rto timers in datacenter TCP, (ip route ... rto_min x), the following can happen : 1) Qdisc is full, transmit fails. TCP sets a timer based on icsk_rto to retry the transmit, without exponential backoff. With low icsk_rto, and lot of sockets, all cpus are servicing timer interrupts like crazy. Intent of the code was to retry with a timer between 200 (TCP_RTO_MIN) and 500ms (TCP_RESOURCE_PROBE_INTERVAL) 2) Receivers can send zero windows if they don't drain their receive queue. TCP sends zero window probes, based on icsk_rto current value, with exponential backoff. With /proc/sys/net/ipv4/tcp_retries2 being 15 (or even smaller in some cases), sender can abort in less than one or two minutes ! If receiver stops the sender, it obviously doesn't care of very tight rto. Probability of dropping the ACK reopening the window is not worth the risk. Lets change the base timer to be at least 200ms (TCP_RTO_MIN) for these events (but not normal RTO based retransmits) A followup patch adds a new SNMP counter, as it would have helped a lot diagnosing this issue. Signed-off-by: Eric Dumazet Signed-off-by: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: David S. Miller --- include/net/tcp.h | 27 ++++++++++++++++++++++----- net/ipv4/tcp_input.c | 2 +- net/ipv4/tcp_output.c | 2 +- 3 files changed, 24 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index 6d204f3f9df8..7a2248a35b13 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1043,14 +1043,31 @@ static inline bool tcp_is_cwnd_limited(const struct sock *sk) return tp->is_cwnd_limited; } -static inline void tcp_check_probe_timer(struct sock *sk) +/* Something is really bad, we could not queue an additional packet, + * because qdisc is full or receiver sent a 0 window. + * We do not want to add fuel to the fire, or abort too early, + * so make sure the timer we arm now is at least 200ms in the future, + * regardless of current icsk_rto value (as it could be ~2ms) + */ +static inline unsigned long tcp_probe0_base(const struct sock *sk) { - const struct tcp_sock *tp = tcp_sk(sk); - const struct inet_connection_sock *icsk = inet_csk(sk); + return max_t(unsigned long, inet_csk(sk)->icsk_rto, TCP_RTO_MIN); +} - if (!tp->packets_out && !icsk->icsk_pending) +/* Variant of inet_csk_rto_backoff() used for zero window probes */ +static inline unsigned long tcp_probe0_when(const struct sock *sk, + unsigned long max_when) +{ + u64 when = (u64)tcp_probe0_base(sk) << inet_csk(sk)->icsk_backoff; + + return (unsigned long)min_t(u64, when, max_when); +} + +static inline void tcp_check_probe_timer(struct sock *sk) +{ + if (!tcp_sk(sk)->packets_out && !inet_csk(sk)->icsk_pending) inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0, - icsk->icsk_rto, TCP_RTO_MAX); + tcp_probe0_base(sk), TCP_RTO_MAX); } static inline void tcp_init_wl(struct tcp_sock *tp, u32 seq) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index df2ca615cd0c..cf8b20ff6658 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3233,7 +3233,7 @@ static void tcp_ack_probe(struct sock *sk) * This function is not for random using! */ } else { - unsigned long when = inet_csk_rto_backoff(icsk, TCP_RTO_MAX); + unsigned long when = tcp_probe0_when(sk, TCP_RTO_MAX); inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0, when, TCP_RTO_MAX); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index a369e8a70b2c..b76c719e1979 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3490,7 +3490,7 @@ void tcp_send_probe0(struct sock *sk) probe_max = TCP_RESOURCE_PROBE_INTERVAL; } inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0, - inet_csk_rto_backoff(icsk, probe_max), + tcp_probe0_when(sk, probe_max), TCP_RTO_MAX); } -- cgit v1.2.3 From e520af48c7e5acae5f17f82a79ba7ab7cf156f3b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 6 May 2015 14:26:25 -0700 Subject: tcp: add TCPWinProbe and TCPKeepAlive SNMP counters Diagnosing problems related to Window Probes has been hard because we lack a counter. TCPWinProbe counts the number of ACK packets a sender has to send at regular intervals to make sure a reverse ACK packet opening back a window had not been lost. TCPKeepAlive counts the number of ACK packets sent to keep TCP flows alive (SO_KEEPALIVE) Signed-off-by: Eric Dumazet Signed-off-by: Yuchung Cheng Acked-by: Neal Cardwell Acked-by: Nandita Dukkipati Signed-off-by: David S. Miller --- include/net/tcp.h | 2 +- include/uapi/linux/snmp.h | 2 ++ net/ipv4/proc.c | 2 ++ net/ipv4/tcp_output.c | 13 +++++++------ net/ipv4/tcp_timer.c | 2 +- 5 files changed, 13 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index 7a2248a35b13..b8ea12880fd9 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -527,7 +527,7 @@ int tcp_fragment(struct sock *, struct sk_buff *, u32, unsigned int, gfp_t); void tcp_send_probe0(struct sock *); void tcp_send_partial(struct sock *); -int tcp_write_wakeup(struct sock *); +int tcp_write_wakeup(struct sock *, int mib); void tcp_send_fin(struct sock *sk); void tcp_send_active_reset(struct sock *sk, gfp_t priority); int tcp_send_synack(struct sock *); diff --git a/include/uapi/linux/snmp.h b/include/uapi/linux/snmp.h index 6a6fb747c78d..eee8968407f0 100644 --- a/include/uapi/linux/snmp.h +++ b/include/uapi/linux/snmp.h @@ -276,6 +276,8 @@ enum LINUX_MIB_TCPACKSKIPPEDFINWAIT2, /* TCPACKSkippedFinWait2 */ LINUX_MIB_TCPACKSKIPPEDTIMEWAIT, /* TCPACKSkippedTimeWait */ LINUX_MIB_TCPACKSKIPPEDCHALLENGE, /* TCPACKSkippedChallenge */ + LINUX_MIB_TCPWINPROBE, /* TCPWinProbe */ + LINUX_MIB_TCPKEEPALIVE, /* TCPKeepAlive */ __LINUX_MIB_MAX }; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index e1f3b911dd1e..da5d483e236a 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -298,6 +298,8 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPACKSkippedFinWait2", LINUX_MIB_TCPACKSKIPPEDFINWAIT2), SNMP_MIB_ITEM("TCPACKSkippedTimeWait", LINUX_MIB_TCPACKSKIPPEDTIMEWAIT), SNMP_MIB_ITEM("TCPACKSkippedChallenge", LINUX_MIB_TCPACKSKIPPEDCHALLENGE), + SNMP_MIB_ITEM("TCPWinProbe", LINUX_MIB_TCPWINPROBE), + SNMP_MIB_ITEM("TCPKeepAlive", LINUX_MIB_TCPKEEPALIVE), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b76c719e1979..7386d32cd670 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3382,7 +3382,7 @@ EXPORT_SYMBOL_GPL(tcp_send_ack); * one is with SEG.SEQ=SND.UNA to deliver urgent pointer, another is * out-of-date with SND.UNA-1 to probe window. */ -static int tcp_xmit_probe_skb(struct sock *sk, int urgent) +static int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib) { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; @@ -3400,6 +3400,7 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent) */ tcp_init_nondata_skb(skb, tp->snd_una - !urgent, TCPHDR_ACK); skb_mstamp_get(&skb->skb_mstamp); + NET_INC_STATS_BH(sock_net(sk), mib); return tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC); } @@ -3407,12 +3408,12 @@ void tcp_send_window_probe(struct sock *sk) { if (sk->sk_state == TCP_ESTABLISHED) { tcp_sk(sk)->snd_wl1 = tcp_sk(sk)->rcv_nxt - 1; - tcp_xmit_probe_skb(sk, 0); + tcp_xmit_probe_skb(sk, 0, LINUX_MIB_TCPWINPROBE); } } /* Initiate keepalive or window probe from timer. */ -int tcp_write_wakeup(struct sock *sk) +int tcp_write_wakeup(struct sock *sk, int mib) { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; @@ -3449,8 +3450,8 @@ int tcp_write_wakeup(struct sock *sk) return err; } else { if (between(tp->snd_up, tp->snd_una + 1, tp->snd_una + 0xFFFF)) - tcp_xmit_probe_skb(sk, 1); - return tcp_xmit_probe_skb(sk, 0); + tcp_xmit_probe_skb(sk, 1, mib); + return tcp_xmit_probe_skb(sk, 0, mib); } } @@ -3464,7 +3465,7 @@ void tcp_send_probe0(struct sock *sk) unsigned long probe_max; int err; - err = tcp_write_wakeup(sk); + err = tcp_write_wakeup(sk, LINUX_MIB_TCPWINPROBE); if (tp->packets_out || !tcp_send_head(sk)) { /* Cancel probe timer, if it is not required. */ diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 8c65dc147d8b..65bf670e8714 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -616,7 +616,7 @@ static void tcp_keepalive_timer (unsigned long data) tcp_write_err(sk); goto out; } - if (tcp_write_wakeup(sk) <= 0) { + if (tcp_write_wakeup(sk, LINUX_MIB_TCPKEEPALIVE) <= 0) { icsk->icsk_probes_out++; elapsed = keepalive_intvl_when(tp); } else { -- cgit v1.2.3 From 4ae92bc77ac8e620f7c8d59b5882a4cb0d1c4ef1 Mon Sep 17 00:00:00 2001 From: Nicolas Schichan Date: Wed, 6 May 2015 16:12:27 +0200 Subject: net: filter: add a callback to allow classic post-verifier transformations This is in preparation for use by the seccomp code, the rationale is not to duplicate additional code within the seccomp layer, but instead, have it abstracted and hidden within the classic BPF API. As an interim step, this now also makes bpf_prepare_filter() visible (not as exported symbol though), so that seccomp can reuse that code path instead of reimplementing it. Joint work with Daniel Borkmann. Signed-off-by: Nicolas Schichan Signed-off-by: Daniel Borkmann Cc: Alexei Starovoitov Cc: Kees Cook Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/filter.h | 6 ++++++ net/core/filter.c | 18 +++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/filter.h b/include/linux/filter.h index fa11b3a367be..91996247cb55 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -384,7 +384,13 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); int sk_attach_bpf(u32 ufd, struct sock *sk); int sk_detach_filter(struct sock *sk); +typedef int (*bpf_aux_classic_check_t)(struct sock_filter *filter, + unsigned int flen); + int bpf_check_classic(const struct sock_filter *filter, unsigned int flen); +struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp, + bpf_aux_classic_check_t trans); + int sk_get_filter(struct sock *sk, struct sock_filter __user *filter, unsigned int len); diff --git a/net/core/filter.c b/net/core/filter.c index bf831a85c315..e670494f1d83 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -988,7 +988,8 @@ out_err: return ERR_PTR(err); } -static struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp) +struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp, + bpf_aux_classic_check_t trans) { int err; @@ -1001,6 +1002,17 @@ static struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp) return ERR_PTR(err); } + /* There might be additional checks and transformations + * needed on classic filters, f.e. in case of seccomp. + */ + if (trans) { + err = trans(fp->insns, fp->len); + if (err) { + __bpf_prog_release(fp); + return ERR_PTR(err); + } + } + /* Probe if we can JIT compile the filter and if so, do * the compilation of the filter. */ @@ -1050,7 +1062,7 @@ int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog) /* bpf_prepare_filter() already takes care of freeing * memory in case something goes wrong. */ - fp = bpf_prepare_filter(fp); + fp = bpf_prepare_filter(fp, NULL); if (IS_ERR(fp)) return PTR_ERR(fp); @@ -1135,7 +1147,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) /* bpf_prepare_filter() already takes care of freeing * memory in case something goes wrong. */ - prog = bpf_prepare_filter(prog); + prog = bpf_prepare_filter(prog, NULL); if (IS_ERR(prog)) return PTR_ERR(prog); -- cgit v1.2.3 From d9e12f42e58da475379b9080708b94f2095904af Mon Sep 17 00:00:00 2001 From: Nicolas Schichan Date: Wed, 6 May 2015 16:12:28 +0200 Subject: seccomp: simplify seccomp_prepare_filter and reuse bpf_prepare_filter Remove the calls to bpf_check_classic(), bpf_convert_filter() and bpf_migrate_runtime() and let bpf_prepare_filter() take care of that instead. seccomp_check_filter() is passed to bpf_prepare_filter() so that it gets called from there, after bpf_check_classic(). We can now remove exposure of two internal classic BPF functions previously used by seccomp. The export of bpf_check_classic() symbol, previously known as sk_chk_filter(), was there since pre git times, and no in-tree module was using it, therefore remove it. Joint work with Daniel Borkmann. Signed-off-by: Nicolas Schichan Signed-off-by: Daniel Borkmann Cc: Alexei Starovoitov Cc: Kees Cook Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/filter.h | 4 --- kernel/seccomp.c | 68 ++++++++++++++++---------------------------------- net/core/filter.c | 8 +++--- 3 files changed, 26 insertions(+), 54 deletions(-) (limited to 'include') diff --git a/include/linux/filter.h b/include/linux/filter.h index 91996247cb55..0dcb44bcfc5f 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -363,9 +363,6 @@ int sk_filter(struct sock *sk, struct sk_buff *skb); void bpf_prog_select_runtime(struct bpf_prog *fp); void bpf_prog_free(struct bpf_prog *fp); -int bpf_convert_filter(struct sock_filter *prog, int len, - struct bpf_insn *new_prog, int *new_len); - struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags); struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size, gfp_t gfp_extra_flags); @@ -387,7 +384,6 @@ int sk_detach_filter(struct sock *sk); typedef int (*bpf_aux_classic_check_t)(struct sock_filter *filter, unsigned int flen); -int bpf_check_classic(const struct sock_filter *filter, unsigned int flen); struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp, bpf_aux_classic_check_t trans); diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 4f44028943e6..93d40f7f3683 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -347,15 +347,14 @@ static inline void seccomp_sync_threads(void) static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) { struct seccomp_filter *filter; - unsigned long fp_size; - struct sock_filter *fp; - int new_len; - long ret; + struct bpf_prog *prog; + unsigned long fsize; if (fprog->len == 0 || fprog->len > BPF_MAXINSNS) return ERR_PTR(-EINVAL); + BUG_ON(INT_MAX / fprog->len < sizeof(struct sock_filter)); - fp_size = fprog->len * sizeof(struct sock_filter); + fsize = bpf_classic_proglen(fprog); /* * Installing a seccomp filter requires that the task has @@ -368,60 +367,37 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) CAP_SYS_ADMIN) != 0) return ERR_PTR(-EACCES); - fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN); - if (!fp) + prog = bpf_prog_alloc(bpf_prog_size(fprog->len), 0); + if (!prog) return ERR_PTR(-ENOMEM); /* Copy the instructions from fprog. */ - ret = -EFAULT; - if (copy_from_user(fp, fprog->filter, fp_size)) - goto free_prog; - - /* Check and rewrite the fprog via the skb checker */ - ret = bpf_check_classic(fp, fprog->len); - if (ret) - goto free_prog; + if (copy_from_user(prog->insns, fprog->filter, fsize)) { + __bpf_prog_free(prog); + return ERR_PTR(-EFAULT); + } - /* Check and rewrite the fprog for seccomp use */ - ret = seccomp_check_filter(fp, fprog->len); - if (ret) - goto free_prog; + prog->len = fprog->len; - /* Convert 'sock_filter' insns to 'bpf_insn' insns */ - ret = bpf_convert_filter(fp, fprog->len, NULL, &new_len); - if (ret) - goto free_prog; + /* bpf_prepare_filter() already takes care of freeing + * memory in case something goes wrong. + */ + prog = bpf_prepare_filter(prog, seccomp_check_filter); + if (IS_ERR(prog)) + return ERR_CAST(prog); /* Allocate a new seccomp_filter */ - ret = -ENOMEM; filter = kzalloc(sizeof(struct seccomp_filter), GFP_KERNEL|__GFP_NOWARN); - if (!filter) - goto free_prog; - - filter->prog = bpf_prog_alloc(bpf_prog_size(new_len), __GFP_NOWARN); - if (!filter->prog) - goto free_filter; - - ret = bpf_convert_filter(fp, fprog->len, filter->prog->insnsi, &new_len); - if (ret) - goto free_filter_prog; + if (!filter) { + bpf_prog_destroy(prog); + return ERR_PTR(-ENOMEM); + } - kfree(fp); + filter->prog = prog; atomic_set(&filter->usage, 1); - filter->prog->len = new_len; - - bpf_prog_select_runtime(filter->prog); return filter; - -free_filter_prog: - __bpf_prog_free(filter->prog); -free_filter: - kfree(filter); -free_prog: - kfree(fp); - return ERR_PTR(ret); } /** diff --git a/net/core/filter.c b/net/core/filter.c index e670494f1d83..f887084740cd 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -355,8 +355,8 @@ static bool convert_bpf_extensions(struct sock_filter *fp, * for socket filters: ctx == 'struct sk_buff *', for seccomp: * ctx == 'struct seccomp_data *'. */ -int bpf_convert_filter(struct sock_filter *prog, int len, - struct bpf_insn *new_prog, int *new_len) +static int bpf_convert_filter(struct sock_filter *prog, int len, + struct bpf_insn *new_prog, int *new_len) { int new_flen = 0, pass = 0, target, i; struct bpf_insn *new_insn; @@ -751,7 +751,8 @@ static bool chk_code_allowed(u16 code_to_probe) * * Returns 0 if the rule set is legal or -EINVAL if not. */ -int bpf_check_classic(const struct sock_filter *filter, unsigned int flen) +static int bpf_check_classic(const struct sock_filter *filter, + unsigned int flen) { bool anc_found; int pc; @@ -825,7 +826,6 @@ int bpf_check_classic(const struct sock_filter *filter, unsigned int flen) return -EINVAL; } -EXPORT_SYMBOL(bpf_check_classic); static int bpf_prog_store_orig_filter(struct bpf_prog *fp, const struct sock_fprog *fprog) -- cgit v1.2.3 From ac67eb2c5347bd9976308c0e0cf1d9e7ca690342 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 6 May 2015 16:12:30 +0200 Subject: seccomp, filter: add and use bpf_prog_create_from_user from seccomp Seccomp has always been a special candidate when it comes to preparation of its filters in seccomp_prepare_filter(). Due to the extra checks and filter rewrite it partially duplicates code and has BPF internals exposed. This patch adds a generic API inside the BPF code code that seccomp can use and thus keep it's filter preparation code minimal and better maintainable. The other side-effect is that now classic JITs can add seccomp support as well by only providing a BPF_LDX | BPF_W | BPF_ABS translation. Tested with seccomp and BPF test suites. Signed-off-by: Daniel Borkmann Cc: Nicolas Schichan Cc: Alexei Starovoitov Cc: Kees Cook Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/filter.h | 12 +++++------- kernel/seccomp.c | 42 ++++++++++++----------------------------- net/core/filter.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 66 insertions(+), 39 deletions(-) (limited to 'include') diff --git a/include/linux/filter.h b/include/linux/filter.h index 0dcb44bcfc5f..3c03a6085b82 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -374,19 +374,17 @@ static inline void bpf_prog_unlock_free(struct bpf_prog *fp) __bpf_prog_free(fp); } +typedef int (*bpf_aux_classic_check_t)(struct sock_filter *filter, + unsigned int flen); + int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog); +int bpf_prog_create_from_user(struct bpf_prog **pfp, struct sock_fprog *fprog, + bpf_aux_classic_check_t trans); void bpf_prog_destroy(struct bpf_prog *fp); int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); int sk_attach_bpf(u32 ufd, struct sock *sk); int sk_detach_filter(struct sock *sk); - -typedef int (*bpf_aux_classic_check_t)(struct sock_filter *filter, - unsigned int flen); - -struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp, - bpf_aux_classic_check_t trans); - int sk_get_filter(struct sock *sk, struct sock_filter __user *filter, unsigned int len); diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 93d40f7f3683..245df6b32b81 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -346,15 +346,13 @@ static inline void seccomp_sync_threads(void) */ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) { - struct seccomp_filter *filter; - struct bpf_prog *prog; - unsigned long fsize; + struct seccomp_filter *sfilter; + int ret; if (fprog->len == 0 || fprog->len > BPF_MAXINSNS) return ERR_PTR(-EINVAL); BUG_ON(INT_MAX / fprog->len < sizeof(struct sock_filter)); - fsize = bpf_classic_proglen(fprog); /* * Installing a seccomp filter requires that the task has @@ -367,37 +365,21 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) CAP_SYS_ADMIN) != 0) return ERR_PTR(-EACCES); - prog = bpf_prog_alloc(bpf_prog_size(fprog->len), 0); - if (!prog) - return ERR_PTR(-ENOMEM); - - /* Copy the instructions from fprog. */ - if (copy_from_user(prog->insns, fprog->filter, fsize)) { - __bpf_prog_free(prog); - return ERR_PTR(-EFAULT); - } - - prog->len = fprog->len; - - /* bpf_prepare_filter() already takes care of freeing - * memory in case something goes wrong. - */ - prog = bpf_prepare_filter(prog, seccomp_check_filter); - if (IS_ERR(prog)) - return ERR_CAST(prog); - /* Allocate a new seccomp_filter */ - filter = kzalloc(sizeof(struct seccomp_filter), - GFP_KERNEL|__GFP_NOWARN); - if (!filter) { - bpf_prog_destroy(prog); + sfilter = kzalloc(sizeof(*sfilter), GFP_KERNEL | __GFP_NOWARN); + if (!sfilter) return ERR_PTR(-ENOMEM); + + ret = bpf_prog_create_from_user(&sfilter->prog, fprog, + seccomp_check_filter); + if (ret < 0) { + kfree(sfilter); + return ERR_PTR(ret); } - filter->prog = prog; - atomic_set(&filter->usage, 1); + atomic_set(&sfilter->usage, 1); - return filter; + return sfilter; } /** diff --git a/net/core/filter.c b/net/core/filter.c index 45c015d6b974..a831f193e2c7 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -991,8 +991,8 @@ out_err: return ERR_PTR(err); } -struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp, - bpf_aux_classic_check_t trans) +static struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp, + bpf_aux_classic_check_t trans) { int err; @@ -1074,6 +1074,53 @@ int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog) } EXPORT_SYMBOL_GPL(bpf_prog_create); +/** + * bpf_prog_create_from_user - create an unattached filter from user buffer + * @pfp: the unattached filter that is created + * @fprog: the filter program + * @trans: post-classic verifier transformation handler + * + * This function effectively does the same as bpf_prog_create(), only + * that it builds up its insns buffer from user space provided buffer. + * It also allows for passing a bpf_aux_classic_check_t handler. + */ +int bpf_prog_create_from_user(struct bpf_prog **pfp, struct sock_fprog *fprog, + bpf_aux_classic_check_t trans) +{ + unsigned int fsize = bpf_classic_proglen(fprog); + struct bpf_prog *fp; + + /* Make sure new filter is there and in the right amounts. */ + if (fprog->filter == NULL) + return -EINVAL; + + fp = bpf_prog_alloc(bpf_prog_size(fprog->len), 0); + if (!fp) + return -ENOMEM; + + if (copy_from_user(fp->insns, fprog->filter, fsize)) { + __bpf_prog_free(fp); + return -EFAULT; + } + + fp->len = fprog->len; + /* Since unattached filters are not copied back to user + * space through sk_get_filter(), we do not need to hold + * a copy here, and can spare us the work. + */ + fp->orig_prog = NULL; + + /* bpf_prepare_filter() already takes care of freeing + * memory in case something goes wrong. + */ + fp = bpf_prepare_filter(fp, trans); + if (IS_ERR(fp)) + return PTR_ERR(fp); + + *pfp = fp; + return 0; +} + void bpf_prog_destroy(struct bpf_prog *fp) { __bpf_prog_release(fp); -- cgit v1.2.3 From 7a0877d4b438886b72be61632eaa774d13262f70 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 7 May 2015 11:02:49 +0200 Subject: netns: rename peernet2id() to peernet2id_alloc() In a following commit, a new function will be introduced to only lookup for a nsid (no allocation if the nsid doesn't exist). To avoid confusion, the existing function is renamed. Signed-off-by: Nicolas Dichtel Acked-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 2 +- include/net/net_namespace.h | 2 +- net/core/net_namespace.c | 4 ++-- net/core/rtnetlink.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 3517ab0aa803..48341ae49012 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -336,7 +336,7 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, if (!net_eq(dev_net(vxlan->dev), vxlan->net) && nla_put_s32(skb, NDA_LINK_NETNSID, - peernet2id(dev_net(vxlan->dev), vxlan->net))) + peernet2id_alloc(dev_net(vxlan->dev), vxlan->net))) goto nla_put_failure; if (send_eth && nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->eth_addr)) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index f733656404de..6d1e2eae32fb 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -271,7 +271,7 @@ static inline struct net *read_pnet(const possible_net_t *pnet) #define __net_initconst __initconst #endif -int peernet2id(struct net *net, struct net *peer); +int peernet2id_alloc(struct net *net, struct net *peer); struct net *get_net_ns_by_id(struct net *net, int id); struct pernet_operations { diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 37c68bb72db3..9c806ac569f9 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -202,13 +202,13 @@ static int __peernet2id(struct net *net, struct net *peer, bool alloc) /* This function returns the id of a peer netns. If no id is assigned, one will * be allocated and returned. */ -int peernet2id(struct net *net, struct net *peer) +int peernet2id_alloc(struct net *net, struct net *peer) { bool alloc = atomic_read(&peer->count) == 0 ? false : true; return __peernet2id(net, peer, alloc); } -EXPORT_SYMBOL(peernet2id); +EXPORT_SYMBOL(peernet2id_alloc); struct net *get_net_ns_by_id(struct net *net, int id) { diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 666e0928ba40..83e08323fdcd 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1204,7 +1204,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, struct net *link_net = dev->rtnl_link_ops->get_link_net(dev); if (!net_eq(dev_net(dev), link_net)) { - int id = peernet2id(dev_net(dev), link_net); + int id = peernet2id_alloc(dev_net(dev), link_net); if (nla_put_s32(skb, IFLA_LINK_NETNSID, id)) goto nla_put_failure; -- cgit v1.2.3 From 59324cf35aba5336b611074028777838a963d03b Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 7 May 2015 11:02:53 +0200 Subject: netlink: allow to listen "all" netns More accurately, listen all netns that have a nsid assigned into the netns where the netlink socket is opened. For this purpose, a netlink socket option is added: NETLINK_LISTEN_ALL_NSID. When this option is set on a netlink socket, this socket will receive netlink notifications from all netns that have a nsid assigned into the netns where the socket has been opened. The nsid is sent to userland via an anscillary data. With this patch, a daemon needs only one socket to listen many netns. This is useful when the number of netns is high. Because 0 is a valid value for a nsid, the field nsid_is_set indicates if the field nsid is valid or not. skb->cb is initialized to 0 on skb allocation, thus we are sure that we will never send a nsid 0 by error to the userland. Signed-off-by: Nicolas Dichtel Acked-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/netlink.h | 2 ++ include/net/net_namespace.h | 2 ++ include/uapi/linux/netlink.h | 1 + net/core/net_namespace.c | 10 ++++++++- net/netlink/af_netlink.c | 52 +++++++++++++++++++++++++++++++++++++++----- 5 files changed, 61 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 6835c1279df7..9120edb650a0 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -28,6 +28,8 @@ struct netlink_skb_parms { __u32 dst_group; __u32 flags; struct sock *sk; + bool nsid_is_set; + int nsid; }; #define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb)) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 6d1e2eae32fb..3f850acc844e 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -272,6 +272,8 @@ static inline struct net *read_pnet(const possible_net_t *pnet) #endif int peernet2id_alloc(struct net *net, struct net *peer); +int peernet2id(struct net *net, struct net *peer); +bool peernet_has_id(struct net *net, struct net *peer); struct net *get_net_ns_by_id(struct net *net, int id); struct pernet_operations { diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h index 1a85940f8ab7..3e34b7d702f8 100644 --- a/include/uapi/linux/netlink.h +++ b/include/uapi/linux/netlink.h @@ -108,6 +108,7 @@ struct nlmsgerr { #define NETLINK_NO_ENOBUFS 5 #define NETLINK_RX_RING 6 #define NETLINK_TX_RING 7 +#define NETLINK_LISTEN_ALL_NSID 8 struct nl_pktinfo { __u32 group; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index ae5008b097de..a665bf490c88 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -229,7 +229,7 @@ int peernet2id_alloc(struct net *net, struct net *peer) EXPORT_SYMBOL(peernet2id_alloc); /* This function returns, if assigned, the id of a peer netns. */ -static int peernet2id(struct net *net, struct net *peer) +int peernet2id(struct net *net, struct net *peer) { unsigned long flags; int id; @@ -240,6 +240,14 @@ static int peernet2id(struct net *net, struct net *peer) return id; } +/* This function returns true is the peer netns has an id assigned into the + * current netns. + */ +bool peernet_has_id(struct net *net, struct net *peer) +{ + return peernet2id(net, peer) >= 0; +} + struct net *get_net_ns_by_id(struct net *net, int id) { unsigned long flags; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index bf7f56d7a9aa..a5fff75accf8 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -83,6 +83,7 @@ struct listeners { #define NETLINK_F_RECV_PKTINFO 0x2 #define NETLINK_F_BROADCAST_SEND_ERROR 0x4 #define NETLINK_F_RECV_NO_ENOBUFS 0x8 +#define NETLINK_F_LISTEN_ALL_NSID 0x10 static inline int netlink_is_kernel(struct sock *sk) { @@ -1932,8 +1933,17 @@ static void do_one_broadcast(struct sock *sk, !test_bit(p->group - 1, nlk->groups)) return; - if (!net_eq(sock_net(sk), p->net)) - return; + if (!net_eq(sock_net(sk), p->net)) { + if (!(nlk->flags & NETLINK_F_LISTEN_ALL_NSID)) + return; + + if (!peernet_has_id(sock_net(sk), p->net)) + return; + + if (!file_ns_capable(sk->sk_socket->file, p->net->user_ns, + CAP_NET_BROADCAST)) + return; + } if (p->failure) { netlink_overrun(sk); @@ -1959,13 +1969,22 @@ static void do_one_broadcast(struct sock *sk, p->failure = 1; if (nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR) p->delivery_failure = 1; - } else if (p->tx_filter && p->tx_filter(sk, p->skb2, p->tx_data)) { + goto out; + } + if (p->tx_filter && p->tx_filter(sk, p->skb2, p->tx_data)) { kfree_skb(p->skb2); p->skb2 = NULL; - } else if (sk_filter(sk, p->skb2)) { + goto out; + } + if (sk_filter(sk, p->skb2)) { kfree_skb(p->skb2); p->skb2 = NULL; - } else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) { + goto out; + } + NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); + NETLINK_CB(p->skb2).nsid_is_set = true; + val = netlink_broadcast_deliver(sk, p->skb2); + if (val < 0) { netlink_overrun(sk); if (nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR) p->delivery_failure = 1; @@ -1974,6 +1993,7 @@ static void do_one_broadcast(struct sock *sk, p->delivered = 1; p->skb2 = NULL; } +out: sock_put(sk); } @@ -2202,6 +2222,16 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, break; } #endif /* CONFIG_NETLINK_MMAP */ + case NETLINK_LISTEN_ALL_NSID: + if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_BROADCAST)) + return -EPERM; + + if (val) + nlk->flags |= NETLINK_F_LISTEN_ALL_NSID; + else + nlk->flags &= ~NETLINK_F_LISTEN_ALL_NSID; + err = 0; + break; default: err = -ENOPROTOOPT; } @@ -2268,6 +2298,16 @@ static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info); } +static void netlink_cmsg_listen_all_nsid(struct sock *sk, struct msghdr *msg, + struct sk_buff *skb) +{ + if (!NETLINK_CB(skb).nsid_is_set) + return; + + put_cmsg(msg, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, sizeof(int), + &NETLINK_CB(skb).nsid); +} + static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; @@ -2421,6 +2461,8 @@ static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, if (nlk->flags & NETLINK_F_RECV_PKTINFO) netlink_cmsg_recv_pktinfo(msg, skb); + if (nlk->flags & NETLINK_F_LISTEN_ALL_NSID) + netlink_cmsg_listen_all_nsid(sk, msg, skb); memset(&scm, 0, sizeof(scm)); scm.creds = *NETLINK_CREDS(skb); -- cgit v1.2.3 From 78f5b899195019f71f7593c604d75ca61658eae3 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 7 May 2015 08:08:51 -0700 Subject: mpls: Change reserved label names to be consistent with netbsd Since these are now visible to userspace it is nice to be consistent with BSD (sys/netmpls/mpls.h in netBSD). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/uapi/linux/mpls.h | 12 ++++++------ net/mpls/af_mpls.c | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/mpls.h b/include/uapi/linux/mpls.h index 0fe6ea5a41d5..139d4dd1cab8 100644 --- a/include/uapi/linux/mpls.h +++ b/include/uapi/linux/mpls.h @@ -32,13 +32,13 @@ struct mpls_label { #define MPLS_LS_TTL_SHIFT 0 /* Reserved labels */ -#define MPLS_LABEL_IPV4_EXPLICIT_NULL 0 /* RFC3032 */ -#define MPLS_LABEL_ROUTER_ALERT 1 /* RFC3032 */ -#define MPLS_LABEL_IPV6_EXPLICIT_NULL 2 /* RFC3032 */ -#define MPLS_LABEL_IMPLICIT_NULL 3 /* RFC3032 */ -#define MPLS_LABEL_ENTROPY_INDICATOR 7 /* RFC6790 */ +#define MPLS_LABEL_IPV4NULL 0 /* RFC3032 */ +#define MPLS_LABEL_RTALERT 1 /* RFC3032 */ +#define MPLS_LABEL_IPV6NULL 2 /* RFC3032 */ +#define MPLS_LABEL_IMPLNULL 3 /* RFC3032 */ +#define MPLS_LABEL_ENTROPY 7 /* RFC6790 */ #define MPLS_LABEL_GAL 13 /* RFC5586 */ -#define MPLS_LABEL_OAM_ALERT 14 /* RFC3429 */ +#define MPLS_LABEL_OAMALERT 14 /* RFC3429 */ #define MPLS_LABEL_EXTENSION 15 /* RFC7274 */ #endif /* _UAPI_MPLS_H */ diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index b6eb7615960a..7b3f732269e4 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -647,7 +647,7 @@ int nla_get_labels(const struct nlattr *nla, return -EINVAL; switch (dec.label) { - case MPLS_LABEL_IMPLICIT_NULL: + case MPLS_LABEL_IMPLNULL: /* RFC3032: This is a label that an LSR may * assign and distribute, but which never * actually appears in the encapsulation. @@ -935,7 +935,7 @@ static int resize_platform_label_table(struct net *net, size_t limit) } /* In case the predefined labels need to be populated */ - if (limit > MPLS_LABEL_IPV4_EXPLICIT_NULL) { + if (limit > MPLS_LABEL_IPV4NULL) { struct net_device *lo = net->loopback_dev; rt0 = mpls_rt_alloc(lo->addr_len); if (!rt0) @@ -945,7 +945,7 @@ static int resize_platform_label_table(struct net *net, size_t limit) rt0->rt_via_table = NEIGH_LINK_TABLE; memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len); } - if (limit > MPLS_LABEL_IPV6_EXPLICIT_NULL) { + if (limit > MPLS_LABEL_IPV6NULL) { struct net_device *lo = net->loopback_dev; rt2 = mpls_rt_alloc(lo->addr_len); if (!rt2) @@ -973,15 +973,15 @@ static int resize_platform_label_table(struct net *net, size_t limit) memcpy(labels, old, cp_size); /* If needed set the predefined labels */ - if ((old_limit <= MPLS_LABEL_IPV6_EXPLICIT_NULL) && - (limit > MPLS_LABEL_IPV6_EXPLICIT_NULL)) { - RCU_INIT_POINTER(labels[MPLS_LABEL_IPV6_EXPLICIT_NULL], rt2); + if ((old_limit <= MPLS_LABEL_IPV6NULL) && + (limit > MPLS_LABEL_IPV6NULL)) { + RCU_INIT_POINTER(labels[MPLS_LABEL_IPV6NULL], rt2); rt2 = NULL; } - if ((old_limit <= MPLS_LABEL_IPV4_EXPLICIT_NULL) && - (limit > MPLS_LABEL_IPV4_EXPLICIT_NULL)) { - RCU_INIT_POINTER(labels[MPLS_LABEL_IPV4_EXPLICIT_NULL], rt0); + if ((old_limit <= MPLS_LABEL_IPV4NULL) && + (limit > MPLS_LABEL_IPV4NULL)) { + RCU_INIT_POINTER(labels[MPLS_LABEL_IPV4NULL], rt0); rt0 = NULL; } -- cgit v1.2.3 From 1a48632ffed61352a7810ce089dc5a8bcd505a60 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 13 Apr 2015 13:24:34 -0400 Subject: pty: Fix input race when closing A read() from a pty master may mistakenly indicate EOF (errno == -EIO) after the pty slave has closed, even though input data remains to be read. For example, pty slave | input worker | pty master | | | | n_tty_read() pty_write() | | input avail? no add data | | sleep schedule worker --->| | . |---> flush_to_ldisc() | . pty_close() | fill read buffer | . wait for worker | wakeup reader --->| . | read buffer full? |---> input avail ? yes |<--- yes - exit worker | copy 4096 bytes to user TTY_OTHER_CLOSED <---| |<--- kick worker | | **** New read() before worker starts **** | | n_tty_read() | | input avail? no | | TTY_OTHER_CLOSED? yes | | return -EIO Several conditions are required to trigger this race: 1. the ldisc read buffer must become full so the input worker exits 2. the read() count parameter must be >= 4096 so the ldisc read buffer is empty 3. the subsequent read() occurs before the kicked worker has processed more input However, the underlying cause of the race is that data is pipelined, while tty state is not; ie., data already written by the pty slave end is not yet visible to the pty master end, but state changes by the pty slave end are visible to the pty master end immediately. Pipeline the TTY_OTHER_CLOSED state through input worker to the reader. 1. Introduce TTY_OTHER_DONE which is set by the input worker when TTY_OTHER_CLOSED is set and either the input buffers are flushed or input processing has completed. Readers/polls are woken when TTY_OTHER_DONE is set. 2. Reader/poll checks TTY_OTHER_DONE instead of TTY_OTHER_CLOSED. 3. A new input worker is started from pty_close() after setting TTY_OTHER_CLOSED, which ensures the TTY_OTHER_DONE state will be set if the last input worker is already finished (or just about to exit). Remove tty_flush_to_ldisc(); no in-tree callers. Fixes: 52bce7f8d4fc ("pty, n_tty: Simplify input processing on final close") Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=96311 BugLink: http://bugs.launchpad.net/bugs/1429756 Cc: # 3.19+ Reported-by: Andy Whitcroft Reported-by: H.J. Lu Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- Documentation/serial/tty.txt | 3 +++ drivers/tty/n_hdlc.c | 4 ++-- drivers/tty/n_tty.c | 22 ++++++++++++++++++---- drivers/tty/pty.c | 5 +++-- drivers/tty/tty_buffer.c | 41 +++++++++++++++++++++++++++-------------- include/linux/tty.h | 2 +- 6 files changed, 54 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/Documentation/serial/tty.txt b/Documentation/serial/tty.txt index 1e52d67d0abf..dbe6623fed1c 100644 --- a/Documentation/serial/tty.txt +++ b/Documentation/serial/tty.txt @@ -198,6 +198,9 @@ TTY_IO_ERROR If set, causes all subsequent userspace read/write TTY_OTHER_CLOSED Device is a pty and the other side has closed. +TTY_OTHER_DONE Device is a pty and the other side has closed and + all pending input processing has been completed. + TTY_NO_WRITE_SPLIT Prevent driver from splitting up writes into smaller chunks. diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 644ddb841d9f..bbc4ce66c2c1 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -600,7 +600,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, add_wait_queue(&tty->read_wait, &wait); for (;;) { - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { + if (test_bit(TTY_OTHER_DONE, &tty->flags)) { ret = -EIO; break; } @@ -828,7 +828,7 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, /* set bits for operations that won't block */ if (n_hdlc->rx_buf_list.head) mask |= POLLIN | POLLRDNORM; /* readable */ - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) + if (test_bit(TTY_OTHER_DONE, &tty->flags)) mask |= POLLHUP; if (tty_hung_up_p(filp)) mask |= POLLHUP; diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index cf6e0f2e1331..cc57a3a6b02b 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1949,6 +1949,18 @@ static inline int input_available_p(struct tty_struct *tty, int poll) return ldata->commit_head - ldata->read_tail >= amt; } +static inline int check_other_done(struct tty_struct *tty) +{ + int done = test_bit(TTY_OTHER_DONE, &tty->flags); + if (done) { + /* paired with cmpxchg() in check_other_closed(); ensures + * read buffer head index is not stale + */ + smp_mb__after_atomic(); + } + return done; +} + /** * copy_from_read_buf - copy read data directly * @tty: terminal device @@ -2167,7 +2179,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, struct n_tty_data *ldata = tty->disc_data; unsigned char __user *b = buf; DEFINE_WAIT_FUNC(wait, woken_wake_function); - int c; + int c, done; int minimum, time; ssize_t retval = 0; long timeout; @@ -2235,8 +2247,10 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, ((minimum - (b - buf)) >= 1)) ldata->minimum_to_wake = (minimum - (b - buf)); + done = check_other_done(tty); + if (!input_available_p(tty, 0)) { - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { + if (done) { retval = -EIO; break; } @@ -2443,12 +2457,12 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, poll_wait(file, &tty->read_wait, wait); poll_wait(file, &tty->write_wait, wait); + if (check_other_done(tty)) + mask |= POLLHUP; if (input_available_p(tty, 1)) mask |= POLLIN | POLLRDNORM; if (tty->packet && tty->link->ctrl_status) mask |= POLLPRI | POLLIN | POLLRDNORM; - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) - mask |= POLLHUP; if (tty_hung_up_p(file)) mask |= POLLHUP; if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) { diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index e72ee629cead..4d5e8409769c 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -53,9 +53,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp) /* Review - krefs on tty_link ?? */ if (!tty->link) return; - tty_flush_to_ldisc(tty->link); set_bit(TTY_OTHER_CLOSED, &tty->link->flags); - wake_up_interruptible(&tty->link->read_wait); + tty_flip_buffer_push(tty->link->port); wake_up_interruptible(&tty->link->write_wait); if (tty->driver->subtype == PTY_TYPE_MASTER) { set_bit(TTY_OTHER_CLOSED, &tty->flags); @@ -243,7 +242,9 @@ static int pty_open(struct tty_struct *tty, struct file *filp) goto out; clear_bit(TTY_IO_ERROR, &tty->flags); + /* TTY_OTHER_CLOSED must be cleared before TTY_OTHER_DONE */ clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); + clear_bit(TTY_OTHER_DONE, &tty->link->flags); set_bit(TTY_THROTTLED, &tty->flags); return 0; diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 75661641f5fe..2f78b77f0f81 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -37,6 +37,28 @@ #define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF) +/* + * If all tty flip buffers have been processed by flush_to_ldisc() or + * dropped by tty_buffer_flush(), check if the linked pty has been closed. + * If so, wake the reader/poll to process + */ +static inline void check_other_closed(struct tty_struct *tty) +{ + unsigned long flags, old; + + /* transition from TTY_OTHER_CLOSED => TTY_OTHER_DONE must be atomic */ + for (flags = ACCESS_ONCE(tty->flags); + test_bit(TTY_OTHER_CLOSED, &flags); + ) { + old = flags; + __set_bit(TTY_OTHER_DONE, &flags); + flags = cmpxchg(&tty->flags, old, flags); + if (old == flags) { + wake_up_interruptible(&tty->read_wait); + break; + } + } +} /** * tty_buffer_lock_exclusive - gain exclusive access to buffer @@ -229,6 +251,8 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) if (ld && ld->ops->flush_buffer) ld->ops->flush_buffer(tty); + check_other_closed(tty); + atomic_dec(&buf->priority); mutex_unlock(&buf->lock); } @@ -471,8 +495,10 @@ static void flush_to_ldisc(struct work_struct *work) smp_rmb(); count = head->commit - head->read; if (!count) { - if (next == NULL) + if (next == NULL) { + check_other_closed(tty); break; + } buf->head = next; tty_buffer_free(port, head); continue; @@ -488,19 +514,6 @@ static void flush_to_ldisc(struct work_struct *work) tty_ldisc_deref(disc); } -/** - * tty_flush_to_ldisc - * @tty: tty to push - * - * Push the terminal flip buffers to the line discipline. - * - * Must not be called from IRQ context. - */ -void tty_flush_to_ldisc(struct tty_struct *tty) -{ - flush_work(&tty->port->buf.work); -} - /** * tty_flip_buffer_push - terminal * @port: tty port to push diff --git a/include/linux/tty.h b/include/linux/tty.h index fe5623c9af71..d76631f615c2 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -339,6 +339,7 @@ struct tty_file_private { #define TTY_EXCLUSIVE 3 /* Exclusive open mode */ #define TTY_DEBUG 4 /* Debugging */ #define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */ +#define TTY_OTHER_DONE 6 /* Closed pty has completed input processing */ #define TTY_LDISC_OPEN 11 /* Line discipline is open */ #define TTY_PTY_LOCK 16 /* pty private */ #define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */ @@ -462,7 +463,6 @@ extern int tty_hung_up_p(struct file *filp); extern void do_SAK(struct tty_struct *tty); extern void __do_SAK(struct tty_struct *tty); extern void no_tty(void); -extern void tty_flush_to_ldisc(struct tty_struct *tty); extern void tty_buffer_free_all(struct tty_port *port); extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld); extern void tty_buffer_init(struct tty_port *port); -- cgit v1.2.3 From 80ba92fa1a92dea128283f69f55b02242e213650 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 8 May 2015 15:05:12 -0700 Subject: codel: add ce_threshold attribute For DCTCP or similar ECN based deployments on fabrics with shallow buffers, hosts are responsible for a good part of the buffering. This patch adds an optional ce_threshold to codel & fq_codel qdiscs, so that DCTCP can have feedback from queuing in the host. A DCTCP enabled egress port simply have a queue occupancy threshold above which ECT packets get CE mark. In codel language this translates to a sojourn time, so that one doesn't have to worry about bytes or bandwidth but delays. This makes the host an active participant in the health of the whole network. This also helps experimenting DCTCP in a setup without DCTCP compliant fabric. On following example, ce_threshold is set to 1ms, and we can see from 'ldelay xxx us' that TCP is not trying to go around the 5ms codel target. Queue has more capacity to absorb inelastic bursts (say from UDP traffic), as queues are maintained to an optimal level. lpaa23:~# ./tc -s -d qd sh dev eth1 qdisc mq 1: dev eth1 root Sent 87910654696 bytes 58065331 pkt (dropped 0, overlimits 0 requeues 42961) backlog 3108242b 364p requeues 42961 qdisc codel 8063: dev eth1 parent 1:1 limit 1000p target 5.0ms ce_threshold 1.0ms interval 100.0ms Sent 7363778701 bytes 4863809 pkt (dropped 0, overlimits 0 requeues 5503) rate 2348Mbit 193919pps backlog 255866b 46p requeues 5503 count 0 lastcount 0 ldelay 1.0ms drop_next 0us maxpacket 68130 ecn_mark 0 drop_overlimit 0 ce_mark 72384 qdisc codel 8064: dev eth1 parent 1:2 limit 1000p target 5.0ms ce_threshold 1.0ms interval 100.0ms Sent 7636486190 bytes 5043942 pkt (dropped 0, overlimits 0 requeues 5186) rate 2319Mbit 191538pps backlog 207418b 64p requeues 5186 count 0 lastcount 0 ldelay 694us drop_next 0us maxpacket 68130 ecn_mark 0 drop_overlimit 0 ce_mark 69873 qdisc codel 8065: dev eth1 parent 1:3 limit 1000p target 5.0ms ce_threshold 1.0ms interval 100.0ms Sent 11569360142 bytes 7641602 pkt (dropped 0, overlimits 0 requeues 5554) rate 3041Mbit 251096pps backlog 210446b 59p requeues 5554 count 0 lastcount 0 ldelay 889us drop_next 0us maxpacket 68130 ecn_mark 0 drop_overlimit 0 ce_mark 37780 ... Signed-off-by: Eric Dumazet Cc: Florian Westphal Cc: Daniel Borkmann Cc: Glenn Judd Cc: Nandita Dukkipati Cc: Neal Cardwell Cc: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: David S. Miller --- include/net/codel.h | 12 +++++++++++- include/uapi/linux/pkt_sched.h | 4 ++++ net/sched/sch_codel.c | 15 +++++++++++++-- net/sched/sch_fq_codel.c | 15 ++++++++++++++- 4 files changed, 42 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/net/codel.h b/include/net/codel.h index aeee28081245..8c0f78f209e8 100644 --- a/include/net/codel.h +++ b/include/net/codel.h @@ -7,7 +7,7 @@ * Copyright (C) 2011-2012 Kathleen Nichols * Copyright (C) 2011-2012 Van Jacobson * Copyright (C) 2012 Michael D. Taht - * Copyright (C) 2012 Eric Dumazet + * Copyright (C) 2012,2015 Eric Dumazet * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -119,11 +119,13 @@ static inline u32 codel_time_to_us(codel_time_t val) /** * struct codel_params - contains codel parameters * @target: target queue size (in time units) + * @ce_threshold: threshold for marking packets with ECN CE * @interval: width of moving time window * @ecn: is Explicit Congestion Notification enabled */ struct codel_params { codel_time_t target; + codel_time_t ce_threshold; codel_time_t interval; bool ecn; }; @@ -159,17 +161,22 @@ struct codel_vars { * @maxpacket: largest packet we've seen so far * @drop_count: temp count of dropped packets in dequeue() * ecn_mark: number of packets we ECN marked instead of dropping + * ce_mark: number of packets CE marked because sojourn time was above ce_threshold */ struct codel_stats { u32 maxpacket; u32 drop_count; u32 ecn_mark; + u32 ce_mark; }; +#define CODEL_DISABLED_THRESHOLD INT_MAX + static void codel_params_init(struct codel_params *params) { params->interval = MS2TIME(100); params->target = MS2TIME(5); + params->ce_threshold = CODEL_DISABLED_THRESHOLD; params->ecn = false; } @@ -350,6 +357,9 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch, vars->rec_inv_sqrt); } end: + if (skb && codel_time_after(vars->ldelay, params->ce_threshold) && + INET_ECN_set_ce(skb)) + stats->ce_mark++; return skb; } #endif diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h index 534b84710745..69d88b309cc7 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -679,6 +679,7 @@ enum { TCA_CODEL_LIMIT, TCA_CODEL_INTERVAL, TCA_CODEL_ECN, + TCA_CODEL_CE_THRESHOLD, __TCA_CODEL_MAX }; @@ -695,6 +696,7 @@ struct tc_codel_xstats { __u32 drop_overlimit; /* number of time max qdisc packet limit was hit */ __u32 ecn_mark; /* number of packets we ECN marked instead of dropped */ __u32 dropping; /* are we in dropping state ? */ + __u32 ce_mark; /* number of CE marked packets because of ce_threshold */ }; /* FQ_CODEL */ @@ -707,6 +709,7 @@ enum { TCA_FQ_CODEL_ECN, TCA_FQ_CODEL_FLOWS, TCA_FQ_CODEL_QUANTUM, + TCA_FQ_CODEL_CE_THRESHOLD, __TCA_FQ_CODEL_MAX }; @@ -730,6 +733,7 @@ struct tc_fq_codel_qd_stats { */ __u32 new_flows_len; /* count of flows in new list */ __u32 old_flows_len; /* count of flows in old list */ + __u32 ce_mark; /* packets above ce_threshold */ }; struct tc_fq_codel_cl_stats { diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c index de28f8e968e8..1474b6560fac 100644 --- a/net/sched/sch_codel.c +++ b/net/sched/sch_codel.c @@ -6,7 +6,7 @@ * * Implemented on linux by : * Copyright (C) 2012 Michael D. Taht - * Copyright (C) 2012 Eric Dumazet + * Copyright (C) 2012,2015 Eric Dumazet * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -109,6 +109,7 @@ static const struct nla_policy codel_policy[TCA_CODEL_MAX + 1] = { [TCA_CODEL_LIMIT] = { .type = NLA_U32 }, [TCA_CODEL_INTERVAL] = { .type = NLA_U32 }, [TCA_CODEL_ECN] = { .type = NLA_U32 }, + [TCA_CODEL_CE_THRESHOLD]= { .type = NLA_U32 }, }; static int codel_change(struct Qdisc *sch, struct nlattr *opt) @@ -133,6 +134,12 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt) q->params.target = ((u64)target * NSEC_PER_USEC) >> CODEL_SHIFT; } + if (tb[TCA_CODEL_CE_THRESHOLD]) { + u64 val = nla_get_u32(tb[TCA_CODEL_CE_THRESHOLD]); + + q->params.ce_threshold = (val * NSEC_PER_USEC) >> CODEL_SHIFT; + } + if (tb[TCA_CODEL_INTERVAL]) { u32 interval = nla_get_u32(tb[TCA_CODEL_INTERVAL]); @@ -201,7 +208,10 @@ static int codel_dump(struct Qdisc *sch, struct sk_buff *skb) nla_put_u32(skb, TCA_CODEL_ECN, q->params.ecn)) goto nla_put_failure; - + if (q->params.ce_threshold != CODEL_DISABLED_THRESHOLD && + nla_put_u32(skb, TCA_CODEL_CE_THRESHOLD, + codel_time_to_us(q->params.ce_threshold))) + goto nla_put_failure; return nla_nest_end(skb, opts); nla_put_failure: @@ -220,6 +230,7 @@ static int codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) .ldelay = codel_time_to_us(q->vars.ldelay), .dropping = q->vars.dropping, .ecn_mark = q->stats.ecn_mark, + .ce_mark = q->stats.ce_mark, }; if (q->vars.dropping) { diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index a6fc53d69513..778739786b32 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -6,7 +6,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Copyright (C) 2012 Eric Dumazet + * Copyright (C) 2012,2015 Eric Dumazet */ #include @@ -292,6 +292,7 @@ static const struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = { [TCA_FQ_CODEL_ECN] = { .type = NLA_U32 }, [TCA_FQ_CODEL_FLOWS] = { .type = NLA_U32 }, [TCA_FQ_CODEL_QUANTUM] = { .type = NLA_U32 }, + [TCA_FQ_CODEL_CE_THRESHOLD] = { .type = NLA_U32 }, }; static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt) @@ -322,6 +323,12 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt) q->cparams.target = (target * NSEC_PER_USEC) >> CODEL_SHIFT; } + if (tb[TCA_FQ_CODEL_CE_THRESHOLD]) { + u64 val = nla_get_u32(tb[TCA_FQ_CODEL_CE_THRESHOLD]); + + q->cparams.ce_threshold = (val * NSEC_PER_USEC) >> CODEL_SHIFT; + } + if (tb[TCA_FQ_CODEL_INTERVAL]) { u64 interval = nla_get_u32(tb[TCA_FQ_CODEL_INTERVAL]); @@ -441,6 +448,11 @@ static int fq_codel_dump(struct Qdisc *sch, struct sk_buff *skb) q->flows_cnt)) goto nla_put_failure; + if (q->cparams.ce_threshold != CODEL_DISABLED_THRESHOLD && + nla_put_u32(skb, TCA_FQ_CODEL_CE_THRESHOLD, + codel_time_to_us(q->cparams.ce_threshold))) + goto nla_put_failure; + return nla_nest_end(skb, opts); nla_put_failure: @@ -459,6 +471,7 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) st.qdisc_stats.drop_overlimit = q->drop_overlimit; st.qdisc_stats.ecn_mark = q->cstats.ecn_mark; st.qdisc_stats.new_flow_count = q->new_flow_count; + st.qdisc_stats.ce_mark = q->cstats.ce_mark; list_for_each(pos, &q->new_flows) st.qdisc_stats.new_flows_len++; -- cgit v1.2.3 From 140e807da12988e2a925fe029336e7bb67a8d4de Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 8 May 2015 21:07:08 -0500 Subject: tun: Utilize the normal socket network namespace refcounting. There is no need for tun to do the weird network namespace refcounting. The existing network namespace refcounting in tfile has almost exactly the same lifetime. So rewrite the code to use the struct sock network namespace refcounting and remove the unnecessary hand rolled network namespace refcounting and the unncesary tfile->net. This change allows the tun code to directly call sock_put bypassing sock_release and making SOCK_EXTERNALLY_ALLOCATED unnecessary. Remove the now unncessary tun_release so that if anything tries to use the sock_release code path the kernel will oops, and let us know about the bug. The macvtap code already uses it's internal socket this way. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/net/tun.c | 24 ++++-------------------- include/linux/net.h | 1 - net/socket.c | 3 --- 3 files changed, 4 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index e470ae59d405..3262f3e2b8b2 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -146,7 +146,6 @@ struct tun_file { struct socket socket; struct socket_wq wq; struct tun_struct __rcu *tun; - struct net *net; struct fasync_struct *fasync; /* only used for fasnyc */ unsigned int flags; @@ -493,10 +492,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean) tun->dev->reg_state == NETREG_REGISTERED) unregister_netdevice(tun->dev); } - - BUG_ON(!test_bit(SOCK_EXTERNALLY_ALLOCATED, - &tfile->socket.flags)); - sk_release_kernel(&tfile->sk); + sock_put(&tfile->sk); } } @@ -1492,18 +1488,10 @@ out: return ret; } -static int tun_release(struct socket *sock) -{ - if (sock->sk) - sock_put(sock->sk); - return 0; -} - /* Ops structure to mimic raw sockets with tun */ static const struct proto_ops tun_socket_ops = { .sendmsg = tun_sendmsg, .recvmsg = tun_recvmsg, - .release = tun_release, }; static struct proto tun_proto = { @@ -1865,7 +1853,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, if (cmd == TUNSETIFF && !tun) { ifr.ifr_name[IFNAMSIZ-1] = '\0'; - ret = tun_set_iff(tfile->net, file, &ifr); + ret = tun_set_iff(sock_net(&tfile->sk), file, &ifr); if (ret) goto unlock; @@ -2154,16 +2142,16 @@ out: static int tun_chr_open(struct inode *inode, struct file * file) { + struct net *net = current->nsproxy->net_ns; struct tun_file *tfile; DBG1(KERN_INFO, "tunX: tun_chr_open\n"); - tfile = (struct tun_file *)sk_alloc(&init_net, AF_UNSPEC, GFP_KERNEL, + tfile = (struct tun_file *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL, &tun_proto); if (!tfile) return -ENOMEM; RCU_INIT_POINTER(tfile->tun, NULL); - tfile->net = get_net(current->nsproxy->net_ns); tfile->flags = 0; tfile->ifindex = 0; @@ -2174,13 +2162,11 @@ static int tun_chr_open(struct inode *inode, struct file * file) tfile->socket.ops = &tun_socket_ops; sock_init_data(&tfile->socket, &tfile->sk); - sk_change_net(&tfile->sk, tfile->net); tfile->sk.sk_write_space = tun_sock_write_space; tfile->sk.sk_sndbuf = INT_MAX; file->private_data = tfile; - set_bit(SOCK_EXTERNALLY_ALLOCATED, &tfile->socket.flags); INIT_LIST_HEAD(&tfile->next); sock_set_flag(&tfile->sk, SOCK_ZEROCOPY); @@ -2191,10 +2177,8 @@ static int tun_chr_open(struct inode *inode, struct file * file) static int tun_chr_close(struct inode *inode, struct file *file) { struct tun_file *tfile = file->private_data; - struct net *net = tfile->net; tun_detach(tfile, true); - put_net(net); return 0; } diff --git a/include/linux/net.h b/include/linux/net.h index 738ea48be889..8a5e81d2bdf7 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -38,7 +38,6 @@ struct net; #define SOCK_NOSPACE 2 #define SOCK_PASSCRED 3 #define SOCK_PASSSEC 4 -#define SOCK_EXTERNALLY_ALLOCATED 5 #ifndef ARCH_HAS_SOCKET_TYPES /** diff --git a/net/socket.c b/net/socket.c index 884e32997698..b5f1f43ed8f4 100644 --- a/net/socket.c +++ b/net/socket.c @@ -576,9 +576,6 @@ void sock_release(struct socket *sock) if (rcu_dereference_protected(sock->wq, 1)->fasync_list) pr_err("%s: fasync list not empty!\n", __func__); - if (test_bit(SOCK_EXTERNALLY_ALLOCATED, &sock->flags)) - return; - this_cpu_sub(sockets_in_use, 1); if (!sock->file) { iput(SOCK_INODE(sock)); -- cgit v1.2.3 From eeb1bd5c40edb0e2fd925c8535e2fdebdbc5cef2 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 8 May 2015 21:08:05 -0500 Subject: net: Add a struct net parameter to sock_create_kern This is long overdue, and is part of cleaning up how we allocate kernel sockets that don't reference count struct net. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- drivers/block/drbd/drbd_receiver.c | 4 ++-- fs/afs/rxrpc.c | 2 +- fs/dlm/lowcomms.c | 16 ++++++++-------- include/linux/net.h | 2 +- net/bluetooth/rfcomm/core.c | 2 +- net/ceph/messenger.c | 4 ++-- net/ipv4/af_inet.c | 2 +- net/ipv4/udp_tunnel.c | 2 +- net/ipv6/ip6_udp_tunnel.c | 2 +- net/l2tp/l2tp_core.c | 4 ++-- net/netfilter/ipvs/ip_vs_sync.c | 4 ++-- net/rxrpc/ar-local.c | 4 ++-- net/socket.c | 4 ++-- 13 files changed, 26 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index cee20354ac37..c097909c589c 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -598,7 +598,7 @@ static struct socket *drbd_try_connect(struct drbd_connection *connection) memcpy(&peer_in6, &connection->peer_addr, peer_addr_len); what = "sock_create_kern"; - err = sock_create_kern(((struct sockaddr *)&src_in6)->sa_family, + err = sock_create_kern(&init_net, ((struct sockaddr *)&src_in6)->sa_family, SOCK_STREAM, IPPROTO_TCP, &sock); if (err < 0) { sock = NULL; @@ -693,7 +693,7 @@ static int prepare_listen_socket(struct drbd_connection *connection, struct acce memcpy(&my_addr, &connection->my_addr, my_addr_len); what = "sock_create_kern"; - err = sock_create_kern(((struct sockaddr *)&my_addr)->sa_family, + err = sock_create_kern(&init_net, ((struct sockaddr *)&my_addr)->sa_family, SOCK_STREAM, IPPROTO_TCP, &s_listen); if (err) { s_listen = NULL; diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 3a57a1b0fb51..b50642870a43 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -85,7 +85,7 @@ int afs_open_socket(void) return -ENOMEM; } - ret = sock_create_kern(AF_RXRPC, SOCK_DGRAM, PF_INET, &socket); + ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET, &socket); if (ret < 0) { destroy_workqueue(afs_async_calls); _leave(" = %d [socket]", ret); diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index d08e079ea5d3..754fd6c0b747 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -921,8 +921,8 @@ static int tcp_accept_from_sock(struct connection *con) mutex_unlock(&connections_lock); memset(&peeraddr, 0, sizeof(peeraddr)); - result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM, - IPPROTO_TCP, &newsock); + result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family, + SOCK_STREAM, IPPROTO_TCP, &newsock); if (result < 0) return -ENOMEM; @@ -1173,8 +1173,8 @@ static void tcp_connect_to_sock(struct connection *con) goto out; /* Create a socket to communicate with */ - result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM, - IPPROTO_TCP, &sock); + result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family, + SOCK_STREAM, IPPROTO_TCP, &sock); if (result < 0) goto out_err; @@ -1258,8 +1258,8 @@ static struct socket *tcp_create_listen_sock(struct connection *con, addr_len = sizeof(struct sockaddr_in6); /* Create a socket to communicate with */ - result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM, - IPPROTO_TCP, &sock); + result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family, + SOCK_STREAM, IPPROTO_TCP, &sock); if (result < 0) { log_print("Can't create listening comms socket"); goto create_out; @@ -1365,8 +1365,8 @@ static int sctp_listen_for_all(void) log_print("Using SCTP for communications"); - result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_SEQPACKET, - IPPROTO_SCTP, &sock); + result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family, + SOCK_SEQPACKET, IPPROTO_SCTP, &sock); if (result < 0) { log_print("Can't create comms socket, check SCTP is loaded"); goto out; diff --git a/include/linux/net.h b/include/linux/net.h index 8a5e81d2bdf7..04aa06852771 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -207,7 +207,7 @@ void sock_unregister(int family); int __sock_create(struct net *net, int family, int type, int proto, struct socket **res, int kern); int sock_create(int family, int type, int proto, struct socket **res); -int sock_create_kern(int family, int type, int proto, struct socket **res); +int sock_create_kern(struct net *net, int family, int type, int proto, struct socket **res); int sock_create_lite(int family, int type, int proto, struct socket **res); void sock_release(struct socket *sock); int sock_sendmsg(struct socket *sock, struct msghdr *msg); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 4fea24275b17..29709fbfd1f5 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -200,7 +200,7 @@ static int rfcomm_l2sock_create(struct socket **sock) BT_DBG(""); - err = sock_create_kern(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock); + err = sock_create_kern(&init_net, PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock); if (!err) { struct sock *sk = (*sock)->sk; sk->sk_data_ready = rfcomm_l2data_ready; diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 967080a9f043..073262fea6dd 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -480,8 +480,8 @@ static int ceph_tcp_connect(struct ceph_connection *con) int ret; BUG_ON(con->sock); - ret = sock_create_kern(con->peer_addr.in_addr.ss_family, SOCK_STREAM, - IPPROTO_TCP, &sock); + ret = sock_create_kern(&init_net, con->peer_addr.in_addr.ss_family, + SOCK_STREAM, IPPROTO_TCP, &sock); if (ret) return ret; sock->sk->sk_allocation = GFP_NOFS; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 8b47a4d79d04..09f4d024dfe5 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1430,7 +1430,7 @@ int inet_ctl_sock_create(struct sock **sk, unsigned short family, struct net *net) { struct socket *sock; - int rc = sock_create_kern(family, type, protocol, &sock); + int rc = sock_create_kern(&init_net, family, type, protocol, &sock); if (rc == 0) { *sk = sock->sk; diff --git a/net/ipv4/udp_tunnel.c b/net/ipv4/udp_tunnel.c index 6bb98cc193c9..4e2837476967 100644 --- a/net/ipv4/udp_tunnel.c +++ b/net/ipv4/udp_tunnel.c @@ -15,7 +15,7 @@ int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg, struct socket *sock = NULL; struct sockaddr_in udp_addr; - err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock); + err = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, 0, &sock); if (err < 0) goto error; diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c index bba8903e871f..478576b61214 100644 --- a/net/ipv6/ip6_udp_tunnel.c +++ b/net/ipv6/ip6_udp_tunnel.c @@ -19,7 +19,7 @@ int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg, int err; struct socket *sock = NULL; - err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock); + err = sock_create_kern(&init_net, AF_INET6, SOCK_DGRAM, 0, &sock); if (err < 0) goto error; diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index a29a504492af..ae513a2fe7f3 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1399,7 +1399,7 @@ static int l2tp_tunnel_sock_create(struct net *net, if (cfg->local_ip6 && cfg->peer_ip6) { struct sockaddr_l2tpip6 ip6_addr = {0}; - err = sock_create_kern(AF_INET6, SOCK_DGRAM, + err = sock_create_kern(&init_net, AF_INET6, SOCK_DGRAM, IPPROTO_L2TP, &sock); if (err < 0) goto out; @@ -1429,7 +1429,7 @@ static int l2tp_tunnel_sock_create(struct net *net, { struct sockaddr_l2tpip ip_addr = {0}; - err = sock_create_kern(AF_INET, SOCK_DGRAM, + err = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, IPPROTO_L2TP, &sock); if (err < 0) goto out; diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 19b9cce6c210..2e9a5b5d1239 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -1458,7 +1458,7 @@ static struct socket *make_send_sock(struct net *net, int id) int result; /* First create a socket move it to right name space later */ - result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); + result = sock_create_kern(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); if (result < 0) { pr_err("Error during creation of socket; terminating\n"); return ERR_PTR(result); @@ -1518,7 +1518,7 @@ static struct socket *make_receive_sock(struct net *net, int id) int result; /* First create a socket */ - result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); + result = sock_create_kern(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); if (result < 0) { pr_err("Error during creation of socket; terminating\n"); return ERR_PTR(result); diff --git a/net/rxrpc/ar-local.c b/net/rxrpc/ar-local.c index ca904ed5400a..78483b4602bf 100644 --- a/net/rxrpc/ar-local.c +++ b/net/rxrpc/ar-local.c @@ -73,8 +73,8 @@ static int rxrpc_create_local(struct rxrpc_local *local) _enter("%p{%d}", local, local->srx.transport_type); /* create a socket to represent the local endpoint */ - ret = sock_create_kern(PF_INET, local->srx.transport_type, IPPROTO_UDP, - &local->socket); + ret = sock_create_kern(&init_net, PF_INET, local->srx.transport_type, + IPPROTO_UDP, &local->socket); if (ret < 0) { _leave(" = %d [socket]", ret); return ret; diff --git a/net/socket.c b/net/socket.c index b5f1f43ed8f4..9963a0b53a64 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1210,9 +1210,9 @@ int sock_create(int family, int type, int protocol, struct socket **res) } EXPORT_SYMBOL(sock_create); -int sock_create_kern(int family, int type, int protocol, struct socket **res) +int sock_create_kern(struct net *net, int family, int type, int protocol, struct socket **res) { - return __sock_create(&init_net, family, type, protocol, res, 1); + return __sock_create(net, family, type, protocol, res, 1); } EXPORT_SYMBOL(sock_create_kern); -- cgit v1.2.3 From 11aa9c28b4209242a9de0a661a7b3405adb568a0 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 8 May 2015 21:09:13 -0500 Subject: net: Pass kern from net_proto_family.create to sk_alloc In preparation for changing how struct net is refcounted on kernel sockets pass the knowledge that we are creating a kernel socket from sock_create_kern through to sk_alloc. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- crypto/af_alg.c | 4 ++-- drivers/isdn/mISDN/socket.c | 12 ++++++------ drivers/net/macvtap.c | 2 +- drivers/net/ppp/pppoe.c | 4 ++-- drivers/net/ppp/pppox.c | 2 +- drivers/net/ppp/pptp.c | 4 ++-- drivers/net/tun.c | 2 +- include/linux/if_pppox.h | 2 +- include/net/af_vsock.h | 2 +- include/net/llc_conn.h | 2 +- include/net/sock.h | 2 +- net/appletalk/ddp.c | 2 +- net/atm/common.c | 4 ++-- net/atm/common.h | 2 +- net/atm/pvc.c | 2 +- net/atm/svc.c | 2 +- net/ax25/af_ax25.c | 4 ++-- net/bluetooth/bnep/sock.c | 2 +- net/bluetooth/cmtp/sock.c | 2 +- net/bluetooth/hci_sock.c | 2 +- net/bluetooth/hidp/sock.c | 2 +- net/bluetooth/l2cap_sock.c | 10 +++++----- net/bluetooth/rfcomm/sock.c | 8 ++++---- net/bluetooth/sco.c | 8 ++++---- net/caif/caif_socket.c | 2 +- net/can/af_can.c | 2 +- net/core/sock.c | 3 ++- net/decnet/af_decnet.c | 8 ++++---- net/ieee802154/socket.c | 2 +- net/ipv4/af_inet.c | 2 +- net/ipv6/af_inet6.c | 2 +- net/ipx/af_ipx.c | 2 +- net/irda/af_irda.c | 2 +- net/iucv/af_iucv.c | 10 +++++----- net/key/af_key.c | 2 +- net/l2tp/l2tp_ppp.c | 4 ++-- net/llc/af_llc.c | 2 +- net/llc/llc_conn.c | 6 +++--- net/netlink/af_netlink.c | 11 +++++------ net/netrom/af_netrom.c | 4 ++-- net/nfc/af_nfc.c | 2 +- net/nfc/llcp.h | 2 +- net/nfc/llcp_core.c | 2 +- net/nfc/llcp_sock.c | 8 ++++---- net/nfc/nfc.h | 2 +- net/nfc/rawsock.c | 4 ++-- net/packet/af_packet.c | 2 +- net/phonet/af_phonet.c | 2 +- net/phonet/pep.c | 2 +- net/rds/af_rds.c | 2 +- net/rose/af_rose.c | 4 ++-- net/rxrpc/af_rxrpc.c | 2 +- net/sctp/ipv6.c | 2 +- net/sctp/protocol.c | 2 +- net/tipc/socket.c | 2 +- net/unix/af_unix.c | 8 ++++---- net/vmw_vsock/af_vsock.c | 7 ++++--- net/vmw_vsock/vmci_transport.c | 2 +- net/x25/af_x25.c | 8 ++++---- 59 files changed, 109 insertions(+), 108 deletions(-) (limited to 'include') diff --git a/crypto/af_alg.c b/crypto/af_alg.c index f22cc56fd1b3..5ad0d5354535 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -244,7 +244,7 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) if (!type) goto unlock; - sk2 = sk_alloc(sock_net(sk), PF_ALG, GFP_KERNEL, &alg_proto); + sk2 = sk_alloc(sock_net(sk), PF_ALG, GFP_KERNEL, &alg_proto, 0); err = -ENOMEM; if (!sk2) goto unlock; @@ -324,7 +324,7 @@ static int alg_create(struct net *net, struct socket *sock, int protocol, return -EPROTONOSUPPORT; err = -ENOMEM; - sk = sk_alloc(net, PF_ALG, GFP_KERNEL, &alg_proto); + sk = sk_alloc(net, PF_ALG, GFP_KERNEL, &alg_proto, kern); if (!sk) goto out; diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 8dc7290089bb..0d29b5a6356d 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -601,14 +601,14 @@ static const struct proto_ops data_sock_ops = { }; static int -data_sock_create(struct net *net, struct socket *sock, int protocol) +data_sock_create(struct net *net, struct socket *sock, int protocol, int kern) { struct sock *sk; if (sock->type != SOCK_DGRAM) return -ESOCKTNOSUPPORT; - sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto); + sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern); if (!sk) return -ENOMEM; @@ -756,14 +756,14 @@ static const struct proto_ops base_sock_ops = { static int -base_sock_create(struct net *net, struct socket *sock, int protocol) +base_sock_create(struct net *net, struct socket *sock, int protocol, int kern) { struct sock *sk; if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto); + sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern); if (!sk) return -ENOMEM; @@ -785,7 +785,7 @@ mISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern) switch (proto) { case ISDN_P_BASE: - err = base_sock_create(net, sock, proto); + err = base_sock_create(net, sock, proto, kern); break; case ISDN_P_TE_S0: case ISDN_P_NT_S0: @@ -799,7 +799,7 @@ mISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern) case ISDN_P_B_L2DTMF: case ISDN_P_B_L2DSP: case ISDN_P_B_L2DSPHDLC: - err = data_sock_create(net, sock, proto); + err = data_sock_create(net, sock, proto, kern); break; default: return err; diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 8c350c5d54ad..0398631a3c24 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -476,7 +476,7 @@ static int macvtap_open(struct inode *inode, struct file *file) err = -ENOMEM; q = (struct macvtap_queue *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL, - &macvtap_proto); + &macvtap_proto, 0); if (!q) goto out; diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index aa1dd926623a..f86c5ab334aa 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -546,11 +546,11 @@ static struct proto pppoe_sk_proto __read_mostly = { * Initialize a new struct sock. * **********************************************************************/ -static int pppoe_create(struct net *net, struct socket *sock) +static int pppoe_create(struct net *net, struct socket *sock, int kern) { struct sock *sk; - sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto); + sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, kern); if (!sk) return -ENOMEM; diff --git a/drivers/net/ppp/pppox.c b/drivers/net/ppp/pppox.c index 2940e9fe351b..0e1b30622477 100644 --- a/drivers/net/ppp/pppox.c +++ b/drivers/net/ppp/pppox.c @@ -118,7 +118,7 @@ static int pppox_create(struct net *net, struct socket *sock, int protocol, !try_module_get(pppox_protos[protocol]->owner)) goto out; - rc = pppox_protos[protocol]->create(net, sock); + rc = pppox_protos[protocol]->create(net, sock, kern); module_put(pppox_protos[protocol]->owner); out: diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index e3bfbd4d0136..14839bc0aaf5 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -561,14 +561,14 @@ static void pptp_sock_destruct(struct sock *sk) skb_queue_purge(&sk->sk_receive_queue); } -static int pptp_create(struct net *net, struct socket *sock) +static int pptp_create(struct net *net, struct socket *sock, int kern) { int error = -ENOMEM; struct sock *sk; struct pppox_sock *po; struct pptp_opt *opt; - sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pptp_sk_proto); + sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pptp_sk_proto, kern); if (!sk) goto out; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3262f3e2b8b2..1a1c4f7b3ec5 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2148,7 +2148,7 @@ static int tun_chr_open(struct inode *inode, struct file * file) DBG1(KERN_INFO, "tunX: tun_chr_open\n"); tfile = (struct tun_file *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL, - &tun_proto); + &tun_proto, 0); if (!tfile) return -ENOMEM; RCU_INIT_POINTER(tfile->tun, NULL); diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h index 66a7d7600f43..b49cf923becc 100644 --- a/include/linux/if_pppox.h +++ b/include/linux/if_pppox.h @@ -74,7 +74,7 @@ static inline struct sock *sk_pppox(struct pppox_sock *po) struct module; struct pppox_proto { - int (*create)(struct net *net, struct socket *sock); + int (*create)(struct net *net, struct socket *sock, int kern); int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg); struct module *owner; diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index 172632dd9930..db639a4c5ab8 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -74,7 +74,7 @@ void vsock_pending_work(struct work_struct *work); struct sock *__vsock_create(struct net *net, struct socket *sock, struct sock *parent, - gfp_t priority, unsigned short type); + gfp_t priority, unsigned short type, int kern); /**** TRANSPORT ****/ diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index 0134681acc4c..fe994d2e5286 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h @@ -96,7 +96,7 @@ static __inline__ char llc_backlog_type(struct sk_buff *skb) } struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, - struct proto *prot); + struct proto *prot, int kern); void llc_sk_free(struct sock *sk); void llc_sk_reset(struct sock *sk); diff --git a/include/net/sock.h b/include/net/sock.h index 3a4898ec8c67..d8dcf91732b0 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1514,7 +1514,7 @@ static inline void unlock_sock_fast(struct sock *sk, bool slow) struct sock *sk_alloc(struct net *net, int family, gfp_t priority, - struct proto *prot); + struct proto *prot, int kern); void sk_free(struct sock *sk); void sk_release_kernel(struct sock *sk); struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority); diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 3b7ad43c7dad..d5871ac493eb 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1030,7 +1030,7 @@ static int atalk_create(struct net *net, struct socket *sock, int protocol, if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) goto out; rc = -ENOMEM; - sk = sk_alloc(net, PF_APPLETALK, GFP_KERNEL, &ddp_proto); + sk = sk_alloc(net, PF_APPLETALK, GFP_KERNEL, &ddp_proto, kern); if (!sk) goto out; rc = 0; diff --git a/net/atm/common.c b/net/atm/common.c index ed0466637e13..49a872db7e42 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -141,7 +141,7 @@ static struct proto vcc_proto = { .release_cb = vcc_release_cb, }; -int vcc_create(struct net *net, struct socket *sock, int protocol, int family) +int vcc_create(struct net *net, struct socket *sock, int protocol, int family, int kern) { struct sock *sk; struct atm_vcc *vcc; @@ -149,7 +149,7 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family) sock->sk = NULL; if (sock->type == SOCK_STREAM) return -EINVAL; - sk = sk_alloc(net, family, GFP_KERNEL, &vcc_proto); + sk = sk_alloc(net, family, GFP_KERNEL, &vcc_proto, kern); if (!sk) return -ENOMEM; sock_init_data(sock, sk); diff --git a/net/atm/common.h b/net/atm/common.h index 4d6f5b2068ac..959436b87182 100644 --- a/net/atm/common.h +++ b/net/atm/common.h @@ -10,7 +10,7 @@ #include /* for poll_table */ -int vcc_create(struct net *net, struct socket *sock, int protocol, int family); +int vcc_create(struct net *net, struct socket *sock, int protocol, int family, int kern); int vcc_release(struct socket *sock); int vcc_connect(struct socket *sock, int itf, short vpi, int vci); int vcc_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, diff --git a/net/atm/pvc.c b/net/atm/pvc.c index ae0324021407..040207ec399f 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -136,7 +136,7 @@ static int pvc_create(struct net *net, struct socket *sock, int protocol, return -EAFNOSUPPORT; sock->ops = &pvc_proto_ops; - return vcc_create(net, sock, protocol, PF_ATMPVC); + return vcc_create(net, sock, protocol, PF_ATMPVC, kern); } static const struct net_proto_family pvc_family_ops = { diff --git a/net/atm/svc.c b/net/atm/svc.c index 1ba23f5018e7..3fa0a9ee98d1 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -660,7 +660,7 @@ static int svc_create(struct net *net, struct socket *sock, int protocol, return -EAFNOSUPPORT; sock->ops = &svc_proto_ops; - error = vcc_create(net, sock, protocol, AF_ATMSVC); + error = vcc_create(net, sock, protocol, AF_ATMSVC, kern); if (error) return error; ATM_SD(sock)->local.sas_family = AF_ATMSVC; diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 330c1f4a5a0b..4273533d22b1 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -855,7 +855,7 @@ static int ax25_create(struct net *net, struct socket *sock, int protocol, return -ESOCKTNOSUPPORT; } - sk = sk_alloc(net, PF_AX25, GFP_ATOMIC, &ax25_proto); + sk = sk_alloc(net, PF_AX25, GFP_ATOMIC, &ax25_proto, kern); if (sk == NULL) return -ENOMEM; @@ -881,7 +881,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) struct sock *sk; ax25_cb *ax25, *oax25; - sk = sk_alloc(sock_net(osk), PF_AX25, GFP_ATOMIC, osk->sk_prot); + sk = sk_alloc(sock_net(osk), PF_AX25, GFP_ATOMIC, osk->sk_prot, 0); if (sk == NULL) return NULL; diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index bde2bdd9e929..b5116fa9835e 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -202,7 +202,7 @@ static int bnep_sock_create(struct net *net, struct socket *sock, int protocol, if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto); + sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, kern); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index d82787d417bd..ce86a7bae844 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -205,7 +205,7 @@ static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol, if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto); + sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, kern); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 56f9edbf3d05..5b14dcafcd08 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -1377,7 +1377,7 @@ static int hci_sock_create(struct net *net, struct socket *sock, int protocol, sock->ops = &hci_sock_ops; - sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto); + sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, kern); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index cb3fdde1968a..008ba439bd62 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -235,7 +235,7 @@ static int hidp_sock_create(struct net *net, struct socket *sock, int protocol, if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto); + sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, kern); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index a7278f05eafb..244287706f91 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -43,7 +43,7 @@ static struct bt_sock_list l2cap_sk_list = { static const struct proto_ops l2cap_sock_ops; static void l2cap_sock_init(struct sock *sk, struct sock *parent); static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, - int proto, gfp_t prio); + int proto, gfp_t prio, int kern); bool l2cap_is_socket(struct socket *sock) { @@ -1193,7 +1193,7 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan) } sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, - GFP_ATOMIC); + GFP_ATOMIC, 0); if (!sk) { release_sock(parent); return NULL; @@ -1523,12 +1523,12 @@ static struct proto l2cap_proto = { }; static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, - int proto, gfp_t prio) + int proto, gfp_t prio, int kern) { struct sock *sk; struct l2cap_chan *chan; - sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto); + sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto, kern); if (!sk) return NULL; @@ -1574,7 +1574,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, sock->ops = &l2cap_sock_ops; - sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC); + sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 825e8fb5114b..b2338e971b33 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -269,12 +269,12 @@ static struct proto rfcomm_proto = { .obj_size = sizeof(struct rfcomm_pinfo) }; -static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio) +static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio, int kern) { struct rfcomm_dlc *d; struct sock *sk; - sk = sk_alloc(net, PF_BLUETOOTH, prio, &rfcomm_proto); + sk = sk_alloc(net, PF_BLUETOOTH, prio, &rfcomm_proto, kern); if (!sk) return NULL; @@ -324,7 +324,7 @@ static int rfcomm_sock_create(struct net *net, struct socket *sock, sock->ops = &rfcomm_sock_ops; - sk = rfcomm_sock_alloc(net, sock, protocol, GFP_ATOMIC); + sk = rfcomm_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern); if (!sk) return -ENOMEM; @@ -969,7 +969,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * goto done; } - sk = rfcomm_sock_alloc(sock_net(parent), NULL, BTPROTO_RFCOMM, GFP_ATOMIC); + sk = rfcomm_sock_alloc(sock_net(parent), NULL, BTPROTO_RFCOMM, GFP_ATOMIC, 0); if (!sk) goto done; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 4322c833e748..6b6e59dc54cf 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -460,11 +460,11 @@ static struct proto sco_proto = { .obj_size = sizeof(struct sco_pinfo) }; -static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio) +static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio, int kern) { struct sock *sk; - sk = sk_alloc(net, PF_BLUETOOTH, prio, &sco_proto); + sk = sk_alloc(net, PF_BLUETOOTH, prio, &sco_proto, kern); if (!sk) return NULL; @@ -501,7 +501,7 @@ static int sco_sock_create(struct net *net, struct socket *sock, int protocol, sock->ops = &sco_sock_ops; - sk = sco_sock_alloc(net, sock, protocol, GFP_ATOMIC); + sk = sco_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern); if (!sk) return -ENOMEM; @@ -1026,7 +1026,7 @@ static void sco_conn_ready(struct sco_conn *conn) bh_lock_sock(parent); sk = sco_sock_alloc(sock_net(parent), NULL, - BTPROTO_SCO, GFP_ATOMIC); + BTPROTO_SCO, GFP_ATOMIC, 0); if (!sk) { bh_unlock_sock(parent); sco_conn_unlock(conn); diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 4ec0c803aef1..78a04ebb113c 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -1047,7 +1047,7 @@ static int caif_create(struct net *net, struct socket *sock, int protocol, * is really not used at all in the net/core or socket.c but the * initialization makes sure that sock->state is not uninitialized. */ - sk = sk_alloc(net, PF_CAIF, GFP_KERNEL, &prot); + sk = sk_alloc(net, PF_CAIF, GFP_KERNEL, &prot, kern); if (!sk) return -ENOMEM; diff --git a/net/can/af_can.c b/net/can/af_can.c index 32d710eaf1fc..d4d404bdfc9a 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -179,7 +179,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol, sock->ops = cp->ops; - sk = sk_alloc(net, PF_CAN, GFP_KERNEL, cp->prot); + sk = sk_alloc(net, PF_CAN, GFP_KERNEL, cp->prot, kern); if (!sk) { err = -ENOMEM; goto errout; diff --git a/net/core/sock.c b/net/core/sock.c index e891bcf325ca..cbc3789b830c 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1396,9 +1396,10 @@ EXPORT_SYMBOL_GPL(sock_update_netprioidx); * @family: protocol family * @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) * @prot: struct proto associated with this new sock instance + * @kern: is this to be a kernel socket? */ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, - struct proto *prot) + struct proto *prot, int kern) { struct sock *sk; diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 754484b3cd0e..675cf94e04f8 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -468,10 +468,10 @@ static struct proto dn_proto = { .obj_size = sizeof(struct dn_sock), }; -static struct sock *dn_alloc_sock(struct net *net, struct socket *sock, gfp_t gfp) +static struct sock *dn_alloc_sock(struct net *net, struct socket *sock, gfp_t gfp, int kern) { struct dn_scp *scp; - struct sock *sk = sk_alloc(net, PF_DECnet, gfp, &dn_proto); + struct sock *sk = sk_alloc(net, PF_DECnet, gfp, &dn_proto, kern); if (!sk) goto out; @@ -693,7 +693,7 @@ static int dn_create(struct net *net, struct socket *sock, int protocol, } - if ((sk = dn_alloc_sock(net, sock, GFP_KERNEL)) == NULL) + if ((sk = dn_alloc_sock(net, sock, GFP_KERNEL, kern)) == NULL) return -ENOBUFS; sk->sk_protocol = protocol; @@ -1096,7 +1096,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) cb = DN_SKB_CB(skb); sk->sk_ack_backlog--; - newsk = dn_alloc_sock(sock_net(sk), newsock, sk->sk_allocation); + newsk = dn_alloc_sock(sock_net(sk), newsock, sk->sk_allocation, 0); if (newsk == NULL) { release_sock(sk); kfree_skb(skb); diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c index b60c65f70346..7aaaf967df58 100644 --- a/net/ieee802154/socket.c +++ b/net/ieee802154/socket.c @@ -1014,7 +1014,7 @@ static int ieee802154_create(struct net *net, struct socket *sock, } rc = -ENOMEM; - sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto); + sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto, kern); if (!sk) goto out; rc = 0; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 09f4d024dfe5..e2dd9cb99d61 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -317,7 +317,7 @@ lookup_protocol: WARN_ON(!answer_prot->slab); err = -ENOBUFS; - sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot); + sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot, kern); if (!sk) goto out; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 4632afa57e05..f3866c0b6cfe 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -167,7 +167,7 @@ lookup_protocol: WARN_ON(!answer_prot->slab); err = -ENOBUFS; - sk = sk_alloc(net, PF_INET6, GFP_KERNEL, answer_prot); + sk = sk_alloc(net, PF_INET6, GFP_KERNEL, answer_prot, kern); if (!sk) goto out; diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 4ea5d7497b5f..48d0dc89b58d 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1347,7 +1347,7 @@ static int ipx_create(struct net *net, struct socket *sock, int protocol, goto out; rc = -ENOMEM; - sk = sk_alloc(net, PF_IPX, GFP_KERNEL, &ipx_proto); + sk = sk_alloc(net, PF_IPX, GFP_KERNEL, &ipx_proto, kern); if (!sk) goto out; diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index ee0ea25c8e7a..fae6822cc367 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -1100,7 +1100,7 @@ static int irda_create(struct net *net, struct socket *sock, int protocol, } /* Allocate networking socket */ - sk = sk_alloc(net, PF_IRDA, GFP_KERNEL, &irda_proto); + sk = sk_alloc(net, PF_IRDA, GFP_KERNEL, &irda_proto, kern); if (sk == NULL) return -ENOMEM; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 6daa52a18d40..918151c11348 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -535,12 +535,12 @@ static void iucv_sock_init(struct sock *sk, struct sock *parent) sk->sk_type = parent->sk_type; } -static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio) +static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio, int kern) { struct sock *sk; struct iucv_sock *iucv; - sk = sk_alloc(&init_net, PF_IUCV, prio, &iucv_proto); + sk = sk_alloc(&init_net, PF_IUCV, prio, &iucv_proto, kern); if (!sk) return NULL; iucv = iucv_sk(sk); @@ -602,7 +602,7 @@ static int iucv_sock_create(struct net *net, struct socket *sock, int protocol, return -ESOCKTNOSUPPORT; } - sk = iucv_sock_alloc(sock, protocol, GFP_KERNEL); + sk = iucv_sock_alloc(sock, protocol, GFP_KERNEL, kern); if (!sk) return -ENOMEM; @@ -1723,7 +1723,7 @@ static int iucv_callback_connreq(struct iucv_path *path, } /* Create the new socket */ - nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC); + nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC, 0); if (!nsk) { err = pr_iucv->path_sever(path, user_data); iucv_path_free(path); @@ -1933,7 +1933,7 @@ static int afiucv_hs_callback_syn(struct sock *sk, struct sk_buff *skb) goto out; } - nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC); + nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC, 0); bh_lock_sock(sk); if ((sk->sk_state != IUCV_LISTEN) || sk_acceptq_is_full(sk) || diff --git a/net/key/af_key.c b/net/key/af_key.c index f0d52d721b3a..9e834ec475a9 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -149,7 +149,7 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol, return -EPROTONOSUPPORT; err = -ENOMEM; - sk = sk_alloc(net, PF_KEY, GFP_KERNEL, &key_proto); + sk = sk_alloc(net, PF_KEY, GFP_KERNEL, &key_proto, kern); if (sk == NULL) goto out; diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index e9b0dec56b8e..f56c9f69e9f2 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -542,12 +542,12 @@ static int pppol2tp_backlog_recv(struct sock *sk, struct sk_buff *skb) /* socket() handler. Initialize a new struct sock. */ -static int pppol2tp_create(struct net *net, struct socket *sock) +static int pppol2tp_create(struct net *net, struct socket *sock, int kern) { int error = -ENOMEM; struct sock *sk; - sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto); + sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, kern); if (!sk) goto out; diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 17a8dff06090..8fd9febaa5ba 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -168,7 +168,7 @@ static int llc_ui_create(struct net *net, struct socket *sock, int protocol, if (likely(sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM)) { rc = -ENOMEM; - sk = llc_sk_alloc(net, PF_LLC, GFP_KERNEL, &llc_proto); + sk = llc_sk_alloc(net, PF_LLC, GFP_KERNEL, &llc_proto, kern); if (sk) { rc = 0; llc_ui_sk_init(sock, sk); diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 81a61fce3afb..3e821daf9dd4 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -768,7 +768,7 @@ static struct sock *llc_create_incoming_sock(struct sock *sk, struct llc_addr *daddr) { struct sock *newsk = llc_sk_alloc(sock_net(sk), sk->sk_family, GFP_ATOMIC, - sk->sk_prot); + sk->sk_prot, 0); struct llc_sock *newllc, *llc = llc_sk(sk); if (!newsk) @@ -931,9 +931,9 @@ static void llc_sk_init(struct sock *sk) * Allocates a LLC sock and initializes it. Returns the new LLC sock * or %NULL if there's no memory available for one */ -struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot) +struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot, int kern) { - struct sock *sk = sk_alloc(net, family, priority, prot); + struct sock *sk = sk_alloc(net, family, priority, prot, kern); if (!sk) goto out; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index a5fff75accf8..be6665ab7f40 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1119,14 +1119,15 @@ static struct proto netlink_proto = { }; static int __netlink_create(struct net *net, struct socket *sock, - struct mutex *cb_mutex, int protocol) + struct mutex *cb_mutex, int protocol, + int kern) { struct sock *sk; struct netlink_sock *nlk; sock->ops = &netlink_ops; - sk = sk_alloc(net, PF_NETLINK, GFP_KERNEL, &netlink_proto); + sk = sk_alloc(net, PF_NETLINK, GFP_KERNEL, &netlink_proto, kern); if (!sk) return -ENOMEM; @@ -1188,7 +1189,7 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, if (err < 0) goto out; - err = __netlink_create(net, sock, cb_mutex, protocol); + err = __netlink_create(net, sock, cb_mutex, protocol, kern); if (err < 0) goto out_module; @@ -2515,14 +2516,12 @@ __netlink_kernel_create(struct net *net, int unit, struct module *module, if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) return NULL; - /* * We have to just have a reference on the net from sk, but don't * get_net it. Besides, we cannot get and then put the net here. * So we create one inside init_net and the move it to net. */ - - if (__netlink_create(&init_net, sock, cb_mutex, unit) < 0) + if (__netlink_create(&init_net, sock, cb_mutex, unit, 0) < 0) goto out_sock_release_nosk; sk = sock->sk; diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index b987fd56c3c5..ed212ffc1d9d 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -433,7 +433,7 @@ static int nr_create(struct net *net, struct socket *sock, int protocol, if (sock->type != SOCK_SEQPACKET || protocol != 0) return -ESOCKTNOSUPPORT; - sk = sk_alloc(net, PF_NETROM, GFP_ATOMIC, &nr_proto); + sk = sk_alloc(net, PF_NETROM, GFP_ATOMIC, &nr_proto, kern); if (sk == NULL) return -ENOMEM; @@ -476,7 +476,7 @@ static struct sock *nr_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) return NULL; - sk = sk_alloc(sock_net(osk), PF_NETROM, GFP_ATOMIC, osk->sk_prot); + sk = sk_alloc(sock_net(osk), PF_NETROM, GFP_ATOMIC, osk->sk_prot, 0); if (sk == NULL) return NULL; diff --git a/net/nfc/af_nfc.c b/net/nfc/af_nfc.c index 2277276f52bc..54e40fa47822 100644 --- a/net/nfc/af_nfc.c +++ b/net/nfc/af_nfc.c @@ -40,7 +40,7 @@ static int nfc_sock_create(struct net *net, struct socket *sock, int proto, read_lock(&proto_tab_lock); if (proto_tab[proto] && try_module_get(proto_tab[proto]->owner)) { - rc = proto_tab[proto]->create(net, sock, proto_tab[proto]); + rc = proto_tab[proto]->create(net, sock, proto_tab[proto], kern); module_put(proto_tab[proto]->owner); } read_unlock(&proto_tab_lock); diff --git a/net/nfc/llcp.h b/net/nfc/llcp.h index de1789e3cc82..1f68724d44d3 100644 --- a/net/nfc/llcp.h +++ b/net/nfc/llcp.h @@ -225,7 +225,7 @@ void nfc_llcp_send_to_raw_sock(struct nfc_llcp_local *local, struct sk_buff *skb, u8 direction); /* Sock API */ -struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp); +struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp, int kern); void nfc_llcp_sock_free(struct nfc_llcp_sock *sock); void nfc_llcp_accept_unlink(struct sock *sk); void nfc_llcp_accept_enqueue(struct sock *parent, struct sock *sk); diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index b18f07ccb504..98876274a1ee 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c @@ -934,7 +934,7 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, sock->ssap = ssap; } - new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type, GFP_ATOMIC); + new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type, GFP_ATOMIC, 0); if (new_sk == NULL) { reason = LLCP_DM_REJ; release_sock(&sock->sk); diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c index 9578bd6a4f3e..b7de0da46acd 100644 --- a/net/nfc/llcp_sock.c +++ b/net/nfc/llcp_sock.c @@ -942,12 +942,12 @@ static void llcp_sock_destruct(struct sock *sk) } } -struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp) +struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp, int kern) { struct sock *sk; struct nfc_llcp_sock *llcp_sock; - sk = sk_alloc(&init_net, PF_NFC, gfp, &llcp_sock_proto); + sk = sk_alloc(&init_net, PF_NFC, gfp, &llcp_sock_proto, kern); if (!sk) return NULL; @@ -993,7 +993,7 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock) } static int llcp_sock_create(struct net *net, struct socket *sock, - const struct nfc_protocol *nfc_proto) + const struct nfc_protocol *nfc_proto, int kern) { struct sock *sk; @@ -1009,7 +1009,7 @@ static int llcp_sock_create(struct net *net, struct socket *sock, else sock->ops = &llcp_sock_ops; - sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC); + sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC, kern); if (sk == NULL) return -ENOMEM; diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index a8ce80b47720..5c93e8412a26 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h @@ -30,7 +30,7 @@ struct nfc_protocol { struct proto *proto; struct module *owner; int (*create)(struct net *net, struct socket *sock, - const struct nfc_protocol *nfc_proto); + const struct nfc_protocol *nfc_proto, int kern); }; struct nfc_rawsock { diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c index 82b4e8024778..e9a91488fe3d 100644 --- a/net/nfc/rawsock.c +++ b/net/nfc/rawsock.c @@ -334,7 +334,7 @@ static void rawsock_destruct(struct sock *sk) } static int rawsock_create(struct net *net, struct socket *sock, - const struct nfc_protocol *nfc_proto) + const struct nfc_protocol *nfc_proto, int kern) { struct sock *sk; @@ -348,7 +348,7 @@ static int rawsock_create(struct net *net, struct socket *sock, else sock->ops = &rawsock_ops; - sk = sk_alloc(net, PF_NFC, GFP_ATOMIC, nfc_proto->proto); + sk = sk_alloc(net, PF_NFC, GFP_ATOMIC, nfc_proto->proto, kern); if (!sk) return -ENOMEM; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 5102c3cc4eec..94713276a1d9 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2832,7 +2832,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, sock->state = SS_UNCONNECTED; err = -ENOBUFS; - sk = sk_alloc(net, PF_PACKET, GFP_KERNEL, &packet_proto); + sk = sk_alloc(net, PF_PACKET, GFP_KERNEL, &packet_proto, kern); if (sk == NULL) goto out; diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index 32ab87d34828..10d42f3220ab 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -97,7 +97,7 @@ static int pn_socket_create(struct net *net, struct socket *sock, int protocol, goto out; } - sk = sk_alloc(net, PF_PHONET, GFP_KERNEL, pnp->prot); + sk = sk_alloc(net, PF_PHONET, GFP_KERNEL, pnp->prot, kern); if (sk == NULL) { err = -ENOMEM; goto out; diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 6de2aeb98a1f..850a86cde0b3 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -845,7 +845,7 @@ static struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp) } /* Create a new to-be-accepted sock */ - newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_KERNEL, sk->sk_prot); + newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_KERNEL, sk->sk_prot, 0); if (!newsk) { pep_reject_conn(sk, skb, PN_PIPE_ERR_OVERLOAD, GFP_KERNEL); err = -ENOBUFS; diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index 10443377fb9d..3d83641f2861 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -440,7 +440,7 @@ static int rds_create(struct net *net, struct socket *sock, int protocol, if (sock->type != SOCK_SEQPACKET || protocol) return -ESOCKTNOSUPPORT; - sk = sk_alloc(net, AF_RDS, GFP_ATOMIC, &rds_proto); + sk = sk_alloc(net, AF_RDS, GFP_ATOMIC, &rds_proto, kern); if (!sk) return -ENOMEM; diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 8ae603069a1a..36dbc2da3661 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -520,7 +520,7 @@ static int rose_create(struct net *net, struct socket *sock, int protocol, if (sock->type != SOCK_SEQPACKET || protocol != 0) return -ESOCKTNOSUPPORT; - sk = sk_alloc(net, PF_ROSE, GFP_ATOMIC, &rose_proto); + sk = sk_alloc(net, PF_ROSE, GFP_ATOMIC, &rose_proto, kern); if (sk == NULL) return -ENOMEM; @@ -559,7 +559,7 @@ static struct sock *rose_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) return NULL; - sk = sk_alloc(sock_net(osk), PF_ROSE, GFP_ATOMIC, &rose_proto); + sk = sk_alloc(sock_net(osk), PF_ROSE, GFP_ATOMIC, &rose_proto, 0); if (sk == NULL) return NULL; diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 0095b9a0b779..25d60ed15284 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -632,7 +632,7 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol, sock->ops = &rxrpc_rpc_ops; sock->state = SS_UNCONNECTED; - sk = sk_alloc(net, PF_RXRPC, GFP_KERNEL, &rxrpc_proto); + sk = sk_alloc(net, PF_RXRPC, GFP_KERNEL, &rxrpc_proto, kern); if (!sk) return -ENOMEM; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 0e4198ee2370..e703ff7fed40 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -635,7 +635,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, struct ipv6_pinfo *newnp, *np = inet6_sk(sk); struct sctp6_sock *newsctp6sk; - newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot); + newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot, 0); if (!newsk) goto out; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 53b7acde9aa3..59e80356672b 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -550,7 +550,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk, struct sctp_association *asoc) { struct sock *newsk = sk_alloc(sock_net(sk), PF_INET, GFP_KERNEL, - sk->sk_prot); + sk->sk_prot, 0); struct inet_sock *newinet; if (!newsk) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 9074b5cede38..8f3c8e2cef8e 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -342,7 +342,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock, } /* Allocate socket's protocol area */ - sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto); + sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto, kern); if (sk == NULL) return -ENOMEM; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 5266ea7b922b..941b3d26e3bf 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -620,7 +620,7 @@ static struct proto unix_proto = { */ static struct lock_class_key af_unix_sk_receive_queue_lock_key; -static struct sock *unix_create1(struct net *net, struct socket *sock) +static struct sock *unix_create1(struct net *net, struct socket *sock, int kern) { struct sock *sk = NULL; struct unix_sock *u; @@ -629,7 +629,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock) if (atomic_long_read(&unix_nr_socks) > 2 * get_max_files()) goto out; - sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_proto); + sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_proto, kern); if (!sk) goto out; @@ -688,7 +688,7 @@ static int unix_create(struct net *net, struct socket *sock, int protocol, return -ESOCKTNOSUPPORT; } - return unix_create1(net, sock) ? 0 : -ENOMEM; + return unix_create1(net, sock, kern) ? 0 : -ENOMEM; } static int unix_release(struct socket *sock) @@ -1088,7 +1088,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, err = -ENOMEM; /* create new sock for complete connection */ - newsk = unix_create1(sock_net(sk), NULL); + newsk = unix_create1(sock_net(sk), NULL, 0); if (newsk == NULL) goto out; diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 2ec86e652a19..df5fc6b340f1 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -581,13 +581,14 @@ struct sock *__vsock_create(struct net *net, struct socket *sock, struct sock *parent, gfp_t priority, - unsigned short type) + unsigned short type, + int kern) { struct sock *sk; struct vsock_sock *psk; struct vsock_sock *vsk; - sk = sk_alloc(net, AF_VSOCK, priority, &vsock_proto); + sk = sk_alloc(net, AF_VSOCK, priority, &vsock_proto, kern); if (!sk) return NULL; @@ -1866,7 +1867,7 @@ static int vsock_create(struct net *net, struct socket *sock, sock->state = SS_UNCONNECTED; - return __vsock_create(net, sock, NULL, GFP_KERNEL, 0) ? 0 : -ENOMEM; + return __vsock_create(net, sock, NULL, GFP_KERNEL, 0, kern) ? 0 : -ENOMEM; } static const struct net_proto_family vsock_family_ops = { diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index c294da095461..1f63daff3965 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c @@ -1022,7 +1022,7 @@ static int vmci_transport_recv_listen(struct sock *sk, } pending = __vsock_create(sock_net(sk), NULL, sk, GFP_KERNEL, - sk->sk_type); + sk->sk_type, 0); if (!pending) { vmci_transport_send_reset(sk, pkt); return -ENOMEM; diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index c3ab230e4493..a750f330b8dd 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -515,10 +515,10 @@ static struct proto x25_proto = { .obj_size = sizeof(struct x25_sock), }; -static struct sock *x25_alloc_socket(struct net *net) +static struct sock *x25_alloc_socket(struct net *net, int kern) { struct x25_sock *x25; - struct sock *sk = sk_alloc(net, AF_X25, GFP_ATOMIC, &x25_proto); + struct sock *sk = sk_alloc(net, AF_X25, GFP_ATOMIC, &x25_proto, kern); if (!sk) goto out; @@ -553,7 +553,7 @@ static int x25_create(struct net *net, struct socket *sock, int protocol, goto out; rc = -ENOBUFS; - if ((sk = x25_alloc_socket(net)) == NULL) + if ((sk = x25_alloc_socket(net, kern)) == NULL) goto out; x25 = x25_sk(sk); @@ -602,7 +602,7 @@ static struct sock *x25_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) goto out; - if ((sk = x25_alloc_socket(sock_net(osk))) == NULL) + if ((sk = x25_alloc_socket(sock_net(osk), 0)) == NULL) goto out; x25 = x25_sk(sk); -- cgit v1.2.3 From 26abe14379f8e2fa3fd1bcf97c9a7ad9364886fe Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 8 May 2015 21:10:31 -0500 Subject: net: Modify sk_alloc to not reference count the netns of kernel sockets. Now that sk_alloc knows when a kernel socket is being allocated modify it to not reference count the network namespace of kernel sockets. Keep track of if a socket needs reference counting by adding a flag to struct sock called sk_net_refcnt. Update all of the callers of sock_create_kern to stop using sk_change_net and sk_release_kernel as those hacks are no longer needed, to avoid reference counting a kernel socket. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- include/net/inet_common.h | 2 +- include/net/sock.h | 2 ++ net/core/sock.c | 8 ++++++-- net/ipv4/af_inet.c | 4 +--- net/ipv4/udp_tunnel.c | 8 +++----- net/ipv6/ip6_udp_tunnel.c | 6 ++---- net/l2tp/l2tp_core.c | 15 ++++++--------- net/netfilter/ipvs/ip_vs_sync.c | 30 +++++++++--------------------- 8 files changed, 30 insertions(+), 45 deletions(-) (limited to 'include') diff --git a/include/net/inet_common.h b/include/net/inet_common.h index 4a92423eefa5..279f83591971 100644 --- a/include/net/inet_common.h +++ b/include/net/inet_common.h @@ -41,7 +41,7 @@ int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, static inline void inet_ctl_sock_destroy(struct sock *sk) { - sk_release_kernel(sk); + sock_release(sk->sk_socket); } #endif diff --git a/include/net/sock.h b/include/net/sock.h index d8dcf91732b0..9e6b2c0b4741 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -184,6 +184,7 @@ struct sock_common { unsigned char skc_reuse:4; unsigned char skc_reuseport:1; unsigned char skc_ipv6only:1; + unsigned char skc_net_refcnt:1; int skc_bound_dev_if; union { struct hlist_node skc_bind_node; @@ -323,6 +324,7 @@ struct sock { #define sk_reuse __sk_common.skc_reuse #define sk_reuseport __sk_common.skc_reuseport #define sk_ipv6only __sk_common.skc_ipv6only +#define sk_net_refcnt __sk_common.skc_net_refcnt #define sk_bound_dev_if __sk_common.skc_bound_dev_if #define sk_bind_node __sk_common.skc_bind_node #define sk_prot __sk_common.skc_prot diff --git a/net/core/sock.c b/net/core/sock.c index cbc3789b830c..9e8968e9ebeb 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1412,7 +1412,10 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, */ sk->sk_prot = sk->sk_prot_creator = prot; sock_lock_init(sk); - sock_net_set(sk, get_net(net)); + sk->sk_net_refcnt = kern ? 0 : 1; + if (likely(sk->sk_net_refcnt)) + get_net(net); + sock_net_set(sk, net); atomic_set(&sk->sk_wmem_alloc, 1); sock_update_classid(sk); @@ -1446,7 +1449,8 @@ static void __sk_free(struct sock *sk) if (sk->sk_peer_cred) put_cred(sk->sk_peer_cred); put_pid(sk->sk_peer_pid); - put_net(sock_net(sk)); + if (likely(sk->sk_net_refcnt)) + put_net(sock_net(sk)); sk_prot_free(sk->sk_prot_creator, sk); } diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index e2dd9cb99d61..235d36afece3 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1430,7 +1430,7 @@ int inet_ctl_sock_create(struct sock **sk, unsigned short family, struct net *net) { struct socket *sock; - int rc = sock_create_kern(&init_net, family, type, protocol, &sock); + int rc = sock_create_kern(net, family, type, protocol, &sock); if (rc == 0) { *sk = sock->sk; @@ -1440,8 +1440,6 @@ int inet_ctl_sock_create(struct sock **sk, unsigned short family, * we do not wish this socket to see incoming packets. */ (*sk)->sk_prot->unhash(*sk); - - sk_change_net(*sk, net); } return rc; } diff --git a/net/ipv4/udp_tunnel.c b/net/ipv4/udp_tunnel.c index 4e2837476967..933ea903f7b8 100644 --- a/net/ipv4/udp_tunnel.c +++ b/net/ipv4/udp_tunnel.c @@ -15,12 +15,10 @@ int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg, struct socket *sock = NULL; struct sockaddr_in udp_addr; - err = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, 0, &sock); + err = sock_create_kern(net, AF_INET, SOCK_DGRAM, 0, &sock); if (err < 0) goto error; - sk_change_net(sock->sk, net); - udp_addr.sin_family = AF_INET; udp_addr.sin_addr = cfg->local_ip; udp_addr.sin_port = cfg->local_udp_port; @@ -47,7 +45,7 @@ int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg, error: if (sock) { kernel_sock_shutdown(sock, SHUT_RDWR); - sk_release_kernel(sock->sk); + sock_release(sock); } *sockp = NULL; return err; @@ -101,7 +99,7 @@ void udp_tunnel_sock_release(struct socket *sock) { rcu_assign_sk_user_data(sock->sk, NULL); kernel_sock_shutdown(sock, SHUT_RDWR); - sk_release_kernel(sock->sk); + sock_release(sock); } EXPORT_SYMBOL_GPL(udp_tunnel_sock_release); diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c index 478576b61214..e1a1136bda7c 100644 --- a/net/ipv6/ip6_udp_tunnel.c +++ b/net/ipv6/ip6_udp_tunnel.c @@ -19,12 +19,10 @@ int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg, int err; struct socket *sock = NULL; - err = sock_create_kern(&init_net, AF_INET6, SOCK_DGRAM, 0, &sock); + err = sock_create_kern(net, AF_INET6, SOCK_DGRAM, 0, &sock); if (err < 0) goto error; - sk_change_net(sock->sk, net); - udp6_addr.sin6_family = AF_INET6; memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6, sizeof(udp6_addr.sin6_addr)); @@ -55,7 +53,7 @@ int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg, error: if (sock) { kernel_sock_shutdown(sock, SHUT_RDWR); - sk_release_kernel(sock->sk); + sock_release(sock); } *sockp = NULL; return err; diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index ae513a2fe7f3..f6b090df3930 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1334,9 +1334,10 @@ static void l2tp_tunnel_del_work(struct work_struct *work) if (sock) inet_shutdown(sock, 2); } else { - if (sock) + if (sock) { kernel_sock_shutdown(sock, SHUT_RDWR); - sk_release_kernel(sk); + sock_release(sock); + } } l2tp_tunnel_sock_put(sk); @@ -1399,13 +1400,11 @@ static int l2tp_tunnel_sock_create(struct net *net, if (cfg->local_ip6 && cfg->peer_ip6) { struct sockaddr_l2tpip6 ip6_addr = {0}; - err = sock_create_kern(&init_net, AF_INET6, SOCK_DGRAM, + err = sock_create_kern(net, AF_INET6, SOCK_DGRAM, IPPROTO_L2TP, &sock); if (err < 0) goto out; - sk_change_net(sock->sk, net); - ip6_addr.l2tp_family = AF_INET6; memcpy(&ip6_addr.l2tp_addr, cfg->local_ip6, sizeof(ip6_addr.l2tp_addr)); @@ -1429,13 +1428,11 @@ static int l2tp_tunnel_sock_create(struct net *net, { struct sockaddr_l2tpip ip_addr = {0}; - err = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, + err = sock_create_kern(net, AF_INET, SOCK_DGRAM, IPPROTO_L2TP, &sock); if (err < 0) goto out; - sk_change_net(sock->sk, net); - ip_addr.l2tp_family = AF_INET; ip_addr.l2tp_addr = cfg->local_ip; ip_addr.l2tp_conn_id = tunnel_id; @@ -1462,7 +1459,7 @@ out: *sockp = sock; if ((err < 0) && sock) { kernel_sock_shutdown(sock, SHUT_RDWR); - sk_release_kernel(sock->sk); + sock_release(sock); *sockp = NULL; } diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 2e9a5b5d1239..b08ba9538d12 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -1457,18 +1457,12 @@ static struct socket *make_send_sock(struct net *net, int id) struct socket *sock; int result; - /* First create a socket move it to right name space later */ - result = sock_create_kern(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); + /* First create a socket */ + result = sock_create_kern(net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); if (result < 0) { pr_err("Error during creation of socket; terminating\n"); return ERR_PTR(result); } - /* - * Kernel sockets that are a part of a namespace, should not - * hold a reference to a namespace in order to allow to stop it. - * After sk_change_net should be released using sk_release_kernel. - */ - sk_change_net(sock->sk, net); result = set_mcast_if(sock->sk, ipvs->master_mcast_ifn); if (result < 0) { pr_err("Error setting outbound mcast interface\n"); @@ -1497,7 +1491,7 @@ static struct socket *make_send_sock(struct net *net, int id) return sock; error: - sk_release_kernel(sock->sk); + sock_release(sock); return ERR_PTR(result); } @@ -1518,17 +1512,11 @@ static struct socket *make_receive_sock(struct net *net, int id) int result; /* First create a socket */ - result = sock_create_kern(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); + result = sock_create_kern(net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); if (result < 0) { pr_err("Error during creation of socket; terminating\n"); return ERR_PTR(result); } - /* - * Kernel sockets that are a part of a namespace, should not - * hold a reference to a namespace in order to allow to stop it. - * After sk_change_net should be released using sk_release_kernel. - */ - sk_change_net(sock->sk, net); /* it is equivalent to the REUSEADDR option in user-space */ sock->sk->sk_reuse = SK_CAN_REUSE; result = sysctl_sync_sock_size(ipvs); @@ -1554,7 +1542,7 @@ static struct socket *make_receive_sock(struct net *net, int id) return sock; error: - sk_release_kernel(sock->sk); + sock_release(sock); return ERR_PTR(result); } @@ -1692,7 +1680,7 @@ done: ip_vs_sync_buff_release(sb); /* release the sending multicast socket */ - sk_release_kernel(tinfo->sock->sk); + sock_release(tinfo->sock); kfree(tinfo); return 0; @@ -1729,7 +1717,7 @@ static int sync_thread_backup(void *data) } /* release the sending multicast socket */ - sk_release_kernel(tinfo->sock->sk); + sock_release(tinfo->sock); kfree(tinfo->buf); kfree(tinfo); @@ -1854,11 +1842,11 @@ int start_sync_thread(struct net *net, int state, char *mcast_ifn, __u8 syncid) return 0; outsocket: - sk_release_kernel(sock->sk); + sock_release(sock); outtinfo: if (tinfo) { - sk_release_kernel(tinfo->sock->sk); + sock_release(tinfo->sock); kfree(tinfo->buf); kfree(tinfo); } -- cgit v1.2.3 From affb9792f1d99e1e4d64411e147b648d65f2576e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 8 May 2015 21:12:13 -0500 Subject: net: kill sk_change_net and sk_release_kernel These functions are no longer needed and no longer used kill them. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- include/net/sock.h | 17 ----------------- net/core/sock.c | 19 ------------------- 2 files changed, 36 deletions(-) (limited to 'include') diff --git a/include/net/sock.h b/include/net/sock.h index 9e6b2c0b4741..d882f4c8e438 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1518,7 +1518,6 @@ static inline void unlock_sock_fast(struct sock *sk, bool slow) struct sock *sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot, int kern); void sk_free(struct sock *sk); -void sk_release_kernel(struct sock *sk); struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority); struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, @@ -2194,22 +2193,6 @@ void sock_net_set(struct sock *sk, struct net *net) write_pnet(&sk->sk_net, net); } -/* - * Kernel sockets, f.e. rtnl or icmp_socket, are a part of a namespace. - * They should not hold a reference to a namespace in order to allow - * to stop it. - * Sockets after sk_change_net should be released using sk_release_kernel - */ -static inline void sk_change_net(struct sock *sk, struct net *net) -{ - struct net *current_net = sock_net(sk); - - if (!net_eq(current_net, net)) { - put_net(current_net); - sock_net_set(sk, net); - } -} - static inline struct sock *skb_steal_sock(struct sk_buff *skb) { if (skb->sk) { diff --git a/net/core/sock.c b/net/core/sock.c index 9e8968e9ebeb..c18738a795b0 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1466,25 +1466,6 @@ void sk_free(struct sock *sk) } EXPORT_SYMBOL(sk_free); -/* - * Last sock_put should drop reference to sk->sk_net. It has already - * been dropped in sk_change_net. Taking reference to stopping namespace - * is not an option. - * Take reference to a socket to remove it from hash _alive_ and after that - * destroy it in the context of init_net. - */ -void sk_release_kernel(struct sock *sk) -{ - if (sk == NULL || sk->sk_socket == NULL) - return; - - sock_hold(sk); - sock_net_set(sk, get_net(&init_net)); - sock_release(sk->sk_socket); - sock_put(sk); -} -EXPORT_SYMBOL(sk_release_kernel); - static void sk_update_clone(const struct sock *sk, struct sock *newsk) { if (mem_cgroup_sockets_enabled && sk->sk_cgrp) -- cgit v1.2.3 From 6791e4661c4bd3e9f193a84247f2c389578a4336 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Sat, 9 May 2015 00:01:55 -0700 Subject: bonding: Allow userspace to set actors' system_priority in AD system This patch allows user to randomize the system-priority in an ad-system. The allowed range is 1 - 0xFFFF while default value is 0xFFFF. If user does not specify this value, the system defaults to 0xFFFF, which is what it was before this patch. Following example code could set the value - # modprobe bonding mode=4 # sys_prio=$(( 1 + RANDOM + RANDOM )) # echo $sys_prio > /sys/class/net/bond0/bonding/ad_actor_sys_prio # echo +eth1 > /sys/class/net/bond0/bonding/slaves ... # ip link set bond0 up Signed-off-by: Mahesh Bandewar Reviewed-by: Nikolay Aleksandrov [jt: * fixed up style issues reported by checkpatch * changed how the default value is set in bond_check_params(), this makes the default consistent between what gets set for a new bond and what the default is claimed to be in the bonding options.] Signed-off-by: Jonathan Toppins Signed-off-by: David S. Miller --- Documentation/networking/bonding.txt | 9 +++++++++ drivers/net/bonding/bond_3ad.c | 5 ++++- drivers/net/bonding/bond_main.c | 12 ++++++++++++ drivers/net/bonding/bond_options.c | 28 +++++++++++++++++++++++++++- drivers/net/bonding/bond_procfs.c | 2 ++ drivers/net/bonding/bond_sysfs.c | 15 +++++++++++++++ include/net/bond_options.h | 1 + include/net/bonding.h | 1 + 8 files changed, 71 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index 83bf4986baea..34946115acec 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -178,6 +178,15 @@ active_slave active slave, or the empty string if there is no active slave or the current mode does not use an active slave. +ad_actor_sys_prio + + In an AD system, this specifies the system priority. The allowed range + is 1 - 65535. If the value is not specified, it takes 65535 as the + default value. + + This parameter has effect only in 802.3ad mode and is available through + SysFs interface. + ad_select Specifies the 802.3ad aggregation selection logic to use. The diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index fbd54f0e32e8..4c003bc87d4b 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1908,7 +1908,8 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution) BOND_AD_INFO(bond).aggregator_identifier = 0; - BOND_AD_INFO(bond).system.sys_priority = 0xFFFF; + BOND_AD_INFO(bond).system.sys_priority = + bond->params.ad_actor_sys_prio; BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr); /* initialize how many times this module is called in one @@ -1959,6 +1960,8 @@ void bond_3ad_bind_slave(struct slave *slave) port->sm_vars &= ~AD_PORT_LACP_ENABLED; /* actor system is the bond's system */ port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr; + port->actor_system_priority = + BOND_AD_INFO(bond).system.sys_priority; /* tx timer(to verify that no more than MAX_TX_IN_SECOND * lacpdu's are sent in one second) */ diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d5fe5d5f490f..5f2f28f0e927 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4140,6 +4140,7 @@ static int bond_check_params(struct bond_params *params) struct bond_opt_value newval; const struct bond_opt_value *valptr; int arp_all_targets_value; + u16 ad_actor_sys_prio = 0; /* Convert string parameters. */ if (mode) { @@ -4434,6 +4435,16 @@ static int bond_check_params(struct bond_params *params) fail_over_mac_value = BOND_FOM_NONE; } + bond_opt_initstr(&newval, "default"); + valptr = bond_opt_parse( + bond_opt_get(BOND_OPT_AD_ACTOR_SYS_PRIO), + &newval); + if (!valptr) { + pr_err("Error: No ad_actor_sys_prio default value"); + return -EINVAL; + } + ad_actor_sys_prio = valptr->value; + if (lp_interval == 0) { pr_warn("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n", INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL); @@ -4462,6 +4473,7 @@ static int bond_check_params(struct bond_params *params) params->lp_interval = lp_interval; params->packets_per_slave = packets_per_slave; params->tlb_dynamic_lb = 1; /* Default value */ + params->ad_actor_sys_prio = ad_actor_sys_prio; if (packets_per_slave > 0) { params->reciprocal_packets_per_slave = reciprocal_value(packets_per_slave); diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 4df28943d222..d2b47e5e99f7 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -70,6 +70,8 @@ static int bond_option_slaves_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, const struct bond_opt_value *newval); +static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, + const struct bond_opt_value *newval); static const struct bond_opt_value bond_mode_tbl[] = { @@ -186,6 +188,12 @@ static const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = { { NULL, -1, 0} }; +static const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = { + { "minval", 1, BOND_VALFLAG_MIN}, + { "maxval", 65535, BOND_VALFLAG_MAX | BOND_VALFLAG_DEFAULT}, + { NULL, -1, 0}, +}; + static const struct bond_option bond_opts[BOND_OPT_LAST] = { [BOND_OPT_MODE] = { .id = BOND_OPT_MODE, @@ -379,7 +387,15 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { .values = bond_tlb_dynamic_lb_tbl, .flags = BOND_OPTFLAG_IFDOWN, .set = bond_option_tlb_dynamic_lb_set, - } + }, + [BOND_OPT_AD_ACTOR_SYS_PRIO] = { + .id = BOND_OPT_AD_ACTOR_SYS_PRIO, + .name = "ad_actor_sys_prio", + .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), + .flags = BOND_OPTFLAG_IFDOWN, + .values = bond_ad_actor_sys_prio_tbl, + .set = bond_option_ad_actor_sys_prio_set, + }, }; /* Searches for an option by name */ @@ -1349,3 +1365,13 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, return 0; } + +static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, + const struct bond_opt_value *newval) +{ + netdev_info(bond->dev, "Setting ad_actor_sys_prio to (%llu)\n", + newval->value); + + bond->params.ad_actor_sys_prio = newval->value; + return 0; +} diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index b20b35acb47d..11369299e7e5 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -135,6 +135,8 @@ static void bond_info_show_master(struct seq_file *seq) bond->params.ad_select); seq_printf(seq, "Aggregator selection policy (ad_select): %s\n", optval->string); + seq_printf(seq, "System priority: %d\n", + BOND_AD_INFO(bond).system.sys_priority); if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { seq_printf(seq, "bond %s has no active aggregator\n", diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 7e9e151d4d61..4a7626611ca6 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -692,6 +692,20 @@ static ssize_t bonding_show_packets_per_slave(struct device *d, static DEVICE_ATTR(packets_per_slave, S_IRUGO | S_IWUSR, bonding_show_packets_per_slave, bonding_sysfs_store_option); +static ssize_t bonding_show_ad_actor_sys_prio(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + + if (BOND_MODE(bond) == BOND_MODE_8023AD) + return sprintf(buf, "%hu\n", bond->params.ad_actor_sys_prio); + + return 0; +} +static DEVICE_ATTR(ad_actor_sys_prio, S_IRUGO | S_IWUSR, + bonding_show_ad_actor_sys_prio, bonding_sysfs_store_option); + static struct attribute *per_bond_attrs[] = { &dev_attr_slaves.attr, &dev_attr_mode.attr, @@ -725,6 +739,7 @@ static struct attribute *per_bond_attrs[] = { &dev_attr_lp_interval.attr, &dev_attr_packets_per_slave.attr, &dev_attr_tlb_dynamic_lb.attr, + &dev_attr_ad_actor_sys_prio.attr, NULL, }; diff --git a/include/net/bond_options.h b/include/net/bond_options.h index ea6546d2c946..894002a2620f 100644 --- a/include/net/bond_options.h +++ b/include/net/bond_options.h @@ -63,6 +63,7 @@ enum { BOND_OPT_LP_INTERVAL, BOND_OPT_SLAVES, BOND_OPT_TLB_DYNAMIC_LB, + BOND_OPT_AD_ACTOR_SYS_PRIO, BOND_OPT_LAST }; diff --git a/include/net/bonding.h b/include/net/bonding.h index 78ed135e9dea..405cf87a450a 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -136,6 +136,7 @@ struct bond_params { int packets_per_slave; int tlb_dynamic_lb; struct reciprocal_value reciprocal_packets_per_slave; + u16 ad_actor_sys_prio; }; struct bond_parm_tbl { -- cgit v1.2.3 From 74514957552edd4661a4608618121f3c71d4e891 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Sat, 9 May 2015 00:01:56 -0700 Subject: bonding: Allow userspace to set actors' macaddr in an AD-system. In an AD system, the communication between actor and partner is the business between these two entities. In the current setup anyone on the same L2 can "guess" the LACPDU contents and then possibly send the spoofed LACPDUs and trick the partner causing connectivity issues for the AD system. This patch allows to use a random mac-address obscuring it's identity making it harder for someone in the L2 is do the same thing. This patch allows user-space to choose the mac-address for the AD-system. This mac-address can not be NULL or a Multicast. If the mac-address is set from user-space; kernel will honor it and will not overwrite it. In the absence (value from user space); the logic will default to using the masters' mac as the mac-address for the AD-system. It can be set using example code below - # modprobe bonding mode=4 # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \ $(( (RANDOM & 0xFE) | 0x02 )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF ))) # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system # echo +eth1 > /sys/class/net/bond0/bonding/slaves ... # ip link set bond0 up Signed-off-by: Mahesh Bandewar Reviewed-by: Nikolay Aleksandrov [jt: fixed up style issues reported by checkpatch] Signed-off-by: Jonathan Toppins Signed-off-by: David S. Miller --- Documentation/networking/bonding.txt | 12 ++++++++++++ drivers/net/bonding/bond_3ad.c | 7 ++++++- drivers/net/bonding/bond_main.c | 1 + drivers/net/bonding/bond_options.c | 27 +++++++++++++++++++++++++++ drivers/net/bonding/bond_procfs.c | 6 ++++++ drivers/net/bonding/bond_sysfs.c | 16 ++++++++++++++++ include/net/bond_options.h | 1 + include/net/bonding.h | 1 + 8 files changed, 70 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index 34946115acec..2c197b68baf0 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -187,6 +187,18 @@ ad_actor_sys_prio This parameter has effect only in 802.3ad mode and is available through SysFs interface. +ad_actor_system + + In an AD system, this specifies the mac-address for the actor in + protocol packet exchanges (LACPDUs). The value cannot be NULL or + multicast. It is preferred to have the local-admin bit set for this + mac but driver does not enforce it. If the value is not given then + system defaults to using the masters' mac address as actors' system + address. + + This parameter has effect only in 802.3ad mode and is available through + SysFs interface. + ad_select Specifies the 802.3ad aggregation selection logic to use. The diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 4c003bc87d4b..012f7bc22d91 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1910,7 +1910,12 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution) BOND_AD_INFO(bond).system.sys_priority = bond->params.ad_actor_sys_prio; - BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr); + if (is_zero_ether_addr(bond->params.ad_actor_system)) + BOND_AD_INFO(bond).system.sys_mac_addr = + *((struct mac_addr *)bond->dev->dev_addr); + else + BOND_AD_INFO(bond).system.sys_mac_addr = + *((struct mac_addr *)bond->params.ad_actor_system); /* initialize how many times this module is called in one * second (should be about every 100ms) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 5f2f28f0e927..a4e2f27ef683 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4474,6 +4474,7 @@ static int bond_check_params(struct bond_params *params) params->packets_per_slave = packets_per_slave; params->tlb_dynamic_lb = 1; /* Default value */ params->ad_actor_sys_prio = ad_actor_sys_prio; + eth_zero_addr(params->ad_actor_system); if (packets_per_slave > 0) { params->reciprocal_packets_per_slave = reciprocal_value(packets_per_slave); diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index d2b47e5e99f7..cdcef217ac84 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -72,6 +72,8 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, const struct bond_opt_value *newval); +static int bond_option_ad_actor_system_set(struct bonding *bond, + const struct bond_opt_value *newval); static const struct bond_opt_value bond_mode_tbl[] = { @@ -396,6 +398,13 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { .values = bond_ad_actor_sys_prio_tbl, .set = bond_option_ad_actor_sys_prio_set, }, + [BOND_OPT_AD_ACTOR_SYSTEM] = { + .id = BOND_OPT_AD_ACTOR_SYSTEM, + .name = "ad_actor_system", + .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), + .flags = BOND_OPTFLAG_RAWVAL | BOND_OPTFLAG_IFDOWN, + .set = bond_option_ad_actor_system_set, + }, }; /* Searches for an option by name */ @@ -1375,3 +1384,21 @@ static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, bond->params.ad_actor_sys_prio = newval->value; return 0; } + +static int bond_option_ad_actor_system_set(struct bonding *bond, + const struct bond_opt_value *newval) +{ + u8 macaddr[ETH_ALEN]; + int i; + + i = sscanf(newval->string, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &macaddr[0], &macaddr[1], &macaddr[2], + &macaddr[3], &macaddr[4], &macaddr[5]); + if (i != ETH_ALEN || !is_valid_ether_addr(macaddr)) { + netdev_err(bond->dev, "Invalid MAC address.\n"); + return -EINVAL; + } + + ether_addr_copy(bond->params.ad_actor_system, macaddr); + return 0; +} diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index 11369299e7e5..e7f3047a26df 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -137,6 +137,8 @@ static void bond_info_show_master(struct seq_file *seq) optval->string); seq_printf(seq, "System priority: %d\n", BOND_AD_INFO(bond).system.sys_priority); + seq_printf(seq, "System MAC address: %pM\n", + &BOND_AD_INFO(bond).system.sys_mac_addr); if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { seq_printf(seq, "bond %s has no active aggregator\n", @@ -200,6 +202,8 @@ static void bond_info_show_slave(struct seq_file *seq, seq_puts(seq, "details actor lacp pdu:\n"); seq_printf(seq, " system priority: %d\n", port->actor_system_priority); + seq_printf(seq, " system mac address: %pM\n", + &port->actor_system); seq_printf(seq, " port key: %d\n", port->actor_oper_port_key); seq_printf(seq, " port priority: %d\n", @@ -212,6 +216,8 @@ static void bond_info_show_slave(struct seq_file *seq, seq_puts(seq, "details partner lacp pdu:\n"); seq_printf(seq, " system priority: %d\n", port->partner_oper.system_priority); + seq_printf(seq, " system mac address: %pM\n", + &port->partner_oper.system); seq_printf(seq, " oper key: %d\n", port->partner_oper.key); seq_printf(seq, " port priority: %d\n", diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 4a7626611ca6..09fefa50d055 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -706,6 +706,21 @@ static ssize_t bonding_show_ad_actor_sys_prio(struct device *d, static DEVICE_ATTR(ad_actor_sys_prio, S_IRUGO | S_IWUSR, bonding_show_ad_actor_sys_prio, bonding_sysfs_store_option); +static ssize_t bonding_show_ad_actor_system(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + + if (BOND_MODE(bond) == BOND_MODE_8023AD) + return sprintf(buf, "%pM\n", bond->params.ad_actor_system); + + return 0; +} + +static DEVICE_ATTR(ad_actor_system, S_IRUGO | S_IWUSR, + bonding_show_ad_actor_system, bonding_sysfs_store_option); + static struct attribute *per_bond_attrs[] = { &dev_attr_slaves.attr, &dev_attr_mode.attr, @@ -740,6 +755,7 @@ static struct attribute *per_bond_attrs[] = { &dev_attr_packets_per_slave.attr, &dev_attr_tlb_dynamic_lb.attr, &dev_attr_ad_actor_sys_prio.attr, + &dev_attr_ad_actor_system.attr, NULL, }; diff --git a/include/net/bond_options.h b/include/net/bond_options.h index 894002a2620f..eeeefa1d3cd8 100644 --- a/include/net/bond_options.h +++ b/include/net/bond_options.h @@ -64,6 +64,7 @@ enum { BOND_OPT_SLAVES, BOND_OPT_TLB_DYNAMIC_LB, BOND_OPT_AD_ACTOR_SYS_PRIO, + BOND_OPT_AD_ACTOR_SYSTEM, BOND_OPT_LAST }; diff --git a/include/net/bonding.h b/include/net/bonding.h index 405cf87a450a..650f38693956 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -137,6 +137,7 @@ struct bond_params { int tlb_dynamic_lb; struct reciprocal_value reciprocal_packets_per_slave; u16 ad_actor_sys_prio; + u8 ad_actor_system[ETH_ALEN]; }; struct bond_parm_tbl { -- cgit v1.2.3 From d22a5fc0c32edcf5c3bb973ee8c9a2606ba500a8 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Sat, 9 May 2015 00:01:57 -0700 Subject: bonding: Implement user key part of port_key in an AD system. The port key has three components - user-key, speed-part, and duplex-part. The LSBit is for the duplex-part, next 5 bits are for the speed while the remaining 10 bits are the user defined key bits. Get these 10 bits from the user-space (through the SysFs interface) and use it to form the admin port-key. Allowed range for the user-key is 0 - 1023 (10 bits). If it is not provided then use zero for the user-key-bits (default). It can set using following example code - # modprobe bonding mode=4 # usr_port_key=$(( RANDOM & 0x3FF )) # echo $usr_port_key > /sys/class/net/bond0/bonding/ad_user_port_key # echo +eth1 > /sys/class/net/bond0/bonding/slaves ... # ip link set bond0 up Signed-off-by: Mahesh Bandewar Reviewed-by: Nikolay Aleksandrov [jt: * fixed up style issues reported by checkpatch * fixed up context from change in ad_actor_sys_prio patch] Signed-off-by: Jonathan Toppins Signed-off-by: David S. Miller --- Documentation/networking/bonding.txt | 63 ++++++++++++++++++++++++++++++++++++ drivers/net/bonding/bond_3ad.c | 14 ++++---- drivers/net/bonding/bond_main.c | 10 ++++++ drivers/net/bonding/bond_options.c | 26 +++++++++++++++ drivers/net/bonding/bond_sysfs.c | 15 +++++++++ include/net/bond_options.h | 1 + include/net/bonding.h | 1 + 7 files changed, 123 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index 2c197b68baf0..334b49ef02d1 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -51,6 +51,7 @@ Table of Contents 3.4 Configuring Bonding Manually via Sysfs 3.5 Configuration with Interfaces Support 3.6 Overriding Configuration for Special Cases +3.7 Configuring LACP for 802.3ad mode in a more secure way 4. Querying Bonding Configuration 4.1 Bonding Configuration @@ -241,6 +242,21 @@ ad_select This option was added in bonding version 3.4.0. +ad_user_port_key + + In an AD system, the port-key has three parts as shown below - + + Bits Use + 00 Duplex + 01-05 Speed + 06-15 User-defined + + This defines the upper 10 bits of the port key. The values can be + from 0 - 1023. If not given, the system defaults to 0. + + This parameter has effect only in 802.3ad mode and is available through + SysFs interface. + all_slaves_active Specifies that duplicate frames (received on inactive ports) should be @@ -1643,6 +1659,53 @@ output port selection. This feature first appeared in bonding driver version 3.7.0 and support for output slave selection was limited to round-robin and active-backup modes. +3.7 Configuring LACP for 802.3ad mode in a more secure way +---------------------------------------------------------- + +When using 802.3ad bonding mode, the Actor (host) and Partner (switch) +exchange LACPDUs. These LACPDUs cannot be sniffed, because they are +destined to link local mac addresses (which switches/bridges are not +supposed to forward). However, most of the values are easily predictable +or are simply the machine's MAC address (which is trivially known to all +other hosts in the same L2). This implies that other machines in the L2 +domain can spoof LACPDU packets from other hosts to the switch and potentially +cause mayhem by joining (from the point of view of the switch) another +machine's aggregate, thus receiving a portion of that hosts incoming +traffic and / or spoofing traffic from that machine themselves (potentially +even successfully terminating some portion of flows). Though this is not +a likely scenario, one could avoid this possibility by simply configuring +few bonding parameters: + + (a) ad_actor_system : You can set a random mac-address that can be used for + these LACPDU exchanges. The value can not be either NULL or Multicast. + Also it's preferable to set the local-admin bit. Following shell code + generates a random mac-address as described above. + + # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \ + $(( (RANDOM & 0xFE) | 0x02 )) \ + $(( RANDOM & 0xFF )) \ + $(( RANDOM & 0xFF )) \ + $(( RANDOM & 0xFF )) \ + $(( RANDOM & 0xFF )) \ + $(( RANDOM & 0xFF ))) + # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system + + (b) ad_actor_sys_prio : Randomize the system priority. The default value + is 65535, but system can take the value from 1 - 65535. Following shell + code generates random priority and sets it. + + # sys_prio=$(( 1 + RANDOM + RANDOM )) + # echo $sys_prio > /sys/class/net/bond0/bonding/ad_actor_sys_prio + + (c) ad_user_port_key : Use the user portion of the port-key. The default + keeps this empty. These are the upper 10 bits of the port-key and value + ranges from 0 - 1023. Following shell code generates these 10 bits and + sets it. + + # usr_port_key=$(( RANDOM & 0x3FF )) + # echo $usr_port_key > /sys/class/net/bond0/bonding/ad_user_port_key + + 4 Querying Bonding Configuration ================================= diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 012f7bc22d91..7fde4d5c2b28 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -75,10 +75,10 @@ /* Port Key definitions * key is determined according to the link speed, duplex and * user key (which is yet not supported) - * -------------------------------------------------------------- - * Port key : | User key | Speed | Duplex | - * -------------------------------------------------------------- - * 16 6 1 0 + * -------------------------------------------------------------- + * Port key | User key (10 bits) | Speed (5 bits) | Duplex| + * -------------------------------------------------------------- + * |15 6|5 1|0 */ #define AD_DUPLEX_KEY_MASKS 0x1 #define AD_SPEED_KEY_MASKS 0x3E @@ -1951,10 +1951,10 @@ void bond_3ad_bind_slave(struct slave *slave) port->slave = slave; port->actor_port_number = SLAVE_AD_INFO(slave)->id; - /* key is determined according to the link speed, duplex and user key(which - * is yet not supported) + /* key is determined according to the link speed, duplex and + * user key */ - port->actor_admin_port_key = 0; + port->actor_admin_port_key = bond->params.ad_user_port_key << 6; port->actor_admin_port_key |= __get_duplex(port); port->actor_admin_port_key |= (__get_link_speed(port) << 1); port->actor_oper_port_key = port->actor_admin_port_key; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a4e2f27ef683..2ee13be7551b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4141,6 +4141,7 @@ static int bond_check_params(struct bond_params *params) const struct bond_opt_value *valptr; int arp_all_targets_value; u16 ad_actor_sys_prio = 0; + u16 ad_user_port_key = 0; /* Convert string parameters. */ if (mode) { @@ -4445,6 +4446,14 @@ static int bond_check_params(struct bond_params *params) } ad_actor_sys_prio = valptr->value; + valptr = bond_opt_parse(bond_opt_get(BOND_OPT_AD_USER_PORT_KEY), + &newval); + if (!valptr) { + pr_err("Error: No ad_user_port_key default value"); + return -EINVAL; + } + ad_user_port_key = valptr->value; + if (lp_interval == 0) { pr_warn("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n", INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL); @@ -4475,6 +4484,7 @@ static int bond_check_params(struct bond_params *params) params->tlb_dynamic_lb = 1; /* Default value */ params->ad_actor_sys_prio = ad_actor_sys_prio; eth_zero_addr(params->ad_actor_system); + params->ad_user_port_key = ad_user_port_key; if (packets_per_slave > 0) { params->reciprocal_packets_per_slave = reciprocal_value(packets_per_slave); diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index cdcef217ac84..c85da05721e6 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -74,6 +74,8 @@ static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_ad_actor_system_set(struct bonding *bond, const struct bond_opt_value *newval); +static int bond_option_ad_user_port_key_set(struct bonding *bond, + const struct bond_opt_value *newval); static const struct bond_opt_value bond_mode_tbl[] = { @@ -196,6 +198,12 @@ static const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = { { NULL, -1, 0}, }; +static const struct bond_opt_value bond_ad_user_port_key_tbl[] = { + { "minval", 0, BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT}, + { "maxval", 1023, BOND_VALFLAG_MAX}, + { NULL, -1, 0}, +}; + static const struct bond_option bond_opts[BOND_OPT_LAST] = { [BOND_OPT_MODE] = { .id = BOND_OPT_MODE, @@ -405,6 +413,14 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { .flags = BOND_OPTFLAG_RAWVAL | BOND_OPTFLAG_IFDOWN, .set = bond_option_ad_actor_system_set, }, + [BOND_OPT_AD_USER_PORT_KEY] = { + .id = BOND_OPT_AD_USER_PORT_KEY, + .name = "ad_user_port_key", + .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), + .flags = BOND_OPTFLAG_IFDOWN, + .values = bond_ad_user_port_key_tbl, + .set = bond_option_ad_user_port_key_set, + } }; /* Searches for an option by name */ @@ -1402,3 +1418,13 @@ static int bond_option_ad_actor_system_set(struct bonding *bond, ether_addr_copy(bond->params.ad_actor_system, macaddr); return 0; } + +static int bond_option_ad_user_port_key_set(struct bonding *bond, + const struct bond_opt_value *newval) +{ + netdev_info(bond->dev, "Setting ad_user_port_key to (%llu)\n", + newval->value); + + bond->params.ad_user_port_key = newval->value; + return 0; +} diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 09fefa50d055..143a2abd1c1c 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -721,6 +721,20 @@ static ssize_t bonding_show_ad_actor_system(struct device *d, static DEVICE_ATTR(ad_actor_system, S_IRUGO | S_IWUSR, bonding_show_ad_actor_system, bonding_sysfs_store_option); +static ssize_t bonding_show_ad_user_port_key(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + + if (BOND_MODE(bond) == BOND_MODE_8023AD) + return sprintf(buf, "%hu\n", bond->params.ad_user_port_key); + + return 0; +} +static DEVICE_ATTR(ad_user_port_key, S_IRUGO | S_IWUSR, + bonding_show_ad_user_port_key, bonding_sysfs_store_option); + static struct attribute *per_bond_attrs[] = { &dev_attr_slaves.attr, &dev_attr_mode.attr, @@ -756,6 +770,7 @@ static struct attribute *per_bond_attrs[] = { &dev_attr_tlb_dynamic_lb.attr, &dev_attr_ad_actor_sys_prio.attr, &dev_attr_ad_actor_system.attr, + &dev_attr_ad_user_port_key.attr, NULL, }; diff --git a/include/net/bond_options.h b/include/net/bond_options.h index eeeefa1d3cd8..c28aca25320e 100644 --- a/include/net/bond_options.h +++ b/include/net/bond_options.h @@ -65,6 +65,7 @@ enum { BOND_OPT_TLB_DYNAMIC_LB, BOND_OPT_AD_ACTOR_SYS_PRIO, BOND_OPT_AD_ACTOR_SYSTEM, + BOND_OPT_AD_USER_PORT_KEY, BOND_OPT_LAST }; diff --git a/include/net/bonding.h b/include/net/bonding.h index 650f38693956..20defc0353d1 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -137,6 +137,7 @@ struct bond_params { int tlb_dynamic_lb; struct reciprocal_value reciprocal_packets_per_slave; u16 ad_actor_sys_prio; + u16 ad_user_port_key; u8 ad_actor_system[ETH_ALEN]; }; -- cgit v1.2.3 From 171a42c38c6e1a5a076d6276e94e55a0b5b7868c Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Sat, 9 May 2015 00:01:58 -0700 Subject: bonding: add netlink support for sys prio, actor sys mac, and port key Adds netlink support for the following bonding options: * BOND_OPT_AD_ACTOR_SYS_PRIO * BOND_OPT_AD_ACTOR_SYSTEM * BOND_OPT_AD_USER_PORT_KEY When setting the actor system mac address we assume the netlink message contains a binary mac and not a string representation of a mac. Signed-off-by: Andy Gospodarek [jt: completed the setting side of the netlink attributes] Signed-off-by: Jonathan Toppins Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 50 ++++++++++++++++++++++++++++++++++++++ drivers/net/bonding/bond_options.c | 30 ++++++++++++++++------- include/uapi/linux/if_link.h | 3 +++ 3 files changed, 74 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 7b1124366011..f7015eb4f8db 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -94,6 +94,10 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_AD_LACP_RATE] = { .type = NLA_U8 }, [IFLA_BOND_AD_SELECT] = { .type = NLA_U8 }, [IFLA_BOND_AD_INFO] = { .type = NLA_NESTED }, + [IFLA_BOND_AD_ACTOR_SYS_PRIO] = { .type = NLA_U16 }, + [IFLA_BOND_AD_USER_PORT_KEY] = { .type = NLA_U16 }, + [IFLA_BOND_AD_ACTOR_SYSTEM] = { .type = NLA_BINARY, + .len = ETH_ALEN }, }; static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { @@ -379,6 +383,36 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } + if (data[IFLA_BOND_AD_ACTOR_SYS_PRIO]) { + int actor_sys_prio = + nla_get_u16(data[IFLA_BOND_AD_ACTOR_SYS_PRIO]); + + bond_opt_initval(&newval, actor_sys_prio); + err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYS_PRIO, &newval); + if (err) + return err; + } + + if (data[IFLA_BOND_AD_USER_PORT_KEY]) { + int port_key = + nla_get_u16(data[IFLA_BOND_AD_USER_PORT_KEY]); + + bond_opt_initval(&newval, port_key); + err = __bond_opt_set(bond, BOND_OPT_AD_USER_PORT_KEY, &newval); + if (err) + return err; + } + + if (data[IFLA_BOND_AD_ACTOR_SYSTEM]) { + if (nla_len(data[IFLA_BOND_AD_ACTOR_SYSTEM]) != ETH_ALEN) + return -EINVAL; + + bond_opt_initval(&newval, + nla_get_be64(data[IFLA_BOND_AD_ACTOR_SYSTEM])); + err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYSTEM, &newval); + if (err) + return err; + } return 0; } @@ -426,6 +460,9 @@ static size_t bond_get_size(const struct net_device *bond_dev) nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_ACTOR_KEY */ nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_PARTNER_KEY*/ nla_total_size(ETH_ALEN) + /* IFLA_BOND_AD_INFO_PARTNER_MAC*/ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_ACTOR_SYS_PRIO */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_USER_PORT_KEY */ + nla_total_size(ETH_ALEN) + /* IFLA_BOND_AD_ACTOR_SYSTEM */ 0; } @@ -551,6 +588,19 @@ static int bond_fill_info(struct sk_buff *skb, if (BOND_MODE(bond) == BOND_MODE_8023AD) { struct ad_info info; + if (nla_put_u16(skb, IFLA_BOND_AD_ACTOR_SYS_PRIO, + bond->params.ad_actor_sys_prio)) + goto nla_put_failure; + + if (nla_put_u16(skb, IFLA_BOND_AD_USER_PORT_KEY, + bond->params.ad_user_port_key)) + goto nla_put_failure; + + if (nla_put(skb, IFLA_BOND_AD_ACTOR_SYSTEM, + sizeof(bond->params.ad_actor_system), + &bond->params.ad_actor_system)) + goto nla_put_failure; + if (!bond_3ad_get_active_agg_info(bond, &info)) { struct nlattr *nest; diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index c85da05721e6..9a32bbd7724e 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -1394,7 +1394,7 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting ad_actor_sys_prio to (%llu)\n", + netdev_info(bond->dev, "Setting ad_actor_sys_prio to %llu\n", newval->value); bond->params.ad_actor_sys_prio = newval->value; @@ -1405,24 +1405,36 @@ static int bond_option_ad_actor_system_set(struct bonding *bond, const struct bond_opt_value *newval) { u8 macaddr[ETH_ALEN]; + u8 *mac; int i; - i = sscanf(newval->string, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", - &macaddr[0], &macaddr[1], &macaddr[2], - &macaddr[3], &macaddr[4], &macaddr[5]); - if (i != ETH_ALEN || !is_valid_ether_addr(macaddr)) { - netdev_err(bond->dev, "Invalid MAC address.\n"); - return -EINVAL; + if (newval->string) { + i = sscanf(newval->string, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &macaddr[0], &macaddr[1], &macaddr[2], + &macaddr[3], &macaddr[4], &macaddr[5]); + if (i != ETH_ALEN) + goto err; + mac = macaddr; + } else { + mac = (u8 *)&newval->value; } - ether_addr_copy(bond->params.ad_actor_system, macaddr); + if (!is_valid_ether_addr(mac)) + goto err; + + netdev_info(bond->dev, "Setting ad_actor_system to %pM\n", mac); + ether_addr_copy(bond->params.ad_actor_system, mac); return 0; + +err: + netdev_err(bond->dev, "Invalid MAC address.\n"); + return -EINVAL; } static int bond_option_ad_user_port_key_set(struct bonding *bond, const struct bond_opt_value *newval) { - netdev_info(bond->dev, "Setting ad_user_port_key to (%llu)\n", + netdev_info(bond->dev, "Setting ad_user_port_key to %llu\n", newval->value); bond->params.ad_user_port_key = newval->value; diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index d9cd19214b98..6d6e502e1051 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -417,6 +417,9 @@ enum { IFLA_BOND_AD_LACP_RATE, IFLA_BOND_AD_SELECT, IFLA_BOND_AD_INFO, + IFLA_BOND_AD_ACTOR_SYS_PRIO, + IFLA_BOND_AD_USER_PORT_KEY, + IFLA_BOND_AD_ACTOR_SYSTEM, __IFLA_BOND_MAX, }; -- cgit v1.2.3 From d2788d34885d4ce5ba17a8996fd95d28942e574e Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 9 May 2015 22:51:32 +0200 Subject: net: sched: further simplify handle_ing Ingress qdisc has no other purpose than calling into tc_classify() that executes attached classifier(s) and action(s). It has a 1:1 relationship to dev->ingress_queue. After having commit 087c1a601ad7 ("net: sched: run ingress qdisc without locks") removed the central ingress lock, one major contention point is gone. The extra indirection layers however, are not necessary for calling into ingress qdisc. pktgen calling locally into netif_receive_skb() with a dummy u32, single CPU result on a Supermicro X10SLM-F, Xeon E3-1240: before ~21,1 Mpps, after patch ~22,9 Mpps. We can redirect the private classifier list to the netdev directly, without changing any classifier API bits (!) and execute on that from handle_ing() side. The __QDISC_STATE_DEACTIVATE test can be removed, ingress qdisc doesn't have a queue and thus dev_deactivate_queue() is also not applicable, ingress_cl_list provides similar behaviour. In other words, ingress qdisc acts like TCQ_F_BUILTIN qdisc. One next possible step is the removal of the dev's ingress (dummy) netdev_queue, and to only have the list member in the netdevice itself. Note, the filter chain is RCU protected and individual filter elements are being kfree'd by sched subsystem after RCU grace period. RCU read lock is being held by __netif_receive_skb_core(). Joint work with Alexei Starovoitov. Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/netdevice.h | 4 ++++ net/core/dev.c | 30 ++++++++++++++---------- net/sched/sch_ingress.c | 58 ++++++++--------------------------------------- 3 files changed, 31 insertions(+), 61 deletions(-) (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1899c74a7127..c4e1caf6056f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1655,7 +1655,11 @@ struct net_device { rx_handler_func_t __rcu *rx_handler; void __rcu *rx_handler_data; +#if CONFIG_NET_CLS_ACT + struct tcf_proto __rcu *ingress_cl_list; +#endif struct netdev_queue __rcu *ingress_queue; + unsigned char broadcast[MAX_ADDR_LEN]; #ifdef CONFIG_RFS_ACCEL struct cpu_rmap *rx_cpu_rmap; diff --git a/net/core/dev.c b/net/core/dev.c index 8a757464bfa2..e5f77c40bbd1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3525,31 +3525,37 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, struct net_device *orig_dev) { - struct netdev_queue *rxq = rcu_dereference(skb->dev->ingress_queue); - struct Qdisc *q; + struct tcf_proto *cl = rcu_dereference_bh(skb->dev->ingress_cl_list); + struct tcf_result cl_res; /* If there's at least one ingress present somewhere (so * we get here via enabled static key), remaining devices * that are not configured with an ingress qdisc will bail - * out w/o the rcu_dereference(). + * out here. */ - if (!rxq || (q = rcu_dereference(rxq->qdisc)) == &noop_qdisc) + if (!cl) return skb; - if (*pt_prev) { *ret = deliver_skb(skb, *pt_prev, orig_dev); *pt_prev = NULL; } + qdisc_bstats_update_cpu(cl->q, skb); skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS); - if (likely(!test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) { - switch (qdisc_enqueue_root(skb, q)) { - case TC_ACT_SHOT: - case TC_ACT_STOLEN: - kfree_skb(skb); - return NULL; - } + switch (tc_classify(skb, cl, &cl_res)) { + case TC_ACT_OK: + case TC_ACT_RECLASSIFY: + skb->tc_index = TC_H_MIN(cl_res.classid); + break; + case TC_ACT_SHOT: + qdisc_qstats_drop_cpu(cl->q); + case TC_ACT_STOLEN: + case TC_ACT_QUEUED: + kfree_skb(skb); + return NULL; + default: + break; } return skb; diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index a89cc3278bfb..e7c648fa9dc3 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -12,16 +12,10 @@ #include #include #include + #include #include - -struct ingress_qdisc_data { - struct tcf_proto __rcu *filter_list; -}; - -/* ------------------------- Class/flow operations ------------------------- */ - static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg) { return NULL; @@ -49,45 +43,11 @@ static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker) static struct tcf_proto __rcu **ingress_find_tcf(struct Qdisc *sch, unsigned long cl) { - struct ingress_qdisc_data *p = qdisc_priv(sch); - - return &p->filter_list; -} - -/* --------------------------- Qdisc operations ---------------------------- */ + struct net_device *dev = qdisc_dev(sch); -static int ingress_enqueue(struct sk_buff *skb, struct Qdisc *sch) -{ - struct ingress_qdisc_data *p = qdisc_priv(sch); - struct tcf_result res; - struct tcf_proto *fl = rcu_dereference_bh(p->filter_list); - int result; - - result = tc_classify(skb, fl, &res); - - qdisc_bstats_update_cpu(sch, skb); - switch (result) { - case TC_ACT_SHOT: - result = TC_ACT_SHOT; - qdisc_qstats_drop_cpu(sch); - break; - case TC_ACT_STOLEN: - case TC_ACT_QUEUED: - result = TC_ACT_STOLEN; - break; - case TC_ACT_RECLASSIFY: - case TC_ACT_OK: - skb->tc_index = TC_H_MIN(res.classid); - default: - result = TC_ACT_OK; - break; - } - - return result; + return &dev->ingress_cl_list; } -/* ------------------------------------------------------------- */ - static int ingress_init(struct Qdisc *sch, struct nlattr *opt) { net_inc_ingress_queue(); @@ -98,9 +58,9 @@ static int ingress_init(struct Qdisc *sch, struct nlattr *opt) static void ingress_destroy(struct Qdisc *sch) { - struct ingress_qdisc_data *p = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); - tcf_destroy_chain(&p->filter_list); + tcf_destroy_chain(&dev->ingress_cl_list); net_dec_ingress_queue(); } @@ -111,6 +71,7 @@ static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb) nest = nla_nest_start(skb, TCA_OPTIONS); if (nest == NULL) goto nla_put_failure; + return nla_nest_end(skb, nest); nla_put_failure: @@ -131,8 +92,6 @@ static const struct Qdisc_class_ops ingress_class_ops = { static struct Qdisc_ops ingress_qdisc_ops __read_mostly = { .cl_ops = &ingress_class_ops, .id = "ingress", - .priv_size = sizeof(struct ingress_qdisc_data), - .enqueue = ingress_enqueue, .init = ingress_init, .destroy = ingress_destroy, .dump = ingress_dump, @@ -149,6 +108,7 @@ static void __exit ingress_module_exit(void) unregister_qdisc(&ingress_qdisc_ops); } -module_init(ingress_module_init) -module_exit(ingress_module_exit) +module_init(ingress_module_init); +module_exit(ingress_module_exit); + MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4cda01e86f68dacc758b2daf6e8809f2ce915b85 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 11 May 2015 19:28:49 +0200 Subject: net: sched: fix typo in net_device ifdef This should have been #ifdef not #if. Reported-by: Fengguang Wu Fixes: d2788d34885d ("net: sched: further simplify handle_ing") Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c4e1caf6056f..a6d706b2a947 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1655,7 +1655,7 @@ struct net_device { rx_handler_func_t __rcu *rx_handler; void __rcu *rx_handler_data; -#if CONFIG_NET_CLS_ACT +#ifdef CONFIG_NET_CLS_ACT struct tcf_proto __rcu *ingress_cl_list; #endif struct netdev_queue __rcu *ingress_queue; -- cgit v1.2.3 From b396cca6fafccf16206a5d041d59c9e6b65b6f5a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 11 May 2015 09:06:56 -0700 Subject: net: sched: deprecate enqueue_root() Only left enqueue_root() user is netem, and it looks not necessary : qdisc_skb_cb(skb)->pkt_len is preserved after one skb_clone() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sch_generic.h | 6 ------ net/sched/sch_netem.c | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 994b5a092f33..1b0a2e88ed2b 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -501,12 +501,6 @@ static inline int qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch) return sch->enqueue(skb, sch); } -static inline int qdisc_enqueue_root(struct sk_buff *skb, struct Qdisc *sch) -{ - qdisc_skb_cb(skb)->pkt_len = skb->len; - return qdisc_enqueue(skb, sch) & NET_XMIT_MASK; -} - static inline bool qdisc_is_percpu_stats(const struct Qdisc *q) { return q->flags & TCQ_F_CPUSTATS; diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 956ead2cab9a..5abd1d9de989 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -440,9 +440,9 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { struct Qdisc *rootq = qdisc_root(sch); u32 dupsave = q->duplicate; /* prevent duplicating a dup... */ - q->duplicate = 0; - qdisc_enqueue_root(skb2, rootq); + q->duplicate = 0; + rootq->enqueue(skb2, rootq); q->duplicate = dupsave; } -- cgit v1.2.3 From 2d94e5224e81c58986a8cf44a3bf4830ce5cb96e Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 7 May 2015 14:26:34 -0700 Subject: HID: hid-sensor-hub: Fix debug lock warning When CONFIG_DEBUG_LOCK_ALLOC is defined, mutex magic is compared and warned for (l->magic != l), here l is the address of mutex pointer. In hid-sensor-hub as part of hsdev creation, a per hsdev mutex is initialized during MFD cell creation. This hsdev, which contains, mutex is part of platform data for the a cell. But platform_data is copied in platform_device_add_data() in platform.c. This copy will copy the whole hsdev structure including mutex. But once copied the magic will no longer match. So when client driver call sensor_hub_input_attr_get_raw_value, this will trigger mutex warning. So to avoid this allocate mutex dynamically. This will be same even after copy. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/hid-sensor-hub.c | 13 ++++++++++--- include/linux/hid-sensor-hub.h | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index c3f6f1e311ea..090a1ba0abb6 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -294,7 +294,7 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, if (!report) return -EINVAL; - mutex_lock(&hsdev->mutex); + mutex_lock(hsdev->mutex_ptr); if (flag == SENSOR_HUB_SYNC) { memset(&hsdev->pending, 0, sizeof(hsdev->pending)); init_completion(&hsdev->pending.ready); @@ -328,7 +328,7 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, kfree(hsdev->pending.raw_data); hsdev->pending.status = false; } - mutex_unlock(&hsdev->mutex); + mutex_unlock(hsdev->mutex_ptr); return ret_val; } @@ -667,7 +667,14 @@ static int sensor_hub_probe(struct hid_device *hdev, hsdev->vendor_id = hdev->vendor; hsdev->product_id = hdev->product; hsdev->usage = collection->usage; - mutex_init(&hsdev->mutex); + hsdev->mutex_ptr = devm_kzalloc(&hdev->dev, + sizeof(struct mutex), + GFP_KERNEL); + if (!hsdev->mutex_ptr) { + ret = -ENOMEM; + goto err_stop_hw; + } + mutex_init(hsdev->mutex_ptr); hsdev->start_collection_index = i; if (last_hsdev) last_hsdev->end_collection_index = i; diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index 0408421d885f..0042bf330b99 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -74,7 +74,7 @@ struct sensor_hub_pending { * @usage: Usage id for this hub device instance. * @start_collection_index: Starting index for a phy type collection * @end_collection_index: Last index for a phy type collection - * @mutex: synchronizing mutex. + * @mutex_ptr: synchronizing mutex pointer. * @pending: Holds information of pending sync read request. */ struct hid_sensor_hub_device { @@ -84,7 +84,7 @@ struct hid_sensor_hub_device { u32 usage; int start_collection_index; int end_collection_index; - struct mutex mutex; + struct mutex *mutex_ptr; struct sensor_hub_pending pending; }; -- cgit v1.2.3 From 0e39250845c0f91acc64264709b25f7f9b85c2c3 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 6 May 2015 21:11:51 -0700 Subject: net: Store virtual address instead of page in netdev_alloc_cache This change makes it so that we store the virtual address of the page in the netdev_alloc_cache instead of the page pointer. The idea behind this is to avoid multiple calls to page_address since the virtual address is required for every access, but the page pointer is only needed at allocation or reset of the page. While I was at it I also reordered the netdev_alloc_cache structure a bit so that the size is always 16 bytes by dropping size in the case where PAGE_SIZE is greater than or equal to 32KB. Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- include/linux/skbuff.h | 5 ++--- net/core/skbuff.c | 55 +++++++++++++++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 9c2f793573fa..8b9a2c35a9d7 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2128,9 +2128,8 @@ static inline void __skb_queue_purge(struct sk_buff_head *list) kfree_skb(skb); } -#define NETDEV_FRAG_PAGE_MAX_ORDER get_order(32768) -#define NETDEV_FRAG_PAGE_MAX_SIZE (PAGE_SIZE << NETDEV_FRAG_PAGE_MAX_ORDER) -#define NETDEV_PAGECNT_MAX_BIAS NETDEV_FRAG_PAGE_MAX_SIZE +#define NETDEV_FRAG_PAGE_MAX_SIZE __ALIGN_MASK(32768, ~PAGE_MASK) +#define NETDEV_FRAG_PAGE_MAX_ORDER get_order(NETDEV_FRAG_PAGE_MAX_SIZE) void *netdev_alloc_frag(unsigned int fragsz); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index d6851ca32598..a3062ec341c3 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -348,7 +348,13 @@ struct sk_buff *build_skb(void *data, unsigned int frag_size) EXPORT_SYMBOL(build_skb); struct netdev_alloc_cache { - struct page_frag frag; + void * va; +#if (PAGE_SIZE < NETDEV_FRAG_PAGE_MAX_SIZE) + __u16 offset; + __u16 size; +#else + __u32 offset; +#endif /* we maintain a pagecount bias, so that we dont dirty cache line * containing page->_count every time we allocate a fragment. */ @@ -361,21 +367,20 @@ static DEFINE_PER_CPU(struct netdev_alloc_cache, napi_alloc_cache); static struct page *__page_frag_refill(struct netdev_alloc_cache *nc, gfp_t gfp_mask) { - const unsigned int order = NETDEV_FRAG_PAGE_MAX_ORDER; struct page *page = NULL; gfp_t gfp = gfp_mask; - if (order) { - gfp_mask |= __GFP_COMP | __GFP_NOWARN | __GFP_NORETRY | - __GFP_NOMEMALLOC; - page = alloc_pages_node(NUMA_NO_NODE, gfp_mask, order); - nc->frag.size = PAGE_SIZE << (page ? order : 0); - } - +#if (PAGE_SIZE < NETDEV_FRAG_PAGE_MAX_SIZE) + gfp_mask |= __GFP_COMP | __GFP_NOWARN | __GFP_NORETRY | + __GFP_NOMEMALLOC; + page = alloc_pages_node(NUMA_NO_NODE, gfp_mask, + NETDEV_FRAG_PAGE_MAX_ORDER); + nc->size = page ? NETDEV_FRAG_PAGE_MAX_SIZE : PAGE_SIZE; +#endif if (unlikely(!page)) page = alloc_pages_node(NUMA_NO_NODE, gfp, 0); - nc->frag.page = page; + nc->va = page ? page_address(page) : NULL; return page; } @@ -383,19 +388,20 @@ static struct page *__page_frag_refill(struct netdev_alloc_cache *nc, static void *__alloc_page_frag(struct netdev_alloc_cache *nc, unsigned int fragsz, gfp_t gfp_mask) { - struct page *page = nc->frag.page; - unsigned int size; + unsigned int size = PAGE_SIZE; + struct page *page; int offset; - if (unlikely(!page)) { + if (unlikely(!nc->va)) { refill: page = __page_frag_refill(nc, gfp_mask); if (!page) return NULL; - /* if size can vary use frag.size else just use PAGE_SIZE */ - size = NETDEV_FRAG_PAGE_MAX_ORDER ? nc->frag.size : PAGE_SIZE; - +#if (PAGE_SIZE < NETDEV_FRAG_PAGE_MAX_SIZE) + /* if size can vary use size else just use PAGE_SIZE */ + size = nc->size; +#endif /* Even if we own the page, we do not use atomic_set(). * This would break get_page_unless_zero() users. */ @@ -404,17 +410,20 @@ refill: /* reset page count bias and offset to start of new frag */ nc->pfmemalloc = page->pfmemalloc; nc->pagecnt_bias = size; - nc->frag.offset = size; + nc->offset = size; } - offset = nc->frag.offset - fragsz; + offset = nc->offset - fragsz; if (unlikely(offset < 0)) { + page = virt_to_page(nc->va); + if (!atomic_sub_and_test(nc->pagecnt_bias, &page->_count)) goto refill; - /* if size can vary use frag.size else just use PAGE_SIZE */ - size = NETDEV_FRAG_PAGE_MAX_ORDER ? nc->frag.size : PAGE_SIZE; - +#if (PAGE_SIZE < NETDEV_FRAG_PAGE_MAX_SIZE) + /* if size can vary use size else just use PAGE_SIZE */ + size = nc->size; +#endif /* OK, page count is 0, we can safely set it */ atomic_set(&page->_count, size); @@ -424,9 +433,9 @@ refill: } nc->pagecnt_bias--; - nc->frag.offset = offset; + nc->offset = offset; - return page_address(page) + offset; + return nc->va + offset; } static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask) -- cgit v1.2.3 From b63ae8ca096dfdbfeef6a209c30a93a966518853 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 6 May 2015 21:11:57 -0700 Subject: mm/net: Rename and move page fragment handling from net/ to mm/ This change moves the __alloc_page_frag functionality out of the networking stack and into the page allocation portion of mm. The idea it so help make this maintainable by placing it with other page allocation functions. Since we are moving it from skbuff.c to page_alloc.c I have also renamed the basic defines and structure from netdev_alloc_cache to page_frag_cache to reflect that this is now part of a different kernel subsystem. I have also added a simple __free_page_frag function which can handle freeing the frags based on the skb->head pointer. The model for this is based off of __free_pages since we don't actually need to deal with all of the cases that put_page handles. I incorporated the virt_to_head_page call and compound_order into the function as it actually allows for a signficant size reduction by reducing code duplication. Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- include/linux/gfp.h | 5 +++ include/linux/mm_types.h | 18 +++++++++ include/linux/skbuff.h | 3 -- mm/page_alloc.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++ net/core/skbuff.c | 100 +++-------------------------------------------- 5 files changed, 127 insertions(+), 97 deletions(-) (limited to 'include') diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 97a9373e61e8..70a7fee1efb3 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -366,6 +366,11 @@ extern void free_pages(unsigned long addr, unsigned int order); extern void free_hot_cold_page(struct page *page, bool cold); extern void free_hot_cold_page_list(struct list_head *list, bool cold); +struct page_frag_cache; +extern void *__alloc_page_frag(struct page_frag_cache *nc, + unsigned int fragsz, gfp_t gfp_mask); +extern void __free_page_frag(void *addr); + extern void __free_kmem_pages(struct page *page, unsigned int order); extern void free_kmem_pages(unsigned long addr, unsigned int order); diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 8d37e26a1007..0038ac7466fd 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -226,6 +226,24 @@ struct page_frag { #endif }; +#define PAGE_FRAG_CACHE_MAX_SIZE __ALIGN_MASK(32768, ~PAGE_MASK) +#define PAGE_FRAG_CACHE_MAX_ORDER get_order(PAGE_FRAG_CACHE_MAX_SIZE) + +struct page_frag_cache { + void * va; +#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) + __u16 offset; + __u16 size; +#else + __u32 offset; +#endif + /* we maintain a pagecount bias, so that we dont dirty cache line + * containing page->_count every time we allocate a fragment. + */ + unsigned int pagecnt_bias; + bool pfmemalloc; +}; + typedef unsigned long __nocast vm_flags_t; /* diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 8b9a2c35a9d7..0039fcc45b3b 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2128,9 +2128,6 @@ static inline void __skb_queue_purge(struct sk_buff_head *list) kfree_skb(skb); } -#define NETDEV_FRAG_PAGE_MAX_SIZE __ALIGN_MASK(32768, ~PAGE_MASK) -#define NETDEV_FRAG_PAGE_MAX_ORDER get_order(NETDEV_FRAG_PAGE_MAX_SIZE) - void *netdev_alloc_frag(unsigned int fragsz); struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int length, diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ebffa0e4a9c0..2fd31aebef30 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2966,6 +2966,104 @@ void free_pages(unsigned long addr, unsigned int order) EXPORT_SYMBOL(free_pages); +/* + * Page Fragment: + * An arbitrary-length arbitrary-offset area of memory which resides + * within a 0 or higher order page. Multiple fragments within that page + * are individually refcounted, in the page's reference counter. + * + * The page_frag functions below provide a simple allocation framework for + * page fragments. This is used by the network stack and network device + * drivers to provide a backing region of memory for use as either an + * sk_buff->head, or to be used in the "frags" portion of skb_shared_info. + */ +static struct page *__page_frag_refill(struct page_frag_cache *nc, + gfp_t gfp_mask) +{ + struct page *page = NULL; + gfp_t gfp = gfp_mask; + +#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) + gfp_mask |= __GFP_COMP | __GFP_NOWARN | __GFP_NORETRY | + __GFP_NOMEMALLOC; + page = alloc_pages_node(NUMA_NO_NODE, gfp_mask, + PAGE_FRAG_CACHE_MAX_ORDER); + nc->size = page ? PAGE_FRAG_CACHE_MAX_SIZE : PAGE_SIZE; +#endif + if (unlikely(!page)) + page = alloc_pages_node(NUMA_NO_NODE, gfp, 0); + + nc->va = page ? page_address(page) : NULL; + + return page; +} + +void *__alloc_page_frag(struct page_frag_cache *nc, + unsigned int fragsz, gfp_t gfp_mask) +{ + unsigned int size = PAGE_SIZE; + struct page *page; + int offset; + + if (unlikely(!nc->va)) { +refill: + page = __page_frag_refill(nc, gfp_mask); + if (!page) + return NULL; + +#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) + /* if size can vary use size else just use PAGE_SIZE */ + size = nc->size; +#endif + /* Even if we own the page, we do not use atomic_set(). + * This would break get_page_unless_zero() users. + */ + atomic_add(size - 1, &page->_count); + + /* reset page count bias and offset to start of new frag */ + nc->pfmemalloc = page->pfmemalloc; + nc->pagecnt_bias = size; + nc->offset = size; + } + + offset = nc->offset - fragsz; + if (unlikely(offset < 0)) { + page = virt_to_page(nc->va); + + if (!atomic_sub_and_test(nc->pagecnt_bias, &page->_count)) + goto refill; + +#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) + /* if size can vary use size else just use PAGE_SIZE */ + size = nc->size; +#endif + /* OK, page count is 0, we can safely set it */ + atomic_set(&page->_count, size); + + /* reset page count bias and offset to start of new frag */ + nc->pagecnt_bias = size; + offset = size - fragsz; + } + + nc->pagecnt_bias--; + nc->offset = offset; + + return nc->va + offset; +} +EXPORT_SYMBOL(__alloc_page_frag); + +/* + * Frees a page fragment allocated out of either a compound or order 0 page. + */ +void __free_page_frag(void *addr) +{ + struct page *page = virt_to_head_page(addr); + + if (unlikely(put_page_testzero(page))) + __free_pages_ok(page, compound_order(page)); +} +EXPORT_SYMBOL(__free_page_frag); + /* * alloc_kmem_pages charges newly allocated pages to the kmem resource counter * of the current memory cgroup. diff --git a/net/core/skbuff.c b/net/core/skbuff.c index a3062ec341c3..dcc0e07abf47 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -347,100 +347,12 @@ struct sk_buff *build_skb(void *data, unsigned int frag_size) } EXPORT_SYMBOL(build_skb); -struct netdev_alloc_cache { - void * va; -#if (PAGE_SIZE < NETDEV_FRAG_PAGE_MAX_SIZE) - __u16 offset; - __u16 size; -#else - __u32 offset; -#endif - /* we maintain a pagecount bias, so that we dont dirty cache line - * containing page->_count every time we allocate a fragment. - */ - unsigned int pagecnt_bias; - bool pfmemalloc; -}; -static DEFINE_PER_CPU(struct netdev_alloc_cache, netdev_alloc_cache); -static DEFINE_PER_CPU(struct netdev_alloc_cache, napi_alloc_cache); - -static struct page *__page_frag_refill(struct netdev_alloc_cache *nc, - gfp_t gfp_mask) -{ - struct page *page = NULL; - gfp_t gfp = gfp_mask; - -#if (PAGE_SIZE < NETDEV_FRAG_PAGE_MAX_SIZE) - gfp_mask |= __GFP_COMP | __GFP_NOWARN | __GFP_NORETRY | - __GFP_NOMEMALLOC; - page = alloc_pages_node(NUMA_NO_NODE, gfp_mask, - NETDEV_FRAG_PAGE_MAX_ORDER); - nc->size = page ? NETDEV_FRAG_PAGE_MAX_SIZE : PAGE_SIZE; -#endif - if (unlikely(!page)) - page = alloc_pages_node(NUMA_NO_NODE, gfp, 0); - - nc->va = page ? page_address(page) : NULL; - - return page; -} - -static void *__alloc_page_frag(struct netdev_alloc_cache *nc, - unsigned int fragsz, gfp_t gfp_mask) -{ - unsigned int size = PAGE_SIZE; - struct page *page; - int offset; - - if (unlikely(!nc->va)) { -refill: - page = __page_frag_refill(nc, gfp_mask); - if (!page) - return NULL; - -#if (PAGE_SIZE < NETDEV_FRAG_PAGE_MAX_SIZE) - /* if size can vary use size else just use PAGE_SIZE */ - size = nc->size; -#endif - /* Even if we own the page, we do not use atomic_set(). - * This would break get_page_unless_zero() users. - */ - atomic_add(size - 1, &page->_count); - - /* reset page count bias and offset to start of new frag */ - nc->pfmemalloc = page->pfmemalloc; - nc->pagecnt_bias = size; - nc->offset = size; - } - - offset = nc->offset - fragsz; - if (unlikely(offset < 0)) { - page = virt_to_page(nc->va); - - if (!atomic_sub_and_test(nc->pagecnt_bias, &page->_count)) - goto refill; - -#if (PAGE_SIZE < NETDEV_FRAG_PAGE_MAX_SIZE) - /* if size can vary use size else just use PAGE_SIZE */ - size = nc->size; -#endif - /* OK, page count is 0, we can safely set it */ - atomic_set(&page->_count, size); - - /* reset page count bias and offset to start of new frag */ - nc->pagecnt_bias = size; - offset = size - fragsz; - } - - nc->pagecnt_bias--; - nc->offset = offset; - - return nc->va + offset; -} +static DEFINE_PER_CPU(struct page_frag_cache, netdev_alloc_cache); +static DEFINE_PER_CPU(struct page_frag_cache, napi_alloc_cache); static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask) { - struct netdev_alloc_cache *nc; + struct page_frag_cache *nc; unsigned long flags; void *data; @@ -466,7 +378,7 @@ EXPORT_SYMBOL(netdev_alloc_frag); static void *__napi_alloc_frag(unsigned int fragsz, gfp_t gfp_mask) { - struct netdev_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache); + struct page_frag_cache *nc = this_cpu_ptr(&napi_alloc_cache); return __alloc_page_frag(nc, fragsz, gfp_mask); } @@ -493,7 +405,7 @@ EXPORT_SYMBOL(napi_alloc_frag); struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len, gfp_t gfp_mask) { - struct netdev_alloc_cache *nc; + struct page_frag_cache *nc; unsigned long flags; struct sk_buff *skb; bool pfmemalloc; @@ -556,7 +468,7 @@ EXPORT_SYMBOL(__netdev_alloc_skb); struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len, gfp_t gfp_mask) { - struct netdev_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache); + struct page_frag_cache *nc = this_cpu_ptr(&napi_alloc_cache); struct sk_buff *skb; void *data; -- cgit v1.2.3 From 181edb2bfa22b50817684135ab6430ed2808abf0 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 6 May 2015 21:12:03 -0700 Subject: net: Add skb_free_frag to replace use of put_page in freeing skb->head This change adds a function called skb_free_frag which is meant to compliment the function netdev_alloc_frag. The general idea is to enable a more lightweight version of page freeing since we don't actually need all the overhead of a put_page, and we don't quite fit the model of __free_pages. Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- include/linux/skbuff.h | 5 +++++ net/core/skbuff.c | 10 ++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 0039fcc45b3b..c0b574a414e7 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2182,6 +2182,11 @@ static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, return __netdev_alloc_skb_ip_align(dev, length, GFP_ATOMIC); } +static inline void skb_free_frag(void *addr) +{ + __free_page_frag(addr); +} + void *napi_alloc_frag(unsigned int fragsz); struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int length, gfp_t gfp_mask); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index dcc0e07abf47..d67e612bf0ef 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -436,7 +436,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len, skb = __build_skb(data, len); if (unlikely(!skb)) { - put_page(virt_to_head_page(data)); + skb_free_frag(data); return NULL; } @@ -490,7 +490,7 @@ struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len, skb = __build_skb(data, len); if (unlikely(!skb)) { - put_page(virt_to_head_page(data)); + skb_free_frag(data); return NULL; } @@ -549,10 +549,12 @@ static void skb_clone_fraglist(struct sk_buff *skb) static void skb_free_head(struct sk_buff *skb) { + unsigned char *head = skb->head; + if (skb->head_frag) - put_page(virt_to_head_page(skb->head)); + skb_free_frag(head); else - kfree(skb->head); + kfree(head); } static void skb_release_data(struct sk_buff *skb) -- cgit v1.2.3 From fcf3b54282e4c5a95a1f45f67558bc105acdbc6a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 May 2015 12:51:38 -0400 Subject: drm/radeon: add new bonaire pci id Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- include/drm/drm_pciids.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 2dd405c9be78..45c39a37f924 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -186,6 +186,7 @@ {0x1002, 0x6658, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x665c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x665d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x665f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6663, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6664, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -- cgit v1.2.3 From 336b7e1f230912cd8df2497be8dd7be4647d8fc8 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Mon, 11 May 2015 14:06:32 -0400 Subject: block: remove export for blk_queue_bio With commit ff36ab345 ("dm: remove request-based logic from make_request_fn wrapper") DM no longer calls blk_queue_bio() directly, so remove its export. Doing so required a forward declaration in blk-core.c. Signed-off-by: Mike Snitzer Signed-off-by: Jens Axboe --- block/blk-core.c | 5 +++-- include/linux/blkdev.h | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/block/blk-core.c b/block/blk-core.c index 7871603f0a29..03b5f8d77f37 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -734,6 +734,8 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id) } EXPORT_SYMBOL(blk_init_queue_node); +static void blk_queue_bio(struct request_queue *q, struct bio *bio); + struct request_queue * blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn, spinlock_t *lock) @@ -1578,7 +1580,7 @@ void init_request_from_bio(struct request *req, struct bio *bio) blk_rq_bio_prep(req->q, req, bio); } -void blk_queue_bio(struct request_queue *q, struct bio *bio) +static void blk_queue_bio(struct request_queue *q, struct bio *bio) { const bool sync = !!(bio->bi_rw & REQ_SYNC); struct blk_plug *plug; @@ -1686,7 +1688,6 @@ out_unlock: spin_unlock_irq(q->queue_lock); } } -EXPORT_SYMBOL_GPL(blk_queue_bio); /* for device mapper only */ /* * If bio->bi_dev is a partition, remap the location diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 7f9a516f24de..5d93a6645e88 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -821,8 +821,6 @@ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, struct scsi_ioctl_command __user *); -extern void blk_queue_bio(struct request_queue *q, struct bio *bio); - /* * A queue has just exitted congestion. Note this in the global counter of * congested queues, and wake up anyone who was waiting for requests to be -- cgit v1.2.3 From a3eb95f891d6130b1fc03dd07a8b54cf0a5c8ab8 Mon Sep 17 00:00:00 2001 From: David Ward Date: Sat, 9 May 2015 22:01:46 -0400 Subject: net_sched: gred: add TCA_GRED_LIMIT attribute In a GRED qdisc, if the default "virtual queue" (VQ) does not have drop parameters configured, then packets for the default VQ are not subjected to RED and are only dropped if the queue is larger than the net_device's tx_queue_len. This behavior is useful for WRED mode, since these packets will still influence the calculated average queue length and (therefore) the drop probability for all of the other VQs. However, for some drivers tx_queue_len is zero. In other cases the user may wish to make the limit the same for all VQs (including the default VQ with no drop parameters). This change adds a TCA_GRED_LIMIT attribute to set the GRED queue limit, in bytes, during qdisc setup. (This limit is in bytes to be consistent with the drop parameters.) The default limit is the same as for a bfifo queue (tx_queue_len * psched_mtu). If the drop parameters of any VQ are configured with a smaller limit than the GRED queue limit, that VQ will still observe the smaller limit instead. Signed-off-by: David Ward Signed-off-by: David S. Miller --- include/uapi/linux/pkt_sched.h | 3 ++- net/sched/sch_gred.c | 28 ++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h index 69d88b309cc7..8d2530daca9f 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -268,7 +268,8 @@ enum { TCA_GRED_STAB, TCA_GRED_DPS, TCA_GRED_MAX_P, - __TCA_GRED_MAX, + TCA_GRED_LIMIT, + __TCA_GRED_MAX, }; #define TCA_GRED_MAX (__TCA_GRED_MAX - 1) diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index a4ca4517cdc8..826e2994152b 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -165,7 +165,8 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc *sch) * if no default DP has been configured. This * allows for DP flows to be left untouched. */ - if (skb_queue_len(&sch->q) < qdisc_dev(sch)->tx_queue_len) + if (likely(sch->qstats.backlog + qdisc_pkt_len(skb) <= + sch->limit)) return qdisc_enqueue_tail(skb, sch); else goto drop; @@ -397,7 +398,10 @@ static inline int gred_change_vq(struct Qdisc *sch, int dp, q->DP = dp; q->prio = prio; - q->limit = ctl->limit; + if (ctl->limit > sch->limit) + q->limit = sch->limit; + else + q->limit = ctl->limit; if (q->backlog == 0) red_end_of_idle_period(&q->vars); @@ -414,6 +418,7 @@ static const struct nla_policy gred_policy[TCA_GRED_MAX + 1] = { [TCA_GRED_STAB] = { .len = 256 }, [TCA_GRED_DPS] = { .len = sizeof(struct tc_gred_sopt) }, [TCA_GRED_MAX_P] = { .type = NLA_U32 }, + [TCA_GRED_LIMIT] = { .type = NLA_U32 }, }; static int gred_change(struct Qdisc *sch, struct nlattr *opt) @@ -433,11 +438,15 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt) if (err < 0) return err; - if (tb[TCA_GRED_PARMS] == NULL && tb[TCA_GRED_STAB] == NULL) + if (tb[TCA_GRED_PARMS] == NULL && tb[TCA_GRED_STAB] == NULL) { + if (tb[TCA_GRED_LIMIT] != NULL) + sch->limit = nla_get_u32(tb[TCA_GRED_LIMIT]); return gred_change_table_def(sch, opt); + } if (tb[TCA_GRED_PARMS] == NULL || - tb[TCA_GRED_STAB] == NULL) + tb[TCA_GRED_STAB] == NULL || + tb[TCA_GRED_LIMIT] != NULL) return -EINVAL; max_P = tb[TCA_GRED_MAX_P] ? nla_get_u32(tb[TCA_GRED_MAX_P]) : 0; @@ -501,6 +510,14 @@ static int gred_init(struct Qdisc *sch, struct nlattr *opt) if (tb[TCA_GRED_PARMS] || tb[TCA_GRED_STAB]) return -EINVAL; + if (tb[TCA_GRED_LIMIT]) + sch->limit = nla_get_u32(tb[TCA_GRED_LIMIT]); + else { + u32 qlen = qdisc_dev(sch)->tx_queue_len ? : 1; + + sch->limit = qlen * psched_mtu(qdisc_dev(sch)); + } + return gred_change_table_def(sch, tb[TCA_GRED_DPS]); } @@ -531,6 +548,9 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) if (nla_put(skb, TCA_GRED_MAX_P, sizeof(max_p), max_p)) goto nla_put_failure; + if (nla_put_u32(skb, TCA_GRED_LIMIT, sch->limit)) + goto nla_put_failure; + parms = nla_nest_start(skb, TCA_GRED_PARMS); if (parms == NULL) goto nla_put_failure; -- cgit v1.2.3 From ebb9a03a590e2325f747be43c8db450e92509501 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sun, 10 May 2015 09:47:46 -0700 Subject: switchdev: s/netdev_switch_/switchdev_/ and s/NETDEV_SWITCH_/SWITCHDEV_/ Turned out that "switchdev" sticks. So just unify all related terms to use this prefix. Signed-off-by: Jiri Pirko Signed-off-by: Scott Feldman Acked-by: Roopa Prabhu Acked-by: Andy Gospodarek Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 4 +- drivers/net/ethernet/rocker/rocker.c | 10 +-- drivers/net/team/team.c | 4 +- include/net/switchdev.h | 111 +++++++++++++++-------------- net/bridge/br.c | 22 +++--- net/bridge/br_netlink.c | 6 +- net/bridge/br_stp.c | 2 +- net/core/net-sysfs.c | 2 +- net/core/rtnetlink.c | 2 +- net/ipv4/fib_trie.c | 40 +++++------ net/switchdev/switchdev.c | 134 +++++++++++++++++------------------ 11 files changed, 166 insertions(+), 171 deletions(-) (limited to 'include') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2ee13be7551b..a475a0389cc7 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4039,8 +4039,8 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_add_slave = bond_enslave, .ndo_del_slave = bond_release, .ndo_fix_features = bond_fix_features, - .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink, - .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink, + .ndo_bridge_setlink = ndo_dflt_switchdev_port_bridge_setlink, + .ndo_bridge_dellink = ndo_dflt_switchdev_port_bridge_dellink, .ndo_features_check = passthru_features_check, }; diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 0c6f0a8b42dd..418f62b19545 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -3377,17 +3377,17 @@ static void rocker_port_fdb_learn_work(struct work_struct *work) container_of(work, struct rocker_fdb_learn_work, work); bool removing = (lw->flags & ROCKER_OP_FLAG_REMOVE); bool learned = (lw->flags & ROCKER_OP_FLAG_LEARNED); - struct netdev_switch_notifier_fdb_info info; + struct switchdev_notifier_fdb_info info; info.addr = lw->addr; info.vid = lw->vid; if (learned && removing) - call_netdev_switch_notifiers(NETDEV_SWITCH_FDB_DEL, - lw->dev, &info.info); + call_switchdev_notifiers(SWITCHDEV_FDB_DEL, + lw->dev, &info.info); else if (learned && !removing) - call_netdev_switch_notifiers(NETDEV_SWITCH_FDB_ADD, - lw->dev, &info.info); + call_switchdev_notifiers(SWITCHDEV_FDB_ADD, + lw->dev, &info.info); kfree(work); } diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 6928448f6b7f..cfe84965afb6 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1977,8 +1977,8 @@ static const struct net_device_ops team_netdev_ops = { .ndo_del_slave = team_del_slave, .ndo_fix_features = team_fix_features, .ndo_change_carrier = team_change_carrier, - .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink, - .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink, + .ndo_bridge_setlink = ndo_dflt_switchdev_port_bridge_setlink, + .ndo_bridge_dellink = ndo_dflt_switchdev_port_bridge_dellink, .ndo_features_check = passthru_features_check, }; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index d2e69ee3019a..cd921fa0d63a 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -43,124 +43,125 @@ struct swdev_ops { u8 tos, u8 type, u32 tb_id); }; -enum netdev_switch_notifier_type { - NETDEV_SWITCH_FDB_ADD = 1, - NETDEV_SWITCH_FDB_DEL, +enum switchdev_notifier_type { + SWITCHDEV_FDB_ADD = 1, + SWITCHDEV_FDB_DEL, }; -struct netdev_switch_notifier_info { +struct switchdev_notifier_info { struct net_device *dev; }; -struct netdev_switch_notifier_fdb_info { - struct netdev_switch_notifier_info info; /* must be first */ +struct switchdev_notifier_fdb_info { + struct switchdev_notifier_info info; /* must be first */ const unsigned char *addr; u16 vid; }; static inline struct net_device * -netdev_switch_notifier_info_to_dev(const struct netdev_switch_notifier_info *info) +switchdev_notifier_info_to_dev(const struct switchdev_notifier_info *info) { return info->dev; } #ifdef CONFIG_NET_SWITCHDEV -int netdev_switch_parent_id_get(struct net_device *dev, - struct netdev_phys_item_id *psid); -int netdev_switch_port_stp_update(struct net_device *dev, u8 state); -int register_netdev_switch_notifier(struct notifier_block *nb); -int unregister_netdev_switch_notifier(struct notifier_block *nb); -int call_netdev_switch_notifiers(unsigned long val, struct net_device *dev, - struct netdev_switch_notifier_info *info); -int netdev_switch_port_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags); -int netdev_switch_port_bridge_dellink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags); -int ndo_dflt_netdev_switch_port_bridge_dellink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags); -int ndo_dflt_netdev_switch_port_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags); -int netdev_switch_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, - u8 tos, u8 type, u32 nlflags, u32 tb_id); -int netdev_switch_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, - u8 tos, u8 type, u32 tb_id); -void netdev_switch_fib_ipv4_abort(struct fib_info *fi); +int switchdev_parent_id_get(struct net_device *dev, + struct netdev_phys_item_id *psid); +int switchdev_port_stp_update(struct net_device *dev, u8 state); +int register_switchdev_notifier(struct notifier_block *nb); +int unregister_switchdev_notifier(struct notifier_block *nb); +int call_switchdev_notifiers(unsigned long val, struct net_device *dev, + struct switchdev_notifier_info *info); +int switchdev_port_bridge_setlink(struct net_device *dev, + struct nlmsghdr *nlh, u16 flags); +int switchdev_port_bridge_dellink(struct net_device *dev, + struct nlmsghdr *nlh, u16 flags); +int ndo_dflt_switchdev_port_bridge_dellink(struct net_device *dev, + struct nlmsghdr *nlh, u16 flags); +int ndo_dflt_switchdev_port_bridge_setlink(struct net_device *dev, + struct nlmsghdr *nlh, u16 flags); +int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, + u8 tos, u8 type, u32 nlflags, u32 tb_id); +int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, + u8 tos, u8 type, u32 tb_id); +void switchdev_fib_ipv4_abort(struct fib_info *fi); #else -static inline int netdev_switch_parent_id_get(struct net_device *dev, - struct netdev_phys_item_id *psid) +static inline int switchdev_parent_id_get(struct net_device *dev, + struct netdev_phys_item_id *psid) { return -EOPNOTSUPP; } -static inline int netdev_switch_port_stp_update(struct net_device *dev, - u8 state) +static inline int switchdev_port_stp_update(struct net_device *dev, + u8 state) { return -EOPNOTSUPP; } -static inline int register_netdev_switch_notifier(struct notifier_block *nb) +static inline int register_switchdev_notifier(struct notifier_block *nb) { return 0; } -static inline int unregister_netdev_switch_notifier(struct notifier_block *nb) +static inline int unregister_switchdev_notifier(struct notifier_block *nb) { return 0; } -static inline int call_netdev_switch_notifiers(unsigned long val, struct net_device *dev, - struct netdev_switch_notifier_info *info) +static inline int call_switchdev_notifiers(unsigned long val, + struct net_device *dev, + struct switchdev_notifier_info *info) { return NOTIFY_DONE; } -static inline int netdev_switch_port_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh, - u16 flags) +static inline int switchdev_port_bridge_setlink(struct net_device *dev, + struct nlmsghdr *nlh, + u16 flags) { return -EOPNOTSUPP; } -static inline int netdev_switch_port_bridge_dellink(struct net_device *dev, - struct nlmsghdr *nlh, - u16 flags) +static inline int switchdev_port_bridge_dellink(struct net_device *dev, + struct nlmsghdr *nlh, + u16 flags) { return -EOPNOTSUPP; } -static inline int ndo_dflt_netdev_switch_port_bridge_dellink(struct net_device *dev, - struct nlmsghdr *nlh, - u16 flags) +static inline int ndo_dflt_switchdev_port_bridge_dellink(struct net_device *dev, + struct nlmsghdr *nlh, + u16 flags) { return 0; } -static inline int ndo_dflt_netdev_switch_port_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh, - u16 flags) +static inline int ndo_dflt_switchdev_port_bridge_setlink(struct net_device *dev, + struct nlmsghdr *nlh, + u16 flags) { return 0; } -static inline int netdev_switch_fib_ipv4_add(u32 dst, int dst_len, - struct fib_info *fi, - u8 tos, u8 type, - u32 nlflags, u32 tb_id) +static inline int switchdev_fib_ipv4_add(u32 dst, int dst_len, + struct fib_info *fi, + u8 tos, u8 type, + u32 nlflags, u32 tb_id) { return 0; } -static inline int netdev_switch_fib_ipv4_del(u32 dst, int dst_len, - struct fib_info *fi, - u8 tos, u8 type, u32 tb_id) +static inline int switchdev_fib_ipv4_del(u32 dst, int dst_len, + struct fib_info *fi, + u8 tos, u8 type, u32 tb_id) { return 0; } -static inline void netdev_switch_fib_ipv4_abort(struct fib_info *fi) +static inline void switchdev_fib_ipv4_abort(struct fib_info *fi) { } diff --git a/net/bridge/br.c b/net/bridge/br.c index 02c24cf63c34..a1abe4936fe1 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -121,13 +121,13 @@ static struct notifier_block br_device_notifier = { .notifier_call = br_device_event }; -static int br_netdev_switch_event(struct notifier_block *unused, - unsigned long event, void *ptr) +static int br_switchdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) { - struct net_device *dev = netdev_switch_notifier_info_to_dev(ptr); + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); struct net_bridge_port *p; struct net_bridge *br; - struct netdev_switch_notifier_fdb_info *fdb_info; + struct switchdev_notifier_fdb_info *fdb_info; int err = NOTIFY_DONE; rtnl_lock(); @@ -138,14 +138,14 @@ static int br_netdev_switch_event(struct notifier_block *unused, br = p->br; switch (event) { - case NETDEV_SWITCH_FDB_ADD: + case SWITCHDEV_FDB_ADD: fdb_info = ptr; err = br_fdb_external_learn_add(br, p, fdb_info->addr, fdb_info->vid); if (err) err = notifier_from_errno(err); break; - case NETDEV_SWITCH_FDB_DEL: + case SWITCHDEV_FDB_DEL: fdb_info = ptr; err = br_fdb_external_learn_del(br, p, fdb_info->addr, fdb_info->vid); @@ -159,8 +159,8 @@ out: return err; } -static struct notifier_block br_netdev_switch_notifier = { - .notifier_call = br_netdev_switch_event, +static struct notifier_block br_switchdev_notifier = { + .notifier_call = br_switchdev_event, }; static void __net_exit br_net_exit(struct net *net) @@ -214,7 +214,7 @@ static int __init br_init(void) if (err) goto err_out3; - err = register_netdev_switch_notifier(&br_netdev_switch_notifier); + err = register_switchdev_notifier(&br_switchdev_notifier); if (err) goto err_out4; @@ -235,7 +235,7 @@ static int __init br_init(void) return 0; err_out5: - unregister_netdev_switch_notifier(&br_netdev_switch_notifier); + unregister_switchdev_notifier(&br_switchdev_notifier); err_out4: unregister_netdevice_notifier(&br_device_notifier); err_out3: @@ -253,7 +253,7 @@ static void __exit br_deinit(void) { stp_proto_unregister(&br_stp_proto); br_netlink_fini(); - unregister_netdev_switch_notifier(&br_netdev_switch_notifier); + unregister_switchdev_notifier(&br_switchdev_notifier); unregister_netdevice_notifier(&br_device_notifier); brioctl_set(NULL); unregister_pernet_subsys(&br_net_ops); diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 4b5c236998ff..dc234533e204 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -631,8 +631,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags) if (p && !(flags & BRIDGE_FLAGS_SELF)) { /* set bridge attributes in hardware if supported */ - ret_offload = netdev_switch_port_bridge_setlink(dev, nlh, - flags); + ret_offload = switchdev_port_bridge_setlink(dev, nlh, flags); if (ret_offload && ret_offload != -EOPNOTSUPP) br_warn(p->br, "error setting attrs on port %u(%s)\n", (unsigned int)p->port_no, p->dev->name); @@ -671,8 +670,7 @@ int br_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags) if (p && !(flags & BRIDGE_FLAGS_SELF)) { /* del bridge attributes in hardware */ - ret_offload = netdev_switch_port_bridge_dellink(dev, nlh, - flags); + ret_offload = switchdev_port_bridge_dellink(dev, nlh, flags); if (ret_offload && ret_offload != -EOPNOTSUPP) br_warn(p->br, "error deleting attrs on port %u (%s)\n", (unsigned int)p->port_no, p->dev->name); diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index fb3ebe615513..28e3f4bc01e0 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -42,7 +42,7 @@ void br_set_state(struct net_bridge_port *p, unsigned int state) int err; p->state = state; - err = netdev_switch_port_stp_update(p->dev, state); + err = switchdev_port_stp_update(p->dev, state); if (err && err != -EOPNOTSUPP) br_warn(p->br, "error setting offload STP state on port %u(%s)\n", (unsigned int) p->port_no, p->dev->name); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 4238d6da5c60..be86a7ce9282 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -460,7 +460,7 @@ static ssize_t phys_switch_id_show(struct device *dev, if (dev_isalive(netdev)) { struct netdev_phys_item_id ppid; - ret = netdev_switch_parent_id_get(netdev, &ppid); + ret = switchdev_parent_id_get(netdev, &ppid); if (!ret) ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id); } diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 83e08323fdcd..fcd41fcd7e70 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1006,7 +1006,7 @@ static int rtnl_phys_switch_id_fill(struct sk_buff *skb, struct net_device *dev) int err; struct netdev_phys_item_id psid; - err = netdev_switch_parent_id_get(dev, &psid); + err = switchdev_parent_id_get(dev, &psid); if (err) { if (err == -EOPNOTSUPP) return 0; diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index e13fcc602da2..03444c6ae342 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1165,13 +1165,13 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) new_fa->fa_state = state & ~FA_S_ACCESSED; new_fa->fa_slen = fa->fa_slen; - err = netdev_switch_fib_ipv4_add(key, plen, fi, - new_fa->fa_tos, - cfg->fc_type, - cfg->fc_nlflags, - tb->tb_id); + err = switchdev_fib_ipv4_add(key, plen, fi, + new_fa->fa_tos, + cfg->fc_type, + cfg->fc_nlflags, + tb->tb_id); if (err) { - netdev_switch_fib_ipv4_abort(fi); + switchdev_fib_ipv4_abort(fi); kmem_cache_free(fn_alias_kmem, new_fa); goto out; } @@ -1215,12 +1215,10 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) new_fa->tb_id = tb->tb_id; /* (Optionally) offload fib entry to switch hardware. */ - err = netdev_switch_fib_ipv4_add(key, plen, fi, tos, - cfg->fc_type, - cfg->fc_nlflags, - tb->tb_id); + err = switchdev_fib_ipv4_add(key, plen, fi, tos, cfg->fc_type, + cfg->fc_nlflags, tb->tb_id); if (err) { - netdev_switch_fib_ipv4_abort(fi); + switchdev_fib_ipv4_abort(fi); goto out_free_new_fa; } @@ -1239,7 +1237,7 @@ succeeded: return 0; out_sw_fib_del: - netdev_switch_fib_ipv4_del(key, plen, fi, tos, cfg->fc_type, tb->tb_id); + switchdev_fib_ipv4_del(key, plen, fi, tos, cfg->fc_type, tb->tb_id); out_free_new_fa: kmem_cache_free(fn_alias_kmem, new_fa); out: @@ -1517,8 +1515,8 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg) if (!fa_to_delete) return -ESRCH; - netdev_switch_fib_ipv4_del(key, plen, fa_to_delete->fa_info, tos, - cfg->fc_type, tb->tb_id); + switchdev_fib_ipv4_del(key, plen, fa_to_delete->fa_info, tos, + cfg->fc_type, tb->tb_id); rtmsg_fib(RTM_DELROUTE, htonl(key), fa_to_delete, plen, tb->tb_id, &cfg->fc_nlinfo, 0); @@ -1767,10 +1765,9 @@ void fib_table_flush_external(struct fib_table *tb) if (!fi || !(fi->fib_flags & RTNH_F_EXTERNAL)) continue; - netdev_switch_fib_ipv4_del(n->key, - KEYLENGTH - fa->fa_slen, - fi, fa->fa_tos, - fa->fa_type, tb->tb_id); + switchdev_fib_ipv4_del(n->key, KEYLENGTH - fa->fa_slen, + fi, fa->fa_tos, fa->fa_type, + tb->tb_id); } /* update leaf slen */ @@ -1835,10 +1832,9 @@ int fib_table_flush(struct fib_table *tb) continue; } - netdev_switch_fib_ipv4_del(n->key, - KEYLENGTH - fa->fa_slen, - fi, fa->fa_tos, - fa->fa_type, tb->tb_id); + switchdev_fib_ipv4_del(n->key, KEYLENGTH - fa->fa_slen, + fi, fa->fa_tos, fa->fa_type, + tb->tb_id); hlist_del_rcu(&fa->fa_list); fib_release_info(fa->fa_info); alias_free_mem_rcu(fa); diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 46568b85c333..52613ed49a8c 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -19,14 +19,14 @@ #include /** - * netdev_switch_parent_id_get - Get ID of a switch + * switchdev_parent_id_get - Get ID of a switch * @dev: port device * @psid: switch ID * * Get ID of a switch this port is part of. */ -int netdev_switch_parent_id_get(struct net_device *dev, - struct netdev_phys_item_id *psid) +int switchdev_parent_id_get(struct net_device *dev, + struct netdev_phys_item_id *psid) { const struct swdev_ops *ops = dev->swdev_ops; @@ -34,17 +34,17 @@ int netdev_switch_parent_id_get(struct net_device *dev, return -EOPNOTSUPP; return ops->swdev_parent_id_get(dev, psid); } -EXPORT_SYMBOL_GPL(netdev_switch_parent_id_get); +EXPORT_SYMBOL_GPL(switchdev_parent_id_get); /** - * netdev_switch_port_stp_update - Notify switch device port of STP + * switchdev_port_stp_update - Notify switch device port of STP * state change * @dev: port device * @state: port STP state * * Notify switch device port of bridge port STP state change. */ -int netdev_switch_port_stp_update(struct net_device *dev, u8 state) +int switchdev_port_stp_update(struct net_device *dev, u8 state) { const struct swdev_ops *ops = dev->swdev_ops; struct net_device *lower_dev; @@ -55,57 +55,57 @@ int netdev_switch_port_stp_update(struct net_device *dev, u8 state) return ops->swdev_port_stp_update(dev, state); netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = netdev_switch_port_stp_update(lower_dev, state); + err = switchdev_port_stp_update(lower_dev, state); if (err && err != -EOPNOTSUPP) return err; } return err; } -EXPORT_SYMBOL_GPL(netdev_switch_port_stp_update); +EXPORT_SYMBOL_GPL(switchdev_port_stp_update); -static DEFINE_MUTEX(netdev_switch_mutex); -static RAW_NOTIFIER_HEAD(netdev_switch_notif_chain); +static DEFINE_MUTEX(switchdev_mutex); +static RAW_NOTIFIER_HEAD(switchdev_notif_chain); /** - * register_netdev_switch_notifier - Register notifier + * register_switchdev_notifier - Register notifier * @nb: notifier_block * * Register switch device notifier. This should be used by code * which needs to monitor events happening in particular device. * Return values are same as for atomic_notifier_chain_register(). */ -int register_netdev_switch_notifier(struct notifier_block *nb) +int register_switchdev_notifier(struct notifier_block *nb) { int err; - mutex_lock(&netdev_switch_mutex); - err = raw_notifier_chain_register(&netdev_switch_notif_chain, nb); - mutex_unlock(&netdev_switch_mutex); + mutex_lock(&switchdev_mutex); + err = raw_notifier_chain_register(&switchdev_notif_chain, nb); + mutex_unlock(&switchdev_mutex); return err; } -EXPORT_SYMBOL_GPL(register_netdev_switch_notifier); +EXPORT_SYMBOL_GPL(register_switchdev_notifier); /** - * unregister_netdev_switch_notifier - Unregister notifier + * unregister_switchdev_notifier - Unregister notifier * @nb: notifier_block * * Unregister switch device notifier. * Return values are same as for atomic_notifier_chain_unregister(). */ -int unregister_netdev_switch_notifier(struct notifier_block *nb) +int unregister_switchdev_notifier(struct notifier_block *nb) { int err; - mutex_lock(&netdev_switch_mutex); - err = raw_notifier_chain_unregister(&netdev_switch_notif_chain, nb); - mutex_unlock(&netdev_switch_mutex); + mutex_lock(&switchdev_mutex); + err = raw_notifier_chain_unregister(&switchdev_notif_chain, nb); + mutex_unlock(&switchdev_mutex); return err; } -EXPORT_SYMBOL_GPL(unregister_netdev_switch_notifier); +EXPORT_SYMBOL_GPL(unregister_switchdev_notifier); /** - * call_netdev_switch_notifiers - Call notifiers + * call_switchdev_notifiers - Call notifiers * @val: value passed unmodified to notifier function * @dev: port device * @info: notifier information data @@ -114,21 +114,21 @@ EXPORT_SYMBOL_GPL(unregister_netdev_switch_notifier); * when it needs to propagate hardware event. * Return values are same as for atomic_notifier_call_chain(). */ -int call_netdev_switch_notifiers(unsigned long val, struct net_device *dev, - struct netdev_switch_notifier_info *info) +int call_switchdev_notifiers(unsigned long val, struct net_device *dev, + struct switchdev_notifier_info *info) { int err; info->dev = dev; - mutex_lock(&netdev_switch_mutex); - err = raw_notifier_call_chain(&netdev_switch_notif_chain, val, info); - mutex_unlock(&netdev_switch_mutex); + mutex_lock(&switchdev_mutex); + err = raw_notifier_call_chain(&switchdev_notif_chain, val, info); + mutex_unlock(&switchdev_mutex); return err; } -EXPORT_SYMBOL_GPL(call_netdev_switch_notifiers); +EXPORT_SYMBOL_GPL(call_switchdev_notifiers); /** - * netdev_switch_port_bridge_setlink - Notify switch device port of bridge + * switchdev_port_bridge_setlink - Notify switch device port of bridge * port attributes * * @dev: port device @@ -137,8 +137,8 @@ EXPORT_SYMBOL_GPL(call_netdev_switch_notifiers); * * Notify switch device port of bridge port attributes */ -int netdev_switch_port_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags) +int switchdev_port_bridge_setlink(struct net_device *dev, + struct nlmsghdr *nlh, u16 flags) { const struct net_device_ops *ops = dev->netdev_ops; @@ -150,10 +150,10 @@ int netdev_switch_port_bridge_setlink(struct net_device *dev, return ops->ndo_bridge_setlink(dev, nlh, flags); } -EXPORT_SYMBOL_GPL(netdev_switch_port_bridge_setlink); +EXPORT_SYMBOL_GPL(switchdev_port_bridge_setlink); /** - * netdev_switch_port_bridge_dellink - Notify switch device port of bridge + * switchdev_port_bridge_dellink - Notify switch device port of bridge * port attribute delete * * @dev: port device @@ -162,8 +162,8 @@ EXPORT_SYMBOL_GPL(netdev_switch_port_bridge_setlink); * * Notify switch device port of bridge port attribute delete */ -int netdev_switch_port_bridge_dellink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags) +int switchdev_port_bridge_dellink(struct net_device *dev, + struct nlmsghdr *nlh, u16 flags) { const struct net_device_ops *ops = dev->netdev_ops; @@ -175,11 +175,11 @@ int netdev_switch_port_bridge_dellink(struct net_device *dev, return ops->ndo_bridge_dellink(dev, nlh, flags); } -EXPORT_SYMBOL_GPL(netdev_switch_port_bridge_dellink); +EXPORT_SYMBOL_GPL(switchdev_port_bridge_dellink); /** - * ndo_dflt_netdev_switch_port_bridge_setlink - default ndo bridge setlink - * op for master devices + * ndo_dflt_switchdev_port_bridge_setlink - default ndo bridge setlink + * op for master devices * * @dev: port device * @nlh: netlink msg with bridge port attributes @@ -187,8 +187,8 @@ EXPORT_SYMBOL_GPL(netdev_switch_port_bridge_dellink); * * Notify master device slaves of bridge port attributes */ -int ndo_dflt_netdev_switch_port_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags) +int ndo_dflt_switchdev_port_bridge_setlink(struct net_device *dev, + struct nlmsghdr *nlh, u16 flags) { struct net_device *lower_dev; struct list_head *iter; @@ -198,18 +198,18 @@ int ndo_dflt_netdev_switch_port_bridge_setlink(struct net_device *dev, return ret; netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = netdev_switch_port_bridge_setlink(lower_dev, nlh, flags); + err = switchdev_port_bridge_setlink(lower_dev, nlh, flags); if (err && err != -EOPNOTSUPP) ret = err; } return ret; } -EXPORT_SYMBOL_GPL(ndo_dflt_netdev_switch_port_bridge_setlink); +EXPORT_SYMBOL_GPL(ndo_dflt_switchdev_port_bridge_setlink); /** - * ndo_dflt_netdev_switch_port_bridge_dellink - default ndo bridge dellink - * op for master devices + * ndo_dflt_switchdev_port_bridge_dellink - default ndo bridge dellink + * op for master devices * * @dev: port device * @nlh: netlink msg with bridge port attributes @@ -217,8 +217,8 @@ EXPORT_SYMBOL_GPL(ndo_dflt_netdev_switch_port_bridge_setlink); * * Notify master device slaves of bridge port attribute deletes */ -int ndo_dflt_netdev_switch_port_bridge_dellink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags) +int ndo_dflt_switchdev_port_bridge_dellink(struct net_device *dev, + struct nlmsghdr *nlh, u16 flags) { struct net_device *lower_dev; struct list_head *iter; @@ -228,16 +228,16 @@ int ndo_dflt_netdev_switch_port_bridge_dellink(struct net_device *dev, return ret; netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = netdev_switch_port_bridge_dellink(lower_dev, nlh, flags); + err = switchdev_port_bridge_dellink(lower_dev, nlh, flags); if (err && err != -EOPNOTSUPP) ret = err; } return ret; } -EXPORT_SYMBOL_GPL(ndo_dflt_netdev_switch_port_bridge_dellink); +EXPORT_SYMBOL_GPL(ndo_dflt_switchdev_port_bridge_dellink); -static struct net_device *netdev_switch_get_lowest_dev(struct net_device *dev) +static struct net_device *switchdev_get_lowest_dev(struct net_device *dev) { const struct swdev_ops *ops = dev->swdev_ops; struct net_device *lower_dev; @@ -253,7 +253,7 @@ static struct net_device *netdev_switch_get_lowest_dev(struct net_device *dev) return dev; netdev_for_each_lower_dev(dev, lower_dev, iter) { - port_dev = netdev_switch_get_lowest_dev(lower_dev); + port_dev = switchdev_get_lowest_dev(lower_dev); if (port_dev) return port_dev; } @@ -261,7 +261,7 @@ static struct net_device *netdev_switch_get_lowest_dev(struct net_device *dev) return NULL; } -static struct net_device *netdev_switch_get_dev_by_nhs(struct fib_info *fi) +static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi) { struct netdev_phys_item_id psid; struct netdev_phys_item_id prev_psid; @@ -276,11 +276,11 @@ static struct net_device *netdev_switch_get_dev_by_nhs(struct fib_info *fi) if (!nh->nh_dev) return NULL; - dev = netdev_switch_get_lowest_dev(nh->nh_dev); + dev = switchdev_get_lowest_dev(nh->nh_dev); if (!dev) return NULL; - if (netdev_switch_parent_id_get(dev, &psid)) + if (switchdev_parent_id_get(dev, &psid)) return NULL; if (nhsel > 0) { @@ -297,7 +297,7 @@ static struct net_device *netdev_switch_get_dev_by_nhs(struct fib_info *fi) } /** - * netdev_switch_fib_ipv4_add - Add IPv4 route entry to switch + * switchdev_fib_ipv4_add - Add IPv4 route entry to switch * * @dst: route's IPv4 destination address * @dst_len: destination address length (prefix length) @@ -309,8 +309,8 @@ static struct net_device *netdev_switch_get_dev_by_nhs(struct fib_info *fi) * * Add IPv4 route entry to switch device. */ -int netdev_switch_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, - u8 tos, u8 type, u32 nlflags, u32 tb_id) +int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, + u8 tos, u8 type, u32 nlflags, u32 tb_id) { struct net_device *dev; const struct swdev_ops *ops; @@ -328,7 +328,7 @@ int netdev_switch_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, if (fi->fib_net->ipv4.fib_offload_disabled) return 0; - dev = netdev_switch_get_dev_by_nhs(fi); + dev = switchdev_get_dev_by_nhs(fi); if (!dev) return 0; ops = dev->swdev_ops; @@ -343,10 +343,10 @@ int netdev_switch_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, return err; } -EXPORT_SYMBOL_GPL(netdev_switch_fib_ipv4_add); +EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_add); /** - * netdev_switch_fib_ipv4_del - Delete IPv4 route entry from switch + * switchdev_fib_ipv4_del - Delete IPv4 route entry from switch * * @dst: route's IPv4 destination address * @dst_len: destination address length (prefix length) @@ -357,8 +357,8 @@ EXPORT_SYMBOL_GPL(netdev_switch_fib_ipv4_add); * * Delete IPv4 route entry from switch device. */ -int netdev_switch_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, - u8 tos, u8 type, u32 tb_id) +int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, + u8 tos, u8 type, u32 tb_id) { struct net_device *dev; const struct swdev_ops *ops; @@ -367,7 +367,7 @@ int netdev_switch_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, if (!(fi->fib_flags & RTNH_F_EXTERNAL)) return 0; - dev = netdev_switch_get_dev_by_nhs(fi); + dev = switchdev_get_dev_by_nhs(fi); if (!dev) return 0; ops = dev->swdev_ops; @@ -381,14 +381,14 @@ int netdev_switch_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, return err; } -EXPORT_SYMBOL_GPL(netdev_switch_fib_ipv4_del); +EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_del); /** - * netdev_switch_fib_ipv4_abort - Abort an IPv4 FIB operation + * switchdev_fib_ipv4_abort - Abort an IPv4 FIB operation * * @fi: route FIB info structure */ -void netdev_switch_fib_ipv4_abort(struct fib_info *fi) +void switchdev_fib_ipv4_abort(struct fib_info *fi) { /* There was a problem installing this route to the offload * device. For now, until we come up with more refined @@ -401,4 +401,4 @@ void netdev_switch_fib_ipv4_abort(struct fib_info *fi) fib_flush_external(fi->fib_net); fi->fib_net->ipv4.fib_offload_disabled = true; } -EXPORT_SYMBOL_GPL(netdev_switch_fib_ipv4_abort); +EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_abort); -- cgit v1.2.3 From 9d47c0a2d958e06322c88245749278633d333cca Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sun, 10 May 2015 09:47:47 -0700 Subject: switchdev: s/swdev_/switchdev_/ Turned out that "switchdev" sticks. So just unify all related terms to use this prefix. Signed-off-by: Jiri Pirko Signed-off-by: Scott Feldman Acked-by: Roopa Prabhu Acked-by: Andy Gospodarek Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 37 +++++++++++++++++---------------- include/linux/netdevice.h | 2 +- include/net/switchdev.h | 30 +++++++++++++-------------- net/dsa/slave.c | 8 ++++---- net/switchdev/switchdev.c | 40 ++++++++++++++++++------------------ 5 files changed, 59 insertions(+), 58 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 418f62b19545..7473874daf1f 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4221,8 +4221,8 @@ static const struct net_device_ops rocker_port_netdev_ops = { * swdev interface ********************/ -static int rocker_port_swdev_parent_id_get(struct net_device *dev, - struct netdev_phys_item_id *psid) +static int rocker_port_switchdev_parent_id_get(struct net_device *dev, + struct netdev_phys_item_id *psid) { struct rocker_port *rocker_port = netdev_priv(dev); struct rocker *rocker = rocker_port->rocker; @@ -4232,18 +4232,19 @@ static int rocker_port_swdev_parent_id_get(struct net_device *dev, return 0; } -static int rocker_port_swdev_port_stp_update(struct net_device *dev, u8 state) +static int rocker_port_switchdev_port_stp_update(struct net_device *dev, + u8 state) { struct rocker_port *rocker_port = netdev_priv(dev); return rocker_port_stp_update(rocker_port, state); } -static int rocker_port_swdev_fib_ipv4_add(struct net_device *dev, - __be32 dst, int dst_len, - struct fib_info *fi, - u8 tos, u8 type, - u32 nlflags, u32 tb_id) +static int rocker_port_switchdev_fib_ipv4_add(struct net_device *dev, + __be32 dst, int dst_len, + struct fib_info *fi, + u8 tos, u8 type, + u32 nlflags, u32 tb_id) { struct rocker_port *rocker_port = netdev_priv(dev); int flags = 0; @@ -4252,10 +4253,10 @@ static int rocker_port_swdev_fib_ipv4_add(struct net_device *dev, fi, tb_id, flags); } -static int rocker_port_swdev_fib_ipv4_del(struct net_device *dev, - __be32 dst, int dst_len, - struct fib_info *fi, - u8 tos, u8 type, u32 tb_id) +static int rocker_port_switchdev_fib_ipv4_del(struct net_device *dev, + __be32 dst, int dst_len, + struct fib_info *fi, + u8 tos, u8 type, u32 tb_id) { struct rocker_port *rocker_port = netdev_priv(dev); int flags = ROCKER_OP_FLAG_REMOVE; @@ -4264,11 +4265,11 @@ static int rocker_port_swdev_fib_ipv4_del(struct net_device *dev, fi, tb_id, flags); } -static const struct swdev_ops rocker_port_swdev_ops = { - .swdev_parent_id_get = rocker_port_swdev_parent_id_get, - .swdev_port_stp_update = rocker_port_swdev_port_stp_update, - .swdev_fib_ipv4_add = rocker_port_swdev_fib_ipv4_add, - .swdev_fib_ipv4_del = rocker_port_swdev_fib_ipv4_del, +static const struct switchdev_ops rocker_port_switchdev_ops = { + .switchdev_parent_id_get = rocker_port_switchdev_parent_id_get, + .switchdev_port_stp_update = rocker_port_switchdev_port_stp_update, + .switchdev_fib_ipv4_add = rocker_port_switchdev_fib_ipv4_add, + .switchdev_fib_ipv4_del = rocker_port_switchdev_fib_ipv4_del, }; /******************** @@ -4623,7 +4624,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) rocker_port_dev_addr_init(rocker, rocker_port); dev->netdev_ops = &rocker_port_netdev_ops; dev->ethtool_ops = &rocker_port_ethtool_ops; - dev->swdev_ops = &rocker_port_swdev_ops; + dev->switchdev_ops = &rocker_port_switchdev_ops; netif_napi_add(dev, &rocker_port->napi_tx, rocker_port_poll_tx, NAPI_POLL_WEIGHT); netif_napi_add(dev, &rocker_port->napi_rx, rocker_port_poll_rx, diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a6d706b2a947..2b39235b9f13 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1567,7 +1567,7 @@ struct net_device { const struct net_device_ops *netdev_ops; const struct ethtool_ops *ethtool_ops; #ifdef CONFIG_NET_SWITCHDEV - const struct swdev_ops *swdev_ops; + const struct switchdev_ops *switchdev_ops; #endif const struct header_ops *header_ops; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index cd921fa0d63a..97b556daeef7 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -19,28 +19,28 @@ struct fib_info; /** * struct switchdev_ops - switchdev operations * - * @swdev_parent_id_get: Called to get an ID of the switch chip this port + * @switchdev_parent_id_get: Called to get an ID of the switch chip this port * is part of. If driver implements this, it indicates that it * represents a port of a switch chip. * - * @swdev_port_stp_update: Called to notify switch device port of bridge + * @switchdev_port_stp_update: Called to notify switch device port of bridge * port STP state change. * - * @swdev_fib_ipv4_add: Called to add/modify IPv4 route to switch device. + * @switchdev_fib_ipv4_add: Called to add/modify IPv4 route to switch device. * - * @swdev_fib_ipv4_del: Called to delete IPv4 route from switch device. + * @switchdev_fib_ipv4_del: Called to delete IPv4 route from switch device. */ -struct swdev_ops { - int (*swdev_parent_id_get)(struct net_device *dev, - struct netdev_phys_item_id *psid); - int (*swdev_port_stp_update)(struct net_device *dev, u8 state); - int (*swdev_fib_ipv4_add)(struct net_device *dev, __be32 dst, - int dst_len, struct fib_info *fi, - u8 tos, u8 type, u32 nlflags, - u32 tb_id); - int (*swdev_fib_ipv4_del)(struct net_device *dev, __be32 dst, - int dst_len, struct fib_info *fi, - u8 tos, u8 type, u32 tb_id); +struct switchdev_ops { + int (*switchdev_parent_id_get)(struct net_device *dev, + struct netdev_phys_item_id *psid); + int (*switchdev_port_stp_update)(struct net_device *dev, u8 state); + int (*switchdev_fib_ipv4_add)(struct net_device *dev, __be32 dst, + int dst_len, struct fib_info *fi, + u8 tos, u8 type, u32 nlflags, + u32 tb_id); + int (*switchdev_fib_ipv4_del)(struct net_device *dev, __be32 dst, + int dst_len, struct fib_info *fi, + u8 tos, u8 type, u32 tb_id); }; enum switchdev_notifier_type { diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 03e041addea3..1546acf6ebd3 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -675,9 +675,9 @@ static const struct net_device_ops dsa_slave_netdev_ops = { .ndo_get_iflink = dsa_slave_get_iflink, }; -static const struct swdev_ops dsa_slave_swdev_ops = { - .swdev_parent_id_get = dsa_slave_parent_id_get, - .swdev_port_stp_update = dsa_slave_stp_update, +static const struct switchdev_ops dsa_slave_switchdev_ops = { + .switchdev_parent_id_get = dsa_slave_parent_id_get, + .switchdev_port_stp_update = dsa_slave_stp_update, }; static void dsa_slave_adjust_link(struct net_device *dev) @@ -866,7 +866,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent, eth_hw_addr_inherit(slave_dev, master); slave_dev->tx_queue_len = 0; slave_dev->netdev_ops = &dsa_slave_netdev_ops; - slave_dev->swdev_ops = &dsa_slave_swdev_ops; + slave_dev->switchdev_ops = &dsa_slave_switchdev_ops; netdev_for_each_tx_queue(slave_dev, dsa_slave_set_lockdep_class_one, NULL); diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 52613ed49a8c..b7f44a23def5 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -28,11 +28,11 @@ int switchdev_parent_id_get(struct net_device *dev, struct netdev_phys_item_id *psid) { - const struct swdev_ops *ops = dev->swdev_ops; + const struct switchdev_ops *ops = dev->switchdev_ops; - if (!ops || !ops->swdev_parent_id_get) + if (!ops || !ops->switchdev_parent_id_get) return -EOPNOTSUPP; - return ops->swdev_parent_id_get(dev, psid); + return ops->switchdev_parent_id_get(dev, psid); } EXPORT_SYMBOL_GPL(switchdev_parent_id_get); @@ -46,13 +46,13 @@ EXPORT_SYMBOL_GPL(switchdev_parent_id_get); */ int switchdev_port_stp_update(struct net_device *dev, u8 state) { - const struct swdev_ops *ops = dev->swdev_ops; + const struct switchdev_ops *ops = dev->switchdev_ops; struct net_device *lower_dev; struct list_head *iter; int err = -EOPNOTSUPP; - if (ops && ops->swdev_port_stp_update) - return ops->swdev_port_stp_update(dev, state); + if (ops && ops->switchdev_port_stp_update) + return ops->switchdev_port_stp_update(dev, state); netdev_for_each_lower_dev(dev, lower_dev, iter) { err = switchdev_port_stp_update(lower_dev, state); @@ -239,17 +239,17 @@ EXPORT_SYMBOL_GPL(ndo_dflt_switchdev_port_bridge_dellink); static struct net_device *switchdev_get_lowest_dev(struct net_device *dev) { - const struct swdev_ops *ops = dev->swdev_ops; + const struct switchdev_ops *ops = dev->switchdev_ops; struct net_device *lower_dev; struct net_device *port_dev; struct list_head *iter; /* Recusively search down until we find a sw port dev. - * (A sw port dev supports swdev_parent_id_get). + * (A sw port dev supports switchdev_parent_id_get). */ if (dev->features & NETIF_F_HW_SWITCH_OFFLOAD && - ops && ops->swdev_parent_id_get) + ops && ops->switchdev_parent_id_get) return dev; netdev_for_each_lower_dev(dev, lower_dev, iter) { @@ -313,7 +313,7 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, u32 nlflags, u32 tb_id) { struct net_device *dev; - const struct swdev_ops *ops; + const struct switchdev_ops *ops; int err = 0; /* Don't offload route if using custom ip rules or if @@ -331,12 +331,12 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, dev = switchdev_get_dev_by_nhs(fi); if (!dev) return 0; - ops = dev->swdev_ops; + ops = dev->switchdev_ops; - if (ops->swdev_fib_ipv4_add) { - err = ops->swdev_fib_ipv4_add(dev, htonl(dst), dst_len, - fi, tos, type, nlflags, - tb_id); + if (ops->switchdev_fib_ipv4_add) { + err = ops->switchdev_fib_ipv4_add(dev, htonl(dst), dst_len, + fi, tos, type, nlflags, + tb_id); if (!err) fi->fib_flags |= RTNH_F_EXTERNAL; } @@ -361,7 +361,7 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, u32 tb_id) { struct net_device *dev; - const struct swdev_ops *ops; + const struct switchdev_ops *ops; int err = 0; if (!(fi->fib_flags & RTNH_F_EXTERNAL)) @@ -370,11 +370,11 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, dev = switchdev_get_dev_by_nhs(fi); if (!dev) return 0; - ops = dev->swdev_ops; + ops = dev->switchdev_ops; - if (ops->swdev_fib_ipv4_del) { - err = ops->swdev_fib_ipv4_del(dev, htonl(dst), dst_len, - fi, tos, type, tb_id); + if (ops->switchdev_fib_ipv4_del) { + err = ops->switchdev_fib_ipv4_del(dev, htonl(dst), dst_len, + fi, tos, type, tb_id); if (!err) fi->fib_flags &= ~RTNH_F_EXTERNAL; } -- cgit v1.2.3 From 3094333d9089d43e8b8f0418676fa6ae06c27b51 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sun, 10 May 2015 09:47:48 -0700 Subject: switchdev: introduce get/set attrs ops Add two new swdev ops for get/set switch port attributes. Most swdev interactions on a port are gets or sets on port attributes, so rather than adding ops for each attribute, let's define clean get/set ops for all attributes, and then we can have clear, consistent rules on how attributes propagate on stacked devs. Add the basic algorithms for get/set attr ops. Use the same recusive algo to walk lower devs we've used for STP updates, for example. For get, compare attr value for each lower dev and only return success if attr values match across all lower devs. For sets, set the same attr value for all lower devs. We'll use a two-phase prepare-commit transaction model for sets. In the first phase, the driver(s) are asked if attr set is OK. If all OK, the commit attr set in second phase. A driver would NACK the prepare phase if it can't set the attr due to lack of resources or support, within it's control. RTNL lock must be held across both phases because we'll recurse all lower devs first in prepare phase, and then recurse all lower devs again in commit phase. If any lower dev fails the prepare phase, we need to abort the transaction for all lower devs. If lower dev recusion isn't desired, allow a flag SWITCHDEV_F_NO_RECURSE to indicate get/set only work on port (lowest) device. Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 43 ++++++++++++ net/switchdev/switchdev.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+) (limited to 'include') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 97b556daeef7..282043844bcf 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -14,6 +14,25 @@ #include #include +#define SWITCHDEV_F_NO_RECURSE BIT(0) + +enum switchdev_trans { + SWITCHDEV_TRANS_NONE, + SWITCHDEV_TRANS_PREPARE, + SWITCHDEV_TRANS_ABORT, + SWITCHDEV_TRANS_COMMIT, +}; + +enum switchdev_attr_id { + SWITCHDEV_ATTR_UNDEFINED, +}; + +struct switchdev_attr { + enum switchdev_attr_id id; + enum switchdev_trans trans; + u32 flags; +}; + struct fib_info; /** @@ -23,6 +42,10 @@ struct fib_info; * is part of. If driver implements this, it indicates that it * represents a port of a switch chip. * + * @switchdev_port_attr_get: Get a port attribute (see switchdev_attr). + * + * @switchdev_port_attr_set: Set a port attribute (see switchdev_attr). + * * @switchdev_port_stp_update: Called to notify switch device port of bridge * port STP state change. * @@ -33,6 +56,10 @@ struct fib_info; struct switchdev_ops { int (*switchdev_parent_id_get)(struct net_device *dev, struct netdev_phys_item_id *psid); + int (*switchdev_port_attr_get)(struct net_device *dev, + struct switchdev_attr *attr); + int (*switchdev_port_attr_set)(struct net_device *dev, + struct switchdev_attr *attr); int (*switchdev_port_stp_update)(struct net_device *dev, u8 state); int (*switchdev_fib_ipv4_add)(struct net_device *dev, __be32 dst, int dst_len, struct fib_info *fi, @@ -68,6 +95,10 @@ switchdev_notifier_info_to_dev(const struct switchdev_notifier_info *info) int switchdev_parent_id_get(struct net_device *dev, struct netdev_phys_item_id *psid); +int switchdev_port_attr_get(struct net_device *dev, + struct switchdev_attr *attr); +int switchdev_port_attr_set(struct net_device *dev, + struct switchdev_attr *attr); int switchdev_port_stp_update(struct net_device *dev, u8 state); int register_switchdev_notifier(struct notifier_block *nb); int unregister_switchdev_notifier(struct notifier_block *nb); @@ -95,6 +126,18 @@ static inline int switchdev_parent_id_get(struct net_device *dev, return -EOPNOTSUPP; } +static inline int switchdev_port_attr_get(struct net_device *dev, + struct switchdev_attr *attr) +{ + return -EOPNOTSUPP; +} + +static inline int switchdev_port_attr_set(struct net_device *dev, + struct switchdev_attr *attr) +{ + return -EOPNOTSUPP; +} + static inline int switchdev_port_stp_update(struct net_device *dev, u8 state) { diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index b7f44a23def5..8f47187dc185 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -36,6 +36,175 @@ int switchdev_parent_id_get(struct net_device *dev, } EXPORT_SYMBOL_GPL(switchdev_parent_id_get); +/** + * switchdev_port_attr_get - Get port attribute + * + * @dev: port device + * @attr: attribute to get + */ +int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr) +{ + const struct switchdev_ops *ops = dev->switchdev_ops; + struct net_device *lower_dev; + struct list_head *iter; + struct switchdev_attr first = { + .id = SWITCHDEV_ATTR_UNDEFINED + }; + int err = -EOPNOTSUPP; + + if (ops && ops->switchdev_port_attr_get) + return ops->switchdev_port_attr_get(dev, attr); + + if (attr->flags & SWITCHDEV_F_NO_RECURSE) + return err; + + /* Switch device port(s) may be stacked under + * bond/team/vlan dev, so recurse down to get attr on + * each port. Return -ENODATA if attr values don't + * compare across ports. + */ + + netdev_for_each_lower_dev(dev, lower_dev, iter) { + err = switchdev_port_attr_get(lower_dev, attr); + if (err) + break; + if (first.id == SWITCHDEV_ATTR_UNDEFINED) + first = *attr; + else if (memcmp(&first, attr, sizeof(*attr))) + return -ENODATA; + } + + return err; +} +EXPORT_SYMBOL_GPL(switchdev_port_attr_get); + +static int __switchdev_port_attr_set(struct net_device *dev, + struct switchdev_attr *attr) +{ + const struct switchdev_ops *ops = dev->switchdev_ops; + struct net_device *lower_dev; + struct list_head *iter; + int err = -EOPNOTSUPP; + + if (ops && ops->switchdev_port_attr_set) + return ops->switchdev_port_attr_set(dev, attr); + + if (attr->flags & SWITCHDEV_F_NO_RECURSE) + return err; + + /* Switch device port(s) may be stacked under + * bond/team/vlan dev, so recurse down to set attr on + * each port. + */ + + netdev_for_each_lower_dev(dev, lower_dev, iter) { + err = __switchdev_port_attr_set(lower_dev, attr); + if (err) + break; + } + + return err; +} + +struct switchdev_attr_set_work { + struct work_struct work; + struct net_device *dev; + struct switchdev_attr attr; +}; + +static void switchdev_port_attr_set_work(struct work_struct *work) +{ + struct switchdev_attr_set_work *asw = + container_of(work, struct switchdev_attr_set_work, work); + int err; + + rtnl_lock(); + err = switchdev_port_attr_set(asw->dev, &asw->attr); + BUG_ON(err); + rtnl_unlock(); + + dev_put(asw->dev); + kfree(work); +} + +static int switchdev_port_attr_set_defer(struct net_device *dev, + struct switchdev_attr *attr) +{ + struct switchdev_attr_set_work *asw; + + asw = kmalloc(sizeof(*asw), GFP_ATOMIC); + if (!asw) + return -ENOMEM; + + INIT_WORK(&asw->work, switchdev_port_attr_set_work); + + dev_hold(dev); + asw->dev = dev; + memcpy(&asw->attr, attr, sizeof(asw->attr)); + + schedule_work(&asw->work); + + return 0; +} + +/** + * switchdev_port_attr_set - Set port attribute + * + * @dev: port device + * @attr: attribute to set + * + * Use a 2-phase prepare-commit transaction model to ensure + * system is not left in a partially updated state due to + * failure from driver/device. + */ +int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) +{ + int err; + + if (!rtnl_is_locked()) { + /* Running prepare-commit transaction across stacked + * devices requires nothing moves, so if rtnl_lock is + * not held, schedule a worker thread to hold rtnl_lock + * while setting attr. + */ + + return switchdev_port_attr_set_defer(dev, attr); + } + + /* Phase I: prepare for attr set. Driver/device should fail + * here if there are going to be issues in the commit phase, + * such as lack of resources or support. The driver/device + * should reserve resources needed for the commit phase here, + * but should not commit the attr. + */ + + attr->trans = SWITCHDEV_TRANS_PREPARE; + err = __switchdev_port_attr_set(dev, attr); + if (err) { + /* Prepare phase failed: abort the transaction. Any + * resources reserved in the prepare phase are + * released. + */ + + attr->trans = SWITCHDEV_TRANS_ABORT; + __switchdev_port_attr_set(dev, attr); + + return err; + } + + /* Phase II: commit attr set. This cannot fail as a fault + * of driver/device. If it does, it's a bug in the driver/device + * because the driver said everythings was OK in phase I. + */ + + attr->trans = SWITCHDEV_TRANS_COMMIT; + err = __switchdev_port_attr_set(dev, attr); + BUG_ON(err); + + return err; +} +EXPORT_SYMBOL_GPL(switchdev_port_attr_set); + /** * switchdev_port_stp_update - Notify switch device port of STP * state change -- cgit v1.2.3 From f8e20a9f87d33865cc1d67f13da0db8d457fc3c9 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sun, 10 May 2015 09:47:49 -0700 Subject: switchdev: convert parent_id_get to switchdev attr get Switch ID is just a gettable port attribute. Convert switchdev op switchdev_parent_id_get to a switchdev attr. Note: for sysfs and netlink interfaces, SWITCHDEV_ATTR_PORT_PARENT_ID is called with SWITCHDEV_F_NO_RECUSE to limit switch ID user-visiblity to only port netdevs. So when a port is stacked under bond/bridge, the user can only query switch id via the switch ports, but not via the upper devices Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 17 +++++++++++----- include/net/switchdev.h | 18 ++++------------- net/core/net-sysfs.c | 10 +++++++--- net/core/rtnetlink.c | 9 ++++++--- net/dsa/slave.c | 16 ++++++++++----- net/switchdev/switchdev.c | 38 +++++++++++------------------------- 6 files changed, 51 insertions(+), 57 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 7473874daf1f..24282991d9fd 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4221,14 +4221,21 @@ static const struct net_device_ops rocker_port_netdev_ops = { * swdev interface ********************/ -static int rocker_port_switchdev_parent_id_get(struct net_device *dev, - struct netdev_phys_item_id *psid) +static int rocker_port_attr_get(struct net_device *dev, + struct switchdev_attr *attr) { struct rocker_port *rocker_port = netdev_priv(dev); struct rocker *rocker = rocker_port->rocker; - psid->id_len = sizeof(rocker->hw.id); - memcpy(&psid->id, &rocker->hw.id, psid->id_len); + switch (attr->id) { + case SWITCHDEV_ATTR_PORT_PARENT_ID: + attr->ppid.id_len = sizeof(rocker->hw.id); + memcpy(&attr->ppid.id, &rocker->hw.id, attr->ppid.id_len); + break; + default: + return -EOPNOTSUPP; + } + return 0; } @@ -4266,7 +4273,7 @@ static int rocker_port_switchdev_fib_ipv4_del(struct net_device *dev, } static const struct switchdev_ops rocker_port_switchdev_ops = { - .switchdev_parent_id_get = rocker_port_switchdev_parent_id_get, + .switchdev_port_attr_get = rocker_port_attr_get, .switchdev_port_stp_update = rocker_port_switchdev_port_stp_update, .switchdev_fib_ipv4_add = rocker_port_switchdev_fib_ipv4_add, .switchdev_fib_ipv4_del = rocker_port_switchdev_fib_ipv4_del, diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 282043844bcf..93316e7ab372 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -25,12 +25,16 @@ enum switchdev_trans { enum switchdev_attr_id { SWITCHDEV_ATTR_UNDEFINED, + SWITCHDEV_ATTR_PORT_PARENT_ID, }; struct switchdev_attr { enum switchdev_attr_id id; enum switchdev_trans trans; u32 flags; + union { + struct netdev_phys_item_id ppid; /* PORT_PARENT_ID */ + }; }; struct fib_info; @@ -38,10 +42,6 @@ struct fib_info; /** * struct switchdev_ops - switchdev operations * - * @switchdev_parent_id_get: Called to get an ID of the switch chip this port - * is part of. If driver implements this, it indicates that it - * represents a port of a switch chip. - * * @switchdev_port_attr_get: Get a port attribute (see switchdev_attr). * * @switchdev_port_attr_set: Set a port attribute (see switchdev_attr). @@ -54,8 +54,6 @@ struct fib_info; * @switchdev_fib_ipv4_del: Called to delete IPv4 route from switch device. */ struct switchdev_ops { - int (*switchdev_parent_id_get)(struct net_device *dev, - struct netdev_phys_item_id *psid); int (*switchdev_port_attr_get)(struct net_device *dev, struct switchdev_attr *attr); int (*switchdev_port_attr_set)(struct net_device *dev, @@ -93,8 +91,6 @@ switchdev_notifier_info_to_dev(const struct switchdev_notifier_info *info) #ifdef CONFIG_NET_SWITCHDEV -int switchdev_parent_id_get(struct net_device *dev, - struct netdev_phys_item_id *psid); int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr); int switchdev_port_attr_set(struct net_device *dev, @@ -120,12 +116,6 @@ void switchdev_fib_ipv4_abort(struct fib_info *fi); #else -static inline int switchdev_parent_id_get(struct net_device *dev, - struct netdev_phys_item_id *psid) -{ - return -EOPNOTSUPP; -} - static inline int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr) { diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index be86a7ce9282..5a9ce96f6d27 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -458,11 +458,15 @@ static ssize_t phys_switch_id_show(struct device *dev, return restart_syscall(); if (dev_isalive(netdev)) { - struct netdev_phys_item_id ppid; + struct switchdev_attr attr = { + .id = SWITCHDEV_ATTR_PORT_PARENT_ID, + .flags = SWITCHDEV_F_NO_RECURSE, + }; - ret = switchdev_parent_id_get(netdev, &ppid); + ret = switchdev_port_attr_get(netdev, &attr); if (!ret) - ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id); + ret = sprintf(buf, "%*phN\n", attr.ppid.id_len, + attr.ppid.id); } rtnl_unlock(); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index fcd41fcd7e70..c6c6b2c34926 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1004,16 +1004,19 @@ static int rtnl_phys_port_name_fill(struct sk_buff *skb, struct net_device *dev) static int rtnl_phys_switch_id_fill(struct sk_buff *skb, struct net_device *dev) { int err; - struct netdev_phys_item_id psid; + struct switchdev_attr attr = { + .id = SWITCHDEV_ATTR_PORT_PARENT_ID, + .flags = SWITCHDEV_F_NO_RECURSE, + }; - err = switchdev_parent_id_get(dev, &psid); + err = switchdev_port_attr_get(dev, &attr); if (err) { if (err == -EOPNOTSUPP) return 0; return err; } - if (nla_put(skb, IFLA_PHYS_SWITCH_ID, psid.id_len, psid.id)) + if (nla_put(skb, IFLA_PHYS_SWITCH_ID, attr.ppid.id_len, attr.ppid.id)) return -EMSGSIZE; return 0; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 1546acf6ebd3..de705b674ac9 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -382,14 +382,20 @@ static int dsa_slave_bridge_port_leave(struct net_device *dev) return ret; } -static int dsa_slave_parent_id_get(struct net_device *dev, - struct netdev_phys_item_id *psid) +static int dsa_slave_port_attr_get(struct net_device *dev, + struct switchdev_attr *attr) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; - psid->id_len = sizeof(ds->index); - memcpy(&psid->id, &ds->index, psid->id_len); + switch (attr->id) { + case SWITCHDEV_ATTR_PORT_PARENT_ID: + attr->ppid.id_len = sizeof(ds->index); + memcpy(&attr->ppid.id, &ds->index, attr->ppid.id_len); + break; + default: + return -EOPNOTSUPP; + } return 0; } @@ -676,7 +682,7 @@ static const struct net_device_ops dsa_slave_netdev_ops = { }; static const struct switchdev_ops dsa_slave_switchdev_ops = { - .switchdev_parent_id_get = dsa_slave_parent_id_get, + .switchdev_port_attr_get = dsa_slave_port_attr_get, .switchdev_port_stp_update = dsa_slave_stp_update, }; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 8f47187dc185..117fd0797abd 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -18,24 +18,6 @@ #include #include -/** - * switchdev_parent_id_get - Get ID of a switch - * @dev: port device - * @psid: switch ID - * - * Get ID of a switch this port is part of. - */ -int switchdev_parent_id_get(struct net_device *dev, - struct netdev_phys_item_id *psid) -{ - const struct switchdev_ops *ops = dev->switchdev_ops; - - if (!ops || !ops->switchdev_parent_id_get) - return -EOPNOTSUPP; - return ops->switchdev_parent_id_get(dev, psid); -} -EXPORT_SYMBOL_GPL(switchdev_parent_id_get); - /** * switchdev_port_attr_get - Get port attribute * @@ -414,11 +396,10 @@ static struct net_device *switchdev_get_lowest_dev(struct net_device *dev) struct list_head *iter; /* Recusively search down until we find a sw port dev. - * (A sw port dev supports switchdev_parent_id_get). + * (A sw port dev supports switchdev_port_attr_get). */ - if (dev->features & NETIF_F_HW_SWITCH_OFFLOAD && - ops && ops->switchdev_parent_id_get) + if (ops && ops->switchdev_port_attr_get) return dev; netdev_for_each_lower_dev(dev, lower_dev, iter) { @@ -432,8 +413,10 @@ static struct net_device *switchdev_get_lowest_dev(struct net_device *dev) static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi) { - struct netdev_phys_item_id psid; - struct netdev_phys_item_id prev_psid; + struct switchdev_attr attr = { + .id = SWITCHDEV_ATTR_PORT_PARENT_ID, + }; + struct switchdev_attr prev_attr; struct net_device *dev = NULL; int nhsel; @@ -449,17 +432,18 @@ static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi) if (!dev) return NULL; - if (switchdev_parent_id_get(dev, &psid)) + if (switchdev_port_attr_get(dev, &attr)) return NULL; if (nhsel > 0) { - if (prev_psid.id_len != psid.id_len) + if (prev_attr.ppid.id_len != attr.ppid.id_len) return NULL; - if (memcmp(prev_psid.id, psid.id, psid.id_len)) + if (memcmp(prev_attr.ppid.id, attr.ppid.id, + attr.ppid.id_len)) return NULL; } - prev_psid = psid; + prev_attr = attr; } return dev; -- cgit v1.2.3 From 3563606258cf3b8f02eabddb1cb45a94c44d9611 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sun, 10 May 2015 09:47:51 -0700 Subject: switchdev: convert STP update to switchdev attr set STP update is just a settable port attribute, so convert switchdev_port_stp_update to an attr set. For DSA, the prepare phase is skipped and STP updates are only done in the commit phase. This is because currently the DSA drivers don't need to allocate any memory for STP updates and the STP update will not fail to HW (unless something horrible goes wrong on the MDIO bus, in which case the prepare phase wouldn't have been able to predict anyway). Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 14 +++++--------- include/net/switchdev.h | 13 ++----------- net/bridge/br_stp.c | 6 +++++- net/dsa/slave.c | 20 +++++++++++++++++++- net/switchdev/switchdev.c | 28 ---------------------------- 5 files changed, 31 insertions(+), 50 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index fa0fa545c0d1..36827d39a70a 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4395,14 +4395,6 @@ static int rocker_port_attr_get(struct net_device *dev, return 0; } -static int rocker_port_switchdev_port_stp_update(struct net_device *dev, - u8 state) -{ - struct rocker_port *rocker_port = netdev_priv(dev); - - return rocker_port_stp_update(rocker_port, SWITCHDEV_TRANS_NONE, state); -} - static void rocker_port_trans_abort(struct rocker_port *rocker_port) { struct list_head *mem, *tmp; @@ -4431,6 +4423,10 @@ static int rocker_port_attr_set(struct net_device *dev, } switch (attr->id) { + case SWITCHDEV_ATTR_PORT_STP_STATE: + err = rocker_port_stp_update(rocker_port, attr->trans, + attr->stp_state); + break; default: err = -EOPNOTSUPP; break; @@ -4466,7 +4462,7 @@ static int rocker_port_switchdev_fib_ipv4_del(struct net_device *dev, static const struct switchdev_ops rocker_port_switchdev_ops = { .switchdev_port_attr_get = rocker_port_attr_get, - .switchdev_port_stp_update = rocker_port_switchdev_port_stp_update, + .switchdev_port_attr_set = rocker_port_attr_set, .switchdev_fib_ipv4_add = rocker_port_switchdev_fib_ipv4_add, .switchdev_fib_ipv4_del = rocker_port_switchdev_fib_ipv4_del, }; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 93316e7ab372..aec5e49661a2 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -26,6 +26,7 @@ enum switchdev_trans { enum switchdev_attr_id { SWITCHDEV_ATTR_UNDEFINED, SWITCHDEV_ATTR_PORT_PARENT_ID, + SWITCHDEV_ATTR_PORT_STP_STATE, }; struct switchdev_attr { @@ -34,6 +35,7 @@ struct switchdev_attr { u32 flags; union { struct netdev_phys_item_id ppid; /* PORT_PARENT_ID */ + u8 stp_state; /* PORT_STP_STATE */ }; }; @@ -46,9 +48,6 @@ struct fib_info; * * @switchdev_port_attr_set: Set a port attribute (see switchdev_attr). * - * @switchdev_port_stp_update: Called to notify switch device port of bridge - * port STP state change. - * * @switchdev_fib_ipv4_add: Called to add/modify IPv4 route to switch device. * * @switchdev_fib_ipv4_del: Called to delete IPv4 route from switch device. @@ -58,7 +57,6 @@ struct switchdev_ops { struct switchdev_attr *attr); int (*switchdev_port_attr_set)(struct net_device *dev, struct switchdev_attr *attr); - int (*switchdev_port_stp_update)(struct net_device *dev, u8 state); int (*switchdev_fib_ipv4_add)(struct net_device *dev, __be32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, u32 nlflags, @@ -95,7 +93,6 @@ int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr); int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr); -int switchdev_port_stp_update(struct net_device *dev, u8 state); int register_switchdev_notifier(struct notifier_block *nb); int unregister_switchdev_notifier(struct notifier_block *nb); int call_switchdev_notifiers(unsigned long val, struct net_device *dev, @@ -128,12 +125,6 @@ static inline int switchdev_port_attr_set(struct net_device *dev, return -EOPNOTSUPP; } -static inline int switchdev_port_stp_update(struct net_device *dev, - u8 state) -{ - return -EOPNOTSUPP; -} - static inline int register_switchdev_notifier(struct notifier_block *nb) { return 0; diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index 28e3f4bc01e0..b9300da31565 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -39,10 +39,14 @@ void br_log_state(const struct net_bridge_port *p) void br_set_state(struct net_bridge_port *p, unsigned int state) { + struct switchdev_attr attr = { + .id = SWITCHDEV_ATTR_PORT_STP_STATE, + .stp_state = state, + }; int err; p->state = state; - err = switchdev_port_stp_update(p->dev, state); + err = switchdev_port_attr_set(p->dev, &attr); if (err && err != -EOPNOTSUPP) br_warn(p->br, "error setting offload STP state on port %u(%s)\n", (unsigned int) p->port_no, p->dev->name); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index de705b674ac9..3fb5210e318c 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -345,6 +345,24 @@ static int dsa_slave_stp_update(struct net_device *dev, u8 state) return ret; } +static int dsa_slave_port_attr_set(struct net_device *dev, + struct switchdev_attr *attr) +{ + int ret = 0; + + switch (attr->id) { + case SWITCHDEV_ATTR_PORT_STP_STATE: + if (attr->trans == SWITCHDEV_TRANS_COMMIT) + ret = dsa_slave_stp_update(dev, attr->stp_state); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + static int dsa_slave_bridge_port_join(struct net_device *dev, struct net_device *br) { @@ -683,7 +701,7 @@ static const struct net_device_ops dsa_slave_netdev_ops = { static const struct switchdev_ops dsa_slave_switchdev_ops = { .switchdev_port_attr_get = dsa_slave_port_attr_get, - .switchdev_port_stp_update = dsa_slave_stp_update, + .switchdev_port_attr_set = dsa_slave_port_attr_set, }; static void dsa_slave_adjust_link(struct net_device *dev) diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 117fd0797abd..a3c359004902 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -187,34 +187,6 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) } EXPORT_SYMBOL_GPL(switchdev_port_attr_set); -/** - * switchdev_port_stp_update - Notify switch device port of STP - * state change - * @dev: port device - * @state: port STP state - * - * Notify switch device port of bridge port STP state change. - */ -int switchdev_port_stp_update(struct net_device *dev, u8 state) -{ - const struct switchdev_ops *ops = dev->switchdev_ops; - struct net_device *lower_dev; - struct list_head *iter; - int err = -EOPNOTSUPP; - - if (ops && ops->switchdev_port_stp_update) - return ops->switchdev_port_stp_update(dev, state); - - netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = switchdev_port_stp_update(lower_dev, state); - if (err && err != -EOPNOTSUPP) - return err; - } - - return err; -} -EXPORT_SYMBOL_GPL(switchdev_port_stp_update); - static DEFINE_MUTEX(switchdev_mutex); static RAW_NOTIFIER_HEAD(switchdev_notif_chain); -- cgit v1.2.3 From 491d0f1533ac750260406dbf84cdad44fd3d8a29 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sun, 10 May 2015 09:47:52 -0700 Subject: switchdev: introduce switchdev add/del obj ops Like switchdev attr get/set, add new switchdev obj add/del. switchdev objs will be things like VLANs or FIB entries, so add/del fits better for objects than get/set used for attributes. Use same two-phase prepare-commit transaction model as in attr set. Signed-off-by: Scott Feldman Acked-by: Sridhar Samudrala Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 31 ++++++++++++++ net/switchdev/switchdev.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) (limited to 'include') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index aec5e49661a2..4f43300df72c 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -41,6 +41,15 @@ struct switchdev_attr { struct fib_info; +enum switchdev_obj_id { + SWITCHDEV_OBJ_UNDEFINED, +}; + +struct switchdev_obj { + enum switchdev_obj_id id; + enum switchdev_trans trans; +}; + /** * struct switchdev_ops - switchdev operations * @@ -48,6 +57,10 @@ struct fib_info; * * @switchdev_port_attr_set: Set a port attribute (see switchdev_attr). * + * @switchdev_port_obj_add: Add an object to port (see switchdev_obj). + * + * @switchdev_port_obj_del: Delete an object from port (see switchdev_obj). + * * @switchdev_fib_ipv4_add: Called to add/modify IPv4 route to switch device. * * @switchdev_fib_ipv4_del: Called to delete IPv4 route from switch device. @@ -57,6 +70,10 @@ struct switchdev_ops { struct switchdev_attr *attr); int (*switchdev_port_attr_set)(struct net_device *dev, struct switchdev_attr *attr); + int (*switchdev_port_obj_add)(struct net_device *dev, + struct switchdev_obj *obj); + int (*switchdev_port_obj_del)(struct net_device *dev, + struct switchdev_obj *obj); int (*switchdev_fib_ipv4_add)(struct net_device *dev, __be32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, u32 nlflags, @@ -93,6 +110,8 @@ int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr); int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr); +int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj); +int switchdev_port_obj_del(struct net_device *dev, struct switchdev_obj *obj); int register_switchdev_notifier(struct notifier_block *nb); int unregister_switchdev_notifier(struct notifier_block *nb); int call_switchdev_notifiers(unsigned long val, struct net_device *dev, @@ -125,6 +144,18 @@ static inline int switchdev_port_attr_set(struct net_device *dev, return -EOPNOTSUPP; } +static inline int switchdev_port_obj_add(struct net_device *dev, + struct switchdev_obj *obj) +{ + return -EOPNOTSUPP; +} + +static inline int switchdev_port_obj_del(struct net_device *dev, + struct switchdev_obj *obj) +{ + return -EOPNOTSUPP; +} + static inline int register_switchdev_notifier(struct notifier_block *nb) { return 0; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index a3c359004902..3d4d99a70b80 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -187,6 +187,113 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) } EXPORT_SYMBOL_GPL(switchdev_port_attr_set); +int __switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) +{ + const struct switchdev_ops *ops = dev->switchdev_ops; + struct net_device *lower_dev; + struct list_head *iter; + int err = -EOPNOTSUPP; + + if (ops && ops->switchdev_port_obj_add) + return ops->switchdev_port_obj_add(dev, obj); + + /* Switch device port(s) may be stacked under + * bond/team/vlan dev, so recurse down to add object on + * each port. + */ + + netdev_for_each_lower_dev(dev, lower_dev, iter) { + err = __switchdev_port_obj_add(lower_dev, obj); + if (err) + break; + } + + return err; +} + +/** + * switchdev_port_obj_add - Add port object + * + * @dev: port device + * @obj: object to add + * + * Use a 2-phase prepare-commit transaction model to ensure + * system is not left in a partially updated state due to + * failure from driver/device. + * + * rtnl_lock must be held. + */ +int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) +{ + int err; + + ASSERT_RTNL(); + + /* Phase I: prepare for obj add. Driver/device should fail + * here if there are going to be issues in the commit phase, + * such as lack of resources or support. The driver/device + * should reserve resources needed for the commit phase here, + * but should not commit the obj. + */ + + obj->trans = SWITCHDEV_TRANS_PREPARE; + err = __switchdev_port_obj_add(dev, obj); + if (err) { + /* Prepare phase failed: abort the transaction. Any + * resources reserved in the prepare phase are + * released. + */ + + obj->trans = SWITCHDEV_TRANS_ABORT; + __switchdev_port_obj_add(dev, obj); + + return err; + } + + /* Phase II: commit obj add. This cannot fail as a fault + * of driver/device. If it does, it's a bug in the driver/device + * because the driver said everythings was OK in phase I. + */ + + obj->trans = SWITCHDEV_TRANS_COMMIT; + err = __switchdev_port_obj_add(dev, obj); + WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id); + + return err; +} +EXPORT_SYMBOL_GPL(switchdev_port_obj_add); + +/** + * switchdev_port_obj_del - Delete port object + * + * @dev: port device + * @obj: object to delete + */ +int switchdev_port_obj_del(struct net_device *dev, struct switchdev_obj *obj) +{ + const struct switchdev_ops *ops = dev->switchdev_ops; + struct net_device *lower_dev; + struct list_head *iter; + int err = -EOPNOTSUPP; + + if (ops && ops->switchdev_port_obj_del) + return ops->switchdev_port_obj_del(dev, obj); + + /* Switch device port(s) may be stacked under + * bond/team/vlan dev, so recurse down to delete object on + * each port. + */ + + netdev_for_each_lower_dev(dev, lower_dev, iter) { + err = switchdev_port_obj_del(lower_dev, obj); + if (err) + break; + } + + return err; +} +EXPORT_SYMBOL_GPL(switchdev_port_obj_del); + static DEFINE_MUTEX(switchdev_mutex); static RAW_NOTIFIER_HEAD(switchdev_notif_chain); -- cgit v1.2.3 From 6fc3016da7c1587aa59e71f8c4dbc4cf1343eab2 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sun, 10 May 2015 09:47:53 -0700 Subject: switchdev: add port vlan obj VLAN obj has flags (PVID and untagged) as well as start and end vid ranges. The switchdev driver can optimize programing the device using the ranges. Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 4f43300df72c..e598c2d45786 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -43,11 +43,19 @@ struct fib_info; enum switchdev_obj_id { SWITCHDEV_OBJ_UNDEFINED, + SWITCHDEV_OBJ_PORT_VLAN, }; struct switchdev_obj { enum switchdev_obj_id id; enum switchdev_trans trans; + union { + struct switchdev_obj_vlan { /* PORT_VLAN */ + u16 flags; + u16 vid_start; + u16 vid_end; + } vlan; + }; }; /** -- cgit v1.2.3 From 6004c86718998aee1337efd3b087d6e17284632d Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sun, 10 May 2015 09:47:55 -0700 Subject: switchdev: add bridge port flags attr rocker: use switchdev get/set attr for bridge port flags Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 25 +++++++++++++++++++++++++ include/net/switchdev.h | 2 ++ 2 files changed, 27 insertions(+) (limited to 'include') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 84084806231a..ceb6a6436144 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4394,6 +4394,9 @@ static int rocker_port_attr_get(struct net_device *dev, attr->ppid.id_len = sizeof(rocker->hw.id); memcpy(&attr->ppid.id, &rocker->hw.id, attr->ppid.id_len); break; + case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS: + attr->brport_flags = rocker_port->brport_flags; + break; default: return -EOPNOTSUPP; } @@ -4411,6 +4414,24 @@ static void rocker_port_trans_abort(struct rocker_port *rocker_port) } } +static int rocker_port_brport_flags_set(struct rocker_port *rocker_port, + enum switchdev_trans trans, + unsigned long brport_flags) +{ + unsigned long orig_flags; + int err = 0; + + orig_flags = rocker_port->brport_flags; + rocker_port->brport_flags = brport_flags; + if ((orig_flags ^ rocker_port->brport_flags) & BR_LEARNING) + err = rocker_port_set_learning(rocker_port, trans); + + if (trans == SWITCHDEV_TRANS_PREPARE) + rocker_port->brport_flags = orig_flags; + + return err; +} + static int rocker_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) { @@ -4433,6 +4454,10 @@ static int rocker_port_attr_set(struct net_device *dev, err = rocker_port_stp_update(rocker_port, attr->trans, attr->stp_state); break; + case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS: + err = rocker_port_brport_flags_set(rocker_port, attr->trans, + attr->brport_flags); + break; default: err = -EOPNOTSUPP; break; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index e598c2d45786..6cf6de1a90b4 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -27,6 +27,7 @@ enum switchdev_attr_id { SWITCHDEV_ATTR_UNDEFINED, SWITCHDEV_ATTR_PORT_PARENT_ID, SWITCHDEV_ATTR_PORT_STP_STATE, + SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS, }; struct switchdev_attr { @@ -36,6 +37,7 @@ struct switchdev_attr { union { struct netdev_phys_item_id ppid; /* PORT_PARENT_ID */ u8 stp_state; /* PORT_STP_STATE */ + unsigned long brport_flags; /* PORT_BRIDGE_FLAGS */ }; }; -- cgit v1.2.3 From e71f220b342d78cfb8ee9f1b60f1351f7183f2a5 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sun, 10 May 2015 09:47:58 -0700 Subject: switchdev: remove old switchdev_port_bridge_setlink New attr-based bridge_setlink can recurse lower devs and recover on err, so remove old wrapper (including ndo_dflt_switchdev_port_bridge_setlink). Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 9 --------- net/switchdev/switchdev.c | 30 ------------------------------ 2 files changed, 39 deletions(-) (limited to 'include') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 6cf6de1a90b4..ce5ceb2dc677 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -132,8 +132,6 @@ int switchdev_port_bridge_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags); int ndo_dflt_switchdev_port_bridge_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags); -int ndo_dflt_switchdev_port_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags); int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, u32 nlflags, u32 tb_id); int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, @@ -204,13 +202,6 @@ static inline int ndo_dflt_switchdev_port_bridge_dellink(struct net_device *dev, return 0; } -static inline int ndo_dflt_switchdev_port_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh, - u16 flags) -{ - return 0; -} - static inline int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index b01791a9b56d..dcdec9de9137 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -536,36 +536,6 @@ int switchdev_port_bridge_dellink(struct net_device *dev, } EXPORT_SYMBOL_GPL(switchdev_port_bridge_dellink); -/** - * ndo_dflt_switchdev_port_bridge_setlink - default ndo bridge setlink - * op for master devices - * - * @dev: port device - * @nlh: netlink msg with bridge port attributes - * @flags: bridge setlink flags - * - * Notify master device slaves of bridge port attributes - */ -int ndo_dflt_switchdev_port_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags) -{ - struct net_device *lower_dev; - struct list_head *iter; - int ret = 0, err = 0; - - if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD)) - return ret; - - netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = switchdev_port_bridge_setlink(lower_dev, nlh, flags); - if (err && err != -EOPNOTSUPP) - ret = err; - } - - return ret; -} -EXPORT_SYMBOL_GPL(ndo_dflt_switchdev_port_bridge_setlink); - /** * ndo_dflt_switchdev_port_bridge_dellink - default ndo bridge dellink * op for master devices -- cgit v1.2.3 From 5c34e0221423aeabc0b085adc5fccda3f91e2c49 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sun, 10 May 2015 09:48:00 -0700 Subject: switchdev: add new switchdev_port_bridge_dellink Same change as setlink. Provide the wrapper op for SELF ndo_bridge_dellink and call into the switchdev driver to delete afspec VLANs. Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 6 ++++++ net/switchdev/switchdev.c | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index ce5ceb2dc677..8ffadca9e760 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -164,6 +164,12 @@ static inline int switchdev_port_obj_del(struct net_device *dev, return -EOPNOTSUPP; } +static inline int switchdev_port_bridge_dellink(struct net_device *dev, + struct nlmsghdr *nlh, u16 flags) +{ + return -EOPNOTSUPP; +} + static inline int register_switchdev_notifier(struct notifier_block *nb) { return 0; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index dcdec9de9137..8ce678e397b4 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -512,27 +512,27 @@ int switchdev_port_bridge_setlink(struct net_device *dev, EXPORT_SYMBOL_GPL(switchdev_port_bridge_setlink); /** - * switchdev_port_bridge_dellink - Notify switch device port of bridge - * port attribute delete + * switchdev_port_bridge_dellink - Set bridge port attributes * * @dev: port device - * @nlh: netlink msg with bridge port attributes - * @flags: bridge setlink flags + * @nlh: netlink header + * @flags: netlink flags * - * Notify switch device port of bridge port attribute delete + * Called for SELF on rtnl_bridge_dellink to set bridge port + * attributes. */ int switchdev_port_bridge_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags) { - const struct net_device_ops *ops = dev->netdev_ops; - - if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD)) - return 0; + struct nlattr *afspec; - if (!ops->ndo_bridge_dellink) - return -EOPNOTSUPP; + afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), + IFLA_AF_SPEC); + if (afspec) + return switchdev_port_br_afspec(dev, afspec, + switchdev_port_obj_del); - return ops->ndo_bridge_dellink(dev, nlh, flags); + return 0; } EXPORT_SYMBOL_GPL(switchdev_port_bridge_dellink); -- cgit v1.2.3 From 87a5dae59e7abaad911ab719caa5548dd6df5557 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sun, 10 May 2015 09:48:02 -0700 Subject: switchdev: remove unused switchdev_port_bridge_dellink Now we can remove old wrappers for dellink. Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 15 --------------- net/switchdev/switchdev.c | 30 ------------------------------ 2 files changed, 45 deletions(-) (limited to 'include') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 8ffadca9e760..397b1e6e04f6 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -130,8 +130,6 @@ int switchdev_port_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags); int switchdev_port_bridge_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags); -int ndo_dflt_switchdev_port_bridge_dellink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags); int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, u32 nlflags, u32 tb_id); int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, @@ -164,12 +162,6 @@ static inline int switchdev_port_obj_del(struct net_device *dev, return -EOPNOTSUPP; } -static inline int switchdev_port_bridge_dellink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags) -{ - return -EOPNOTSUPP; -} - static inline int register_switchdev_notifier(struct notifier_block *nb) { return 0; @@ -201,13 +193,6 @@ static inline int switchdev_port_bridge_dellink(struct net_device *dev, return -EOPNOTSUPP; } -static inline int ndo_dflt_switchdev_port_bridge_dellink(struct net_device *dev, - struct nlmsghdr *nlh, - u16 flags) -{ - return 0; -} - static inline int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 8ce678e397b4..0e15b6f6bb56 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -536,36 +536,6 @@ int switchdev_port_bridge_dellink(struct net_device *dev, } EXPORT_SYMBOL_GPL(switchdev_port_bridge_dellink); -/** - * ndo_dflt_switchdev_port_bridge_dellink - default ndo bridge dellink - * op for master devices - * - * @dev: port device - * @nlh: netlink msg with bridge port attributes - * @flags: bridge dellink flags - * - * Notify master device slaves of bridge port attribute deletes - */ -int ndo_dflt_switchdev_port_bridge_dellink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags) -{ - struct net_device *lower_dev; - struct list_head *iter; - int ret = 0, err = 0; - - if (!(dev->features & NETIF_F_HW_SWITCH_OFFLOAD)) - return ret; - - netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = switchdev_port_bridge_dellink(lower_dev, nlh, flags); - if (err && err != -EOPNOTSUPP) - ret = err; - } - - return ret; -} -EXPORT_SYMBOL_GPL(ndo_dflt_switchdev_port_bridge_dellink); - static struct net_device *switchdev_get_lowest_dev(struct net_device *dev) { const struct switchdev_ops *ops = dev->switchdev_ops; -- cgit v1.2.3 From 8793d0a664a8a2c5e18e929c1f995c784c105705 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sun, 10 May 2015 09:48:04 -0700 Subject: switchdev: add new switchdev_port_bridge_getlink Like bridge_setlink, add switchdev wrapper to handle bridge_getlink and call into port driver to get port attrs. For now, only BR_LEARNING and BR_LEARNING_SYNC are returned. To add more, we'll probably want to break away from ndo_dflt_bridge_getlink() and build the netlink skb directly in the switchdev code. Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 10 ++++++++++ net/switchdev/switchdev.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'include') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 397b1e6e04f6..e081d67f973a 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -126,6 +126,9 @@ int register_switchdev_notifier(struct notifier_block *nb); int unregister_switchdev_notifier(struct notifier_block *nb); int call_switchdev_notifiers(unsigned long val, struct net_device *dev, struct switchdev_notifier_info *info); +int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, + struct net_device *dev, u32 filter_mask, + int nlflags); int switchdev_port_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags); int switchdev_port_bridge_dellink(struct net_device *dev, @@ -179,6 +182,13 @@ static inline int call_switchdev_notifiers(unsigned long val, return NOTIFY_DONE; } +static inline int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, + u32 seq, struct net_device *dev, + u32 filter_mask, int nlflags) +{ + return -EOPNOTSUPP; +} + static inline int switchdev_port_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags) diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 0e15b6f6bb56..9210355ec965 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -358,6 +358,34 @@ int call_switchdev_notifiers(unsigned long val, struct net_device *dev, } EXPORT_SYMBOL_GPL(call_switchdev_notifiers); +/** + * switchdev_port_bridge_getlink - Get bridge port attributes + * + * @dev: port device + * + * Called for SELF on rtnl_bridge_getlink to get bridge port + * attributes. + */ +int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, + struct net_device *dev, u32 filter_mask, + int nlflags) +{ + struct switchdev_attr attr = { + .id = SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS, + }; + u16 mode = BRIDGE_MODE_UNDEF; + u32 mask = BR_LEARNING | BR_LEARNING_SYNC; + int err; + + err = switchdev_port_attr_get(dev, &attr); + if (err) + return err; + + return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, + attr.brport_flags, mask, nlflags); +} +EXPORT_SYMBOL_GPL(switchdev_port_bridge_getlink); + static int switchdev_port_br_setflag(struct net_device *dev, struct nlattr *nlattr, unsigned long brport_flag) -- cgit v1.2.3 From 58c2cb16b116d7feace621bd6b647bbabacfa225 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sun, 10 May 2015 09:48:06 -0700 Subject: switchdev: convert fib_ipv4_add/del over to switchdev_port_obj_add/del The IPv4 FIB ops convert nicely to the switchdev objs and we're left with only four switchdev ops: port get/set and port add/del. Other objs will follow, such as FDB. So go ahead and convert IPv4 FIB over to switchdev obj for consistency, anticipating more objs to come. Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 41 +++++++++++------------------- include/net/switchdev.h | 21 ++++++++-------- net/switchdev/switchdev.c | 49 +++++++++++++++++++++++------------- 3 files changed, 55 insertions(+), 56 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 56ee316db1a1..1c906504cfe2 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4449,6 +4449,7 @@ static int rocker_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) { struct rocker_port *rocker_port = netdev_priv(dev); + struct switchdev_obj_ipv4_fib *fib4; int err = 0; switch (obj->trans) { @@ -4467,6 +4468,12 @@ static int rocker_port_obj_add(struct net_device *dev, err = rocker_port_vlans_add(rocker_port, obj->trans, &obj->vlan); break; + case SWITCHDEV_OBJ_IPV4_FIB: + fib4 = &obj->ipv4_fib; + err = rocker_port_fib_ipv4(rocker_port, obj->trans, + fib4->dst, fib4->dst_len, + fib4->fi, fib4->tb_id, 0); + break; default: err = -EOPNOTSUPP; break; @@ -4508,12 +4515,19 @@ static int rocker_port_obj_del(struct net_device *dev, struct switchdev_obj *obj) { struct rocker_port *rocker_port = netdev_priv(dev); + struct switchdev_obj_ipv4_fib *fib4; int err = 0; switch (obj->id) { case SWITCHDEV_OBJ_PORT_VLAN: err = rocker_port_vlans_del(rocker_port, &obj->vlan); break; + case SWITCHDEV_OBJ_IPV4_FIB: + fib4 = &obj->ipv4_fib; + err = rocker_port_fib_ipv4(rocker_port, SWITCHDEV_TRANS_NONE, + fib4->dst, fib4->dst_len, fib4->fi, + fib4->tb_id, ROCKER_OP_FLAG_REMOVE); + break; default: err = -EOPNOTSUPP; break; @@ -4522,38 +4536,11 @@ static int rocker_port_obj_del(struct net_device *dev, return err; } -static int rocker_port_switchdev_fib_ipv4_add(struct net_device *dev, - __be32 dst, int dst_len, - struct fib_info *fi, - u8 tos, u8 type, - u32 nlflags, u32 tb_id) -{ - struct rocker_port *rocker_port = netdev_priv(dev); - int flags = 0; - - return rocker_port_fib_ipv4(rocker_port, SWITCHDEV_TRANS_NONE, - dst, dst_len, fi, tb_id, flags); -} - -static int rocker_port_switchdev_fib_ipv4_del(struct net_device *dev, - __be32 dst, int dst_len, - struct fib_info *fi, - u8 tos, u8 type, u32 tb_id) -{ - struct rocker_port *rocker_port = netdev_priv(dev); - int flags = ROCKER_OP_FLAG_REMOVE; - - return rocker_port_fib_ipv4(rocker_port, SWITCHDEV_TRANS_NONE, - dst, dst_len, fi, tb_id, flags); -} - static const struct switchdev_ops rocker_port_switchdev_ops = { .switchdev_port_attr_get = rocker_port_attr_get, .switchdev_port_attr_set = rocker_port_attr_set, .switchdev_port_obj_add = rocker_port_obj_add, .switchdev_port_obj_del = rocker_port_obj_del, - .switchdev_fib_ipv4_add = rocker_port_switchdev_fib_ipv4_add, - .switchdev_fib_ipv4_del = rocker_port_switchdev_fib_ipv4_del, }; /******************** diff --git a/include/net/switchdev.h b/include/net/switchdev.h index e081d67f973a..3b217b4cca27 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -46,6 +46,7 @@ struct fib_info; enum switchdev_obj_id { SWITCHDEV_OBJ_UNDEFINED, SWITCHDEV_OBJ_PORT_VLAN, + SWITCHDEV_OBJ_IPV4_FIB, }; struct switchdev_obj { @@ -57,6 +58,15 @@ struct switchdev_obj { u16 vid_start; u16 vid_end; } vlan; + struct switchdev_obj_ipv4_fib { /* IPV4_FIB */ + u32 dst; + int dst_len; + struct fib_info *fi; + u8 tos; + u8 type; + u32 nlflags; + u32 tb_id; + } ipv4_fib; }; }; @@ -70,10 +80,6 @@ struct switchdev_obj { * @switchdev_port_obj_add: Add an object to port (see switchdev_obj). * * @switchdev_port_obj_del: Delete an object from port (see switchdev_obj). - * - * @switchdev_fib_ipv4_add: Called to add/modify IPv4 route to switch device. - * - * @switchdev_fib_ipv4_del: Called to delete IPv4 route from switch device. */ struct switchdev_ops { int (*switchdev_port_attr_get)(struct net_device *dev, @@ -84,13 +90,6 @@ struct switchdev_ops { struct switchdev_obj *obj); int (*switchdev_port_obj_del)(struct net_device *dev, struct switchdev_obj *obj); - int (*switchdev_fib_ipv4_add)(struct net_device *dev, __be32 dst, - int dst_len, struct fib_info *fi, - u8 tos, u8 type, u32 nlflags, - u32 tb_id); - int (*switchdev_fib_ipv4_del)(struct net_device *dev, __be32 dst, - int dst_len, struct fib_info *fi, - u8 tos, u8 type, u32 tb_id); }; enum switchdev_notifier_type { diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 9210355ec965..65d49d4477b9 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -641,8 +641,19 @@ static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi) int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, u32 nlflags, u32 tb_id) { + struct switchdev_obj fib_obj = { + .id = SWITCHDEV_OBJ_IPV4_FIB, + .ipv4_fib = { + .dst = htonl(dst), + .dst_len = dst_len, + .fi = fi, + .tos = tos, + .type = type, + .nlflags = nlflags, + .tb_id = tb_id, + }, + }; struct net_device *dev; - const struct switchdev_ops *ops; int err = 0; /* Don't offload route if using custom ip rules or if @@ -660,15 +671,10 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, dev = switchdev_get_dev_by_nhs(fi); if (!dev) return 0; - ops = dev->switchdev_ops; - - if (ops->switchdev_fib_ipv4_add) { - err = ops->switchdev_fib_ipv4_add(dev, htonl(dst), dst_len, - fi, tos, type, nlflags, - tb_id); - if (!err) - fi->fib_flags |= RTNH_F_EXTERNAL; - } + + err = switchdev_port_obj_add(dev, &fib_obj); + if (!err) + fi->fib_flags |= RTNH_F_EXTERNAL; return err; } @@ -689,8 +695,19 @@ EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_add); int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, u32 tb_id) { + struct switchdev_obj fib_obj = { + .id = SWITCHDEV_OBJ_IPV4_FIB, + .ipv4_fib = { + .dst = htonl(dst), + .dst_len = dst_len, + .fi = fi, + .tos = tos, + .type = type, + .nlflags = 0, + .tb_id = tb_id, + }, + }; struct net_device *dev; - const struct switchdev_ops *ops; int err = 0; if (!(fi->fib_flags & RTNH_F_EXTERNAL)) @@ -699,14 +716,10 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, dev = switchdev_get_dev_by_nhs(fi); if (!dev) return 0; - ops = dev->switchdev_ops; - if (ops->switchdev_fib_ipv4_del) { - err = ops->switchdev_fib_ipv4_del(dev, htonl(dst), dst_len, - fi, tos, type, tb_id); - if (!err) - fi->fib_flags &= ~RTNH_F_EXTERNAL; - } + err = switchdev_port_obj_del(dev, &fib_obj); + if (!err) + fi->fib_flags &= ~RTNH_F_EXTERNAL; return err; } -- cgit v1.2.3 From 7889cbee8357aaed85898d028829dfb4f75bae2c Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sun, 10 May 2015 09:48:07 -0700 Subject: switchdev: remove NETIF_F_HW_SWITCH_OFFLOAD feature flag Roopa said remove the feature flag for this series and she'll work on bringing it back if needed at a later date. Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 5 +---- drivers/net/ethernet/rocker/rocker.c | 3 +-- drivers/net/team/team.c | 2 +- include/linux/netdev_features.h | 5 +---- net/core/ethtool.c | 1 - 5 files changed, 4 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 147642dae3d0..a2e25de98bde 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1015,10 +1015,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev, netdev_features_t mask; struct slave *slave; - /* If any slave has the offload feature flag set, - * set the offload flag on the bond. - */ - mask = features | NETIF_F_HW_SWITCH_OFFLOAD; + mask = features; features &= ~NETIF_F_ONE_FOR_ALL; features |= NETIF_F_ALL_FOR_ALL; diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 1c906504cfe2..9715e3322706 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4906,8 +4906,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) rocker_carrier_init(rocker_port); dev->features |= NETIF_F_NETNS_LOCAL | - NETIF_F_HW_VLAN_CTAG_FILTER | - NETIF_F_HW_SWITCH_OFFLOAD; + NETIF_F_HW_VLAN_CTAG_FILTER; err = register_netdev(dev); if (err) { diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index bda32be596ef..1ec035a53c3d 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1924,7 +1924,7 @@ static netdev_features_t team_fix_features(struct net_device *dev, struct team *team = netdev_priv(dev); netdev_features_t mask; - mask = features | NETIF_F_HW_SWITCH_OFFLOAD; + mask = features; features &= ~NETIF_F_ONE_FOR_ALL; features |= NETIF_F_ALL_FOR_ALL; diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index 7d59dc6ab789..9672781c593d 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -66,7 +66,6 @@ enum { NETIF_F_HW_VLAN_STAG_FILTER_BIT,/* Receive filtering on VLAN STAGs */ NETIF_F_HW_L2FW_DOFFLOAD_BIT, /* Allow L2 Forwarding in Hardware */ NETIF_F_BUSY_POLL_BIT, /* Busy poll */ - NETIF_F_HW_SWITCH_OFFLOAD_BIT, /* HW switch offload */ /* * Add your fresh new feature above and remember to update @@ -125,7 +124,6 @@ enum { #define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX) #define NETIF_F_HW_L2FW_DOFFLOAD __NETIF_F(HW_L2FW_DOFFLOAD) #define NETIF_F_BUSY_POLL __NETIF_F(BUSY_POLL) -#define NETIF_F_HW_SWITCH_OFFLOAD __NETIF_F(HW_SWITCH_OFFLOAD) /* Features valid for ethtool to change */ /* = all defined minus driver/device-class-related */ @@ -161,8 +159,7 @@ enum { */ #define NETIF_F_ONE_FOR_ALL (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \ NETIF_F_SG | NETIF_F_HIGHDMA | \ - NETIF_F_FRAGLIST | NETIF_F_VLAN_CHALLENGED | \ - NETIF_F_HW_SWITCH_OFFLOAD) + NETIF_F_FRAGLIST | NETIF_F_VLAN_CHALLENGED) /* * If one device doesn't support one of these features, then disable it diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 1d00b8922902..eb0c3ace7458 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -98,7 +98,6 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] [NETIF_F_RXALL_BIT] = "rx-all", [NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload", [NETIF_F_BUSY_POLL_BIT] = "busy-poll", - [NETIF_F_HW_SWITCH_OFFLOAD_BIT] = "hw-switch-offload", }; static const char -- cgit v1.2.3 From a2029240e5836e73ebcc1a8ddb8c22d636f89c9a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 11 May 2015 21:17:53 +0200 Subject: net: deinline netif_tx_stop_all_queues(), remove WARN_ON in netif_tx_stop_queue() These functions compile to 60 bytes of machine code each. With this .config: http://busybox.net/~vda/kernel_config there are 617 calls of netif_tx_stop_queue() and 49 calls of netif_tx_stop_all_queues() in vmlinux. To fix this, remove WARN_ON in netif_tx_stop_queue() as suggested by davem, and deinline netif_tx_stop_all_queues(). Change in code size is about 20k: text data bss dec hex filename 82426986 22255416 20627456 125309858 77813a2 vmlinux.before 82406248 22255416 20627456 125289120 777c2a0 vmlinux gcc-4.7.2 still creates deinlined version of netif_tx_stop_queue sometimes: $ nm --size-sort vmlinux | grep netif_tx_stop_queue | wc -l 190 ffffffff81b558a8 : ffffffff81b558a8: 55 push %rbp ffffffff81b558a9: 48 89 e5 mov %rsp,%rbp ffffffff81b558ac: f0 80 8f e0 01 00 00 lock orb $0x1,0x1e0(%rdi) ffffffff81b558b3: 01 ffffffff81b558b4: 5d pop %rbp ffffffff81b558b5: c3 retq This needs additional fixing. Signed-off-by: Denys Vlasenko CC: Alexei Starovoitov CC: Alexander Duyck CC: Joe Perches CC: David S. Miller CC: Jiri Pirko CC: linux-kernel@vger.kernel.org CC: netdev@vger.kernel.org CC: netfilter-devel@vger.kernel.org Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/netdevice.h | 14 +------------- net/core/dev.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2b39235b9f13..fa57915f440c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2559,10 +2559,6 @@ static inline void netif_tx_wake_all_queues(struct net_device *dev) static inline void netif_tx_stop_queue(struct netdev_queue *dev_queue) { - if (WARN_ON(!dev_queue)) { - pr_info("netif_stop_queue() cannot be called before register_netdev()\n"); - return; - } set_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state); } @@ -2578,15 +2574,7 @@ static inline void netif_stop_queue(struct net_device *dev) netif_tx_stop_queue(netdev_get_tx_queue(dev, 0)); } -static inline void netif_tx_stop_all_queues(struct net_device *dev) -{ - unsigned int i; - - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - netif_tx_stop_queue(txq); - } -} +void netif_tx_stop_all_queues(struct net_device *dev); static inline bool netif_tx_queue_stopped(const struct netdev_queue *dev_queue) { diff --git a/net/core/dev.c b/net/core/dev.c index e5f77c40bbd1..fd012bbe0486 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6301,6 +6301,17 @@ static int netif_alloc_netdev_queues(struct net_device *dev) return 0; } +void netif_tx_stop_all_queues(struct net_device *dev) +{ + unsigned int i; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + netif_tx_stop_queue(txq); + } +} +EXPORT_SYMBOL(netif_tx_stop_all_queues); + /** * register_netdevice - register a network device * @dev: device to register -- cgit v1.2.3 From cffc642d93f9324a06dfbd7da9af29652952a248 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Mon, 11 May 2015 22:22:44 -0700 Subject: test_bpf: add 173 new testcases for eBPF add an exhaustive set of eBPF tests bringing total to: test_bpf: Summary: 233 PASSED, 0 FAILED, [0/226 JIT'ed] Signed-off-by: Michael Holzheu Signed-off-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/linux/filter.h | 10 + lib/test_bpf.c | 2192 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2202 insertions(+) (limited to 'include') diff --git a/include/linux/filter.h b/include/linux/filter.h index 3c03a6085b82..ce1d72d34382 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -207,6 +207,16 @@ struct bpf_prog_aux; .off = OFF, \ .imm = 0 }) +/* Atomic memory add, *(uint *)(dst_reg + off16) += src_reg */ + +#define BPF_STX_XADD(SIZE, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_STX | BPF_SIZE(SIZE) | BPF_XADD, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = 0 }) + /* Memory store, *(uint *) (dst_reg + off16) = imm32 */ #define BPF_ST_MEM(SIZE, DST, OFF, IMM) \ diff --git a/lib/test_bpf.c b/lib/test_bpf.c index 3c41049d72d8..8bca780e3613 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -1806,6 +1806,2198 @@ static struct bpf_test tests[] = { 0x10, 0xbf, 0x48, 0xd6, 0x43, 0xd6}, { { 38, 256 } } }, + /* BPF_ALU | BPF_MOV | BPF_X */ + { + "ALU_MOV_X: dst = 2", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R1, 2), + BPF_ALU32_REG(BPF_MOV, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU_MOV_X: dst = 4294967295", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R1, 4294967295), + BPF_ALU32_REG(BPF_MOV, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 4294967295 } }, + }, + { + "ALU64_MOV_X: dst = 2", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R1, 2), + BPF_ALU64_REG(BPF_MOV, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU64_MOV_X: dst = 4294967295", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R1, 4294967295), + BPF_ALU64_REG(BPF_MOV, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 4294967295 } }, + }, + /* BPF_ALU | BPF_MOV | BPF_K */ + { + "ALU_MOV_K: dst = 2", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 2), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU_MOV_K: dst = 4294967295", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 4294967295), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 4294967295 } }, + }, + { + "ALU_MOV_K: 0x0000ffffffff0000 = 0x00000000ffffffff", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x0000ffffffff0000), + BPF_LD_IMM64(R3, 0x00000000ffffffff), + BPF_ALU32_IMM(BPF_MOV, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + { + "ALU64_MOV_K: dst = 2", + .u.insns_int = { + BPF_ALU64_IMM(BPF_MOV, R0, 2), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU64_MOV_K: dst = 2147483647", + .u.insns_int = { + BPF_ALU64_IMM(BPF_MOV, R0, 2147483647), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2147483647 } }, + }, + { + "ALU64_OR_K: dst = 0x0", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x0000ffffffff0000), + BPF_LD_IMM64(R3, 0x0), + BPF_ALU64_IMM(BPF_MOV, R2, 0x0), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + { + "ALU64_MOV_K: dst = -1", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x0000ffffffff0000), + BPF_LD_IMM64(R3, 0xffffffffffffffff), + BPF_ALU64_IMM(BPF_MOV, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + /* BPF_ALU | BPF_ADD | BPF_X */ + { + "ALU_ADD_X: 1 + 2 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_MOV, R1, 2), + BPF_ALU32_REG(BPF_ADD, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU_ADD_X: 1 + 4294967294 = 4294967295", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_MOV, R1, 4294967294), + BPF_ALU32_REG(BPF_ADD, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 4294967295 } }, + }, + { + "ALU64_ADD_X: 1 + 2 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_MOV, R1, 2), + BPF_ALU64_REG(BPF_ADD, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU64_ADD_X: 1 + 4294967294 = 4294967295", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_MOV, R1, 4294967294), + BPF_ALU64_REG(BPF_ADD, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 4294967295 } }, + }, + /* BPF_ALU | BPF_ADD | BPF_K */ + { + "ALU_ADD_K: 1 + 2 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_ADD, R0, 2), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU_ADD_K: 3 + 0 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_ADD, R0, 0), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU_ADD_K: 1 + 4294967294 = 4294967295", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_ADD, R0, 4294967294), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 4294967295 } }, + }, + { + "ALU_ADD_K: 0 + (-1) = 0x00000000ffffffff", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x0), + BPF_LD_IMM64(R3, 0x00000000ffffffff), + BPF_ALU32_IMM(BPF_ADD, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + { + "ALU64_ADD_K: 1 + 2 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU64_IMM(BPF_ADD, R0, 2), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU64_ADD_K: 3 + 0 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU64_IMM(BPF_ADD, R0, 0), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU64_ADD_K: 1 + 2147483646 = 2147483647", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU64_IMM(BPF_ADD, R0, 2147483646), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2147483647 } }, + }, + { + "ALU64_ADD_K: 2147483646 + -2147483647 = -1", + .u.insns_int = { + BPF_LD_IMM64(R0, 2147483646), + BPF_ALU64_IMM(BPF_ADD, R0, -2147483647), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, -1 } }, + }, + { + "ALU64_ADD_K: 1 + 0 = 1", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x1), + BPF_LD_IMM64(R3, 0x1), + BPF_ALU64_IMM(BPF_ADD, R2, 0x0), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + { + "ALU64_ADD_K: 0 + (-1) = 0xffffffffffffffff", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x0), + BPF_LD_IMM64(R3, 0xffffffffffffffff), + BPF_ALU64_IMM(BPF_ADD, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + /* BPF_ALU | BPF_SUB | BPF_X */ + { + "ALU_SUB_X: 3 - 1 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_MOV, R1, 1), + BPF_ALU32_REG(BPF_SUB, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU_SUB_X: 4294967295 - 4294967294 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 4294967295), + BPF_ALU32_IMM(BPF_MOV, R1, 4294967294), + BPF_ALU32_REG(BPF_SUB, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU64_SUB_X: 3 - 1 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_MOV, R1, 1), + BPF_ALU64_REG(BPF_SUB, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU64_SUB_X: 4294967295 - 4294967294 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 4294967295), + BPF_ALU32_IMM(BPF_MOV, R1, 4294967294), + BPF_ALU64_REG(BPF_SUB, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_ALU | BPF_SUB | BPF_K */ + { + "ALU_SUB_K: 3 - 1 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_SUB, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU_SUB_K: 3 - 0 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_SUB, R0, 0), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU_SUB_K: 4294967295 - 4294967294 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 4294967295), + BPF_ALU32_IMM(BPF_SUB, R0, 4294967294), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU64_SUB_K: 3 - 1 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU64_IMM(BPF_SUB, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU64_SUB_K: 3 - 0 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU64_IMM(BPF_SUB, R0, 0), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU64_SUB_K: 4294967294 - 4294967295 = -1", + .u.insns_int = { + BPF_LD_IMM64(R0, 4294967294), + BPF_ALU64_IMM(BPF_SUB, R0, 4294967295), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, -1 } }, + }, + { + "ALU64_ADD_K: 2147483646 - 2147483647 = -1", + .u.insns_int = { + BPF_LD_IMM64(R0, 2147483646), + BPF_ALU64_IMM(BPF_SUB, R0, 2147483647), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, -1 } }, + }, + /* BPF_ALU | BPF_MUL | BPF_X */ + { + "ALU_MUL_X: 2 * 3 = 6", + .u.insns_int = { + BPF_LD_IMM64(R0, 2), + BPF_ALU32_IMM(BPF_MOV, R1, 3), + BPF_ALU32_REG(BPF_MUL, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 6 } }, + }, + { + "ALU_MUL_X: 2 * 0x7FFFFFF8 = 0xFFFFFFF0", + .u.insns_int = { + BPF_LD_IMM64(R0, 2), + BPF_ALU32_IMM(BPF_MOV, R1, 0x7FFFFFF8), + BPF_ALU32_REG(BPF_MUL, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xFFFFFFF0 } }, + }, + { + "ALU_MUL_X: -1 * -1 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, -1), + BPF_ALU32_IMM(BPF_MOV, R1, -1), + BPF_ALU32_REG(BPF_MUL, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU64_MUL_X: 2 * 3 = 6", + .u.insns_int = { + BPF_LD_IMM64(R0, 2), + BPF_ALU32_IMM(BPF_MOV, R1, 3), + BPF_ALU64_REG(BPF_MUL, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 6 } }, + }, + { + "ALU64_MUL_X: 1 * 2147483647 = 2147483647", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_MOV, R1, 2147483647), + BPF_ALU64_REG(BPF_MUL, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2147483647 } }, + }, + /* BPF_ALU | BPF_MUL | BPF_K */ + { + "ALU_MUL_K: 2 * 3 = 6", + .u.insns_int = { + BPF_LD_IMM64(R0, 2), + BPF_ALU32_IMM(BPF_MUL, R0, 3), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 6 } }, + }, + { + "ALU_MUL_K: 3 * 1 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_MUL, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU_MUL_K: 2 * 0x7FFFFFF8 = 0xFFFFFFF0", + .u.insns_int = { + BPF_LD_IMM64(R0, 2), + BPF_ALU32_IMM(BPF_MUL, R0, 0x7FFFFFF8), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xFFFFFFF0 } }, + }, + { + "ALU_MUL_K: 1 * (-1) = 0x00000000ffffffff", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x1), + BPF_LD_IMM64(R3, 0x00000000ffffffff), + BPF_ALU32_IMM(BPF_MUL, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + { + "ALU64_MUL_K: 2 * 3 = 6", + .u.insns_int = { + BPF_LD_IMM64(R0, 2), + BPF_ALU64_IMM(BPF_MUL, R0, 3), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 6 } }, + }, + { + "ALU64_MUL_K: 3 * 1 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU64_IMM(BPF_MUL, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU64_MUL_K: 1 * 2147483647 = 2147483647", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU64_IMM(BPF_MUL, R0, 2147483647), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2147483647 } }, + }, + { + "ALU64_MUL_K: 1 * -2147483647 = -2147483647", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU64_IMM(BPF_MUL, R0, -2147483647), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, -2147483647 } }, + }, + { + "ALU64_MUL_K: 1 * (-1) = 0xffffffffffffffff", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x1), + BPF_LD_IMM64(R3, 0xffffffffffffffff), + BPF_ALU64_IMM(BPF_MUL, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + /* BPF_ALU | BPF_DIV | BPF_X */ + { + "ALU_DIV_X: 6 / 2 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 6), + BPF_ALU32_IMM(BPF_MOV, R1, 2), + BPF_ALU32_REG(BPF_DIV, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU_DIV_X: 4294967295 / 4294967295 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 4294967295), + BPF_ALU32_IMM(BPF_MOV, R1, 4294967295), + BPF_ALU32_REG(BPF_DIV, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU64_DIV_X: 6 / 2 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 6), + BPF_ALU32_IMM(BPF_MOV, R1, 2), + BPF_ALU64_REG(BPF_DIV, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU64_DIV_X: 2147483647 / 2147483647 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 2147483647), + BPF_ALU32_IMM(BPF_MOV, R1, 2147483647), + BPF_ALU64_REG(BPF_DIV, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU64_DIV_X: 0xffffffffffffffff / (-1) = 0x0000000000000001", + .u.insns_int = { + BPF_LD_IMM64(R2, 0xffffffffffffffffUL), + BPF_LD_IMM64(R4, 0xffffffffffffffffUL), + BPF_LD_IMM64(R3, 0x0000000000000001UL), + BPF_ALU64_REG(BPF_DIV, R2, R4), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + /* BPF_ALU | BPF_DIV | BPF_K */ + { + "ALU_DIV_K: 6 / 2 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 6), + BPF_ALU32_IMM(BPF_DIV, R0, 2), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU_DIV_K: 3 / 1 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_DIV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU_DIV_K: 4294967295 / 4294967295 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 4294967295), + BPF_ALU32_IMM(BPF_DIV, R0, 4294967295), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU_DIV_K: 0xffffffffffffffff / (-1) = 0x1", + .u.insns_int = { + BPF_LD_IMM64(R2, 0xffffffffffffffffUL), + BPF_LD_IMM64(R3, 0x1UL), + BPF_ALU32_IMM(BPF_DIV, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + { + "ALU64_DIV_K: 6 / 2 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 6), + BPF_ALU64_IMM(BPF_DIV, R0, 2), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU64_DIV_K: 3 / 1 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU64_IMM(BPF_DIV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU64_DIV_K: 2147483647 / 2147483647 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 2147483647), + BPF_ALU64_IMM(BPF_DIV, R0, 2147483647), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU64_DIV_K: 0xffffffffffffffff / (-1) = 0x0000000000000001", + .u.insns_int = { + BPF_LD_IMM64(R2, 0xffffffffffffffffUL), + BPF_LD_IMM64(R3, 0x0000000000000001UL), + BPF_ALU64_IMM(BPF_DIV, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + /* BPF_ALU | BPF_MOD | BPF_X */ + { + "ALU_MOD_X: 3 % 2 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_MOV, R1, 2), + BPF_ALU32_REG(BPF_MOD, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU_MOD_X: 4294967295 % 4294967293 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 4294967295), + BPF_ALU32_IMM(BPF_MOV, R1, 4294967293), + BPF_ALU32_REG(BPF_MOD, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU64_MOD_X: 3 % 2 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_MOV, R1, 2), + BPF_ALU64_REG(BPF_MOD, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU64_MOD_X: 2147483647 % 2147483645 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 2147483647), + BPF_ALU32_IMM(BPF_MOV, R1, 2147483645), + BPF_ALU64_REG(BPF_MOD, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + /* BPF_ALU | BPF_MOD | BPF_K */ + { + "ALU_MOD_K: 3 % 2 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_MOD, R0, 2), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU_MOD_K: 3 % 1 = 0", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_MOD, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0 } }, + }, + { + "ALU_MOD_K: 4294967295 % 4294967293 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 4294967295), + BPF_ALU32_IMM(BPF_MOD, R0, 4294967293), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU64_MOD_K: 3 % 2 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU64_IMM(BPF_MOD, R0, 2), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU64_MOD_K: 3 % 1 = 0", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU64_IMM(BPF_MOD, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0 } }, + }, + { + "ALU64_MOD_K: 2147483647 % 2147483645 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 2147483647), + BPF_ALU64_IMM(BPF_MOD, R0, 2147483645), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + /* BPF_ALU | BPF_AND | BPF_X */ + { + "ALU_AND_X: 3 & 2 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_MOV, R1, 2), + BPF_ALU32_REG(BPF_AND, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU_AND_X: 0xffffffff & 0xffffffff = 0xffffffff", + .u.insns_int = { + BPF_LD_IMM64(R0, 0xffffffff), + BPF_ALU32_IMM(BPF_MOV, R1, 0xffffffff), + BPF_ALU32_REG(BPF_AND, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffffffff } }, + }, + { + "ALU64_AND_X: 3 & 2 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_MOV, R1, 2), + BPF_ALU64_REG(BPF_AND, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU64_AND_X: 0xffffffff & 0xffffffff = 0xffffffff", + .u.insns_int = { + BPF_LD_IMM64(R0, 0xffffffff), + BPF_ALU32_IMM(BPF_MOV, R1, 0xffffffff), + BPF_ALU64_REG(BPF_AND, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffffffff } }, + }, + /* BPF_ALU | BPF_AND | BPF_K */ + { + "ALU_AND_K: 3 & 2 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU32_IMM(BPF_AND, R0, 2), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU_AND_K: 0xffffffff & 0xffffffff = 0xffffffff", + .u.insns_int = { + BPF_LD_IMM64(R0, 0xffffffff), + BPF_ALU32_IMM(BPF_AND, R0, 0xffffffff), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffffffff } }, + }, + { + "ALU64_AND_K: 3 & 2 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU64_IMM(BPF_AND, R0, 2), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU64_AND_K: 0xffffffff & 0xffffffff = 0xffffffff", + .u.insns_int = { + BPF_LD_IMM64(R0, 0xffffffff), + BPF_ALU64_IMM(BPF_AND, R0, 0xffffffff), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffffffff } }, + }, + { + "ALU64_AND_K: 0x0000ffffffff0000 & 0x0 = 0x0000ffff00000000", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x0000ffffffff0000), + BPF_LD_IMM64(R3, 0x0000000000000000), + BPF_ALU64_IMM(BPF_AND, R2, 0x0), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + { + "ALU64_AND_K: 0x0000ffffffff0000 & -1 = 0x0000ffffffffffff", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x0000ffffffff0000), + BPF_LD_IMM64(R3, 0x0000ffffffff0000), + BPF_ALU64_IMM(BPF_AND, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + { + "ALU64_AND_K: 0xffffffffffffffff & -1 = 0xffffffffffffffff", + .u.insns_int = { + BPF_LD_IMM64(R2, 0xffffffffffffffff), + BPF_LD_IMM64(R3, 0xffffffffffffffff), + BPF_ALU64_IMM(BPF_AND, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + /* BPF_ALU | BPF_OR | BPF_X */ + { + "ALU_OR_X: 1 | 2 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_MOV, R1, 2), + BPF_ALU32_REG(BPF_OR, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU_OR_X: 0x0 | 0xffffffff = 0xffffffff", + .u.insns_int = { + BPF_LD_IMM64(R0, 0), + BPF_ALU32_IMM(BPF_MOV, R1, 0xffffffff), + BPF_ALU32_REG(BPF_OR, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffffffff } }, + }, + { + "ALU64_OR_X: 1 | 2 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_MOV, R1, 2), + BPF_ALU64_REG(BPF_OR, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU64_OR_X: 0 | 0xffffffff = 0xffffffff", + .u.insns_int = { + BPF_LD_IMM64(R0, 0), + BPF_ALU32_IMM(BPF_MOV, R1, 0xffffffff), + BPF_ALU64_REG(BPF_OR, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffffffff } }, + }, + /* BPF_ALU | BPF_OR | BPF_K */ + { + "ALU_OR_K: 1 | 2 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_OR, R0, 2), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU_OR_K: 0 & 0xffffffff = 0xffffffff", + .u.insns_int = { + BPF_LD_IMM64(R0, 0), + BPF_ALU32_IMM(BPF_OR, R0, 0xffffffff), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffffffff } }, + }, + { + "ALU64_OR_K: 1 | 2 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU64_IMM(BPF_OR, R0, 2), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU64_OR_K: 0 & 0xffffffff = 0xffffffff", + .u.insns_int = { + BPF_LD_IMM64(R0, 0), + BPF_ALU64_IMM(BPF_OR, R0, 0xffffffff), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffffffff } }, + }, + { + "ALU64_OR_K: 0x0000ffffffff0000 | 0x0 = 0x0000ffff00000000", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x0000ffffffff0000), + BPF_LD_IMM64(R3, 0x0000ffffffff0000), + BPF_ALU64_IMM(BPF_OR, R2, 0x0), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + { + "ALU64_OR_K: 0x0000ffffffff0000 | -1 = 0xffffffffffffffff", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x0000ffffffff0000), + BPF_LD_IMM64(R3, 0xffffffffffffffff), + BPF_ALU64_IMM(BPF_OR, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + { + "ALU64_OR_K: 0x000000000000000 | -1 = 0xffffffffffffffff", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x0000000000000000), + BPF_LD_IMM64(R3, 0xffffffffffffffff), + BPF_ALU64_IMM(BPF_OR, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + /* BPF_ALU | BPF_XOR | BPF_X */ + { + "ALU_XOR_X: 5 ^ 6 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 5), + BPF_ALU32_IMM(BPF_MOV, R1, 6), + BPF_ALU32_REG(BPF_XOR, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU_XOR_X: 0x1 ^ 0xffffffff = 0xfffffffe", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_MOV, R1, 0xffffffff), + BPF_ALU32_REG(BPF_XOR, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xfffffffe } }, + }, + { + "ALU64_XOR_X: 5 ^ 6 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 5), + BPF_ALU32_IMM(BPF_MOV, R1, 6), + BPF_ALU64_REG(BPF_XOR, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU64_XOR_X: 1 ^ 0xffffffff = 0xfffffffe", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_MOV, R1, 0xffffffff), + BPF_ALU64_REG(BPF_XOR, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xfffffffe } }, + }, + /* BPF_ALU | BPF_XOR | BPF_K */ + { + "ALU_XOR_K: 5 ^ 6 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 5), + BPF_ALU32_IMM(BPF_XOR, R0, 6), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU_XOR_K: 1 ^ 0xffffffff = 0xfffffffe", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_XOR, R0, 0xffffffff), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xfffffffe } }, + }, + { + "ALU64_XOR_K: 5 ^ 6 = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, 5), + BPF_ALU64_IMM(BPF_XOR, R0, 6), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU64_XOR_K: 1 & 0xffffffff = 0xfffffffe", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU64_IMM(BPF_XOR, R0, 0xffffffff), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xfffffffe } }, + }, + { + "ALU64_XOR_K: 0x0000ffffffff0000 ^ 0x0 = 0x0000ffffffff0000", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x0000ffffffff0000), + BPF_LD_IMM64(R3, 0x0000ffffffff0000), + BPF_ALU64_IMM(BPF_XOR, R2, 0x0), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + { + "ALU64_XOR_K: 0x0000ffffffff0000 ^ -1 = 0xffff00000000ffff", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x0000ffffffff0000), + BPF_LD_IMM64(R3, 0xffff00000000ffff), + BPF_ALU64_IMM(BPF_XOR, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + { + "ALU64_XOR_K: 0x000000000000000 ^ -1 = 0xffffffffffffffff", + .u.insns_int = { + BPF_LD_IMM64(R2, 0x0000000000000000), + BPF_LD_IMM64(R3, 0xffffffffffffffff), + BPF_ALU64_IMM(BPF_XOR, R2, 0xffffffff), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + /* BPF_ALU | BPF_LSH | BPF_X */ + { + "ALU_LSH_X: 1 << 1 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_MOV, R1, 1), + BPF_ALU32_REG(BPF_LSH, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU_LSH_X: 1 << 31 = 0x80000000", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_MOV, R1, 31), + BPF_ALU32_REG(BPF_LSH, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x80000000 } }, + }, + { + "ALU64_LSH_X: 1 << 1 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_MOV, R1, 1), + BPF_ALU64_REG(BPF_LSH, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU64_LSH_X: 1 << 31 = 0x80000000", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_MOV, R1, 31), + BPF_ALU64_REG(BPF_LSH, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x80000000 } }, + }, + /* BPF_ALU | BPF_LSH | BPF_K */ + { + "ALU_LSH_K: 1 << 1 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_LSH, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU_LSH_K: 1 << 31 = 0x80000000", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU32_IMM(BPF_LSH, R0, 31), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x80000000 } }, + }, + { + "ALU64_LSH_K: 1 << 1 = 2", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU64_IMM(BPF_LSH, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 2 } }, + }, + { + "ALU64_LSH_K: 1 << 31 = 0x80000000", + .u.insns_int = { + BPF_LD_IMM64(R0, 1), + BPF_ALU64_IMM(BPF_LSH, R0, 31), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x80000000 } }, + }, + /* BPF_ALU | BPF_RSH | BPF_X */ + { + "ALU_RSH_X: 2 >> 1 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 2), + BPF_ALU32_IMM(BPF_MOV, R1, 1), + BPF_ALU32_REG(BPF_RSH, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU_RSH_X: 0x80000000 >> 31 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 0x80000000), + BPF_ALU32_IMM(BPF_MOV, R1, 31), + BPF_ALU32_REG(BPF_RSH, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU64_RSH_X: 2 >> 1 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 2), + BPF_ALU32_IMM(BPF_MOV, R1, 1), + BPF_ALU64_REG(BPF_RSH, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU64_RSH_X: 0x80000000 >> 31 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 0x80000000), + BPF_ALU32_IMM(BPF_MOV, R1, 31), + BPF_ALU64_REG(BPF_RSH, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_ALU | BPF_RSH | BPF_K */ + { + "ALU_RSH_K: 2 >> 1 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 2), + BPF_ALU32_IMM(BPF_RSH, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU_RSH_K: 0x80000000 >> 31 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 0x80000000), + BPF_ALU32_IMM(BPF_RSH, R0, 31), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU64_RSH_K: 2 >> 1 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 2), + BPF_ALU64_IMM(BPF_RSH, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "ALU64_RSH_K: 0x80000000 >> 31 = 1", + .u.insns_int = { + BPF_LD_IMM64(R0, 0x80000000), + BPF_ALU64_IMM(BPF_RSH, R0, 31), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_ALU | BPF_ARSH | BPF_X */ + { + "ALU_ARSH_X: 0xff00ff0000000000 >> 40 = 0xffffffffffff00ff", + .u.insns_int = { + BPF_LD_IMM64(R0, 0xff00ff0000000000LL), + BPF_ALU32_IMM(BPF_MOV, R1, 40), + BPF_ALU64_REG(BPF_ARSH, R0, R1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffff00ff } }, + }, + /* BPF_ALU | BPF_ARSH | BPF_K */ + { + "ALU_ARSH_K: 0xff00ff0000000000 >> 40 = 0xffffffffffff00ff", + .u.insns_int = { + BPF_LD_IMM64(R0, 0xff00ff0000000000LL), + BPF_ALU64_IMM(BPF_ARSH, R0, 40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffff00ff } }, + }, + /* BPF_ALU | BPF_NEG */ + { + "ALU_NEG: -(3) = -3", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 3), + BPF_ALU32_IMM(BPF_NEG, R0, 0), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, -3 } }, + }, + { + "ALU_NEG: -(-3) = 3", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, -3), + BPF_ALU32_IMM(BPF_NEG, R0, 0), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + { + "ALU64_NEG: -(3) = -3", + .u.insns_int = { + BPF_LD_IMM64(R0, 3), + BPF_ALU64_IMM(BPF_NEG, R0, 0), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, -3 } }, + }, + { + "ALU64_NEG: -(-3) = 3", + .u.insns_int = { + BPF_LD_IMM64(R0, -3), + BPF_ALU64_IMM(BPF_NEG, R0, 0), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 3 } }, + }, + /* BPF_ALU | BPF_END | BPF_FROM_BE */ + { + "ALU_END_FROM_BE 16: 0x0123456789abcdef -> 0xcdef", + .u.insns_int = { + BPF_LD_IMM64(R0, 0x0123456789abcdefLL), + BPF_ENDIAN(BPF_FROM_BE, R0, 16), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, cpu_to_be16(0xcdef) } }, + }, + { + "ALU_END_FROM_BE 32: 0x0123456789abcdef -> 0x89abcdef", + .u.insns_int = { + BPF_LD_IMM64(R0, 0x0123456789abcdefLL), + BPF_ENDIAN(BPF_FROM_BE, R0, 32), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, cpu_to_be32(0x89abcdef) } }, + }, + { + "ALU_END_FROM_BE 64: 0x0123456789abcdef -> 0x89abcdef", + .u.insns_int = { + BPF_LD_IMM64(R0, 0x0123456789abcdefLL), + BPF_ENDIAN(BPF_FROM_BE, R0, 64), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, (u32) cpu_to_be64(0x0123456789abcdefLL) } }, + }, + /* BPF_ALU | BPF_END | BPF_FROM_LE */ + { + "ALU_END_FROM_LE 16: 0x0123456789abcdef -> 0xefcd", + .u.insns_int = { + BPF_LD_IMM64(R0, 0x0123456789abcdefLL), + BPF_ENDIAN(BPF_FROM_LE, R0, 16), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, cpu_to_le16(0xcdef) } }, + }, + { + "ALU_END_FROM_LE 32: 0x0123456789abcdef -> 0xefcdab89", + .u.insns_int = { + BPF_LD_IMM64(R0, 0x0123456789abcdefLL), + BPF_ENDIAN(BPF_FROM_LE, R0, 32), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, cpu_to_le32(0x89abcdef) } }, + }, + { + "ALU_END_FROM_LE 64: 0x0123456789abcdef -> 0x67452301", + .u.insns_int = { + BPF_LD_IMM64(R0, 0x0123456789abcdefLL), + BPF_ENDIAN(BPF_FROM_LE, R0, 64), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, (u32) cpu_to_le64(0x0123456789abcdefLL) } }, + }, + /* BPF_ST(X) | BPF_MEM | BPF_B/H/W/DW */ + { + "ST_MEM_B: Store/Load byte: max negative", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_ST_MEM(BPF_B, R10, -40, 0xff), + BPF_LDX_MEM(BPF_B, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xff } }, + }, + { + "ST_MEM_B: Store/Load byte: max positive", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_ST_MEM(BPF_H, R10, -40, 0x7f), + BPF_LDX_MEM(BPF_H, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x7f } }, + }, + { + "STX_MEM_B: Store/Load byte: max negative", + .u.insns_int = { + BPF_LD_IMM64(R0, 0), + BPF_LD_IMM64(R1, 0xffLL), + BPF_STX_MEM(BPF_B, R10, R1, -40), + BPF_LDX_MEM(BPF_B, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xff } }, + }, + { + "ST_MEM_H: Store/Load half word: max negative", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_ST_MEM(BPF_H, R10, -40, 0xffff), + BPF_LDX_MEM(BPF_H, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffff } }, + }, + { + "ST_MEM_H: Store/Load half word: max positive", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_ST_MEM(BPF_H, R10, -40, 0x7fff), + BPF_LDX_MEM(BPF_H, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x7fff } }, + }, + { + "STX_MEM_H: Store/Load half word: max negative", + .u.insns_int = { + BPF_LD_IMM64(R0, 0), + BPF_LD_IMM64(R1, 0xffffLL), + BPF_STX_MEM(BPF_H, R10, R1, -40), + BPF_LDX_MEM(BPF_H, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffff } }, + }, + { + "ST_MEM_W: Store/Load word: max negative", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_ST_MEM(BPF_W, R10, -40, 0xffffffff), + BPF_LDX_MEM(BPF_W, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffffffff } }, + }, + { + "ST_MEM_W: Store/Load word: max positive", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_ST_MEM(BPF_W, R10, -40, 0x7fffffff), + BPF_LDX_MEM(BPF_W, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x7fffffff } }, + }, + { + "STX_MEM_W: Store/Load word: max negative", + .u.insns_int = { + BPF_LD_IMM64(R0, 0), + BPF_LD_IMM64(R1, 0xffffffffLL), + BPF_STX_MEM(BPF_W, R10, R1, -40), + BPF_LDX_MEM(BPF_W, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffffffff } }, + }, + { + "ST_MEM_DW: Store/Load double word: max negative", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_ST_MEM(BPF_DW, R10, -40, 0xffffffff), + BPF_LDX_MEM(BPF_DW, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffffffff } }, + }, + { + "ST_MEM_DW: Store/Load double word: max negative 2", + .u.insns_int = { + BPF_LD_IMM64(R2, 0xffff00000000ffff), + BPF_LD_IMM64(R3, 0xffffffffffffffff), + BPF_ST_MEM(BPF_DW, R10, -40, 0xffffffff), + BPF_LDX_MEM(BPF_DW, R2, R10, -40), + BPF_JMP_REG(BPF_JEQ, R2, R3, 2), + BPF_MOV32_IMM(R0, 2), + BPF_EXIT_INSN(), + BPF_MOV32_IMM(R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x1 } }, + }, + { + "ST_MEM_DW: Store/Load double word: max positive", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_ST_MEM(BPF_DW, R10, -40, 0x7fffffff), + BPF_LDX_MEM(BPF_DW, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x7fffffff } }, + }, + { + "STX_MEM_DW: Store/Load double word: max negative", + .u.insns_int = { + BPF_LD_IMM64(R0, 0), + BPF_LD_IMM64(R1, 0xffffffffffffffffLL), + BPF_STX_MEM(BPF_W, R10, R1, -40), + BPF_LDX_MEM(BPF_W, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0xffffffff } }, + }, + /* BPF_STX | BPF_XADD | BPF_W/DW */ + { + "STX_XADD_W: Test: 0x12 + 0x10 = 0x22", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0x12), + BPF_ST_MEM(BPF_W, R10, -40, 0x10), + BPF_STX_XADD(BPF_W, R10, R0, -40), + BPF_LDX_MEM(BPF_W, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x22 } }, + }, + { + "STX_XADD_DW: Test: 0x12 + 0x10 = 0x22", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0x12), + BPF_ST_MEM(BPF_DW, R10, -40, 0x10), + BPF_STX_XADD(BPF_DW, R10, R0, -40), + BPF_LDX_MEM(BPF_DW, R0, R10, -40), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 0x22 } }, + }, + /* BPF_JMP | BPF_EXIT */ + { + "JMP_EXIT", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0x4711), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 0x4712), + }, + INTERNAL, + { }, + { { 0, 0x4711 } }, + }, + /* BPF_JMP | BPF_JA */ + { + "JMP_JA: Unconditional jump: if (true) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_JMP_IMM(BPF_JA, 0, 0, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JSGT | BPF_K */ + { + "JMP_JSGT_K: Signed jump: if (-1 > -2) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 0xffffffffffffffffLL), + BPF_JMP_IMM(BPF_JSGT, R1, -2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "JMP_JSGT_K: Signed jump: if (-1 > -1) return 0", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_LD_IMM64(R1, 0xffffffffffffffffLL), + BPF_JMP_IMM(BPF_JSGT, R1, -1, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JSGE | BPF_K */ + { + "JMP_JSGE_K: Signed jump: if (-1 >= -2) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 0xffffffffffffffffLL), + BPF_JMP_IMM(BPF_JSGE, R1, -2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "JMP_JSGE_K: Signed jump: if (-1 >= -1) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 0xffffffffffffffffLL), + BPF_JMP_IMM(BPF_JSGE, R1, -1, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JGT | BPF_K */ + { + "JMP_JGT_K: if (3 > 2) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_JMP_IMM(BPF_JGT, R1, 2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JGE | BPF_K */ + { + "JMP_JGE_K: if (3 >= 2) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_JMP_IMM(BPF_JGE, R1, 2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "JMP_JGE_K: if (3 >= 3) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_JMP_IMM(BPF_JGE, R1, 3, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JNE | BPF_K */ + { + "JMP_JNE_K: if (3 != 2) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_JMP_IMM(BPF_JNE, R1, 2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JEQ | BPF_K */ + { + "JMP_JEQ_K: if (3 == 3) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_JMP_IMM(BPF_JEQ, R1, 3, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JSET | BPF_K */ + { + "JMP_JSET_K: if (0x3 & 0x2) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_JMP_IMM(BPF_JNE, R1, 2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "JMP_JSET_K: if (0x3 & 0xffffffff) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_JMP_IMM(BPF_JNE, R1, 0xffffffff, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JSGT | BPF_X */ + { + "JMP_JSGT_X: Signed jump: if (-1 > -2) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, -1), + BPF_LD_IMM64(R2, -2), + BPF_JMP_REG(BPF_JSGT, R1, R2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "JMP_JSGT_X: Signed jump: if (-1 > -1) return 0", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_LD_IMM64(R1, -1), + BPF_LD_IMM64(R2, -1), + BPF_JMP_REG(BPF_JSGT, R1, R2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JSGE | BPF_X */ + { + "JMP_JSGE_X: Signed jump: if (-1 >= -2) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, -1), + BPF_LD_IMM64(R2, -2), + BPF_JMP_REG(BPF_JSGE, R1, R2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "JMP_JSGE_X: Signed jump: if (-1 >= -1) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, -1), + BPF_LD_IMM64(R2, -1), + BPF_JMP_REG(BPF_JSGE, R1, R2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JGT | BPF_X */ + { + "JMP_JGT_X: if (3 > 2) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_LD_IMM64(R2, 2), + BPF_JMP_REG(BPF_JGT, R1, R2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JGE | BPF_X */ + { + "JMP_JGE_X: if (3 >= 2) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_LD_IMM64(R2, 2), + BPF_JMP_REG(BPF_JGE, R1, R2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "JMP_JGE_X: if (3 >= 3) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_LD_IMM64(R2, 3), + BPF_JMP_REG(BPF_JGE, R1, R2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JNE | BPF_X */ + { + "JMP_JNE_X: if (3 != 2) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_LD_IMM64(R2, 2), + BPF_JMP_REG(BPF_JNE, R1, R2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JEQ | BPF_X */ + { + "JMP_JEQ_X: if (3 == 3) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_LD_IMM64(R2, 3), + BPF_JMP_REG(BPF_JEQ, R1, R2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + /* BPF_JMP | BPF_JSET | BPF_X */ + { + "JMP_JSET_X: if (0x3 & 0x2) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_LD_IMM64(R2, 2), + BPF_JMP_REG(BPF_JNE, R1, R2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, + { + "JMP_JSET_X: if (0x3 & 0xffffffff) return 1", + .u.insns_int = { + BPF_ALU32_IMM(BPF_MOV, R0, 0), + BPF_LD_IMM64(R1, 3), + BPF_LD_IMM64(R2, 0xffffffff), + BPF_JMP_REG(BPF_JNE, R1, R2, 1), + BPF_EXIT_INSN(), + BPF_ALU32_IMM(BPF_MOV, R0, 1), + BPF_EXIT_INSN(), + }, + INTERNAL, + { }, + { { 0, 1 } }, + }, }; static struct net_device dev; -- cgit v1.2.3 From 9449c3cd90472141cf081af88181a56163ff7132 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Tue, 12 May 2015 18:29:44 +0800 Subject: net: make skb_dst_pop routine static As xfrm_output_one() is the only caller of skb_dst_pop(), we should make skb_dst_pop() localized. Signed-off-by: Ying Xue Signed-off-by: David S. Miller --- include/net/dst.h | 12 ------------ net/xfrm/xfrm_output.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/net/dst.h b/include/net/dst.h index 22aa93f165f1..2bc73f8a00a9 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -349,18 +349,6 @@ static inline void skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev, __skb_tunnel_rx(skb, dev, net); } -/* Children define the path of the packet through the - * Linux networking. Thus, destinations are stackable. - */ - -static inline struct dst_entry *skb_dst_pop(struct sk_buff *skb) -{ - struct dst_entry *child = dst_clone(skb_dst(skb)->child); - - skb_dst_drop(skb); - return child; -} - int dst_discard_sk(struct sock *sk, struct sk_buff *skb); static inline int dst_discard(struct sk_buff *skb) { diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index fbcedbe33190..68ada2ca4b60 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -38,6 +38,18 @@ static int xfrm_skb_check_space(struct sk_buff *skb) return pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC); } +/* Children define the path of the packet through the + * Linux networking. Thus, destinations are stackable. + */ + +static struct dst_entry *skb_dst_pop(struct sk_buff *skb) +{ + struct dst_entry *child = dst_clone(skb_dst(skb)->child); + + skb_dst_drop(skb); + return child; +} + static int xfrm_output_one(struct sk_buff *skb, int err) { struct dst_entry *dst = skb_dst(skb); -- cgit v1.2.3 From 01d460dd70adc858e15307332832183c622bee50 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 12 May 2015 09:37:00 -0600 Subject: net: Remove remaining remnants of pm_qos from netdevice.h Commit e2c6544829f removed pm_qos from struct net_device but left the comment and header file. Remove those. Signed-off-by: David Ahern Cc: Thomas Graf Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1899c74a7127..05b9a694e213 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -25,7 +25,6 @@ #ifndef _LINUX_NETDEVICE_H #define _LINUX_NETDEVICE_H -#include #include #include #include @@ -1499,8 +1498,6 @@ enum netdev_priv_flags { * * @qdisc_tx_busylock: XXX: need comments on this one * - * @pm_qos_req: Power Management QoS object - * * FIXME: cleanup struct net_device such that network protocol info * moves out. */ -- cgit v1.2.3 From f7bcb70ebae0dcdb5a2d859b09e4465784d99029 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 8 May 2015 13:47:23 -0700 Subject: ktime: Fix ktime_divns to do signed division It was noted that the 32bit implementation of ktime_divns() was doing unsigned division and didn't properly handle negative values. And when a ktime helper was changed to utilize ktime_divns, it caused a regression on some IR blasters. See the following bugzilla for details: https://bugzilla.redhat.com/show_bug.cgi?id=1200353 This patch fixes the problem in ktime_divns by checking and preserving the sign bit, and then reapplying it if appropriate after the division, it also changes the return type to a s64 to make it more obvious this is expected. Nicolas also pointed out that negative dividers would cause infinite loops on 32bit systems, negative dividers is unlikely for users of this function, but out of caution this patch adds checks for negative dividers for both 32-bit (BUG_ON) and 64-bit(WARN_ON) versions to make sure no such use cases creep in. [ tglx: Hand an u64 to do_div() to avoid the compiler warning ] Fixes: 166afb64511e 'ktime: Sanitize ktime_to_us/ms conversion' Reported-and-tested-by: Trevor Cordes Signed-off-by: John Stultz Acked-by: Nicolas Pitre Cc: Ingo Molnar Cc: Josh Boyer Cc: One Thousand Gnomes Cc: Link: http://lkml.kernel.org/r/1431118043-23452-1-git-send-email-john.stultz@linaro.org Signed-off-by: Thomas Gleixner --- include/linux/ktime.h | 27 +++++++++++++++++++++------ kernel/time/hrtimer.c | 14 ++++++++------ 2 files changed, 29 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/linux/ktime.h b/include/linux/ktime.h index 5fc3d1083071..2b6a204bd8d4 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -166,19 +166,34 @@ static inline bool ktime_before(const ktime_t cmp1, const ktime_t cmp2) } #if BITS_PER_LONG < 64 -extern u64 __ktime_divns(const ktime_t kt, s64 div); -static inline u64 ktime_divns(const ktime_t kt, s64 div) +extern s64 __ktime_divns(const ktime_t kt, s64 div); +static inline s64 ktime_divns(const ktime_t kt, s64 div) { + /* + * Negative divisors could cause an inf loop, + * so bug out here. + */ + BUG_ON(div < 0); if (__builtin_constant_p(div) && !(div >> 32)) { - u64 ns = kt.tv64; - do_div(ns, div); - return ns; + s64 ns = kt.tv64; + u64 tmp = ns < 0 ? -ns : ns; + + do_div(tmp, div); + return ns < 0 ? -tmp : tmp; } else { return __ktime_divns(kt, div); } } #else /* BITS_PER_LONG < 64 */ -# define ktime_divns(kt, div) (u64)((kt).tv64 / (div)) +static inline s64 ktime_divns(const ktime_t kt, s64 div) +{ + /* + * 32-bit implementation cannot handle negative divisors, + * so catch them on 64bit as well. + */ + WARN_ON(div < 0); + return kt.tv64 / div; +} #endif static inline s64 ktime_to_us(const ktime_t kt) diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 76d4bd962b19..93ef7190bdea 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -266,21 +266,23 @@ lock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags) /* * Divide a ktime value by a nanosecond value */ -u64 __ktime_divns(const ktime_t kt, s64 div) +s64 __ktime_divns(const ktime_t kt, s64 div) { - u64 dclc; int sft = 0; + s64 dclc; + u64 tmp; dclc = ktime_to_ns(kt); + tmp = dclc < 0 ? -dclc : dclc; + /* Make sure the divisor is less than 2^32: */ while (div >> 32) { sft++; div >>= 1; } - dclc >>= sft; - do_div(dclc, (unsigned long) div); - - return dclc; + tmp >>= sft; + do_div(tmp, (unsigned long) div); + return dclc < 0 ? -tmp : tmp; } EXPORT_SYMBOL_GPL(__ktime_divns); #endif /* BITS_PER_LONG >= 64 */ -- cgit v1.2.3 From 275e2bc0f25d5eb99c99ebb7293fc3722533124b Mon Sep 17 00:00:00 2001 From: Sergey Popovich Date: Sat, 2 May 2015 19:28:17 +0200 Subject: netfilter: ipset: Fix ext_*() macros So pointers returned by these macros could be referenced with -> directly. Signed-off-by: Sergey Popovich Signed-off-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/ipset/ip_set.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index 34b172301558..f88be7258e5f 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h @@ -122,13 +122,13 @@ struct ip_set_skbinfo { struct ip_set; #define ext_timeout(e, s) \ -(unsigned long *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_TIMEOUT]) +((unsigned long *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_TIMEOUT])) #define ext_counter(e, s) \ -(struct ip_set_counter *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COUNTER]) +((struct ip_set_counter *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COUNTER])) #define ext_comment(e, s) \ -(struct ip_set_comment *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COMMENT]) +((struct ip_set_comment *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COMMENT])) #define ext_skbinfo(e, s) \ -(struct ip_set_skbinfo *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_SKBINFO]) +((struct ip_set_skbinfo *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_SKBINFO])) typedef int (*ipset_adtfn)(struct ip_set *set, void *value, const struct ip_set_ext *ext, -- cgit v1.2.3 From 5eb764edee52e837638b8d55ceace2c68e248cd2 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Tue, 12 May 2015 23:03:53 -0700 Subject: switchdev: align comment with other comments in block Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- include/net/switchdev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 3b217b4cca27..9f9a7cc573c3 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -53,7 +53,7 @@ struct switchdev_obj { enum switchdev_obj_id id; enum switchdev_trans trans; union { - struct switchdev_obj_vlan { /* PORT_VLAN */ + struct switchdev_obj_vlan { /* PORT_VLAN */ u16 flags; u16 vid_start; u16 vid_end; -- cgit v1.2.3 From 42275bd8fcb351f951781d8882f359d25976824b Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 13 May 2015 11:16:50 -0700 Subject: switchdev: don't use anonymous union on switchdev attr/obj structs Older gcc versions (e.g. gcc version 4.4.6) don't like anonymous unions which was causing build issues on the newly added switchdev attr/obj structs. Fix this by using named union on structs. Signed-off-by: Scott Feldman Reported-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 18 ++++++++--------- include/net/switchdev.h | 4 ++-- net/bridge/br_stp.c | 2 +- net/core/net-sysfs.c | 4 ++-- net/core/rtnetlink.c | 3 ++- net/dsa/slave.c | 6 +++--- net/switchdev/switchdev.c | 39 ++++++++++++++++++------------------ 7 files changed, 39 insertions(+), 37 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index ca533936658b..f0a9cb44be6b 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4339,11 +4339,11 @@ static int rocker_port_attr_get(struct net_device *dev, switch (attr->id) { case SWITCHDEV_ATTR_PORT_PARENT_ID: - attr->ppid.id_len = sizeof(rocker->hw.id); - memcpy(&attr->ppid.id, &rocker->hw.id, attr->ppid.id_len); + attr->u.ppid.id_len = sizeof(rocker->hw.id); + memcpy(&attr->u.ppid.id, &rocker->hw.id, attr->u.ppid.id_len); break; case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS: - attr->brport_flags = rocker_port->brport_flags; + attr->u.brport_flags = rocker_port->brport_flags; break; default: return -EOPNOTSUPP; @@ -4400,11 +4400,11 @@ static int rocker_port_attr_set(struct net_device *dev, switch (attr->id) { case SWITCHDEV_ATTR_PORT_STP_STATE: err = rocker_port_stp_update(rocker_port, attr->trans, - attr->stp_state); + attr->u.stp_state); break; case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS: err = rocker_port_brport_flags_set(rocker_port, attr->trans, - attr->brport_flags); + attr->u.brport_flags); break; default: err = -EOPNOTSUPP; @@ -4466,10 +4466,10 @@ static int rocker_port_obj_add(struct net_device *dev, switch (obj->id) { case SWITCHDEV_OBJ_PORT_VLAN: err = rocker_port_vlans_add(rocker_port, obj->trans, - &obj->vlan); + &obj->u.vlan); break; case SWITCHDEV_OBJ_IPV4_FIB: - fib4 = &obj->ipv4_fib; + fib4 = &obj->u.ipv4_fib; err = rocker_port_fib_ipv4(rocker_port, obj->trans, htonl(fib4->dst), fib4->dst_len, fib4->fi, fib4->tb_id, 0); @@ -4520,10 +4520,10 @@ static int rocker_port_obj_del(struct net_device *dev, switch (obj->id) { case SWITCHDEV_OBJ_PORT_VLAN: - err = rocker_port_vlans_del(rocker_port, &obj->vlan); + err = rocker_port_vlans_del(rocker_port, &obj->u.vlan); break; case SWITCHDEV_OBJ_IPV4_FIB: - fib4 = &obj->ipv4_fib; + fib4 = &obj->u.ipv4_fib; err = rocker_port_fib_ipv4(rocker_port, SWITCHDEV_TRANS_NONE, htonl(fib4->dst), fib4->dst_len, fib4->fi, fib4->tb_id, diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 9f9a7cc573c3..ea5b1c230d3d 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -38,7 +38,7 @@ struct switchdev_attr { struct netdev_phys_item_id ppid; /* PORT_PARENT_ID */ u8 stp_state; /* PORT_STP_STATE */ unsigned long brport_flags; /* PORT_BRIDGE_FLAGS */ - }; + } u; }; struct fib_info; @@ -67,7 +67,7 @@ struct switchdev_obj { u32 nlflags; u32 tb_id; } ipv4_fib; - }; + } u; }; /** diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index b9300da31565..45f1ff113af9 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -41,7 +41,7 @@ void br_set_state(struct net_bridge_port *p, unsigned int state) { struct switchdev_attr attr = { .id = SWITCHDEV_ATTR_PORT_STP_STATE, - .stp_state = state, + .u.stp_state = state, }; int err; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 5a9ce96f6d27..18b34d771ed4 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -465,8 +465,8 @@ static ssize_t phys_switch_id_show(struct device *dev, ret = switchdev_port_attr_get(netdev, &attr); if (!ret) - ret = sprintf(buf, "%*phN\n", attr.ppid.id_len, - attr.ppid.id); + ret = sprintf(buf, "%*phN\n", attr.u.ppid.id_len, + attr.u.ppid.id); } rtnl_unlock(); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index c6c6b2c34926..141ccc357e2e 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1016,7 +1016,8 @@ static int rtnl_phys_switch_id_fill(struct sk_buff *skb, struct net_device *dev) return err; } - if (nla_put(skb, IFLA_PHYS_SWITCH_ID, attr.ppid.id_len, attr.ppid.id)) + if (nla_put(skb, IFLA_PHYS_SWITCH_ID, attr.u.ppid.id_len, + attr.u.ppid.id)) return -EMSGSIZE; return 0; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 3fb5210e318c..04ffad311704 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -353,7 +353,7 @@ static int dsa_slave_port_attr_set(struct net_device *dev, switch (attr->id) { case SWITCHDEV_ATTR_PORT_STP_STATE: if (attr->trans == SWITCHDEV_TRANS_COMMIT) - ret = dsa_slave_stp_update(dev, attr->stp_state); + ret = dsa_slave_stp_update(dev, attr->u.stp_state); break; default: ret = -EOPNOTSUPP; @@ -408,8 +408,8 @@ static int dsa_slave_port_attr_get(struct net_device *dev, switch (attr->id) { case SWITCHDEV_ATTR_PORT_PARENT_ID: - attr->ppid.id_len = sizeof(ds->index); - memcpy(&attr->ppid.id, &ds->index, attr->ppid.id_len); + attr->u.ppid.id_len = sizeof(ds->index); + memcpy(&attr->u.ppid.id, &ds->index, attr->u.ppid.id_len); break; default: return -EOPNOTSUPP; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 77f1b6e3f78e..0409f9b5bdbc 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -383,7 +383,7 @@ int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, return err; return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, - attr.brport_flags, mask, nlflags); + attr.u.brport_flags, mask, nlflags); } EXPORT_SYMBOL_GPL(switchdev_port_bridge_getlink); @@ -402,9 +402,9 @@ static int switchdev_port_br_setflag(struct net_device *dev, return err; if (flag) - attr.brport_flags |= brport_flag; + attr.u.brport_flags |= brport_flag; else - attr.brport_flags &= ~brport_flag; + attr.u.brport_flags &= ~brport_flag; return switchdev_port_attr_set(dev, &attr); } @@ -466,6 +466,7 @@ static int switchdev_port_br_afspec(struct net_device *dev, struct switchdev_obj obj = { .id = SWITCHDEV_OBJ_PORT_VLAN, }; + struct switchdev_obj_vlan *vlan = &obj.u.vlan; int rem; int err; @@ -475,30 +476,30 @@ static int switchdev_port_br_afspec(struct net_device *dev, if (nla_len(attr) != sizeof(struct bridge_vlan_info)) return -EINVAL; vinfo = nla_data(attr); - obj.vlan.flags = vinfo->flags; + vlan->flags = vinfo->flags; if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { - if (obj.vlan.vid_start) + if (vlan->vid_start) return -EINVAL; - obj.vlan.vid_start = vinfo->vid; + vlan->vid_start = vinfo->vid; } else if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) { - if (!obj.vlan.vid_start) + if (!vlan->vid_start) return -EINVAL; - obj.vlan.vid_end = vinfo->vid; - if (obj.vlan.vid_end <= obj.vlan.vid_start) + vlan->vid_end = vinfo->vid; + if (vlan->vid_end <= vlan->vid_start) return -EINVAL; err = f(dev, &obj); if (err) return err; - memset(&obj.vlan, 0, sizeof(obj.vlan)); + memset(vlan, 0, sizeof(*vlan)); } else { - if (obj.vlan.vid_start) + if (vlan->vid_start) return -EINVAL; - obj.vlan.vid_start = vinfo->vid; - obj.vlan.vid_end = vinfo->vid; + vlan->vid_start = vinfo->vid; + vlan->vid_end = vinfo->vid; err = f(dev, &obj); if (err) return err; - memset(&obj.vlan, 0, sizeof(obj.vlan)); + memset(vlan, 0, sizeof(*vlan)); } } @@ -613,10 +614,10 @@ static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi) return NULL; if (nhsel > 0) { - if (prev_attr.ppid.id_len != attr.ppid.id_len) + if (prev_attr.u.ppid.id_len != attr.u.ppid.id_len) return NULL; - if (memcmp(prev_attr.ppid.id, attr.ppid.id, - attr.ppid.id_len)) + if (memcmp(prev_attr.u.ppid.id, attr.u.ppid.id, + attr.u.ppid.id_len)) return NULL; } @@ -644,7 +645,7 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, { struct switchdev_obj fib_obj = { .id = SWITCHDEV_OBJ_IPV4_FIB, - .ipv4_fib = { + .u.ipv4_fib = { .dst = dst, .dst_len = dst_len, .fi = fi, @@ -698,7 +699,7 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, { struct switchdev_obj fib_obj = { .id = SWITCHDEV_OBJ_IPV4_FIB, - .ipv4_fib = { + .u.ipv4_fib = { .dst = dst, .dst_len = dst_len, .fi = fi, -- cgit v1.2.3 From e578d9c02587d57bfa7b560767c698a668a468c6 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 11 May 2015 19:50:41 +0200 Subject: net: sched: use counter to break reclassify loops Seems all we want here is to avoid endless 'goto reclassify' loop. tc_classify_compat even resets this counter when something other than TC_ACT_RECLASSIFY is returned, so this skb-counter doesn't break hypothetical loops induced by something other than perpetual TC_ACT_RECLASSIFY return values. skb_act_clone is now identical to skb_clone, so just use that. Tested with following (bogus) filter: tc filter add dev eth0 parent ffff: \ protocol ip u32 match u32 0 0 police rate 10Kbit burst \ 64000 mtu 1500 action reclassify Acked-by: Daniel Borkmann Signed-off-by: Florian Westphal Acked-by: Alexei Starovoitov Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- Documentation/networking/tc-actions-env-rules.txt | 4 ---- include/net/sch_generic.h | 15 --------------- include/uapi/linux/pkt_cls.h | 2 +- net/sched/act_mirred.c | 2 +- net/sched/sch_api.c | 12 +++--------- 5 files changed, 5 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/Documentation/networking/tc-actions-env-rules.txt b/Documentation/networking/tc-actions-env-rules.txt index 95c71716b2e2..f37814693ad3 100644 --- a/Documentation/networking/tc-actions-env-rules.txt +++ b/Documentation/networking/tc-actions-env-rules.txt @@ -8,10 +8,6 @@ For example if your action queues a packet to be processed later, or intentionally branches by redirecting a packet, then you need to clone the packet. -There are certain fields in the skb tc_verd that need to be reset so we -avoid loops, etc. A few are generic enough that skb_act_clone() -resets them for you, so invoke skb_act_clone() rather than skb_clone(). - 2) If you munge any packet thou shalt call pskb_expand_head in the case someone else is referencing the skb. After that you "own" the skb. diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 1b0a2e88ed2b..2738f6f87908 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -739,21 +739,6 @@ static inline u32 qdisc_l2t(struct qdisc_rate_table* rtab, unsigned int pktlen) return rtab->data[slot]; } -#ifdef CONFIG_NET_CLS_ACT -static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask, - int action) -{ - struct sk_buff *n; - - n = skb_clone(skb, gfp_mask); - - if (n) { - n->tc_verd = SET_TC_VERD(n->tc_verd, 0); - } - return n; -} -#endif - struct psched_ratecfg { u64 rate_bytes_ps; /* bytes per second */ u32 mult; diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 596ffa0c7084..ffc112c8e1c2 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -44,13 +44,13 @@ bits 9,10,11: redirect counter - redirect TTL. Loop avoidance #define TC_OK2MUNGE _TC_MAKEMASK1(1) #define SET_TC_OK2MUNGE(v) ( TC_OK2MUNGE | (v & ~TC_OK2MUNGE)) #define CLR_TC_OK2MUNGE(v) ( v & ~TC_OK2MUNGE) -#endif #define S_TC_VERD _TC_MAKE32(2) #define M_TC_VERD _TC_MAKEMASK(4,S_TC_VERD) #define G_TC_VERD(x) _TC_GETVALUE(x,S_TC_VERD,M_TC_VERD) #define V_TC_VERD(x) _TC_MAKEVALUE(x,S_TC_VERD) #define SET_TC_VERD(v,n) ((V_TC_VERD(n)) | (v & ~M_TC_VERD)) +#endif #define S_TC_FROM _TC_MAKE32(6) #define M_TC_FROM _TC_MAKEMASK(2,S_TC_FROM) diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 3f63ceac8e01..a42a3b257226 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -151,7 +151,7 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, } at = G_TC_AT(skb->tc_verd); - skb2 = skb_act_clone(skb, GFP_ATOMIC, m->tcf_action); + skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2 == NULL) goto out; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index ad9eed70bc8f..0b74dc0ede9c 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1816,13 +1816,8 @@ int tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp, continue; err = tp->classify(skb, tp, res); - if (err >= 0) { -#ifdef CONFIG_NET_CLS_ACT - if (err != TC_ACT_RECLASSIFY && skb->tc_verd) - skb->tc_verd = SET_TC_VERD(skb->tc_verd, 0); -#endif + if (err >= 0) return err; - } } return -1; } @@ -1834,23 +1829,22 @@ int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp, int err = 0; #ifdef CONFIG_NET_CLS_ACT const struct tcf_proto *otp = tp; + int limit = 0; reclassify: #endif err = tc_classify_compat(skb, tp, res); #ifdef CONFIG_NET_CLS_ACT if (err == TC_ACT_RECLASSIFY) { - u32 verd = G_TC_VERD(skb->tc_verd); tp = otp; - if (verd++ >= MAX_REC_LOOP) { + if (unlikely(limit++ >= MAX_REC_LOOP)) { net_notice_ratelimited("%s: packet reclassify loop rule prio %u protocol %02x\n", tp->q->ops->id, tp->prio & 0xffff, ntohs(tp->protocol)); return TC_ACT_SHOT; } - skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd); goto reclassify; } #endif -- cgit v1.2.3 From 1bd758eb1cab2fa5b71a23f9e5d3c8076f4ed650 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 May 2015 14:56:07 +0200 Subject: net: change name of flow_dissector header to match the .c file name add couple of empty lines on the way. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 +- drivers/net/ethernet/cisco/enic/enic_clsf.c | 2 +- include/linux/skbuff.h | 2 +- include/net/flow_dissector.h | 68 +++++++++++++++++++++++++++++ include/net/flow_keys.h | 61 -------------------------- include/net/ip.h | 2 +- include/net/ipv6.h | 2 +- net/core/flow_dissector.c | 2 +- net/sched/cls_flow.c | 2 +- net/sched/sch_choke.c | 2 +- 10 files changed, 76 insertions(+), 69 deletions(-) create mode 100644 include/net/flow_dissector.h delete mode 100644 include/net/flow_keys.h (limited to 'include') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a2e25de98bde..fe7c38721775 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -76,7 +76,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index 0be6850be8a2..380f04903a36 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include "enic_res.h" #include "enic_clsf.h" diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index c0b574a414e7..e35c2b13d434 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include /* A. Checksumming of received packets by device. * diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h new file mode 100644 index 000000000000..5e99a7b3963c --- /dev/null +++ b/include/net/flow_dissector.h @@ -0,0 +1,68 @@ +#ifndef _NET_FLOW_DISSECTOR_H +#define _NET_FLOW_DISSECTOR_H + +/* struct flow_keys: + * @src: source ip address in case of IPv4 + * For IPv6 it contains 32bit hash of src address + * @dst: destination ip address in case of IPv4 + * For IPv6 it contains 32bit hash of dst address + * @ports: port numbers of Transport header + * port16[0]: src port number + * port16[1]: dst port number + * @thoff: Transport header offset + * @n_proto: Network header protocol (eg. IPv4/IPv6) + * @ip_proto: Transport header protocol (eg. TCP/UDP) + * All the members, except thoff, are in network byte order. + */ +struct flow_keys { + /* (src,dst) must be grouped, in the same way than in IP header */ + __be32 src; + __be32 dst; + union { + __be32 ports; + __be16 port16[2]; + }; + u16 thoff; + __be16 n_proto; + u8 ip_proto; +}; + +bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow, + void *data, __be16 proto, int nhoff, int hlen); + +static inline bool skb_flow_dissect(const struct sk_buff *skb, + struct flow_keys *flow) +{ + return __skb_flow_dissect(skb, flow, NULL, 0, 0, 0); +} + +__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto, + void *data, int hlen_proto); + +static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, + int thoff, u8 ip_proto) +{ + return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0); +} + +u32 flow_hash_from_keys(struct flow_keys *keys); + +unsigned int flow_get_hlen(const unsigned char *data, unsigned int max_len, + __be16 protocol); + +/* struct flow_keys_digest: + * + * This structure is used to hold a digest of the full flow keys. This is a + * larger "hash" of a flow to allow definitively matching specific flows where + * the 32 bit skb->hash is not large enough. The size is limited to 16 bytes so + * that it can by used in CB of skb (see sch_choke for an example). + */ +#define FLOW_KEYS_DIGEST_LEN 16 +struct flow_keys_digest { + u8 data[FLOW_KEYS_DIGEST_LEN]; +}; + +void make_flow_keys_digest(struct flow_keys_digest *digest, + const struct flow_keys *flow); + +#endif diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h deleted file mode 100644 index 6d6ef626811a..000000000000 --- a/include/net/flow_keys.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef _NET_FLOW_KEYS_H -#define _NET_FLOW_KEYS_H - -/* struct flow_keys: - * @src: source ip address in case of IPv4 - * For IPv6 it contains 32bit hash of src address - * @dst: destination ip address in case of IPv4 - * For IPv6 it contains 32bit hash of dst address - * @ports: port numbers of Transport header - * port16[0]: src port number - * port16[1]: dst port number - * @thoff: Transport header offset - * @n_proto: Network header protocol (eg. IPv4/IPv6) - * @ip_proto: Transport header protocol (eg. TCP/UDP) - * All the members, except thoff, are in network byte order. - */ -struct flow_keys { - /* (src,dst) must be grouped, in the same way than in IP header */ - __be32 src; - __be32 dst; - union { - __be32 ports; - __be16 port16[2]; - }; - u16 thoff; - __be16 n_proto; - u8 ip_proto; -}; - -bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow, - void *data, __be16 proto, int nhoff, int hlen); -static inline bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow) -{ - return __skb_flow_dissect(skb, flow, NULL, 0, 0, 0); -} -__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto, - void *data, int hlen_proto); -static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto) -{ - return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0); -} -u32 flow_hash_from_keys(struct flow_keys *keys); -unsigned int flow_get_hlen(const unsigned char *data, unsigned int max_len, - __be16 protocol); - -/* struct flow_keys_digest: - * - * This structure is used to hold a digest of the full flow keys. This is a - * larger "hash" of a flow to allow definitively matching specific flows where - * the 32 bit skb->hash is not large enough. The size is limited to 16 bytes so - * that it can by used in CB of skb (see sch_choke for an example). - */ -#define FLOW_KEYS_DIGEST_LEN 16 -struct flow_keys_digest { - u8 data[FLOW_KEYS_DIGEST_LEN]; -}; - -void make_flow_keys_digest(struct flow_keys_digest *digest, - const struct flow_keys *flow); - -#endif diff --git a/include/net/ip.h b/include/net/ip.h index d14af7edd197..562eb653aebc 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -31,7 +31,7 @@ #include #include #include -#include +#include struct sock; diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 53d25ef1699a..9932b86394a9 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #define SIN6_LEN_RFC2133 24 diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index d3acc4dff4ae..eaa86b539221 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include /* copy saddr & daddr, possibly using 64bit load/store diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index a620c4e288a5..4c5a92298906 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) #include diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index dfe3da75594c..2624e991a2d1 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include /* CHOKe stateless AQM for fair bandwidth allocation -- cgit v1.2.3 From b0a31431b4d81fb1ccc36ce64ce3fe6a0aca4031 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 May 2015 14:56:08 +0200 Subject: flow_dissector: remove unused function flow_get_hlen declaration commit 56193d1bce ("net: Add function for parsing the header length out of linear ethernet frames") added this function declaration but it is defined nowhere. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'include') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 5e99a7b3963c..118ae6926a72 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -47,9 +47,6 @@ static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, u32 flow_hash_from_keys(struct flow_keys *keys); -unsigned int flow_get_hlen(const unsigned char *data, unsigned int max_len, - __be16 protocol); - /* struct flow_keys_digest: * * This structure is used to hold a digest of the full flow keys. This is a -- cgit v1.2.3 From 10b89ee43e849544eddfe34e535341fc077464ec Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 May 2015 14:56:09 +0200 Subject: net: move *skb_get_poff declarations into correct header Since these functions are defined in flow_dissector.c, move header declarations from skbuff.h into flow_dissector.h Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/skbuff.h | 4 ---- include/net/flow_dissector.h | 3 +++ net/core/filter.c | 1 + net/ethernet/eth.c | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index e35c2b13d434..17607ab9e7a2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3424,10 +3424,6 @@ struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb, unsigned int transport_len, __sum16(*skb_chkf)(struct sk_buff *skb)); -u32 skb_get_poff(const struct sk_buff *skb); -u32 __skb_get_poff(const struct sk_buff *skb, void *data, - const struct flow_keys *keys, int hlen); - /** * skb_head_is_locked - Determine if the skb->head is locked down * @skb: skb to check diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 118ae6926a72..4570ccafe59d 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -46,6 +46,9 @@ static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, } u32 flow_hash_from_keys(struct flow_keys *keys); +u32 skb_get_poff(const struct sk_buff *skb); +u32 __skb_get_poff(const struct sk_buff *skb, void *data, + const struct flow_keys *keys, int hlen); /* struct flow_keys_digest: * diff --git a/net/core/filter.c b/net/core/filter.c index a831f193e2c7..6805717be614 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 9045e2a1108f..9332a0ab0698 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -58,6 +58,7 @@ #include #include #include +#include #include __setup("ether=", netdev_boot_setup); -- cgit v1.2.3 From 9c684b5083bc191c4b7b189c73d75587e167a474 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 May 2015 14:56:11 +0200 Subject: net: move __skb_get_hash function declaration to flow_dissector.h Since the definition of the function is in flow_dissector.c, it makes sense to have the declaration in flow_dissector.h Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/skbuff.h | 1 - include/net/flow_dissector.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 17607ab9e7a2..ae2d1b7769d8 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -918,7 +918,6 @@ skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type) skb->hash = hash; } -void __skb_get_hash(struct sk_buff *skb); static inline __u32 skb_get_hash(struct sk_buff *skb) { if (!skb->l4_hash && !skb->sw_hash) diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 4570ccafe59d..e4ee761ca8c0 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -46,6 +46,7 @@ static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, } u32 flow_hash_from_keys(struct flow_keys *keys); +void __skb_get_hash(struct sk_buff *skb); u32 skb_get_poff(const struct sk_buff *skb); u32 __skb_get_poff(const struct sk_buff *skb, void *data, const struct flow_keys *keys, int hlen); -- cgit v1.2.3 From 5605c76240aadc823e3d46ac9afde2f26fbcf019 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 May 2015 14:56:12 +0200 Subject: net: move __skb_tx_hash to dev.c __skb_tx_hash function has no relation to flow_dissect so just move it to dev.c Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 +++ include/linux/skbuff.h | 3 --- net/core/dev.c | 28 ++++++++++++++++++++++++++++ net/core/flow_dissector.c | 28 ---------------------------- 4 files changed, 31 insertions(+), 31 deletions(-) (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index cd0951c1893d..d3ed01c18247 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2832,6 +2832,9 @@ static inline int netif_set_xps_queue(struct net_device *dev, } #endif +u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb, + unsigned int num_tx_queues); + /* * Returns a Tx hash for the given packet when dev->real_num_tx_queues is used * as a distribution range limit for the returned value. diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index ae2d1b7769d8..b01c7fba7c17 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3299,9 +3299,6 @@ static inline bool skb_rx_queue_recorded(const struct sk_buff *skb) return skb->queue_mapping != 0; } -u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb, - unsigned int num_tx_queues); - static inline struct sec_path *skb_sec_path(struct sk_buff *skb) { #ifdef CONFIG_XFRM diff --git a/net/core/dev.c b/net/core/dev.c index 90a568a150b4..d044d2f8532b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2350,6 +2350,34 @@ void netif_device_attach(struct net_device *dev) } EXPORT_SYMBOL(netif_device_attach); +/* + * Returns a Tx hash based on the given packet descriptor a Tx queues' number + * to be used as a distribution range. + */ +u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb, + unsigned int num_tx_queues) +{ + u32 hash; + u16 qoffset = 0; + u16 qcount = num_tx_queues; + + if (skb_rx_queue_recorded(skb)) { + hash = skb_get_rx_queue(skb); + while (unlikely(hash >= num_tx_queues)) + hash -= num_tx_queues; + return hash; + } + + if (dev->num_tc) { + u8 tc = netdev_get_prio_tc_map(dev, skb->priority); + qoffset = dev->tc_to_txq[tc].offset; + qcount = dev->tc_to_txq[tc].count; + } + + return (u16) reciprocal_scale(skb_get_hash(skb), qcount) + qoffset; +} +EXPORT_SYMBOL(__skb_tx_hash); + static void skb_warn_bad_offload(const struct sk_buff *skb) { static const netdev_features_t null_features = 0; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 0d9bc3a586ba..07ca11d06339 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -371,34 +371,6 @@ __u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb) } EXPORT_SYMBOL(skb_get_hash_perturb); -/* - * Returns a Tx hash based on the given packet descriptor a Tx queues' number - * to be used as a distribution range. - */ -u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb, - unsigned int num_tx_queues) -{ - u32 hash; - u16 qoffset = 0; - u16 qcount = num_tx_queues; - - if (skb_rx_queue_recorded(skb)) { - hash = skb_get_rx_queue(skb); - while (unlikely(hash >= num_tx_queues)) - hash -= num_tx_queues; - return hash; - } - - if (dev->num_tc) { - u8 tc = netdev_get_prio_tc_map(dev, skb->priority); - qoffset = dev->tc_to_txq[tc].offset; - qcount = dev->tc_to_txq[tc].count; - } - - return (u16) reciprocal_scale(skb_get_hash(skb), qcount) + qoffset; -} -EXPORT_SYMBOL(__skb_tx_hash); - u32 __skb_get_poff(const struct sk_buff *skb, void *data, const struct flow_keys *keys, int hlen) { -- cgit v1.2.3 From fbff949e3bc7f3f7d9e8b3ef4855ec7138276a25 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 May 2015 14:56:15 +0200 Subject: flow_dissector: introduce programable flow_dissector Introduce dissector infrastructure which allows user to specify which parts of skb he wants to dissect. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 61 ++++++++++++++++++++++++++++++++++++++++++++ net/core/flow_dissector.c | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) (limited to 'include') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index e4ee761ca8c0..20239e807f77 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -1,6 +1,64 @@ #ifndef _NET_FLOW_DISSECTOR_H #define _NET_FLOW_DISSECTOR_H +/** + * struct flow_dissector_key_basic: + * @thoff: Transport header offset + * @n_proto: Network header protocol (eg. IPv4/IPv6) + * @ip_proto: Transport header protocol (eg. TCP/UDP) + */ +struct flow_dissector_key_basic { + u16 thoff; + __be16 n_proto; + u8 ip_proto; +}; + +/** + * struct flow_dissector_key_addrs: + * @src: source ip address in case of IPv4 + * For IPv6 it contains 32bit hash of src address + * @dst: destination ip address in case of IPv4 + * For IPv6 it contains 32bit hash of dst address + */ +struct flow_dissector_key_addrs { + /* (src,dst) must be grouped, in the same way than in IP header */ + __be32 src; + __be32 dst; +}; + +/** + * flow_dissector_key_tp_ports: + * @ports: port numbers of Transport header + * port16[0]: src port number + * port16[1]: dst port number + */ +struct flow_dissector_key_ports { + union { + __be32 ports; + __be16 port16[2]; + }; +}; + +enum flow_dissector_key_id { + FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ + FLOW_DISSECTOR_KEY_IPV4_ADDRS, /* struct flow_dissector_key_addrs */ + FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, /* struct flow_dissector_key_addrs */ + FLOW_DISSECTOR_KEY_PORTS, /* struct flow_dissector_key_ports */ + + FLOW_DISSECTOR_KEY_MAX, +}; + +struct flow_dissector_key { + enum flow_dissector_key_id key_id; + size_t offset; /* offset of struct flow_dissector_key_* + in target the struct */ +}; + +struct flow_dissector { + unsigned int used_keys; /* each bit repesents presence of one key id */ + unsigned short int offset[FLOW_DISSECTOR_KEY_MAX]; +}; + /* struct flow_keys: * @src: source ip address in case of IPv4 * For IPv6 it contains 32bit hash of src address @@ -27,6 +85,9 @@ struct flow_keys { u8 ip_proto; }; +void skb_flow_dissector_init(struct flow_dissector *flow_dissector, + const struct flow_dissector_key *key, + unsigned int key_count); bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow, void *data, __be16 proto, int nhoff, int hlen); diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index d885e282908e..6883e22b8fc4 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -15,6 +16,53 @@ #include #include +static bool skb_flow_dissector_uses_key(struct flow_dissector *flow_dissector, + enum flow_dissector_key_id key_id) +{ + return flow_dissector->used_keys & (1 << key_id); +} + +static void skb_flow_dissector_set_key(struct flow_dissector *flow_dissector, + enum flow_dissector_key_id key_id) +{ + flow_dissector->used_keys |= (1 << key_id); +} + +static void *skb_flow_dissector_target(struct flow_dissector *flow_dissector, + enum flow_dissector_key_id key_id, + void *target_container) +{ + return ((char *) target_container) + flow_dissector->offset[key_id]; +} + +void skb_flow_dissector_init(struct flow_dissector *flow_dissector, + const struct flow_dissector_key *key, + unsigned int key_count) +{ + unsigned int i; + + memset(flow_dissector, 0, sizeof(*flow_dissector)); + + for (i = 0; i < key_count; i++, key++) { + /* User should make sure that every key target offset is withing + * boundaries of unsigned short. + */ + BUG_ON(key->offset > USHRT_MAX); + BUG_ON(skb_flow_dissector_uses_key(flow_dissector, + key->key_id)); + + skb_flow_dissector_set_key(flow_dissector, key->key_id); + flow_dissector->offset[key->key_id] = key->offset; + } + + /* Ensure that the dissector always includes basic key. That way + * we are able to avoid handling lack of it in fast path. + */ + BUG_ON(!skb_flow_dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_BASIC)); +} +EXPORT_SYMBOL(skb_flow_dissector_init); + /* copy saddr & daddr, possibly using 64bit load/store * Equivalent to : flow->src = iph->saddr; * flow->dst = iph->daddr; -- cgit v1.2.3 From 06635a35d13d42b95422bba6633f175245cc644e Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 May 2015 14:56:16 +0200 Subject: flow_dissect: use programable dissector in skb_flow_dissect and friends Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 18 +-- drivers/net/ethernet/cisco/enic/enic_clsf.c | 27 ++-- drivers/net/ethernet/cisco/enic/enic_ethtool.c | 10 +- drivers/net/hyperv/netvsc_drv.c | 8 +- include/linux/skbuff.h | 4 +- include/net/flow_dissector.h | 63 ++++---- include/net/ip.h | 8 +- include/net/ipv6.h | 8 +- net/core/flow_dissector.c | 199 +++++++++++++++++-------- net/ethernet/eth.c | 6 +- net/sched/cls_flow.c | 20 +-- net/sched/sch_choke.c | 4 +- 12 files changed, 229 insertions(+), 146 deletions(-) (limited to 'include') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index fe7c38721775..ef26e0147050 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3051,16 +3051,16 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, int noff, proto = -1; if (bond->params.xmit_policy > BOND_XMIT_POLICY_LAYER23) - return skb_flow_dissect(skb, fk); + return skb_flow_dissect_flow_keys(skb, fk); - fk->ports = 0; + fk->ports.ports = 0; noff = skb_network_offset(skb); if (skb->protocol == htons(ETH_P_IP)) { if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph)))) return false; iph = ip_hdr(skb); - fk->src = iph->saddr; - fk->dst = iph->daddr; + fk->addrs.src = iph->saddr; + fk->addrs.dst = iph->daddr; noff += iph->ihl << 2; if (!ip_is_fragment(iph)) proto = iph->protocol; @@ -3068,15 +3068,15 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph6)))) return false; iph6 = ipv6_hdr(skb); - fk->src = (__force __be32)ipv6_addr_hash(&iph6->saddr); - fk->dst = (__force __be32)ipv6_addr_hash(&iph6->daddr); + fk->addrs.src = (__force __be32)ipv6_addr_hash(&iph6->saddr); + fk->addrs.dst = (__force __be32)ipv6_addr_hash(&iph6->daddr); noff += sizeof(*iph6); proto = iph6->nexthdr; } else { return false; } if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34 && proto >= 0) - fk->ports = skb_flow_get_ports(skb, noff, proto); + fk->ports.ports = skb_flow_get_ports(skb, noff, proto); return true; } @@ -3102,8 +3102,8 @@ u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb) bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23) hash = bond_eth_hash(skb); else - hash = (__force u32)flow.ports; - hash ^= (__force u32)flow.dst ^ (__force u32)flow.src; + hash = (__force u32)flow.ports.ports; + hash ^= (__force u32)flow.addrs.dst ^ (__force u32)flow.addrs.src; hash ^= (hash >> 16); hash ^= (hash >> 8); diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index 380f04903a36..d3d25c7e5b96 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -22,7 +22,7 @@ int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq) int res; struct filter data; - switch (keys->ip_proto) { + switch (keys->basic.ip_proto) { case IPPROTO_TCP: data.u.ipv4.protocol = PROTO_TCP; break; @@ -33,10 +33,10 @@ int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq) return -EPROTONOSUPPORT; }; data.type = FILTER_IPV4_5TUPLE; - data.u.ipv4.src_addr = ntohl(keys->src); - data.u.ipv4.dst_addr = ntohl(keys->dst); - data.u.ipv4.src_port = ntohs(keys->port16[0]); - data.u.ipv4.dst_port = ntohs(keys->port16[1]); + data.u.ipv4.src_addr = ntohl(keys->addrs.src); + data.u.ipv4.dst_addr = ntohl(keys->addrs.dst); + data.u.ipv4.src_port = ntohs(keys->ports.port16[0]); + data.u.ipv4.dst_port = ntohs(keys->ports.port16[1]); data.u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE; spin_lock_bh(&enic->devcmd_lock); @@ -158,11 +158,11 @@ static struct enic_rfs_fltr_node *htbl_key_search(struct hlist_head *h, struct enic_rfs_fltr_node *tpos; hlist_for_each_entry(tpos, h, node) - if (tpos->keys.src == k->src && - tpos->keys.dst == k->dst && - tpos->keys.ports == k->ports && - tpos->keys.ip_proto == k->ip_proto && - tpos->keys.n_proto == k->n_proto) + if (tpos->keys.addrs.src == k->addrs.src && + tpos->keys.addrs.dst == k->addrs.dst && + tpos->keys.ports.ports == k->ports.ports && + tpos->keys.basic.ip_proto == k->basic.ip_proto && + tpos->keys.basic.n_proto == k->basic.n_proto) return tpos; return NULL; } @@ -177,9 +177,10 @@ int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, int res, i; enic = netdev_priv(dev); - res = skb_flow_dissect(skb, &keys); - if (!res || keys.n_proto != htons(ETH_P_IP) || - (keys.ip_proto != IPPROTO_TCP && keys.ip_proto != IPPROTO_UDP)) + res = skb_flow_dissect_flow_keys(skb, &keys); + if (!res || keys.basic.n_proto != htons(ETH_P_IP) || + (keys.basic.ip_proto != IPPROTO_TCP && + keys.basic.ip_proto != IPPROTO_UDP)) return -EPROTONOSUPPORT; tbl_idx = skb_get_hash_raw(skb) & ENIC_RFS_FLW_MASK; diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c index 28d9ca675a27..7588f8dcc890 100644 --- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c +++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c @@ -334,7 +334,7 @@ static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd) n = htbl_fltr_search(enic, (u16)fsp->location); if (!n) return -EINVAL; - switch (n->keys.ip_proto) { + switch (n->keys.basic.ip_proto) { case IPPROTO_TCP: fsp->flow_type = TCP_V4_FLOW; break; @@ -346,16 +346,16 @@ static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd) break; } - fsp->h_u.tcp_ip4_spec.ip4src = n->keys.src; + fsp->h_u.tcp_ip4_spec.ip4src = n->keys.addrs.src; fsp->m_u.tcp_ip4_spec.ip4src = (__u32)~0; - fsp->h_u.tcp_ip4_spec.ip4dst = n->keys.dst; + fsp->h_u.tcp_ip4_spec.ip4dst = n->keys.addrs.dst; fsp->m_u.tcp_ip4_spec.ip4dst = (__u32)~0; - fsp->h_u.tcp_ip4_spec.psrc = n->keys.port16[0]; + fsp->h_u.tcp_ip4_spec.psrc = n->keys.ports.port16[0]; fsp->m_u.tcp_ip4_spec.psrc = (__u16)~0; - fsp->h_u.tcp_ip4_spec.pdst = n->keys.port16[1]; + fsp->h_u.tcp_ip4_spec.pdst = n->keys.ports.port16[1]; fsp->m_u.tcp_ip4_spec.pdst = (__u16)~0; fsp->ring_cookie = n->rq_id; diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 5993c7e2d723..8e5fe888a0ec 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -196,12 +196,12 @@ static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb) struct flow_keys flow; int data_len; - if (!skb_flow_dissect(skb, &flow) || - !(flow.n_proto == htons(ETH_P_IP) || - flow.n_proto == htons(ETH_P_IPV6))) + if (!skb_flow_dissect_flow_keys(skb, &flow) || + !(flow.basic.n_proto == htons(ETH_P_IP) || + flow.basic.n_proto == htons(ETH_P_IPV6))) return false; - if (flow.ip_proto == IPPROTO_TCP) + if (flow.basic.ip_proto == IPPROTO_TCP) data_len = 12; else data_len = 8; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index b01c7fba7c17..f83aa6568cbf 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1935,8 +1935,8 @@ static inline void skb_probe_transport_header(struct sk_buff *skb, if (skb_transport_header_was_set(skb)) return; - else if (skb_flow_dissect(skb, &keys)) - skb_set_transport_header(skb, keys.thoff); + else if (skb_flow_dissect_flow_keys(skb, &keys)) + skb_set_transport_header(skb, keys.basic.thoff); else skb_set_transport_header(skb, offset_hint); } diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 20239e807f77..0c8d406fb730 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -59,42 +59,47 @@ struct flow_dissector { unsigned short int offset[FLOW_DISSECTOR_KEY_MAX]; }; -/* struct flow_keys: - * @src: source ip address in case of IPv4 - * For IPv6 it contains 32bit hash of src address - * @dst: destination ip address in case of IPv4 - * For IPv6 it contains 32bit hash of dst address - * @ports: port numbers of Transport header - * port16[0]: src port number - * port16[1]: dst port number - * @thoff: Transport header offset - * @n_proto: Network header protocol (eg. IPv4/IPv6) - * @ip_proto: Transport header protocol (eg. TCP/UDP) - * All the members, except thoff, are in network byte order. - */ -struct flow_keys { - /* (src,dst) must be grouped, in the same way than in IP header */ - __be32 src; - __be32 dst; - union { - __be32 ports; - __be16 port16[2]; - }; - u16 thoff; - __be16 n_proto; - u8 ip_proto; -}; - void skb_flow_dissector_init(struct flow_dissector *flow_dissector, const struct flow_dissector_key *key, unsigned int key_count); -bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow, + +bool __skb_flow_dissect(const struct sk_buff *skb, + struct flow_dissector *flow_dissector, + void *target_container, void *data, __be16 proto, int nhoff, int hlen); static inline bool skb_flow_dissect(const struct sk_buff *skb, - struct flow_keys *flow) + struct flow_dissector *flow_dissector, + void *target_container) +{ + return __skb_flow_dissect(skb, flow_dissector, target_container, + NULL, 0, 0, 0); +} + +struct flow_keys { + struct flow_dissector_key_addrs addrs; + struct flow_dissector_key_ports ports; + struct flow_dissector_key_basic basic; +}; + +extern struct flow_dissector flow_keys_dissector; +extern struct flow_dissector flow_keys_buf_dissector; + +static inline bool skb_flow_dissect_flow_keys(const struct sk_buff *skb, + struct flow_keys *flow) +{ + memset(flow, 0, sizeof(*flow)); + return __skb_flow_dissect(skb, &flow_keys_dissector, flow, + NULL, 0, 0, 0); +} + +static inline bool skb_flow_dissect_flow_keys_buf(struct flow_keys *flow, + void *data, __be16 proto, + int nhoff, int hlen) { - return __skb_flow_dissect(skb, flow, NULL, 0, 0, 0); + memset(flow, 0, sizeof(*flow)); + return __skb_flow_dissect(NULL, &flow_keys_buf_dissector, flow, + data, proto, nhoff, hlen); } __be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto, diff --git a/include/net/ip.h b/include/net/ip.h index 562eb653aebc..b0443d4fe13f 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -360,10 +360,10 @@ static inline void inet_set_txhash(struct sock *sk) struct inet_sock *inet = inet_sk(sk); struct flow_keys keys; - keys.src = inet->inet_saddr; - keys.dst = inet->inet_daddr; - keys.port16[0] = inet->inet_sport; - keys.port16[1] = inet->inet_dport; + keys.addrs.src = inet->inet_saddr; + keys.addrs.dst = inet->inet_daddr; + keys.ports.port16[0] = inet->inet_sport; + keys.ports.port16[1] = inet->inet_dport; sk->sk_txhash = flow_hash_from_keys(&keys); } diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 9932b86394a9..9eed9761dfce 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -698,10 +698,10 @@ static inline void ip6_set_txhash(struct sock *sk) struct ipv6_pinfo *np = inet6_sk(sk); struct flow_keys keys; - keys.src = (__force __be32)ipv6_addr_hash(&np->saddr); - keys.dst = (__force __be32)ipv6_addr_hash(&sk->sk_v6_daddr); - keys.port16[0] = inet->inet_sport; - keys.port16[1] = inet->inet_dport; + keys.addrs.src = (__force __be32)ipv6_addr_hash(&np->saddr); + keys.addrs.dst = (__force __be32)ipv6_addr_hash(&sk->sk_v6_daddr); + keys.ports.port16[0] = inet->inet_sport; + keys.ports.port16[1] = inet->inet_dport; sk->sk_txhash = flow_hash_from_keys(&keys); } diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 6883e22b8fc4..6a49acaa6651 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -63,17 +64,6 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector, } EXPORT_SYMBOL(skb_flow_dissector_init); -/* copy saddr & daddr, possibly using 64bit load/store - * Equivalent to : flow->src = iph->saddr; - * flow->dst = iph->daddr; - */ -static void iph_to_flow_copy_addrs(struct flow_keys *flow, const struct iphdr *iph) -{ - BUILD_BUG_ON(offsetof(typeof(*flow), dst) != - offsetof(typeof(*flow), src) + sizeof(flow->src)); - memcpy(&flow->src, &iph->saddr, sizeof(flow->src) + sizeof(flow->dst)); -} - /** * __skb_flow_get_ports - extract the upper layer ports and return them * @skb: sk_buff to extract the ports from @@ -111,17 +101,27 @@ EXPORT_SYMBOL(__skb_flow_get_ports); /** * __skb_flow_dissect - extract the flow_keys struct and return it * @skb: sk_buff to extract the flow from, can be NULL if the rest are specified + * @flow_dissector: list of keys to dissect + * @target_container: target structure to put dissected values into * @data: raw buffer pointer to the packet, if NULL use skb->data * @proto: protocol for which to get the flow, if @data is NULL use skb->protocol * @nhoff: network header offset, if @data is NULL use skb_network_offset(skb) * @hlen: packet header length, if @data is NULL use skb_headlen(skb) * - * The function will try to retrieve the struct flow_keys from either the skbuff - * or a raw buffer specified by the rest parameters + * The function will try to retrieve individual keys into target specified + * by flow_dissector from either the skbuff or a raw buffer specified by the + * rest parameters. + * + * Caller must take care of zeroing target container memory. */ -bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow, +bool __skb_flow_dissect(const struct sk_buff *skb, + struct flow_dissector *flow_dissector, + void *target_container, void *data, __be16 proto, int nhoff, int hlen) { + struct flow_dissector_key_basic *key_basic; + struct flow_dissector_key_addrs *key_addrs; + struct flow_dissector_key_ports *key_ports; u8 ip_proto; if (!data) { @@ -131,7 +131,12 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow, hlen = skb_headlen(skb); } - memset(flow, 0, sizeof(*flow)); + /* It is ensured by skb_flow_dissector_init() that basic key will + * be always present. + */ + key_basic = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_BASIC, + target_container); again: switch (proto) { @@ -148,14 +153,13 @@ ip: if (ip_is_fragment(iph)) ip_proto = 0; - /* skip the address processing if skb is NULL. The assumption - * here is that if there is no skb we are not looking for flow - * info but lengths and protocols. - */ - if (!skb) + if (!skb_flow_dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_IPV4_ADDRS)) break; - - iph_to_flow_copy_addrs(flow, iph); + key_addrs = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_IPV4_ADDRS, + target_container); + memcpy(key_addrs, &iph->saddr, sizeof(*key_addrs)); break; } case htons(ETH_P_IPV6): { @@ -171,12 +175,15 @@ ipv6: ip_proto = iph->nexthdr; nhoff += sizeof(struct ipv6hdr); - /* see comment above in IPv4 section */ - if (!skb) + if (!skb_flow_dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS)) break; + key_addrs = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, + target_container); - flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr); - flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); + key_addrs->src = (__force __be32)ipv6_addr_hash(&iph->saddr); + key_addrs->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); flow_label = ip6_flowlabel(iph); if (flow_label) { @@ -184,10 +191,18 @@ ipv6: * use that to represent the ports without any * further dissection. */ - flow->n_proto = proto; - flow->ip_proto = ip_proto; - flow->ports = flow_label; - flow->thoff = (u16)nhoff; + + key_basic->n_proto = proto; + key_basic->ip_proto = ip_proto; + key_basic->thoff = (u16)nhoff; + + if (!skb_flow_dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_PORTS)) + break; + key_ports = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_PORTS, + target_container); + key_ports->ports = flow_label; return true; } @@ -234,14 +249,22 @@ ipv6: hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); if (!hdr) return false; - flow->src = hdr->srcnode; - flow->dst = 0; - flow->n_proto = proto; - flow->thoff = (u16)nhoff; + key_basic->n_proto = proto; + key_basic->thoff = (u16)nhoff; + + if (skb_flow_dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS)) { + return true; + key_addrs = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, + target_container); + key_addrs->src = hdr->srcnode; + key_addrs->dst = 0; + } return true; } case htons(ETH_P_FCOE): - flow->thoff = (u16)(nhoff + FCOE_HEADER_LEN); + key_basic->thoff = (u16)(nhoff + FCOE_HEADER_LEN); /* fall through */ default: return false; @@ -296,14 +319,24 @@ ipv6: break; } - flow->n_proto = proto; - flow->ip_proto = ip_proto; - flow->thoff = (u16) nhoff; - - /* unless skb is set we don't need to record port info */ - if (skb) - flow->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, - data, hlen); + /* It is ensured by skb_flow_dissector_init() that basic key will + * be always present. + */ + key_basic = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_BASIC, + target_container); + key_basic->n_proto = proto; + key_basic->ip_proto = ip_proto; + key_basic->thoff = (u16) nhoff; + + if (skb_flow_dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_PORTS)) { + key_ports = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_PORTS, + target_container); + key_ports->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, + data, hlen); + } return true; } @@ -325,16 +358,16 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) u32 hash; /* get a consistent hash (same value on both flow directions) */ - if (((__force u32)keys->dst < (__force u32)keys->src) || - (((__force u32)keys->dst == (__force u32)keys->src) && - ((__force u16)keys->port16[1] < (__force u16)keys->port16[0]))) { - swap(keys->dst, keys->src); - swap(keys->port16[0], keys->port16[1]); + if (((__force u32)keys->addrs.dst < (__force u32)keys->addrs.src) || + (((__force u32)keys->addrs.dst == (__force u32)keys->addrs.src) && + ((__force u16)keys->ports.port16[1] < (__force u16)keys->ports.port16[0]))) { + swap(keys->addrs.dst, keys->addrs.src); + swap(keys->ports.port16[0], keys->ports.port16[1]); } - hash = __flow_hash_3words((__force u32)keys->dst, - (__force u32)keys->src, - (__force u32)keys->ports, + hash = __flow_hash_3words((__force u32)keys->addrs.dst, + (__force u32)keys->addrs.src, + (__force u32)keys->ports.ports, keyval); if (!hash) hash = 1; @@ -352,7 +385,7 @@ EXPORT_SYMBOL(flow_hash_from_keys); static inline u32 ___skb_get_hash(const struct sk_buff *skb, struct flow_keys *keys, u32 keyval) { - if (!skb_flow_dissect(skb, keys)) + if (!skb_flow_dissect_flow_keys(skb, keys)) return 0; return __flow_hash_from_keys(keys, keyval); @@ -377,11 +410,11 @@ void make_flow_keys_digest(struct flow_keys_digest *digest, memset(digest, 0, sizeof(*digest)); - data->n_proto = flow->n_proto; - data->ip_proto = flow->ip_proto; - data->ports = flow->ports; - data->src = flow->src; - data->dst = flow->dst; + data->n_proto = flow->basic.n_proto; + data->ip_proto = flow->basic.ip_proto; + data->ports = flow->ports.ports; + data->src = flow->addrs.src; + data->dst = flow->addrs.dst; } EXPORT_SYMBOL(make_flow_keys_digest); @@ -404,7 +437,7 @@ void __skb_get_hash(struct sk_buff *skb) hash = ___skb_get_hash(skb, &keys, hashrnd); if (!hash) return; - if (keys.ports) + if (keys.ports.ports) skb->l4_hash = 1; skb->sw_hash = 1; skb->hash = hash; @@ -422,9 +455,9 @@ EXPORT_SYMBOL(skb_get_hash_perturb); u32 __skb_get_poff(const struct sk_buff *skb, void *data, const struct flow_keys *keys, int hlen) { - u32 poff = keys->thoff; + u32 poff = keys->basic.thoff; - switch (keys->ip_proto) { + switch (keys->basic.ip_proto) { case IPPROTO_TCP: { /* access doff as u8 to avoid unaligned access */ const u8 *doff; @@ -478,8 +511,52 @@ u32 skb_get_poff(const struct sk_buff *skb) { struct flow_keys keys; - if (!skb_flow_dissect(skb, &keys)) + if (!skb_flow_dissect_flow_keys(skb, &keys)) return 0; return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb)); } + +static const struct flow_dissector_key flow_keys_dissector_keys[] = { + { + .key_id = FLOW_DISSECTOR_KEY_BASIC, + .offset = offsetof(struct flow_keys, basic), + }, + { + .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS, + .offset = offsetof(struct flow_keys, addrs), + }, + { + .key_id = FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, + .offset = offsetof(struct flow_keys, addrs), + }, + { + .key_id = FLOW_DISSECTOR_KEY_PORTS, + .offset = offsetof(struct flow_keys, ports), + }, +}; + +static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = { + { + .key_id = FLOW_DISSECTOR_KEY_BASIC, + .offset = offsetof(struct flow_keys, basic), + }, +}; + +struct flow_dissector flow_keys_dissector __read_mostly; +EXPORT_SYMBOL(flow_keys_dissector); + +struct flow_dissector flow_keys_buf_dissector __read_mostly; + +static int __init init_default_flow_dissectors(void) +{ + skb_flow_dissector_init(&flow_keys_dissector, + flow_keys_dissector_keys, + ARRAY_SIZE(flow_keys_dissector_keys)); + skb_flow_dissector_init(&flow_keys_buf_dissector, + flow_keys_buf_dissector_keys, + ARRAY_SIZE(flow_keys_buf_dissector_keys)); + return 0; +} + +late_initcall_sync(init_default_flow_dissectors); diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 9332a0ab0698..c3325bd2f3fb 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -131,9 +131,9 @@ u32 eth_get_headlen(void *data, unsigned int len) return len; /* parse any remaining L2/L3 headers, check for L4 */ - if (!__skb_flow_dissect(NULL, &keys, data, - eth->h_proto, sizeof(*eth), len)) - return max_t(u32, keys.thoff, sizeof(*eth)); + if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto, + sizeof(*eth), len)) + return max_t(u32, keys.basic.thoff, sizeof(*eth)); /* parse for any L4 headers */ return min_t(u32, __skb_get_poff(NULL, data, &keys, len), len); diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 4c5a92298906..4b3e3e30bf4d 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -68,35 +68,35 @@ static inline u32 addr_fold(void *addr) static u32 flow_get_src(const struct sk_buff *skb, const struct flow_keys *flow) { - if (flow->src) - return ntohl(flow->src); + if (flow->addrs.src) + return ntohl(flow->addrs.src); return addr_fold(skb->sk); } static u32 flow_get_dst(const struct sk_buff *skb, const struct flow_keys *flow) { - if (flow->dst) - return ntohl(flow->dst); + if (flow->addrs.dst) + return ntohl(flow->addrs.dst); return addr_fold(skb_dst(skb)) ^ (__force u16) tc_skb_protocol(skb); } static u32 flow_get_proto(const struct sk_buff *skb, const struct flow_keys *flow) { - return flow->ip_proto; + return flow->basic.ip_proto; } static u32 flow_get_proto_src(const struct sk_buff *skb, const struct flow_keys *flow) { - if (flow->ports) - return ntohs(flow->port16[0]); + if (flow->ports.ports) + return ntohs(flow->ports.port16[0]); return addr_fold(skb->sk); } static u32 flow_get_proto_dst(const struct sk_buff *skb, const struct flow_keys *flow) { - if (flow->ports) - return ntohs(flow->port16[1]); + if (flow->ports.ports) + return ntohs(flow->ports.port16[1]); return addr_fold(skb_dst(skb)) ^ (__force u16) tc_skb_protocol(skb); } @@ -295,7 +295,7 @@ static int flow_classify(struct sk_buff *skb, const struct tcf_proto *tp, keymask = f->keymask; if (keymask & FLOW_KEYS_NEEDED) - skb_flow_dissect(skb, &flow_keys); + skb_flow_dissect_flow_keys(skb, &flow_keys); for (n = 0; n < f->nkeys; n++) { key = ffs(keymask) - 1; diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index 2624e991a2d1..93d5742dc7e0 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -170,13 +170,13 @@ static bool choke_match_flow(struct sk_buff *skb1, if (!choke_skb_cb(skb1)->keys_valid) { choke_skb_cb(skb1)->keys_valid = 1; - skb_flow_dissect(skb1, &temp); + skb_flow_dissect_flow_keys(skb1, &temp); make_flow_keys_digest(&choke_skb_cb(skb1)->keys, &temp); } if (!choke_skb_cb(skb2)->keys_valid) { choke_skb_cb(skb2)->keys_valid = 1; - skb_flow_dissect(skb2, &temp); + skb_flow_dissect_flow_keys(skb2, &temp); make_flow_keys_digest(&choke_skb_cb(skb2)->keys, &temp); } -- cgit v1.2.3 From c3f8eaeb6ea501bd0e2e424f5dfecf952b12a06f Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 May 2015 14:56:17 +0200 Subject: flow_dissector: add missing header includes Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 0c8d406fb730..1add8918a155 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -1,6 +1,9 @@ #ifndef _NET_FLOW_DISSECTOR_H #define _NET_FLOW_DISSECTOR_H +#include +#include + /** * struct flow_dissector_key_basic: * @thoff: Transport header offset -- cgit v1.2.3 From b924933cbbfbdcaa2831a39780c116ec6e48c397 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 May 2015 14:56:18 +0200 Subject: flow_dissector: introduce support for ipv6 addressses So far, only hashes made out of ipv6 addresses could be dissected. This patch introduces support for dissection of full ipv6 addresses. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 13 +++++++++++++ net/core/flow_dissector.c | 29 +++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 1add8918a155..586b12306a52 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -3,6 +3,7 @@ #include #include +#include /** * struct flow_dissector_key_basic: @@ -42,11 +43,23 @@ struct flow_dissector_key_ports { }; }; +/** + * struct flow_dissector_key_ipv6_addrs: + * @src: source ip address + * @dst: destination ip address + */ +struct flow_dissector_key_ipv6_addrs { + /* (src,dst) must be grouped, in the same way than in IP header */ + struct in6_addr src; + struct in6_addr dst; +}; + enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ FLOW_DISSECTOR_KEY_IPV4_ADDRS, /* struct flow_dissector_key_addrs */ FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, /* struct flow_dissector_key_addrs */ FLOW_DISSECTOR_KEY_PORTS, /* struct flow_dissector_key_ports */ + FLOW_DISSECTOR_KEY_IPV6_ADDRS, /* struct flow_dissector_key_ipv6_addrs */ FLOW_DISSECTOR_KEY_MAX, }; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 6a49acaa6651..1b95d5ccc9d6 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -175,16 +175,29 @@ ipv6: ip_proto = iph->nexthdr; nhoff += sizeof(struct ipv6hdr); - if (!skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS)) - break; - key_addrs = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, - target_container); + if (skb_flow_dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS)) { + key_addrs = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, + target_container); - key_addrs->src = (__force __be32)ipv6_addr_hash(&iph->saddr); - key_addrs->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); + key_addrs->src = (__force __be32)ipv6_addr_hash(&iph->saddr); + key_addrs->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); + goto flow_label; + } + if (skb_flow_dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_IPV6_ADDRS)) { + struct flow_dissector_key_ipv6_addrs *key_ipv6_addrs; + key_ipv6_addrs = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_IPV6_ADDRS, + target_container); + + memcpy(key_ipv6_addrs, &iph->saddr, sizeof(*key_ipv6_addrs)); + goto flow_label; + } + break; +flow_label: flow_label = ip6_flowlabel(iph); if (flow_label) { /* Awesome, IPv6 packet has a flow label so we can -- cgit v1.2.3 From 67a900cc0436d74e7ff89042371760def087680d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 May 2015 14:56:19 +0200 Subject: flow_dissector: introduce support for Ethernet addresses Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 13 +++++++++++++ net/core/flow_dissector.c | 12 ++++++++++++ 2 files changed, 25 insertions(+) (limited to 'include') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 586b12306a52..5eac9870689c 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -4,6 +4,7 @@ #include #include #include +#include /** * struct flow_dissector_key_basic: @@ -54,12 +55,24 @@ struct flow_dissector_key_ipv6_addrs { struct in6_addr dst; }; +/** + * struct flow_dissector_key_eth_addrs: + * @src: source Ethernet address + * @dst: destination Ethernet address + */ +struct flow_dissector_key_eth_addrs { + /* (dst,src) must be grouped, in the same way than in ETH header */ + unsigned char dst[ETH_ALEN]; + unsigned char src[ETH_ALEN]; +}; + enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ FLOW_DISSECTOR_KEY_IPV4_ADDRS, /* struct flow_dissector_key_addrs */ FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, /* struct flow_dissector_key_addrs */ FLOW_DISSECTOR_KEY_PORTS, /* struct flow_dissector_key_ports */ FLOW_DISSECTOR_KEY_IPV6_ADDRS, /* struct flow_dissector_key_ipv6_addrs */ + FLOW_DISSECTOR_KEY_ETH_ADDRS, /* struct flow_dissector_key_eth_addrs */ FLOW_DISSECTOR_KEY_MAX, }; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 1b95d5ccc9d6..7a0b391114a5 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -138,6 +139,17 @@ bool __skb_flow_dissect(const struct sk_buff *skb, FLOW_DISSECTOR_KEY_BASIC, target_container); + if (skb_flow_dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_ETH_ADDRS)) { + struct ethhdr *eth = eth_hdr(skb); + struct flow_dissector_key_eth_addrs *key_eth_addrs; + + key_eth_addrs = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_ETH_ADDRS, + target_container); + memcpy(key_eth_addrs, ð->h_dest, sizeof(*key_eth_addrs)); + } + again: switch (proto) { case htons(ETH_P_IP): { -- cgit v1.2.3 From 59346afe7a5548ab3e9730aeff33993faa76abbe Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 May 2015 14:56:20 +0200 Subject: flow_dissector: change port array into src, dst tuple Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_clsf.c | 4 ++-- drivers/net/ethernet/cisco/enic/enic_ethtool.c | 4 ++-- include/net/flow_dissector.h | 9 ++++++--- include/net/ip.h | 4 ++-- include/net/ipv6.h | 4 ++-- net/core/flow_dissector.c | 4 ++-- net/sched/cls_flow.c | 4 ++-- 7 files changed, 18 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index d3d25c7e5b96..6739ebc08c47 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -35,8 +35,8 @@ int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq) data.type = FILTER_IPV4_5TUPLE; data.u.ipv4.src_addr = ntohl(keys->addrs.src); data.u.ipv4.dst_addr = ntohl(keys->addrs.dst); - data.u.ipv4.src_port = ntohs(keys->ports.port16[0]); - data.u.ipv4.dst_port = ntohs(keys->ports.port16[1]); + data.u.ipv4.src_port = ntohs(keys->ports.src); + data.u.ipv4.dst_port = ntohs(keys->ports.dst); data.u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE; spin_lock_bh(&enic->devcmd_lock); diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c index 7588f8dcc890..117c0968dd0b 100644 --- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c +++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c @@ -352,10 +352,10 @@ static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd) fsp->h_u.tcp_ip4_spec.ip4dst = n->keys.addrs.dst; fsp->m_u.tcp_ip4_spec.ip4dst = (__u32)~0; - fsp->h_u.tcp_ip4_spec.psrc = n->keys.ports.port16[0]; + fsp->h_u.tcp_ip4_spec.psrc = n->keys.ports.src; fsp->m_u.tcp_ip4_spec.psrc = (__u16)~0; - fsp->h_u.tcp_ip4_spec.pdst = n->keys.ports.port16[1]; + fsp->h_u.tcp_ip4_spec.pdst = n->keys.ports.dst; fsp->m_u.tcp_ip4_spec.pdst = (__u16)~0; fsp->ring_cookie = n->rq_id; diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 5eac9870689c..bac9c1421f58 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -34,13 +34,16 @@ struct flow_dissector_key_addrs { /** * flow_dissector_key_tp_ports: * @ports: port numbers of Transport header - * port16[0]: src port number - * port16[1]: dst port number + * src: source port number + * dst: destination port number */ struct flow_dissector_key_ports { union { __be32 ports; - __be16 port16[2]; + struct { + __be16 src; + __be16 dst; + }; }; }; diff --git a/include/net/ip.h b/include/net/ip.h index b0443d4fe13f..0ed6d768e606 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -362,8 +362,8 @@ static inline void inet_set_txhash(struct sock *sk) keys.addrs.src = inet->inet_saddr; keys.addrs.dst = inet->inet_daddr; - keys.ports.port16[0] = inet->inet_sport; - keys.ports.port16[1] = inet->inet_dport; + keys.ports.src = inet->inet_sport; + keys.ports.dst = inet->inet_dport; sk->sk_txhash = flow_hash_from_keys(&keys); } diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 9eed9761dfce..aab8190d16e8 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -700,8 +700,8 @@ static inline void ip6_set_txhash(struct sock *sk) keys.addrs.src = (__force __be32)ipv6_addr_hash(&np->saddr); keys.addrs.dst = (__force __be32)ipv6_addr_hash(&sk->sk_v6_daddr); - keys.ports.port16[0] = inet->inet_sport; - keys.ports.port16[1] = inet->inet_dport; + keys.ports.src = inet->inet_sport; + keys.ports.dst = inet->inet_dport; sk->sk_txhash = flow_hash_from_keys(&keys); } diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 7a0b391114a5..204d09c42510 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -385,9 +385,9 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) /* get a consistent hash (same value on both flow directions) */ if (((__force u32)keys->addrs.dst < (__force u32)keys->addrs.src) || (((__force u32)keys->addrs.dst == (__force u32)keys->addrs.src) && - ((__force u16)keys->ports.port16[1] < (__force u16)keys->ports.port16[0]))) { + ((__force u16)keys->ports.dst < (__force u16)keys->ports.src))) { swap(keys->addrs.dst, keys->addrs.src); - swap(keys->ports.port16[0], keys->ports.port16[1]); + swap(keys->ports.src, keys->ports.dst); } hash = __flow_hash_3words((__force u32)keys->addrs.dst, diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 4b3e3e30bf4d..b4359924846c 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -88,7 +88,7 @@ static u32 flow_get_proto(const struct sk_buff *skb, const struct flow_keys *flo static u32 flow_get_proto_src(const struct sk_buff *skb, const struct flow_keys *flow) { if (flow->ports.ports) - return ntohs(flow->ports.port16[0]); + return ntohs(flow->ports.src); return addr_fold(skb->sk); } @@ -96,7 +96,7 @@ static u32 flow_get_proto_src(const struct sk_buff *skb, const struct flow_keys static u32 flow_get_proto_dst(const struct sk_buff *skb, const struct flow_keys *flow) { if (flow->ports.ports) - return ntohs(flow->ports.port16[1]); + return ntohs(flow->ports.dst); return addr_fold(skb_dst(skb)) ^ (__force u16) tc_skb_protocol(skb); } -- cgit v1.2.3 From 77b9900ef53ae047e36a37d13a2aa33bb2d60641 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 12 May 2015 14:56:21 +0200 Subject: tc: introduce Flower classifier This patch introduces a flow-based filter. So far, the very essential packet fields are supported. This patch is only the first step. There is a lot of potential performance improvements possible to implement. Also a lot of features are missing now. They will be addressed in follow-up patches. Signed-off-by: Jiri Pirko Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/uapi/linux/pkt_cls.h | 30 ++ net/sched/Kconfig | 10 + net/sched/Makefile | 1 + net/sched/cls_flower.c | 688 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 729 insertions(+) create mode 100644 net/sched/cls_flower.c (limited to 'include') diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index ffc112c8e1c2..39fb53d67b11 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -409,6 +409,36 @@ enum { #define TCA_BPF_MAX (__TCA_BPF_MAX - 1) +/* Flower classifier */ + +enum { + TCA_FLOWER_UNSPEC, + TCA_FLOWER_CLASSID, + TCA_FLOWER_INDEV, + TCA_FLOWER_ACT, + TCA_FLOWER_KEY_ETH_DST, /* ETH_ALEN */ + TCA_FLOWER_KEY_ETH_DST_MASK, /* ETH_ALEN */ + TCA_FLOWER_KEY_ETH_SRC, /* ETH_ALEN */ + TCA_FLOWER_KEY_ETH_SRC_MASK, /* ETH_ALEN */ + TCA_FLOWER_KEY_ETH_TYPE, /* be16 */ + TCA_FLOWER_KEY_IP_PROTO, /* u8 */ + TCA_FLOWER_KEY_IPV4_SRC, /* be32 */ + TCA_FLOWER_KEY_IPV4_SRC_MASK, /* be32 */ + TCA_FLOWER_KEY_IPV4_DST, /* be32 */ + TCA_FLOWER_KEY_IPV4_DST_MASK, /* be32 */ + TCA_FLOWER_KEY_IPV6_SRC, /* struct in6_addr */ + TCA_FLOWER_KEY_IPV6_SRC_MASK, /* struct in6_addr */ + TCA_FLOWER_KEY_IPV6_DST, /* struct in6_addr */ + TCA_FLOWER_KEY_IPV6_DST_MASK, /* struct in6_addr */ + TCA_FLOWER_KEY_TCP_SRC, /* be16 */ + TCA_FLOWER_KEY_TCP_DST, /* be16 */ + TCA_FLOWER_KEY_UDP_SRC, /* be16 */ + TCA_FLOWER_KEY_UDP_DST, /* be16 */ + __TCA_FLOWER_MAX, +}; + +#define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) + /* Extended Matches */ struct tcf_ematch_tree_hdr { diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 2274e723a3df..5fd1c2f487d2 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -477,6 +477,16 @@ config NET_CLS_BPF To compile this code as a module, choose M here: the module will be called cls_bpf. +config NET_CLS_FLOWER + tristate "Flower classifier" + select NET_CLS + ---help--- + If you say Y here, you will be able to classify packets based on + a configurable combination of packet keys and masks. + + To compile this code as a module, choose M here: the module will + be called cls_flower. + config NET_EMATCH bool "Extended Matches" select NET_CLS diff --git a/net/sched/Makefile b/net/sched/Makefile index 7ca7f4c1b8c2..690c1689e090 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_NET_CLS_BASIC) += cls_basic.o obj-$(CONFIG_NET_CLS_FLOW) += cls_flow.o obj-$(CONFIG_NET_CLS_CGROUP) += cls_cgroup.o obj-$(CONFIG_NET_CLS_BPF) += cls_bpf.o +obj-$(CONFIG_NET_CLS_FLOWER) += cls_flower.o obj-$(CONFIG_NET_EMATCH) += ematch.o obj-$(CONFIG_NET_EMATCH_CMP) += em_cmp.o obj-$(CONFIG_NET_EMATCH_NBYTE) += em_nbyte.o diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c new file mode 100644 index 000000000000..9bc654c764cd --- /dev/null +++ b/net/sched/cls_flower.c @@ -0,0 +1,688 @@ +/* + * net/sched/cls_flower.c Flower classifier + * + * Copyright (c) 2015 Jiri Pirko + * + * 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. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +struct fl_flow_key { + int indev_ifindex; + struct flow_dissector_key_basic basic; + struct flow_dissector_key_eth_addrs eth; + union { + struct flow_dissector_key_addrs ipv4; + struct flow_dissector_key_ipv6_addrs ipv6; + }; + struct flow_dissector_key_ports tp; +} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */ + +struct fl_flow_mask_range { + unsigned short int start; + unsigned short int end; +}; + +struct fl_flow_mask { + struct fl_flow_key key; + struct fl_flow_mask_range range; + struct rcu_head rcu; +}; + +struct cls_fl_head { + struct rhashtable ht; + struct fl_flow_mask mask; + struct flow_dissector dissector; + u32 hgen; + bool mask_assigned; + struct list_head filters; + struct rhashtable_params ht_params; + struct rcu_head rcu; +}; + +struct cls_fl_filter { + struct rhash_head ht_node; + struct fl_flow_key mkey; + struct tcf_exts exts; + struct tcf_result res; + struct fl_flow_key key; + struct list_head list; + u32 handle; + struct rcu_head rcu; +}; + +static unsigned short int fl_mask_range(const struct fl_flow_mask *mask) +{ + return mask->range.end - mask->range.start; +} + +static void fl_mask_update_range(struct fl_flow_mask *mask) +{ + const u8 *bytes = (const u8 *) &mask->key; + size_t size = sizeof(mask->key); + size_t i, first = 0, last = size - 1; + + for (i = 0; i < sizeof(mask->key); i++) { + if (bytes[i]) { + if (!first && i) + first = i; + last = i; + } + } + mask->range.start = rounddown(first, sizeof(long)); + mask->range.end = roundup(last + 1, sizeof(long)); +} + +static void *fl_key_get_start(struct fl_flow_key *key, + const struct fl_flow_mask *mask) +{ + return (u8 *) key + mask->range.start; +} + +static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key, + struct fl_flow_mask *mask) +{ + const long *lkey = fl_key_get_start(key, mask); + const long *lmask = fl_key_get_start(&mask->key, mask); + long *lmkey = fl_key_get_start(mkey, mask); + int i; + + for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) + *lmkey++ = *lkey++ & *lmask++; +} + +static void fl_clear_masked_range(struct fl_flow_key *key, + struct fl_flow_mask *mask) +{ + memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask)); +} + +static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp, + struct tcf_result *res) +{ + struct cls_fl_head *head = rcu_dereference_bh(tp->root); + struct cls_fl_filter *f; + struct fl_flow_key skb_key; + struct fl_flow_key skb_mkey; + + fl_clear_masked_range(&skb_key, &head->mask); + skb_key.indev_ifindex = skb->skb_iif; + /* skb_flow_dissect() does not set n_proto in case an unknown protocol, + * so do it rather here. + */ + skb_key.basic.n_proto = skb->protocol; + skb_flow_dissect(skb, &head->dissector, &skb_key); + + fl_set_masked_key(&skb_mkey, &skb_key, &head->mask); + + f = rhashtable_lookup_fast(&head->ht, + fl_key_get_start(&skb_mkey, &head->mask), + head->ht_params); + if (f) { + *res = f->res; + return tcf_exts_exec(skb, &f->exts, res); + } + return -1; +} + +static int fl_init(struct tcf_proto *tp) +{ + struct cls_fl_head *head; + + head = kzalloc(sizeof(*head), GFP_KERNEL); + if (!head) + return -ENOBUFS; + + INIT_LIST_HEAD_RCU(&head->filters); + rcu_assign_pointer(tp->root, head); + + return 0; +} + +static void fl_destroy_filter(struct rcu_head *head) +{ + struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu); + + tcf_exts_destroy(&f->exts); + kfree(f); +} + +static bool fl_destroy(struct tcf_proto *tp, bool force) +{ + struct cls_fl_head *head = rtnl_dereference(tp->root); + struct cls_fl_filter *f, *next; + + if (!force && !list_empty(&head->filters)) + return false; + + list_for_each_entry_safe(f, next, &head->filters, list) { + list_del_rcu(&f->list); + call_rcu(&f->rcu, fl_destroy_filter); + } + RCU_INIT_POINTER(tp->root, NULL); + if (head->mask_assigned) + rhashtable_destroy(&head->ht); + kfree_rcu(head, rcu); + return true; +} + +static unsigned long fl_get(struct tcf_proto *tp, u32 handle) +{ + struct cls_fl_head *head = rtnl_dereference(tp->root); + struct cls_fl_filter *f; + + list_for_each_entry(f, &head->filters, list) + if (f->handle == handle) + return (unsigned long) f; + return 0; +} + +static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { + [TCA_FLOWER_UNSPEC] = { .type = NLA_UNSPEC }, + [TCA_FLOWER_CLASSID] = { .type = NLA_U32 }, + [TCA_FLOWER_INDEV] = { .type = NLA_STRING, + .len = IFNAMSIZ }, + [TCA_FLOWER_KEY_ETH_DST] = { .len = ETH_ALEN }, + [TCA_FLOWER_KEY_ETH_DST_MASK] = { .len = ETH_ALEN }, + [TCA_FLOWER_KEY_ETH_SRC] = { .len = ETH_ALEN }, + [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .len = ETH_ALEN }, + [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NLA_U16 }, + [TCA_FLOWER_KEY_IP_PROTO] = { .type = NLA_U8 }, + [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NLA_U32 }, + [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 }, + [TCA_FLOWER_KEY_IPV4_DST] = { .type = NLA_U32 }, + [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NLA_U32 }, + [TCA_FLOWER_KEY_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, + [TCA_FLOWER_KEY_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) }, + [TCA_FLOWER_KEY_IPV6_DST] = { .len = sizeof(struct in6_addr) }, + [TCA_FLOWER_KEY_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) }, + [TCA_FLOWER_KEY_TCP_SRC] = { .type = NLA_U16 }, + [TCA_FLOWER_KEY_TCP_DST] = { .type = NLA_U16 }, + [TCA_FLOWER_KEY_TCP_SRC] = { .type = NLA_U16 }, + [TCA_FLOWER_KEY_TCP_DST] = { .type = NLA_U16 }, +}; + +static void fl_set_key_val(struct nlattr **tb, + void *val, int val_type, + void *mask, int mask_type, int len) +{ + if (!tb[val_type]) + return; + memcpy(val, nla_data(tb[val_type]), len); + if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type]) + memset(mask, 0xff, len); + else + memcpy(mask, nla_data(tb[mask_type]), len); +} + +static int fl_set_key(struct net *net, struct nlattr **tb, + struct fl_flow_key *key, struct fl_flow_key *mask) +{ + int err; + + if (tb[TCA_FLOWER_INDEV]) { + err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV]); + if (err < 0) + return err; + key->indev_ifindex = err; + mask->indev_ifindex = 0xffffffff; + } + + fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, + mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, + sizeof(key->eth.dst)); + fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, + mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, + sizeof(key->eth.src)); + fl_set_key_val(tb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE, + &mask->basic.n_proto, TCA_FLOWER_UNSPEC, + sizeof(key->basic.n_proto)); + if (key->basic.n_proto == htons(ETH_P_IP) || + key->basic.n_proto == htons(ETH_P_IPV6)) { + fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, + &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, + sizeof(key->basic.ip_proto)); + } + if (key->basic.n_proto == htons(ETH_P_IP)) { + fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, + &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, + sizeof(key->ipv4.src)); + fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, + &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, + sizeof(key->ipv4.dst)); + } else if (key->basic.n_proto == htons(ETH_P_IPV6)) { + fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, + &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, + sizeof(key->ipv6.src)); + fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, + &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, + sizeof(key->ipv6.dst)); + } + if (key->basic.ip_proto == IPPROTO_TCP) { + fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, + &mask->tp.src, TCA_FLOWER_UNSPEC, + sizeof(key->tp.src)); + fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, + &mask->tp.dst, TCA_FLOWER_UNSPEC, + sizeof(key->tp.dst)); + } else if (key->basic.ip_proto == IPPROTO_UDP) { + fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, + &mask->tp.src, TCA_FLOWER_UNSPEC, + sizeof(key->tp.src)); + fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, + &mask->tp.dst, TCA_FLOWER_UNSPEC, + sizeof(key->tp.dst)); + } + + return 0; +} + +static bool fl_mask_eq(struct fl_flow_mask *mask1, + struct fl_flow_mask *mask2) +{ + const long *lmask1 = fl_key_get_start(&mask1->key, mask1); + const long *lmask2 = fl_key_get_start(&mask2->key, mask2); + + return !memcmp(&mask1->range, &mask2->range, sizeof(mask1->range)) && + !memcmp(lmask1, lmask2, fl_mask_range(mask1)); +} + +static const struct rhashtable_params fl_ht_params = { + .key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */ + .head_offset = offsetof(struct cls_fl_filter, ht_node), + .automatic_shrinking = true, +}; + +static int fl_init_hashtable(struct cls_fl_head *head, + struct fl_flow_mask *mask) +{ + head->ht_params = fl_ht_params; + head->ht_params.key_len = fl_mask_range(mask); + head->ht_params.key_offset += mask->range.start; + + return rhashtable_init(&head->ht, &head->ht_params); +} + +#define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member) +#define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member)) +#define FL_KEY_MEMBER_END_OFFSET(member) \ + (FL_KEY_MEMBER_OFFSET(member) + FL_KEY_MEMBER_SIZE(member)) + +#define FL_KEY_IN_RANGE(mask, member) \ + (FL_KEY_MEMBER_OFFSET(member) <= (mask)->range.end && \ + FL_KEY_MEMBER_END_OFFSET(member) >= (mask)->range.start) + +#define FL_KEY_SET(keys, cnt, id, member) \ + do { \ + keys[cnt].key_id = id; \ + keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member); \ + cnt++; \ + } while(0); + +#define FL_KEY_SET_IF_IN_RANGE(mask, keys, cnt, id, member) \ + do { \ + if (FL_KEY_IN_RANGE(mask, member)) \ + FL_KEY_SET(keys, cnt, id, member); \ + } while(0); + +static void fl_init_dissector(struct cls_fl_head *head, + struct fl_flow_mask *mask) +{ + struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX]; + size_t cnt = 0; + + FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic); + FL_KEY_SET_IF_IN_RANGE(mask, keys, cnt, + FLOW_DISSECTOR_KEY_ETH_ADDRS, eth); + FL_KEY_SET_IF_IN_RANGE(mask, keys, cnt, + FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4); + FL_KEY_SET_IF_IN_RANGE(mask, keys, cnt, + FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6); + FL_KEY_SET_IF_IN_RANGE(mask, keys, cnt, + FLOW_DISSECTOR_KEY_PORTS, tp); + + skb_flow_dissector_init(&head->dissector, keys, cnt); +} + +static int fl_check_assign_mask(struct cls_fl_head *head, + struct fl_flow_mask *mask) +{ + int err; + + if (head->mask_assigned) { + if (!fl_mask_eq(&head->mask, mask)) + return -EINVAL; + else + return 0; + } + + /* Mask is not assigned yet. So assign it and init hashtable + * according to that. + */ + err = fl_init_hashtable(head, mask); + if (err) + return err; + memcpy(&head->mask, mask, sizeof(head->mask)); + head->mask_assigned = true; + + fl_init_dissector(head, mask); + + return 0; +} + +static int fl_set_parms(struct net *net, struct tcf_proto *tp, + struct cls_fl_filter *f, struct fl_flow_mask *mask, + unsigned long base, struct nlattr **tb, + struct nlattr *est, bool ovr) +{ + struct tcf_exts e; + int err; + + tcf_exts_init(&e, TCA_FLOWER_ACT, 0); + err = tcf_exts_validate(net, tp, tb, est, &e, ovr); + if (err < 0) + return err; + + if (tb[TCA_FLOWER_CLASSID]) { + f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]); + tcf_bind_filter(tp, &f->res, base); + } + + err = fl_set_key(net, tb, &f->key, &mask->key); + if (err) + goto errout; + + fl_mask_update_range(mask); + fl_set_masked_key(&f->mkey, &f->key, mask); + + tcf_exts_change(tp, &f->exts, &e); + + return 0; +errout: + tcf_exts_destroy(&e); + return err; +} + +static u32 fl_grab_new_handle(struct tcf_proto *tp, + struct cls_fl_head *head) +{ + unsigned int i = 0x80000000; + u32 handle; + + do { + if (++head->hgen == 0x7FFFFFFF) + head->hgen = 1; + } while (--i > 0 && fl_get(tp, head->hgen)); + + if (unlikely(i == 0)) { + pr_err("Insufficient number of handles\n"); + handle = 0; + } else { + handle = head->hgen; + } + + return handle; +} + +static int fl_change(struct net *net, struct sk_buff *in_skb, + struct tcf_proto *tp, unsigned long base, + u32 handle, struct nlattr **tca, + unsigned long *arg, bool ovr) +{ + struct cls_fl_head *head = rtnl_dereference(tp->root); + struct cls_fl_filter *fold = (struct cls_fl_filter *) *arg; + struct cls_fl_filter *fnew; + struct nlattr *tb[TCA_FLOWER_MAX + 1]; + struct fl_flow_mask mask = {}; + int err; + + if (!tca[TCA_OPTIONS]) + return -EINVAL; + + err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], fl_policy); + if (err < 0) + return err; + + if (fold && handle && fold->handle != handle) + return -EINVAL; + + fnew = kzalloc(sizeof(*fnew), GFP_KERNEL); + if (!fnew) + return -ENOBUFS; + + tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0); + + if (!handle) { + handle = fl_grab_new_handle(tp, head); + if (!handle) { + err = -EINVAL; + goto errout; + } + } + fnew->handle = handle; + + err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr); + if (err) + goto errout; + + err = fl_check_assign_mask(head, &mask); + if (err) + goto errout; + + err = rhashtable_insert_fast(&head->ht, &fnew->ht_node, + head->ht_params); + if (err) + goto errout; + if (fold) + rhashtable_remove_fast(&head->ht, &fold->ht_node, + head->ht_params); + + *arg = (unsigned long) fnew; + + if (fold) { + list_replace_rcu(&fnew->list, &fold->list); + tcf_unbind_filter(tp, &fold->res); + call_rcu(&fold->rcu, fl_destroy_filter); + } else { + list_add_tail_rcu(&fnew->list, &head->filters); + } + + return 0; + +errout: + kfree(fnew); + return err; +} + +static int fl_delete(struct tcf_proto *tp, unsigned long arg) +{ + struct cls_fl_head *head = rtnl_dereference(tp->root); + struct cls_fl_filter *f = (struct cls_fl_filter *) arg; + + rhashtable_remove_fast(&head->ht, &f->ht_node, + head->ht_params); + list_del_rcu(&f->list); + tcf_unbind_filter(tp, &f->res); + call_rcu(&f->rcu, fl_destroy_filter); + return 0; +} + +static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg) +{ + struct cls_fl_head *head = rtnl_dereference(tp->root); + struct cls_fl_filter *f; + + list_for_each_entry_rcu(f, &head->filters, list) { + if (arg->count < arg->skip) + goto skip; + if (arg->fn(tp, (unsigned long) f, arg) < 0) { + arg->stop = 1; + break; + } +skip: + arg->count++; + } +} + +static int fl_dump_key_val(struct sk_buff *skb, + void *val, int val_type, + void *mask, int mask_type, int len) +{ + int err; + + if (!memchr_inv(mask, 0, len)) + return 0; + err = nla_put(skb, val_type, len, val); + if (err) + return err; + if (mask_type != TCA_FLOWER_UNSPEC) { + err = nla_put(skb, mask_type, len, mask); + if (err) + return err; + } + return 0; +} + +static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, + struct sk_buff *skb, struct tcmsg *t) +{ + struct cls_fl_head *head = rtnl_dereference(tp->root); + struct cls_fl_filter *f = (struct cls_fl_filter *) fh; + struct nlattr *nest; + struct fl_flow_key *key, *mask; + + if (!f) + return skb->len; + + t->tcm_handle = f->handle; + + nest = nla_nest_start(skb, TCA_OPTIONS); + if (!nest) + goto nla_put_failure; + + if (f->res.classid && + nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid)) + goto nla_put_failure; + + key = &f->key; + mask = &head->mask.key; + + if (mask->indev_ifindex) { + struct net_device *dev; + + dev = __dev_get_by_index(net, key->indev_ifindex); + if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name)) + goto nla_put_failure; + } + + if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, + mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, + sizeof(key->eth.dst)) || + fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC, + mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK, + sizeof(key->eth.src)) || + fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE, + &mask->basic.n_proto, TCA_FLOWER_UNSPEC, + sizeof(key->basic.n_proto))) + goto nla_put_failure; + if ((key->basic.n_proto == htons(ETH_P_IP) || + key->basic.n_proto == htons(ETH_P_IPV6)) && + fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO, + &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, + sizeof(key->basic.ip_proto))) + goto nla_put_failure; + + if (key->basic.n_proto == htons(ETH_P_IP) && + (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, + &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, + sizeof(key->ipv4.src)) || + fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, + &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, + sizeof(key->ipv4.dst)))) + goto nla_put_failure; + else if (key->basic.n_proto == htons(ETH_P_IPV6) && + (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, + &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, + sizeof(key->ipv6.src)) || + fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST, + &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK, + sizeof(key->ipv6.dst)))) + goto nla_put_failure; + + if (key->basic.ip_proto == IPPROTO_TCP && + (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC, + &mask->tp.src, TCA_FLOWER_UNSPEC, + sizeof(key->tp.src)) || + fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST, + &mask->tp.dst, TCA_FLOWER_UNSPEC, + sizeof(key->tp.dst)))) + goto nla_put_failure; + else if (key->basic.ip_proto == IPPROTO_UDP && + (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC, + &mask->tp.src, TCA_FLOWER_UNSPEC, + sizeof(key->tp.src)) || + fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST, + &mask->tp.dst, TCA_FLOWER_UNSPEC, + sizeof(key->tp.dst)))) + goto nla_put_failure; + + if (tcf_exts_dump(skb, &f->exts)) + goto nla_put_failure; + + nla_nest_end(skb, nest); + + if (tcf_exts_dump_stats(skb, &f->exts) < 0) + goto nla_put_failure; + + return skb->len; + +nla_put_failure: + nla_nest_cancel(skb, nest); + return -1; +} + +static struct tcf_proto_ops cls_fl_ops __read_mostly = { + .kind = "flower", + .classify = fl_classify, + .init = fl_init, + .destroy = fl_destroy, + .get = fl_get, + .change = fl_change, + .delete = fl_delete, + .walk = fl_walk, + .dump = fl_dump, + .owner = THIS_MODULE, +}; + +static int __init cls_fl_init(void) +{ + return register_tcf_proto_ops(&cls_fl_ops); +} + +static void __exit cls_fl_exit(void) +{ + unregister_tcf_proto_ops(&cls_fl_ops); +} + +module_init(cls_fl_init); +module_exit(cls_fl_exit); + +MODULE_AUTHOR("Jiri Pirko "); +MODULE_DESCRIPTION("Flower classifier"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From a9b6391814d5d6b8668fca2dace86949b7244e2e Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Tue, 12 May 2015 11:56:50 -0400 Subject: packet: rollover statistics Rollover indicates exceptional conditions. Export a counter to inform socket owners of this state. If no socket with sufficient room is found, rollover fails. Also count these events. Finally, also count when flows are rolled over early thanks to huge flow detection, to validate its correctness. Tested: Read counters in bench_rollover on all other tests in the patchset Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- include/uapi/linux/if_packet.h | 7 +++++++ net/packet/af_packet.c | 19 ++++++++++++++++++- net/packet/internal.h | 3 +++ 3 files changed, 28 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h index 053bd102fbe0..d3d715f8c88f 100644 --- a/include/uapi/linux/if_packet.h +++ b/include/uapi/linux/if_packet.h @@ -54,6 +54,7 @@ struct sockaddr_ll { #define PACKET_FANOUT 18 #define PACKET_TX_HAS_OFF 19 #define PACKET_QDISC_BYPASS 20 +#define PACKET_ROLLOVER_STATS 21 #define PACKET_FANOUT_HASH 0 #define PACKET_FANOUT_LB 1 @@ -75,6 +76,12 @@ struct tpacket_stats_v3 { unsigned int tp_freeze_q_cnt; }; +struct tpacket_rollover_stats { + __aligned_u64 tp_all; + __aligned_u64 tp_huge; + __aligned_u64 tp_failed; +}; + union tpacket_stats_u { struct tpacket_stats stats1; struct tpacket_stats_v3 stats3; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 8f0156b10f8d..31d58565726c 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1395,7 +1395,7 @@ static unsigned int fanout_demux_rollover(struct packet_fanout *f, unsigned int num) { struct packet_sock *po, *po_next; - unsigned int i, j, room; + unsigned int i, j, room = ROOM_NONE; po = pkt_sk(f->arr[idx]); @@ -1413,6 +1413,9 @@ static unsigned int fanout_demux_rollover(struct packet_fanout *f, packet_rcv_has_room(po_next, skb) == ROOM_NORMAL) { if (i != j) po->rollover->sock = i; + atomic_long_inc(&po->rollover->num); + if (room == ROOM_LOW) + atomic_long_inc(&po->rollover->num_huge); return i; } @@ -1420,6 +1423,7 @@ static unsigned int fanout_demux_rollover(struct packet_fanout *f, i = 0; } while (i != j); + atomic_long_inc(&po->rollover->num_failed); return idx; } @@ -1554,6 +1558,9 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) po->rollover = kzalloc(sizeof(*po->rollover), GFP_KERNEL); if (!po->rollover) return -ENOMEM; + atomic_long_set(&po->rollover->num, 0); + atomic_long_set(&po->rollover->num_huge, 0); + atomic_long_set(&po->rollover->num_failed, 0); } mutex_lock(&fanout_mutex); @@ -3584,6 +3591,7 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, struct packet_sock *po = pkt_sk(sk); void *data = &val; union tpacket_stats_u st; + struct tpacket_rollover_stats rstats; if (level != SOL_PACKET) return -ENOPROTOOPT; @@ -3659,6 +3667,15 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, ((u32)po->fanout->flags << 24)) : 0); break; + case PACKET_ROLLOVER_STATS: + if (!po->rollover) + return -EINVAL; + rstats.tp_all = atomic_long_read(&po->rollover->num); + rstats.tp_huge = atomic_long_read(&po->rollover->num_huge); + rstats.tp_failed = atomic_long_read(&po->rollover->num_failed); + data = &rstats; + lv = sizeof(rstats); + break; case PACKET_TX_HAS_OFF: val = po->tp_tx_has_off; break; diff --git a/net/packet/internal.h b/net/packet/internal.h index a9d30a17c714..c035d263c1e8 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -89,6 +89,9 @@ struct packet_fanout { struct packet_rollover { int sock; + atomic_long_t num; + atomic_long_t num_huge; + atomic_long_t num_failed; #define ROLLOVER_HLEN (L1_CACHE_BYTES / sizeof(u32)) u32 history[ROLLOVER_HLEN] ____cacheline_aligned; } ____cacheline_aligned_in_smp; -- cgit v1.2.3 From f0b5e8a42f37a880b8467e59dc814f4f21581d3d Mon Sep 17 00:00:00 2001 From: Pablo Neira Date: Tue, 12 May 2015 20:28:07 +0200 Subject: net: kill useless net_*_ingress_queue() definitions when NET_CLS_ACT is unset This fixes 4577139b2dabf589 ("net: use jump label patching for ingress qdisc in __netif_receive_skb_core"). The only client of this is sch_ingress and it depends on NET_CLS_ACT. So there is no way these definition can be of any help. Cc: Daniel Borkmann Signed-off-by: Pablo Neira Ayuso Acked-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 8 -------- 1 file changed, 8 deletions(-) (limited to 'include') diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 7b8e260c4a27..bd29ab4b0941 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -82,14 +82,6 @@ struct netdev_queue *dev_ingress_queue_create(struct net_device *dev); #ifdef CONFIG_NET_CLS_ACT void net_inc_ingress_queue(void); void net_dec_ingress_queue(void); -#else -static inline void net_inc_ingress_queue(void) -{ -} - -static inline void net_dec_ingress_queue(void) -{ -} #endif extern void rtnetlink_init(void); -- cgit v1.2.3 From 35d32e8fe4ab44180e46a0dd54abea6985398d00 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 13 May 2015 12:57:27 -0400 Subject: geneve: move definition of geneve_hdr() to geneve.h This is a static inline with identical definitions in multiple places... Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- include/net/geneve.h | 5 +++++ net/ipv4/geneve.c | 5 ----- net/openvswitch/vport-geneve.c | 5 ----- 3 files changed, 5 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/net/geneve.h b/include/net/geneve.h index 14fb8d3390b4..2a0543a1899d 100644 --- a/include/net/geneve.h +++ b/include/net/geneve.h @@ -62,6 +62,11 @@ struct genevehdr { struct geneve_opt options[]; }; +static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb) +{ + return (struct genevehdr *)(udp_hdr(skb) + 1); +} + #ifdef CONFIG_INET struct geneve_sock; diff --git a/net/ipv4/geneve.c b/net/ipv4/geneve.c index 8e6a7fe27a4c..001843d41135 100644 --- a/net/ipv4/geneve.c +++ b/net/ipv4/geneve.c @@ -60,11 +60,6 @@ struct geneve_net { static int geneve_net_id; -static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb) -{ - return (struct genevehdr *)(udp_hdr(skb) + 1); -} - static struct geneve_sock *geneve_find_sock(struct net *net, sa_family_t family, __be16 port) { diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c index bf02fd5808c9..208c576bd1b6 100644 --- a/net/openvswitch/vport-geneve.c +++ b/net/openvswitch/vport-geneve.c @@ -46,11 +46,6 @@ static inline struct geneve_port *geneve_vport(const struct vport *vport) return vport_priv(vport); } -static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb) -{ - return (struct genevehdr *)(udp_hdr(skb) + 1); -} - /* Convert 64 bit tunnel ID to 24 bit VNI. */ static void tunnel_id_to_vni(__be64 tun_id, __u8 *vni) { -- cgit v1.2.3 From 2d07dc79fe04a43d82a346ced6bbf07bdb523f1b Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 13 May 2015 12:57:30 -0400 Subject: geneve: add initial netdev driver for GENEVE tunnels This is an initial implementation of a netdev driver for GENEVE tunnels. This implementation uses a fixed UDP port, and only supports point-to-point links with specific partner endpoints. Only IPv4 links are supported at this time. Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/Kconfig | 14 ++ drivers/net/Makefile | 1 + drivers/net/geneve.c | 503 +++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/if_link.h | 9 + 4 files changed, 527 insertions(+) create mode 100644 drivers/net/geneve.c (limited to 'include') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index df51d6025a90..019fceffc9e5 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -179,6 +179,20 @@ config VXLAN To compile this driver as a module, choose M here: the module will be called vxlan. +config GENEVE + tristate "Generic Network Virtualization Encapsulation netdev" + depends on INET && GENEVE_CORE + select NET_IP_TUNNEL + ---help--- + This allows one to create geneve virtual interfaces that provide + Layer 2 Networks over Layer 3 Networks. GENEVE is often used + to tunnel virtual network infrastructure in virtualized environments. + For more information see: + http://tools.ietf.org/html/draft-gross-geneve-02 + + To compile this driver as a module, choose M here: the module + will be called geneve. + config NETCONSOLE tristate "Network console logging support" ---help--- diff --git a/drivers/net/Makefile b/drivers/net/Makefile index e25fdd7d905e..c12cb22478a7 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_TUN) += tun.o obj-$(CONFIG_VETH) += veth.o obj-$(CONFIG_VIRTIO_NET) += virtio_net.o obj-$(CONFIG_VXLAN) += vxlan.o +obj-$(CONFIG_GENEVE) += geneve.o obj-$(CONFIG_NLMON) += nlmon.o # diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c new file mode 100644 index 000000000000..b7eafa4c1a67 --- /dev/null +++ b/drivers/net/geneve.c @@ -0,0 +1,503 @@ +/* + * GENEVE: Generic Network Virtualization Encapsulation + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#define GENEVE_NETDEV_VER "0.6" + +#define GENEVE_UDP_PORT 6081 + +#define GENEVE_N_VID (1u << 24) +#define GENEVE_VID_MASK (GENEVE_N_VID - 1) + +#define VNI_HASH_BITS 10 +#define VNI_HASH_SIZE (1<rcv_data; + + /* Find the device for this VNI */ + hash = geneve_net_vni_hash(gnvh->vni); + vni_list_head = &gn->vni_list[hash]; + hlist_for_each_entry_rcu(dummy, vni_list_head, hlist) { + if (!memcmp(gnvh->vni, dummy->vni, sizeof(dummy->vni)) && + iph->saddr == dummy->remote.sin_addr.s_addr) { + geneve = dummy; + break; + } + } + if (!geneve) + goto drop; + + /* Drop packets w/ critical options, + * since we don't support any... + */ + if (gnvh->critical) + goto drop; + + skb_reset_mac_header(skb); + skb_scrub_packet(skb, !net_eq(geneve->net, dev_net(geneve->dev))); + skb->protocol = eth_type_trans(skb, geneve->dev); + skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); + + /* Ignore packet loops (and multicast echo) */ + if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) + goto drop; + + skb_reset_network_header(skb); + + iph = ip_hdr(skb); /* Now inner IP header... */ + err = IP_ECN_decapsulate(iph, skb); + + if (unlikely(err)) { + if (log_ecn_error) + net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n", + &iph->saddr, iph->tos); + if (err > 1) { + ++geneve->dev->stats.rx_frame_errors; + ++geneve->dev->stats.rx_errors; + goto drop; + } + } + + stats = this_cpu_ptr(geneve->dev->tstats); + u64_stats_update_begin(&stats->syncp); + stats->rx_packets++; + stats->rx_bytes += skb->len; + u64_stats_update_end(&stats->syncp); + + netif_rx(skb); + + return; +drop: + /* Consume bad packet */ + kfree_skb(skb); +} + +/* Setup stats when device is created */ +static int geneve_init(struct net_device *dev) +{ + dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); + if (!dev->tstats) + return -ENOMEM; + + return 0; +} + +static void geneve_uninit(struct net_device *dev) +{ + free_percpu(dev->tstats); +} + +static int geneve_open(struct net_device *dev) +{ + struct geneve_dev *geneve = netdev_priv(dev); + struct net *net = geneve->net; + struct geneve_net *gn = net_generic(geneve->net, geneve_net_id); + struct geneve_sock *gs; + + gs = geneve_sock_add(net, htons(GENEVE_UDP_PORT), geneve_rx, gn, + false, false); + if (IS_ERR(gs)) + return PTR_ERR(gs); + + geneve->sock = gs; + + return 0; +} + +static int geneve_stop(struct net_device *dev) +{ + struct geneve_dev *geneve = netdev_priv(dev); + struct geneve_sock *gs = geneve->sock; + + geneve_sock_release(gs); + + return 0; +} + +static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct geneve_dev *geneve = netdev_priv(dev); + struct geneve_sock *gs = geneve->sock; + struct rtable *rt = NULL; + const struct iphdr *iip; /* interior IP header */ + struct flowi4 fl4; + int err; + __be16 sport; + __u8 tos, ttl = 0; + + iip = ip_hdr(skb); + + skb_reset_mac_header(skb); + + /* TODO: port min/max limits should be configurable */ + sport = udp_flow_src_port(dev_net(dev), skb, 0, 0, true); + + memset(&fl4, 0, sizeof(fl4)); + fl4.daddr = geneve->remote.sin_addr.s_addr; + rt = ip_route_output_key(geneve->net, &fl4); + if (IS_ERR(rt)) { + netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); + dev->stats.tx_carrier_errors++; + goto tx_error; + } + if (rt->dst.dev == dev) { /* is this necessary? */ + netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr); + dev->stats.collisions++; + goto rt_tx_error; + } + + /* TODO: tos and ttl should be configurable */ + + tos = ip_tunnel_ecn_encap(0, iip, skb); + + if (IN_MULTICAST(ntohl(fl4.daddr))) + ttl = 1; + + ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + + /* no need to handle local destination and encap bypass...yet... */ + + err = geneve_xmit_skb(gs, rt, skb, fl4.saddr, fl4.daddr, + tos, ttl, 0, sport, htons(GENEVE_UDP_PORT), 0, + geneve->vni, 0, NULL, false, + !net_eq(geneve->net, dev_net(geneve->dev))); + if (err < 0) + ip_rt_put(rt); + + iptunnel_xmit_stats(err, &dev->stats, dev->tstats); + + return NETDEV_TX_OK; + +rt_tx_error: + ip_rt_put(rt); +tx_error: + dev->stats.tx_errors++; + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + +static const struct net_device_ops geneve_netdev_ops = { + .ndo_init = geneve_init, + .ndo_uninit = geneve_uninit, + .ndo_open = geneve_open, + .ndo_stop = geneve_stop, + .ndo_start_xmit = geneve_xmit, + .ndo_get_stats64 = ip_tunnel_get_stats64, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + +static void geneve_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *drvinfo) +{ + strlcpy(drvinfo->version, GENEVE_NETDEV_VER, sizeof(drvinfo->version)); + strlcpy(drvinfo->driver, "geneve", sizeof(drvinfo->driver)); +} + +static const struct ethtool_ops geneve_ethtool_ops = { + .get_drvinfo = geneve_get_drvinfo, + .get_link = ethtool_op_get_link, +}; + +/* Info for udev, that this is a virtual tunnel endpoint */ +static struct device_type geneve_type = { + .name = "geneve", +}; + +/* Initialize the device structure. */ +static void geneve_setup(struct net_device *dev) +{ + ether_setup(dev); + + dev->netdev_ops = &geneve_netdev_ops; + dev->ethtool_ops = &geneve_ethtool_ops; + dev->destructor = free_netdev; + + SET_NETDEV_DEVTYPE(dev, &geneve_type); + + dev->tx_queue_len = 0; + dev->features |= NETIF_F_LLTX; + dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= NETIF_F_RXCSUM; + dev->features |= NETIF_F_GSO_SOFTWARE; + + dev->vlan_features = dev->features; + dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; + + dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM; + dev->hw_features |= NETIF_F_GSO_SOFTWARE; + dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; + + netif_keep_dst(dev); + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; +} + +static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = { + [IFLA_GENEVE_ID] = { .type = NLA_U32 }, + [IFLA_GENEVE_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) }, +}; + +static int geneve_validate(struct nlattr *tb[], struct nlattr *data[]) +{ + if (tb[IFLA_ADDRESS]) { + if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) + return -EINVAL; + + if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) + return -EADDRNOTAVAIL; + } + + if (!data) + return -EINVAL; + + if (data[IFLA_GENEVE_ID]) { + __u32 vni = nla_get_u32(data[IFLA_GENEVE_ID]); + + if (vni >= GENEVE_VID_MASK) + return -ERANGE; + } + + return 0; +} + +static int geneve_newlink(struct net *net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + struct geneve_net *gn = net_generic(net, geneve_net_id); + struct geneve_dev *dummy, *geneve = netdev_priv(dev); + struct hlist_head *vni_list_head; + struct sockaddr_in remote; /* IPv4 address for link partner */ + __u32 vni, hash; + int err; + + if (!data[IFLA_GENEVE_ID] || !data[IFLA_GENEVE_REMOTE]) + return -EINVAL; + + geneve->net = net; + geneve->dev = dev; + + vni = nla_get_u32(data[IFLA_GENEVE_ID]); + geneve->vni[0] = (vni & 0x00ff0000) >> 16; + geneve->vni[1] = (vni & 0x0000ff00) >> 8; + geneve->vni[2] = vni & 0x000000ff; + + geneve->remote.sin_addr.s_addr = + nla_get_in_addr(data[IFLA_GENEVE_REMOTE]); + if (IN_MULTICAST(ntohl(geneve->remote.sin_addr.s_addr))) + return -EINVAL; + + remote = geneve->remote; + hash = geneve_net_vni_hash(geneve->vni); + vni_list_head = &gn->vni_list[hash]; + hlist_for_each_entry_rcu(dummy, vni_list_head, hlist) { + if (!memcmp(geneve->vni, dummy->vni, sizeof(dummy->vni)) && + !memcmp(&remote, &dummy->remote, sizeof(dummy->remote))) + return -EBUSY; + } + + if (tb[IFLA_ADDRESS] == NULL) + eth_hw_addr_random(dev); + + err = register_netdevice(dev); + if (err) + return err; + + list_add(&geneve->next, &gn->geneve_list); + + hlist_add_head_rcu(&geneve->hlist, &gn->vni_list[hash]); + + return 0; +} + +static void geneve_dellink(struct net_device *dev, struct list_head *head) +{ + struct geneve_dev *geneve = netdev_priv(dev); + + if (!hlist_unhashed(&geneve->hlist)) + hlist_del_rcu(&geneve->hlist); + + list_del(&geneve->next); + unregister_netdevice_queue(dev, head); +} + +static size_t geneve_get_size(const struct net_device *dev) +{ + return nla_total_size(sizeof(__u32)) + /* IFLA_GENEVE_ID */ + nla_total_size(sizeof(struct in_addr)) + /* IFLA_GENEVE_REMOTE */ + 0; +} + +static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev) +{ + struct geneve_dev *geneve = netdev_priv(dev); + __u32 vni; + + vni = (geneve->vni[0] << 16) | (geneve->vni[1] << 8) | geneve->vni[2]; + if (nla_put_u32(skb, IFLA_GENEVE_ID, vni)) + goto nla_put_failure; + + if (nla_put_in_addr(skb, IFLA_GENEVE_REMOTE, + geneve->remote.sin_addr.s_addr)) + goto nla_put_failure; + + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static struct rtnl_link_ops geneve_link_ops __read_mostly = { + .kind = "geneve", + .maxtype = IFLA_GENEVE_MAX, + .policy = geneve_policy, + .priv_size = sizeof(struct geneve_dev), + .setup = geneve_setup, + .validate = geneve_validate, + .newlink = geneve_newlink, + .dellink = geneve_dellink, + .get_size = geneve_get_size, + .fill_info = geneve_fill_info, +}; + +static __net_init int geneve_init_net(struct net *net) +{ + struct geneve_net *gn = net_generic(net, geneve_net_id); + unsigned int h; + + INIT_LIST_HEAD(&gn->geneve_list); + + for (h = 0; h < VNI_HASH_SIZE; ++h) + INIT_HLIST_HEAD(&gn->vni_list[h]); + + return 0; +} + +static void __net_exit geneve_exit_net(struct net *net) +{ + struct geneve_net *gn = net_generic(net, geneve_net_id); + struct geneve_dev *geneve, *next; + struct net_device *dev, *aux; + LIST_HEAD(list); + + rtnl_lock(); + + /* gather any geneve devices that were moved into this ns */ + for_each_netdev_safe(net, dev, aux) + if (dev->rtnl_link_ops == &geneve_link_ops) + unregister_netdevice_queue(dev, &list); + + /* now gather any other geneve devices that were created in this ns */ + list_for_each_entry_safe(geneve, next, &gn->geneve_list, next) { + /* If geneve->dev is in the same netns, it was already added + * to the list by the previous loop. + */ + if (!net_eq(dev_net(geneve->dev), net)) + unregister_netdevice_queue(geneve->dev, &list); + } + + /* unregister the devices gathered above */ + unregister_netdevice_many(&list); + rtnl_unlock(); +} + +static struct pernet_operations geneve_net_ops = { + .init = geneve_init_net, + .exit = geneve_exit_net, + .id = &geneve_net_id, + .size = sizeof(struct geneve_net), +}; + +static int __init geneve_init_module(void) +{ + int rc; + + rc = register_pernet_subsys(&geneve_net_ops); + if (rc) + goto out1; + + rc = rtnl_link_register(&geneve_link_ops); + if (rc) + goto out2; + + return 0; +out2: + unregister_pernet_subsys(&geneve_net_ops); +out1: + return rc; +} +late_initcall(geneve_init_module); + +static void __exit geneve_cleanup_module(void) +{ + rtnl_link_unregister(&geneve_link_ops); + unregister_pernet_subsys(&geneve_net_ops); +} +module_exit(geneve_cleanup_module); + +MODULE_LICENSE("GPL"); +MODULE_VERSION(GENEVE_NETDEV_VER); +MODULE_AUTHOR("John W. Linville "); +MODULE_DESCRIPTION("Interface driver for GENEVE encapsulated traffic"); +MODULE_ALIAS_RTNL_LINK("geneve"); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 6d6e502e1051..afccc9393fef 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -390,6 +390,15 @@ struct ifla_vxlan_port_range { __be16 high; }; +/* GENEVE section */ +enum { + IFLA_GENEVE_UNSPEC, + IFLA_GENEVE_ID, + IFLA_GENEVE_REMOTE, + __IFLA_GENEVE_MAX +}; +#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) + /* Bonding section */ enum { -- cgit v1.2.3 From 87d5c18ce1f41a2410d4fb26d5d68c55867450f5 Mon Sep 17 00:00:00 2001 From: Pablo Neira Date: Wed, 13 May 2015 18:19:34 +0200 Subject: netfilter: cleanup struct nf_hook_ops indentation Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- include/linux/netfilter.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 63560d0a8dfe..83be4a3cec98 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -79,16 +79,16 @@ typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, const struct nf_hook_state *state); struct nf_hook_ops { - struct list_head list; + struct list_head list; /* User fills in from here down. */ - nf_hookfn *hook; - struct module *owner; - void *priv; - u_int8_t pf; - unsigned int hooknum; + nf_hookfn *hook; + struct module *owner; + void *priv; + u_int8_t pf; + unsigned int hooknum; /* Hooks are ordered in ascending priority. */ - int priority; + int priority; }; struct nf_sockopt_ops { -- cgit v1.2.3 From f7191483461ce2ae579b6f7227fa7ce49e006656 Mon Sep 17 00:00:00 2001 From: Pablo Neira Date: Wed, 13 May 2015 18:19:35 +0200 Subject: netfilter: add hook list to nf_hook_state Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- include/linux/netfilter.h | 7 +++++-- net/netfilter/core.c | 6 ++---- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 83be4a3cec98..388ed1952242 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -54,10 +54,12 @@ struct nf_hook_state { struct net_device *in; struct net_device *out; struct sock *sk; + struct list_head *hook_list; int (*okfn)(struct sock *, struct sk_buff *); }; static inline void nf_hook_state_init(struct nf_hook_state *p, + struct list_head *hook_list, unsigned int hook, int thresh, u_int8_t pf, struct net_device *indev, @@ -71,6 +73,7 @@ static inline void nf_hook_state_init(struct nf_hook_state *p, p->in = indev; p->out = outdev; p->sk = sk; + p->hook_list = hook_list; p->okfn = okfn; } @@ -166,8 +169,8 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, if (nf_hooks_active(pf, hook)) { struct nf_hook_state state; - nf_hook_state_init(&state, hook, thresh, pf, - indev, outdev, sk, okfn); + nf_hook_state_init(&state, &nf_hooks[pf][hook], hook, thresh, + pf, indev, outdev, sk, okfn); return nf_hook_slow(skb, &state); } return 1; diff --git a/net/netfilter/core.c b/net/netfilter/core.c index e6163017c42d..e418cfd603c0 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -166,11 +166,9 @@ int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state) /* We may already have this, but read-locks nest anyway */ rcu_read_lock(); - elem = list_entry_rcu(&nf_hooks[state->pf][state->hook], - struct nf_hook_ops, list); + elem = list_entry_rcu(state->hook_list, struct nf_hook_ops, list); next_hook: - verdict = nf_iterate(&nf_hooks[state->pf][state->hook], skb, state, - &elem); + verdict = nf_iterate(state->hook_list, skb, state, &elem); if (verdict == NF_ACCEPT || verdict == NF_STOP) { ret = 1; } else if ((verdict & NF_VERDICT_MASK) == NF_DROP) { -- cgit v1.2.3 From b8d0aad0c77f488d1d51a02d871a5cbc2d8032b9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Date: Wed, 13 May 2015 18:19:36 +0200 Subject: netfilter: add nf_hook_list_active() In preparation to have netfilter ingress per-device hook list. Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- include/linux/netfilter.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 388ed1952242..49d00638d1fa 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -134,26 +134,33 @@ extern struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; #ifdef HAVE_JUMP_LABEL extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; -static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook) +static inline bool nf_hook_list_active(struct list_head *nf_hook_list, + u_int8_t pf, unsigned int hook) { if (__builtin_constant_p(pf) && __builtin_constant_p(hook)) return static_key_false(&nf_hooks_needed[pf][hook]); - return !list_empty(&nf_hooks[pf][hook]); + return !list_empty(nf_hook_list); } #else -static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook) +static inline bool nf_hook_list_active(struct list_head *nf_hook_list, + u_int8_t pf, unsigned int hook) { - return !list_empty(&nf_hooks[pf][hook]); + return !list_empty(nf_hook_list); } #endif +static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook) +{ + return nf_hook_list_active(&nf_hooks[pf][hook], pf, hook); +} + int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state); /** * nf_hook_thresh - call a netfilter hook - * + * * Returns 1 if the hook has allowed the packet to pass. The function * okfn must be invoked by the caller in this case. Any other return * value indicates the packet has been consumed by the hook. -- cgit v1.2.3 From 1cf51900f8545b358b5deaacfda348d990f671db Mon Sep 17 00:00:00 2001 From: Pablo Neira Date: Wed, 13 May 2015 18:19:37 +0200 Subject: net: add CONFIG_NET_INGRESS to enable ingress filtering This new config switch enables the ingress filtering infrastructure that is controlled through the ingress_needed static key. This prepares the introduction of the Netfilter ingress hook that resides under this unique static key. Note that CONFIG_SCH_INGRESS automatically selects this, that should be no problem since this also depends on CONFIG_NET_CLS_ACT. Signed-off-by: Pablo Neira Ayuso Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 2 +- net/Kconfig | 3 +++ net/core/dev.c | 7 ++++--- net/sched/Kconfig | 1 + 4 files changed, 9 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index bd29ab4b0941..a2324fb45cf4 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -79,7 +79,7 @@ static inline struct netdev_queue *dev_ingress_queue(struct net_device *dev) struct netdev_queue *dev_ingress_queue_create(struct net_device *dev); -#ifdef CONFIG_NET_CLS_ACT +#ifdef CONFIG_NET_INGRESS void net_inc_ingress_queue(void); void net_dec_ingress_queue(void); #endif diff --git a/net/Kconfig b/net/Kconfig index 44dd5786ee91..57a7c5af3175 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -45,6 +45,9 @@ config COMPAT_NETLINK_MESSAGES Newly written code should NEVER need this option but do compat-independent messages instead! +config NET_INGRESS + bool + menu "Networking options" source "net/packet/Kconfig" diff --git a/net/core/dev.c b/net/core/dev.c index af549062ae8e..a5ef90016ce7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1630,7 +1630,7 @@ int call_netdevice_notifiers(unsigned long val, struct net_device *dev) } EXPORT_SYMBOL(call_netdevice_notifiers); -#ifdef CONFIG_NET_CLS_ACT +#ifdef CONFIG_NET_INGRESS static struct static_key ingress_needed __read_mostly; void net_inc_ingress_queue(void) @@ -3798,13 +3798,14 @@ another_round: } skip_taps: -#ifdef CONFIG_NET_CLS_ACT +#ifdef CONFIG_NET_INGRESS if (static_key_false(&ingress_needed)) { skb = handle_ing(skb, &pt_prev, &ret, orig_dev); if (!skb) goto unlock; } - +#endif +#ifdef CONFIG_NET_CLS_ACT skb->tc_verd = 0; ncls: #endif diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 5fd1c2f487d2..daa33432b716 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -312,6 +312,7 @@ config NET_SCH_PIE config NET_SCH_INGRESS tristate "Ingress Qdisc" depends on NET_CLS_ACT + select NET_INGRESS ---help--- Say Y here if you want to use classifiers for incoming packets. If unsure, say Y. -- cgit v1.2.3 From e687ad60af09010936bbd0b2a3b5d90a8ee8353c Mon Sep 17 00:00:00 2001 From: Pablo Neira Date: Wed, 13 May 2015 18:19:38 +0200 Subject: netfilter: add netfilter ingress hook after handle_ing() under unique static key This patch adds the Netfilter ingress hook just after the existing tc ingress hook, that seems to be the consensus solution for this. Note that the Netfilter hook resides under the global static key that enables ingress filtering. Nonetheless, Netfilter still also has its own static key for minimal impact on the existing handle_ing(). * Without this patch: Result: OK: 6216490(c6216338+d152) usec, 100000000 (60byte,0frags) 16086246pps 7721Mb/sec (7721398080bps) errors: 100000000 42.46% kpktgend_0 [kernel.kallsyms] [k] __netif_receive_skb_core 25.92% kpktgend_0 [kernel.kallsyms] [k] kfree_skb 7.81% kpktgend_0 [pktgen] [k] pktgen_thread_worker 5.62% kpktgend_0 [kernel.kallsyms] [k] ip_rcv 2.70% kpktgend_0 [kernel.kallsyms] [k] netif_receive_skb_internal 2.34% kpktgend_0 [kernel.kallsyms] [k] netif_receive_skb_sk 1.44% kpktgend_0 [kernel.kallsyms] [k] __build_skb * With this patch: Result: OK: 6214833(c6214731+d101) usec, 100000000 (60byte,0frags) 16090536pps 7723Mb/sec (7723457280bps) errors: 100000000 41.23% kpktgend_0 [kernel.kallsyms] [k] __netif_receive_skb_core 26.57% kpktgend_0 [kernel.kallsyms] [k] kfree_skb 7.72% kpktgend_0 [pktgen] [k] pktgen_thread_worker 5.55% kpktgend_0 [kernel.kallsyms] [k] ip_rcv 2.78% kpktgend_0 [kernel.kallsyms] [k] netif_receive_skb_internal 2.06% kpktgend_0 [kernel.kallsyms] [k] netif_receive_skb_sk 1.43% kpktgend_0 [kernel.kallsyms] [k] __build_skb * Without this patch + tc ingress: tc filter add dev eth4 parent ffff: protocol ip prio 1 \ u32 match ip dst 4.3.2.1/32 Result: OK: 9269001(c9268821+d179) usec, 100000000 (60byte,0frags) 10788648pps 5178Mb/sec (5178551040bps) errors: 100000000 40.99% kpktgend_0 [kernel.kallsyms] [k] __netif_receive_skb_core 17.50% kpktgend_0 [kernel.kallsyms] [k] kfree_skb 11.77% kpktgend_0 [cls_u32] [k] u32_classify 5.62% kpktgend_0 [kernel.kallsyms] [k] tc_classify_compat 5.18% kpktgend_0 [pktgen] [k] pktgen_thread_worker 3.23% kpktgend_0 [kernel.kallsyms] [k] tc_classify 2.97% kpktgend_0 [kernel.kallsyms] [k] ip_rcv 1.83% kpktgend_0 [kernel.kallsyms] [k] netif_receive_skb_internal 1.50% kpktgend_0 [kernel.kallsyms] [k] netif_receive_skb_sk 0.99% kpktgend_0 [kernel.kallsyms] [k] __build_skb * With this patch + tc ingress: tc filter add dev eth4 parent ffff: protocol ip prio 1 \ u32 match ip dst 4.3.2.1/32 Result: OK: 9308218(c9308091+d126) usec, 100000000 (60byte,0frags) 10743194pps 5156Mb/sec (5156733120bps) errors: 100000000 42.01% kpktgend_0 [kernel.kallsyms] [k] __netif_receive_skb_core 17.78% kpktgend_0 [kernel.kallsyms] [k] kfree_skb 11.70% kpktgend_0 [cls_u32] [k] u32_classify 5.46% kpktgend_0 [kernel.kallsyms] [k] tc_classify_compat 5.16% kpktgend_0 [pktgen] [k] pktgen_thread_worker 2.98% kpktgend_0 [kernel.kallsyms] [k] ip_rcv 2.84% kpktgend_0 [kernel.kallsyms] [k] tc_classify 1.96% kpktgend_0 [kernel.kallsyms] [k] netif_receive_skb_internal 1.57% kpktgend_0 [kernel.kallsyms] [k] netif_receive_skb_sk Note that the results are very similar before and after. I can see gcc gets the code under the ingress static key out of the hot path. Then, on that cold branch, it generates the code to accomodate the netfilter ingress static key. My explanation for this is that this reduces the pressure on the instruction cache for non-users as the new code is out of the hot path, and it comes with minimal impact for tc ingress users. Using gcc version 4.8.4 on: Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 8 [...] L1d cache: 16K L1i cache: 64K L2 cache: 2048K L3 cache: 8192K Signed-off-by: Pablo Neira Ayuso Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 +++ include/linux/netfilter.h | 1 + include/linux/netfilter_ingress.h | 41 +++++++++++++++++++++++++++++++++++++++ include/uapi/linux/netfilter.h | 6 ++++++ net/core/dev.c | 36 ++++++++++++++++++++++++++++++++++ net/netfilter/Kconfig | 7 +++++++ net/netfilter/core.c | 31 ++++++++++++++++++++++++++++- 7 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 include/linux/netfilter_ingress.h (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index d3ed01c18247..51f8d2f5dc3f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1656,6 +1656,9 @@ struct net_device { struct tcf_proto __rcu *ingress_cl_list; #endif struct netdev_queue __rcu *ingress_queue; +#ifdef CONFIG_NETFILTER_INGRESS + struct list_head nf_hooks_ingress; +#endif unsigned char broadcast[MAX_ADDR_LEN]; #ifdef CONFIG_RFS_ACCEL diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 49d00638d1fa..f5ff5d156da8 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -86,6 +86,7 @@ struct nf_hook_ops { /* User fills in from here down. */ nf_hookfn *hook; + struct net_device *dev; struct module *owner; void *priv; u_int8_t pf; diff --git a/include/linux/netfilter_ingress.h b/include/linux/netfilter_ingress.h new file mode 100644 index 000000000000..cb0727fe2b3d --- /dev/null +++ b/include/linux/netfilter_ingress.h @@ -0,0 +1,41 @@ +#ifndef _NETFILTER_INGRESS_H_ +#define _NETFILTER_INGRESS_H_ + +#include +#include + +#ifdef CONFIG_NETFILTER_INGRESS +static inline int nf_hook_ingress_active(struct sk_buff *skb) +{ + return nf_hook_list_active(&skb->dev->nf_hooks_ingress, + NFPROTO_NETDEV, NF_NETDEV_INGRESS); +} + +static inline int nf_hook_ingress(struct sk_buff *skb) +{ + struct nf_hook_state state; + + nf_hook_state_init(&state, &skb->dev->nf_hooks_ingress, + NF_NETDEV_INGRESS, INT_MIN, NFPROTO_NETDEV, NULL, + skb->dev, NULL, NULL); + return nf_hook_slow(skb, &state); +} + +static inline void nf_hook_ingress_init(struct net_device *dev) +{ + INIT_LIST_HEAD(&dev->nf_hooks_ingress); +} +#else /* CONFIG_NETFILTER_INGRESS */ +static inline int nf_hook_ingress_active(struct sk_buff *skb) +{ + return 0; +} + +static inline int nf_hook_ingress(struct sk_buff *skb) +{ + return 0; +} + +static inline void nf_hook_ingress_init(struct net_device *dev) {} +#endif /* CONFIG_NETFILTER_INGRESS */ +#endif /* _NETFILTER_INGRESS_H_ */ diff --git a/include/uapi/linux/netfilter.h b/include/uapi/linux/netfilter.h index ef1b1f88ca18..177027cce6b3 100644 --- a/include/uapi/linux/netfilter.h +++ b/include/uapi/linux/netfilter.h @@ -51,11 +51,17 @@ enum nf_inet_hooks { NF_INET_NUMHOOKS }; +enum nf_dev_hooks { + NF_NETDEV_INGRESS, + NF_NETDEV_NUMHOOKS +}; + enum { NFPROTO_UNSPEC = 0, NFPROTO_INET = 1, NFPROTO_IPV4 = 2, NFPROTO_ARP = 3, + NFPROTO_NETDEV = 5, NFPROTO_BRIDGE = 7, NFPROTO_IPV6 = 10, NFPROTO_DECNET = 12, diff --git a/net/core/dev.c b/net/core/dev.c index a5ef90016ce7..29f0d6e6542c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -135,6 +135,7 @@ #include #include #include +#include #include "net-sysfs.h" @@ -3666,6 +3667,13 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb, return skb; } +#else +static inline struct sk_buff *handle_ing(struct sk_buff *skb, + struct packet_type **pt_prev, + int *ret, struct net_device *orig_dev) +{ + return skb; +} #endif /** @@ -3739,6 +3747,28 @@ static bool skb_pfmemalloc_protocol(struct sk_buff *skb) } } +#ifdef CONFIG_NETFILTER_INGRESS +static inline int nf_ingress(struct sk_buff *skb, struct packet_type **pt_prev, + int *ret, struct net_device *orig_dev) +{ + if (nf_hook_ingress_active(skb)) { + if (*pt_prev) { + *ret = deliver_skb(skb, *pt_prev, orig_dev); + *pt_prev = NULL; + } + + return nf_hook_ingress(skb); + } + return 0; +} +#else +static inline int nf_ingress(struct sk_buff *skb, struct packet_type **pt_prev, + int *ret, struct net_device *orig_dev) +{ + return 0; +} +#endif + static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) { struct packet_type *ptype, *pt_prev; @@ -3803,6 +3833,9 @@ skip_taps: skb = handle_ing(skb, &pt_prev, &ret, orig_dev); if (!skb) goto unlock; + + if (nf_ingress(skb, &pt_prev, &ret, orig_dev) < 0) + goto unlock; } #endif #ifdef CONFIG_NET_CLS_ACT @@ -6968,6 +7001,9 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, dev->group = INIT_NETDEV_GROUP; if (!dev->ethtool_ops) dev->ethtool_ops = &default_ethtool_ops; + + nf_hook_ingress_init(dev); + return dev; free_all: diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index f70e34a68f70..db1c674397ad 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -1,6 +1,13 @@ menu "Core Netfilter Configuration" depends on NET && INET && NETFILTER +config NETFILTER_INGRESS + bool "Netfilter ingress support" + select NET_INGRESS + help + This allows you to classify packets from ingress using the Netfilter + infrastructure. + config NETFILTER_NETLINK tristate diff --git a/net/netfilter/core.c b/net/netfilter/core.c index e418cfd603c0..653e32eac08c 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -64,10 +64,27 @@ static DEFINE_MUTEX(nf_hook_mutex); int nf_register_hook(struct nf_hook_ops *reg) { + struct list_head *nf_hook_list; struct nf_hook_ops *elem; mutex_lock(&nf_hook_mutex); - list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) { + switch (reg->pf) { + case NFPROTO_NETDEV: +#ifdef CONFIG_NETFILTER_INGRESS + if (reg->hooknum == NF_NETDEV_INGRESS) { + BUG_ON(reg->dev == NULL); + nf_hook_list = ®->dev->nf_hooks_ingress; + net_inc_ingress_queue(); + break; + } +#endif + /* Fall through. */ + default: + nf_hook_list = &nf_hooks[reg->pf][reg->hooknum]; + break; + } + + list_for_each_entry(elem, nf_hook_list, list) { if (reg->priority < elem->priority) break; } @@ -85,6 +102,18 @@ void nf_unregister_hook(struct nf_hook_ops *reg) mutex_lock(&nf_hook_mutex); list_del_rcu(®->list); mutex_unlock(&nf_hook_mutex); + switch (reg->pf) { + case NFPROTO_NETDEV: +#ifdef CONFIG_NETFILTER_INGRESS + if (reg->hooknum == NF_NETDEV_INGRESS) { + net_dec_ingress_queue(); + break; + } + break; +#endif + default: + break; + } #ifdef HAVE_JUMP_LABEL static_key_slow_dec(&nf_hooks_needed[reg->pf][reg->hooknum]); #endif -- cgit v1.2.3 From 7fb48c5bc3100f7674a8e26f42c1518196500728 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sun, 3 May 2015 22:05:28 +0200 Subject: netfilter: bridge: neigh_head and physoutdev can't be used at same time The neigh_header is only needed when we detect DNAT after prerouting and neigh cache didn't have a mac address for us. The output port has not been chosen yet so we can re-use the storage area, bringing struct size down to 32 bytes on x86_64. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/linux/skbuff.h | 8 +++++--- net/bridge/br_netfilter.c | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index c0b574a414e7..3d932e64125a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -170,12 +170,14 @@ struct nf_bridge_info { BRNF_PROTO_UNCHANGED, BRNF_PROTO_8021Q, BRNF_PROTO_PPPOE - } orig_proto; + } orig_proto:8; bool pkt_otherhost; unsigned int mask; struct net_device *physindev; - struct net_device *physoutdev; - char neigh_header[8]; + union { + struct net_device *physoutdev; + char neigh_header[8]; + }; }; #endif diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index ab55e2472beb..13973da29b2a 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -973,6 +973,8 @@ static void br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb) nf_bridge->neigh_header, ETH_HLEN - ETH_ALEN); skb->dev = nf_bridge->physindev; + + nf_bridge->physoutdev = NULL; br_handle_frame_finish(NULL, skb); } -- cgit v1.2.3 From a3b1c1eb50f9b3e0c73c37157d0c61b2e90ae580 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 6 May 2015 16:28:57 +0200 Subject: netfilter: ipset: deinline ip_set_put_extensions() On x86 allyesconfig build: The function compiles to 489 bytes of machine code. It has 25 callsites. text data bss dec hex filename 82441375 22255384 20627456 125324215 7784bb7 vmlinux.before 82434909 22255384 20627456 125317749 7783275 vmlinux Signed-off-by: Denys Vlasenko CC: Jozsef Kadlecsik CC: Eric W. Biederman CC: David S. Miller CC: Jan Engelhardt CC: Jiri Pirko CC: linux-kernel@vger.kernel.org CC: netdev@vger.kernel.org CC: netfilter-devel@vger.kernel.org Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/ipset/ip_set.h | 24 ++---------------------- net/netfilter/ipset/ip_set_core.c | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index f88be7258e5f..ffdfdc24952a 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h @@ -533,29 +533,9 @@ bitmap_bytes(u32 a, u32 b) #include #include -static inline int +int ip_set_put_extensions(struct sk_buff *skb, const struct ip_set *set, - const void *e, bool active) -{ - if (SET_WITH_TIMEOUT(set)) { - unsigned long *timeout = ext_timeout(e, set); - - if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, - htonl(active ? ip_set_timeout_get(timeout) - : *timeout))) - return -EMSGSIZE; - } - if (SET_WITH_COUNTER(set) && - ip_set_put_counter(skb, ext_counter(e, set))) - return -EMSGSIZE; - if (SET_WITH_COMMENT(set) && - ip_set_put_comment(skb, ext_comment(e, set))) - return -EMSGSIZE; - if (SET_WITH_SKBINFO(set) && - ip_set_put_skbinfo(skb, ext_skbinfo(e, set))) - return -EMSGSIZE; - return 0; -} + const void *e, bool active); #define IP_SET_INIT_KEXT(skb, opt, set) \ { .bytes = (skb)->len, .packets = 1, \ diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 7f9c0565e715..475e4960a164 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -432,6 +432,31 @@ ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[], } EXPORT_SYMBOL_GPL(ip_set_get_extensions); +int +ip_set_put_extensions(struct sk_buff *skb, const struct ip_set *set, + const void *e, bool active) +{ + if (SET_WITH_TIMEOUT(set)) { + unsigned long *timeout = ext_timeout(e, set); + + if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, + htonl(active ? ip_set_timeout_get(timeout) + : *timeout))) + return -EMSGSIZE; + } + if (SET_WITH_COUNTER(set) && + ip_set_put_counter(skb, ext_counter(e, set))) + return -EMSGSIZE; + if (SET_WITH_COMMENT(set) && + ip_set_put_comment(skb, ext_comment(e, set))) + return -EMSGSIZE; + if (SET_WITH_SKBINFO(set) && + ip_set_put_skbinfo(skb, ext_skbinfo(e, set))) + return -EMSGSIZE; + return 0; +} +EXPORT_SYMBOL_GPL(ip_set_put_extensions); + /* * Creating/destroying/renaming/swapping affect the existence and * the properties of a set. All of these can be executed from userspace -- cgit v1.2.3 From 922f2dd1b65a888e34c472979460dc23211750a2 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 12 May 2015 10:33:24 -0700 Subject: net: phy: Add phy_ignore_ta_mask to account for broken turn-around Some PHY devices/switches will not release the turn-around line as they should do at the end of a MDIO transaction. To help with such situations, allow MDIO bus drivers to be made aware of such restrictions. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- include/linux/phy.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/linux/phy.h b/include/linux/phy.h index 685809835b5c..701c7a3946e0 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -181,6 +181,9 @@ struct mii_bus { /* PHY addresses to be ignored when probing */ u32 phy_mask; + /* PHY addresses to ignore the TA/read failure */ + u32 phy_ignore_ta_mask; + /* * Pointer to an array of interrupts, each PHY's * interrupt at the index matching its address -- cgit v1.2.3 From 8f4fc071b1926d0b20336e2b3f8ab85c94c734c5 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Thu, 14 May 2015 15:16:55 -0700 Subject: gfp: add __GFP_NOACCOUNT Not all kmem allocations should be accounted to memcg. The following patch gives an example when accounting of a certain type of allocations to memcg can effectively result in a memory leak. This patch adds the __GFP_NOACCOUNT flag which if passed to kmalloc and friends will force the allocation to go through the root cgroup. It will be used by the next patch. Note, since in case of kmemleak enabled each kmalloc implies yet another allocation from the kmemleak_object cache, we add __GFP_NOACCOUNT to gfp_kmemleak_mask. Alternatively, we could introduce a per kmem cache flag disabling accounting for all allocations of a particular kind, but (a) we would not be able to bypass accounting for kmalloc then and (b) a kmem cache with this flag set could not be merged with a kmem cache without this flag, which would increase the number of global caches and therefore fragmentation even if the memory cgroup controller is not used. Despite its generic name, currently __GFP_NOACCOUNT disables accounting only for kmem allocations while user page allocations are always charged. To catch abusing of this flag, a warning is issued on an attempt of passing it to mem_cgroup_try_charge. Signed-off-by: Vladimir Davydov Cc: Tejun Heo Cc: Johannes Weiner Cc: Michal Hocko Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Cc: Greg Thelen Cc: Greg Kroah-Hartman Cc: [4.0.x] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/gfp.h | 2 ++ include/linux/memcontrol.h | 4 ++++ mm/kmemleak.c | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 97a9373e61e8..15928f0647e4 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -30,6 +30,7 @@ struct vm_area_struct; #define ___GFP_HARDWALL 0x20000u #define ___GFP_THISNODE 0x40000u #define ___GFP_RECLAIMABLE 0x80000u +#define ___GFP_NOACCOUNT 0x100000u #define ___GFP_NOTRACK 0x200000u #define ___GFP_NO_KSWAPD 0x400000u #define ___GFP_OTHER_NODE 0x800000u @@ -87,6 +88,7 @@ struct vm_area_struct; #define __GFP_HARDWALL ((__force gfp_t)___GFP_HARDWALL) /* Enforce hardwall cpuset memory allocs */ #define __GFP_THISNODE ((__force gfp_t)___GFP_THISNODE)/* No fallback, no policies */ #define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE) /* Page is reclaimable */ +#define __GFP_NOACCOUNT ((__force gfp_t)___GFP_NOACCOUNT) /* Don't account to kmemcg */ #define __GFP_NOTRACK ((__force gfp_t)___GFP_NOTRACK) /* Don't track with kmemcheck */ #define __GFP_NO_KSWAPD ((__force gfp_t)___GFP_NO_KSWAPD) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 72dff5fb0d0c..6c8918114804 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -463,6 +463,8 @@ memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **memcg, int order) if (!memcg_kmem_enabled()) return true; + if (gfp & __GFP_NOACCOUNT) + return true; /* * __GFP_NOFAIL allocations will move on even if charging is not * possible. Therefore we don't even try, and have this allocation @@ -522,6 +524,8 @@ memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp) { if (!memcg_kmem_enabled()) return cachep; + if (gfp & __GFP_NOACCOUNT) + return cachep; if (gfp & __GFP_NOFAIL) return cachep; if (in_interrupt() || (!current->mm) || (current->flags & PF_KTHREAD)) diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 5405aff5a590..f0fe4f2c1fa7 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -115,7 +115,8 @@ #define BYTES_PER_POINTER sizeof(void *) /* GFP bitmask for kmemleak internal allocations */ -#define gfp_kmemleak_mask(gfp) (((gfp) & (GFP_KERNEL | GFP_ATOMIC)) | \ +#define gfp_kmemleak_mask(gfp) (((gfp) & (GFP_KERNEL | GFP_ATOMIC | \ + __GFP_NOACCOUNT)) | \ __GFP_NORETRY | __GFP_NOMEMALLOC | \ __GFP_NOWARN) -- cgit v1.2.3 From 929aa5b250bfc59aca492d3213c7f3a53e2a5247 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 14 May 2015 15:17:01 -0700 Subject: uidgid: make uid_valid and gid_valid work with !CONFIG_MULTIUSER {u,g}id_valid call {u,g}id_eq, which calls __k{u,g}id_val on both arguments and compares. With !CONFIG_MULTIUSER, __k{u,g}id_val return a constant 0, which makes {u,g}id_valid always return false. Change {u,g}id_valid to compare their argument against -1 instead. That produces identical results in the normal CONFIG_MULTIUSER=y case, but with !CONFIG_MULTIUSER will make {u,g}id_valid constant-fold into "return true;" rather than "return false;". This fixes uses of devpts without CONFIG_MULTIUSER. Signed-off-by: Josh Triplett Reported-by: Fengguang Wu , Cc: Peter Hurley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/uidgid.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h index 0ee05da38899..03835522dfcb 100644 --- a/include/linux/uidgid.h +++ b/include/linux/uidgid.h @@ -109,12 +109,12 @@ static inline bool gid_lte(kgid_t left, kgid_t right) static inline bool uid_valid(kuid_t uid) { - return !uid_eq(uid, INVALID_UID); + return __kuid_val(uid) != (uid_t) -1; } static inline bool gid_valid(kgid_t gid) { - return !gid_eq(gid, INVALID_GID); + return __kgid_val(gid) != (gid_t) -1; } #ifdef CONFIG_USER_NS -- cgit v1.2.3 From 264ea103a7473f51aced838e68ed384ea2c759f5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 14 May 2015 14:26:56 -0700 Subject: tcp: syncookies: extend validity range Now we allow storing more request socks per listener, we might hit syncookie mode less often and hit following bug in our stack : When we send a burst of syncookies, then exit this mode, tcp_synq_no_recent_overflow() can return false if the ACK packets coming from clients are coming three seconds after the end of syncookie episode. This is a way too strong requirement and conflicts with rest of syncookie code which allows ACK to be aged up to 2 minutes. Perfectly valid ACK packets are dropped just because clients might be in a crowded wifi environment or on another planet. So let's fix this, and also change tcp_synq_overflow() to not dirty a cache line for every syncookie we send, as we are under attack. Signed-off-by: Eric Dumazet Acked-by: Florian Westphal Acked-by: Yuchung Cheng Signed-off-by: David S. Miller --- include/net/tcp.h | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index b8ea12880fd9..7ace6acbf5fd 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -326,18 +326,6 @@ static inline bool tcp_too_many_orphans(struct sock *sk, int shift) bool tcp_check_oom(struct sock *sk, int shift); -/* syncookies: remember time of last synqueue overflow */ -static inline void tcp_synq_overflow(struct sock *sk) -{ - tcp_sk(sk)->rx_opt.ts_recent_stamp = jiffies; -} - -/* syncookies: no recent synqueue overflow on this listening socket? */ -static inline bool tcp_synq_no_recent_overflow(const struct sock *sk) -{ - unsigned long last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp; - return time_after(jiffies, last_overflow + TCP_TIMEOUT_FALLBACK); -} extern struct proto tcp_prot; @@ -483,13 +471,35 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb); * i.e. a sent cookie is valid only at most for 2*60 seconds (or less if * the counter advances immediately after a cookie is generated). */ -#define MAX_SYNCOOKIE_AGE 2 +#define MAX_SYNCOOKIE_AGE 2 +#define TCP_SYNCOOKIE_PERIOD (60 * HZ) +#define TCP_SYNCOOKIE_VALID (MAX_SYNCOOKIE_AGE * TCP_SYNCOOKIE_PERIOD) + +/* syncookies: remember time of last synqueue overflow + * But do not dirty this field too often (once per second is enough) + */ +static inline void tcp_synq_overflow(struct sock *sk) +{ + unsigned long last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp; + unsigned long now = jiffies; + + if (time_after(now, last_overflow + HZ)) + tcp_sk(sk)->rx_opt.ts_recent_stamp = now; +} + +/* syncookies: no recent synqueue overflow on this listening socket? */ +static inline bool tcp_synq_no_recent_overflow(const struct sock *sk) +{ + unsigned long last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp; + + return time_after(jiffies, last_overflow + TCP_SYNCOOKIE_VALID); +} static inline u32 tcp_cookie_time(void) { u64 val = get_jiffies_64(); - do_div(val, 60 * HZ); + do_div(val, TCP_SYNCOOKIE_PERIOD); return val; } -- cgit v1.2.3 From a4afd37b26f4b9f640310a89b7f8d176ae3460b1 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 13 May 2015 13:12:43 +0200 Subject: test_bpf: add tests related to BPF_MAXINSNS Couple of torture test cases related to the bug fixed in 0b59d8806a31 ("ARM: net: delegate filter to kernel interpreter when imm_offset() return value can't fit into 12bits."). I've added a helper to allocate and fill the insn space. Output on x86_64 from my laptop: test_bpf: #233 BPF_MAXINSNS: Maximum possible literals jited:0 7 PASS test_bpf: #234 BPF_MAXINSNS: Single literal jited:0 8 PASS test_bpf: #235 BPF_MAXINSNS: Run/add until end jited:0 11553 PASS test_bpf: #236 BPF_MAXINSNS: Too many instructions PASS test_bpf: #237 BPF_MAXINSNS: Very long jump jited:0 9 PASS test_bpf: #238 BPF_MAXINSNS: Ctx heavy transformations jited:0 20329 20398 PASS test_bpf: #239 BPF_MAXINSNS: Call heavy transformations jited:0 32178 32475 PASS test_bpf: #240 BPF_MAXINSNS: Jump heavy test jited:0 10518 PASS test_bpf: #233 BPF_MAXINSNS: Maximum possible literals jited:1 4 PASS test_bpf: #234 BPF_MAXINSNS: Single literal jited:1 4 PASS test_bpf: #235 BPF_MAXINSNS: Run/add until end jited:1 1625 PASS test_bpf: #236 BPF_MAXINSNS: Too many instructions PASS test_bpf: #237 BPF_MAXINSNS: Very long jump jited:1 8 PASS test_bpf: #238 BPF_MAXINSNS: Ctx heavy transformations jited:1 3301 3174 PASS test_bpf: #239 BPF_MAXINSNS: Call heavy transformations jited:1 24107 23491 PASS test_bpf: #240 BPF_MAXINSNS: Jump heavy test jited:1 8651 PASS Signed-off-by: Daniel Borkmann Cc: Alexei Starovoitov Cc: Nicolas Schichan Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/filter.h | 8 ++ lib/test_bpf.c | 317 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 316 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/linux/filter.h b/include/linux/filter.h index ce1d72d34382..200be4a74a33 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -277,6 +277,14 @@ struct bpf_prog_aux; .off = 0, \ .imm = 0 }) +/* Internal classic blocks for direct assignment */ + +#define __BPF_STMT(CODE, K) \ + ((struct sock_filter) BPF_STMT(CODE, K)) + +#define __BPF_JUMP(CODE, K, JT, JF) \ + ((struct sock_filter) BPF_JUMP(CODE, K, JT, JF)) + #define bytes_to_bpf_size(bytes) \ ({ \ int bpf_size = -EINVAL; \ diff --git a/lib/test_bpf.c b/lib/test_bpf.c index 8bca780e3613..66358b21acce 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -21,6 +21,7 @@ #include #include #include +#include /* General test specific settings */ #define MAX_SUBTESTS 3 @@ -67,6 +68,10 @@ struct bpf_test { union { struct sock_filter insns[MAX_INSNS]; struct bpf_insn insns_int[MAX_INSNS]; + struct { + void *insns; + unsigned int len; + } ptr; } u; __u8 aux; __u8 data[MAX_DATA]; @@ -74,8 +79,190 @@ struct bpf_test { int data_size; __u32 result; } test[MAX_SUBTESTS]; + int (*fill_helper)(struct bpf_test *self); }; +/* Large test cases need separate allocation and fill handler. */ + +static int bpf_fill_maxinsns1(struct bpf_test *self) +{ + unsigned int len = BPF_MAXINSNS; + struct sock_filter *insn; + __u32 k = ~0; + int i; + + insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL); + if (!insn) + return -ENOMEM; + + for (i = 0; i < len; i++, k--) + insn[i] = __BPF_STMT(BPF_RET | BPF_K, k); + + self->u.ptr.insns = insn; + self->u.ptr.len = len; + + return 0; +} + +static int bpf_fill_maxinsns2(struct bpf_test *self) +{ + unsigned int len = BPF_MAXINSNS; + struct sock_filter *insn; + int i; + + insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL); + if (!insn) + return -ENOMEM; + + for (i = 0; i < len; i++) + insn[i] = __BPF_STMT(BPF_RET | BPF_K, 0xfefefefe); + + self->u.ptr.insns = insn; + self->u.ptr.len = len; + + return 0; +} + +static int bpf_fill_maxinsns3(struct bpf_test *self) +{ + unsigned int len = BPF_MAXINSNS; + struct sock_filter *insn; + struct rnd_state rnd; + int i; + + insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL); + if (!insn) + return -ENOMEM; + + prandom_seed_state(&rnd, 3141592653589793238ULL); + + for (i = 0; i < len - 1; i++) { + __u32 k = prandom_u32_state(&rnd); + + insn[i] = __BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, k); + } + + insn[len - 1] = __BPF_STMT(BPF_RET | BPF_A, 0); + + self->u.ptr.insns = insn; + self->u.ptr.len = len; + + return 0; +} + +static int bpf_fill_maxinsns4(struct bpf_test *self) +{ + unsigned int len = BPF_MAXINSNS + 1; + struct sock_filter *insn; + int i; + + insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL); + if (!insn) + return -ENOMEM; + + for (i = 0; i < len; i++) + insn[i] = __BPF_STMT(BPF_RET | BPF_K, 0xfefefefe); + + self->u.ptr.insns = insn; + self->u.ptr.len = len; + + return 0; +} + +static int bpf_fill_maxinsns5(struct bpf_test *self) +{ + unsigned int len = BPF_MAXINSNS; + struct sock_filter *insn; + int i; + + insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL); + if (!insn) + return -ENOMEM; + + insn[0] = __BPF_JUMP(BPF_JMP | BPF_JA, len - 2, 0, 0); + + for (i = 1; i < len - 1; i++) + insn[i] = __BPF_STMT(BPF_RET | BPF_K, 0xfefefefe); + + insn[len - 1] = __BPF_STMT(BPF_RET | BPF_K, 0xabababab); + + self->u.ptr.insns = insn; + self->u.ptr.len = len; + + return 0; +} + +static int bpf_fill_maxinsns6(struct bpf_test *self) +{ + unsigned int len = BPF_MAXINSNS; + struct sock_filter *insn; + int i; + + insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL); + if (!insn) + return -ENOMEM; + + for (i = 0; i < len - 1; i++) + insn[i] = __BPF_STMT(BPF_LD | BPF_W | BPF_ABS, SKF_AD_OFF + + SKF_AD_VLAN_TAG_PRESENT); + + insn[len - 1] = __BPF_STMT(BPF_RET | BPF_A, 0); + + self->u.ptr.insns = insn; + self->u.ptr.len = len; + + return 0; +} + +static int bpf_fill_maxinsns7(struct bpf_test *self) +{ + unsigned int len = BPF_MAXINSNS; + struct sock_filter *insn; + int i; + + insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL); + if (!insn) + return -ENOMEM; + + for (i = 0; i < len - 4; i++) + insn[i] = __BPF_STMT(BPF_LD | BPF_W | BPF_ABS, SKF_AD_OFF + + SKF_AD_CPU); + + insn[len - 4] = __BPF_STMT(BPF_MISC | BPF_TAX, 0); + insn[len - 3] = __BPF_STMT(BPF_LD | BPF_W | BPF_ABS, SKF_AD_OFF + + SKF_AD_CPU); + insn[len - 2] = __BPF_STMT(BPF_ALU | BPF_SUB | BPF_X, 0); + insn[len - 1] = __BPF_STMT(BPF_RET | BPF_A, 0); + + self->u.ptr.insns = insn; + self->u.ptr.len = len; + + return 0; +} + +static int bpf_fill_maxinsns8(struct bpf_test *self) +{ + unsigned int len = BPF_MAXINSNS; + struct sock_filter *insn; + int i, jmp_off = len - 3; + + insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL); + if (!insn) + return -ENOMEM; + + insn[0] = __BPF_STMT(BPF_LD | BPF_IMM, 0xffffffff); + + for (i = 1; i < len - 1; i++) + insn[i] = __BPF_JUMP(BPF_JMP | BPF_JGT, 0xffffffff, jmp_off--, 0); + + insn[len - 1] = __BPF_STMT(BPF_RET | BPF_A, 0); + + self->u.ptr.insns = insn; + self->u.ptr.len = len; + + return 0; +} + static struct bpf_test tests[] = { { "TAX", @@ -3998,6 +4185,73 @@ static struct bpf_test tests[] = { { }, { { 0, 1 } }, }, + { /* Mainly checking JIT here. */ + "BPF_MAXINSNS: Maximum possible literals", + { }, + CLASSIC | FLAG_NO_DATA, + { }, + { { 0, 0xffffffff } }, + .fill_helper = bpf_fill_maxinsns1, + }, + { /* Mainly checking JIT here. */ + "BPF_MAXINSNS: Single literal", + { }, + CLASSIC | FLAG_NO_DATA, + { }, + { { 0, 0xfefefefe } }, + .fill_helper = bpf_fill_maxinsns2, + }, + { /* Mainly checking JIT here. */ + "BPF_MAXINSNS: Run/add until end", + { }, + CLASSIC | FLAG_NO_DATA, + { }, + { { 0, 0x947bf368 } }, + .fill_helper = bpf_fill_maxinsns3, + }, + { + "BPF_MAXINSNS: Too many instructions", + { }, + CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, + { }, + { }, + .fill_helper = bpf_fill_maxinsns4, + }, + { /* Mainly checking JIT here. */ + "BPF_MAXINSNS: Very long jump", + { }, + CLASSIC | FLAG_NO_DATA, + { }, + { { 0, 0xabababab } }, + .fill_helper = bpf_fill_maxinsns5, + }, + { /* Mainly checking JIT here. */ + "BPF_MAXINSNS: Ctx heavy transformations", + { }, + CLASSIC, + { }, + { + { 1, !!(SKB_VLAN_TCI & VLAN_TAG_PRESENT) }, + { 10, !!(SKB_VLAN_TCI & VLAN_TAG_PRESENT) } + }, + .fill_helper = bpf_fill_maxinsns6, + }, + { /* Mainly checking JIT here. */ + "BPF_MAXINSNS: Call heavy transformations", + { }, + CLASSIC | FLAG_NO_DATA, + { }, + { { 1, 0 }, { 10, 0 } }, + .fill_helper = bpf_fill_maxinsns7, + }, + { /* Mainly checking JIT here. */ + "BPF_MAXINSNS: Jump heavy test", + { }, + CLASSIC | FLAG_NO_DATA, + { }, + { { 0, 0xffffffff } }, + .fill_helper = bpf_fill_maxinsns8, + }, }; static struct net_device dev; @@ -4051,10 +4305,15 @@ static void release_test_data(const struct bpf_test *test, void *data) kfree_skb(data); } -static int probe_filter_length(struct sock_filter *fp) +static int filter_length(int which) { - int len = 0; + struct sock_filter *fp; + int len; + if (tests[which].fill_helper) + return tests[which].u.ptr.len; + + fp = tests[which].u.insns; for (len = MAX_INSNS - 1; len > 0; --len) if (fp[len].code != 0 || fp[len].k != 0) break; @@ -4062,16 +4321,25 @@ static int probe_filter_length(struct sock_filter *fp) return len + 1; } +static void *filter_pointer(int which) +{ + if (tests[which].fill_helper) + return tests[which].u.ptr.insns; + else + return tests[which].u.insns; +} + static struct bpf_prog *generate_filter(int which, int *err) { - struct bpf_prog *fp; - struct sock_fprog_kern fprog; - unsigned int flen = probe_filter_length(tests[which].u.insns); __u8 test_type = tests[which].aux & TEST_TYPE_MASK; + unsigned int flen = filter_length(which); + void *fptr = filter_pointer(which); + struct sock_fprog_kern fprog; + struct bpf_prog *fp; switch (test_type) { case CLASSIC: - fprog.filter = tests[which].u.insns; + fprog.filter = fptr; fprog.len = flen; *err = bpf_prog_create(&fp, &fprog); @@ -4107,8 +4375,7 @@ static struct bpf_prog *generate_filter(int which, int *err) } fp->len = flen; - memcpy(fp->insnsi, tests[which].u.insns_int, - fp->len * sizeof(struct bpf_insn)); + memcpy(fp->insnsi, fptr, fp->len * sizeof(struct bpf_insn)); bpf_prog_select_runtime(fp); break; @@ -4180,6 +4447,29 @@ static int run_one(const struct bpf_prog *fp, struct bpf_test *test) return err_cnt; } +static __init int prepare_bpf_tests(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tests); i++) { + if (tests[i].fill_helper && + tests[i].fill_helper(&tests[i]) < 0) + return -ENOMEM; + } + + return 0; +} + +static __init void destroy_bpf_tests(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tests); i++) { + if (tests[i].fill_helper) + kfree(tests[i].u.ptr.insns); + } +} + static __init int test_bpf(void) { int i, err_cnt = 0, pass_cnt = 0; @@ -4227,7 +4517,16 @@ static __init int test_bpf(void) static int __init test_bpf_init(void) { - return test_bpf(); + int ret; + + ret = prepare_bpf_tests(); + if (ret < 0) + return ret; + + ret = test_bpf(); + + destroy_bpf_tests(); + return ret; } static void __exit test_bpf_exit(void) -- cgit v1.2.3 From ef7f3a5c7149ad2dbd1d8a71d0aa88a02d1dbcb8 Mon Sep 17 00:00:00 2001 From: Bert Vermeulen Date: Wed, 13 May 2015 13:35:39 +0200 Subject: mdio-gpio: Propagate mii_bus.phy_ignore_ta_mask This also changes mii_bus.phy_mask to u32 for consistency. Signed-off-by: Bert Vermeulen Signed-off-by: David S. Miller --- drivers/net/phy/mdio-gpio.c | 1 + include/linux/mdio-gpio.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 53d18150f4e2..7dc21e56a7aa 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -158,6 +158,7 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, new_bus->name = "GPIO Bitbanged MDIO", new_bus->phy_mask = pdata->phy_mask; + new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask; new_bus->irq = pdata->irqs; new_bus->parent = dev; diff --git a/include/linux/mdio-gpio.h b/include/linux/mdio-gpio.h index 66c30a763b10..11f00cdabe3d 100644 --- a/include/linux/mdio-gpio.h +++ b/include/linux/mdio-gpio.h @@ -23,7 +23,8 @@ struct mdio_gpio_platform_data { bool mdio_active_low; bool mdo_active_low; - unsigned int phy_mask; + u32 phy_mask; + u32 phy_ignore_ta_mask; int irqs[PHY_MAX_ADDR]; /* reset callback */ int (*reset)(struct mii_bus *bus); -- cgit v1.2.3 From eea39946a1f36e8a5a47c86e7ecfca6076868505 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Wed, 13 May 2015 21:17:41 -0700 Subject: rename RTNH_F_EXTERNAL to RTNH_F_OFFLOAD RTNH_F_EXTERNAL today is printed as "offload" in iproute2 output. This patch renames the flag to be consistent with what the user sees. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- include/uapi/linux/rtnetlink.h | 2 +- net/ipv4/fib_trie.c | 2 +- net/switchdev/switchdev.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 974db03f7b1a..17fb02f488da 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -337,7 +337,7 @@ struct rtnexthop { #define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */ #define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */ #define RTNH_F_ONLINK 4 /* Gateway is forced on link */ -#define RTNH_F_EXTERNAL 8 /* Route installed externally */ +#define RTNH_F_OFFLOAD 8 /* offloaded route */ /* Macros to handle hexthops */ diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index e13fcc602da2..64c2076ced54 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1764,7 +1764,7 @@ void fib_table_flush_external(struct fib_table *tb) /* record local slen */ slen = fa->fa_slen; - if (!fi || !(fi->fib_flags & RTNH_F_EXTERNAL)) + if (!fi || !(fi->fib_flags & RTNH_F_OFFLOAD)) continue; netdev_switch_fib_ipv4_del(n->key, diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 46568b85c333..055453d48668 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -338,7 +338,7 @@ int netdev_switch_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, fi, tos, type, nlflags, tb_id); if (!err) - fi->fib_flags |= RTNH_F_EXTERNAL; + fi->fib_flags |= RTNH_F_OFFLOAD; } return err; @@ -364,7 +364,7 @@ int netdev_switch_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, const struct swdev_ops *ops; int err = 0; - if (!(fi->fib_flags & RTNH_F_EXTERNAL)) + if (!(fi->fib_flags & RTNH_F_OFFLOAD)) return 0; dev = netdev_switch_get_dev_by_nhs(fi); @@ -376,7 +376,7 @@ int netdev_switch_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, err = ops->swdev_fib_ipv4_del(dev, htonl(dst), dst_len, fi, tos, type, tb_id); if (!err) - fi->fib_flags &= ~RTNH_F_EXTERNAL; + fi->fib_flags &= ~RTNH_F_OFFLOAD; } return err; -- cgit v1.2.3 From 55917a21d0cc012bb6073bb05bb768fd51d8e237 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 14 May 2015 14:57:23 +0200 Subject: netfilter: x_tables: add context to know if extension runs from nft_compat Currently, we have four xtables extensions that cannot be used from the xt over nft compat layer. The problem is that they need real access to the full blown xt_entry to validate that the rule comes with the right dependencies. This check was introduced to overcome the lack of sufficient userspace dependency validation in iptables. To resolve this problem, this patch introduces a new field to the xt_tgchk_param structure that tell us if the extension is run from nft_compat context. The three affected extensions are: 1) CLUSTERIP, this target has been superseded by xt_cluster. So just bail out by returning -EINVAL. 2) TCPMSS. Relax the checking when used from nft_compat. If used with the wrong configuration, it will corrupt !syn packets by adding TCP MSS option. 3) ebt_stp. Relax the check to make sure it uses the reserved destination MAC address for STP. Signed-off-by: Pablo Neira Ayuso Tested-by: Arturo Borrero Gonzalez --- include/linux/netfilter/x_tables.h | 2 ++ net/bridge/netfilter/ebt_stp.c | 6 ++++-- net/ipv4/netfilter/ipt_CLUSTERIP.c | 5 +++++ net/netfilter/nft_compat.c | 2 ++ net/netfilter/xt_TCPMSS.c | 6 ++++++ 5 files changed, 19 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index a3e215bb0241..09f38206c18f 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -62,6 +62,7 @@ struct xt_mtchk_param { void *matchinfo; unsigned int hook_mask; u_int8_t family; + bool nft_compat; }; /** @@ -92,6 +93,7 @@ struct xt_tgchk_param { void *targinfo; unsigned int hook_mask; u_int8_t family; + bool nft_compat; }; /* Target destructor parameters */ diff --git a/net/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c index 071d87214dde..0c40570069ba 100644 --- a/net/bridge/netfilter/ebt_stp.c +++ b/net/bridge/netfilter/ebt_stp.c @@ -164,8 +164,10 @@ static int ebt_stp_mt_check(const struct xt_mtchk_param *par) !(info->bitmask & EBT_STP_MASK)) return -EINVAL; /* Make sure the match only receives stp frames */ - if (!ether_addr_equal(e->destmac, bridge_ula) || - !ether_addr_equal(e->destmsk, msk) || !(e->bitmask & EBT_DESTMAC)) + if (!par->nft_compat && + (!ether_addr_equal(e->destmac, bridge_ula) || + !ether_addr_equal(e->destmsk, msk) || + !(e->bitmask & EBT_DESTMAC))) return -EINVAL; return 0; diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 771ab3d01ad3..45cb16a6a4a3 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -367,6 +367,11 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) struct clusterip_config *config; int ret; + if (par->nft_compat) { + pr_err("cannot use CLUSTERIP target from nftables compat\n"); + return -EOPNOTSUPP; + } + if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP && cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT && cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) { diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index 7f29cfc76349..66def315eb56 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c @@ -161,6 +161,7 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par, par->hook_mask = 0; } par->family = ctx->afi->family; + par->nft_compat = true; } static void target_compat_from_user(struct xt_target *t, void *in, void *out) @@ -377,6 +378,7 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, par->hook_mask = 0; } par->family = ctx->afi->family; + par->nft_compat = true; } static void match_compat_from_user(struct xt_match *m, void *in, void *out) diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index e762de5ee89b..8c3190e2fc6a 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c @@ -277,6 +277,9 @@ static int tcpmss_tg4_check(const struct xt_tgchk_param *par) "FORWARD, OUTPUT and POSTROUTING hooks\n"); return -EINVAL; } + if (par->nft_compat) + return 0; + xt_ematch_foreach(ematch, e) if (find_syn_match(ematch)) return 0; @@ -299,6 +302,9 @@ static int tcpmss_tg6_check(const struct xt_tgchk_param *par) "FORWARD, OUTPUT and POSTROUTING hooks\n"); return -EINVAL; } + if (par->nft_compat) + return 0; + xt_ematch_foreach(ematch, e) if (find_syn_match(ematch)) return 0; -- cgit v1.2.3 From b3cad287d13b5f6695c6b4aab72969cd64bf0171 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Thu, 7 May 2015 14:54:16 +0200 Subject: conntrack: RFC5961 challenge ACK confuse conntrack LAST-ACK transition In compliance with RFC5961, the network stack send challenge ACK in response to spurious SYN packets, since commit 0c228e833c88 ("tcp: Restore RFC5961-compliant behavior for SYN packets"). This pose a problem for netfilter conntrack in state LAST_ACK, because this challenge ACK is (falsely) seen as ACKing last FIN, causing a false state transition (into TIME_WAIT). The challenge ACK is hard to distinguish from real last ACK. Thus, solution introduce a flag that tracks the potential for seeing a challenge ACK, in case a SYN packet is let through and current state is LAST_ACK. When conntrack transition LAST_ACK to TIME_WAIT happens, this flag is used for determining if we are expecting a challenge ACK. Scapy based reproducer script avail here: https://github.com/netoptimizer/network-testing/blob/master/scapy/tcp_hacks_3WHS_LAST_ACK.py Fixes: 0c228e833c88 ("tcp: Restore RFC5961-compliant behavior for SYN packets") Signed-off-by: Jesper Dangaard Brouer Acked-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso --- include/uapi/linux/netfilter/nf_conntrack_tcp.h | 3 +++ net/netfilter/nf_conntrack_proto_tcp.c | 35 ++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/netfilter/nf_conntrack_tcp.h b/include/uapi/linux/netfilter/nf_conntrack_tcp.h index 9993a421201c..ef9f80f0f529 100644 --- a/include/uapi/linux/netfilter/nf_conntrack_tcp.h +++ b/include/uapi/linux/netfilter/nf_conntrack_tcp.h @@ -42,6 +42,9 @@ enum tcp_conntrack { /* The field td_maxack has been set */ #define IP_CT_TCP_FLAG_MAXACK_SET 0x20 +/* Marks possibility for expected RFC5961 challenge ACK */ +#define IP_CT_EXP_CHALLENGE_ACK 0x40 + struct nf_ct_tcp_flags { __u8 flags; __u8 mask; diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 5caa0c41bf26..70383de72054 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -202,7 +202,7 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sES -> sES :-) * sFW -> sCW Normal close request answered by ACK. * sCW -> sCW - * sLA -> sTW Last ACK detected. + * sLA -> sTW Last ACK detected (RFC5961 challenged) * sTW -> sTW Retransmitted last ACK. Remain in the same state. * sCL -> sCL */ @@ -261,7 +261,7 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sES -> sES :-) * sFW -> sCW Normal close request answered by ACK. * sCW -> sCW - * sLA -> sTW Last ACK detected. + * sLA -> sTW Last ACK detected (RFC5961 challenged) * sTW -> sTW Retransmitted last ACK. * sCL -> sCL */ @@ -906,6 +906,7 @@ static int tcp_packet(struct nf_conn *ct, 1 : ct->proto.tcp.last_win; ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_scale = ct->proto.tcp.last_wscale; + ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK; ct->proto.tcp.seen[ct->proto.tcp.last_dir].flags = ct->proto.tcp.last_flags; memset(&ct->proto.tcp.seen[dir], 0, @@ -923,7 +924,9 @@ static int tcp_packet(struct nf_conn *ct, * may be in sync but we are not. In that case, we annotate * the TCP options and let the packet go through. If it is a * valid SYN packet, the server will reply with a SYN/ACK, and - * then we'll get in sync. Otherwise, the server ignores it. */ + * then we'll get in sync. Otherwise, the server potentially + * responds with a challenge ACK if implementing RFC5961. + */ if (index == TCP_SYN_SET && dir == IP_CT_DIR_ORIGINAL) { struct ip_ct_tcp_state seen = {}; @@ -939,6 +942,13 @@ static int tcp_packet(struct nf_conn *ct, ct->proto.tcp.last_flags |= IP_CT_TCP_FLAG_SACK_PERM; } + /* Mark the potential for RFC5961 challenge ACK, + * this pose a special problem for LAST_ACK state + * as ACK is intrepretated as ACKing last FIN. + */ + if (old_state == TCP_CONNTRACK_LAST_ACK) + ct->proto.tcp.last_flags |= + IP_CT_EXP_CHALLENGE_ACK; } spin_unlock_bh(&ct->lock); if (LOG_INVALID(net, IPPROTO_TCP)) @@ -970,6 +980,25 @@ static int tcp_packet(struct nf_conn *ct, nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: invalid state "); return -NF_ACCEPT; + case TCP_CONNTRACK_TIME_WAIT: + /* RFC5961 compliance cause stack to send "challenge-ACK" + * e.g. in response to spurious SYNs. Conntrack MUST + * not believe this ACK is acking last FIN. + */ + if (old_state == TCP_CONNTRACK_LAST_ACK && + index == TCP_ACK_SET && + ct->proto.tcp.last_dir != dir && + ct->proto.tcp.last_index == TCP_SYN_SET && + (ct->proto.tcp.last_flags & IP_CT_EXP_CHALLENGE_ACK)) { + /* Detected RFC5961 challenge ACK */ + ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK; + spin_unlock_bh(&ct->lock); + if (LOG_INVALID(net, IPPROTO_TCP)) + nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, + "nf_ct_tcp: challenge-ACK ignored "); + return NF_ACCEPT; /* Don't change state */ + } + break; case TCP_CONNTRACK_CLOSE: if (index == TCP_RST_SET && (ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET) -- cgit v1.2.3 From 07ee0722bf941960fb3888f9c9b5839473372fd1 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 15 May 2015 11:30:47 +0800 Subject: rhashtable: Add cap on number of elements in hash table We currently have no limit on the number of elements in a hash table. This is a problem because some users (tipc) set a ceiling on the maximum table size and when that is reached the hash table may degenerate. Others may encounter OOM when growing and if we allow insertions when that happens the hash table perofrmance may also suffer. This patch adds a new paramater insecure_max_entries which becomes the cap on the table. If unset it defaults to max_size * 2. If it is also zero it means that there is no cap on the number of elements in the table. However, the table will grow whenever the utilisation hits 100% and if that growth fails, you will get ENOMEM on insertion. As allowing oversubscription is potentially dangerous, the name contains the word insecure. Note that the cap is not a hard limit. This is done for performance reasons as enforcing a hard limit will result in use of atomic ops that are heavier than the ones we currently use. The reasoning is that we're only guarding against a gross over- subscription of the table, rather than a small breach of the limit. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/rhashtable.h | 19 +++++++++++++++++++ lib/rhashtable.c | 11 +++++++++++ 2 files changed, 30 insertions(+) (limited to 'include') diff --git a/include/linux/rhashtable.h b/include/linux/rhashtable.h index dbcbcc59aa92..843ceca9a21e 100644 --- a/include/linux/rhashtable.h +++ b/include/linux/rhashtable.h @@ -17,6 +17,7 @@ #ifndef _LINUX_RHASHTABLE_H #define _LINUX_RHASHTABLE_H +#include #include #include #include @@ -100,6 +101,7 @@ struct rhashtable; * @key_len: Length of key * @key_offset: Offset of key in struct to be hashed * @head_offset: Offset of rhash_head in struct to be hashed + * @insecure_max_entries: Maximum number of entries (may be exceeded) * @max_size: Maximum size while expanding * @min_size: Minimum size while shrinking * @nulls_base: Base value to generate nulls marker @@ -115,6 +117,7 @@ struct rhashtable_params { size_t key_len; size_t key_offset; size_t head_offset; + unsigned int insecure_max_entries; unsigned int max_size; unsigned int min_size; u32 nulls_base; @@ -286,6 +289,18 @@ static inline bool rht_grow_above_100(const struct rhashtable *ht, (!ht->p.max_size || tbl->size < ht->p.max_size); } +/** + * rht_grow_above_max - returns true if table is above maximum + * @ht: hash table + * @tbl: current table + */ +static inline bool rht_grow_above_max(const struct rhashtable *ht, + const struct bucket_table *tbl) +{ + return ht->p.insecure_max_entries && + atomic_read(&ht->nelems) >= ht->p.insecure_max_entries; +} + /* The bucket lock is selected based on the hash and protects mutations * on a group of hash buckets. * @@ -589,6 +604,10 @@ restart: goto out; } + err = -E2BIG; + if (unlikely(rht_grow_above_max(ht, tbl))) + goto out; + if (unlikely(rht_grow_above_100(ht, tbl))) { slow_path: spin_unlock_bh(lock); diff --git a/lib/rhashtable.c b/lib/rhashtable.c index b28df4019ade..4396434e4715 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -14,6 +14,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -446,6 +447,10 @@ int rhashtable_insert_slow(struct rhashtable *ht, const void *key, if (key && rhashtable_lookup_fast(ht, key, ht->p)) goto exit; + err = -E2BIG; + if (unlikely(rht_grow_above_max(ht, tbl))) + goto exit; + err = -EAGAIN; if (rhashtable_check_elasticity(ht, tbl, hash) || rht_grow_above_100(ht, tbl)) @@ -738,6 +743,12 @@ int rhashtable_init(struct rhashtable *ht, if (params->max_size) ht->p.max_size = rounddown_pow_of_two(params->max_size); + if (params->insecure_max_entries) + ht->p.insecure_max_entries = + rounddown_pow_of_two(params->insecure_max_entries); + else + ht->p.insecure_max_entries = ht->p.max_size * 2; + ht->p.min_size = max(ht->p.min_size, HASH_MIN_SIZE); /* The maximum (not average) chain length grows with the -- cgit v1.2.3 From d53a2aa3a116609c7db8799da31541c4ba5999eb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 15 May 2015 08:52:19 -0700 Subject: net: fix sparse error in csum_replace4() make C=2 CF=-D__CHECK_ENDIAN__ net/ipv4/netfilter/nf_nat_l3proto_ipv4.o CHECK net/ipv4/netfilter/nf_nat_l3proto_ipv4.c include/net/checksum.h:125:64: warning: incorrect type in argument 2 (different base types) include/net/checksum.h:125:64: expected restricted __wsum [usertype] addend include/net/checksum.h:125:64: got restricted __be32 [usertype] from include/net/checksum.h:125:71: warning: incorrect type in argument 2 (different base types) include/net/checksum.h:125:71: expected restricted __wsum [usertype] addend include/net/checksum.h:125:71: got restricted __be32 [usertype] to include/net/checksum.h:125:64: warning: incorrect type in argument 2 (different base types) include/net/checksum.h:125:64: expected restricted __wsum [usertype] addend include/net/checksum.h:125:64: got restricted __be32 [usertype] from include/net/checksum.h:125:71: warning: incorrect type in argument 2 (different base types) include/net/checksum.h:125:71: expected restricted __wsum [usertype] addend include/net/checksum.h:125:71: got restricted __be32 [usertype] to Fixes: 4565af0d406b ("net: optimise csum_replace4()") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/checksum.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/checksum.h b/include/net/checksum.h index 0a55ac715077..2d1d73cb773e 100644 --- a/include/net/checksum.h +++ b/include/net/checksum.h @@ -122,7 +122,9 @@ static inline __wsum csum_partial_ext(const void *buff, int len, __wsum sum) static inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to) { - *sum = csum_fold(csum_add(csum_sub(~csum_unfold(*sum), from), to)); + __wsum tmp = csum_sub(~csum_unfold(*sum), (__force __wsum)from); + + *sum = csum_fold(csum_add(tmp, (__force __wsum)to)); } /* Implements RFC 1624 (Incremental Internet Checksum) -- cgit v1.2.3 From c91d46065209bfe6124396fc409765ced0601b59 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 15 May 2015 05:48:07 -0700 Subject: net: fix two sparse errors First one in __skb_checksum_validate_complete() fixes the following (and other callers) make C=2 CF=-D__CHECK_ENDIAN__ net/ipv4/tcp_ipv4.o CHECK net/ipv4/tcp_ipv4.c include/linux/skbuff.h:3052:24: warning: incorrect type in return expression (different base types) include/linux/skbuff.h:3052:24: expected restricted __sum16 include/linux/skbuff.h:3052:24: got int Second is fixing gso_make_checksum() : CHECK net/ipv4/gre_offload.c include/linux/skbuff.h:3360:14: warning: incorrect type in assignment (different base types) include/linux/skbuff.h:3360:14: expected unsigned short [unsigned] [usertype] csum include/linux/skbuff.h:3360:14: got restricted __sum16 include/linux/skbuff.h:3365:16: warning: incorrect type in return expression (different base types) include/linux/skbuff.h:3365:16: expected restricted __sum16 include/linux/skbuff.h:3365:16: got unsigned short [unsigned] [usertype] csum Fixes: 5a21232983aa7 ("net: Support for csum_bad in skbuff") Fixes: 7e2b10c1e52ca ("net: Support for multiple checksums with gso") Signed-off-by: Eric Dumazet CC: Tom Herbert Acked-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/skbuff.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index f83aa6568cbf..b57eebfb67e0 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3051,7 +3051,7 @@ static inline __sum16 __skb_checksum_validate_complete(struct sk_buff *skb, } } else if (skb->csum_bad) { /* ip_summed == CHECKSUM_NONE in this case */ - return 1; + return (__force __sum16)1; } skb->csum = psum; @@ -3353,15 +3353,14 @@ static inline int gso_pskb_expand_head(struct sk_buff *skb, int extra) static inline __sum16 gso_make_checksum(struct sk_buff *skb, __wsum res) { int plen = SKB_GSO_CB(skb)->csum_start - skb_headroom(skb) - - skb_transport_offset(skb); - __u16 csum; + skb_transport_offset(skb); + __wsum partial; - csum = csum_fold(csum_partial(skb_transport_header(skb), - plen, skb->csum)); + partial = csum_partial(skb_transport_header(skb), plen, skb->csum); skb->csum = res; SKB_GSO_CB(skb)->csum_start -= plen; - return csum; + return csum_fold(partial); } static inline bool skb_is_gso(const struct sk_buff *skb) -- cgit v1.2.3 From 1a24e04e4b50939daa3041682b38b82c896ca438 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 15 May 2015 12:39:25 -0700 Subject: net: fix sk_mem_reclaim_partial() sk_mem_reclaim_partial() goal is to ensure each socket has one SK_MEM_QUANTUM forward allocation. This is needed both for performance and better handling of memory pressure situations in follow up patches. SK_MEM_QUANTUM is currently a page, but might be reduced to 4096 bytes as some arches have 64KB pages. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 6 +++--- net/core/sock.c | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/net/sock.h b/include/net/sock.h index d882f4c8e438..4581a60636f8 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1368,7 +1368,7 @@ static inline struct inode *SOCK_INODE(struct socket *socket) * Functions for memory accounting */ int __sk_mem_schedule(struct sock *sk, int size, int kind); -void __sk_mem_reclaim(struct sock *sk); +void __sk_mem_reclaim(struct sock *sk, int amount); #define SK_MEM_QUANTUM ((int)PAGE_SIZE) #define SK_MEM_QUANTUM_SHIFT ilog2(SK_MEM_QUANTUM) @@ -1409,7 +1409,7 @@ static inline void sk_mem_reclaim(struct sock *sk) if (!sk_has_account(sk)) return; if (sk->sk_forward_alloc >= SK_MEM_QUANTUM) - __sk_mem_reclaim(sk); + __sk_mem_reclaim(sk, sk->sk_forward_alloc); } static inline void sk_mem_reclaim_partial(struct sock *sk) @@ -1417,7 +1417,7 @@ static inline void sk_mem_reclaim_partial(struct sock *sk) if (!sk_has_account(sk)) return; if (sk->sk_forward_alloc > SK_MEM_QUANTUM) - __sk_mem_reclaim(sk); + __sk_mem_reclaim(sk, sk->sk_forward_alloc - 1); } static inline void sk_mem_charge(struct sock *sk, int size) diff --git a/net/core/sock.c b/net/core/sock.c index c18738a795b0..29124fcdc42a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2069,12 +2069,13 @@ EXPORT_SYMBOL(__sk_mem_schedule); /** * __sk_reclaim - reclaim memory_allocated * @sk: socket + * @amount: number of bytes (rounded down to a SK_MEM_QUANTUM multiple) */ -void __sk_mem_reclaim(struct sock *sk) +void __sk_mem_reclaim(struct sock *sk, int amount) { - sk_memory_allocated_sub(sk, - sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT); - sk->sk_forward_alloc &= SK_MEM_QUANTUM - 1; + amount >>= SK_MEM_QUANTUM_SHIFT; + sk_memory_allocated_sub(sk, amount); + sk->sk_forward_alloc -= amount << SK_MEM_QUANTUM_SHIFT; if (sk_under_memory_pressure(sk) && (sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0))) -- cgit v1.2.3 From a6c5ea4ccf0033591e6e476d7a273c0074c07aa7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 15 May 2015 12:39:26 -0700 Subject: tcp: rename sk_forced_wmem_schedule() to sk_forced_mem_schedule() We plan to use sk_forced_wmem_schedule() in input path as well, so make it non static and rename it. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/tcp.h | 2 ++ net/ipv4/tcp_output.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index 7ace6acbf5fd..841691a296dc 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -311,6 +311,8 @@ static inline bool tcp_out_of_memory(struct sock *sk) return false; } +void sk_forced_mem_schedule(struct sock *sk, int size); + static inline bool tcp_too_many_orphans(struct sock *sk, int shift) { struct percpu_counter *ocp = sk->sk_prot->orphan_count; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 7386d32cd670..bac1a950d087 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2816,8 +2816,10 @@ begin_fwd: * connection tear down and (memory) recovery. * Otherwise tcp_send_fin() could be tempted to either delay FIN * or even be forced to close flow without any FIN. + * In general, we want to allow one skb per socket to avoid hangs + * with edge trigger epoll() */ -static void sk_forced_wmem_schedule(struct sock *sk, int size) +void sk_forced_mem_schedule(struct sock *sk, int size) { int amt, status; @@ -2864,7 +2866,7 @@ coalesce: return; } skb_reserve(skb, MAX_TCP_HEADER); - sk_forced_wmem_schedule(sk, skb->truesize); + sk_forced_mem_schedule(sk, skb->truesize); /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */ tcp_init_nondata_skb(skb, tp->write_seq, TCPHDR_ACK | TCPHDR_FIN); -- cgit v1.2.3 From b8da51ebb1aa93908350f95efae73aecbc2e266c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 15 May 2015 12:39:27 -0700 Subject: tcp: introduce tcp_under_memory_pressure() Introduce an optimized version of sk_under_memory_pressure() for TCP. Our intent is to use it in fast paths. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/tcp.h | 8 ++++++++ net/ipv4/tcp_input.c | 8 ++++---- net/ipv4/tcp_output.c | 4 ++-- net/ipv4/tcp_timer.c | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index 841691a296dc..0d85223efa4c 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -286,6 +286,14 @@ extern atomic_long_t tcp_memory_allocated; extern struct percpu_counter tcp_sockets_allocated; extern int tcp_memory_pressure; +/* optimized version of sk_under_memory_pressure() for TCP sockets */ +static inline bool tcp_under_memory_pressure(const struct sock *sk) +{ + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) + return !!sk->sk_cgrp->memory_pressure; + + return tcp_memory_pressure; +} /* * The next routines deal with comparing 32 bit unsigned ints * and worry about wraparound (automatic with unsigned arithmetic). diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index cf8b20ff6658..093779f7e893 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -359,7 +359,7 @@ static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb) /* Check #1 */ if (tp->rcv_ssthresh < tp->window_clamp && (int)tp->rcv_ssthresh < tcp_space(sk) && - !sk_under_memory_pressure(sk)) { + !tcp_under_memory_pressure(sk)) { int incr; /* Check #2. Increase window, if skb with such overhead @@ -446,7 +446,7 @@ static void tcp_clamp_window(struct sock *sk) if (sk->sk_rcvbuf < sysctl_tcp_rmem[2] && !(sk->sk_userlocks & SOCK_RCVBUF_LOCK) && - !sk_under_memory_pressure(sk) && + !tcp_under_memory_pressure(sk) && sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0)) { sk->sk_rcvbuf = min(atomic_read(&sk->sk_rmem_alloc), sysctl_tcp_rmem[2]); @@ -4781,7 +4781,7 @@ static int tcp_prune_queue(struct sock *sk) if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) tcp_clamp_window(sk); - else if (sk_under_memory_pressure(sk)) + else if (tcp_under_memory_pressure(sk)) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); tcp_collapse_ofo_queue(sk); @@ -4825,7 +4825,7 @@ static bool tcp_should_expand_sndbuf(const struct sock *sk) return false; /* If we are under global TCP memory pressure, do not expand. */ - if (sk_under_memory_pressure(sk)) + if (tcp_under_memory_pressure(sk)) return false; /* If we are under soft global TCP memory pressure, do not expand. */ diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index bac1a950d087..08c2cc40b26d 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2392,7 +2392,7 @@ u32 __tcp_select_window(struct sock *sk) if (free_space < (full_space >> 1)) { icsk->icsk_ack.quick = 0; - if (sk_under_memory_pressure(sk)) + if (tcp_under_memory_pressure(sk)) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); @@ -2843,7 +2843,7 @@ void tcp_send_fin(struct sock *sk) * Note: in the latter case, FIN packet will be sent after a timeout, * as TCP stack thinks it has already been transmitted. */ - if (tskb && (tcp_send_head(sk) || sk_under_memory_pressure(sk))) { + if (tskb && (tcp_send_head(sk) || tcp_under_memory_pressure(sk))) { coalesce: TCP_SKB_CB(tskb)->tcp_flags |= TCPHDR_FIN; TCP_SKB_CB(tskb)->end_seq++; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 65bf670e8714..5b752f58a900 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -247,7 +247,7 @@ void tcp_delack_timer_handler(struct sock *sk) } out: - if (sk_under_memory_pressure(sk)) + if (tcp_under_memory_pressure(sk)) sk_mem_reclaim(sk); } -- cgit v1.2.3 From 45d4122ca7cdb3a4b91f392605cd22cfa75f1d99 Mon Sep 17 00:00:00 2001 From: "Samudrala, Sridhar" Date: Wed, 13 May 2015 21:55:43 -0700 Subject: switchdev: add support for fdb add/del/dump via switchdev_port_obj ops. - introduce port fdb obj and generic switchdev_port_fdb_add/del/dump() - use switchdev_port_fdb_add/del/dump in rocker/team/bonding ndo ops. - add support for fdb obj in switchdev_port_obj_add/del/dump() - switch rocker to implement fdb ops via switchdev_ops v3: updated to sync with named union changes. Signed-off-by: Sridhar Samudrala Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 3 + drivers/net/ethernet/rocker/rocker.c | 188 +++++++++++++++-------------------- drivers/net/team/team.c | 3 + include/net/switchdev.h | 50 ++++++++++ net/switchdev/switchdev.c | 175 ++++++++++++++++++++++++++++++++ 5 files changed, 312 insertions(+), 107 deletions(-) (limited to 'include') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ef26e0147050..2268438f3f63 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4039,6 +4039,9 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_bridge_setlink = switchdev_port_bridge_setlink, .ndo_bridge_getlink = switchdev_port_bridge_getlink, .ndo_bridge_dellink = switchdev_port_bridge_dellink, + .ndo_fdb_add = switchdev_port_fdb_add, + .ndo_fdb_del = switchdev_port_fdb_del, + .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_features_check = passthru_features_check, }; diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 3e13dcccd73d..0f5e962d691c 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4193,110 +4193,6 @@ static int rocker_port_vlan_rx_kill_vid(struct net_device *dev, ROCKER_OP_FLAG_REMOVE, vid); } -static int rocker_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *dev, - const unsigned char *addr, u16 vid, - u16 nlm_flags) -{ - struct rocker_port *rocker_port = netdev_priv(dev); - __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, vid, NULL); - int flags = 0; - - if (!rocker_port_is_bridged(rocker_port)) - return -EINVAL; - - return rocker_port_fdb(rocker_port, SWITCHDEV_TRANS_NONE, - addr, vlan_id, flags); -} - -static int rocker_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *dev, - const unsigned char *addr, u16 vid) -{ - struct rocker_port *rocker_port = netdev_priv(dev); - __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, vid, NULL); - int flags = ROCKER_OP_FLAG_REMOVE; - - if (!rocker_port_is_bridged(rocker_port)) - return -EINVAL; - - return rocker_port_fdb(rocker_port, SWITCHDEV_TRANS_NONE, - addr, vlan_id, flags); -} - -static int rocker_fdb_fill_info(struct sk_buff *skb, - struct rocker_port *rocker_port, - const unsigned char *addr, u16 vid, - u32 portid, u32 seq, int type, - unsigned int flags) -{ - struct nlmsghdr *nlh; - struct ndmsg *ndm; - - nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags); - if (!nlh) - return -EMSGSIZE; - - ndm = nlmsg_data(nlh); - ndm->ndm_family = AF_BRIDGE; - ndm->ndm_pad1 = 0; - ndm->ndm_pad2 = 0; - ndm->ndm_flags = NTF_SELF; - ndm->ndm_type = 0; - ndm->ndm_ifindex = rocker_port->dev->ifindex; - ndm->ndm_state = NUD_REACHABLE; - - if (nla_put(skb, NDA_LLADDR, ETH_ALEN, addr)) - goto nla_put_failure; - - if (vid && nla_put_u16(skb, NDA_VLAN, vid)) - goto nla_put_failure; - - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static int rocker_port_fdb_dump(struct sk_buff *skb, - struct netlink_callback *cb, - struct net_device *dev, - struct net_device *filter_dev, - int idx) -{ - struct rocker_port *rocker_port = netdev_priv(dev); - struct rocker *rocker = rocker_port->rocker; - struct rocker_fdb_tbl_entry *found; - struct hlist_node *tmp; - int bkt; - unsigned long lock_flags; - const unsigned char *addr; - u16 vid; - int err; - - spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags); - hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) { - if (found->key.pport != rocker_port->pport) - continue; - if (idx < cb->args[0]) - goto skip; - addr = found->key.addr; - vid = rocker_port_vlan_to_vid(rocker_port, found->key.vlan_id); - err = rocker_fdb_fill_info(skb, rocker_port, addr, vid, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWNEIGH, NLM_F_MULTI); - if (err < 0) - break; -skip: - ++idx; - } - spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags); - return idx; -} - static int rocker_port_get_phys_port_name(struct net_device *dev, char *buf, size_t len) { @@ -4320,12 +4216,12 @@ static const struct net_device_ops rocker_port_netdev_ops = { .ndo_set_mac_address = rocker_port_set_mac_address, .ndo_vlan_rx_add_vid = rocker_port_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = rocker_port_vlan_rx_kill_vid, - .ndo_fdb_add = rocker_port_fdb_add, - .ndo_fdb_del = rocker_port_fdb_del, - .ndo_fdb_dump = rocker_port_fdb_dump, .ndo_bridge_getlink = switchdev_port_bridge_getlink, .ndo_bridge_setlink = switchdev_port_bridge_setlink, .ndo_bridge_dellink = switchdev_port_bridge_dellink, + .ndo_fdb_add = switchdev_port_fdb_add, + .ndo_fdb_del = switchdev_port_fdb_del, + .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_get_phys_port_name = rocker_port_get_phys_port_name, }; @@ -4447,6 +4343,19 @@ static int rocker_port_vlans_add(struct rocker_port *rocker_port, return 0; } +static int rocker_port_fdb_add(struct rocker_port *rocker_port, + enum switchdev_trans trans, + struct switchdev_obj_fdb *fdb) +{ + __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL); + int flags = 0; + + if (!rocker_port_is_bridged(rocker_port)) + return -EINVAL; + + return rocker_port_fdb(rocker_port, trans, fdb->addr, vlan_id, flags); +} + static int rocker_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) { @@ -4476,6 +4385,9 @@ static int rocker_port_obj_add(struct net_device *dev, htonl(fib4->dst), fib4->dst_len, fib4->fi, fib4->tb_id, 0); break; + case SWITCHDEV_OBJ_PORT_FDB: + err = rocker_port_fdb_add(rocker_port, obj->trans, &obj->u.fdb); + break; default: err = -EOPNOTSUPP; break; @@ -4513,6 +4425,19 @@ static int rocker_port_vlans_del(struct rocker_port *rocker_port, return 0; } +static int rocker_port_fdb_del(struct rocker_port *rocker_port, + enum switchdev_trans trans, + struct switchdev_obj_fdb *fdb) +{ + __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL); + int flags = ROCKER_OP_FLAG_REMOVE; + + if (!rocker_port_is_bridged(rocker_port)) + return -EINVAL; + + return rocker_port_fdb(rocker_port, trans, fdb->addr, vlan_id, flags); +} + static int rocker_port_obj_del(struct net_device *dev, struct switchdev_obj *obj) { @@ -4531,6 +4456,54 @@ static int rocker_port_obj_del(struct net_device *dev, fib4->fi, fib4->tb_id, ROCKER_OP_FLAG_REMOVE); break; + case SWITCHDEV_OBJ_PORT_FDB: + err = rocker_port_fdb_del(rocker_port, obj->trans, &obj->u.fdb); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static int rocker_port_fdb_dump(struct rocker_port *rocker_port, + struct switchdev_obj *obj) +{ + struct rocker *rocker = rocker_port->rocker; + struct switchdev_obj_fdb *fdb = &obj->u.fdb; + struct rocker_fdb_tbl_entry *found; + struct hlist_node *tmp; + unsigned long lock_flags; + int bkt; + int err = 0; + + spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags); + hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) { + if (found->key.pport != rocker_port->pport) + continue; + fdb->addr = found->key.addr; + fdb->vid = rocker_port_vlan_to_vid(rocker_port, + found->key.vlan_id); + err = obj->cb(rocker_port->dev, obj); + if (err) + break; + } + spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags); + + return err; +} + +static int rocker_port_obj_dump(struct net_device *dev, + struct switchdev_obj *obj) +{ + struct rocker_port *rocker_port = netdev_priv(dev); + int err = 0; + + switch (obj->id) { + case SWITCHDEV_OBJ_PORT_FDB: + err = rocker_port_fdb_dump(rocker_port, obj); + break; default: err = -EOPNOTSUPP; break; @@ -4544,6 +4517,7 @@ static const struct switchdev_ops rocker_port_switchdev_ops = { .switchdev_port_attr_set = rocker_port_attr_set, .switchdev_port_obj_add = rocker_port_obj_add, .switchdev_port_obj_del = rocker_port_obj_del, + .switchdev_port_obj_dump = rocker_port_obj_dump, }; /******************** diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 1ec035a53c3d..daa054b3ff03 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1980,6 +1980,9 @@ static const struct net_device_ops team_netdev_ops = { .ndo_bridge_setlink = switchdev_port_bridge_setlink, .ndo_bridge_getlink = switchdev_port_bridge_getlink, .ndo_bridge_dellink = switchdev_port_bridge_dellink, + .ndo_fdb_add = switchdev_port_fdb_add, + .ndo_fdb_del = switchdev_port_fdb_del, + .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_features_check = passthru_features_check, }; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index ea5b1c230d3d..437f8fe75705 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -47,11 +47,13 @@ enum switchdev_obj_id { SWITCHDEV_OBJ_UNDEFINED, SWITCHDEV_OBJ_PORT_VLAN, SWITCHDEV_OBJ_IPV4_FIB, + SWITCHDEV_OBJ_PORT_FDB, }; struct switchdev_obj { enum switchdev_obj_id id; enum switchdev_trans trans; + int (*cb)(struct net_device *dev, struct switchdev_obj *obj); union { struct switchdev_obj_vlan { /* PORT_VLAN */ u16 flags; @@ -67,6 +69,10 @@ struct switchdev_obj { u32 nlflags; u32 tb_id; } ipv4_fib; + struct switchdev_obj_fdb { /* PORT_FDB */ + const unsigned char *addr; + u16 vid; + } fdb; } u; }; @@ -80,6 +86,8 @@ struct switchdev_obj { * @switchdev_port_obj_add: Add an object to port (see switchdev_obj). * * @switchdev_port_obj_del: Delete an object from port (see switchdev_obj). + * + * @switchdev_port_obj_dump: Dump port objects (see switchdev_obj). */ struct switchdev_ops { int (*switchdev_port_attr_get)(struct net_device *dev, @@ -90,6 +98,8 @@ struct switchdev_ops { struct switchdev_obj *obj); int (*switchdev_port_obj_del)(struct net_device *dev, struct switchdev_obj *obj); + int (*switchdev_port_obj_dump)(struct net_device *dev, + struct switchdev_obj *obj); }; enum switchdev_notifier_type { @@ -121,6 +131,7 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr); int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj); int switchdev_port_obj_del(struct net_device *dev, struct switchdev_obj *obj); +int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj); int register_switchdev_notifier(struct notifier_block *nb); int unregister_switchdev_notifier(struct notifier_block *nb); int call_switchdev_notifiers(unsigned long val, struct net_device *dev, @@ -137,6 +148,15 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, u32 tb_id); void switchdev_fib_ipv4_abort(struct fib_info *fi); +int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], + struct net_device *dev, const unsigned char *addr, + u16 vid, u16 nlm_flags); +int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], + struct net_device *dev, const unsigned char *addr, + u16 vid); +int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, + struct net_device *dev, + struct net_device *filter_dev, int idx); #else @@ -164,6 +184,12 @@ static inline int switchdev_port_obj_del(struct net_device *dev, return -EOPNOTSUPP; } +static inline int switchdev_port_obj_dump(struct net_device *dev, + struct switchdev_obj *obj) +{ + return -EOPNOTSUPP; +} + static inline int register_switchdev_notifier(struct notifier_block *nb) { return 0; @@ -221,6 +247,30 @@ static inline void switchdev_fib_ipv4_abort(struct fib_info *fi) { } +static inline int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], + struct net_device *dev, + const unsigned char *addr, + u16 vid, u16 nlm_flags) +{ + return -EOPNOTSUPP; +} + +static inline int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], + struct net_device *dev, + const unsigned char *addr, u16 vid) +{ + return -EOPNOTSUPP; +} + +static inline int switchdev_port_fdb_dump(struct sk_buff *skb, + struct netlink_callback *cb, + struct net_device *dev, + struct net_device *filter_dev, + int idx) +{ + return -EOPNOTSUPP; +} + #endif #endif /* _LINUX_SWITCHDEV_H_ */ diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 0409f9b5bdbc..d4c8cf828240 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -296,6 +296,36 @@ int switchdev_port_obj_del(struct net_device *dev, struct switchdev_obj *obj) } EXPORT_SYMBOL_GPL(switchdev_port_obj_del); +/** + * switchdev_port_obj_dump - Dump port objects + * + * @dev: port device + * @obj: object to dump + */ +int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj) +{ + const struct switchdev_ops *ops = dev->switchdev_ops; + struct net_device *lower_dev; + struct list_head *iter; + int err = -EOPNOTSUPP; + + if (ops && ops->switchdev_port_obj_dump) + return ops->switchdev_port_obj_dump(dev, obj); + + /* Switch device port(s) may be stacked under + * bond/team/vlan dev, so recurse down to dump objects on + * first port at bottom of stack. + */ + + netdev_for_each_lower_dev(dev, lower_dev, iter) { + err = switchdev_port_obj_dump(lower_dev, obj); + break; + } + + return err; +} +EXPORT_SYMBOL_GPL(switchdev_port_obj_dump); + static DEFINE_MUTEX(switchdev_mutex); static RAW_NOTIFIER_HEAD(switchdev_notif_chain); @@ -566,6 +596,151 @@ int switchdev_port_bridge_dellink(struct net_device *dev, } EXPORT_SYMBOL_GPL(switchdev_port_bridge_dellink); +/** + * switchdev_port_fdb_add - Add FDB (MAC/VLAN) entry to port + * + * @ndmsg: netlink hdr + * @nlattr: netlink attributes + * @dev: port device + * @addr: MAC address to add + * @vid: VLAN to add + * + * Add FDB entry to switch device. + */ +int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], + struct net_device *dev, const unsigned char *addr, + u16 vid, u16 nlm_flags) +{ + struct switchdev_obj obj = { + .id = SWITCHDEV_OBJ_PORT_FDB, + .u.fdb = { + .addr = addr, + .vid = vid, + }, + }; + + return switchdev_port_obj_add(dev, &obj); +} +EXPORT_SYMBOL_GPL(switchdev_port_fdb_add); + +/** + * switchdev_port_fdb_del - Delete FDB (MAC/VLAN) entry from port + * + * @ndmsg: netlink hdr + * @nlattr: netlink attributes + * @dev: port device + * @addr: MAC address to delete + * @vid: VLAN to delete + * + * Delete FDB entry from switch device. + */ +int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], + struct net_device *dev, const unsigned char *addr, + u16 vid) +{ + struct switchdev_obj obj = { + .id = SWITCHDEV_OBJ_PORT_FDB, + .u.fdb = { + .addr = addr, + .vid = vid, + }, + }; + + return switchdev_port_obj_del(dev, &obj); +} +EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); + +struct switchdev_fdb_dump { + struct switchdev_obj obj; + struct sk_buff *skb; + struct netlink_callback *cb; + struct net_device *filter_dev; + int idx; +}; + +static int switchdev_port_fdb_dump_cb(struct net_device *dev, + struct switchdev_obj *obj) +{ + struct switchdev_fdb_dump *dump = + container_of(obj, struct switchdev_fdb_dump, obj); + u32 portid = NETLINK_CB(dump->cb->skb).portid; + u32 seq = dump->cb->nlh->nlmsg_seq; + struct nlmsghdr *nlh; + struct ndmsg *ndm; + struct net_device *master = netdev_master_upper_dev_get(dev); + + if (dump->idx < dump->cb->args[0]) + goto skip; + + if (master && dump->filter_dev != master) + goto skip; + + nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH, + sizeof(*ndm), NLM_F_MULTI); + if (!nlh) + return -EMSGSIZE; + + ndm = nlmsg_data(nlh); + ndm->ndm_family = AF_BRIDGE; + ndm->ndm_pad1 = 0; + ndm->ndm_pad2 = 0; + ndm->ndm_flags = NTF_SELF; + ndm->ndm_type = 0; + ndm->ndm_ifindex = dev->ifindex; + ndm->ndm_state = NUD_REACHABLE; + + if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, obj->u.fdb.addr)) + goto nla_put_failure; + + if (obj->u.fdb.vid && nla_put_u16(dump->skb, NDA_VLAN, obj->u.fdb.vid)) + goto nla_put_failure; + + nlmsg_end(dump->skb, nlh); + +skip: + dump->idx++; + return 0; + +nla_put_failure: + nlmsg_cancel(dump->skb, nlh); + return -EMSGSIZE; +} + +/** + * switchdev_port_fdb_dump - Dump port FDB (MAC/VLAN) entries + * + * @skb: netlink skb + * @cb: netlink callback + * @dev: port device + * @filter_dev: filter device + * @idx: + * + * Delete FDB entry from switch device. + */ +int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, + struct net_device *dev, + struct net_device *filter_dev, int idx) +{ + struct switchdev_fdb_dump dump = { + .obj = { + .id = SWITCHDEV_OBJ_PORT_FDB, + .cb = switchdev_port_fdb_dump_cb, + }, + .skb = skb, + .cb = cb, + .filter_dev = filter_dev, + .idx = idx, + }; + int err; + + err = switchdev_port_obj_dump(dev, &dump.obj); + if (err) + return err; + + return dump.idx; +} +EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump); + static struct net_device *switchdev_get_lowest_dev(struct net_device *dev) { const struct switchdev_ops *ops = dev->switchdev_ops; -- cgit v1.2.3 From de133464c9e70808d3e5a861294bc55940988178 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Fri, 15 May 2015 14:47:32 -0700 Subject: netns: make nsid_lock per net The spinlock is used to protect netns_ids which is per net, so there is no need to use a global spinlock. Cc: Nicolas Dichtel Signed-off-by: Cong Wang Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller --- include/net/net_namespace.h | 1 + net/core/net_namespace.c | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 3f850acc844e..72eb23723294 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -58,6 +58,7 @@ struct net { struct list_head exit_list; /* Use only net_mutex */ struct user_namespace *user_ns; /* Owning user namespace */ + spinlock_t nsid_lock; struct idr netns_ids; struct ns_common ns; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index d2f42da9479b..2c2eb1b629b1 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -28,7 +28,6 @@ static LIST_HEAD(pernet_list); static struct list_head *first_device = &pernet_list; DEFINE_MUTEX(net_mutex); -static DEFINE_SPINLOCK(nsid_lock); LIST_HEAD(net_namespace_list); EXPORT_SYMBOL_GPL(net_namespace_list); @@ -218,10 +217,10 @@ int peernet2id_alloc(struct net *net, struct net *peer) bool alloc; int id; - spin_lock_irqsave(&nsid_lock, flags); + spin_lock_irqsave(&net->nsid_lock, flags); alloc = atomic_read(&peer->count) == 0 ? false : true; id = __peernet2id_alloc(net, peer, &alloc); - spin_unlock_irqrestore(&nsid_lock, flags); + spin_unlock_irqrestore(&net->nsid_lock, flags); if (alloc && id >= 0) rtnl_net_notifyid(net, RTM_NEWNSID, id); return id; @@ -234,9 +233,9 @@ int peernet2id(struct net *net, struct net *peer) unsigned long flags; int id; - spin_lock_irqsave(&nsid_lock, flags); + spin_lock_irqsave(&net->nsid_lock, flags); id = __peernet2id(net, peer); - spin_unlock_irqrestore(&nsid_lock, flags); + spin_unlock_irqrestore(&net->nsid_lock, flags); return id; } @@ -257,11 +256,11 @@ struct net *get_net_ns_by_id(struct net *net, int id) return NULL; rcu_read_lock(); - spin_lock_irqsave(&nsid_lock, flags); + spin_lock_irqsave(&net->nsid_lock, flags); peer = idr_find(&net->netns_ids, id); if (peer) get_net(peer); - spin_unlock_irqrestore(&nsid_lock, flags); + spin_unlock_irqrestore(&net->nsid_lock, flags); rcu_read_unlock(); return peer; @@ -282,6 +281,7 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) net->dev_base_seq = 1; net->user_ns = user_ns; idr_init(&net->netns_ids); + spin_lock_init(&net->nsid_lock); list_for_each_entry(ops, &pernet_list, list) { error = ops_init(ops, net); @@ -404,17 +404,17 @@ static void cleanup_net(struct work_struct *work) for_each_net(tmp) { int id; - spin_lock_irq(&nsid_lock); + spin_lock_irq(&tmp->nsid_lock); id = __peernet2id(tmp, net); if (id >= 0) idr_remove(&tmp->netns_ids, id); - spin_unlock_irq(&nsid_lock); + spin_unlock_irq(&tmp->nsid_lock); if (id >= 0) rtnl_net_notifyid(tmp, RTM_DELNSID, id); } - spin_lock_irq(&nsid_lock); + spin_lock_irq(&net->nsid_lock); idr_destroy(&net->netns_ids); - spin_unlock_irq(&nsid_lock); + spin_unlock_irq(&net->nsid_lock); } rtnl_unlock(); @@ -563,15 +563,15 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh) if (IS_ERR(peer)) return PTR_ERR(peer); - spin_lock_irqsave(&nsid_lock, flags); + spin_lock_irqsave(&net->nsid_lock, flags); if (__peernet2id(net, peer) >= 0) { - spin_unlock_irqrestore(&nsid_lock, flags); + spin_unlock_irqrestore(&net->nsid_lock, flags); err = -EEXIST; goto out; } err = alloc_netid(net, peer, nsid); - spin_unlock_irqrestore(&nsid_lock, flags); + spin_unlock_irqrestore(&net->nsid_lock, flags); if (err >= 0) { rtnl_net_notifyid(net, RTM_NEWNSID, err); err = 0; @@ -695,9 +695,9 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb) }; unsigned long flags; - spin_lock_irqsave(&nsid_lock, flags); + spin_lock_irqsave(&net->nsid_lock, flags); idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb); - spin_unlock_irqrestore(&nsid_lock, flags); + spin_unlock_irqrestore(&net->nsid_lock, flags); cb->args[0] = net_cb.idx; return skb->len; -- cgit v1.2.3 From 5cf422808244ca8f1177c72fe6e1ce8322794b57 Mon Sep 17 00:00:00 2001 From: Andy Zhou Date: Fri, 15 May 2015 14:15:35 -0700 Subject: ipv4: introduce frag_expire_skip_icmp() Improve readability of skip ICMP for de-fragmentation expiration logic. This change will also make the logic easier to maintain when the following patches in this series are applied. Signed-off-by: Andy Zhou Signed-off-by: David S. Miller --- include/net/ip.h | 10 ++++++++++ net/ipv4/ip_fragment.c | 13 +++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/net/ip.h b/include/net/ip.h index 0ed6d768e606..43f6f39df9fc 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -478,6 +478,16 @@ enum ip_defrag_users { IP_DEFRAG_MACVLAN, }; +/* Return true if the value of 'user' is between 'lower_bond' + * and 'upper_bond' inclusively. + */ +static inline bool ip_defrag_user_in_between(u32 user, + enum ip_defrag_users lower_bond, + enum ip_defrag_users upper_bond) +{ + return user >= lower_bond && user <= upper_bond; +} + int ip_defrag(struct sk_buff *skb, u32 user); #ifdef CONFIG_INET struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index cc1da6d9cb35..83424f1742b8 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -173,6 +173,13 @@ static void ipq_kill(struct ipq *ipq) inet_frag_kill(&ipq->q, &ip4_frags); } +static bool frag_expire_skip_icmp(u32 user) +{ + return user == IP_DEFRAG_AF_PACKET || + ip_defrag_user_in_between(user, IP_DEFRAG_CONNTRACK_IN, + __IP_DEFRAG_CONNTRACK_IN_END); +} + /* * Oops, a fragment queue timed out. Kill it and send an ICMP reply. */ @@ -217,10 +224,8 @@ static void ip_expire(unsigned long arg) /* Only an end host needs to send an ICMP * "Fragment Reassembly Timeout" message, per RFC792. */ - if (qp->user == IP_DEFRAG_AF_PACKET || - ((qp->user >= IP_DEFRAG_CONNTRACK_IN) && - (qp->user <= __IP_DEFRAG_CONNTRACK_IN_END) && - (skb_rtable(head)->rt_type != RTN_LOCAL))) + if (frag_expire_skip_icmp(qp->user) && + (skb_rtable(head)->rt_type != RTN_LOCAL)) goto out_rcu_unlock; /* Send an ICMP "Fragment Reassembly Timeout" message. */ -- cgit v1.2.3 From 49d16b23cd1e61c028ee088c5a64e9ac6a9c6147 Mon Sep 17 00:00:00 2001 From: Andy Zhou Date: Fri, 15 May 2015 14:15:37 -0700 Subject: bridge_netfilter: No ICMP packet on IPv4 fragmentation error When bridge netfilter re-fragments an IP packet for output, all packets that can not be re-fragmented to their original input size should be silently discarded. However, current bridge netfilter output path generates an ICMP packet with 'size exceeded MTU' message for such packets, this is a bug. This patch refactors the ip_fragment() API to allow two separate use cases. The bridge netfilter user case will not send ICMP, the routing output will, as before. Signed-off-by: Andy Zhou Acked-by: Florian Westphal Signed-off-by: David S. Miller --- include/net/ip.h | 4 ++-- net/bridge/br_netfilter.c | 21 ++++++++++++++++++++- net/ipv4/ip_output.c | 40 ++++++++++++++++++++++++++++------------ 3 files changed, 50 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/net/ip.h b/include/net/ip.h index 43f6f39df9fc..cd7a6a458bb6 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -108,8 +108,8 @@ int ip_local_deliver(struct sk_buff *skb); int ip_mr_input(struct sk_buff *skb); int ip_output(struct sock *sk, struct sk_buff *skb); int ip_mc_output(struct sock *sk, struct sk_buff *skb); -int ip_fragment(struct sock *sk, struct sk_buff *skb, - int (*output)(struct sock *, struct sk_buff *)); +int ip_do_fragment(struct sock *sk, struct sk_buff *skb, + int (*output)(struct sock *, struct sk_buff *)); int ip_do_nat(struct sk_buff *skb); void ip_send_check(struct iphdr *ip); int __ip_local_out(struct sk_buff *skb); diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 2b0e8bb49944..1d2eb32d8270 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -853,6 +853,25 @@ static int br_nf_push_frag_xmit(struct sock *sk, struct sk_buff *skb) return br_dev_queue_push_xmit(sk, skb); } +static int br_nf_ip_fragment(struct sock *sk, struct sk_buff *skb, + int (*output)(struct sock *, struct sk_buff *)) +{ + unsigned int mtu = ip_skb_dst_mtu(skb); + struct iphdr *iph = ip_hdr(skb); + struct rtable *rt = skb_rtable(skb); + struct net_device *dev = rt->dst.dev; + + if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) || + (IPCB(skb)->frag_max_size && + IPCB(skb)->frag_max_size > mtu))) { + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS); + kfree_skb(skb); + return -EMSGSIZE; + } + + return ip_do_fragment(sk, skb, output); +} + static int br_nf_dev_queue_xmit(struct sock *sk, struct sk_buff *skb) { int ret; @@ -886,7 +905,7 @@ static int br_nf_dev_queue_xmit(struct sock *sk, struct sk_buff *skb) skb_copy_from_linear_data_offset(skb, -data->size, data->mac, data->size); - ret = ip_fragment(sk, skb, br_nf_push_frag_xmit); + ret = br_nf_ip_fragment(sk, skb, br_nf_push_frag_xmit); } else { nf_bridge_info_free(skb); ret = br_dev_queue_push_xmit(sk, skb); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 2acc5dc32807..8d91b922fcfe 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -83,6 +83,9 @@ int sysctl_ip_default_ttl __read_mostly = IPDEFTTL; EXPORT_SYMBOL(sysctl_ip_default_ttl); +static int ip_fragment(struct sock *sk, struct sk_buff *skb, + int (*output)(struct sock *, struct sk_buff *)); + /* Generate a checksum for an outgoing IP datagram. */ void ip_send_check(struct iphdr *iph) { @@ -478,6 +481,28 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) skb_copy_secmark(to, from); } +static int ip_fragment(struct sock *sk, struct sk_buff *skb, + int (*output)(struct sock *, struct sk_buff *)) +{ + struct iphdr *iph = ip_hdr(skb); + unsigned int mtu = ip_skb_dst_mtu(skb); + + if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) || + (IPCB(skb)->frag_max_size && + IPCB(skb)->frag_max_size > mtu))) { + struct rtable *rt = skb_rtable(skb); + struct net_device *dev = rt->dst.dev; + + IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(mtu)); + kfree_skb(skb); + return -EMSGSIZE; + } + + return ip_do_fragment(sk, skb, output); +} + /* * This IP datagram is too large to be sent in one piece. Break it up into * smaller pieces (each of size equal to IP header plus @@ -485,8 +510,8 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) * single device frame, and queue such a frame for sending. */ -int ip_fragment(struct sock *sk, struct sk_buff *skb, - int (*output)(struct sock *, struct sk_buff *)) +int ip_do_fragment(struct sock *sk, struct sk_buff *skb, + int (*output)(struct sock *, struct sk_buff *)) { struct iphdr *iph; int ptr; @@ -507,15 +532,6 @@ int ip_fragment(struct sock *sk, struct sk_buff *skb, iph = ip_hdr(skb); mtu = ip_skb_dst_mtu(skb); - if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) || - (IPCB(skb)->frag_max_size && - IPCB(skb)->frag_max_size > mtu))) { - IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, - htonl(mtu)); - kfree_skb(skb); - return -EMSGSIZE; - } /* * Setup starting values. @@ -751,7 +767,7 @@ fail: IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS); return err; } -EXPORT_SYMBOL(ip_fragment); +EXPORT_SYMBOL(ip_do_fragment); int ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) -- cgit v1.2.3 From 1a19cb680be0d4b06ce9a9d6516b8f45f544d3e8 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:39 +0200 Subject: ieee802154: change transmit power to s32 This patch change the transmit power from s8 to s32. This prepares to store a mbm value instead dbm inside the transmit power variable. The old interface keep the a s8 dbm value, which should be backward compatibility when assign s8 to s32. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 +- include/net/cfg802154.h | 2 +- include/net/mac802154.h | 2 +- net/ieee802154/nl802154.c | 6 +++--- net/mac802154/driver-ops.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 67d00fbc2e0e..02b6bb72304d 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1194,7 +1194,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, } static int -at86rf230_set_txpower(struct ieee802154_hw *hw, s8 db) +at86rf230_set_txpower(struct ieee802154_hw *hw, s32 db) { struct at86rf230_local *lp = hw->priv; diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 6ea16c84293b..47804cddb46f 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -85,7 +85,7 @@ struct wpan_phy { u8 current_channel; u8 current_page; u32 channels_supported[IEEE802154_MAX_PAGE + 1]; - s8 transmit_power; + s32 transmit_power; struct wpan_phy_cca cca; __le64 perm_extended_addr; diff --git a/include/net/mac802154.h b/include/net/mac802154.h index 7df28a4c23f9..400e4e85c53f 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -213,7 +213,7 @@ struct ieee802154_ops { int (*set_hw_addr_filt)(struct ieee802154_hw *hw, struct ieee802154_hw_addr_filt *filt, unsigned long changed); - int (*set_txpower)(struct ieee802154_hw *hw, s8 dbm); + int (*set_txpower)(struct ieee802154_hw *hw, s32 dbm); int (*set_lbt)(struct ieee802154_hw *hw, bool on); int (*set_cca_mode)(struct ieee802154_hw *hw, const struct wpan_phy_cca *cca); diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index d750d9778ba7..f3185c71af10 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -207,7 +207,7 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { [NL802154_ATTR_PAGE] = { .type = NLA_U8, }, [NL802154_ATTR_CHANNEL] = { .type = NLA_U8, }, - [NL802154_ATTR_TX_POWER] = { .type = NLA_S8, }, + [NL802154_ATTR_TX_POWER] = { .type = NLA_S32, }, [NL802154_ATTR_CCA_MODE] = { .type = NLA_U32, }, [NL802154_ATTR_CCA_OPT] = { .type = NLA_U32, }, @@ -301,8 +301,8 @@ static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev, goto nla_put_failure; } - if (nla_put_s8(msg, NL802154_ATTR_TX_POWER, - rdev->wpan_phy.transmit_power)) + if (nla_put_s32(msg, NL802154_ATTR_TX_POWER, + rdev->wpan_phy.transmit_power)) goto nla_put_failure; finish: diff --git a/net/mac802154/driver-ops.h b/net/mac802154/driver-ops.h index a0533357b9ea..57c1bdbfaa91 100644 --- a/net/mac802154/driver-ops.h +++ b/net/mac802154/driver-ops.h @@ -58,7 +58,7 @@ drv_set_channel(struct ieee802154_local *local, u8 page, u8 channel) return local->ops->set_channel(&local->hw, page, channel); } -static inline int drv_set_tx_power(struct ieee802154_local *local, s8 dbm) +static inline int drv_set_tx_power(struct ieee802154_local *local, s32 dbm) { might_sleep(); -- cgit v1.2.3 From e2eb173aaacd1a1bcd255d3e74ffb719e47eeadb Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:40 +0200 Subject: ieee802154: change transmit power to mbm This patch change the handling of transmit power level from dbm to mbm. This prepares to handle floating point transmit power levels values. The old netlink 802.15.4 will convert the dbm value to mbm for handling backward compatibility. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 3 ++- include/net/cfg802154.h | 1 + include/net/mac802154.h | 4 ++-- net/ieee802154/nl-mac.c | 4 ++-- net/mac802154/driver-ops.h | 4 ++-- 5 files changed, 9 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 02b6bb72304d..3a303e4a3c07 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1194,9 +1194,10 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, } static int -at86rf230_set_txpower(struct ieee802154_hw *hw, s32 db) +at86rf230_set_txpower(struct ieee802154_hw *hw, s32 mbm) { struct at86rf230_local *lp = hw->priv; + s8 db = mbm / 100; /* typical maximum output is 5dBm with RG_PHY_TX_PWR 0x60, lower five * bits decrease power in 1dB steps. 0x60 represents extra PA gain of diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 47804cddb46f..b5b3f9f43084 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -85,6 +85,7 @@ struct wpan_phy { u8 current_channel; u8 current_page; u32 channels_supported[IEEE802154_MAX_PAGE + 1]; + /* current transmit_power in mBm */ s32 transmit_power; struct wpan_phy_cca cca; diff --git a/include/net/mac802154.h b/include/net/mac802154.h index 400e4e85c53f..e863a8557c0a 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -171,7 +171,7 @@ struct ieee802154_hw { * Returns either zero, or negative errno. * * set_txpower: - * Set radio transmit power in dB. Called with pib_lock held. + * Set radio transmit power in mBm. Called with pib_lock held. * Returns either zero, or negative errno. * * set_lbt @@ -213,7 +213,7 @@ struct ieee802154_ops { int (*set_hw_addr_filt)(struct ieee802154_hw *hw, struct ieee802154_hw_addr_filt *filt, unsigned long changed); - int (*set_txpower)(struct ieee802154_hw *hw, s32 dbm); + int (*set_txpower)(struct ieee802154_hw *hw, s32 mbm); int (*set_lbt)(struct ieee802154_hw *hw, bool on); int (*set_cca_mode)(struct ieee802154_hw *hw, const struct wpan_phy_cca *cca); diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index 2b4955d7aae5..4ba2e13f7a07 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -117,7 +117,7 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, rtnl_unlock(); if (nla_put_s8(msg, IEEE802154_ATTR_TXPOWER, - params.transmit_power) || + params.transmit_power / 100) || nla_put_u8(msg, IEEE802154_ATTR_LBT_ENABLED, params.lbt) || nla_put_u8(msg, IEEE802154_ATTR_CCA_MODE, params.cca.mode) || @@ -510,7 +510,7 @@ int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info) ops->get_mac_params(dev, ¶ms); if (info->attrs[IEEE802154_ATTR_TXPOWER]) - params.transmit_power = nla_get_s8(info->attrs[IEEE802154_ATTR_TXPOWER]); + params.transmit_power = nla_get_s8(info->attrs[IEEE802154_ATTR_TXPOWER]) * 100; if (info->attrs[IEEE802154_ATTR_LBT_ENABLED]) params.lbt = nla_get_u8(info->attrs[IEEE802154_ATTR_LBT_ENABLED]); diff --git a/net/mac802154/driver-ops.h b/net/mac802154/driver-ops.h index 57c1bdbfaa91..d289ae3f1e93 100644 --- a/net/mac802154/driver-ops.h +++ b/net/mac802154/driver-ops.h @@ -58,7 +58,7 @@ drv_set_channel(struct ieee802154_local *local, u8 page, u8 channel) return local->ops->set_channel(&local->hw, page, channel); } -static inline int drv_set_tx_power(struct ieee802154_local *local, s32 dbm) +static inline int drv_set_tx_power(struct ieee802154_local *local, s32 mbm) { might_sleep(); @@ -67,7 +67,7 @@ static inline int drv_set_tx_power(struct ieee802154_local *local, s32 dbm) return -EOPNOTSUPP; } - return local->ops->set_txpower(&local->hw, dbm); + return local->ops->set_txpower(&local->hw, mbm); } static inline int drv_set_cca_mode(struct ieee802154_local *local, -- cgit v1.2.3 From 32b23550ad64d9676f2218b3d5de46bacf98ef1d Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:41 +0200 Subject: ieee802154: change cca ed level to mbm This patch change the handling of cca energy detection level from dbm to mbm. This prepares to handle floating point cca energy detection levels values. The old netlink 802.15.4 will convert the dbm value to mbm for handling backward compatibility. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 3 ++- include/net/cfg802154.h | 1 + include/net/mac802154.h | 5 ++--- net/ieee802154/nl-mac.c | 4 ++-- net/mac802154/driver-ops.h | 4 ++-- 5 files changed, 9 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 3a303e4a3c07..e68d45ed622e 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1268,9 +1268,10 @@ at86rf23x_get_desens_steps(struct at86rf230_local *lp, s32 level) } static int -at86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 level) +at86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm) { struct at86rf230_local *lp = hw->priv; + s32 level = mbm / 100; if (level < lp->data->rssi_base_val || level > 30) return -EINVAL; diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index b5b3f9f43084..9ced2c9fdbfc 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -91,6 +91,7 @@ struct wpan_phy { __le64 perm_extended_addr; + /* current cca ed threshold in mBm */ s32 cca_ed_level; /* PHY depended MAC PIB values */ diff --git a/include/net/mac802154.h b/include/net/mac802154.h index e863a8557c0a..71e245605ef8 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -184,7 +184,7 @@ struct ieee802154_hw { * Returns either zero, or negative errno. * * set_cca_ed_level - * Sets the CCA energy detection threshold in dBm. Called with pib_lock + * Sets the CCA energy detection threshold in mBm. Called with pib_lock * held. * Returns either zero, or negative errno. * @@ -217,8 +217,7 @@ struct ieee802154_ops { int (*set_lbt)(struct ieee802154_hw *hw, bool on); int (*set_cca_mode)(struct ieee802154_hw *hw, const struct wpan_phy_cca *cca); - int (*set_cca_ed_level)(struct ieee802154_hw *hw, - s32 level); + int (*set_cca_ed_level)(struct ieee802154_hw *hw, s32 mbm); int (*set_csma_params)(struct ieee802154_hw *hw, u8 min_be, u8 max_be, u8 retries); int (*set_frame_retries)(struct ieee802154_hw *hw, diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index 4ba2e13f7a07..cdc1cc3543f6 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -122,7 +122,7 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, nla_put_u8(msg, IEEE802154_ATTR_CCA_MODE, params.cca.mode) || nla_put_s32(msg, IEEE802154_ATTR_CCA_ED_LEVEL, - params.cca_ed_level) || + params.cca_ed_level / 100) || nla_put_u8(msg, IEEE802154_ATTR_CSMA_RETRIES, params.csma_retries) || nla_put_u8(msg, IEEE802154_ATTR_CSMA_MIN_BE, @@ -519,7 +519,7 @@ int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info) params.cca.mode = nla_get_u8(info->attrs[IEEE802154_ATTR_CCA_MODE]); if (info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]) - params.cca_ed_level = nla_get_s32(info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]); + params.cca_ed_level = nla_get_s32(info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]) * 100; if (info->attrs[IEEE802154_ATTR_CSMA_RETRIES]) params.csma_retries = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_RETRIES]); diff --git a/net/mac802154/driver-ops.h b/net/mac802154/driver-ops.h index d289ae3f1e93..caecd5f43aa7 100644 --- a/net/mac802154/driver-ops.h +++ b/net/mac802154/driver-ops.h @@ -96,7 +96,7 @@ static inline int drv_set_lbt_mode(struct ieee802154_local *local, bool mode) } static inline int -drv_set_cca_ed_level(struct ieee802154_local *local, s32 ed_level) +drv_set_cca_ed_level(struct ieee802154_local *local, s32 mbm) { might_sleep(); @@ -105,7 +105,7 @@ drv_set_cca_ed_level(struct ieee802154_local *local, s32 ed_level) return -EOPNOTSUPP; } - return local->ops->set_cca_ed_level(&local->hw, ed_level); + return local->ops->set_cca_ed_level(&local->hw, mbm); } static inline int drv_set_pan_id(struct ieee802154_local *local, __le16 pan_id) -- cgit v1.2.3 From 72f655e44db9c7e835ceba96dc03cbe979d3f80d Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:42 +0200 Subject: ieee802154: introduce wpan_phy_supported This patch introduce the wpan_phy_supported struct for wpan_phy. There is currently no way to check if a transceiver can handle IEEE 802.15.4 complaint values. With this struct we can check before if the transceiver supports these values before sending to driver layer. Signed-off-by: Alexander Aring Suggested-by: Phoebe Buckheister Acked-by: Varka Bhadram Cc: Alan Ott Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 8 ++++---- drivers/net/ieee802154/cc2520.c | 2 +- drivers/net/ieee802154/fakelb.c | 30 +++++++++++++++--------------- drivers/net/ieee802154/mrf24j40.c | 2 +- include/net/cfg802154.h | 6 +++++- net/ieee802154/nl-phy.c | 4 ++-- net/ieee802154/nl802154.c | 4 ++-- 7 files changed, 30 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index e68d45ed622e..151d57f4320d 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1579,7 +1579,7 @@ at86rf230_detect_device(struct at86rf230_local *lp) case 3: chip = "at86rf231"; lp->data = &at86rf231_data; - lp->hw->phy->channels_supported[0] = 0x7FFF800; + lp->hw->phy->supported.channels[0] = 0x7FFF800; lp->hw->phy->current_channel = 11; lp->hw->phy->symbol_duration = 16; break; @@ -1587,15 +1587,15 @@ at86rf230_detect_device(struct at86rf230_local *lp) chip = "at86rf212"; lp->data = &at86rf212_data; lp->hw->flags |= IEEE802154_HW_LBT; - lp->hw->phy->channels_supported[0] = 0x00007FF; - lp->hw->phy->channels_supported[2] = 0x00007FF; + lp->hw->phy->supported.channels[0] = 0x00007FF; + lp->hw->phy->supported.channels[2] = 0x00007FF; lp->hw->phy->current_channel = 5; lp->hw->phy->symbol_duration = 25; break; case 11: chip = "at86rf233"; lp->data = &at86rf233_data; - lp->hw->phy->channels_supported[0] = 0x7FFF800; + lp->hw->phy->supported.channels[0] = 0x7FFF800; lp->hw->phy->current_channel = 13; lp->hw->phy->symbol_duration = 16; break; diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index f833b8bb6663..84b28a05c5a1 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -653,7 +653,7 @@ static int cc2520_register(struct cc2520_private *priv) ieee802154_random_extended_addr(&priv->hw->phy->perm_extended_addr); /* We do support only 2.4 Ghz */ - priv->hw->phy->channels_supported[0] = 0x7FFF800; + priv->hw->phy->supported.channels[0] = 0x7FFF800; priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK | IEEE802154_HW_AFILT; diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index dc2bfb600b4b..91bbf030a443 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -149,35 +149,35 @@ static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake) priv->hw = hw; /* 868 MHz BPSK 802.15.4-2003 */ - hw->phy->channels_supported[0] |= 1; + hw->phy->supported.channels[0] |= 1; /* 915 MHz BPSK 802.15.4-2003 */ - hw->phy->channels_supported[0] |= 0x7fe; + hw->phy->supported.channels[0] |= 0x7fe; /* 2.4 GHz O-QPSK 802.15.4-2003 */ - hw->phy->channels_supported[0] |= 0x7FFF800; + hw->phy->supported.channels[0] |= 0x7FFF800; /* 868 MHz ASK 802.15.4-2006 */ - hw->phy->channels_supported[1] |= 1; + hw->phy->supported.channels[1] |= 1; /* 915 MHz ASK 802.15.4-2006 */ - hw->phy->channels_supported[1] |= 0x7fe; + hw->phy->supported.channels[1] |= 0x7fe; /* 868 MHz O-QPSK 802.15.4-2006 */ - hw->phy->channels_supported[2] |= 1; + hw->phy->supported.channels[2] |= 1; /* 915 MHz O-QPSK 802.15.4-2006 */ - hw->phy->channels_supported[2] |= 0x7fe; + hw->phy->supported.channels[2] |= 0x7fe; /* 2.4 GHz CSS 802.15.4a-2007 */ - hw->phy->channels_supported[3] |= 0x3fff; + hw->phy->supported.channels[3] |= 0x3fff; /* UWB Sub-gigahertz 802.15.4a-2007 */ - hw->phy->channels_supported[4] |= 1; + hw->phy->supported.channels[4] |= 1; /* UWB Low band 802.15.4a-2007 */ - hw->phy->channels_supported[4] |= 0x1e; + hw->phy->supported.channels[4] |= 0x1e; /* UWB High band 802.15.4a-2007 */ - hw->phy->channels_supported[4] |= 0xffe0; + hw->phy->supported.channels[4] |= 0xffe0; /* 750 MHz O-QPSK 802.15.4c-2009 */ - hw->phy->channels_supported[5] |= 0xf; + hw->phy->supported.channels[5] |= 0xf; /* 750 MHz MPSK 802.15.4c-2009 */ - hw->phy->channels_supported[5] |= 0xf0; + hw->phy->supported.channels[5] |= 0xf0; /* 950 MHz BPSK 802.15.4d-2009 */ - hw->phy->channels_supported[6] |= 0x3ff; + hw->phy->supported.channels[6] |= 0x3ff; /* 950 MHz GFSK 802.15.4d-2009 */ - hw->phy->channels_supported[6] |= 0x3ffc00; + hw->phy->supported.channels[6] |= 0x3ffc00; INIT_LIST_HEAD(&priv->list); priv->fake = fake; diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index fba2dfd910f7..f2a1bd122a74 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -750,7 +750,7 @@ static int mrf24j40_probe(struct spi_device *spi) devrec->hw->priv = devrec; devrec->hw->parent = &devrec->spi->dev; - devrec->hw->phy->channels_supported[0] = CHANNEL_MASK; + devrec->hw->phy->supported.channels[0] = CHANNEL_MASK; devrec->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK | IEEE802154_HW_AFILT; diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 9ced2c9fdbfc..1941d7a79219 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -61,6 +61,10 @@ struct cfg802154_ops { struct wpan_dev *wpan_dev, bool mode); }; +struct wpan_phy_supported { + u32 channels[IEEE802154_MAX_PAGE + 1]; +}; + struct wpan_phy_cca { enum nl802154_cca_modes mode; enum nl802154_cca_opts opt; @@ -84,7 +88,7 @@ struct wpan_phy { */ u8 current_channel; u8 current_page; - u32 channels_supported[IEEE802154_MAX_PAGE + 1]; + struct wpan_phy_supported supported; /* current transmit_power in mBm */ s32 transmit_power; struct wpan_phy_cca cca; diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index 346c6665d25e..cbc0d09351e0 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c @@ -56,8 +56,8 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid, nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel)) goto nla_put_failure; for (i = 0; i < 32; i++) { - if (phy->channels_supported[i]) - buf[pages++] = phy->channels_supported[i] | (i << 27); + if (phy->supported.channels[i]) + buf[pages++] = phy->supported.channels[i] | (i << 27); } if (pages && nla_put(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST, diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index f3185c71af10..d271879a2174 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -248,7 +248,7 @@ nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev, for (page = 0; page <= IEEE802154_MAX_PAGE; page++) { if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL, - rdev->wpan_phy.channels_supported[page])) + rdev->wpan_phy.supported.channels[page])) return -ENOBUFS; } nla_nest_end(msg, nl_page); @@ -626,7 +626,7 @@ static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info) /* check 802.15.4 constraints */ if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL || - !(rdev->wpan_phy.channels_supported[page] & BIT(channel))) + !(rdev->wpan_phy.supported.channels[page] & BIT(channel))) return -EINVAL; return rdev_set_channel(rdev, page, channel); -- cgit v1.2.3 From fea3318d20776a94afeea0460c6ee9904e60569e Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:43 +0200 Subject: ieee802154: add several phy supported handling This patch adds support for phy supported handling for all other already existing handling 802.15.4 functionality. We assume now a fully 802.15.4 complaint transceiver at phy allocation. If a transceiver can support 802.15.4 default values only, then the values should be overwirtten by values the transceiver supports. If the transceiver doesn't set the according hardware flags, we assume the 802.15.4 defaults now which cannot be changed. Signed-off-by: Alexander Aring Suggested-by: Phoebe Buckheister Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 26 +++++++++++++++++++++++++- include/net/nl802154.h | 22 ++++++++++++++++++++++ net/ieee802154/nl802154.c | 22 +++++++++++++++++----- net/mac802154/main.c | 26 ++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 1941d7a79219..23abd08a310a 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -61,8 +61,32 @@ struct cfg802154_ops { struct wpan_dev *wpan_dev, bool mode); }; +static inline bool +wpan_phy_supported_bool(bool b, enum nl802154_supported_bool_states st) +{ + switch (st) { + case NL802154_SUPPORTED_BOOL_TRUE: + return b; + case NL802154_SUPPORTED_BOOL_FALSE: + return !b; + case NL802154_SUPPORTED_BOOL_BOTH: + return true; + default: + WARN_ON(1); + } + + return false; +} + struct wpan_phy_supported { - u32 channels[IEEE802154_MAX_PAGE + 1]; + u32 channels[IEEE802154_MAX_PAGE + 1], + cca_modes, cca_opts; + enum nl802154_supported_bool_states lbt; + u8 min_minbe, max_minbe, min_maxbe, max_maxbe, + min_csma_backoffs, max_csma_backoffs; + s8 min_frame_retries, max_frame_retries; + size_t tx_powers_size, cca_ed_levels_size; + const s32 *tx_powers, *cca_ed_levels; }; struct wpan_phy_cca { diff --git a/include/net/nl802154.h b/include/net/nl802154.h index f8b5bc997959..055277156eef 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -162,4 +162,26 @@ enum nl802154_cca_opts { NL802154_CCA_OPT_ATTR_MAX = __NL802154_CCA_OPT_ATTR_AFTER_LAST - 1 }; +/** + * enum nl802154_supported_bool_states - bool states for bool capability entry + * + * @NL802154_SUPPORTED_BOOL_FALSE: indicates to set false + * @NL802154_SUPPORTED_BOOL_TRUE: indicates to set true + * @__NL802154_SUPPORTED_BOOL_INVALD: reserved + * @NL802154_SUPPORTED_BOOL_BOTH: indicates to set true and false + * @__NL802154_SUPPORTED_BOOL_AFTER_LAST: Internal + * @NL802154_SUPPORTED_BOOL_MAX: highest value for bool states + */ +enum nl802154_supported_bool_states { + NL802154_SUPPORTED_BOOL_FALSE, + NL802154_SUPPORTED_BOOL_TRUE, + /* to handle them in a mask */ + __NL802154_SUPPORTED_BOOL_INVALD, + NL802154_SUPPORTED_BOOL_BOTH, + + /* keep last */ + __NL802154_SUPPORTED_BOOL_AFTER_LAST, + NL802154_SUPPORTED_BOOL_MAX = __NL802154_SUPPORTED_BOOL_AFTER_LAST - 1 +}; + #endif /* __NL802154_H */ diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index d271879a2174..fa0c4048b0e8 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -642,7 +642,9 @@ static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info) cca.mode = nla_get_u32(info->attrs[NL802154_ATTR_CCA_MODE]); /* checking 802.15.4 constraints */ - if (cca.mode < NL802154_CCA_ENERGY || cca.mode > NL802154_CCA_ATTR_MAX) + if (cca.mode < NL802154_CCA_ENERGY || + cca.mode > NL802154_CCA_ATTR_MAX || + !(rdev->wpan_phy.supported.cca_modes & BIT(cca.mode))) return -EINVAL; if (cca.mode == NL802154_CCA_ENERGY_CARRIER) { @@ -650,7 +652,8 @@ static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info) return -EINVAL; cca.opt = nla_get_u32(info->attrs[NL802154_ATTR_CCA_OPT]); - if (cca.opt > NL802154_CCA_OPT_ATTR_MAX) + if (cca.opt > NL802154_CCA_OPT_ATTR_MAX || + !(rdev->wpan_phy.supported.cca_opts & BIT(cca.opt))) return -EINVAL; } @@ -744,7 +747,11 @@ nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info) max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]); /* check 802.15.4 constraints */ - if (max_be < 3 || max_be > 8 || min_be > max_be) + if (min_be < rdev->wpan_phy.supported.min_minbe || + min_be > rdev->wpan_phy.supported.max_minbe || + max_be < rdev->wpan_phy.supported.min_maxbe || + max_be > rdev->wpan_phy.supported.max_maxbe || + min_be > max_be) return -EINVAL; return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be); @@ -769,7 +776,8 @@ nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info) info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]); /* check 802.15.4 constraints */ - if (max_csma_backoffs > 5) + if (max_csma_backoffs < rdev->wpan_phy.supported.min_csma_backoffs || + max_csma_backoffs > rdev->wpan_phy.supported.max_csma_backoffs) return -EINVAL; return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs); @@ -793,7 +801,8 @@ nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info) info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]); /* check 802.15.4 constraints */ - if (max_frame_retries < -1 || max_frame_retries > 7) + if (max_frame_retries < rdev->wpan_phy.supported.min_frame_retries || + max_frame_retries > rdev->wpan_phy.supported.max_frame_retries) return -EINVAL; return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries); @@ -813,6 +822,9 @@ static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info) return -EINVAL; mode = !!nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]); + if (!wpan_phy_supported_bool(mode, rdev->wpan_phy.supported.lbt)) + return -EINVAL; + return rdev_set_lbt_mode(rdev, wpan_dev, mode); } diff --git a/net/mac802154/main.c b/net/mac802154/main.c index 08cb32dc8fd3..ddcd6ff8d39c 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -107,6 +107,15 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) skb_queue_head_init(&local->skb_queue); + /* init supported flags with 802.15.4 default ranges */ + phy->supported.max_minbe = 8; + phy->supported.min_maxbe = 3; + phy->supported.max_maxbe = 8; + phy->supported.min_frame_retries = -1; + phy->supported.max_frame_retries = 7; + phy->supported.max_csma_backoffs = 5; + phy->supported.lbt = NL802154_SUPPORTED_BOOL_FALSE; + return &local->hw; } EXPORT_SYMBOL(ieee802154_alloc_hw); @@ -155,6 +164,23 @@ int ieee802154_register_hw(struct ieee802154_hw *hw) ieee802154_setup_wpan_phy_pib(local->phy); + if (!(hw->flags & IEEE802154_HW_CSMA_PARAMS)) { + local->phy->supported.min_csma_backoffs = 4; + local->phy->supported.max_csma_backoffs = 4; + local->phy->supported.min_maxbe = 5; + local->phy->supported.max_maxbe = 5; + local->phy->supported.min_minbe = 3; + local->phy->supported.max_minbe = 3; + } + + if (!(hw->flags & IEEE802154_HW_FRAME_RETRIES)) { + /* TODO should be 3, but our default value is -1 which means + * no ARET handling. + */ + local->phy->supported.min_frame_retries = -1; + local->phy->supported.max_frame_retries = -1; + } + rc = wpan_phy_register(local->phy); if (rc < 0) goto out_wq; -- cgit v1.2.3 From 791021bf13ec9d0fc14bfd8c9c4b368ace568239 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:44 +0200 Subject: mac802154: check for really changes This patch adds check if the value is really changed inside pib/mib. If a transceiver do support only one value for e.g. max_be then this will also handle that the driver layer doesn't need to care about handling to set one value only. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 12 ++++++++++++ net/mac802154/cfg.c | 26 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'include') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 23abd08a310a..37abc1603285 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -94,6 +94,18 @@ struct wpan_phy_cca { enum nl802154_cca_opts opt; }; +static inline bool +wpan_phy_cca_cmp(const struct wpan_phy_cca *a, const struct wpan_phy_cca *b) +{ + if (a->mode != b->mode) + return false; + + if (a->mode == NL802154_CCA_ENERGY_CARRIER) + return a->opt == b->opt; + + return true; +} + struct wpan_phy { struct mutex pib_lock; diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index c63601582c71..45c4dc39766e 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -73,6 +73,10 @@ ieee802154_set_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel) ASSERT_RTNL(); + if (wpan_phy->current_page == page && + wpan_phy->current_channel == channel) + return 0; + ret = drv_set_channel(local, page, channel); if (!ret) { wpan_phy->current_page = page; @@ -91,6 +95,9 @@ ieee802154_set_cca_mode(struct wpan_phy *wpan_phy, ASSERT_RTNL(); + if (wpan_phy_cca_cmp(&wpan_phy->cca, cca)) + return 0; + /* check if phy support this setting */ if (!(local->hw.flags & IEEE802154_HW_CCA_MODE)) return -EOPNOTSUPP; @@ -108,6 +115,9 @@ ieee802154_set_pan_id(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, { ASSERT_RTNL(); + if (wpan_dev->pan_id == pan_id) + return 0; + wpan_dev->pan_id = pan_id; return 0; } @@ -121,6 +131,10 @@ ieee802154_set_backoff_exponent(struct wpan_phy *wpan_phy, ASSERT_RTNL(); + if (wpan_dev->min_be == min_be && + wpan_dev->max_be == max_be) + return 0; + if (!(local->hw.flags & IEEE802154_HW_CSMA_PARAMS)) return -EOPNOTSUPP; @@ -135,6 +149,9 @@ ieee802154_set_short_addr(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, { ASSERT_RTNL(); + if (wpan_dev->short_addr == short_addr) + return 0; + wpan_dev->short_addr = short_addr; return 0; } @@ -148,6 +165,9 @@ ieee802154_set_max_csma_backoffs(struct wpan_phy *wpan_phy, ASSERT_RTNL(); + if (wpan_dev->csma_retries == max_csma_backoffs) + return 0; + if (!(local->hw.flags & IEEE802154_HW_CSMA_PARAMS)) return -EOPNOTSUPP; @@ -164,6 +184,9 @@ ieee802154_set_max_frame_retries(struct wpan_phy *wpan_phy, ASSERT_RTNL(); + if (wpan_dev->frame_retries == max_frame_retries) + return 0; + if (!(local->hw.flags & IEEE802154_HW_FRAME_RETRIES)) return -EOPNOTSUPP; @@ -179,6 +202,9 @@ ieee802154_set_lbt_mode(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, ASSERT_RTNL(); + if (wpan_dev->lbt == mode) + return 0; + if (!(local->hw.flags & IEEE802154_HW_LBT)) return -EOPNOTSUPP; -- cgit v1.2.3 From edea8f7c75ec6c238130bd7e74d9f6f4c26e97b0 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:46 +0200 Subject: cfg802154: introduce wpan phy flags This patch introduce a flag property for the wpan phy structure. The current flag settings in ieee802154_hw are accessable in mac802154 layer only which is okay for flags which indicates MAC handling which are done by phy. For real PHY layer settings like cca mode, transmit power, cca energy detection level. The difference between these flags are that the MAC handling flags are only handled in mac802154/HardMac layer e.g. on an interface up. The phy settings are direct netlink calls from nl802154 into the driver layer and the nl802154 need to have a chance to check if the driver supports this handling before sending to the next layer. We also check now on PHY flags while dumping and setting pib attributes. In comparing with MIB attributes the 802.15.4 gives us an default value which we assume when a transceiver implement less functionality. In case of MIB settings the nl802154 layer doesn't need to check on the ieee802154_hw flags then. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 9 +++++++-- include/net/cfg802154.h | 16 ++++++++++++++++ include/net/mac802154.h | 29 +++++++---------------------- net/ieee802154/nl802154.c | 27 +++++++++++++++++---------- net/mac802154/mac_cmd.c | 6 +++--- 5 files changed, 50 insertions(+), 37 deletions(-) (limited to 'include') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 151d57f4320d..b0ffd1cd0010 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1566,8 +1566,13 @@ at86rf230_detect_device(struct at86rf230_local *lp) } lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AACK | - IEEE802154_HW_TXPOWER | IEEE802154_HW_ARET | - IEEE802154_HW_AFILT | IEEE802154_HW_PROMISCUOUS; + IEEE802154_HW_CSMA_PARAMS | + IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT | + IEEE802154_HW_PROMISCUOUS; + + lp->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER | + WPAN_PHY_FLAG_CCA_ED_LEVEL | + WPAN_PHY_FLAG_CCA_MODE; lp->hw->phy->cca.mode = NL802154_CCA_ENERGY; diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 37abc1603285..a12c6c5247e9 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -106,6 +106,20 @@ wpan_phy_cca_cmp(const struct wpan_phy_cca *a, const struct wpan_phy_cca *b) return true; } +/** + * @WPAN_PHY_FLAG_TRANSMIT_POWER: Indicates that transceiver will support + * transmit power setting. + * @WPAN_PHY_FLAG_CCA_ED_LEVEL: Indicates that transceiver will support cca ed + * level setting. + * @WPAN_PHY_FLAG_CCA_MODE: Indicates that transceiver will support cca mode + * setting. + */ +enum wpan_phy_flags { + WPAN_PHY_FLAG_TXPOWER = BIT(1), + WPAN_PHY_FLAG_CCA_ED_LEVEL = BIT(2), + WPAN_PHY_FLAG_CCA_MODE = BIT(3), +}; + struct wpan_phy { struct mutex pib_lock; @@ -117,6 +131,8 @@ struct wpan_phy { */ const void *privid; + u32 flags; + /* * This is a PIB according to 802.15.4-2011. * We do not provide timing-related variables, as they diff --git a/include/net/mac802154.h b/include/net/mac802154.h index 71e245605ef8..9605c7f7453f 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -89,41 +89,26 @@ struct ieee802154_hw { #define IEEE802154_HW_TX_OMIT_CKSUM 0x00000001 /* Indicates that receiver will autorespond with ACK frames. */ #define IEEE802154_HW_AACK 0x00000002 -/* Indicates that transceiver will support transmit power setting. */ -#define IEEE802154_HW_TXPOWER 0x00000004 /* Indicates that transceiver will support listen before transmit. */ -#define IEEE802154_HW_LBT 0x00000008 -/* Indicates that transceiver will support cca mode setting. */ -#define IEEE802154_HW_CCA_MODE 0x00000010 -/* Indicates that transceiver will support cca ed level setting. */ -#define IEEE802154_HW_CCA_ED_LEVEL 0x00000020 +#define IEEE802154_HW_LBT 0x00000004 /* Indicates that transceiver will support csma (max_be, min_be, csma retries) * settings. */ -#define IEEE802154_HW_CSMA_PARAMS 0x00000040 +#define IEEE802154_HW_CSMA_PARAMS 0x00000008 /* Indicates that transceiver will support ARET frame retries setting. */ -#define IEEE802154_HW_FRAME_RETRIES 0x00000080 +#define IEEE802154_HW_FRAME_RETRIES 0x00000010 /* Indicates that transceiver will support hardware address filter setting. */ -#define IEEE802154_HW_AFILT 0x00000100 +#define IEEE802154_HW_AFILT 0x00000020 /* Indicates that transceiver will support promiscuous mode setting. */ -#define IEEE802154_HW_PROMISCUOUS 0x00000200 +#define IEEE802154_HW_PROMISCUOUS 0x00000040 /* Indicates that receiver omits FCS. */ -#define IEEE802154_HW_RX_OMIT_CKSUM 0x00000400 +#define IEEE802154_HW_RX_OMIT_CKSUM 0x00000080 /* Indicates that receiver will not filter frames with bad checksum. */ -#define IEEE802154_HW_RX_DROP_BAD_CKSUM 0x00000800 +#define IEEE802154_HW_RX_DROP_BAD_CKSUM 0x00000100 /* Indicates that receiver omits FCS and xmitter will add FCS on it's own. */ #define IEEE802154_HW_OMIT_CKSUM (IEEE802154_HW_TX_OMIT_CKSUM | \ IEEE802154_HW_RX_OMIT_CKSUM) -/* This groups the most common CSMA support fields into one. */ -#define IEEE802154_HW_CSMA (IEEE802154_HW_CCA_MODE | \ - IEEE802154_HW_CCA_ED_LEVEL | \ - IEEE802154_HW_CSMA_PARAMS) - -/* This groups the most common ARET support fields into one. */ -#define IEEE802154_HW_ARET (IEEE802154_HW_CSMA | \ - IEEE802154_HW_FRAME_RETRIES) - /* struct ieee802154_ops - callbacks from mac802154 to the driver * * This structure contains various callbacks that the driver may diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index fa0c4048b0e8..40fb0be009b2 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -291,19 +291,23 @@ static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev, goto nla_put_failure; /* cca mode */ - if (nla_put_u32(msg, NL802154_ATTR_CCA_MODE, - rdev->wpan_phy.cca.mode)) - goto nla_put_failure; - - if (rdev->wpan_phy.cca.mode == NL802154_CCA_ENERGY_CARRIER) { - if (nla_put_u32(msg, NL802154_ATTR_CCA_OPT, - rdev->wpan_phy.cca.opt)) + if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) { + if (nla_put_u32(msg, NL802154_ATTR_CCA_MODE, + rdev->wpan_phy.cca.mode)) goto nla_put_failure; + + if (rdev->wpan_phy.cca.mode == NL802154_CCA_ENERGY_CARRIER) { + if (nla_put_u32(msg, NL802154_ATTR_CCA_OPT, + rdev->wpan_phy.cca.opt)) + goto nla_put_failure; + } } - if (nla_put_s32(msg, NL802154_ATTR_TX_POWER, - rdev->wpan_phy.transmit_power)) - goto nla_put_failure; + if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) { + if (nla_put_s32(msg, NL802154_ATTR_TX_POWER, + rdev->wpan_phy.transmit_power)) + goto nla_put_failure; + } finish: genlmsg_end(msg, hdr); @@ -637,6 +641,9 @@ static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info) struct cfg802154_registered_device *rdev = info->user_ptr[0]; struct wpan_phy_cca cca; + if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) + return -EOPNOTSUPP; + if (!info->attrs[NL802154_ATTR_CCA_MODE]) return -EINVAL; diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c index bdccb4ecd30f..6dcbb3b5994c 100644 --- a/net/mac802154/mac_cmd.c +++ b/net/mac802154/mac_cmd.c @@ -91,19 +91,19 @@ static int mac802154_set_mac_params(struct net_device *dev, wpan_dev->frame_retries = params->frame_retries; wpan_dev->lbt = params->lbt; - if (local->hw.flags & IEEE802154_HW_TXPOWER) { + if (local->hw.phy->flags & WPAN_PHY_FLAG_TXPOWER) { ret = drv_set_tx_power(local, params->transmit_power); if (ret < 0) return ret; } - if (local->hw.flags & IEEE802154_HW_CCA_MODE) { + if (local->hw.phy->flags & WPAN_PHY_FLAG_CCA_MODE) { ret = drv_set_cca_mode(local, ¶ms->cca); if (ret < 0) return ret; } - if (local->hw.flags & IEEE802154_HW_CCA_ED_LEVEL) { + if (local->hw.phy->flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) { ret = drv_set_cca_ed_level(local, params->cca_ed_level); if (ret < 0) return ret; -- cgit v1.2.3 From 65318680c97cca15e3678148b3a5acaa33e991ec Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:47 +0200 Subject: ieee802154: add iftypes capability This patch adds capability flags for supported interface types. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 2 +- net/ieee802154/nl802154.c | 3 ++- net/mac802154/main.c | 6 ++++++ 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index a12c6c5247e9..11bbf17ad865 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -80,7 +80,7 @@ wpan_phy_supported_bool(bool b, enum nl802154_supported_bool_states st) struct wpan_phy_supported { u32 channels[IEEE802154_MAX_PAGE + 1], - cca_modes, cca_opts; + cca_modes, cca_opts, iftypes; enum nl802154_supported_bool_states lbt; u8 min_minbe, max_minbe, min_maxbe, max_maxbe, min_csma_backoffs, max_csma_backoffs; diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 40fb0be009b2..3afb20e43ff8 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -579,7 +579,8 @@ static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL802154_ATTR_IFTYPE]) { type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]); - if (type > NL802154_IFTYPE_MAX) + if (type > NL802154_IFTYPE_MAX || + !(rdev->wpan_phy.supported.iftypes & BIT(type))) return -EINVAL; } diff --git a/net/mac802154/main.c b/net/mac802154/main.c index ddcd6ff8d39c..356b346e1ee8 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -116,6 +116,9 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) phy->supported.max_csma_backoffs = 5; phy->supported.lbt = NL802154_SUPPORTED_BOOL_FALSE; + /* always supported */ + phy->supported.iftypes = BIT(NL802154_IFTYPE_NODE); + return &local->hw; } EXPORT_SYMBOL(ieee802154_alloc_hw); @@ -181,6 +184,9 @@ int ieee802154_register_hw(struct ieee802154_hw *hw) local->phy->supported.max_frame_retries = -1; } + if (hw->flags & IEEE802154_HW_PROMISCUOUS) + local->phy->supported.iftypes |= BIT(NL802154_IFTYPE_MONITOR); + rc = wpan_phy_register(local->phy); if (rc < 0) goto out_wq; -- cgit v1.2.3 From 0e66545701014814360b08a7a43ca652f82b6e5a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 17 May 2015 21:44:53 +0200 Subject: nl802154: add support for dump phy capabilities This patch add support to nl802154 to dump all phy capabilities which is inside the wpan_phy_supported struct. Also we introduce a new method to dumping supported channels. The new method will offer a easier interface and has lesser netlink traffic. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/nl802154.h | 57 ++++++++++++++++++++++ net/ieee802154/nl802154.c | 117 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 173 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/nl802154.h b/include/net/nl802154.h index 055277156eef..0badebd1de7f 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -100,6 +100,8 @@ enum nl802154_attrs { NL802154_ATTR_EXTENDED_ADDR, + NL802154_ATTR_WPAN_PHY_CAPS, + /* add attributes here, update the policy in nl802154.c */ __NL802154_ATTR_AFTER_LAST, @@ -119,6 +121,61 @@ enum nl802154_iftype { NL802154_IFTYPE_MAX = NUM_NL802154_IFTYPES - 1 }; +/** + * enum nl802154_wpan_phy_capability_attr - wpan phy capability attributes + * + * @__NL802154_CAP_ATTR_INVALID: attribute number 0 is reserved + * @NL802154_CAP_ATTR_CHANNELS: a nested attribute for nl802154_channel_attr + * @NL802154_CAP_ATTR_TX_POWERS: a nested attribute for + * nl802154_wpan_phy_tx_power + * @NL802154_CAP_ATTR_MIN_CCA_ED_LEVEL: minimum value for cca_ed_level + * @NL802154_CAP_ATTR_MAX_CCA_ED_LEVEL: maxmimum value for cca_ed_level + * @NL802154_CAP_ATTR_CCA_MODES: nl802154_cca_modes flags + * @NL802154_CAP_ATTR_CCA_OPTS: nl802154_cca_opts flags + * @NL802154_CAP_ATTR_MIN_MINBE: minimum of minbe value + * @NL802154_CAP_ATTR_MAX_MINBE: maximum of minbe value + * @NL802154_CAP_ATTR_MIN_MAXBE: minimum of maxbe value + * @NL802154_CAP_ATTR_MAX_MINBE: maximum of maxbe value + * @NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS: minimum of csma backoff value + * @NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS: maximum of csma backoffs value + * @NL802154_CAP_ATTR_MIN_FRAME_RETRIES: minimum of frame retries value + * @NL802154_CAP_ATTR_MAX_FRAME_RETRIES: maximum of frame retries value + * @NL802154_CAP_ATTR_IFTYPES: nl802154_iftype flags + * @NL802154_CAP_ATTR_LBT: nl802154_supported_bool_states flags + * @NL802154_CAP_ATTR_MAX: highest cap attribute currently defined + * @__NL802154_CAP_ATTR_AFTER_LAST: internal use + */ +enum nl802154_wpan_phy_capability_attr { + __NL802154_CAP_ATTR_INVALID, + + NL802154_CAP_ATTR_IFTYPES, + + NL802154_CAP_ATTR_CHANNELS, + NL802154_CAP_ATTR_TX_POWERS, + + NL802154_CAP_ATTR_CCA_ED_LEVELS, + NL802154_CAP_ATTR_CCA_MODES, + NL802154_CAP_ATTR_CCA_OPTS, + + NL802154_CAP_ATTR_MIN_MINBE, + NL802154_CAP_ATTR_MAX_MINBE, + + NL802154_CAP_ATTR_MIN_MAXBE, + NL802154_CAP_ATTR_MAX_MAXBE, + + NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS, + NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS, + + NL802154_CAP_ATTR_MIN_FRAME_RETRIES, + NL802154_CAP_ATTR_MAX_FRAME_RETRIES, + + NL802154_CAP_ATTR_LBT, + + /* keep last */ + __NL802154_CAP_ATTR_AFTER_LAST, + NL802154_CAP_ATTR_MAX = __NL802154_CAP_ATTR_AFTER_LAST - 1 +}; + /** * enum nl802154_cca_modes - cca modes * diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 3afb20e43ff8..54f4959fc9bb 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -225,6 +225,8 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { [NL802154_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_S8, }, [NL802154_ATTR_LBT_MODE] = { .type = NLA_U8, }, + + [NL802154_ATTR_WPAN_PHY_CAPS] = { .type = NLA_NESTED }, }; /* message building helper */ @@ -235,6 +237,28 @@ static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq, return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd); } +static int +nl802154_put_flags(struct sk_buff *msg, int attr, u32 mask) +{ + struct nlattr *nl_flags = nla_nest_start(msg, attr); + int i; + + if (!nl_flags) + return -ENOBUFS; + + i = 0; + while (mask) { + if ((mask & 1) && nla_put_flag(msg, i)) + return -ENOBUFS; + + mask >>= 1; + i++; + } + + nla_nest_end(msg, nl_flags); + return 0; +} + static int nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev, struct sk_buff *msg) @@ -256,6 +280,92 @@ nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev, return 0; } +static int +nl802154_put_capabilities(struct sk_buff *msg, + struct cfg802154_registered_device *rdev) +{ + const struct wpan_phy_supported *caps = &rdev->wpan_phy.supported; + struct nlattr *nl_caps, *nl_channels; + int i; + + nl_caps = nla_nest_start(msg, NL802154_ATTR_WPAN_PHY_CAPS); + if (!nl_caps) + return -ENOBUFS; + + nl_channels = nla_nest_start(msg, NL802154_CAP_ATTR_CHANNELS); + if (!nl_channels) + return -ENOBUFS; + + for (i = 0; i <= IEEE802154_MAX_PAGE; i++) { + if (caps->channels[i]) { + if (nl802154_put_flags(msg, i, caps->channels[i])) + return -ENOBUFS; + } + } + + nla_nest_end(msg, nl_channels); + + if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) { + struct nlattr *nl_ed_lvls; + + nl_ed_lvls = nla_nest_start(msg, + NL802154_CAP_ATTR_CCA_ED_LEVELS); + if (!nl_ed_lvls) + return -ENOBUFS; + + for (i = 0; i < caps->cca_ed_levels_size; i++) { + if (nla_put_s32(msg, i, caps->cca_ed_levels[i])) + return -ENOBUFS; + } + + nla_nest_end(msg, nl_ed_lvls); + } + + if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) { + struct nlattr *nl_tx_pwrs; + + nl_tx_pwrs = nla_nest_start(msg, NL802154_CAP_ATTR_TX_POWERS); + if (!nl_tx_pwrs) + return -ENOBUFS; + + for (i = 0; i < caps->tx_powers_size; i++) { + if (nla_put_s32(msg, i, caps->tx_powers[i])) + return -ENOBUFS; + } + + nla_nest_end(msg, nl_tx_pwrs); + } + + if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) { + if (nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_MODES, + caps->cca_modes) || + nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_OPTS, + caps->cca_opts)) + return -ENOBUFS; + } + + if (nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MINBE, caps->min_minbe) || + nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MINBE, caps->max_minbe) || + nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MAXBE, caps->min_maxbe) || + nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MAXBE, caps->max_maxbe) || + nla_put_u8(msg, NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS, + caps->min_csma_backoffs) || + nla_put_u8(msg, NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS, + caps->max_csma_backoffs) || + nla_put_s8(msg, NL802154_CAP_ATTR_MIN_FRAME_RETRIES, + caps->min_frame_retries) || + nla_put_s8(msg, NL802154_CAP_ATTR_MAX_FRAME_RETRIES, + caps->max_frame_retries) || + nl802154_put_flags(msg, NL802154_CAP_ATTR_IFTYPES, + caps->iftypes) || + nla_put_u32(msg, NL802154_CAP_ATTR_LBT, caps->lbt)) + return -ENOBUFS; + + nla_nest_end(msg, nl_caps); + + return 0; +} + static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev, enum nl802154_commands cmd, struct sk_buff *msg, u32 portid, u32 seq, @@ -286,7 +396,9 @@ static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev, rdev->wpan_phy.current_channel)) goto nla_put_failure; - /* supported channels array */ + /* TODO remove this behaviour, we still keep support it for a while + * so users can change the behaviour to the new one. + */ if (nl802154_send_wpan_phy_channels(rdev, msg)) goto nla_put_failure; @@ -309,6 +421,9 @@ static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev, goto nla_put_failure; } + if (nl802154_put_capabilities(msg, rdev)) + goto nla_put_failure; + finish: genlmsg_end(msg, hdr); return 0; -- cgit v1.2.3 From b5d721d761fccf491f92eefc611e318561683d0a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 18 May 2015 17:06:14 -0700 Subject: inet: properly align icsk_ca_priv tcp_illinois and upcoming tcp_cdg require 64bit alignment of icsk_ca_priv x86 does not care, but other architectures might. Fixes: 05cbc0db03e82 ("ipv4: Create probe timer for tcp PMTU as per RFC4821") Signed-off-by: Eric Dumazet Cc: Fan Du Acked-by: Fan Du Signed-off-by: David S. Miller --- include/net/inet_connection_sock.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index 48a815823587..497bc14cdb85 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -129,9 +129,10 @@ struct inet_connection_sock { u32 probe_timestamp; } icsk_mtup; - u32 icsk_ca_priv[16]; u32 icsk_user_timeout; -#define ICSK_CA_PRIV_SIZE (16 * sizeof(u32)) + + u64 icsk_ca_priv[64 / sizeof(u64)]; +#define ICSK_CA_PRIV_SIZE (8 * sizeof(u64)) }; #define ICSK_TIME_RETRANS 1 /* Retransmit timer */ -- cgit v1.2.3 From 77bb3dfdc0d554befad58fdefbc41be5bc3ed38a Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Tue, 19 May 2015 18:40:49 +0100 Subject: xen/events: don't bind non-percpu VIRQs with percpu chip A non-percpu VIRQ (e.g., VIRQ_CONSOLE) may be freed on a different VCPU than it is bound to. This can result in a race between handle_percpu_irq() and removing the action in __free_irq() because handle_percpu_irq() does not take desc->lock. The interrupt handler sees a NULL action and oopses. Only use the percpu chip/handler for per-CPU VIRQs (like VIRQ_TIMER). # cat /proc/interrupts | grep virq 40: 87246 0 xen-percpu-virq timer0 44: 0 0 xen-percpu-virq debug0 47: 0 20995 xen-percpu-virq timer1 51: 0 0 xen-percpu-virq debug1 69: 0 0 xen-dyn-virq xen-pcpu 74: 0 0 xen-dyn-virq mce 75: 29 0 xen-dyn-virq hvc_console Signed-off-by: David Vrabel Cc: --- drivers/tty/hvc/hvc_xen.c | 2 +- drivers/xen/events/events_base.c | 12 ++++++++---- include/xen/events.h | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 5bab1c684bb1..7a3d146a5f0e 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -289,7 +289,7 @@ static int xen_initial_domain_console_init(void) return -ENOMEM; } - info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0); + info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false); info->vtermno = HVC_COOKIE; spin_lock(&xencons_lock); diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 2b8553bd8715..38387950490e 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -957,7 +957,7 @@ unsigned xen_evtchn_nr_channels(void) } EXPORT_SYMBOL_GPL(xen_evtchn_nr_channels); -int bind_virq_to_irq(unsigned int virq, unsigned int cpu) +int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu) { struct evtchn_bind_virq bind_virq; int evtchn, irq, ret; @@ -971,8 +971,12 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu) if (irq < 0) goto out; - irq_set_chip_and_handler_name(irq, &xen_percpu_chip, - handle_percpu_irq, "virq"); + if (percpu) + irq_set_chip_and_handler_name(irq, &xen_percpu_chip, + handle_percpu_irq, "virq"); + else + irq_set_chip_and_handler_name(irq, &xen_dynamic_chip, + handle_edge_irq, "virq"); bind_virq.virq = virq; bind_virq.vcpu = cpu; @@ -1062,7 +1066,7 @@ int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu, { int irq, retval; - irq = bind_virq_to_irq(virq, cpu); + irq = bind_virq_to_irq(virq, cpu, irqflags & IRQF_PERCPU); if (irq < 0) return irq; retval = request_irq(irq, handler, irqflags, devname, dev_id); diff --git a/include/xen/events.h b/include/xen/events.h index 5321cd9636e6..7d95fdf9cf3e 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -17,7 +17,7 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id); -int bind_virq_to_irq(unsigned int virq, unsigned int cpu); +int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu); int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu, irq_handler_t handler, unsigned long irqflags, const char *devname, -- cgit v1.2.3 From c9a70d43461d83818825ae065bb8fc887421e150 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 18 May 2015 16:31:47 +0530 Subject: net-next: ethtool: Added port speed macros. Signed-off-by: Parav Pandit Signed-off-by: David S. Miller --- include/uapi/linux/ethtool.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index 2e49fc880d29..ae832b45b44c 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -1264,15 +1264,19 @@ enum ethtool_sfeatures_retval_bits { * it was forced up into this mode or autonegotiated. */ -/* The forced speed, 10Mb, 100Mb, gigabit, [2.5|10|20|40|56]GbE. */ +/* The forced speed, 10Mb, 100Mb, gigabit, [2.5|5|10|20|25|40|50|56|100]GbE. */ #define SPEED_10 10 #define SPEED_100 100 #define SPEED_1000 1000 #define SPEED_2500 2500 +#define SPEED_5000 5000 #define SPEED_10000 10000 #define SPEED_20000 20000 +#define SPEED_25000 25000 #define SPEED_40000 40000 +#define SPEED_50000 50000 #define SPEED_56000 56000 +#define SPEED_100000 100000 #define SPEED_UNKNOWN -1 -- cgit v1.2.3 From 492135557dc090a1abb2cfbe1a412757e3ed68ab Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 19 May 2015 21:04:22 +0200 Subject: tcp: add rfc3168, section 6.1.1.1. fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This work as a follow-up of commit f7b3bec6f516 ("net: allow setting ecn via routing table") and adds RFC3168 section 6.1.1.1. fallback for outgoing ECN connections. In other words, this work adds a retry with a non-ECN setup SYN packet, as suggested from the RFC on the first timeout: [...] A host that receives no reply to an ECN-setup SYN within the normal SYN retransmission timeout interval MAY resend the SYN and any subsequent SYN retransmissions with CWR and ECE cleared. [...] Schematic client-side view when assuming the server is in tcp_ecn=2 mode, that is, Linux default since 2009 via commit 255cac91c3c9 ("tcp: extend ECN sysctl to allow server-side only ECN"): 1) Normal ECN-capable path: SYN ECE CWR -----> <----- SYN ACK ECE ACK -----> 2) Path with broken middlebox, when client has fallback: SYN ECE CWR ----X crappy middlebox drops packet (timeout, rtx) SYN -----> <----- SYN ACK ACK -----> In case we would not have the fallback implemented, the middlebox drop point would basically end up as: SYN ECE CWR ----X crappy middlebox drops packet (timeout, rtx) SYN ECE CWR ----X crappy middlebox drops packet (timeout, rtx) SYN ECE CWR ----X crappy middlebox drops packet (timeout, rtx) In any case, it's rather a smaller percentage of sites where there would occur such additional setup latency: it was found in end of 2014 that ~56% of IPv4 and 65% of IPv6 servers of Alexa 1 million list would negotiate ECN (aka tcp_ecn=2 default), 0.42% of these webservers will fail to connect when trying to negotiate with ECN (tcp_ecn=1) due to timeouts, which the fallback would mitigate with a slight latency trade-off. Recent related paper on this topic: Brian Trammell, Mirja Kühlewind, Damiano Boppart, Iain Learmonth, Gorry Fairhurst, and Richard Scheffenegger: "Enabling Internet-Wide Deployment of Explicit Congestion Notification." Proc. PAM 2015, New York. http://ecn.ethz.ch/ecn-pam15.pdf Thus, when net.ipv4.tcp_ecn=1 is being set, the patch will perform RFC3168, section 6.1.1.1. fallback on timeout. For users explicitly not wanting this which can be in DC use case, we add a net.ipv4.tcp_ecn_fallback knob that allows for disabling the fallback. tp->ecn_flags are not being cleared in tcp_ecn_clear_syn() on output, but rather we let tcp_ecn_rcv_synack() take that over on input path in case a SYN ACK ECE was delayed. Thus a spurious SYN retransmission will not prevent ECN being negotiated eventually in that case. Reference: https://www.ietf.org/proceedings/92/slides/slides-92-iccrg-1.pdf Reference: https://www.ietf.org/proceedings/89/slides/slides-89-tsvarea-1.pdf Signed-off-by: Daniel Borkmann Signed-off-by: Florian Westphal Signed-off-by: Mirja Kühlewind Signed-off-by: Brian Trammell Cc: Eric Dumazet Cc: Dave That Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- Documentation/networking/dctcp.txt | 1 + Documentation/networking/ip-sysctl.txt | 9 +++++++++ include/net/netns/ipv4.h | 2 ++ include/net/tcp.h | 2 ++ net/ipv4/sysctl_net_ipv4.c | 7 +++++++ net/ipv4/tcp_ipv4.c | 5 ++++- net/ipv4/tcp_output.c | 13 +++++++++++++ 7 files changed, 38 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/networking/dctcp.txt b/Documentation/networking/dctcp.txt index 0d5dfbc89ec9..13a857753208 100644 --- a/Documentation/networking/dctcp.txt +++ b/Documentation/networking/dctcp.txt @@ -8,6 +8,7 @@ the data center network to provide multi-bit feedback to the end hosts. To enable it on end hosts: sysctl -w net.ipv4.tcp_congestion_control=dctcp + sysctl -w net.ipv4.tcp_ecn_fallback=0 (optional) All switches in the data center network running DCTCP must support ECN marking and be configured for marking when reaching defined switch buffer diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 5095c63e50ed..cb083e0d682c 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -267,6 +267,15 @@ tcp_ecn - INTEGER but do not request ECN on outgoing connections. Default: 2 +tcp_ecn_fallback - BOOLEAN + If the kernel detects that ECN connection misbehaves, enable fall + back to non-ECN. Currently, this knob implements the fallback + from RFC3168, section 6.1.1.1., but we reserve that in future, + additional detection mechanisms could be implemented under this + knob. The value is not used, if tcp_ecn or per route (or congestion + control) ECN settings are disabled. + Default: 1 (fallback enabled) + tcp_fack - BOOLEAN Enable FACK congestion avoidance and fast retransmission. The value is not used, if tcp_sack is not enabled. diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 614a49be68a9..6848b8bb2e63 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -77,6 +77,8 @@ struct netns_ipv4 { struct local_ports ip_local_ports; int sysctl_tcp_ecn; + int sysctl_tcp_ecn_fallback; + int sysctl_ip_no_pmtu_disc; int sysctl_ip_fwd_use_pmtu; int sysctl_ip_nonlocal_bind; diff --git a/include/net/tcp.h b/include/net/tcp.h index 0d85223efa4c..2bb2bad21d5c 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -712,6 +712,8 @@ static inline u32 tcp_skb_timestamp(const struct sk_buff *skb) #define TCPHDR_ECE 0x40 #define TCPHDR_CWR 0x80 +#define TCPHDR_SYN_ECN (TCPHDR_SYN | TCPHDR_ECE | TCPHDR_CWR) + /* This is what the send packet queuing engine uses to pass * TCP per-packet control information to the transmission code. * We also store the host-order sequence numbers in here too. diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index c3852a7ff3c7..841de32f1fee 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -820,6 +820,13 @@ static struct ctl_table ipv4_net_table[] = { .mode = 0644, .proc_handler = proc_dointvec }, + { + .procname = "tcp_ecn_fallback", + .data = &init_net.ipv4.sysctl_tcp_ecn_fallback, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, { .procname = "ip_local_port_range", .maxlen = sizeof(init_net.ipv4.ip_local_ports.range), diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 91cb4768a860..0cc4b5a630cd 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2411,12 +2411,15 @@ static int __net_init tcp_sk_init(struct net *net) goto fail; *per_cpu_ptr(net->ipv4.tcp_sk, cpu) = sk; } + net->ipv4.sysctl_tcp_ecn = 2; + net->ipv4.sysctl_tcp_ecn_fallback = 1; + net->ipv4.sysctl_tcp_base_mss = TCP_BASE_MSS; net->ipv4.sysctl_tcp_probe_threshold = TCP_PROBE_THRESHOLD; net->ipv4.sysctl_tcp_probe_interval = TCP_PROBE_INTERVAL; - return 0; + return 0; fail: tcp_sk_exit(net); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 08c2cc40b26d..e29d43b5a0bb 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -350,6 +350,15 @@ static void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb) } } +static void tcp_ecn_clear_syn(struct sock *sk, struct sk_buff *skb) +{ + if (sock_net(sk)->ipv4.sysctl_tcp_ecn_fallback) + /* tp->ecn_flags are cleared at a later point in time when + * SYN ACK is ultimatively being received. + */ + TCP_SKB_CB(skb)->tcp_flags &= ~(TCPHDR_ECE | TCPHDR_CWR); +} + static void tcp_ecn_make_synack(const struct request_sock *req, struct tcphdr *th, struct sock *sk) @@ -2615,6 +2624,10 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) } } + /* RFC3168, section 6.1.1.1. ECN fallback */ + if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN_ECN) == TCPHDR_SYN_ECN) + tcp_ecn_clear_syn(sk, skb); + tcp_retrans_try_collapse(sk, skb, cur_mss); /* Make a copy, if the first transmission SKB clone we made -- cgit v1.2.3 From 06b2c61c92a9942769ee8da22d3ce8b8b935c038 Mon Sep 17 00:00:00 2001 From: Andy Zhou Date: Tue, 19 May 2015 12:41:47 -0700 Subject: ip: remove unused function prototype ip_do_nat() function was removed prior to kernel 3.4. Remove the unnecessary function prototype as well. Reported-by: Florian Westphal Signed-off-by: Andy Zhou Signed-off-by: David S. Miller --- include/net/ip.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/net/ip.h b/include/net/ip.h index cd7a6a458bb6..7921a36b805c 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -110,7 +110,6 @@ int ip_output(struct sock *sk, struct sk_buff *skb); int ip_mc_output(struct sock *sk, struct sk_buff *skb); int ip_do_fragment(struct sock *sk, struct sk_buff *skb, int (*output)(struct sock *, struct sk_buff *)); -int ip_do_nat(struct sk_buff *skb); void ip_send_check(struct iphdr *ip); int __ip_local_out(struct sk_buff *skb); int ip_local_out_sk(struct sock *sk, struct sk_buff *skb); -- cgit v1.2.3 From faecbb45ebefb20260ad4a631e011e93c896cb73 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 20 May 2015 13:42:25 +0200 Subject: Revert "netfilter: bridge: query conntrack about skb dnat" This reverts commit c055d5b03bb4cb69d349d787c9787c0383abd8b2. There are two issues: 'dnat_took_place' made me think that this is related to -j DNAT/MASQUERADE. But thats only one part of the story. This is also relevant for SNAT when we undo snat translation in reverse/reply direction. Furthermore, I originally wanted to do this mainly to avoid storing ipv6 addresses once we make DNAT/REDIRECT work for ipv6 on bridges. However, I forgot about SNPT/DNPT which is stateless. So we can't escape storing address for ipv6 anyway. Might as well do it for ipv4 too. Reported-and-tested-by: Bernhard Thaler Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/linux/skbuff.h | 1 + net/bridge/br_netfilter.c | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 66e374d62f64..f15154a879c7 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -176,6 +176,7 @@ struct nf_bridge_info { struct net_device *physindev; struct net_device *physoutdev; char neigh_header[8]; + __be32 ipv4_daddr; }; #endif diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index ab55e2472beb..60ddfbeb47f5 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -37,10 +37,6 @@ #include #include -#if IS_ENABLED(CONFIG_NF_CONNTRACK) -#include -#endif - #include #include "br_private.h" #ifdef CONFIG_SYSCTL @@ -350,24 +346,15 @@ free_skb: return 0; } -static bool dnat_took_place(const struct sk_buff *skb) +static bool daddr_was_changed(const struct sk_buff *skb, + const struct nf_bridge_info *nf_bridge) { -#if IS_ENABLED(CONFIG_NF_CONNTRACK) - enum ip_conntrack_info ctinfo; - struct nf_conn *ct; - - ct = nf_ct_get(skb, &ctinfo); - if (!ct || nf_ct_is_untracked(ct)) - return false; - - return test_bit(IPS_DST_NAT_BIT, &ct->status); -#else - return false; -#endif + return ip_hdr(skb)->daddr != nf_bridge->ipv4_daddr; } /* This requires some explaining. If DNAT has taken place, * we will need to fix up the destination Ethernet address. + * This is also true when SNAT takes place (for the reply direction). * * There are two cases to consider: * 1. The packet was DNAT'ed to a device in the same bridge @@ -421,7 +408,7 @@ static int br_nf_pre_routing_finish(struct sock *sk, struct sk_buff *skb) nf_bridge->pkt_otherhost = false; } nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; - if (dnat_took_place(skb)) { + if (daddr_was_changed(skb, nf_bridge)) { if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) { struct in_device *in_dev = __in_dev_get_rcu(dev); @@ -632,6 +619,7 @@ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { + struct nf_bridge_info *nf_bridge; struct net_bridge_port *p; struct net_bridge *br; __u32 len = nf_bridge_encap_header_len(skb); @@ -669,6 +657,9 @@ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops, if (!setup_pre_routing(skb)) return NF_DROP; + nf_bridge = nf_bridge_info_get(skb); + nf_bridge->ipv4_daddr = ip_hdr(skb)->daddr; + skb->protocol = htons(ETH_P_IP); NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, state->sk, skb, -- cgit v1.2.3 From eb9344781a2f8381ed60cd9e662d9ced2d168ecb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 19 May 2015 13:26:55 -0700 Subject: tcp: add a force_schedule argument to sk_stream_alloc_skb() In commit 8e4d980ac215 ("tcp: fix behavior for epoll edge trigger") we fixed a possible hang of TCP sockets under memory pressure, by allowing sk_stream_alloc_skb() to use sk_forced_mem_schedule() if no packet is in socket write queue. It turns out there are other cases where we want to force memory schedule : tcp_fragment() & tso_fragment() need to split a big TSO packet into two smaller ones. If we block here because of TCP memory pressure, we can effectively block TCP socket from sending new data. If no further ACK is coming, this hang would be definitive, and socket has no chance to effectively reduce its memory usage. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 3 ++- net/ipv4/tcp.c | 19 +++++++++++-------- net/ipv4/tcp_output.c | 10 +++++----- 3 files changed, 18 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/include/net/sock.h b/include/net/sock.h index 4581a60636f8..26c1c3171e00 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2025,7 +2025,8 @@ static inline void sk_stream_moderate_sndbuf(struct sock *sk) } } -struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp); +struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp, + bool force_schedule); /** * sk_page_frag - return an appropriate page_frag diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index bb9bb844204f..ca1d476c80ef 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -808,7 +808,8 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, } EXPORT_SYMBOL(tcp_splice_read); -struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp) +struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp, + bool force_schedule) { struct sk_buff *skb; @@ -820,15 +821,15 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp) skb = alloc_skb_fclone(size + sk->sk_prot->max_header, gfp); if (likely(skb)) { - bool mem_schedule; + bool mem_scheduled; - if (skb_queue_len(&sk->sk_write_queue) == 0) { - mem_schedule = true; + if (force_schedule) { + mem_scheduled = true; sk_forced_mem_schedule(sk, skb->truesize); } else { - mem_schedule = sk_wmem_schedule(sk, skb->truesize); + mem_scheduled = sk_wmem_schedule(sk, skb->truesize); } - if (likely(mem_schedule)) { + if (likely(mem_scheduled)) { skb_reserve(skb, sk->sk_prot->max_header); /* * Make sure that we have exactly size bytes @@ -918,7 +919,8 @@ new_segment: if (!sk_stream_memory_free(sk)) goto wait_for_sndbuf; - skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation); + skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation, + skb_queue_empty(&sk->sk_write_queue)); if (!skb) goto wait_for_memory; @@ -1154,7 +1156,8 @@ new_segment: skb = sk_stream_alloc_skb(sk, select_size(sk, sg), - sk->sk_allocation); + sk->sk_allocation, + skb_queue_empty(&sk->sk_write_queue)); if (!skb) goto wait_for_memory; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index e29d43b5a0bb..3aebe0157dfa 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1172,7 +1172,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, return -ENOMEM; /* Get a new skb... force flag on. */ - buff = sk_stream_alloc_skb(sk, nsize, gfp); + buff = sk_stream_alloc_skb(sk, nsize, gfp, true); if (!buff) return -ENOMEM; /* We'll just try again later. */ @@ -1731,7 +1731,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len, if (skb->len != skb->data_len) return tcp_fragment(sk, skb, len, mss_now, gfp); - buff = sk_stream_alloc_skb(sk, 0, gfp); + buff = sk_stream_alloc_skb(sk, 0, gfp, true); if (unlikely(!buff)) return -ENOMEM; @@ -1950,7 +1950,7 @@ static int tcp_mtu_probe(struct sock *sk) } /* We're allowed to probe. Build it now. */ - nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC); + nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC, false); if (!nskb) return -1; sk->sk_wmem_queued += nskb->truesize; @@ -3190,7 +3190,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) /* limit to order-0 allocations */ space = min_t(size_t, space, SKB_MAX_HEAD(MAX_TCP_HEADER)); - syn_data = sk_stream_alloc_skb(sk, space, sk->sk_allocation); + syn_data = sk_stream_alloc_skb(sk, space, sk->sk_allocation, false); if (!syn_data) goto fallback; syn_data->ip_summed = CHECKSUM_PARTIAL; @@ -3256,7 +3256,7 @@ int tcp_connect(struct sock *sk) return 0; } - buff = sk_stream_alloc_skb(sk, 0, sk->sk_allocation); + buff = sk_stream_alloc_skb(sk, 0, sk->sk_allocation, true); if (unlikely(!buff)) return -ENOBUFS; -- cgit v1.2.3 From 04fd61ab36ec065e194ab5e74ae34a5240d992bb Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 19 May 2015 16:59:03 -0700 Subject: bpf: allow bpf programs to tail-call other bpf programs introduce bpf_tail_call(ctx, &jmp_table, index) helper function which can be used from BPF programs like: int bpf_prog(struct pt_regs *ctx) { ... bpf_tail_call(ctx, &jmp_table, index); ... } that is roughly equivalent to: int bpf_prog(struct pt_regs *ctx) { ... if (jmp_table[index]) return (*jmp_table[index])(ctx); ... } The important detail that it's not a normal call, but a tail call. The kernel stack is precious, so this helper reuses the current stack frame and jumps into another BPF program without adding extra call frame. It's trivially done in interpreter and a bit trickier in JITs. In case of x64 JIT the bigger part of generated assembler prologue is common for all programs, so it is simply skipped while jumping. Other JITs can do similar prologue-skipping optimization or do stack unwind before jumping into the next program. bpf_tail_call() arguments: ctx - context pointer jmp_table - one of BPF_MAP_TYPE_PROG_ARRAY maps used as the jump table index - index in the jump table Since all BPF programs are idenitified by file descriptor, user space need to populate the jmp_table with FDs of other BPF programs. If jmp_table[index] is empty the bpf_tail_call() doesn't jump anywhere and program execution continues as normal. New BPF_MAP_TYPE_PROG_ARRAY map type is introduced so that user space can populate this jmp_table array with FDs of other bpf programs. Programs can share the same jmp_table array or use multiple jmp_tables. The chain of tail calls can form unpredictable dynamic loops therefore tail_call_cnt is used to limit the number of calls and currently is set to 32. Use cases: Acked-by: Daniel Borkmann ========== - simplify complex programs by splitting them into a sequence of small programs - dispatch routine For tracing and future seccomp the program may be triggered on all system calls, but processing of syscall arguments will be different. It's more efficient to implement them as: int syscall_entry(struct seccomp_data *ctx) { bpf_tail_call(ctx, &syscall_jmp_table, ctx->nr /* syscall number */); ... default: process unknown syscall ... } int sys_write_event(struct seccomp_data *ctx) {...} int sys_read_event(struct seccomp_data *ctx) {...} syscall_jmp_table[__NR_write] = sys_write_event; syscall_jmp_table[__NR_read] = sys_read_event; For networking the program may call into different parsers depending on packet format, like: int packet_parser(struct __sk_buff *skb) { ... parse L2, L3 here ... __u8 ipproto = load_byte(skb, ... offsetof(struct iphdr, protocol)); bpf_tail_call(skb, &ipproto_jmp_table, ipproto); ... default: process unknown protocol ... } int parse_tcp(struct __sk_buff *skb) {...} int parse_udp(struct __sk_buff *skb) {...} ipproto_jmp_table[IPPROTO_TCP] = parse_tcp; ipproto_jmp_table[IPPROTO_UDP] = parse_udp; - for TC use case, bpf_tail_call() allows to implement reclassify-like logic - bpf_map_update_elem/delete calls into BPF_MAP_TYPE_PROG_ARRAY jump table are atomic, so user space can build chains of BPF programs on the fly Implementation details: ======================= - high performance of bpf_tail_call() is the goal. It could have been implemented without JIT changes as a wrapper on top of BPF_PROG_RUN() macro, but with two downsides: . all programs would have to pay performance penalty for this feature and tail call itself would be slower, since mandatory stack unwind, return, stack allocate would be done for every tailcall. . tailcall would be limited to programs running preempt_disabled, since generic 'void *ctx' doesn't have room for 'tail_call_cnt' and it would need to be either global per_cpu variable accessed by helper and by wrapper or global variable protected by locks. In this implementation x64 JIT bypasses stack unwind and jumps into the callee program after prologue. - bpf_prog_array_compatible() ensures that prog_type of callee and caller are the same and JITed/non-JITed flag is the same, since calling JITed program from non-JITed is invalid, since stack frames are different. Similarly calling kprobe type program from socket type program is invalid. - jump table is implemented as BPF_MAP_TYPE_PROG_ARRAY to reuse 'map' abstraction, its user space API and all of verifier logic. It's in the existing arraymap.c file, since several functions are shared with regular array map. Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/bpf.h | 22 +++++++++ include/linux/filter.h | 2 +- include/uapi/linux/bpf.h | 10 +++++ kernel/bpf/arraymap.c | 113 ++++++++++++++++++++++++++++++++++++++++++++--- kernel/bpf/core.c | 73 +++++++++++++++++++++++++++++- kernel/bpf/syscall.c | 23 +++++++++- kernel/bpf/verifier.c | 17 +++++++ kernel/trace/bpf_trace.c | 2 + net/core/filter.c | 2 + 9 files changed, 255 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index d5cda067115a..8821b9a8689e 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -126,6 +126,27 @@ struct bpf_prog_aux { struct work_struct work; }; +struct bpf_array { + struct bpf_map map; + u32 elem_size; + /* 'ownership' of prog_array is claimed by the first program that + * is going to use this map or by the first program which FD is stored + * in the map to make sure that all callers and callees have the same + * prog_type and JITed flag + */ + enum bpf_prog_type owner_prog_type; + bool owner_jited; + union { + char value[0] __aligned(8); + struct bpf_prog *prog[0] __aligned(8); + }; +}; +#define MAX_TAIL_CALL_CNT 32 + +u64 bpf_tail_call(u64 ctx, u64 r2, u64 index, u64 r4, u64 r5); +void bpf_prog_array_map_clear(struct bpf_map *map); +bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp); + #ifdef CONFIG_BPF_SYSCALL void bpf_register_prog_type(struct bpf_prog_type_list *tl); void bpf_register_map_type(struct bpf_map_type_list *tl); @@ -160,5 +181,6 @@ extern const struct bpf_func_proto bpf_map_delete_elem_proto; extern const struct bpf_func_proto bpf_get_prandom_u32_proto; extern const struct bpf_func_proto bpf_get_smp_processor_id_proto; +extern const struct bpf_func_proto bpf_tail_call_proto; #endif /* _LINUX_BPF_H */ diff --git a/include/linux/filter.h b/include/linux/filter.h index 200be4a74a33..17724f6ea983 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -378,7 +378,7 @@ static inline void bpf_prog_unlock_ro(struct bpf_prog *fp) int sk_filter(struct sock *sk, struct sk_buff *skb); -void bpf_prog_select_runtime(struct bpf_prog *fp); +int bpf_prog_select_runtime(struct bpf_prog *fp); void bpf_prog_free(struct bpf_prog *fp); struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index a9ebdf5701e8..f0a9af8b4dae 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -113,6 +113,7 @@ enum bpf_map_type { BPF_MAP_TYPE_UNSPEC, BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_ARRAY, + BPF_MAP_TYPE_PROG_ARRAY, }; enum bpf_prog_type { @@ -210,6 +211,15 @@ enum bpf_func_id { * Return: 0 on success */ BPF_FUNC_l4_csum_replace, + + /** + * bpf_tail_call(ctx, prog_array_map, index) - jump into another BPF program + * @ctx: context pointer passed to next program + * @prog_array_map: pointer to map which type is BPF_MAP_TYPE_PROG_ARRAY + * @index: index inside array that selects specific program to run + * Return: 0 on success + */ + BPF_FUNC_tail_call, __BPF_FUNC_MAX_ID, }; diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 8a6616583f38..614bcd4c1d74 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -14,12 +14,7 @@ #include #include #include - -struct bpf_array { - struct bpf_map map; - u32 elem_size; - char value[0] __aligned(8); -}; +#include /* Called from syscall */ static struct bpf_map *array_map_alloc(union bpf_attr *attr) @@ -154,3 +149,109 @@ static int __init register_array_map(void) return 0; } late_initcall(register_array_map); + +static struct bpf_map *prog_array_map_alloc(union bpf_attr *attr) +{ + /* only bpf_prog file descriptors can be stored in prog_array map */ + if (attr->value_size != sizeof(u32)) + return ERR_PTR(-EINVAL); + return array_map_alloc(attr); +} + +static void prog_array_map_free(struct bpf_map *map) +{ + struct bpf_array *array = container_of(map, struct bpf_array, map); + int i; + + synchronize_rcu(); + + /* make sure it's empty */ + for (i = 0; i < array->map.max_entries; i++) + BUG_ON(array->prog[i] != NULL); + kvfree(array); +} + +static void *prog_array_map_lookup_elem(struct bpf_map *map, void *key) +{ + return NULL; +} + +/* only called from syscall */ +static int prog_array_map_update_elem(struct bpf_map *map, void *key, + void *value, u64 map_flags) +{ + struct bpf_array *array = container_of(map, struct bpf_array, map); + struct bpf_prog *prog, *old_prog; + u32 index = *(u32 *)key, ufd; + + if (map_flags != BPF_ANY) + return -EINVAL; + + if (index >= array->map.max_entries) + return -E2BIG; + + ufd = *(u32 *)value; + prog = bpf_prog_get(ufd); + if (IS_ERR(prog)) + return PTR_ERR(prog); + + if (!bpf_prog_array_compatible(array, prog)) { + bpf_prog_put(prog); + return -EINVAL; + } + + old_prog = xchg(array->prog + index, prog); + if (old_prog) + bpf_prog_put(old_prog); + + return 0; +} + +static int prog_array_map_delete_elem(struct bpf_map *map, void *key) +{ + struct bpf_array *array = container_of(map, struct bpf_array, map); + struct bpf_prog *old_prog; + u32 index = *(u32 *)key; + + if (index >= array->map.max_entries) + return -E2BIG; + + old_prog = xchg(array->prog + index, NULL); + if (old_prog) { + bpf_prog_put(old_prog); + return 0; + } else { + return -ENOENT; + } +} + +/* decrement refcnt of all bpf_progs that are stored in this map */ +void bpf_prog_array_map_clear(struct bpf_map *map) +{ + struct bpf_array *array = container_of(map, struct bpf_array, map); + int i; + + for (i = 0; i < array->map.max_entries; i++) + prog_array_map_delete_elem(map, &i); +} + +static const struct bpf_map_ops prog_array_ops = { + .map_alloc = prog_array_map_alloc, + .map_free = prog_array_map_free, + .map_get_next_key = array_map_get_next_key, + .map_lookup_elem = prog_array_map_lookup_elem, + .map_update_elem = prog_array_map_update_elem, + .map_delete_elem = prog_array_map_delete_elem, +}; + +static struct bpf_map_type_list prog_array_type __read_mostly = { + .ops = &prog_array_ops, + .type = BPF_MAP_TYPE_PROG_ARRAY, +}; + +static int __init register_prog_array_map(void) +{ + bpf_register_map_type(&prog_array_type); + return 0; +} +late_initcall(register_prog_array_map); diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 54f0e7fcd0e2..d44b25cbe460 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -176,6 +176,15 @@ noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) return 0; } +const struct bpf_func_proto bpf_tail_call_proto = { + .func = NULL, + .gpl_only = false, + .ret_type = RET_VOID, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_CONST_MAP_PTR, + .arg3_type = ARG_ANYTHING, +}; + /** * __bpf_prog_run - run eBPF program on a given context * @ctx: is the data we are operating on @@ -244,6 +253,7 @@ static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn) [BPF_ALU64 | BPF_NEG] = &&ALU64_NEG, /* Call instruction */ [BPF_JMP | BPF_CALL] = &&JMP_CALL, + [BPF_JMP | BPF_CALL | BPF_X] = &&JMP_TAIL_CALL, /* Jumps */ [BPF_JMP | BPF_JA] = &&JMP_JA, [BPF_JMP | BPF_JEQ | BPF_X] = &&JMP_JEQ_X, @@ -286,6 +296,7 @@ static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn) [BPF_LD | BPF_IND | BPF_B] = &&LD_IND_B, [BPF_LD | BPF_IMM | BPF_DW] = &&LD_IMM_DW, }; + u32 tail_call_cnt = 0; void *ptr; int off; @@ -431,6 +442,30 @@ select_insn: BPF_R4, BPF_R5); CONT; + JMP_TAIL_CALL: { + struct bpf_map *map = (struct bpf_map *) (unsigned long) BPF_R2; + struct bpf_array *array = container_of(map, struct bpf_array, map); + struct bpf_prog *prog; + u64 index = BPF_R3; + + if (unlikely(index >= array->map.max_entries)) + goto out; + + if (unlikely(tail_call_cnt > MAX_TAIL_CALL_CNT)) + goto out; + + tail_call_cnt++; + + prog = READ_ONCE(array->prog[index]); + if (unlikely(!prog)) + goto out; + + ARG1 = BPF_R1; + insn = prog->insnsi; + goto select_insn; +out: + CONT; + } /* JMP */ JMP_JA: insn += insn->off; @@ -619,6 +654,40 @@ void __weak bpf_int_jit_compile(struct bpf_prog *prog) { } +bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp) +{ + if (array->owner_prog_type) { + if (array->owner_prog_type != fp->type) + return false; + if (array->owner_jited != fp->jited) + return false; + } else { + array->owner_prog_type = fp->type; + array->owner_jited = fp->jited; + } + return true; +} + +static int check_tail_call(const struct bpf_prog *fp) +{ + struct bpf_prog_aux *aux = fp->aux; + int i; + + for (i = 0; i < aux->used_map_cnt; i++) { + struct bpf_array *array; + struct bpf_map *map; + + map = aux->used_maps[i]; + if (map->map_type != BPF_MAP_TYPE_PROG_ARRAY) + continue; + array = container_of(map, struct bpf_array, map); + if (!bpf_prog_array_compatible(array, fp)) + return -EINVAL; + } + + return 0; +} + /** * bpf_prog_select_runtime - select execution runtime for BPF program * @fp: bpf_prog populated with internal BPF program @@ -626,7 +695,7 @@ void __weak bpf_int_jit_compile(struct bpf_prog *prog) * try to JIT internal BPF program, if JIT is not available select interpreter * BPF program will be executed via BPF_PROG_RUN() macro */ -void bpf_prog_select_runtime(struct bpf_prog *fp) +int bpf_prog_select_runtime(struct bpf_prog *fp) { fp->bpf_func = (void *) __bpf_prog_run; @@ -634,6 +703,8 @@ void bpf_prog_select_runtime(struct bpf_prog *fp) bpf_int_jit_compile(fp); /* Lock whole bpf_prog as read-only */ bpf_prog_lock_ro(fp); + + return check_tail_call(fp); } EXPORT_SYMBOL_GPL(bpf_prog_select_runtime); diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 3bae6c591914..98a69bd83069 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -68,6 +68,12 @@ static int bpf_map_release(struct inode *inode, struct file *filp) { struct bpf_map *map = filp->private_data; + if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) + /* prog_array stores refcnt-ed bpf_prog pointers + * release them all when user space closes prog_array_fd + */ + bpf_prog_array_map_clear(map); + bpf_map_put(map); return 0; } @@ -392,6 +398,19 @@ static void fixup_bpf_calls(struct bpf_prog *prog) */ BUG_ON(!prog->aux->ops->get_func_proto); + if (insn->imm == BPF_FUNC_tail_call) { + /* mark bpf_tail_call as different opcode + * to avoid conditional branch in + * interpeter for every normal call + * and to prevent accidental JITing by + * JIT compiler that doesn't support + * bpf_tail_call yet + */ + insn->imm = 0; + insn->code |= BPF_X; + continue; + } + fn = prog->aux->ops->get_func_proto(insn->imm); /* all functions that have prototype and verifier allowed * programs to call them, must be real in-kernel functions @@ -532,7 +551,9 @@ static int bpf_prog_load(union bpf_attr *attr) fixup_bpf_calls(prog); /* eBPF program is ready to be JITed */ - bpf_prog_select_runtime(prog); + err = bpf_prog_select_runtime(prog); + if (err < 0) + goto free_used_maps; err = anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog, O_RDWR | O_CLOEXEC); if (err < 0) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 47dcd3aa6e23..cfd9a40b9a5a 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -907,6 +907,23 @@ static int check_call(struct verifier_env *env, int func_id) fn->ret_type, func_id); return -EINVAL; } + + if (map && map->map_type == BPF_MAP_TYPE_PROG_ARRAY && + func_id != BPF_FUNC_tail_call) + /* prog_array map type needs extra care: + * only allow to pass it into bpf_tail_call() for now. + * bpf_map_delete_elem() can be allowed in the future, + * while bpf_map_update_elem() must only be done via syscall + */ + return -EINVAL; + + if (func_id == BPF_FUNC_tail_call && + map->map_type != BPF_MAP_TYPE_PROG_ARRAY) + /* don't allow any other map type to be passed into + * bpf_tail_call() + */ + return -EINVAL; + return 0; } diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 2d56ce501632..646445e41bd4 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -172,6 +172,8 @@ static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func return &bpf_probe_read_proto; case BPF_FUNC_ktime_get_ns: return &bpf_ktime_get_ns_proto; + case BPF_FUNC_tail_call: + return &bpf_tail_call_proto; case BPF_FUNC_trace_printk: /* diff --git a/net/core/filter.c b/net/core/filter.c index 6805717be614..3adcca6f17a4 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1421,6 +1421,8 @@ sk_filter_func_proto(enum bpf_func_id func_id) return &bpf_get_prandom_u32_proto; case BPF_FUNC_get_smp_processor_id: return &bpf_get_smp_processor_id_proto; + case BPF_FUNC_tail_call: + return &bpf_tail_call_proto; default: return NULL; } -- cgit v1.2.3 From f5af1f57a2914e290de40e2c93716da8885c4965 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 20 May 2015 10:59:01 -0700 Subject: inet_hashinfo: remove bsocket counter We no longer need bsocket atomic counter, as inet_csk_get_port() calls bind_conflict() regardless of its value, after commit 2b05ad33e1e624e ("tcp: bind() fix autoselection to share ports") This patch removes overhead of maintaining this counter and double inet_csk_get_port() calls under pressure. Signed-off-by: Eric Dumazet Cc: Marcelo Ricardo Leitner Cc: Flavio Leitner Acked-by: Flavio Leitner Signed-off-by: David S. Miller --- include/net/inet_hashtables.h | 2 -- net/ipv4/inet_connection_sock.c | 5 ----- net/ipv4/inet_hashtables.c | 7 ------- 3 files changed, 14 deletions(-) (limited to 'include') diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 73fe0f9525d9..774d24151d4a 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -148,8 +148,6 @@ struct inet_hashinfo { */ struct inet_listen_hashbucket listening_hash[INET_LHTABLE_SIZE] ____cacheline_aligned_in_smp; - - atomic_t bsockets; }; static inline struct inet_ehash_bucket *inet_ehash_bucket( diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 8976ca423a07..b95fb263a13f 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -127,11 +127,6 @@ again: (tb->num_owners < smallest_size || smallest_size == -1)) { smallest_size = tb->num_owners; smallest_rover = rover; - if (atomic_read(&hashinfo->bsockets) > (high - low) + 1 && - !inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, false)) { - snum = smallest_rover; - goto tb_found; - } } if (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, false)) { snum = rover; diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index c6fb80bd5826..3766bddb3e8a 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -90,10 +90,6 @@ void inet_bind_bucket_destroy(struct kmem_cache *cachep, struct inet_bind_bucket void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb, const unsigned short snum) { - struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; - - atomic_inc(&hashinfo->bsockets); - inet_sk(sk)->inet_num = snum; sk_add_bind_node(sk, &tb->owners); tb->num_owners++; @@ -111,8 +107,6 @@ static void __inet_put_port(struct sock *sk) struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash]; struct inet_bind_bucket *tb; - atomic_dec(&hashinfo->bsockets); - spin_lock(&head->lock); tb = inet_csk(sk)->icsk_bind_hash; __sk_del_bind_node(sk); @@ -608,7 +602,6 @@ void inet_hashinfo_init(struct inet_hashinfo *h) { int i; - atomic_set(&h->bsockets, 0); for (i = 0; i < INET_LHTABLE_SIZE; i++) { spin_lock_init(&h->listening_hash[i].lock); INIT_HLIST_NULLS_HEAD(&h->listening_hash[i].head, -- cgit v1.2.3 From 2efd055c53c06b7e89c167c98069bab9afce7e59 Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Wed, 20 May 2015 16:35:41 -0700 Subject: tcp: add tcpi_segs_in and tcpi_segs_out to tcp_info This patch tracks the total number of inbound and outbound segments on a TCP socket. One may use this number to have an idea on connection quality when compared against the retransmissions. RFC4898 named these : tcpEStatsPerfSegsIn and tcpEStatsPerfSegsOut These are a 32bit field each and can be fetched both from TCP_INFO getsockopt() if one has a handle on a TCP socket, or from inet_diag netlink facility (iproute2/ss patch will follow) Note that tp->segs_out was placed near tp->snd_nxt for good data locality and minimal performance impact, while tp->segs_in was placed near tp->bytes_received for the same reason. Join work with Eric Dumazet. Note that received SYN are accounted on the listener, but sent SYNACK are not accounted. Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/tcp.h | 7 ++++++- include/uapi/linux/tcp.h | 4 +++- net/ipv4/tcp.c | 2 ++ net/ipv4/tcp_ipv4.c | 1 + net/ipv4/tcp_minisocks.c | 1 + net/ipv4/tcp_output.c | 1 + net/ipv6/tcp_ipv6.c | 1 + 7 files changed, 15 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index e6fb5df22db1..f0212026c77f 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -149,11 +149,16 @@ struct tcp_sock { * sum(delta(rcv_nxt)), or how many bytes * were acked. */ + u32 segs_in; /* RFC4898 tcpEStatsPerfSegsIn + * total number of segments in. + */ u32 rcv_nxt; /* What we want to receive next */ u32 copied_seq; /* Head of yet unread data */ u32 rcv_wup; /* rcv_nxt on last window update sent */ u32 snd_nxt; /* Next sequence we send */ - + u32 segs_out; /* RFC4898 tcpEStatsPerfSegsOut + * The total number of segments sent. + */ u64 bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked * sum(delta(snd_una)), or how many bytes * were acked. diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h index 51ebedba577f..65a77b071e22 100644 --- a/include/uapi/linux/tcp.h +++ b/include/uapi/linux/tcp.h @@ -192,8 +192,10 @@ struct tcp_info { __u64 tcpi_pacing_rate; __u64 tcpi_max_pacing_rate; - __u64 tcpi_bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked */ + __u64 tcpi_bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked */ __u64 tcpi_bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived */ + __u32 tcpi_segs_out; /* RFC4898 tcpEStatsPerfSegsOut */ + __u32 tcpi_segs_in; /* RFC4898 tcpEStatsPerfSegsIn */ }; /* for TCP_MD5SIG socket option */ diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 0a3f9a00565b..7f3e721b9e69 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2695,6 +2695,8 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) spin_lock_bh(&sk->sk_lock.slock); info->tcpi_bytes_acked = tp->bytes_acked; info->tcpi_bytes_received = tp->bytes_received; + info->tcpi_segs_out = tp->segs_out; + info->tcpi_segs_in = tp->segs_in; spin_unlock_bh(&sk->sk_lock.slock); } EXPORT_SYMBOL_GPL(tcp_get_info); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0cc4b5a630cd..feb875769b8d 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1626,6 +1626,7 @@ process: skb->dev = NULL; bh_lock_sock_nested(sk); + tcp_sk(sk)->segs_in += max_t(u16, 1, skb_shinfo(skb)->gso_segs); ret = 0; if (!sock_owned_by_user(sk)) { if (!tcp_prequeue(sk, skb)) diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index ebe2ab2596ed..b62d15c86946 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -448,6 +448,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, newtp->rcv_wup = newtp->copied_seq = newtp->rcv_nxt = treq->rcv_isn + 1; + newtp->segs_in = 0; newtp->snd_sml = newtp->snd_una = newtp->snd_nxt = newtp->snd_up = treq->snt_isn + 1; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 3aebe0157dfa..534e5fdb04c1 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1027,6 +1027,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS, tcp_skb_pcount(skb)); + tp->segs_out += tcp_skb_pcount(skb); /* OK, its time to fill skb_shinfo(skb)->gso_segs */ skb_shinfo(skb)->gso_segs = tcp_skb_pcount(skb); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index b6575d665568..beac6bf840b9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1421,6 +1421,7 @@ process: skb->dev = NULL; bh_lock_sock_nested(sk); + tcp_sk(sk)->segs_in += max_t(u16, 1, skb_shinfo(skb)->gso_segs); ret = 0; if (!sock_owned_by_user(sk)) { if (!tcp_prequeue(sk, skb)) -- cgit v1.2.3 From bd5850d39f10f9d216bff69bcbf5938680b862ae Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 21 May 2015 02:26:24 +0200 Subject: net: sched: pkt_cls: remove unused macros from uapi Jamal points out that this header also contains kernel internal magic that cannot be used from userspace for anything meaningful. Lets remove what the kernel doesn't use anymore and wrap remainder with __KERNEL__. Suggested-by: Jamal Hadi Salim Suggested-by: Alexei Starovoitov Signed-off-by: Florian Westphal Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/uapi/linux/pkt_cls.h | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 39fb53d67b11..4f0d1bc3647d 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -4,6 +4,7 @@ #include #include +#ifdef __KERNEL__ /* I think i could have done better macros ; for now this is stolen from * some arch/mips code - jhs */ @@ -35,23 +36,6 @@ bits 9,10,11: redirect counter - redirect TTL. Loop avoidance * * */ -#ifndef __KERNEL__ -/* backwards compat for userspace only */ -#define TC_MUNGED _TC_MAKEMASK1(0) -#define SET_TC_MUNGED(v) ( TC_MUNGED | (v & ~TC_MUNGED)) -#define CLR_TC_MUNGED(v) ( v & ~TC_MUNGED) - -#define TC_OK2MUNGE _TC_MAKEMASK1(1) -#define SET_TC_OK2MUNGE(v) ( TC_OK2MUNGE | (v & ~TC_OK2MUNGE)) -#define CLR_TC_OK2MUNGE(v) ( v & ~TC_OK2MUNGE) - -#define S_TC_VERD _TC_MAKE32(2) -#define M_TC_VERD _TC_MAKEMASK(4,S_TC_VERD) -#define G_TC_VERD(x) _TC_GETVALUE(x,S_TC_VERD,M_TC_VERD) -#define V_TC_VERD(x) _TC_MAKEVALUE(x,S_TC_VERD) -#define SET_TC_VERD(v,n) ((V_TC_VERD(n)) | (v & ~M_TC_VERD)) -#endif - #define S_TC_FROM _TC_MAKE32(6) #define M_TC_FROM _TC_MAKEMASK(2,S_TC_FROM) #define G_TC_FROM(x) _TC_GETVALUE(x,S_TC_FROM,M_TC_FROM) @@ -65,20 +49,16 @@ bits 9,10,11: redirect counter - redirect TTL. Loop avoidance #define SET_TC_NCLS(v) ( TC_NCLS | (v & ~TC_NCLS)) #define CLR_TC_NCLS(v) ( v & ~TC_NCLS) -#ifndef __KERNEL__ -#define S_TC_RTTL _TC_MAKE32(9) -#define M_TC_RTTL _TC_MAKEMASK(3,S_TC_RTTL) -#define G_TC_RTTL(x) _TC_GETVALUE(x,S_TC_RTTL,M_TC_RTTL) -#define V_TC_RTTL(x) _TC_MAKEVALUE(x,S_TC_RTTL) -#define SET_TC_RTTL(v,n) ((V_TC_RTTL(n)) | (v & ~M_TC_RTTL)) -#endif - #define S_TC_AT _TC_MAKE32(12) #define M_TC_AT _TC_MAKEMASK(2,S_TC_AT) #define G_TC_AT(x) _TC_GETVALUE(x,S_TC_AT,M_TC_AT) #define V_TC_AT(x) _TC_MAKEVALUE(x,S_TC_AT) #define SET_TC_AT(v,n) ((V_TC_AT(n)) | (v & ~M_TC_AT)) +#define MAX_REC_LOOP 4 +#define MAX_RED_LOOP 4 +#endif + /* Action attributes */ enum { TCA_ACT_UNSPEC, @@ -98,8 +78,6 @@ enum { #define TCA_ACT_NOUNBIND 0 #define TCA_ACT_REPLACE 1 #define TCA_ACT_NOREPLACE 0 -#define MAX_REC_LOOP 4 -#define MAX_RED_LOOP 4 #define TC_ACT_UNSPEC (-1) #define TC_ACT_OK 0 -- cgit v1.2.3 From d654976cbf852ee20612ee10dbe57cdacda9f452 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 21 May 2015 21:51:19 -0700 Subject: tcp: fix a potential deadlock in tcp_get_info() Taking socket spinlock in tcp_get_info() can deadlock, as inet_diag_dump_icsk() holds the &hashinfo->ehash_locks[i], while packet processing can use the reverse locking order. We could avoid this locking for TCP_LISTEN states, but lockdep would certainly get confused as all TCP sockets share same lockdep classes. [ 523.722504] ====================================================== [ 523.728706] [ INFO: possible circular locking dependency detected ] [ 523.734990] 4.1.0-dbg-DEV #1676 Not tainted [ 523.739202] ------------------------------------------------------- [ 523.745474] ss/18032 is trying to acquire lock: [ 523.750002] (slock-AF_INET){+.-...}, at: [] tcp_get_info+0x2c4/0x360 [ 523.758129] [ 523.758129] but task is already holding lock: [ 523.763968] (&(&hashinfo->ehash_locks[i])->rlock){+.-...}, at: [] inet_diag_dump_icsk+0x1d5/0x6c0 [ 523.774661] [ 523.774661] which lock already depends on the new lock. [ 523.774661] [ 523.782850] [ 523.782850] the existing dependency chain (in reverse order) is: [ 523.790326] -> #1 (&(&hashinfo->ehash_locks[i])->rlock){+.-...}: [ 523.796599] [] lock_acquire+0xbb/0x270 [ 523.802565] [] _raw_spin_lock+0x38/0x50 [ 523.808628] [] __inet_hash_nolisten+0x78/0x110 [ 523.815273] [] tcp_v4_syn_recv_sock+0x24b/0x350 [ 523.822067] [] tcp_check_req+0x3c1/0x500 [ 523.828199] [] tcp_v4_do_rcv+0x239/0x3d0 [ 523.834331] [] tcp_v4_rcv+0xa8e/0xc10 [ 523.840202] [] ip_local_deliver_finish+0x133/0x3e0 [ 523.847214] [] ip_local_deliver+0xaa/0xc0 [ 523.853440] [] ip_rcv_finish+0x168/0x5c0 [ 523.859624] [] ip_rcv+0x307/0x420 Lets use u64_sync infrastructure instead. As a bonus, 64bit arches get optimized, as these are nop for them. Fixes: 0df48c26d841 ("tcp: add tcpi_bytes_acked to tcp_info") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/tcp.h | 2 ++ net/ipv4/tcp.c | 11 +++++++---- net/ipv4/tcp_fastopen.c | 4 ++++ net/ipv4/tcp_input.c | 4 ++++ 4 files changed, 17 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 3b2911502a8c..e8bbf403618f 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -158,6 +158,8 @@ struct tcp_sock { * sum(delta(snd_una)), or how many bytes * were acked. */ + struct u64_stats_sync syncp; /* protects 64bit vars (cf tcp_get_info()) */ + u32 snd_una; /* First byte we want an ack for */ u32 snd_sml; /* Last byte of the most recently transmitted small packet */ u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 46efa03d2b11..f1377f2a0472 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -402,6 +402,7 @@ void tcp_init_sock(struct sock *sk) tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; tp->snd_cwnd_clamp = ~0; tp->mss_cache = TCP_MSS_DEFAULT; + u64_stats_init(&tp->syncp); tp->reordering = sysctl_tcp_reordering; tcp_enable_early_retrans(tp); @@ -2598,6 +2599,7 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) const struct tcp_sock *tp = tcp_sk(sk); const struct inet_connection_sock *icsk = inet_csk(sk); u32 now = tcp_time_stamp; + unsigned int start; u32 rate; memset(info, 0, sizeof(*info)); @@ -2665,10 +2667,11 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) rate = READ_ONCE(sk->sk_max_pacing_rate); info->tcpi_max_pacing_rate = rate != ~0U ? rate : ~0ULL; - spin_lock_bh(&sk->sk_lock.slock); - info->tcpi_bytes_acked = tp->bytes_acked; - info->tcpi_bytes_received = tp->bytes_received; - spin_unlock_bh(&sk->sk_lock.slock); + do { + start = u64_stats_fetch_begin_irq(&tp->syncp); + info->tcpi_bytes_acked = tp->bytes_acked; + info->tcpi_bytes_received = tp->bytes_received; + } while (u64_stats_fetch_retry_irq(&tp->syncp, start)); } EXPORT_SYMBOL_GPL(tcp_get_info); diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index 3c673d5e6cff..46b087a27503 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c @@ -206,6 +206,10 @@ static bool tcp_fastopen_create_child(struct sock *sk, skb_set_owner_r(skb2, child); __skb_queue_tail(&child->sk_receive_queue, skb2); tp->syn_data_acked = 1; + + /* u64_stats_update_begin(&tp->syncp) not needed here, + * as we certainly are not changing upper 32bit value (0) + */ tp->bytes_received = end_seq - TCP_SKB_CB(skb)->seq - 1; } else { end_seq = TCP_SKB_CB(skb)->seq + 1; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 243d674b3ef5..c9ab964189a0 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3286,7 +3286,9 @@ static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack) { u32 delta = ack - tp->snd_una; + u64_stats_update_begin(&tp->syncp); tp->bytes_acked += delta; + u64_stats_update_end(&tp->syncp); tp->snd_una = ack; } @@ -3295,7 +3297,9 @@ static void tcp_rcv_nxt_update(struct tcp_sock *tp, u32 seq) { u32 delta = seq - tp->rcv_nxt; + u64_stats_update_begin(&tp->syncp); tp->bytes_received += delta; + u64_stats_update_end(&tp->syncp); tp->rcv_nxt = seq; } -- cgit v1.2.3 From 4a3a8c0c3a613e481bea931f0d65dc4a7efaa9b9 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 22 May 2015 17:43:52 +0200 Subject: mac802154: remove pib lock This patch removes the pib lock which is now replaced by rtnl lock. The new interface already use the rtnl lock only. Nevertheless this patch will fix issues while using new and old interface at the same time. Signed-off-by: Alexander Aring Reviewed-by: Stefan Schmidt Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 2 -- net/ieee802154/core.c | 2 -- net/ieee802154/nl-phy.c | 6 +++--- net/mac802154/iface.c | 7 ------- net/mac802154/mib.c | 4 ++-- 5 files changed, 5 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 11bbf17ad865..c6aa1d210182 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -121,8 +121,6 @@ enum wpan_phy_flags { }; struct wpan_phy { - struct mutex pib_lock; - /* If multiple wpan_phys are registered and you're handed e.g. * a regular netdev with assigned ieee802154_ptr, you won't * know whether it points to a wpan_phy your driver has registered diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index 2ee00e8a0308..b0248e934230 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -121,8 +121,6 @@ wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size) /* atomic_inc_return makes it start at 1, make it start at 0 */ rdev->wpan_phy_idx--; - mutex_init(&rdev->wpan_phy.pib_lock); - INIT_LIST_HEAD(&rdev->wpan_dev_list); device_initialize(&rdev->wpan_phy.dev); dev_set_name(&rdev->wpan_phy.dev, PHY_NAME "%d", rdev->wpan_phy_idx); diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index cbc0d09351e0..77d73014bde3 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c @@ -50,7 +50,7 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid, if (!hdr) goto out; - mutex_lock(&phy->pib_lock); + rtnl_lock(); if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || nla_put_u8(msg, IEEE802154_ATTR_PAGE, phy->current_page) || nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel)) @@ -63,13 +63,13 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid, nla_put(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST, pages * sizeof(uint32_t), buf)) goto nla_put_failure; - mutex_unlock(&phy->pib_lock); + rtnl_unlock(); kfree(buf); genlmsg_end(msg, hdr); return 0; nla_put_failure: - mutex_unlock(&phy->pib_lock); + rtnl_unlock(); genlmsg_cancel(msg, hdr); out: kfree(buf); diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index 2a5878889289..22f478be7489 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -242,7 +242,6 @@ static int mac802154_wpan_open(struct net_device *dev) struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); struct ieee802154_local *local = sdata->local; struct wpan_dev *wpan_dev = &sdata->wpan_dev; - struct wpan_phy *phy = sdata->local->phy; rc = ieee802154_check_concurrent_iface(sdata, sdata->vif.type); if (rc < 0) @@ -252,8 +251,6 @@ static int mac802154_wpan_open(struct net_device *dev) if (rc < 0) return rc; - mutex_lock(&phy->pib_lock); - if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) { rc = drv_set_promiscuous_mode(local, wpan_dev->promiscuous_mode); @@ -295,11 +292,7 @@ static int mac802154_wpan_open(struct net_device *dev) goto out; } - mutex_unlock(&phy->pib_lock); - return 0; - out: - mutex_unlock(&phy->pib_lock); return rc; } diff --git a/net/mac802154/mib.c b/net/mac802154/mib.c index 5cf019a57fd7..033dfc7755c6 100644 --- a/net/mac802154/mib.c +++ b/net/mac802154/mib.c @@ -91,16 +91,16 @@ void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan) struct ieee802154_local *local = sdata->local; int res; + ASSERT_RTNL(); + BUG_ON(dev->type != ARPHRD_IEEE802154); res = drv_set_channel(local, page, chan); if (res) { pr_debug("set_channel failed\n"); } else { - mutex_lock(&local->phy->pib_lock); local->phy->current_channel = chan; local->phy->current_page = page; - mutex_unlock(&local->phy->pib_lock); } } -- cgit v1.2.3 From 344f8c119df742f2bf7098cf8fc326351f583249 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 22 May 2015 17:43:53 +0200 Subject: mac802154: use atomic ops for sequence incrementation This patch will use atomic operations for sequence number incrementation while MAC header generation. Upper layers like af_802154 or 6LoWPAN could call this function in a parallel context while generating 802.15.4 MAC header before queuing into wpan interfaces transmit queue. Signed-off-by: Alexander Aring Reviewed-by: Stefan Schmidt Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 4 ++-- include/net/ieee802154_netdev.h | 1 - net/ieee802154/6lowpan/core.c | 8 -------- net/mac802154/ieee802154_i.h | 1 - net/mac802154/iface.c | 9 ++++++--- net/mac802154/mac_cmd.c | 1 - net/mac802154/mib.c | 9 --------- 7 files changed, 8 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index c6aa1d210182..4de59aa96173 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -177,9 +177,9 @@ struct wpan_dev { __le64 extended_addr; /* MAC BSN field */ - u8 bsn; + atomic_t bsn; /* MAC DSN field */ - u8 dsn; + atomic_t dsn; u8 min_be; u8 max_be; diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 94a297052442..144fefb4d619 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -431,7 +431,6 @@ struct ieee802154_mlme_ops { */ __le16 (*get_pan_id)(const struct net_device *dev); __le16 (*get_short_addr)(const struct net_device *dev); - u8 (*get_dsn)(const struct net_device *dev); }; static inline struct ieee802154_mlme_ops * diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c index 0ae5822ef944..2e77fada7e54 100644 --- a/net/ieee802154/6lowpan/core.c +++ b/net/ieee802154/6lowpan/core.c @@ -69,13 +69,6 @@ static __le16 lowpan_get_short_addr(const struct net_device *dev) return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev); } -static u8 lowpan_get_dsn(const struct net_device *dev) -{ - struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; - - return ieee802154_mlme_ops(real_dev)->get_dsn(real_dev); -} - static struct header_ops lowpan_header_ops = { .create = lowpan_header_create, }; @@ -106,7 +99,6 @@ static const struct net_device_ops lowpan_netdev_ops = { static struct ieee802154_mlme_ops lowpan_mlme = { .get_pan_id = lowpan_get_pan_id, .get_short_addr = lowpan_get_short_addr, - .get_dsn = lowpan_get_dsn, }; static void lowpan_setup(struct net_device *dev) diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index 127ba18386fc..56b3847466e9 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -141,7 +141,6 @@ __le16 mac802154_dev_get_short_addr(const struct net_device *dev); __le16 mac802154_dev_get_pan_id(const struct net_device *dev); void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val); void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan); -u8 mac802154_dev_get_dsn(const struct net_device *dev); int mac802154_get_params(struct net_device *dev, struct ieee802154_llsec_params *params); diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index 22f478be7489..0ec7bc402e29 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -368,7 +368,7 @@ static int mac802154_header_create(struct sk_buff *skb, hdr.fc.type = cb->type; hdr.fc.security_enabled = cb->secen; hdr.fc.ack_request = cb->ackreq; - hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev); + hdr.seq = atomic_inc_return(&dev->ieee802154_ptr->dsn) & 0xFF; if (mac802154_set_header_security(sdata, &hdr, cb) < 0) return -EINVAL; @@ -468,13 +468,16 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, enum nl802154_iftype type) { struct wpan_dev *wpan_dev = &sdata->wpan_dev; + u8 tmp; /* set some type-dependent values */ sdata->vif.type = type; sdata->wpan_dev.iftype = type; - get_random_bytes(&wpan_dev->bsn, 1); - get_random_bytes(&wpan_dev->dsn, 1); + get_random_bytes(&tmp, sizeof(tmp)); + atomic_set(&wpan_dev->bsn, tmp); + get_random_bytes(&tmp, sizeof(tmp)); + atomic_set(&wpan_dev->dsn, tmp); /* defaults per 802.15.4-2011 */ wpan_dev->min_be = 3; diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c index 6dcbb3b5994c..3b347d4d3d4c 100644 --- a/net/mac802154/mac_cmd.c +++ b/net/mac802154/mac_cmd.c @@ -153,7 +153,6 @@ struct ieee802154_mlme_ops mac802154_mlme_wpan = { .start_req = mac802154_mlme_start_req, .get_pan_id = mac802154_dev_get_pan_id, .get_short_addr = mac802154_dev_get_short_addr, - .get_dsn = mac802154_dev_get_dsn, .llsec = &mac802154_llsec_ops, diff --git a/net/mac802154/mib.c b/net/mac802154/mib.c index 033dfc7755c6..00a62de9cc23 100644 --- a/net/mac802154/mib.c +++ b/net/mac802154/mib.c @@ -76,15 +76,6 @@ void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val) spin_unlock_bh(&sdata->mib_lock); } -u8 mac802154_dev_get_dsn(const struct net_device *dev) -{ - struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); - - BUG_ON(dev->type != ARPHRD_IEEE802154); - - return sdata->wpan_dev.dsn++; -} - void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan) { struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); -- cgit v1.2.3 From c947f7e1e31a708f5a4ea8c1a627bec578cd9223 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 22 May 2015 17:43:54 +0200 Subject: mac802154: remove mib lock This patch removes the mib lock. The new locking mechanism is to protect the mib values with the rtnl lock. Note that this isn't always necessary if we have an interface up the most mib values are readonly (e.g. address settings). With this behaviour we can remove locking in hotpath like frame parsing completely. It depends on context if we need to hold the rtnl lock or not, this makes the callbacks of ieee802154_mlme_ops unnecessary because these callbacks hols always the locks. Signed-off-by: Alexander Aring Reviewed-by: Stefan Schmidt Signed-off-by: Marcel Holtmann --- include/net/ieee802154_netdev.h | 9 -------- net/ieee802154/6lowpan/core.c | 20 ----------------- net/ieee802154/6lowpan/tx.c | 2 +- net/ieee802154/nl-mac.c | 14 ++++++++---- net/ieee802154/socket.c | 12 +++++----- net/mac802154/ieee802154_i.h | 6 ----- net/mac802154/iface.c | 8 ------- net/mac802154/mac_cmd.c | 6 ++--- net/mac802154/mib.c | 50 ----------------------------------------- net/mac802154/rx.c | 5 ----- 10 files changed, 18 insertions(+), 114 deletions(-) (limited to 'include') diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 144fefb4d619..84a72a1382a8 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -422,15 +422,6 @@ struct ieee802154_mlme_ops { struct ieee802154_mac_params *params); struct ieee802154_llsec_ops *llsec; - - /* The fields below are required. */ - - /* - * FIXME: these should become the part of PIB/MIB interface. - * However we still don't have IB interface of any kind - */ - __le16 (*get_pan_id)(const struct net_device *dev); - __le16 (*get_short_addr)(const struct net_device *dev); }; static inline struct ieee802154_mlme_ops * diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c index 2e77fada7e54..f20a387a1011 100644 --- a/net/ieee802154/6lowpan/core.c +++ b/net/ieee802154/6lowpan/core.c @@ -55,20 +55,6 @@ LIST_HEAD(lowpan_devices); static int lowpan_open_count; -static __le16 lowpan_get_pan_id(const struct net_device *dev) -{ - struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; - - return ieee802154_mlme_ops(real_dev)->get_pan_id(real_dev); -} - -static __le16 lowpan_get_short_addr(const struct net_device *dev) -{ - struct net_device *real_dev = lowpan_dev_info(dev)->real_dev; - - return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev); -} - static struct header_ops lowpan_header_ops = { .create = lowpan_header_create, }; @@ -96,11 +82,6 @@ static const struct net_device_ops lowpan_netdev_ops = { .ndo_start_xmit = lowpan_xmit, }; -static struct ieee802154_mlme_ops lowpan_mlme = { - .get_pan_id = lowpan_get_pan_id, - .get_short_addr = lowpan_get_short_addr, -}; - static void lowpan_setup(struct net_device *dev) { dev->addr_len = IEEE802154_ADDR_LEN; @@ -116,7 +97,6 @@ static void lowpan_setup(struct net_device *dev) dev->netdev_ops = &lowpan_netdev_ops; dev->header_ops = &lowpan_header_ops; - dev->ml_priv = &lowpan_mlme; dev->destructor = free_netdev; dev->features |= NETIF_F_NETNS_LOCAL; } diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c index 2349070bd534..98acf7319754 100644 --- a/net/ieee802154/6lowpan/tx.c +++ b/net/ieee802154/6lowpan/tx.c @@ -207,7 +207,7 @@ static int lowpan_header(struct sk_buff *skb, struct net_device *dev) /* prepare wpan address data */ sa.mode = IEEE802154_ADDR_LONG; - sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + sa.pan_id = lowpan_dev_info(dev)->real_dev->ieee802154_ptr->pan_id; sa.extended_addr = ieee802154_devaddr_from_raw(saddr); /* intra-PAN communications */ diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index cdc1cc3543f6..ada58a81b753 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -97,8 +97,10 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, BUG_ON(!phy); get_device(&phy->dev); - short_addr = ops->get_short_addr(dev); - pan_id = ops->get_pan_id(dev); + rtnl_lock(); + short_addr = dev->ieee802154_ptr->short_addr; + pan_id = dev->ieee802154_ptr->pan_id; + rtnl_unlock(); if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) || nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || @@ -244,7 +246,9 @@ int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info) addr.mode = IEEE802154_ADDR_LONG; addr.extended_addr = nla_get_hwaddr( info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]); - addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + rtnl_lock(); + addr.pan_id = dev->ieee802154_ptr->pan_id; + rtnl_unlock(); ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr, nla_get_shortaddr(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]), @@ -281,7 +285,9 @@ int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info) addr.short_addr = nla_get_shortaddr( info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]); } - addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + rtnl_lock(); + addr.pan_id = dev->ieee802154_ptr->pan_id; + rtnl_unlock(); ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr, nla_get_u8(info->attrs[IEEE802154_ATTR_REASON])); diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c index 7aaaf967df58..e5cc2537c2a3 100644 --- a/net/ieee802154/socket.c +++ b/net/ieee802154/socket.c @@ -64,10 +64,8 @@ ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr) if (tmp->type != ARPHRD_IEEE802154) continue; - pan_id = ieee802154_mlme_ops(tmp)->get_pan_id(tmp); - short_addr = - ieee802154_mlme_ops(tmp)->get_short_addr(tmp); - + pan_id = tmp->ieee802154_ptr->pan_id; + short_addr = tmp->ieee802154_ptr->short_addr; if (pan_id == addr->pan_id && short_addr == addr->short_addr) { dev = tmp; @@ -797,9 +795,9 @@ static int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) /* Data frame processing */ BUG_ON(dev->type != ARPHRD_IEEE802154); - pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); - short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev); - hw_addr = ieee802154_devaddr_from_raw(dev->dev_addr); + pan_id = dev->ieee802154_ptr->pan_id; + short_addr = dev->ieee802154_ptr->short_addr; + hw_addr = dev->ieee802154_ptr->extended_addr; read_lock(&dgram_lock); sk_for_each(sk, &dgram_head) { diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index 56b3847466e9..eec668f3637f 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -86,8 +86,6 @@ struct ieee802154_sub_if_data { unsigned long state; char name[IFNAMSIZ]; - spinlock_t mib_lock; - /* protects sec from concurrent access by netlink. access by * encrypt/decrypt/header_create safe without additional protection. */ @@ -136,10 +134,6 @@ ieee802154_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); enum hrtimer_restart ieee802154_xmit_ifs_timer(struct hrtimer *timer); /* MIB callbacks */ -void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val); -__le16 mac802154_dev_get_short_addr(const struct net_device *dev); -__le16 mac802154_dev_get_pan_id(const struct net_device *dev); -void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val); void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan); int mac802154_get_params(struct net_device *dev, diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index 0ec7bc402e29..f30788d2702f 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -63,7 +63,6 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) int err = -ENOIOCTLCMD; rtnl_lock(); - spin_lock_bh(&sdata->mib_lock); switch (cmd) { case SIOCGIFADDR: @@ -88,7 +87,6 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } case SIOCSIFADDR: if (netif_running(dev)) { - spin_unlock_bh(&sdata->mib_lock); rtnl_unlock(); return -EBUSY; } @@ -111,7 +109,6 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) break; } - spin_unlock_bh(&sdata->mib_lock); rtnl_unlock(); return err; } @@ -374,8 +371,6 @@ static int mac802154_header_create(struct sk_buff *skb, return -EINVAL; if (!saddr) { - spin_lock_bh(&sdata->mib_lock); - if (wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) || wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) || wpan_dev->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) { @@ -387,8 +382,6 @@ static int mac802154_header_create(struct sk_buff *skb, } hdr.source.pan_id = wpan_dev->pan_id; - - spin_unlock_bh(&sdata->mib_lock); } else { hdr.source = *(const struct ieee802154_addr *)saddr; } @@ -500,7 +493,6 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, sdata->dev->ml_priv = &mac802154_mlme_wpan; wpan_dev->promiscuous_mode = false; - spin_lock_init(&sdata->mib_lock); mutex_init(&sdata->sec_mtx); mac802154_llsec_init(&sdata->sec); diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c index 3b347d4d3d4c..5220c2b2735b 100644 --- a/net/mac802154/mac_cmd.c +++ b/net/mac802154/mac_cmd.c @@ -43,8 +43,8 @@ static int mac802154_mlme_start_req(struct net_device *dev, BUG_ON(addr->mode != IEEE802154_ADDR_SHORT); - mac802154_dev_set_pan_id(dev, addr->pan_id); - mac802154_dev_set_short_addr(dev, addr->short_addr); + dev->ieee802154_ptr->pan_id = addr->pan_id; + dev->ieee802154_ptr->short_addr = addr->short_addr; mac802154_dev_set_page_channel(dev, page, channel); if (ops->llsec) { @@ -151,8 +151,6 @@ static struct ieee802154_llsec_ops mac802154_llsec_ops = { struct ieee802154_mlme_ops mac802154_mlme_wpan = { .start_req = mac802154_mlme_start_req, - .get_pan_id = mac802154_dev_get_pan_id, - .get_short_addr = mac802154_dev_get_short_addr, .llsec = &mac802154_llsec_ops, diff --git a/net/mac802154/mib.c b/net/mac802154/mib.c index 00a62de9cc23..73f94fbf8785 100644 --- a/net/mac802154/mib.c +++ b/net/mac802154/mib.c @@ -26,56 +26,6 @@ #include "ieee802154_i.h" #include "driver-ops.h" -void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val) -{ - struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); - - BUG_ON(dev->type != ARPHRD_IEEE802154); - - spin_lock_bh(&sdata->mib_lock); - sdata->wpan_dev.short_addr = val; - spin_unlock_bh(&sdata->mib_lock); -} - -__le16 mac802154_dev_get_short_addr(const struct net_device *dev) -{ - struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); - __le16 ret; - - BUG_ON(dev->type != ARPHRD_IEEE802154); - - spin_lock_bh(&sdata->mib_lock); - ret = sdata->wpan_dev.short_addr; - spin_unlock_bh(&sdata->mib_lock); - - return ret; -} - -__le16 mac802154_dev_get_pan_id(const struct net_device *dev) -{ - struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); - __le16 ret; - - BUG_ON(dev->type != ARPHRD_IEEE802154); - - spin_lock_bh(&sdata->mib_lock); - ret = sdata->wpan_dev.pan_id; - spin_unlock_bh(&sdata->mib_lock); - - return ret; -} - -void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val) -{ - struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); - - BUG_ON(dev->type != ARPHRD_IEEE802154); - - spin_lock_bh(&sdata->mib_lock); - sdata->wpan_dev.pan_id = val; - spin_unlock_bh(&sdata->mib_lock); -} - void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan) { struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index c0d67b2b4132..e0f10063cac3 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c @@ -47,8 +47,6 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata, pr_debug("getting packet via slave interface %s\n", sdata->dev->name); - spin_lock_bh(&sdata->mib_lock); - span = wpan_dev->pan_id; sshort = wpan_dev->short_addr; @@ -83,13 +81,10 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata, skb->pkt_type = PACKET_OTHERHOST; break; default: - spin_unlock_bh(&sdata->mib_lock); pr_debug("invalid dest mode\n"); goto fail; } - spin_unlock_bh(&sdata->mib_lock); - skb->dev = sdata->dev; rc = mac802154_llsec_decrypt(&sdata->sec, skb); -- cgit v1.2.3 From be12a1fe298e8be04d5215364f94654dff81b0bc Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Thu, 21 May 2015 16:59:58 +0200 Subject: net: skbuff: add skb_append_pagefrags and use it Signed-off-by: Hannes Frederic Sowa Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/skbuff.h | 3 +++ net/core/skbuff.c | 18 ++++++++++++++++++ net/ipv4/ip_output.c | 15 ++++----------- 3 files changed, 25 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index b617095adb88..f708936cdd23 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -861,6 +861,9 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, int len, int odd, struct sk_buff *skb), void *from, int length); +int skb_append_pagefrags(struct sk_buff *skb, struct page *page, + int offset, size_t size); + struct skb_seq_state { __u32 lower_offset; __u32 upper_offset; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index f3fe9bd9e672..4f2babeaf18d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2915,6 +2915,24 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, } EXPORT_SYMBOL(skb_append_datato_frags); +int skb_append_pagefrags(struct sk_buff *skb, struct page *page, + int offset, size_t size) +{ + int i = skb_shinfo(skb)->nr_frags; + + if (skb_can_coalesce(skb, i, page, offset)) { + skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], size); + } else if (i < MAX_SKB_FRAGS) { + get_page(page); + skb_fill_page_desc(skb, i, page, offset, size); + } else { + return -EMSGSIZE; + } + + return 0; +} +EXPORT_SYMBOL_GPL(skb_append_pagefrags); + /** * skb_pull_rcsum - pull skb and update receive checksum * @skb: buffer to update diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 8d91b922fcfe..451b009dae75 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1233,11 +1233,9 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, } while (size > 0) { - int i; - - if (skb_is_gso(skb)) + if (skb_is_gso(skb)) { len = size; - else { + } else { /* Check if the remaining data fits into current packet. */ len = mtu - skb->len; @@ -1289,15 +1287,10 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, continue; } - i = skb_shinfo(skb)->nr_frags; if (len > size) len = size; - if (skb_can_coalesce(skb, i, page, offset)) { - skb_frag_size_add(&skb_shinfo(skb)->frags[i-1], len); - } else if (i < MAX_SKB_FRAGS) { - get_page(page); - skb_fill_page_desc(skb, i, page, offset, len); - } else { + + if (skb_append_pagefrags(skb, page, offset, len)) { err = -EMSGSIZE; goto error; } -- cgit v1.2.3 From a60e3cc7c92973a31fad0fd04dc5cf4355d3d1ef Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Thu, 21 May 2015 17:00:00 +0200 Subject: net: make skb_splice_bits more configureable Prepare skb_splice_bits to be able to deal with AF_UNIX sockets. AF_UNIX sockets don't use lock_sock/release_sock and thus we have to use a callback to make the locking and unlocking configureable. Signed-off-by: Hannes Frederic Sowa Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/skbuff.h | 11 +++++++++-- net/core/skbuff.c | 45 ++++++++++++++++++++++++++++----------------- net/ipv4/tcp.c | 5 +++-- 3 files changed, 40 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index f708936cdd23..6b41c15efa27 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -35,6 +35,7 @@ #include #include #include +#include /* A. Checksumming of received packets by device. * @@ -2699,9 +2700,15 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len); __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, __wsum csum); -int skb_splice_bits(struct sk_buff *skb, unsigned int offset, +ssize_t skb_socket_splice(struct sock *sk, + struct pipe_inode_info *pipe, + struct splice_pipe_desc *spd); +int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, struct pipe_inode_info *pipe, unsigned int len, - unsigned int flags); + unsigned int flags, + ssize_t (*splice_cb)(struct sock *, + struct pipe_inode_info *, + struct splice_pipe_desc *)); void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); unsigned int skb_zerocopy_headlen(const struct sk_buff *from); int skb_zerocopy(struct sk_buff *to, struct sk_buff *from, diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 4f2babeaf18d..02769fa4f5c8 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1870,15 +1870,39 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe, return false; } +ssize_t skb_socket_splice(struct sock *sk, + struct pipe_inode_info *pipe, + struct splice_pipe_desc *spd) +{ + int ret; + + /* Drop the socket lock, otherwise we have reverse + * locking dependencies between sk_lock and i_mutex + * here as compared to sendfile(). We enter here + * with the socket lock held, and splice_to_pipe() will + * grab the pipe inode lock. For sendfile() emulation, + * we call into ->sendpage() with the i_mutex lock held + * and networking will grab the socket lock. + */ + release_sock(sk); + ret = splice_to_pipe(pipe, spd); + lock_sock(sk); + + return ret; +} + /* * Map data from the skb to a pipe. Should handle both the linear part, * the fragments, and the frag list. It does NOT handle frag lists within * the frag list, if such a thing exists. We'd probably need to recurse to * handle that cleanly. */ -int skb_splice_bits(struct sk_buff *skb, unsigned int offset, +int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, struct pipe_inode_info *pipe, unsigned int tlen, - unsigned int flags) + unsigned int flags, + ssize_t (*splice_cb)(struct sock *, + struct pipe_inode_info *, + struct splice_pipe_desc *)) { struct partial_page partial[MAX_SKB_FRAGS]; struct page *pages[MAX_SKB_FRAGS]; @@ -1891,7 +1915,6 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, .spd_release = sock_spd_release, }; struct sk_buff *frag_iter; - struct sock *sk = skb->sk; int ret = 0; /* @@ -1914,20 +1937,8 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, } done: - if (spd.nr_pages) { - /* - * Drop the socket lock, otherwise we have reverse - * locking dependencies between sk_lock and i_mutex - * here as compared to sendfile(). We enter here - * with the socket lock held, and splice_to_pipe() will - * grab the pipe inode lock. For sendfile() emulation, - * we call into ->sendpage() with the i_mutex lock held - * and networking will grab the socket lock. - */ - release_sock(sk); - ret = splice_to_pipe(pipe, &spd); - lock_sock(sk); - } + if (spd.nr_pages) + ret = splice_cb(sk, pipe, &spd); return ret; } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 90afcec3f427..65f791f74845 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -695,8 +695,9 @@ static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, struct tcp_splice_state *tss = rd_desc->arg.data; int ret; - ret = skb_splice_bits(skb, offset, tss->pipe, min(rd_desc->count, len), - tss->flags); + ret = skb_splice_bits(skb, skb->sk, offset, tss->pipe, + min(rd_desc->count, len), tss->flags, + skb_socket_splice); if (ret > 0) rd_desc->count -= ret; return ret; -- cgit v1.2.3 From cc4a84c3da6f9dd6a297dc81fe4437643a60fe03 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 22 May 2015 14:07:30 -0700 Subject: net: phy: bcm7xxx: Fix 7425 PHY ID and flags While adding support for 7425 PHY in the 7xxx PHY driver, the ID that was used was actually coming from an external PHY: a BCM5461x. Fix this by using the proper ID for the internal 7425 PHY and set the PHY_IS_INTERNAL flag, otherwise consumers of this PHY driver would not be able to properly identify it as such. Fixes: d068b02cfdfc2 ("net: phy: add BCM7425 and BCM7429 PHYs") Signed-off-by: Florian Fainelli Reviewed-by: Petri Gynther Signed-off-by: David S. Miller --- drivers/net/phy/bcm7xxx.c | 2 +- include/linux/brcmphy.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index 64c74c6a4828..b5dc59de094e 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -404,7 +404,7 @@ static struct phy_driver bcm7xxx_driver[] = { .name = "Broadcom BCM7425", .features = PHY_GBIT_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause, - .flags = 0, + .flags = PHY_IS_INTERNAL, .config_init = bcm7xxx_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h index ae2982c0f7a6..656da2a12ffe 100644 --- a/include/linux/brcmphy.h +++ b/include/linux/brcmphy.h @@ -17,7 +17,7 @@ #define PHY_ID_BCM7250 0xae025280 #define PHY_ID_BCM7364 0xae025260 #define PHY_ID_BCM7366 0x600d8490 -#define PHY_ID_BCM7425 0x03625e60 +#define PHY_ID_BCM7425 0x600d86b0 #define PHY_ID_BCM7429 0x600d8730 #define PHY_ID_BCM7439 0x600d8480 #define PHY_ID_BCM7439_2 0xae025080 -- cgit v1.2.3 From 286c2349f6665c3e67f464a5faa14a0e28be4842 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 22 May 2015 20:55:56 -0700 Subject: ipv6: Clean up ipv6_select_ident() and ip6_fragment() This patch changes the ipv6_select_ident() signature to return a fragment id instead of taking a whole frag_hdr as a param to only set the frag_hdr->identification. It also cleans up ip6_fragment() to obtain the fragment id at the beginning instead of using multiple "if" later to check fragment id has been generated or not. Signed-off-by: Martin KaFai Lau Cc: Hannes Frederic Sowa Cc: Steffen Klassert Cc: Julian Anastasov Signed-off-by: David S. Miller --- include/net/ipv6.h | 3 +-- net/ipv6/ip6_output.c | 17 ++++++----------- net/ipv6/output_core.c | 5 ++--- 3 files changed, 9 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index aab8190d16e8..8c4f881edbd2 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -671,8 +671,7 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); } -void ipv6_select_ident(struct net *net, struct frag_hdr *fhdr, - struct rt6_info *rt); +u32 ipv6_select_ident(struct net *net, struct rt6_info *rt); void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb); int ip6_dst_hoplimit(struct dst_entry *dst); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index bc09cb97b840..05e2cdf938bd 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -551,7 +551,7 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb, struct frag_hdr *fh; unsigned int mtu, hlen, left, len; int hroom, troom; - __be32 frag_id = 0; + __be32 frag_id; int ptr, offset = 0, err = 0; u8 *prevhdr, nexthdr = 0; struct net *net = dev_net(skb_dst(skb)->dev); @@ -584,6 +584,8 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb, } mtu -= hlen + sizeof(struct frag_hdr); + frag_id = ipv6_select_ident(net, rt); + if (skb_has_frag_list(skb)) { int first_len = skb_pagelen(skb); struct sk_buff *frag2; @@ -632,11 +634,10 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb, skb_reset_network_header(skb); memcpy(skb_network_header(skb), tmp_hdr, hlen); - ipv6_select_ident(net, fh, rt); fh->nexthdr = nexthdr; fh->reserved = 0; fh->frag_off = htons(IP6_MF); - frag_id = fh->identification; + fh->identification = frag_id; first_len = skb_pagelen(skb); skb->data_len = first_len - skb_headlen(skb); @@ -778,11 +779,7 @@ slow_path: */ fh->nexthdr = nexthdr; fh->reserved = 0; - if (!frag_id) { - ipv6_select_ident(net, fh, rt); - frag_id = fh->identification; - } else - fh->identification = frag_id; + fh->identification = frag_id; /* * Copy a block of the IP datagram. @@ -1064,7 +1061,6 @@ static inline int ip6_ufo_append_data(struct sock *sk, { struct sk_buff *skb; - struct frag_hdr fhdr; int err; /* There is support for UDP large send offload by network @@ -1106,8 +1102,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, skb_shinfo(skb)->gso_size = (mtu - fragheaderlen - sizeof(struct frag_hdr)) & ~7; skb_shinfo(skb)->gso_type = SKB_GSO_UDP; - ipv6_select_ident(sock_net(sk), &fhdr, rt); - skb_shinfo(skb)->ip6_frag_id = fhdr.identification; + skb_shinfo(skb)->ip6_frag_id = ipv6_select_ident(sock_net(sk), rt); append: return skb_append_datato_frags(sk, skb, getfrag, from, diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 85892af57364..ef0e2326496b 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -60,8 +60,7 @@ void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident); -void ipv6_select_ident(struct net *net, struct frag_hdr *fhdr, - struct rt6_info *rt) +u32 ipv6_select_ident(struct net *net, struct rt6_info *rt) { static u32 ip6_idents_hashrnd __read_mostly; u32 id; @@ -70,7 +69,7 @@ void ipv6_select_ident(struct net *net, struct frag_hdr *fhdr, id = __ipv6_select_ident(net, ip6_idents_hashrnd, &rt->rt6i_dst.addr, &rt->rt6i_src.addr); - fhdr->identification = htonl(id); + return htonl(id); } EXPORT_SYMBOL(ipv6_select_ident); -- cgit v1.2.3 From fd0273d7939f2ce3247f6aac5f6b9a0135d4cd39 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 22 May 2015 20:55:57 -0700 Subject: ipv6: Remove external dependency on rt6i_dst and rt6i_src This patch removes the assumptions that the returned rt is always a RTF_CACHE entry with the rt6i_dst and rt6i_src containing the destination and source address. The dst and src can be recovered from the calling site. We may consider to rename (rt6i_dst, rt6i_src) to (rt6i_key_dst, rt6i_key_src) later. Signed-off-by: Martin KaFai Lau Reviewed-by: Hannes Frederic Sowa Cc: Steffen Klassert Cc: Julian Anastasov Signed-off-by: David S. Miller --- drivers/scsi/cxgbi/libcxgbi.c | 2 +- include/net/ipv6.h | 4 +++- net/ipv6/icmp.c | 2 +- net/ipv6/ip6_output.c | 13 ++++++++----- net/ipv6/ndisc.c | 2 +- net/ipv6/output_core.c | 10 ++++++---- net/ipv6/tcp_ipv6.c | 2 +- net/netfilter/ipvs/ip_vs_xmit.c | 4 ++-- net/sctp/ipv6.c | 3 ++- 9 files changed, 25 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index eb58afcfb73b..45d30398d7c3 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -728,7 +728,7 @@ static struct cxgbi_sock *cxgbi_check_route6(struct sockaddr *dst_addr) } ndev = n->dev; - if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) { + if (ipv6_addr_is_multicast(&daddr6->sin6_addr)) { pr_info("multi-cast route %pI6 port %u, dev %s.\n", daddr6->sin6_addr.s6_addr, ntohs(daddr6->sin6_port), ndev->name); diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 8c4f881edbd2..b950a2000b7f 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -671,7 +671,9 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); } -u32 ipv6_select_ident(struct net *net, struct rt6_info *rt); +u32 ipv6_select_ident(struct net *net, + const struct in6_addr *daddr, + const struct in6_addr *saddr); void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb); int ip6_dst_hoplimit(struct dst_entry *dst); diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 2c2b5d51f15c..24b359d1425b 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -207,7 +207,7 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type, struct inet_peer *peer; peer = inet_getpeer_v6(net->ipv6.peers, - &rt->rt6i_dst.addr, 1); + &fl6->daddr, 1); res = inet_peer_xrlim_allow(peer, tmo); if (peer) inet_putpeer(peer); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 05e2cdf938bd..3097f2c5e890 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -459,7 +459,7 @@ int ip6_forward(struct sk_buff *skb) else target = &hdr->daddr; - peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1); + peer = inet_getpeer_v6(net->ipv6.peers, &hdr->daddr, 1); /* Limit redirects both by destination (here) and by source (inside ndisc_send_redirect) @@ -584,7 +584,8 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb, } mtu -= hlen + sizeof(struct frag_hdr); - frag_id = ipv6_select_ident(net, rt); + frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr, + &ipv6_hdr(skb)->saddr); if (skb_has_frag_list(skb)) { int first_len = skb_pagelen(skb); @@ -1057,7 +1058,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, int odd, struct sk_buff *skb), void *from, int length, int hh_len, int fragheaderlen, int transhdrlen, int mtu, unsigned int flags, - struct rt6_info *rt) + const struct flowi6 *fl6) { struct sk_buff *skb; @@ -1102,7 +1103,9 @@ static inline int ip6_ufo_append_data(struct sock *sk, skb_shinfo(skb)->gso_size = (mtu - fragheaderlen - sizeof(struct frag_hdr)) & ~7; skb_shinfo(skb)->gso_type = SKB_GSO_UDP; - skb_shinfo(skb)->ip6_frag_id = ipv6_select_ident(sock_net(sk), rt); + skb_shinfo(skb)->ip6_frag_id = ipv6_select_ident(sock_net(sk), + &fl6->daddr, + &fl6->saddr); append: return skb_append_datato_frags(sk, skb, getfrag, from, @@ -1327,7 +1330,7 @@ emsgsize: (sk->sk_type == SOCK_DGRAM)) { err = ip6_ufo_append_data(sk, queue, getfrag, from, length, hh_len, fragheaderlen, - transhdrlen, mtu, flags, rt); + transhdrlen, mtu, flags, fl6); if (err) goto error; return 0; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 96f153c0846b..0a05b35a90fc 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1506,7 +1506,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) "Redirect: destination is not a neighbour\n"); goto release; } - peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1); + peer = inet_getpeer_v6(net->ipv6.peers, &ipv6_hdr(skb)->saddr, 1); ret = inet_peer_xrlim_allow(peer, 1*HZ); if (peer) inet_putpeer(peer); diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index ef0e2326496b..055e85cb7b65 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -10,7 +10,8 @@ #include static u32 __ipv6_select_ident(struct net *net, u32 hashrnd, - struct in6_addr *dst, struct in6_addr *src) + const struct in6_addr *dst, + const struct in6_addr *src) { u32 hash, id; @@ -60,15 +61,16 @@ void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident); -u32 ipv6_select_ident(struct net *net, struct rt6_info *rt) +u32 ipv6_select_ident(struct net *net, + const struct in6_addr *daddr, + const struct in6_addr *saddr) { static u32 ip6_idents_hashrnd __read_mostly; u32 id; net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd)); - id = __ipv6_select_ident(net, ip6_idents_hashrnd, &rt->rt6i_dst.addr, - &rt->rt6i_src.addr); + id = __ipv6_select_ident(net, ip6_idents_hashrnd, daddr, saddr); return htonl(id); } EXPORT_SYMBOL(ipv6_select_ident); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index fefe4455e1f3..1a9390a370c0 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -262,7 +262,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, rt = (struct rt6_info *) dst; if (tcp_death_row.sysctl_tw_recycle && !tp->rx_opt.ts_recent_stamp && - ipv6_addr_equal(&rt->rt6i_dst.addr, &sk->sk_v6_daddr)) + ipv6_addr_equal(&fl6.daddr, &sk->sk_v6_daddr)) tcp_fetch_timewait_stamp(sk, dst); icsk->icsk_ext_hdr_len = 0; diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 19986ec5f21a..38f862728f75 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -781,7 +781,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, /* From world but DNAT to loopback address? */ if (local && skb->dev && !(skb->dev->flags & IFF_LOOPBACK) && - ipv6_addr_type(&rt->rt6i_dst.addr) & IPV6_ADDR_LOOPBACK) { + ipv6_addr_type(&cp->daddr.in6) & IPV6_ADDR_LOOPBACK) { IP_VS_DBG_RL_PKT(1, AF_INET6, pp, skb, 0, "ip_vs_nat_xmit_v6(): " "stopping DNAT to loopback address"); @@ -1346,7 +1346,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, /* From world but DNAT to loopback address? */ if (local && skb->dev && !(skb->dev->flags & IFF_LOOPBACK) && - ipv6_addr_type(&rt->rt6i_dst.addr) & IPV6_ADDR_LOOPBACK) { + ipv6_addr_type(&cp->daddr.in6) & IPV6_ADDR_LOOPBACK) { IP_VS_DBG(1, "%s(): " "stopping DNAT to loopback %pI6\n", __func__, &cp->daddr.in6); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index e703ff7fed40..17a0120ae5a5 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -332,7 +332,8 @@ out: rt = (struct rt6_info *)dst; t->dst = dst; t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; - pr_debug("rt6_dst:%pI6 rt6_src:%pI6\n", &rt->rt6i_dst.addr, + pr_debug("rt6_dst:%pI6/%d rt6_src:%pI6\n", + &rt->rt6i_dst.addr, rt->rt6i_dst.plen, &fl6->saddr); } else { t->dst = NULL; -- cgit v1.2.3 From 2647a9b07032c5a95ddee1fcb65d95bddbc6b7f9 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 22 May 2015 20:55:58 -0700 Subject: ipv6: Remove external dependency on rt6i_gateway and RTF_ANYCAST When creating a RTF_CACHE route, RTF_ANYCAST is set based on rt6i_dst. Also, rt6i_gateway is always set to the nexthop while the nexthop could be a gateway or the rt6i_dst.addr. After removing the rt6i_dst and rt6i_src dependency in the last patch, we also need to stop the caller from depending on rt6i_gateway and RTF_ANYCAST. Signed-off-by: Martin KaFai Lau Cc: Hannes Frederic Sowa Cc: Steffen Klassert Cc: Julian Anastasov Signed-off-by: David S. Miller --- include/net/ip6_route.h | 19 ++++++++++++++----- net/bluetooth/6lowpan.c | 2 +- net/ipv6/icmp.c | 4 ++-- net/ipv6/ip6_output.c | 5 +++-- net/ipv6/route.c | 6 +----- net/netfilter/nf_conntrack_h323_main.c | 4 ++-- net/netfilter/xt_addrtype.c | 2 +- 7 files changed, 24 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 5e192068e6cb..4caf7d697dee 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -163,11 +163,14 @@ static inline bool ipv6_unicast_destination(const struct sk_buff *skb) return rt->rt6i_flags & RTF_LOCAL; } -static inline bool ipv6_anycast_destination(const struct sk_buff *skb) +static inline bool ipv6_anycast_destination(const struct dst_entry *dst, + const struct in6_addr *daddr) { - struct rt6_info *rt = (struct rt6_info *) skb_dst(skb); + struct rt6_info *rt = (struct rt6_info *)dst; - return rt->rt6i_flags & RTF_ANYCAST; + return rt->rt6i_flags & RTF_ANYCAST || + (rt->rt6i_dst.plen != 128 && + ipv6_addr_equal(&rt->rt6i_dst.addr, daddr)); } int ip6_fragment(struct sock *sk, struct sk_buff *skb, @@ -194,9 +197,15 @@ static inline bool ip6_sk_ignore_df(const struct sock *sk) inet6_sk(sk)->pmtudisc == IPV6_PMTUDISC_OMIT; } -static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt) +static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt, + struct in6_addr *daddr) { - return &rt->rt6i_gateway; + if (rt->rt6i_flags & RTF_GATEWAY) + return &rt->rt6i_gateway; + else if (rt->rt6i_flags & RTF_CACHE) + return &rt->rt6i_dst.addr; + else + return daddr; } #endif diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 1742b849fcff..f3d6046c8ee7 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -192,7 +192,7 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev, if (ipv6_addr_any(nexthop)) return NULL; } else { - nexthop = rt6_nexthop(rt); + nexthop = rt6_nexthop(rt, daddr); /* We need to remember the address because it is needed * by bt_xmit() when sending the packet. In bt_xmit(), the diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 24b359d1425b..713d7434c911 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -337,7 +337,7 @@ static struct dst_entry *icmpv6_route_lookup(struct net *net, * We won't send icmp if the destination is known * anycast. */ - if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) { + if (ipv6_anycast_destination(dst, &fl6->daddr)) { net_dbg_ratelimited("icmp6_send: acast source\n"); dst_release(dst); return ERR_PTR(-EINVAL); @@ -564,7 +564,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) if (!ipv6_unicast_destination(skb) && !(net->ipv6.sysctl.anycast_src_echo_reply && - ipv6_anycast_destination(skb))) + ipv6_anycast_destination(skb_dst(skb), saddr))) saddr = NULL; memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr)); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 3097f2c5e890..61741676b987 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -105,7 +105,7 @@ static int ip6_finish_output2(struct sock *sk, struct sk_buff *skb) } rcu_read_lock_bh(); - nexthop = rt6_nexthop((struct rt6_info *)dst); + nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr); neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop); if (unlikely(!neigh)) neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false); @@ -934,7 +934,8 @@ static int ip6_dst_lookup_tail(struct sock *sk, */ rt = (struct rt6_info *) *dst; rcu_read_lock_bh(); - n = __ipv6_neigh_lookup_noref(rt->dst.dev, rt6_nexthop(rt)); + n = __ipv6_neigh_lookup_noref(rt->dst.dev, + rt6_nexthop(rt, &fl6->daddr)); err = n && !(n->nud_state & NUD_VALID) ? -EINVAL : 0; rcu_read_unlock_bh(); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0c889cb89cc3..ce3b1754b4f5 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1945,11 +1945,7 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort, if (rt->rt6i_idev) in6_dev_hold(rt->rt6i_idev); rt->dst.lastuse = jiffies; - - if (ort->rt6i_flags & RTF_GATEWAY) - rt->rt6i_gateway = ort->rt6i_gateway; - else - rt->rt6i_gateway = *dest; + rt->rt6i_gateway = ort->rt6i_gateway; rt->rt6i_flags = ort->rt6i_flags; rt6_set_from(rt, ort); rt->rt6i_metric = 0; diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c index 1d69f5b9748f..9511af04dc81 100644 --- a/net/netfilter/nf_conntrack_h323_main.c +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -779,8 +779,8 @@ static int callforward_do_filter(struct net *net, flowi6_to_flowi(&fl1), false)) { if (!afinfo->route(net, (struct dst_entry **)&rt2, flowi6_to_flowi(&fl2), false)) { - if (ipv6_addr_equal(rt6_nexthop(rt1), - rt6_nexthop(rt2)) && + if (ipv6_addr_equal(rt6_nexthop(rt1, &fl1.daddr), + rt6_nexthop(rt2, &fl2.daddr)) && rt1->dst.dev == rt2->dst.dev) ret = 1; dst_release(&rt2->dst); diff --git a/net/netfilter/xt_addrtype.c b/net/netfilter/xt_addrtype.c index fab6eea1bf38..5b4743cc0436 100644 --- a/net/netfilter/xt_addrtype.c +++ b/net/netfilter/xt_addrtype.c @@ -73,7 +73,7 @@ static u32 match_lookup_rt6(struct net *net, const struct net_device *dev, if (dev == NULL && rt->rt6i_flags & RTF_LOCAL) ret |= XT_ADDRTYPE_LOCAL; - if (rt->rt6i_flags & RTF_ANYCAST) + if (ipv6_anycast_destination((struct dst_entry *)rt, addr)) ret |= XT_ADDRTYPE_ANYCAST; dst_release(&rt->dst); -- cgit v1.2.3 From 45e4fd26683c9a5f88600d91b08a484f7f09226a Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 22 May 2015 20:56:00 -0700 Subject: ipv6: Only create RTF_CACHE routes after encountering pmtu exception This patch creates a RTF_CACHE routes only after encountering a pmtu exception. After ip6_rt_update_pmtu() has inserted the RTF_CACHE route to the fib6 tree, the rt->rt6i_node->fn_sernum is bumped which will fail the ip6_dst_check() and trigger a relookup. Signed-off-by: Martin KaFai Lau Cc: Hannes Frederic Sowa Cc: Steffen Klassert Cc: Julian Anastasov Signed-off-by: David S. Miller --- include/net/ip6_route.h | 2 +- net/ipv6/ip6_fib.c | 1 + net/ipv6/route.c | 100 ++++++++++++++++++++++++------------------------ 3 files changed, 53 insertions(+), 50 deletions(-) (limited to 'include') diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 4caf7d697dee..784ee3d01dbf 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -202,7 +202,7 @@ static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt, { if (rt->rt6i_flags & RTF_GATEWAY) return &rt->rt6i_gateway; - else if (rt->rt6i_flags & RTF_CACHE) + else if (unlikely(rt->rt6i_flags & RTF_CACHE)) return &rt->rt6i_dst.addr; else return daddr; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index bde57b113009..83341b3a248d 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -738,6 +738,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, rt6_clean_expires(iter); else rt6_set_expires(iter, rt->dst.expires); + iter->rt6i_pmtu = rt->rt6i_pmtu; return -EEXIST; } /* If we have the same destination and the same metric, diff --git a/net/ipv6/route.c b/net/ipv6/route.c index f199d6357b31..e7ae2430dfed 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -873,16 +873,13 @@ static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, struct flowi6 *fl6, int flags) { struct fib6_node *fn, *saved_fn; - struct rt6_info *rt, *nrt; + struct rt6_info *rt; int strict = 0; - int attempts = 3; - int err; strict |= flags & RT6_LOOKUP_F_IFACE; if (net->ipv6.devconf_all->forwarding == 0) strict |= RT6_LOOKUP_F_REACHABLE; -redo_fib6_lookup_lock: read_lock_bh(&table->tb6_lock); fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); @@ -901,46 +898,12 @@ redo_rt6_select: strict &= ~RT6_LOOKUP_F_REACHABLE; fn = saved_fn; goto redo_rt6_select; - } else { - dst_hold(&rt->dst); - read_unlock_bh(&table->tb6_lock); - goto out2; } } dst_hold(&rt->dst); read_unlock_bh(&table->tb6_lock); - if (rt->rt6i_flags & RTF_CACHE) - goto out2; - - if (!rt6_is_gw_or_nonexthop(rt) || - !(rt->dst.flags & DST_HOST) || !(rt->rt6i_flags & RTF_LOCAL)) - nrt = ip6_rt_cache_alloc(rt, &fl6->daddr, &fl6->saddr); - else - goto out2; - - ip6_rt_put(rt); - rt = nrt ? : net->ipv6.ip6_null_entry; - - dst_hold(&rt->dst); - if (nrt) { - err = ip6_ins_rt(nrt); - if (!err) - goto out2; - } - - if (--attempts <= 0) - goto out2; - - /* - * Race condition! In the gap, when table->tb6_lock was - * released someone could insert this route. Relookup. - */ - ip6_rt_put(rt); - goto redo_fib6_lookup_lock; - -out2: rt6_dst_from_metrics_check(rt); rt->dst.lastuse = jiffies; rt->dst.__use++; @@ -1113,24 +1076,63 @@ static void ip6_link_failure(struct sk_buff *skb) } } -static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb, u32 mtu) +static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu) +{ + struct net *net = dev_net(rt->dst.dev); + + rt->rt6i_flags |= RTF_MODIFIED; + rt->rt6i_pmtu = mtu; + rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires); +} + +static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, + const struct ipv6hdr *iph, u32 mtu) { struct rt6_info *rt6 = (struct rt6_info *)dst; - dst_confirm(dst); - if (mtu < dst_mtu(dst) && (rt6->rt6i_flags & RTF_CACHE)) { - struct net *net = dev_net(dst->dev); + if (rt6->rt6i_flags & RTF_LOCAL) + return; - rt6->rt6i_flags |= RTF_MODIFIED; - if (mtu < IPV6_MIN_MTU) - mtu = IPV6_MIN_MTU; + dst_confirm(dst); + mtu = max_t(u32, mtu, IPV6_MIN_MTU); + if (mtu >= dst_mtu(dst)) + return; - rt6->rt6i_pmtu = mtu; - rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires); + if (rt6->rt6i_flags & RTF_CACHE) { + rt6_do_update_pmtu(rt6, mtu); + } else { + const struct in6_addr *daddr, *saddr; + struct rt6_info *nrt6; + + if (iph) { + daddr = &iph->daddr; + saddr = &iph->saddr; + } else if (sk) { + daddr = &sk->sk_v6_daddr; + saddr = &inet6_sk(sk)->saddr; + } else { + return; + } + nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr); + if (nrt6) { + rt6_do_update_pmtu(nrt6, mtu); + + /* ip6_ins_rt(nrt6) will bump the + * rt6->rt6i_node->fn_sernum + * which will fail the next rt6_check() and + * invalidate the sk->sk_dst_cache. + */ + ip6_ins_rt(nrt6); + } } } +static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, + struct sk_buff *skb, u32 mtu) +{ + __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu); +} + void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, int oif, u32 mark) { @@ -1147,7 +1149,7 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, dst = ip6_route_output(net, NULL, &fl6); if (!dst->error) - ip6_rt_update_pmtu(dst, NULL, skb, ntohl(mtu)); + __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu)); dst_release(dst); } EXPORT_SYMBOL_GPL(ip6_update_pmtu); -- cgit v1.2.3 From b197df4f0f3782782e9ea8996e91b65ae33e8dd9 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 22 May 2015 20:56:01 -0700 Subject: ipv6: Add rt6_get_cookie() function Instead of doing the rt6->rt6i_node check whenever we need to get the route's cookie. Refactor it into rt6_get_cookie(). It is a prep work to handle FLOWI_FLAG_KNOWN_NH and also percpu rt6_info later. Signed-off-by: Martin KaFai Lau Cc: Hannes Frederic Sowa Cc: Steffen Klassert Cc: Julian Anastasov Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 5 +++++ include/net/ip6_route.h | 2 +- net/ipv6/ip6_tunnel.c | 2 +- net/ipv6/tcp_ipv6.c | 3 +-- net/ipv6/xfrm6_policy.c | 6 ++---- net/netfilter/ipvs/ip_vs_xmit.c | 2 +- net/sctp/ipv6.c | 2 +- 7 files changed, 12 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index e00018011028..a4bece6797da 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -159,6 +159,11 @@ static inline void rt6_update_expires(struct rt6_info *rt0, int timeout) rt0->rt6i_flags |= RTF_EXPIRES; } +static inline u32 rt6_get_cookie(const struct rt6_info *rt) +{ + return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; +} + static inline void ip6_rt_put(struct rt6_info *rt) { /* dst_release() accepts a NULL parameter. diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 784ee3d01dbf..297629aadb19 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -145,7 +145,7 @@ static inline void __ip6_dst_store(struct sock *sk, struct dst_entry *dst, #ifdef CONFIG_IPV6_SUBTREES np->saddr_cache = saddr; #endif - np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; + np->dst_cookie = rt6_get_cookie(rt); } static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 5cafd92c2312..2e67b660118b 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -151,7 +151,7 @@ EXPORT_SYMBOL_GPL(ip6_tnl_dst_reset); void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst) { struct rt6_info *rt = (struct rt6_info *) dst; - t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; + t->dst_cookie = rt6_get_cookie(rt); dst_release(t->dst_cache); t->dst_cache = dst; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 1a9390a370c0..7be3d858cbf0 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -99,8 +99,7 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) dst_hold(dst); sk->sk_rx_dst = dst; inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; - if (rt->rt6i_node) - inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum; + inet6_sk(sk)->rx_dst_cookie = rt6_get_cookie(rt); } } diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 6ae256b4c55a..ed0583c1b9fc 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -76,8 +76,7 @@ static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst, { if (dst->ops->family == AF_INET6) { struct rt6_info *rt = (struct rt6_info *)dst; - if (rt->rt6i_node) - path->path_cookie = rt->rt6i_node->fn_sernum; + path->path_cookie = rt6_get_cookie(rt); } path->u.rt6.rt6i_nfheader_len = nfheader_len; @@ -105,8 +104,7 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, RTF_LOCAL); xdst->u.rt6.rt6i_metric = rt->rt6i_metric; xdst->u.rt6.rt6i_node = rt->rt6i_node; - if (rt->rt6i_node) - xdst->route_cookie = rt->rt6i_node->fn_sernum; + xdst->route_cookie = rt6_get_cookie(rt); xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway; xdst->u.rt6.rt6i_dst = rt->rt6i_dst; xdst->u.rt6.rt6i_src = rt->rt6i_src; diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 38f862728f75..5eff9f6dcfb8 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -435,7 +435,7 @@ __ip_vs_get_out_rt_v6(int skb_af, struct sk_buff *skb, struct ip_vs_dest *dest, goto err_unreach; } rt = (struct rt6_info *) dst; - cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; + cookie = rt6_get_cookie(rt); __ip_vs_dst_set(dest, dest_dst, &rt->dst, cookie); spin_unlock_bh(&dest->dst_lock); IP_VS_DBG(10, "new dst %pI6, src %pI6, refcnt=%d\n", diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 17a0120ae5a5..e917d27328ea 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -331,7 +331,7 @@ out: rt = (struct rt6_info *)dst; t->dst = dst; - t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; + t->dst_cookie = rt6_get_cookie(rt); pr_debug("rt6_dst:%pI6/%d rt6_src:%pI6\n", &rt->rt6i_dst.addr, rt->rt6i_dst.plen, &fl6->saddr); -- cgit v1.2.3 From 3da59bd94583d1239e4fbdee452265a160b9cd71 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 22 May 2015 20:56:03 -0700 Subject: ipv6: Create RTF_CACHE clone when FLOWI_FLAG_KNOWN_NH is set This patch always creates RTF_CACHE clone with DST_NOCACHE when FLOWI_FLAG_KNOWN_NH is set so that the rt6i_dst is set to the fl6->daddr. Signed-off-by: Martin KaFai Lau Acked-by: Julian Anastasov Tested-by: Julian Anastasov Cc: Hannes Frederic Sowa Cc: Steffen Klassert Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 3 +++ net/ipv6/route.c | 59 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index a4bece6797da..5556111022eb 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -161,6 +161,9 @@ static inline void rt6_update_expires(struct rt6_info *rt0, int timeout) static inline u32 rt6_get_cookie(const struct rt6_info *rt) { + if (unlikely(rt->dst.flags & DST_NOCACHE)) + rt = (struct rt6_info *)(rt->dst.from); + return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e7ae2430dfed..9e4c3c5d1591 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -901,13 +901,34 @@ redo_rt6_select: } } - dst_hold(&rt->dst); + dst_use(&rt->dst, jiffies); read_unlock_bh(&table->tb6_lock); - rt6_dst_from_metrics_check(rt); - rt->dst.lastuse = jiffies; - rt->dst.__use++; + if (rt == net->ipv6.ip6_null_entry || (rt->rt6i_flags & RTF_CACHE)) { + goto done; + } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) && + !(rt->rt6i_flags & RTF_GATEWAY))) { + /* Create a RTF_CACHE clone which will not be + * owned by the fib6 tree. It is for the special case where + * the daddr in the skb during the neighbor look-up is different + * from the fl6->daddr used to look-up route here. + */ + + struct rt6_info *uncached_rt; + + uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL); + dst_release(&rt->dst); + + if (uncached_rt) + uncached_rt->dst.flags |= DST_NOCACHE; + else + uncached_rt = net->ipv6.ip6_null_entry; + dst_hold(&uncached_rt->dst); + return uncached_rt; + } +done: + rt6_dst_from_metrics_check(rt); return rt; } @@ -1019,6 +1040,26 @@ static void rt6_dst_from_metrics_check(struct rt6_info *rt) dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true); } +static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie) +{ + if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie)) + return NULL; + + if (rt6_check_expired(rt)) + return NULL; + + return &rt->dst; +} + +static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie) +{ + if (rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK && + rt6_check((struct rt6_info *)(rt->dst.from), cookie)) + return &rt->dst; + else + return NULL; +} + static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) { struct rt6_info *rt; @@ -1029,15 +1070,13 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) * DST_OBSOLETE_FORCE_CHK which forces validation calls down * into this function always. */ - if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie)) - return NULL; - - if (rt6_check_expired(rt)) - return NULL; rt6_dst_from_metrics_check(rt); - return dst; + if (unlikely(dst->flags & DST_NOCACHE)) + return rt6_dst_from_check(rt, cookie); + else + return rt6_check(rt, cookie); } static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) -- cgit v1.2.3 From 8d0b94afdca84598912347e61defa846a0988d04 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 22 May 2015 20:56:04 -0700 Subject: ipv6: Keep track of DST_NOCACHE routes in case of iface down/unregister This patch keeps track of the DST_NOCACHE routes in a list and replaces its dev with loopback during the iface down/unregister event. Signed-off-by: Martin KaFai Lau Cc: Hannes Frederic Sowa Cc: Steffen Klassert Cc: Julian Anastasov Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 3 ++ net/ipv6/route.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 5556111022eb..cc8f03c10c43 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -120,6 +120,9 @@ struct rt6_info { struct rt6key rt6i_src; struct rt6key rt6i_prefsrc; + struct list_head rt6i_uncached; + struct uncached_list *rt6i_uncached_list; + struct inet6_dev *rt6i_idev; u32 rt6i_metric; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 9e4c3c5d1591..94ce1e0b5a33 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -105,6 +105,67 @@ static struct rt6_info *rt6_get_route_info(struct net *net, const struct in6_addr *gwaddr, int ifindex); #endif +struct uncached_list { + spinlock_t lock; + struct list_head head; +}; + +static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list); + +static void rt6_uncached_list_add(struct rt6_info *rt) +{ + struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list); + + rt->dst.flags |= DST_NOCACHE; + rt->rt6i_uncached_list = ul; + + spin_lock_bh(&ul->lock); + list_add_tail(&rt->rt6i_uncached, &ul->head); + spin_unlock_bh(&ul->lock); +} + +static void rt6_uncached_list_del(struct rt6_info *rt) +{ + if (!list_empty(&rt->rt6i_uncached)) { + struct uncached_list *ul = rt->rt6i_uncached_list; + + spin_lock_bh(&ul->lock); + list_del(&rt->rt6i_uncached); + spin_unlock_bh(&ul->lock); + } +} + +static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev) +{ + struct net_device *loopback_dev = net->loopback_dev; + int cpu; + + for_each_possible_cpu(cpu) { + struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu); + struct rt6_info *rt; + + spin_lock_bh(&ul->lock); + list_for_each_entry(rt, &ul->head, rt6i_uncached) { + struct inet6_dev *rt_idev = rt->rt6i_idev; + struct net_device *rt_dev = rt->dst.dev; + + if (rt_idev && (rt_idev->dev == dev || !dev) && + rt_idev->dev != loopback_dev) { + rt->rt6i_idev = in6_dev_get(loopback_dev); + in6_dev_put(rt_idev); + } + + if (rt_dev && (rt_dev == dev || !dev) && + rt_dev != loopback_dev) { + rt->dst.dev = loopback_dev; + dev_hold(rt->dst.dev); + dev_put(rt_dev); + } + } + spin_unlock_bh(&ul->lock); + } +} + static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) { struct rt6_info *rt = (struct rt6_info *)dst; @@ -262,6 +323,7 @@ static inline struct rt6_info *ip6_dst_alloc(struct net *net, memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst)); INIT_LIST_HEAD(&rt->rt6i_siblings); + INIT_LIST_HEAD(&rt->rt6i_uncached); } return rt; } @@ -269,11 +331,14 @@ static inline struct rt6_info *ip6_dst_alloc(struct net *net, static void ip6_dst_destroy(struct dst_entry *dst) { struct rt6_info *rt = (struct rt6_info *)dst; - struct inet6_dev *idev = rt->rt6i_idev; struct dst_entry *from = dst->from; + struct inet6_dev *idev; dst_destroy_metrics_generic(dst); + rt6_uncached_list_del(rt); + + idev = rt->rt6i_idev; if (idev) { rt->rt6i_idev = NULL; in6_dev_put(idev); @@ -920,7 +985,7 @@ redo_rt6_select: dst_release(&rt->dst); if (uncached_rt) - uncached_rt->dst.flags |= DST_NOCACHE; + rt6_uncached_list_add(uncached_rt); else uncached_rt = net->ipv6.ip6_null_entry; dst_hold(&uncached_rt->dst); @@ -2367,6 +2432,7 @@ void rt6_ifdown(struct net *net, struct net_device *dev) fib6_clean_all(net, fib6_ifdown, &adn); icmp6_clean_all(fib6_ifdown, &adn); + rt6_uncached_list_flush_dev(net, dev); } struct rt6_mtu_change_arg { @@ -3263,6 +3329,7 @@ static struct notifier_block ip6_route_dev_notifier = { int __init ip6_route_init(void) { int ret; + int cpu; ret = -ENOMEM; ip6_dst_ops_template.kmem_cachep = @@ -3322,6 +3389,13 @@ int __init ip6_route_init(void) if (ret) goto out_register_late_subsys; + for_each_possible_cpu(cpu) { + struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu); + + INIT_LIST_HEAD(&ul->head); + spin_lock_init(&ul->lock); + } + out: return ret; -- cgit v1.2.3 From d52d3997f843ffefaa8d8462790ffcaca6c74192 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 22 May 2015 20:56:06 -0700 Subject: ipv6: Create percpu rt6_info After the patch 'ipv6: Only create RTF_CACHE routes after encountering pmtu exception', we need to compensate the performance hit (bouncing dst->__refcnt). Signed-off-by: Martin KaFai Lau Cc: Hannes Frederic Sowa Cc: Steffen Klassert Cc: Julian Anastasov Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 3 +- include/uapi/linux/ipv6_route.h | 1 + net/ipv6/ip6_fib.c | 24 +++++++- net/ipv6/route.c | 132 +++++++++++++++++++++++++++++++++++----- 4 files changed, 142 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index cc8f03c10c43..3b76849c190f 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -124,6 +124,7 @@ struct rt6_info { struct uncached_list *rt6i_uncached_list; struct inet6_dev *rt6i_idev; + struct rt6_info * __percpu *rt6i_pcpu; u32 rt6i_metric; u32 rt6i_pmtu; @@ -164,7 +165,7 @@ static inline void rt6_update_expires(struct rt6_info *rt0, int timeout) static inline u32 rt6_get_cookie(const struct rt6_info *rt) { - if (unlikely(rt->dst.flags & DST_NOCACHE)) + if (rt->rt6i_flags & RTF_PCPU || unlikely(rt->dst.flags & DST_NOCACHE)) rt = (struct rt6_info *)(rt->dst.from); return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; diff --git a/include/uapi/linux/ipv6_route.h b/include/uapi/linux/ipv6_route.h index 2be7bd174751..f6598d1c886e 100644 --- a/include/uapi/linux/ipv6_route.h +++ b/include/uapi/linux/ipv6_route.h @@ -34,6 +34,7 @@ #define RTF_PREF(pref) ((pref) << 27) #define RTF_PREF_MASK 0x18000000 +#define RTF_PCPU 0x40000000 #define RTF_LOCAL 0x80000000 diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 83341b3a248d..55d19861ab20 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -154,10 +154,32 @@ static void node_free(struct fib6_node *fn) kmem_cache_free(fib6_node_kmem, fn); } +static void rt6_free_pcpu(struct rt6_info *non_pcpu_rt) +{ + int cpu; + + if (!non_pcpu_rt->rt6i_pcpu) + return; + + for_each_possible_cpu(cpu) { + struct rt6_info **ppcpu_rt; + struct rt6_info *pcpu_rt; + + ppcpu_rt = per_cpu_ptr(non_pcpu_rt->rt6i_pcpu, cpu); + pcpu_rt = *ppcpu_rt; + if (pcpu_rt) { + dst_free(&pcpu_rt->dst); + *ppcpu_rt = NULL; + } + } +} + static void rt6_release(struct rt6_info *rt) { - if (atomic_dec_and_test(&rt->rt6i_ref)) + if (atomic_dec_and_test(&rt->rt6i_ref)) { + rt6_free_pcpu(rt); dst_free(&rt->dst); + } } static void fib6_link_table(struct net *net, struct fib6_table *tb) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 90c8eaa24565..1a1122a6bbf5 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -165,11 +165,18 @@ static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev) } } +static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt) +{ + return dst_metrics_write_ptr(rt->dst.from); +} + static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) { struct rt6_info *rt = (struct rt6_info *)dst; - if (rt->rt6i_flags & RTF_CACHE) + if (rt->rt6i_flags & RTF_PCPU) + return rt6_pcpu_cow_metrics(rt); + else if (rt->rt6i_flags & RTF_CACHE) return NULL; else return dst_cow_metrics_generic(dst, old); @@ -309,10 +316,10 @@ static const struct rt6_info ip6_blk_hole_entry_template = { #endif /* allocate dst with ip6_dst_ops */ -static inline struct rt6_info *ip6_dst_alloc(struct net *net, - struct net_device *dev, - int flags, - struct fib6_table *table) +static struct rt6_info *__ip6_dst_alloc(struct net *net, + struct net_device *dev, + int flags, + struct fib6_table *table) { struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0, DST_OBSOLETE_FORCE_CHK, flags); @@ -327,6 +334,34 @@ static inline struct rt6_info *ip6_dst_alloc(struct net *net, return rt; } +static struct rt6_info *ip6_dst_alloc(struct net *net, + struct net_device *dev, + int flags, + struct fib6_table *table) +{ + struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags, table); + + if (rt) { + rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC); + if (rt->rt6i_pcpu) { + int cpu; + + for_each_possible_cpu(cpu) { + struct rt6_info **p; + + p = per_cpu_ptr(rt->rt6i_pcpu, cpu); + /* no one shares rt */ + *p = NULL; + } + } else { + dst_destroy((struct dst_entry *)rt); + return NULL; + } + } + + return rt; +} + static void ip6_dst_destroy(struct dst_entry *dst) { struct rt6_info *rt = (struct rt6_info *)dst; @@ -335,6 +370,9 @@ static void ip6_dst_destroy(struct dst_entry *dst) dst_destroy_metrics_generic(dst); + if (rt->rt6i_pcpu) + free_percpu(rt->rt6i_pcpu); + rt6_uncached_list_del(rt); idev = rt->rt6i_idev; @@ -912,11 +950,11 @@ static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort, * Clone the route. */ - if (ort->rt6i_flags & RTF_CACHE) + if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)) ort = (struct rt6_info *)ort->dst.from; - rt = ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, - 0, ort->rt6i_table); + rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, + 0, ort->rt6i_table); if (!rt) return NULL; @@ -943,6 +981,54 @@ static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort, return rt; } +static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt) +{ + struct rt6_info *pcpu_rt; + + pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev), + rt->dst.dev, rt->dst.flags, + rt->rt6i_table); + + if (!pcpu_rt) + return NULL; + ip6_rt_copy_init(pcpu_rt, rt); + pcpu_rt->rt6i_protocol = rt->rt6i_protocol; + pcpu_rt->rt6i_flags |= RTF_PCPU; + return pcpu_rt; +} + +/* It should be called with read_lock_bh(&tb6_lock) acquired */ +static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt) +{ + struct rt6_info *pcpu_rt, *prev, **p; + + p = this_cpu_ptr(rt->rt6i_pcpu); + pcpu_rt = *p; + + if (pcpu_rt) + goto done; + + pcpu_rt = ip6_rt_pcpu_alloc(rt); + if (!pcpu_rt) { + struct net *net = dev_net(rt->dst.dev); + + pcpu_rt = net->ipv6.ip6_null_entry; + goto done; + } + + prev = cmpxchg(p, NULL, pcpu_rt); + if (prev) { + /* If someone did it before us, return prev instead */ + dst_destroy(&pcpu_rt->dst); + pcpu_rt = prev; + } + +done: + dst_hold(&pcpu_rt->dst); + rt6_dst_from_metrics_check(pcpu_rt); + return pcpu_rt; +} + static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif, struct flowi6 *fl6, int flags) { @@ -975,11 +1061,13 @@ redo_rt6_select: } } - dst_use(&rt->dst, jiffies); - read_unlock_bh(&table->tb6_lock); if (rt == net->ipv6.ip6_null_entry || (rt->rt6i_flags & RTF_CACHE)) { - goto done; + dst_use(&rt->dst, jiffies); + read_unlock_bh(&table->tb6_lock); + + rt6_dst_from_metrics_check(rt); + return rt; } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) && !(rt->rt6i_flags & RTF_GATEWAY))) { /* Create a RTF_CACHE clone which will not be @@ -990,6 +1078,9 @@ redo_rt6_select: struct rt6_info *uncached_rt; + dst_use(&rt->dst, jiffies); + read_unlock_bh(&table->tb6_lock); + uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL); dst_release(&rt->dst); @@ -997,13 +1088,22 @@ redo_rt6_select: rt6_uncached_list_add(uncached_rt); else uncached_rt = net->ipv6.ip6_null_entry; + dst_hold(&uncached_rt->dst); return uncached_rt; - } -done: - rt6_dst_from_metrics_check(rt); - return rt; + } else { + /* Get a percpu copy */ + + struct rt6_info *pcpu_rt; + + rt->dst.lastuse = jiffies; + rt->dst.__use++; + pcpu_rt = rt6_get_pcpu_route(rt); + read_unlock_bh(&table->tb6_lock); + + return pcpu_rt; + } } static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table, @@ -1147,7 +1247,7 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) rt6_dst_from_metrics_check(rt); - if (unlikely(dst->flags & DST_NOCACHE)) + if ((rt->rt6i_flags & RTF_PCPU) || unlikely(dst->flags & DST_NOCACHE)) return rt6_dst_from_check(rt, cookie); else return rt6_check(rt, cookie); -- cgit v1.2.3 From 7f1598678d4c05e3e085bf780a5ab3119637ac3c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 25 May 2015 16:02:21 -0700 Subject: ipv6: ipv6_select_ident() returns a __be32 ipv6_select_ident() returns a 32bit value in network order. Fixes: 286c2349f666 ("ipv6: Clean up ipv6_select_ident() and ip6_fragment()") Signed-off-by: Eric Dumazet Reported-by: kbuild test robot Acked-by: Martin KaFai Lau Signed-off-by: David S. Miller --- include/net/ipv6.h | 6 +++--- net/ipv6/output_core.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index b950a2000b7f..35d485c78080 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -671,9 +671,9 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); } -u32 ipv6_select_ident(struct net *net, - const struct in6_addr *daddr, - const struct in6_addr *saddr); +__be32 ipv6_select_ident(struct net *net, + const struct in6_addr *daddr, + const struct in6_addr *saddr); void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb); int ip6_dst_hoplimit(struct dst_entry *dst); diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 055e85cb7b65..21678acd4521 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -61,9 +61,9 @@ void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident); -u32 ipv6_select_ident(struct net *net, - const struct in6_addr *daddr, - const struct in6_addr *saddr) +__be32 ipv6_select_ident(struct net *net, + const struct in6_addr *daddr, + const struct in6_addr *saddr) { static u32 ip6_idents_hashrnd __read_mostly; u32 id; -- cgit v1.2.3 From cacce073bfd2b4091fbc58e906e7a9a21f538ff6 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 14 May 2015 23:05:49 +0200 Subject: bcma: add module_bcma_driver() This makes it possible to save some lines of code in drivers with an simple bcma driver registration. Signed-off-by: Hauke Mehrtens Signed-off-by: Kalle Valo --- include/linux/bcma/bcma.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'include') diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index e34f906647d3..2ff4a9961e1d 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -305,6 +305,15 @@ int __bcma_driver_register(struct bcma_driver *drv, struct module *owner); extern void bcma_driver_unregister(struct bcma_driver *drv); +/* module_bcma_driver() - Helper macro for drivers that don't do + * anything special in module init/exit. This eliminates a lot of + * boilerplate. Each module may only use this macro once, and + * calling it replaces module_init() and module_exit() + */ +#define module_bcma_driver(__bcma_driver) \ + module_driver(__bcma_driver, bcma_driver_register, \ + bcma_driver_unregister) + /* Set a fallback SPROM. * See kdoc at the function definition for complete documentation. */ extern int bcma_arch_register_fallback_sprom( -- cgit v1.2.3 From ebddf1a8d78aa3436353fae75c4396e50cb2d6cf Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 26 May 2015 18:41:20 +0200 Subject: netfilter: nf_tables: allow to bind table to net_device This patch adds the internal NFT_AF_NEEDS_DEV flag to indicate that you must attach this table to a net_device. This change is required by the follow up patch that introduces the new netdev table. Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 8 ++++++ include/uapi/linux/netfilter/nf_tables.h | 2 ++ net/netfilter/nf_tables_api.c | 46 ++++++++++++++++++++++++++++---- 3 files changed, 51 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index e6bcf55dcf20..3d6f48ca40a7 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -819,6 +819,7 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt, * @use: number of chain references to this table * @flags: table flag (see enum nft_table_flags) * @name: name of the table + * @dev: this table is bound to this device (if any) */ struct nft_table { struct list_head list; @@ -828,6 +829,11 @@ struct nft_table { u32 use; u16 flags; char name[NFT_TABLE_MAXNAMELEN]; + struct net_device *dev; +}; + +enum nft_af_flags { + NFT_AF_NEEDS_DEV = (1 << 0), }; /** @@ -838,6 +844,7 @@ struct nft_table { * @nhooks: number of hooks in this family * @owner: module owner * @tables: used internally + * @flags: family flags * @nops: number of hook ops in this family * @hook_ops_init: initialization function for chain hook ops * @hooks: hookfn overrides for packet validation @@ -848,6 +855,7 @@ struct nft_af_info { unsigned int nhooks; struct module *owner; struct list_head tables; + u32 flags; unsigned int nops; void (*hook_ops_init)(struct nf_hook_ops *, unsigned int); diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index 5fa1cd04762e..89a671e0f5e7 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -146,12 +146,14 @@ enum nft_table_flags { * @NFTA_TABLE_NAME: name of the table (NLA_STRING) * @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32) * @NFTA_TABLE_USE: number of chains in this table (NLA_U32) + * @NFTA_TABLE_DEV: net device name (NLA_STRING) */ enum nft_table_attributes { NFTA_TABLE_UNSPEC, NFTA_TABLE_NAME, NFTA_TABLE_FLAGS, NFTA_TABLE_USE, + NFTA_TABLE_DEV, __NFTA_TABLE_MAX }; #define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index ad9d11fb29fd..2fd4e99dd074 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -399,6 +399,8 @@ static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = { [NFTA_TABLE_NAME] = { .type = NLA_STRING, .len = NFT_TABLE_MAXNAMELEN - 1 }, [NFTA_TABLE_FLAGS] = { .type = NLA_U32 }, + [NFTA_TABLE_DEV] = { .type = NLA_STRING, + .len = IFNAMSIZ - 1 }, }; static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net, @@ -423,6 +425,10 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net, nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use))) goto nla_put_failure; + if (table->dev && + nla_put_string(skb, NFTA_TABLE_DEV, table->dev->name)) + goto nla_put_failure; + nlmsg_end(skb, nlh); return 0; @@ -608,6 +614,11 @@ static int nf_tables_updtable(struct nft_ctx *ctx) if (flags == ctx->table->flags) return 0; + if ((ctx->afi->flags & NFT_AF_NEEDS_DEV) && + ctx->nla[NFTA_TABLE_DEV] && + nla_strcmp(ctx->nla[NFTA_TABLE_DEV], ctx->table->dev->name)) + return -EOPNOTSUPP; + trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE, sizeof(struct nft_trans_table)); if (trans == NULL) @@ -645,6 +656,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, struct nft_table *table; struct net *net = sock_net(skb->sk); int family = nfmsg->nfgen_family; + struct net_device *dev = NULL; u32 flags = 0; struct nft_ctx ctx; int err; @@ -679,30 +691,50 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, return -EINVAL; } + if (afi->flags & NFT_AF_NEEDS_DEV) { + char ifname[IFNAMSIZ]; + + if (!nla[NFTA_TABLE_DEV]) + return -EOPNOTSUPP; + + nla_strlcpy(ifname, nla[NFTA_TABLE_DEV], IFNAMSIZ); + dev = dev_get_by_name(net, ifname); + if (!dev) + return -ENOENT; + } else if (nla[NFTA_TABLE_DEV]) { + return -EOPNOTSUPP; + } + + err = -EAFNOSUPPORT; if (!try_module_get(afi->owner)) - return -EAFNOSUPPORT; + goto err1; err = -ENOMEM; table = kzalloc(sizeof(*table), GFP_KERNEL); if (table == NULL) - goto err1; + goto err2; nla_strlcpy(table->name, name, NFT_TABLE_MAXNAMELEN); INIT_LIST_HEAD(&table->chains); INIT_LIST_HEAD(&table->sets); table->flags = flags; + table->dev = dev; nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla); err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE); if (err < 0) - goto err2; + goto err3; list_add_tail_rcu(&table->list, &afi->tables); return 0; -err2: +err3: kfree(table); -err1: +err2: module_put(afi->owner); +err1: + if (dev != NULL) + dev_put(dev); + return err; } @@ -806,6 +838,9 @@ static void nf_tables_table_destroy(struct nft_ctx *ctx) { BUG_ON(ctx->table->use > 0); + if (ctx->table->dev) + dev_put(ctx->table->dev); + kfree(ctx->table); module_put(ctx->afi->owner); } @@ -1361,6 +1396,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, ops->priority = priority; ops->priv = chain; ops->hook = afi->hooks[ops->hooknum]; + ops->dev = table->dev; if (hookfn) ops->hook = hookfn; if (afi->hook_ops_init) -- cgit v1.2.3 From ed6c4136f1571bd6ab362afc3410905a8a69ca42 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 26 May 2015 18:41:40 +0200 Subject: netfilter: nf_tables: add netdev table to filter from ingress This allows us to create netdev tables that contain ingress chains. Use skb_header_pointer() as we may see shared sk_buffs at this stage. This change provides access to the existing nf_tables features from the ingress hook. Signed-off-by: Pablo Neira Ayuso --- include/net/netns/nftables.h | 1 + net/netfilter/Kconfig | 5 ++ net/netfilter/Makefile | 1 + net/netfilter/nf_tables_netdev.c | 183 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 190 insertions(+) create mode 100644 net/netfilter/nf_tables_netdev.c (limited to 'include') diff --git a/include/net/netns/nftables.h b/include/net/netns/nftables.h index eee608b12cc9..c80781146019 100644 --- a/include/net/netns/nftables.h +++ b/include/net/netns/nftables.h @@ -13,6 +13,7 @@ struct netns_nftables { struct nft_af_info *inet; struct nft_af_info *arp; struct nft_af_info *bridge; + struct nft_af_info *netdev; unsigned int base_seq; u8 gencursor; }; diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 9a89e7c67d78..bd5aaebaa9a2 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -456,6 +456,11 @@ config NF_TABLES_INET help This option enables support for a mixed IPv4/IPv6 "inet" table. +config NF_TABLES_NETDEV + tristate "Netfilter nf_tables netdev tables support" + help + This option enables support for the "netdev" table. + config NFT_EXTHDR tristate "Netfilter nf_tables IPv6 exthdr module" help diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index a87d8b8ec730..70d026d46fe7 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -75,6 +75,7 @@ nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o obj-$(CONFIG_NF_TABLES) += nf_tables.o obj-$(CONFIG_NF_TABLES_INET) += nf_tables_inet.o +obj-$(CONFIG_NF_TABLES_NETDEV) += nf_tables_netdev.o obj-$(CONFIG_NFT_COMPAT) += nft_compat.o obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o obj-$(CONFIG_NFT_META) += nft_meta.o diff --git a/net/netfilter/nf_tables_netdev.c b/net/netfilter/nf_tables_netdev.c new file mode 100644 index 000000000000..04cb17057f46 --- /dev/null +++ b/net/netfilter/nf_tables_netdev.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2015 Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +static inline void +nft_netdev_set_pktinfo_ipv4(struct nft_pktinfo *pkt, + const struct nf_hook_ops *ops, struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct iphdr *iph, _iph; + u32 len, thoff; + + nft_set_pktinfo(pkt, ops, skb, state); + + iph = skb_header_pointer(skb, skb_network_offset(skb), sizeof(*iph), + &_iph); + if (!iph) + return; + + iph = ip_hdr(skb); + if (iph->ihl < 5 || iph->version != 4) + return; + + len = ntohs(iph->tot_len); + thoff = iph->ihl * 4; + if (skb->len < len) + return; + else if (len < thoff) + return; + + pkt->tprot = iph->protocol; + pkt->xt.thoff = thoff; + pkt->xt.fragoff = ntohs(iph->frag_off) & IP_OFFSET; +} + +static inline void +__nft_netdev_set_pktinfo_ipv6(struct nft_pktinfo *pkt, + const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ +#if IS_ENABLED(CONFIG_IPV6) + struct ipv6hdr *ip6h, _ip6h; + unsigned int thoff = 0; + unsigned short frag_off; + int protohdr; + u32 pkt_len; + + ip6h = skb_header_pointer(skb, skb_network_offset(skb), sizeof(*ip6h), + &_ip6h); + if (!ip6h) + return; + + if (ip6h->version != 6) + return; + + pkt_len = ntohs(ip6h->payload_len); + if (pkt_len + sizeof(*ip6h) > skb->len) + return; + + protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, NULL); + if (protohdr < 0) + return; + + pkt->tprot = protohdr; + pkt->xt.thoff = thoff; + pkt->xt.fragoff = frag_off; +#endif +} + +static inline void nft_netdev_set_pktinfo_ipv6(struct nft_pktinfo *pkt, + const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + nft_set_pktinfo(pkt, ops, skb, state); + __nft_netdev_set_pktinfo_ipv6(pkt, ops, skb, state); +} + +static unsigned int +nft_do_chain_netdev(const struct nf_hook_ops *ops, struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct nft_pktinfo pkt; + + switch (eth_hdr(skb)->h_proto) { + case htons(ETH_P_IP): + nft_netdev_set_pktinfo_ipv4(&pkt, ops, skb, state); + break; + case htons(ETH_P_IPV6): + nft_netdev_set_pktinfo_ipv6(&pkt, ops, skb, state); + break; + default: + nft_set_pktinfo(&pkt, ops, skb, state); + break; + } + + return nft_do_chain(&pkt, ops); +} + +static struct nft_af_info nft_af_netdev __read_mostly = { + .family = NFPROTO_NETDEV, + .nhooks = NF_NETDEV_NUMHOOKS, + .owner = THIS_MODULE, + .flags = NFT_AF_NEEDS_DEV, + .nops = 1, + .hooks = { + [NF_NETDEV_INGRESS] = nft_do_chain_netdev, + }, +}; + +static int nf_tables_netdev_init_net(struct net *net) +{ + net->nft.netdev = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL); + if (net->nft.netdev == NULL) + return -ENOMEM; + + memcpy(net->nft.netdev, &nft_af_netdev, sizeof(nft_af_netdev)); + + if (nft_register_afinfo(net, net->nft.netdev) < 0) + goto err; + + return 0; +err: + kfree(net->nft.netdev); + return -ENOMEM; +} + +static void nf_tables_netdev_exit_net(struct net *net) +{ + nft_unregister_afinfo(net->nft.netdev); + kfree(net->nft.netdev); +} + +static struct pernet_operations nf_tables_netdev_net_ops = { + .init = nf_tables_netdev_init_net, + .exit = nf_tables_netdev_exit_net, +}; + +static const struct nf_chain_type nft_filter_chain_netdev = { + .name = "filter", + .type = NFT_CHAIN_T_DEFAULT, + .family = NFPROTO_NETDEV, + .owner = THIS_MODULE, + .hook_mask = (1 << NF_NETDEV_INGRESS), +}; + +static int __init nf_tables_netdev_init(void) +{ + int ret; + + nft_register_chain_type(&nft_filter_chain_netdev); + ret = register_pernet_subsys(&nf_tables_netdev_net_ops); + if (ret < 0) + nft_unregister_chain_type(&nft_filter_chain_netdev); + + return ret; +} + +static void __exit nf_tables_netdev_exit(void) +{ + unregister_pernet_subsys(&nf_tables_netdev_net_ops); + nft_unregister_chain_type(&nft_filter_chain_netdev); +} + +module_init(nf_tables_netdev_init); +module_exit(nf_tables_netdev_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Pablo Neira Ayuso "); +MODULE_ALIAS_NFT_FAMILY(5); /* NFPROTO_NETDEV */ -- cgit v1.2.3 From d0997b44c9081071e39417b188f7db6d1ea37341 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 25 May 2015 15:38:33 +0300 Subject: ieee802154: Remove ieee802154_reduced_mlme_ops references. As there doesn't seem to be a definition of it or any users of it. Signed-off-by: Lennert Buytenhek Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/ieee802154_netdev.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'include') diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 84a72a1382a8..0a87975128ec 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -430,10 +430,4 @@ ieee802154_mlme_ops(const struct net_device *dev) return dev->ml_priv; } -static inline struct ieee802154_reduced_mlme_ops * -ieee802154_reduced_mlme_ops(const struct net_device *dev) -{ - return dev->ml_priv; -} - #endif -- cgit v1.2.3 From 095dc8e0c3686d586a01a50abc3e1bb9ac633054 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 26 May 2015 07:55:34 -0700 Subject: tcp: fix/cleanup inet_ehash_locks_alloc() If tcp ehash table is constrained to a very small number of buckets (eg boot parameter thash_entries=128), then we can crash if spinlock array has more entries. While we are at it, un-inline inet_ehash_locks_alloc() and make following changes : - Budget 2 cache lines per cpu worth of 'spinlocks' - Try to kmalloc() the array to avoid extra TLB pressure. (Most servers at Google allocate 8192 bytes for this hash table) - Get rid of various #ifdef Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/inet_hashtables.h | 47 +++---------------------------------------- net/ipv4/inet_hashtables.c | 31 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 44 deletions(-) (limited to 'include') diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 774d24151d4a..b73c88a19dd4 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -164,52 +163,12 @@ static inline spinlock_t *inet_ehash_lockp( return &hashinfo->ehash_locks[hash & hashinfo->ehash_locks_mask]; } -static inline int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo) -{ - unsigned int i, size = 256; -#if defined(CONFIG_PROVE_LOCKING) - unsigned int nr_pcpus = 2; -#else - unsigned int nr_pcpus = num_possible_cpus(); -#endif - if (nr_pcpus >= 4) - size = 512; - if (nr_pcpus >= 8) - size = 1024; - if (nr_pcpus >= 16) - size = 2048; - if (nr_pcpus >= 32) - size = 4096; - if (sizeof(spinlock_t) != 0) { -#ifdef CONFIG_NUMA - if (size * sizeof(spinlock_t) > PAGE_SIZE) - hashinfo->ehash_locks = vmalloc(size * sizeof(spinlock_t)); - else -#endif - hashinfo->ehash_locks = kmalloc(size * sizeof(spinlock_t), - GFP_KERNEL); - if (!hashinfo->ehash_locks) - return ENOMEM; - for (i = 0; i < size; i++) - spin_lock_init(&hashinfo->ehash_locks[i]); - } - hashinfo->ehash_locks_mask = size - 1; - return 0; -} +int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo); static inline void inet_ehash_locks_free(struct inet_hashinfo *hashinfo) { - if (hashinfo->ehash_locks) { -#ifdef CONFIG_NUMA - unsigned int size = (hashinfo->ehash_locks_mask + 1) * - sizeof(spinlock_t); - if (size > PAGE_SIZE) - vfree(hashinfo->ehash_locks); - else -#endif - kfree(hashinfo->ehash_locks); - hashinfo->ehash_locks = NULL; - } + kvfree(hashinfo->ehash_locks); + hashinfo->ehash_locks = NULL; } struct inet_bind_bucket * diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 3766bddb3e8a..185efef0f125 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -609,3 +610,33 @@ void inet_hashinfo_init(struct inet_hashinfo *h) } } EXPORT_SYMBOL_GPL(inet_hashinfo_init); + +int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo) +{ + unsigned int i, nblocks = 1; + + if (sizeof(spinlock_t) != 0) { + /* allocate 2 cache lines or at least one spinlock per cpu */ + nblocks = max_t(unsigned int, + 2 * L1_CACHE_BYTES / sizeof(spinlock_t), + 1); + nblocks = roundup_pow_of_two(nblocks * num_possible_cpus()); + + /* no more locks than number of hash buckets */ + nblocks = min(nblocks, hashinfo->ehash_mask + 1); + + hashinfo->ehash_locks = kmalloc_array(nblocks, sizeof(spinlock_t), + GFP_KERNEL | __GFP_NOWARN); + if (!hashinfo->ehash_locks) + hashinfo->ehash_locks = vmalloc(nblocks * sizeof(spinlock_t)); + + if (!hashinfo->ehash_locks) + return -ENOMEM; + + for (i = 0; i < nblocks; i++) + spin_lock_init(&hashinfo->ehash_locks[i]); + } + hashinfo->ehash_locks_mask = nblocks - 1; + return 0; +} +EXPORT_SYMBOL_GPL(inet_ehash_locks_alloc); -- cgit v1.2.3 From 194ec9368c0dbc421acdb2620d4dfb3cc3d022ff Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 14 May 2015 15:28:24 +0100 Subject: drivers: of/base: move of_init to driver_init Commit 5590f3196b29 ("drivers/core/of: Add symlink to device-tree from devices with an OF node") adds the symlink `of_node` for each device pointing to it's device tree node while creating/initialising it. However the devicetree sysfs is created and setup in of_init which is executed at core_initcall level. For all the devices created before of_init, the following error is thrown: "Error -2(-ENOENT) creating of_node link" Like many other components in driver model, initialize the sysfs support for OF/devicetree from driver_init so that it's ready before any devices are created. Fixes: 5590f3196b29 ("drivers/core/of: Add symlink to device-tree from devices with an OF node") Suggested-by: Rob Herring Cc: Grant Likely Cc: Pawel Moll Cc: Benjamin Herrenschmidt Signed-off-by: Sudeep Holla Tested-by: Robert Schwebel Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/base/init.c | 2 ++ drivers/of/base.c | 8 +++----- include/linux/of.h | 6 ++++++ 3 files changed, 11 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/base/init.c b/drivers/base/init.c index da033d3bab3c..48c0e220acc0 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "base.h" @@ -34,4 +35,5 @@ void __init driver_init(void) cpu_dev_init(); memory_dev_init(); container_dev_init(); + of_core_init(); } diff --git a/drivers/of/base.c b/drivers/of/base.c index 99764db0875a..f0650265febf 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -189,7 +189,7 @@ int __of_attach_node_sysfs(struct device_node *np) return 0; } -static int __init of_init(void) +void __init of_core_init(void) { struct device_node *np; @@ -198,7 +198,8 @@ static int __init of_init(void) of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj); if (!of_kset) { mutex_unlock(&of_mutex); - return -ENOMEM; + pr_err("devicetree: failed to register existing nodes\n"); + return; } for_each_of_allnodes(np) __of_attach_node_sysfs(np); @@ -207,10 +208,7 @@ static int __init of_init(void) /* Symlink in /proc as required by userspace ABI */ if (of_root) proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base"); - - return 0; } -core_initcall(of_init); static struct property *__of_find_property(const struct device_node *np, const char *name, int *lenp) diff --git a/include/linux/of.h b/include/linux/of.h index ddeaae6d2083..b871ff9d81d7 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -121,6 +121,8 @@ extern struct device_node *of_stdout; extern raw_spinlock_t devtree_lock; #ifdef CONFIG_OF +void of_core_init(void); + static inline bool is_of_node(struct fwnode_handle *fwnode) { return fwnode && fwnode->type == FWNODE_OF; @@ -376,6 +378,10 @@ bool of_console_check(struct device_node *dn, char *name, int index); #else /* CONFIG_OF */ +static inline void of_core_init(void) +{ +} + static inline bool is_of_node(struct fwnode_handle *fwnode) { return false; -- cgit v1.2.3 From e463d88c36d42211aa72ed76d32fb8bf37820ef1 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 26 May 2015 12:19:58 -0700 Subject: net: phy: Add phy_interface_is_rgmii helper RGMII interfaces come in 4 different flavors that the PHY library needs to care about: regular RGMII (no delays), RGMII with either RX or TX delay, and both. In order to avoid errors of checking only for one type of RGMII interface and miss the 3 others, introduce a convenience function which tests for all values. Suggested-by: David S. Miller Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- include/linux/phy.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include') diff --git a/include/linux/phy.h b/include/linux/phy.h index 701c7a3946e0..a26c3f84b8dd 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -677,6 +677,17 @@ static inline bool phy_is_internal(struct phy_device *phydev) return phydev->is_internal; } +/** + * phy_interface_is_rgmii - Convenience function for testing if a PHY interface + * is RGMII (all variants) + * @phydev: the phy_device struct + */ +static inline bool phy_interface_is_rgmii(struct phy_device *phydev) +{ + return phydev->interface >= PHY_INTERFACE_MODE_RGMII && + phydev->interface <= PHY_INTERFACE_MODE_RGMII_TXID; +} + /** * phy_write_mmd - Convenience function for writing a register * on an MMD on a given PHY. -- cgit v1.2.3 From b371b594317869971af326adcf7cd65cabdb4087 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 21 May 2015 10:57:13 +0200 Subject: perf/x86: Fix event/group validation Commit 43b4578071c0 ("perf/x86: Reduce stack usage of x86_schedule_events()") violated the rule that 'fake' scheduling; as used for event/group validation; should not change the event state. This went mostly un-noticed because repeated calls of x86_pmu::get_event_constraints() would give the same result. And x86_pmu::put_event_constraints() would mostly not do anything. Commit e979121b1b15 ("perf/x86/intel: Implement cross-HT corruption bug workaround") made the situation much worse by actually setting the event->hw.constraint value to NULL, so when validation and actual scheduling interact we get NULL ptr derefs. Fix it by removing the constraint pointer from the event and move it back to an array, this time in cpuc instead of on the stack. validate_group() x86_schedule_events() event->hw.constraint = c; # store perf_task_event_sched_in() ... x86_schedule_events(); event->hw.constraint = c2; # store ... put_event_constraints(event); # assume failure to schedule intel_put_event_constraints() event->hw.constraint = NULL; c = event->hw.constraint; # read -> NULL if (!test_bit(hwc->idx, c->idxmsk)) # <- *BOOM* NULL deref This in particular is possible when the event in question is a cpu-wide event and group-leader, where the validate_group() tries to add an event to the group. Reported-by: Vince Weaver Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Hunter Cc: Linus Torvalds Cc: Maria Dimakopoulou Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 43b4578071c0 ("perf/x86: Reduce stack usage of x86_schedule_events()") Fixes: e979121b1b15 ("perf/x86/intel: Implement cross-HT corruption bug workaround") Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 33 +++++++++++++++------------ arch/x86/kernel/cpu/perf_event.h | 9 ++++---- arch/x86/kernel/cpu/perf_event_intel.c | 15 ++++-------- arch/x86/kernel/cpu/perf_event_intel_ds.c | 4 ++-- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 7 +++--- arch/x86/kernel/cpu/perf_event_intel_uncore.h | 1 + include/linux/perf_event.h | 4 ---- 7 files changed, 33 insertions(+), 40 deletions(-) (limited to 'include') diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 87848ebe2bb7..1664eeea65e0 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -620,7 +620,7 @@ struct sched_state { struct perf_sched { int max_weight; int max_events; - struct perf_event **events; + struct event_constraint **constraints; struct sched_state state; int saved_states; struct sched_state saved[SCHED_STATES_MAX]; @@ -629,7 +629,7 @@ struct perf_sched { /* * Initialize interator that runs through all events and counters. */ -static void perf_sched_init(struct perf_sched *sched, struct perf_event **events, +static void perf_sched_init(struct perf_sched *sched, struct event_constraint **constraints, int num, int wmin, int wmax) { int idx; @@ -637,10 +637,10 @@ static void perf_sched_init(struct perf_sched *sched, struct perf_event **events memset(sched, 0, sizeof(*sched)); sched->max_events = num; sched->max_weight = wmax; - sched->events = events; + sched->constraints = constraints; for (idx = 0; idx < num; idx++) { - if (events[idx]->hw.constraint->weight == wmin) + if (constraints[idx]->weight == wmin) break; } @@ -687,7 +687,7 @@ static bool __perf_sched_find_counter(struct perf_sched *sched) if (sched->state.event >= sched->max_events) return false; - c = sched->events[sched->state.event]->hw.constraint; + c = sched->constraints[sched->state.event]; /* Prefer fixed purpose counters */ if (c->idxmsk64 & (~0ULL << INTEL_PMC_IDX_FIXED)) { idx = INTEL_PMC_IDX_FIXED; @@ -745,7 +745,7 @@ static bool perf_sched_next_event(struct perf_sched *sched) if (sched->state.weight > sched->max_weight) return false; } - c = sched->events[sched->state.event]->hw.constraint; + c = sched->constraints[sched->state.event]; } while (c->weight != sched->state.weight); sched->state.counter = 0; /* start with first counter */ @@ -756,12 +756,12 @@ static bool perf_sched_next_event(struct perf_sched *sched) /* * Assign a counter for each event. */ -int perf_assign_events(struct perf_event **events, int n, +int perf_assign_events(struct event_constraint **constraints, int n, int wmin, int wmax, int *assign) { struct perf_sched sched; - perf_sched_init(&sched, events, n, wmin, wmax); + perf_sched_init(&sched, constraints, n, wmin, wmax); do { if (!perf_sched_find_counter(&sched)) @@ -788,9 +788,9 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) x86_pmu.start_scheduling(cpuc); for (i = 0, wmin = X86_PMC_IDX_MAX, wmax = 0; i < n; i++) { - hwc = &cpuc->event_list[i]->hw; + cpuc->event_constraint[i] = NULL; c = x86_pmu.get_event_constraints(cpuc, i, cpuc->event_list[i]); - hwc->constraint = c; + cpuc->event_constraint[i] = c; wmin = min(wmin, c->weight); wmax = max(wmax, c->weight); @@ -801,7 +801,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) */ for (i = 0; i < n; i++) { hwc = &cpuc->event_list[i]->hw; - c = hwc->constraint; + c = cpuc->event_constraint[i]; /* never assigned */ if (hwc->idx == -1) @@ -821,9 +821,10 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) } /* slow path */ - if (i != n) - unsched = perf_assign_events(cpuc->event_list, n, wmin, + if (i != n) { + unsched = perf_assign_events(cpuc->event_constraint, n, wmin, wmax, assign); + } /* * In case of success (unsched = 0), mark events as committed, @@ -840,7 +841,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) e = cpuc->event_list[i]; e->hw.flags |= PERF_X86_EVENT_COMMITTED; if (x86_pmu.commit_scheduling) - x86_pmu.commit_scheduling(cpuc, e, assign[i]); + x86_pmu.commit_scheduling(cpuc, i, assign[i]); } } @@ -1292,8 +1293,10 @@ static void x86_pmu_del(struct perf_event *event, int flags) x86_pmu.put_event_constraints(cpuc, event); /* Delete the array entry. */ - while (++i < cpuc->n_events) + while (++i < cpuc->n_events) { cpuc->event_list[i-1] = cpuc->event_list[i]; + cpuc->event_constraint[i-1] = cpuc->event_constraint[i]; + } --cpuc->n_events; perf_event_update_userpage(event); diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 6ac5cb7a9e14..fdfaab7c5e55 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -172,7 +172,10 @@ struct cpu_hw_events { added in the current transaction */ int assign[X86_PMC_IDX_MAX]; /* event to counter assignment */ u64 tags[X86_PMC_IDX_MAX]; + struct perf_event *event_list[X86_PMC_IDX_MAX]; /* in enabled order */ + struct event_constraint *event_constraint[X86_PMC_IDX_MAX]; + unsigned int group_flag; int is_fake; @@ -519,9 +522,7 @@ struct x86_pmu { void (*put_event_constraints)(struct cpu_hw_events *cpuc, struct perf_event *event); - void (*commit_scheduling)(struct cpu_hw_events *cpuc, - struct perf_event *event, - int cntr); + void (*commit_scheduling)(struct cpu_hw_events *cpuc, int idx, int cntr); void (*start_scheduling)(struct cpu_hw_events *cpuc); @@ -717,7 +718,7 @@ static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc, void x86_pmu_enable_all(int added); -int perf_assign_events(struct perf_event **events, int n, +int perf_assign_events(struct event_constraint **constraints, int n, int wmin, int wmax, int *assign); int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign); diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 3998131d1a68..7a58fb5df15c 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -2106,7 +2106,7 @@ static struct event_constraint * intel_get_event_constraints(struct cpu_hw_events *cpuc, int idx, struct perf_event *event) { - struct event_constraint *c1 = event->hw.constraint; + struct event_constraint *c1 = cpuc->event_constraint[idx]; struct event_constraint *c2; /* @@ -2188,8 +2188,6 @@ intel_put_shared_regs_event_constraints(struct cpu_hw_events *cpuc, static void intel_put_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event) { - struct event_constraint *c = event->hw.constraint; - intel_put_shared_regs_event_constraints(cpuc, event); /* @@ -2197,19 +2195,14 @@ static void intel_put_event_constraints(struct cpu_hw_events *cpuc, * all events are subject to and must call the * put_excl_constraints() routine */ - if (c && cpuc->excl_cntrs) + if (cpuc->excl_cntrs) intel_put_excl_constraints(cpuc, event); - - /* cleanup dynamic constraint */ - if (c && (c->flags & PERF_X86_EVENT_DYNAMIC)) - event->hw.constraint = NULL; } -static void intel_commit_scheduling(struct cpu_hw_events *cpuc, - struct perf_event *event, int cntr) +static void intel_commit_scheduling(struct cpu_hw_events *cpuc, int idx, int cntr) { struct intel_excl_cntrs *excl_cntrs = cpuc->excl_cntrs; - struct event_constraint *c = event->hw.constraint; + struct event_constraint *c = cpuc->event_constraint[idx]; struct intel_excl_states *xlo, *xl; int tid = cpuc->excl_thread_id; int o_tid = 1 - tid; diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 813f75d71175..7f73b3553e2e 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -706,9 +706,9 @@ void intel_pmu_pebs_disable(struct perf_event *event) cpuc->pebs_enabled &= ~(1ULL << hwc->idx); - if (event->hw.constraint->flags & PERF_X86_EVENT_PEBS_LDLAT) + if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT) cpuc->pebs_enabled &= ~(1ULL << (hwc->idx + 32)); - else if (event->hw.constraint->flags & PERF_X86_EVENT_PEBS_ST) + else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST) cpuc->pebs_enabled &= ~(1ULL << 63); if (cpuc->enabled) diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index c635b8b49e93..ec2ba578d286 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -365,9 +365,8 @@ static int uncore_assign_events(struct intel_uncore_box *box, int assign[], int bitmap_zero(used_mask, UNCORE_PMC_IDX_MAX); for (i = 0, wmin = UNCORE_PMC_IDX_MAX, wmax = 0; i < n; i++) { - hwc = &box->event_list[i]->hw; c = uncore_get_event_constraint(box, box->event_list[i]); - hwc->constraint = c; + box->event_constraint[i] = c; wmin = min(wmin, c->weight); wmax = max(wmax, c->weight); } @@ -375,7 +374,7 @@ static int uncore_assign_events(struct intel_uncore_box *box, int assign[], int /* fastpath, try to reuse previous register */ for (i = 0; i < n; i++) { hwc = &box->event_list[i]->hw; - c = hwc->constraint; + c = box->event_constraint[i]; /* never assigned */ if (hwc->idx == -1) @@ -395,7 +394,7 @@ static int uncore_assign_events(struct intel_uncore_box *box, int assign[], int } /* slow path */ if (i != n) - ret = perf_assign_events(box->event_list, n, + ret = perf_assign_events(box->event_constraint, n, wmin, wmax, assign); if (!assign || ret) { diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h index 6c8c1e7e69d8..f789ec9a0133 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h @@ -97,6 +97,7 @@ struct intel_uncore_box { atomic_t refcnt; struct perf_event *events[UNCORE_PMC_IDX_MAX]; struct perf_event *event_list[UNCORE_PMC_IDX_MAX]; + struct event_constraint *event_constraint[UNCORE_PMC_IDX_MAX]; unsigned long active_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)]; u64 tags[UNCORE_PMC_IDX_MAX]; struct pci_dev *pci_dev; diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 61992cf2e977..d8a82a89f35a 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -92,8 +92,6 @@ struct hw_perf_event_extra { int idx; /* index in shared_regs->regs[] */ }; -struct event_constraint; - /** * struct hw_perf_event - performance event hardware details: */ @@ -112,8 +110,6 @@ struct hw_perf_event { struct hw_perf_event_extra extra_reg; struct hw_perf_event_extra branch_reg; - - struct event_constraint *constraint; }; struct { /* software */ struct hrtimer hrtimer; -- cgit v1.2.3 From 0f999b09f5c1b135e840501840dbcd01fad66f79 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 27 May 2015 09:10:54 +0530 Subject: ieee802154: add set transmit power support This patch adds transmission power setting support for IEEE-802.15.4 devices via nl802154. Signed-off-by: Varka Bhadram Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 1 + net/ieee802154/nl802154.c | 30 ++++++++++++++++++++++++++++++ net/ieee802154/rdev-ops.h | 12 ++++++++++++ net/ieee802154/trace.h | 15 +++++++++++++++ net/mac802154/cfg.c | 19 +++++++++++++++++++ 5 files changed, 77 insertions(+) (limited to 'include') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 4de59aa96173..2e3bb012c2ff 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -44,6 +44,7 @@ struct cfg802154_ops { int (*set_channel)(struct wpan_phy *wpan_phy, u8 page, u8 channel); int (*set_cca_mode)(struct wpan_phy *wpan_phy, const struct wpan_phy_cca *cca); + int (*set_tx_power)(struct wpan_phy *wpan_phy, s32 power); int (*set_pan_id)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, __le16 pan_id); int (*set_short_addr)(struct wpan_phy *wpan_phy, diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 212a795b33c9..5c9d524ba02c 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -783,6 +783,28 @@ static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info) return rdev_set_cca_mode(rdev, &cca); } +static int nl802154_set_tx_power(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + s32 power; + int i; + + if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER)) + return -EOPNOTSUPP; + + if (!info->attrs[NL802154_ATTR_TX_POWER]) + return -EINVAL; + + power = nla_get_s32(info->attrs[NL802154_ATTR_TX_POWER]); + + for (i = 0; i < rdev->wpan_phy.supported.tx_powers_size; i++) { + if (power == rdev->wpan_phy.supported.tx_powers[i]) + return rdev_set_tx_power(rdev, power); + } + + return -EINVAL; +} + static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info) { struct cfg802154_registered_device *rdev = info->user_ptr[0]; @@ -1093,6 +1115,14 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_SET_TX_POWER, + .doit = nl802154_set_tx_power, + .policy = nl802154_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | + NL802154_FLAG_NEED_RTNL, + }, { .cmd = NL802154_CMD_SET_PAN_ID, .doit = nl802154_set_pan_id, diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 7b5a9dd94fe5..36456118a6ec 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -74,6 +74,18 @@ rdev_set_cca_mode(struct cfg802154_registered_device *rdev, return ret; } +static inline int +rdev_set_tx_power(struct cfg802154_registered_device *rdev, + s32 power) +{ + int ret; + + trace_802154_rdev_set_tx_power(&rdev->wpan_phy, power); + ret = rdev->ops->set_tx_power(&rdev->wpan_phy, power); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; +} + static inline int rdev_set_pan_id(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev, __le16 pan_id) diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h index 5ac25eb6ed17..1f1cecc420d7 100644 --- a/net/ieee802154/trace.h +++ b/net/ieee802154/trace.h @@ -93,6 +93,21 @@ TRACE_EVENT(802154_rdev_set_channel, __entry->page, __entry->channel) ); +TRACE_EVENT(802154_rdev_set_tx_power, + TP_PROTO(struct wpan_phy *wpan_phy, s32 power), + TP_ARGS(wpan_phy, power), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + __field(s32, power) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + __entry->power = power; + ), + TP_printk(WPAN_PHY_PR_FMT ", power: %d", WPAN_PHY_PR_ARG, + __entry->power) +); + TRACE_EVENT(802154_rdev_set_cca_mode, TP_PROTO(struct wpan_phy *wpan_phy, const struct wpan_phy_cca *cca), TP_ARGS(wpan_phy, cca), diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index d5290ea49dca..ab12fa296eb3 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -105,6 +105,24 @@ ieee802154_set_cca_mode(struct wpan_phy *wpan_phy, return ret; } +static int +ieee802154_set_tx_power(struct wpan_phy *wpan_phy, s32 power) +{ + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); + int ret; + + ASSERT_RTNL(); + + if (wpan_phy->transmit_power == power) + return 0; + + ret = drv_set_tx_power(local, power); + if (!ret) + wpan_phy->transmit_power = power; + + return ret; +} + static int ieee802154_set_pan_id(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, __le16 pan_id) @@ -195,6 +213,7 @@ const struct cfg802154_ops mac802154_config_ops = { .del_virtual_intf = ieee802154_del_iface, .set_channel = ieee802154_set_channel, .set_cca_mode = ieee802154_set_cca_mode, + .set_tx_power = ieee802154_set_tx_power, .set_pan_id = ieee802154_set_pan_id, .set_short_addr = ieee802154_set_short_addr, .set_backoff_exponent = ieee802154_set_backoff_exponent, -- cgit v1.2.3 From d6b915e29f4adea94bc02ba7675bb4f84e6a1abd Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 22 May 2015 16:32:51 +0200 Subject: ip_fragment: don't forward defragmented DF packet We currently always send fragments without DF bit set. Thus, given following setup: mtu1500 - mtu1500:1400 - mtu1400:1280 - mtu1280 A R1 R2 B Where R1 and R2 run linux with netfilter defragmentation/conntrack enabled, then if Host A sent a fragmented packet _with_ DF set to B, R1 will respond with icmp too big error if one of these fragments exceeded 1400 bytes. However, if R1 receives fragment sizes 1200 and 100, it would forward the reassembled packet without refragmenting, i.e. R2 will send an icmp error in response to a packet that was never sent, citing mtu that the original sender never exceeded. The other minor issue is that a refragmentation on R1 will conceal the MTU of R2-B since refragmentation does not set DF bit on the fragments. This modifies ip_fragment so that we track largest fragment size seen both for DF and non-DF packets, and set frag_max_size to the largest value. If the DF fragment size is larger or equal to the non-df one, we will consider the packet a path mtu probe: We set DF bit on the reassembled skb and also tag it with a new IPCB flag to force refragmentation even if skb fits outdev mtu. We will also set DF bit on each fragment in this case. Joint work with Hannes Frederic Sowa. Reported-by: Jesse Gross Signed-off-by: Florian Westphal Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/net/inet_frag.h | 2 +- include/net/ip.h | 1 + net/ipv4/ip_fragment.c | 31 ++++++++++++++++++++++++++----- net/ipv4/ip_output.c | 12 ++++++++++-- 4 files changed, 38 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 8d1765577acc..e1300b3dd597 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -43,7 +43,7 @@ enum { * @len: total length of the original datagram * @meat: length of received fragments so far * @flags: fragment queue flags - * @max_size: (ipv4 only) maximum received fragment size with IP_DF set + * @max_size: maximum received fragment size * @net: namespace that this frag belongs to */ struct inet_frag_queue { diff --git a/include/net/ip.h b/include/net/ip.h index 7921a36b805c..9b976cf99122 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -45,6 +45,7 @@ struct inet_skb_parm { #define IPSKB_FRAG_COMPLETE BIT(3) #define IPSKB_REROUTED BIT(4) #define IPSKB_DOREDIRECT BIT(5) +#define IPSKB_FRAG_PMTU BIT(6) u16 frag_max_size; }; diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 47fa64ee82b1..a50dc6d408d1 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -75,6 +75,7 @@ struct ipq { __be16 id; u8 protocol; u8 ecn; /* RFC3168 support */ + u16 max_df_size; /* largest frag with DF set seen */ int iif; unsigned int rid; struct inet_peer *peer; @@ -326,6 +327,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) { struct sk_buff *prev, *next; struct net_device *dev; + unsigned int fragsize; int flags, offset; int ihl, end; int err = -ENOENT; @@ -481,9 +483,14 @@ found: if (offset == 0) qp->q.flags |= INET_FRAG_FIRST_IN; + fragsize = skb->len + ihl; + + if (fragsize > qp->q.max_size) + qp->q.max_size = fragsize; + if (ip_hdr(skb)->frag_off & htons(IP_DF) && - skb->len + ihl > qp->q.max_size) - qp->q.max_size = skb->len + ihl; + fragsize > qp->max_df_size) + qp->max_df_size = fragsize; if (qp->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && qp->q.meat == qp->q.len) { @@ -613,13 +620,27 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, head->next = NULL; head->dev = dev; head->tstamp = qp->q.stamp; - IPCB(head)->frag_max_size = qp->q.max_size; + IPCB(head)->frag_max_size = max(qp->max_df_size, qp->q.max_size); iph = ip_hdr(head); - /* max_size != 0 implies at least one fragment had IP_DF set */ - iph->frag_off = qp->q.max_size ? htons(IP_DF) : 0; iph->tot_len = htons(len); iph->tos |= ecn; + + /* When we set IP_DF on a refragmented skb we must also force a + * call to ip_fragment to avoid forwarding a DF-skb of size s while + * original sender only sent fragments of size f (where f < s). + * + * We only set DF/IPSKB_FRAG_PMTU if such DF fragment was the largest + * frag seen to avoid sending tiny DF-fragments in case skb was built + * from one very small df-fragment and one large non-df frag. + */ + if (qp->max_df_size == qp->q.max_size) { + IPCB(head)->flags |= IPSKB_FRAG_PMTU; + iph->frag_off = htons(IP_DF); + } else { + iph->frag_off = 0; + } + IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS); qp->q.fragments = NULL; qp->q.fragments_tail = NULL; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index d6dd8ba04441..f5f5ef1cebd5 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -278,7 +278,7 @@ static int ip_finish_output(struct sock *sk, struct sk_buff *skb) if (skb_is_gso(skb)) return ip_finish_output_gso(sk, skb, mtu); - if (skb->len > mtu) + if (skb->len > mtu || (IPCB(skb)->flags & IPSKB_FRAG_PMTU)) return ip_fragment(sk, skb, mtu, ip_finish_output2); return ip_finish_output2(sk, skb); @@ -492,7 +492,10 @@ static int ip_fragment(struct sock *sk, struct sk_buff *skb, { struct iphdr *iph = ip_hdr(skb); - if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) || + if ((iph->frag_off & htons(IP_DF)) == 0) + return ip_do_fragment(sk, skb, output); + + if (unlikely(!skb->ignore_df || (IPCB(skb)->frag_max_size && IPCB(skb)->frag_max_size > mtu))) { struct rtable *rt = skb_rtable(skb); @@ -537,6 +540,8 @@ int ip_do_fragment(struct sock *sk, struct sk_buff *skb, iph = ip_hdr(skb); mtu = ip_skb_dst_mtu(skb); + if (IPCB(skb)->frag_max_size && IPCB(skb)->frag_max_size < mtu) + mtu = IPCB(skb)->frag_max_size; /* * Setup starting values. @@ -732,6 +737,9 @@ slow_path: iph = ip_hdr(skb2); iph->frag_off = htons((offset >> 3)); + if (IPCB(skb)->flags & IPSKB_FRAG_PMTU) + iph->frag_off |= htons(IP_DF); + /* ANK: dirty, but effective trick. Upgrade options only if * the segment to be fragmented was THE FIRST (otherwise, * options are already fixed) and make it ONCE -- cgit v1.2.3 From b69644c1c72e179738dd5c7e52e99d8550189472 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 27 May 2015 13:42:10 +0200 Subject: nl802154: add support to set cca ed level This patch adds support for setting the current cca ed level value over nl802154. Signed-off-by: Alexander Aring Reviewed-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 1 + net/ieee802154/nl802154.c | 30 ++++++++++++++++++++++++++++++ net/ieee802154/rdev-ops.h | 11 +++++++++++ net/ieee802154/trace.h | 15 +++++++++++++++ net/mac802154/cfg.c | 19 +++++++++++++++++++ 5 files changed, 76 insertions(+) (limited to 'include') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 2e3bb012c2ff..290a9a69af07 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -44,6 +44,7 @@ struct cfg802154_ops { int (*set_channel)(struct wpan_phy *wpan_phy, u8 page, u8 channel); int (*set_cca_mode)(struct wpan_phy *wpan_phy, const struct wpan_phy_cca *cca); + int (*set_cca_ed_level)(struct wpan_phy *wpan_phy, s32 ed_level); int (*set_tx_power)(struct wpan_phy *wpan_phy, s32 power); int (*set_pan_id)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, __le16 pan_id); diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index a89d9d024126..7dbb1f4ce7df 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -790,6 +790,28 @@ static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info) return rdev_set_cca_mode(rdev, &cca); } +static int nl802154_set_cca_ed_level(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + s32 ed_level; + int i; + + if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL)) + return -EOPNOTSUPP; + + if (!info->attrs[NL802154_ATTR_CCA_ED_LEVEL]) + return -EINVAL; + + ed_level = nla_get_s32(info->attrs[NL802154_ATTR_CCA_ED_LEVEL]); + + for (i = 0; i < rdev->wpan_phy.supported.cca_ed_levels_size; i++) { + if (ed_level == rdev->wpan_phy.supported.cca_ed_levels[i]) + return rdev_set_cca_ed_level(rdev, ed_level); + } + + return -EINVAL; +} + static int nl802154_set_tx_power(struct sk_buff *skb, struct genl_info *info) { struct cfg802154_registered_device *rdev = info->user_ptr[0]; @@ -1122,6 +1144,14 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_SET_CCA_ED_LEVEL, + .doit = nl802154_set_cca_ed_level, + .policy = nl802154_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | + NL802154_FLAG_NEED_RTNL, + }, { .cmd = NL802154_CMD_SET_TX_POWER, .doit = nl802154_set_tx_power, diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 36456118a6ec..b2155a123f6c 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -74,6 +74,17 @@ rdev_set_cca_mode(struct cfg802154_registered_device *rdev, return ret; } +static inline int +rdev_set_cca_ed_level(struct cfg802154_registered_device *rdev, s32 ed_level) +{ + int ret; + + trace_802154_rdev_set_cca_ed_level(&rdev->wpan_phy, ed_level); + ret = rdev->ops->set_cca_ed_level(&rdev->wpan_phy, ed_level); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; +} + static inline int rdev_set_tx_power(struct cfg802154_registered_device *rdev, s32 power) diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h index ac790bb1b4fe..73eb7605c1eb 100644 --- a/net/ieee802154/trace.h +++ b/net/ieee802154/trace.h @@ -123,6 +123,21 @@ TRACE_EVENT(802154_rdev_set_cca_mode, WPAN_CCA_PR_ARG) ); +TRACE_EVENT(802154_rdev_set_cca_ed_level, + TP_PROTO(struct wpan_phy *wpan_phy, s32 ed_level), + TP_ARGS(wpan_phy, ed_level), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + __field(s32, ed_level) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + __entry->ed_level = ed_level; + ), + TP_printk(WPAN_PHY_PR_FMT ", ed_level: %d", WPAN_PHY_PR_ARG, + __entry->ed_level) +); + DECLARE_EVENT_CLASS(802154_le16_template, TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, __le16 le16arg), diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index ab12fa296eb3..317c4662e544 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -105,6 +105,24 @@ ieee802154_set_cca_mode(struct wpan_phy *wpan_phy, return ret; } +static int +ieee802154_set_cca_ed_level(struct wpan_phy *wpan_phy, s32 ed_level) +{ + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); + int ret; + + ASSERT_RTNL(); + + if (wpan_phy->cca_ed_level == ed_level) + return 0; + + ret = drv_set_cca_ed_level(local, ed_level); + if (!ret) + wpan_phy->cca_ed_level = ed_level; + + return ret; +} + static int ieee802154_set_tx_power(struct wpan_phy *wpan_phy, s32 power) { @@ -213,6 +231,7 @@ const struct cfg802154_ops mac802154_config_ops = { .del_virtual_intf = ieee802154_del_iface, .set_channel = ieee802154_set_channel, .set_cca_mode = ieee802154_set_cca_mode, + .set_cca_ed_level = ieee802154_set_cca_ed_level, .set_tx_power = ieee802154_set_tx_power, .set_pan_id = ieee802154_set_pan_id, .set_short_addr = ieee802154_set_short_addr, -- cgit v1.2.3 From 9302d7bb0c5cd46be5706859301f18c137b2439f Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 26 May 2015 17:30:17 -0600 Subject: sctp: Fix mangled IPv4 addresses on a IPv6 listening socket sctp_v4_map_v6 was subtly writing and reading from members of a union in a way the clobbered data it needed to read before it read it. Zeroing the v6 flowinfo overwrites the v4 sin_addr with 0, meaning that every place that calls sctp_v4_map_v6 gets ::ffff:0.0.0.0 as the result. Reorder things to guarantee correct behaviour no matter what the union layout is. This impacts user space clients that open an IPv6 SCTP socket and receive IPv4 connections. Prior to 299ee user space would see a sockaddr with AF_INET and a correct address, after 299ee the sockaddr is AF_INET6, but the address is wrong. Fixes: 299ee123e198 (sctp: Fixup v4mapped behaviour to comply with Sock API) Signed-off-by: Jason Gunthorpe Acked-by: Daniel Borkmann Acked-by: Neil Horman Signed-off-by: David S. Miller --- include/net/sctp/sctp.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index c56a438c3a1e..ce13cf20f625 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -574,11 +574,14 @@ static inline void sctp_v6_map_v4(union sctp_addr *addr) /* Map v4 address to v4-mapped v6 address */ static inline void sctp_v4_map_v6(union sctp_addr *addr) { + __be16 port; + + port = addr->v4.sin_port; + addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr; + addr->v6.sin6_port = port; addr->v6.sin6_family = AF_INET6; addr->v6.sin6_flowinfo = 0; addr->v6.sin6_scope_id = 0; - addr->v6.sin6_port = addr->v4.sin_port; - addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr; addr->v6.sin6_addr.s6_addr32[0] = 0; addr->v6.sin6_addr.s6_addr32[1] = 0; addr->v6.sin6_addr.s6_addr32[2] = htonl(0x0000ffff); -- cgit v1.2.3 From e5c4708b2b6fec0300db60ee3cf4b4ae96430a12 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Tue, 26 May 2015 19:20:14 -0700 Subject: pci: Add Cavium PCI vendor id This vendor id will be used by network (vNIC), USB (xHCI), SATA (AHCI), GPIO, I2C, MMC and maybe other drivers for ThunderX SoC. Acked-by: Bjorn Helgaas Signed-off-by: Sunil Goutham Signed-off-by: Aleksey Makarov Signed-off-by: David S. Miller --- include/linux/pci_ids.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 2f7b9a40f627..2972c7f3aa1d 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2329,6 +2329,8 @@ #define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea #define PCI_DEVICE_ID_ALTIMA_AC1003 0x03eb +#define PCI_VENDOR_ID_CAVIUM 0x177d + #define PCI_VENDOR_ID_BELKIN 0x1799 #define PCI_DEVICE_ID_BELKIN_F5D7010V7 0x701f -- cgit v1.2.3 From ed2dfd900992aa7b6b3d0abd8ec9a7e9d2c7f827 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 May 2015 11:34:37 -0700 Subject: tcp/dccp: warn user for preferred ip_local_port_range After commit 07f4c90062f8f ("tcp/dccp: try to not exhaust ip_local_port_range in connect()") it is advised to have an even number of ports described in /proc/sys/net/ipv4/ip_local_port_range This means start/end values should have a different parity. Let's warn sysadmins of this, so that they can update their settings if they want to. Suggested-by: David S. Miller Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/netns/ipv4.h | 1 + net/ipv4/sysctl_net_ipv4.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'include') diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 6848b8bb2e63..c68926b4899c 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -19,6 +19,7 @@ struct sock; struct local_ports { seqlock_t lock; int range[2]; + bool warned; }; struct ping_group_range { diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index e64892769607..0330ab2e2b63 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -45,7 +45,13 @@ static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX }; /* Update system visible IP port range */ static void set_local_port_range(struct net *net, int range[2]) { + bool same_parity = !((range[0] ^ range[1]) & 1); + write_seqlock(&net->ipv4.ip_local_ports.lock); + if (same_parity && !net->ipv4.ip_local_ports.warned) { + net->ipv4.ip_local_ports.warned = true; + pr_err_ratelimited("ip_local_port_range: prefer different parity for start/end values.\n"); + } net->ipv4.ip_local_ports.range[0] = range[0]; net->ipv4.ip_local_ports.range[1] = range[1]; write_sequnlock(&net->ipv4.ip_local_ports.lock); -- cgit v1.2.3 From f36963c9d3f6f415732710da3acdd8608a9fa0e5 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 9 May 2015 03:14:13 +0930 Subject: cpumask_set_cpu_local_first => cpumask_local_spread, lament da91309e0a7e (cpumask: Utility function to set n'th cpu...) created a genuinely weird function. I never saw it before, it went through DaveM. (He only does this to make us other maintainers feel better about our own mistakes.) cpumask_set_cpu_local_first's purpose is say "I need to spread things across N online cpus, choose the ones on this numa node first"; you call it in a loop. It can fail. One of the two callers ignores this, the other aborts and fails the device open. It can fail in two ways: allocating the off-stack cpumask, or through a convoluted codepath which AFAICT can only occur if cpu_online_mask changes. Which shouldn't happen, because if cpu_online_mask can change while you call this, it could return a now-offline cpu anyway. It contains a nonsensical test "!cpumask_of_node(numa_node)". This was drawn to my attention by Geert, who said this causes a warning on Sparc. It sets a single bit in a cpumask instead of returning a cpu number, because that's what the callers want. It could be made more efficient by passing the previous cpu rather than an index, but that would be more invasive to the callers. Fixes: da91309e0a7e8966d916a74cce42ed170fde06bf Signed-off-by: Rusty Russell (then rebased) Tested-by: Amir Vadai Acked-by: Amir Vadai Acked-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 6 +-- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 10 ++-- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 6 +-- include/linux/cpumask.h | 6 +-- lib/cpumask.c | 74 +++++++++----------------- 5 files changed, 37 insertions(+), 65 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index a6dcbf850c1f..6f9ffb9026cd 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -2358,11 +2358,11 @@ static int be_evt_queues_create(struct be_adapter *adapter) adapter->cfg_num_qs); for_all_evt_queues(adapter, eqo, i) { + int numa_node = dev_to_node(&adapter->pdev->dev); if (!zalloc_cpumask_var(&eqo->affinity_mask, GFP_KERNEL)) return -ENOMEM; - cpumask_set_cpu_local_first(i, dev_to_node(&adapter->pdev->dev), - eqo->affinity_mask); - + cpumask_set_cpu(cpumask_local_spread(i, numa_node), + eqo->affinity_mask); netif_napi_add(adapter->netdev, &eqo->napi, be_poll, BE_NAPI_WEIGHT); napi_hash_add(&eqo->napi); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 32f5ec737472..cf467a9f6cc7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1501,17 +1501,13 @@ static int mlx4_en_init_affinity_hint(struct mlx4_en_priv *priv, int ring_idx) { struct mlx4_en_rx_ring *ring = priv->rx_ring[ring_idx]; int numa_node = priv->mdev->dev->numa_node; - int ret = 0; if (!zalloc_cpumask_var(&ring->affinity_mask, GFP_KERNEL)) return -ENOMEM; - ret = cpumask_set_cpu_local_first(ring_idx, numa_node, - ring->affinity_mask); - if (ret) - free_cpumask_var(ring->affinity_mask); - - return ret; + cpumask_set_cpu(cpumask_local_spread(ring_idx, numa_node), + ring->affinity_mask); + return 0; } static void mlx4_en_free_affinity_hint(struct mlx4_en_priv *priv, int ring_idx) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index f7bf312fb443..7bed3a88579f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -144,9 +144,9 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, ring->queue_index = queue_index; if (queue_index < priv->num_tx_rings_p_up) - cpumask_set_cpu_local_first(queue_index, - priv->mdev->dev->numa_node, - &ring->affinity_mask); + cpumask_set_cpu(cpumask_local_spread(queue_index, + priv->mdev->dev->numa_node), + &ring->affinity_mask); *pring = ring; return 0; diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 27e285b92b5f..59915ea5373c 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -151,10 +151,8 @@ static inline unsigned int cpumask_any_but(const struct cpumask *mask, return 1; } -static inline int cpumask_set_cpu_local_first(int i, int numa_node, cpumask_t *dstp) +static inline unsigned int cpumask_local_spread(unsigned int i, int node) { - set_bit(0, cpumask_bits(dstp)); - return 0; } @@ -208,7 +206,7 @@ static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp) int cpumask_next_and(int n, const struct cpumask *, const struct cpumask *); int cpumask_any_but(const struct cpumask *mask, unsigned int cpu); -int cpumask_set_cpu_local_first(int i, int numa_node, cpumask_t *dstp); +unsigned int cpumask_local_spread(unsigned int i, int node); /** * for_each_cpu - iterate over every cpu in a mask diff --git a/lib/cpumask.c b/lib/cpumask.c index 830dd5dec40f..5f627084f2e9 100644 --- a/lib/cpumask.c +++ b/lib/cpumask.c @@ -139,64 +139,42 @@ void __init free_bootmem_cpumask_var(cpumask_var_t mask) #endif /** - * cpumask_set_cpu_local_first - set i'th cpu with local numa cpu's first - * + * cpumask_local_spread - select the i'th cpu with local numa cpu's first * @i: index number - * @numa_node: local numa_node - * @dstp: cpumask with the relevant cpu bit set according to the policy + * @node: local numa_node * - * This function sets the cpumask according to a numa aware policy. - * cpumask could be used as an affinity hint for the IRQ related to a - * queue. When the policy is to spread queues across cores - local cores - * first. + * This function selects an online CPU according to a numa aware policy; + * local cpus are returned first, followed by non-local ones, then it + * wraps around. * - * Returns 0 on success, -ENOMEM for no memory, and -EAGAIN when failed to set - * the cpu bit and need to re-call the function. + * It's not very efficient, but useful for setup. */ -int cpumask_set_cpu_local_first(int i, int numa_node, cpumask_t *dstp) +unsigned int cpumask_local_spread(unsigned int i, int node) { - cpumask_var_t mask; int cpu; - int ret = 0; - - if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) - return -ENOMEM; + /* Wrap: we always want a cpu. */ i %= num_online_cpus(); - if (numa_node == -1 || !cpumask_of_node(numa_node)) { - /* Use all online cpu's for non numa aware system */ - cpumask_copy(mask, cpu_online_mask); + if (node == -1) { + for_each_cpu(cpu, cpu_online_mask) + if (i-- == 0) + return cpu; } else { - int n; - - cpumask_and(mask, - cpumask_of_node(numa_node), cpu_online_mask); - - n = cpumask_weight(mask); - if (i >= n) { - i -= n; - - /* If index > number of local cpu's, mask out local - * cpu's - */ - cpumask_andnot(mask, cpu_online_mask, mask); + /* NUMA first. */ + for_each_cpu_and(cpu, cpumask_of_node(node), cpu_online_mask) + if (i-- == 0) + return cpu; + + for_each_cpu(cpu, cpu_online_mask) { + /* Skip NUMA nodes, done above. */ + if (cpumask_test_cpu(cpu, cpumask_of_node(node))) + continue; + + if (i-- == 0) + return cpu; } } - - for_each_cpu(cpu, mask) { - if (--i < 0) - goto out; - } - - ret = -EAGAIN; - -out: - free_cpumask_var(mask); - - if (!ret) - cpumask_set_cpu(cpu, dstp); - - return ret; + BUG(); } -EXPORT_SYMBOL(cpumask_set_cpu_local_first); +EXPORT_SYMBOL(cpumask_local_spread); -- cgit v1.2.3 From 8cf6f497de405ca9eb87ffb34d90699962d10125 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Tue, 26 May 2015 08:22:49 -0700 Subject: ethtool: Add helper routines to pass vf to rx_flow_spec The ring_cookie is 64 bits wide which is much larger than can be used for actual queue index values. So provide some helper routines to pack a VF index into the cookie. This is useful to steer packets to a VF ring without having to know the queue layout of the device. CC: Alex Duyck Signed-off-by: John Fastabend Signed-off-by: Jeff Kirsher --- include/uapi/linux/ethtool.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index ae832b45b44c..0594933cdf55 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -796,6 +796,31 @@ struct ethtool_rx_flow_spec { __u32 location; }; +/* How rings are layed out when accessing virtual functions or + * offloaded queues is device specific. To allow users to do flow + * steering and specify these queues the ring cookie is partitioned + * into a 32bit queue index with an 8 bit virtual function id. + * This also leaves the 3bytes for further specifiers. It is possible + * future devices may support more than 256 virtual functions if + * devices start supporting PCIe w/ARI. However at the moment I + * do not know of any devices that support this so I do not reserve + * space for this at this time. If a future patch consumes the next + * byte it should be aware of this possiblity. + */ +#define ETHTOOL_RX_FLOW_SPEC_RING 0x00000000FFFFFFFFLL +#define ETHTOOL_RX_FLOW_SPEC_RING_VF 0x000000FF00000000LL +#define ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF 32 +static inline __u64 ethtool_get_flow_spec_ring(__u64 ring_cookie) +{ + return ETHTOOL_RX_FLOW_SPEC_RING & ring_cookie; +}; + +static inline __u64 ethtool_get_flow_spec_ring_vf(__u64 ring_cookie) +{ + return (ETHTOOL_RX_FLOW_SPEC_RING_VF & ring_cookie) >> + ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF; +}; + /** * struct ethtool_rxnfc - command to get or set RX flow classification rules * @cmd: Specific command number - %ETHTOOL_GRXFH, %ETHTOOL_SRXFH, -- cgit v1.2.3 From 3a7af58faa7829faa26026c245d2a8a44e9605c5 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Mon, 13 Apr 2015 18:27:35 +0200 Subject: mac80211: Fix mac80211.h docbook comments A couple of enums in mac80211.h became structures recently, but the comments didn't follow suit, leading to errors like: Error(.//include/net/mac80211.h:367): Cannot parse enum! Documentation/DocBook/Makefile:93: recipe for target 'Documentation/DocBook/80211.xml' failed make[1]: *** [Documentation/DocBook/80211.xml] Error 1 Makefile:1361: recipe for target 'mandocs' failed make: *** [mandocs] Error 2 Fix the comments comments accordingly. Added a couple of other small comment fixes while I was there to silence other recently-added docbook warnings. Reported-by: Jim Davis Signed-off-by: Jonathan Corbet Signed-off-by: Johannes Berg --- include/net/mac80211.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8e3668b44c29..fc57f6b82fc5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -354,7 +354,7 @@ enum ieee80211_rssi_event_data { }; /** - * enum ieee80211_rssi_event - data attached to an %RSSI_EVENT + * struct ieee80211_rssi_event - data attached to an %RSSI_EVENT * @data: See &enum ieee80211_rssi_event_data */ struct ieee80211_rssi_event { @@ -388,7 +388,7 @@ enum ieee80211_mlme_event_status { }; /** - * enum ieee80211_mlme_event - data attached to an %MLME_EVENT + * struct ieee80211_mlme_event - data attached to an %MLME_EVENT * @data: See &enum ieee80211_mlme_event_data * @status: See &enum ieee80211_mlme_event_status * @reason: the reason code if applicable @@ -401,9 +401,10 @@ struct ieee80211_mlme_event { /** * struct ieee80211_event - event to be sent to the driver - * @type The event itself. See &enum ieee80211_event_type. + * @type: The event itself. See &enum ieee80211_event_type. * @rssi: relevant if &type is %RSSI_EVENT * @mlme: relevant if &type is %AUTH_EVENT + * @u: union holding the above two fields */ struct ieee80211_event { enum ieee80211_event_type type; -- cgit v1.2.3 From aad653a0bc09dd4ebcb5579f9f835bbae9ef2ba3 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 19 May 2015 15:58:37 +1000 Subject: block: discard bdi_unregister() in favour of bdi_destroy() bdi_unregister() now contains very little functionality. It contains a "WARN_ON" if bdi->dev is NULL. This warning is of no real consequence as bdi->dev isn't needed by anything else in the function, and it triggers if blk_cleanup_queue() -> bdi_destroy() is called before bdi_unregister, which happens since Commit: 6cd18e711dd8 ("block: destroy bdi before blockdev is unregistered.") So this isn't wanted. It also calls bdi_set_min_ratio(). This needs to be called after writes through the bdi have all been flushed, and before the bdi is destroyed. Calling it early is better than calling it late as it frees up a global resource. Calling it immediately after bdi_wb_shutdown() in bdi_destroy() perfectly fits these requirements. So bdi_unregister() can be discarded with the important content moved to bdi_destroy(), as can the writeback_bdi_unregister event which is already not used. Reported-by: Mike Snitzer Cc: stable@vger.kernel.org (v4.0) Fixes: c4db59d31e39 ("fs: don't reassign dirty inodes to default_backing_dev_info") Fixes: 6cd18e711dd8 ("block: destroy bdi before blockdev is unregistered.") Acked-by: Peter Zijlstra (Intel) Acked-by: Dan Williams Tested-by: Nicholas Moulin Signed-off-by: NeilBrown Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe --- block/genhd.c | 1 - include/linux/backing-dev.h | 1 - include/trace/events/writeback.h | 1 - mm/backing-dev.c | 18 +----------------- 4 files changed, 1 insertion(+), 20 deletions(-) (limited to 'include') diff --git a/block/genhd.c b/block/genhd.c index 0a536dc05f3b..666e11b83983 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -653,7 +653,6 @@ void del_gendisk(struct gendisk *disk) disk->flags &= ~GENHD_FL_UP; sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi"); - bdi_unregister(&disk->queue->backing_dev_info); blk_unregister_queue(disk); blk_unregister_region(disk_devt(disk), disk->minors); diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index aff923ae8c4b..d87d8eced064 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -116,7 +116,6 @@ __printf(3, 4) int bdi_register(struct backing_dev_info *bdi, struct device *parent, const char *fmt, ...); int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev); -void bdi_unregister(struct backing_dev_info *bdi); int __must_check bdi_setup_and_register(struct backing_dev_info *, char *); void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages, enum wb_reason reason); diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h index 880dd7437172..c178d13d6f4c 100644 --- a/include/trace/events/writeback.h +++ b/include/trace/events/writeback.h @@ -250,7 +250,6 @@ DEFINE_EVENT(writeback_class, name, \ DEFINE_WRITEBACK_EVENT(writeback_nowork); DEFINE_WRITEBACK_EVENT(writeback_wake_background); DEFINE_WRITEBACK_EVENT(writeback_bdi_register); -DEFINE_WRITEBACK_EVENT(writeback_bdi_unregister); DECLARE_EVENT_CLASS(wbc_class, TP_PROTO(struct writeback_control *wbc, struct backing_dev_info *bdi), diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 6dc4580df2af..000e7b3b9896 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -359,23 +359,6 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi) flush_delayed_work(&bdi->wb.dwork); } -/* - * Called when the device behind @bdi has been removed or ejected. - * - * We can't really do much here except for reducing the dirty ratio at - * the moment. In the future we should be able to set a flag so that - * the filesystem can handle errors at mark_inode_dirty time instead - * of only at writeback time. - */ -void bdi_unregister(struct backing_dev_info *bdi) -{ - if (WARN_ON_ONCE(!bdi->dev)) - return; - - bdi_set_min_ratio(bdi, 0); -} -EXPORT_SYMBOL(bdi_unregister); - static void bdi_wb_init(struct bdi_writeback *wb, struct backing_dev_info *bdi) { memset(wb, 0, sizeof(*wb)); @@ -443,6 +426,7 @@ void bdi_destroy(struct backing_dev_info *bdi) int i; bdi_wb_shutdown(bdi); + bdi_set_min_ratio(bdi, 0); WARN_ON(!list_empty(&bdi->work_list)); WARN_ON(delayed_work_pending(&bdi->wb.dwork)); -- cgit v1.2.3 From 80188b0d77d7426b494af739ac129e0e684acb84 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 29 May 2015 07:39:34 +1000 Subject: percpu_counter: batch size aware __percpu_counter_compare() XFS uses non-stanard batch sizes for avoiding frequent global counter updates on it's allocated inode counters, as they increment or decrement in batches of 64 inodes. Hence the standard percpu counter batch of 32 means that the counter is effectively a global counter. Currently Xfs uses a batch size of 128 so that it doesn't take the global lock on every single modification. However, Xfs also needs to compare accurately against zero, which means we need to use percpu_counter_compare(), and that has a hard-coded batch size of 32, and hence will spuriously fail to detect when it is supposed to use precise comparisons and hence the accounting goes wrong. Add __percpu_counter_compare() to take a custom batch size so we can use it sanely in XFS and factor percpu_counter_compare() to use it. Signed-off-by: Dave Chinner Acked-by: Tejun Heo Signed-off-by: Dave Chinner --- include/linux/percpu_counter.h | 13 ++++++++++++- lib/percpu_counter.c | 6 +++--- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/percpu_counter.h b/include/linux/percpu_counter.h index 50e50095c8d1..84a109449610 100644 --- a/include/linux/percpu_counter.h +++ b/include/linux/percpu_counter.h @@ -41,7 +41,12 @@ void percpu_counter_destroy(struct percpu_counter *fbc); void percpu_counter_set(struct percpu_counter *fbc, s64 amount); void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch); s64 __percpu_counter_sum(struct percpu_counter *fbc); -int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs); +int __percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch); + +static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs) +{ + return __percpu_counter_compare(fbc, rhs, percpu_counter_batch); +} static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount) { @@ -116,6 +121,12 @@ static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs) return 0; } +static inline int +__percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch) +{ + return percpu_counter_compare(fbc, rhs); +} + static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount) { diff --git a/lib/percpu_counter.c b/lib/percpu_counter.c index 48144cdae819..f051d69f0910 100644 --- a/lib/percpu_counter.c +++ b/lib/percpu_counter.c @@ -197,13 +197,13 @@ static int percpu_counter_hotcpu_callback(struct notifier_block *nb, * Compare counter against given value. * Return 1 if greater, 0 if equal and -1 if less */ -int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs) +int __percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch) { s64 count; count = percpu_counter_read(fbc); /* Check to see if rough count will be sufficient for comparison */ - if (abs(count - rhs) > (percpu_counter_batch*num_online_cpus())) { + if (abs(count - rhs) > (batch * num_online_cpus())) { if (count > rhs) return 1; else @@ -218,7 +218,7 @@ int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs) else return 0; } -EXPORT_SYMBOL(percpu_counter_compare); +EXPORT_SYMBOL(__percpu_counter_compare); static int __init percpu_counter_startup(void) { -- cgit v1.2.3 From e5feb1ebaadfb1f5f70a3591e762d780232a4f5d Mon Sep 17 00:00:00 2001 From: "Shreyas B. Prabhu" Date: Thu, 28 May 2015 15:44:16 -0700 Subject: tracing/mm: don't trace kmem_cache_free on offline cpus Since tracepoints use RCU for protection, they must not be called on offline cpus. trace_kmem_cache_free can be called on an offline cpu in this scenario caught by LOCKDEP: =============================== [ INFO: suspicious RCU usage. ] 4.1.0-rc1+ #9 Not tainted ------------------------------- include/trace/events/kmem.h:148 suspicious rcu_dereference_check() usage! other info that might help us debug this: RCU used illegally from offline CPU! rcu_scheduler_active = 1, debug_locks = 1 no locks held by swapper/1/0. stack backtrace: CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.1.0-rc1+ #9 Call Trace: .dump_stack+0x98/0xd4 (unreliable) .lockdep_rcu_suspicious+0x108/0x170 .kmem_cache_free+0x344/0x4b0 .__mmdrop+0x4c/0x160 .idle_task_exit+0xf0/0x100 .pnv_smp_cpu_kill_self+0x58/0x2c0 .cpu_die+0x34/0x50 .arch_cpu_idle_dead+0x20/0x40 .cpu_startup_entry+0x708/0x7a0 .start_secondary+0x36c/0x3a0 start_secondary_prolog+0x10/0x14 Fix this by converting kmem_cache_free trace point into TRACE_EVENT_CONDITION where condition is cpu_online(smp_processor_id()) Signed-off-by: Shreyas B. Prabhu Reported-by: Aneesh Kumar K.V Reviewed-by: Preeti U Murthy Acked-by: Steven Rostedt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/trace/events/kmem.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h index 81ea59812117..78efa0a197a9 100644 --- a/include/trace/events/kmem.h +++ b/include/trace/events/kmem.h @@ -140,11 +140,22 @@ DEFINE_EVENT(kmem_free, kfree, TP_ARGS(call_site, ptr) ); -DEFINE_EVENT(kmem_free, kmem_cache_free, +DEFINE_EVENT_CONDITION(kmem_free, kmem_cache_free, TP_PROTO(unsigned long call_site, const void *ptr), - TP_ARGS(call_site, ptr) + TP_ARGS(call_site, ptr), + + /* + * This trace can be potentially called from an offlined cpu. + * Since trace points use RCU and RCU should not be used from + * offline cpus, filter such calls out. + * While this trace can be called from a preemptable section, + * it has no impact on the condition since tasks can migrate + * only from online cpus to other online cpus. Thus its safe + * to use raw_smp_processor_id. + */ + TP_CONDITION(cpu_online(raw_smp_processor_id())) ); TRACE_EVENT(mm_page_free, -- cgit v1.2.3 From 1f0c27b50f4f2567e649f49d77daee2bbf3f40e5 Mon Sep 17 00:00:00 2001 From: "Shreyas B. Prabhu" Date: Thu, 28 May 2015 15:44:19 -0700 Subject: tracing/mm: don't trace mm_page_free on offline cpus Since tracepoints use RCU for protection, they must not be called on offline cpus. trace_mm_page_free can be called on an offline cpu in this scenario caught by LOCKDEP: =============================== [ INFO: suspicious RCU usage. ] 4.1.0-rc1+ #9 Not tainted ------------------------------- include/trace/events/kmem.h:170 suspicious rcu_dereference_check() usage! other info that might help us debug this: RCU used illegally from offline CPU! rcu_scheduler_active = 1, debug_locks = 1 no locks held by swapper/1/0. stack backtrace: CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.1.0-rc1+ #9 Call Trace: .dump_stack+0x98/0xd4 (unreliable) .lockdep_rcu_suspicious+0x108/0x170 .free_pages_prepare+0x494/0x680 .free_hot_cold_page+0x50/0x280 .destroy_context+0x90/0xd0 .__mmdrop+0x58/0x160 .idle_task_exit+0xf0/0x100 .pnv_smp_cpu_kill_self+0x58/0x2c0 .cpu_die+0x34/0x50 .arch_cpu_idle_dead+0x20/0x40 .cpu_startup_entry+0x708/0x7a0 .start_secondary+0x36c/0x3a0 start_secondary_prolog+0x10/0x14 Fix this by converting mm_page_free trace point into TRACE_EVENT_CONDITION where condition is cpu_online(smp_processor_id()) Signed-off-by: Shreyas B. Prabhu Reviewed-by: Preeti U Murthy Acked-by: Steven Rostedt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/trace/events/kmem.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h index 78efa0a197a9..aa863549e77a 100644 --- a/include/trace/events/kmem.h +++ b/include/trace/events/kmem.h @@ -158,12 +158,24 @@ DEFINE_EVENT_CONDITION(kmem_free, kmem_cache_free, TP_CONDITION(cpu_online(raw_smp_processor_id())) ); -TRACE_EVENT(mm_page_free, +TRACE_EVENT_CONDITION(mm_page_free, TP_PROTO(struct page *page, unsigned int order), TP_ARGS(page, order), + + /* + * This trace can be potentially called from an offlined cpu. + * Since trace points use RCU and RCU should not be used from + * offline cpus, filter such calls out. + * While this trace can be called from a preemptable section, + * it has no impact on the condition since tasks can migrate + * only from online cpus to other online cpus. Thus its safe + * to use raw_smp_processor_id. + */ + TP_CONDITION(cpu_online(raw_smp_processor_id())), + TP_STRUCT__entry( __field( unsigned long, pfn ) __field( unsigned int, order ) -- cgit v1.2.3 From 649b8de2f75145bf14cb1783688e16d51ac9b89a Mon Sep 17 00:00:00 2001 From: "Shreyas B. Prabhu" Date: Thu, 28 May 2015 15:44:22 -0700 Subject: tracing/mm: don't trace mm_page_pcpu_drain on offline cpus Since tracepoints use RCU for protection, they must not be called on offline cpus. trace_mm_page_pcpu_drain can be called on an offline cpu in this scenario caught by LOCKDEP: =============================== [ INFO: suspicious RCU usage. ] 4.1.0-rc1+ #9 Not tainted ------------------------------- include/trace/events/kmem.h:265 suspicious rcu_dereference_check() usage! other info that might help us debug this: RCU used illegally from offline CPU! rcu_scheduler_active = 1, debug_locks = 1 1 lock held by swapper/5/0: #0: (&(&zone->lock)->rlock){..-...}, at: [] .free_pcppages_bulk+0x70/0x920 stack backtrace: CPU: 5 PID: 0 Comm: swapper/5 Not tainted 4.1.0-rc1+ #9 Call Trace: .dump_stack+0x98/0xd4 (unreliable) .lockdep_rcu_suspicious+0x108/0x170 .free_pcppages_bulk+0x60c/0x920 .free_hot_cold_page+0x208/0x280 .destroy_context+0x90/0xd0 .__mmdrop+0x58/0x160 .idle_task_exit+0xf0/0x100 .pnv_smp_cpu_kill_self+0x58/0x2c0 .cpu_die+0x34/0x50 .arch_cpu_idle_dead+0x20/0x40 .cpu_startup_entry+0x708/0x7a0 .start_secondary+0x36c/0x3a0 start_secondary_prolog+0x10/0x14 Fix this by converting mm_page_pcpu_drain trace point into TRACE_EVENT_CONDITION where condition is cpu_online(smp_processor_id()) Signed-off-by: Shreyas B. Prabhu Reviewed-by: Preeti U Murthy Acked-by: Steven Rostedt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/trace/events/kmem.h | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h index aa863549e77a..f7554fd7fc62 100644 --- a/include/trace/events/kmem.h +++ b/include/trace/events/kmem.h @@ -276,12 +276,35 @@ DEFINE_EVENT(mm_page, mm_page_alloc_zone_locked, TP_ARGS(page, order, migratetype) ); -DEFINE_EVENT_PRINT(mm_page, mm_page_pcpu_drain, +TRACE_EVENT_CONDITION(mm_page_pcpu_drain, TP_PROTO(struct page *page, unsigned int order, int migratetype), TP_ARGS(page, order, migratetype), + /* + * This trace can be potentially called from an offlined cpu. + * Since trace points use RCU and RCU should not be used from + * offline cpus, filter such calls out. + * While this trace can be called from a preemptable section, + * it has no impact on the condition since tasks can migrate + * only from online cpus to other online cpus. Thus its safe + * to use raw_smp_processor_id. + */ + TP_CONDITION(cpu_online(raw_smp_processor_id())), + + TP_STRUCT__entry( + __field( unsigned long, pfn ) + __field( unsigned int, order ) + __field( int, migratetype ) + ), + + TP_fast_assign( + __entry->pfn = page ? page_to_pfn(page) : -1UL; + __entry->order = order; + __entry->migratetype = migratetype; + ), + TP_printk("page=%p pfn=%lu order=%d migratetype=%d", pfn_to_page(__entry->pfn), __entry->pfn, __entry->order, __entry->migratetype) -- cgit v1.2.3 From f7b81d67d0547c6ce246c89900eaa41303a3f89a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 27 May 2015 11:02:46 -0700 Subject: clk: qcom: Add support for NSS/GMAC clocks and resets Add the NSS/GMAC clocks and the TCM clock and NSS resets. Signed-off-by: Stephen Boyd Signed-off-by: Mathieu Olivari Signed-off-by: David S. Miller --- drivers/clk/qcom/gcc-ipq806x.c | 594 ++++++++++++++++++++++++++- include/dt-bindings/clock/qcom,gcc-ipq806x.h | 2 + include/dt-bindings/reset/qcom,gcc-ipq806x.h | 43 ++ 3 files changed, 638 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index a50936a17376..563969942a1d 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c @@ -140,12 +140,47 @@ static struct clk_regmap pll14_vote = { }, }; +#define NSS_PLL_RATE(f, _l, _m, _n, i) \ + { \ + .freq = f, \ + .l = _l, \ + .m = _m, \ + .n = _n, \ + .ibits = i, \ + } + +static struct pll_freq_tbl pll18_freq_tbl[] = { + NSS_PLL_RATE(550000000, 44, 0, 1, 0x01495625), + NSS_PLL_RATE(733000000, 58, 16, 25, 0x014b5625), +}; + +static struct clk_pll pll18 = { + .l_reg = 0x31a4, + .m_reg = 0x31a8, + .n_reg = 0x31ac, + .config_reg = 0x31b4, + .mode_reg = 0x31a0, + .status_reg = 0x31b8, + .status_bit = 16, + .post_div_shift = 16, + .post_div_width = 1, + .freq_tbl = pll18_freq_tbl, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll18", + .parent_names = (const char *[]){ "pxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + enum { P_PXO, P_PLL8, P_PLL3, P_PLL0, P_CXO, + P_PLL14, + P_PLL18, }; static const struct parent_map gcc_pxo_pll8_map[] = { @@ -197,6 +232,22 @@ static const char *gcc_pxo_pll8_pll0_map[] = { "pll0_vote", }; +static const struct parent_map gcc_pxo_pll8_pll14_pll18_pll0_map[] = { + { P_PXO, 0 }, + { P_PLL8, 4 }, + { P_PLL0, 2 }, + { P_PLL14, 5 }, + { P_PLL18, 1 } +}; + +static const char *gcc_pxo_pll8_pll14_pll18_pll0[] = { + "pxo", + "pll8_vote", + "pll0_vote", + "pll14", + "pll18", +}; + static struct freq_tbl clk_tbl_gsbi_uart[] = { { 1843200, P_PLL8, 2, 6, 625 }, { 3686400, P_PLL8, 2, 12, 625 }, @@ -2202,6 +2253,472 @@ static struct clk_branch ebi2_aon_clk = { }, }; +static const struct freq_tbl clk_tbl_gmac[] = { + { 133000000, P_PLL0, 1, 50, 301 }, + { 266000000, P_PLL0, 1, 127, 382 }, + { } +}; + +static struct clk_dyn_rcg gmac_core1_src = { + .ns_reg[0] = 0x3cac, + .ns_reg[1] = 0x3cb0, + .md_reg[0] = 0x3ca4, + .md_reg[1] = 0x3ca8, + .bank_reg = 0x3ca0, + .mn[0] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .mn[1] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .s[0] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .s[1] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .p[0] = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .p[1] = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .mux_sel_bit = 0, + .freq_tbl = clk_tbl_gmac, + .clkr = { + .enable_reg = 0x3ca0, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core1_src", + .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + }, + }, +}; + +static struct clk_branch gmac_core1_clk = { + .halt_reg = 0x3c20, + .halt_bit = 4, + .hwcg_reg = 0x3cb4, + .hwcg_bit = 6, + .clkr = { + .enable_reg = 0x3cb4, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core1_clk", + .parent_names = (const char *[]){ + "gmac_core1_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_dyn_rcg gmac_core2_src = { + .ns_reg[0] = 0x3ccc, + .ns_reg[1] = 0x3cd0, + .md_reg[0] = 0x3cc4, + .md_reg[1] = 0x3cc8, + .bank_reg = 0x3ca0, + .mn[0] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .mn[1] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .s[0] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .s[1] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .p[0] = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .p[1] = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .mux_sel_bit = 0, + .freq_tbl = clk_tbl_gmac, + .clkr = { + .enable_reg = 0x3cc0, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core2_src", + .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + }, + }, +}; + +static struct clk_branch gmac_core2_clk = { + .halt_reg = 0x3c20, + .halt_bit = 5, + .hwcg_reg = 0x3cd4, + .hwcg_bit = 6, + .clkr = { + .enable_reg = 0x3cd4, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core2_clk", + .parent_names = (const char *[]){ + "gmac_core2_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_dyn_rcg gmac_core3_src = { + .ns_reg[0] = 0x3cec, + .ns_reg[1] = 0x3cf0, + .md_reg[0] = 0x3ce4, + .md_reg[1] = 0x3ce8, + .bank_reg = 0x3ce0, + .mn[0] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .mn[1] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .s[0] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .s[1] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .p[0] = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .p[1] = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .mux_sel_bit = 0, + .freq_tbl = clk_tbl_gmac, + .clkr = { + .enable_reg = 0x3ce0, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core3_src", + .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + }, + }, +}; + +static struct clk_branch gmac_core3_clk = { + .halt_reg = 0x3c20, + .halt_bit = 6, + .hwcg_reg = 0x3cf4, + .hwcg_bit = 6, + .clkr = { + .enable_reg = 0x3cf4, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core3_clk", + .parent_names = (const char *[]){ + "gmac_core3_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_dyn_rcg gmac_core4_src = { + .ns_reg[0] = 0x3d0c, + .ns_reg[1] = 0x3d10, + .md_reg[0] = 0x3d04, + .md_reg[1] = 0x3d08, + .bank_reg = 0x3d00, + .mn[0] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .mn[1] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .s[0] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .s[1] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .p[0] = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .p[1] = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .mux_sel_bit = 0, + .freq_tbl = clk_tbl_gmac, + .clkr = { + .enable_reg = 0x3d00, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core4_src", + .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + }, + }, +}; + +static struct clk_branch gmac_core4_clk = { + .halt_reg = 0x3c20, + .halt_bit = 7, + .hwcg_reg = 0x3d14, + .hwcg_bit = 6, + .clkr = { + .enable_reg = 0x3d14, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core4_clk", + .parent_names = (const char *[]){ + "gmac_core4_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl clk_tbl_nss_tcm[] = { + { 266000000, P_PLL0, 3, 0, 0 }, + { 400000000, P_PLL0, 2, 0, 0 }, + { } +}; + +static struct clk_dyn_rcg nss_tcm_src = { + .ns_reg[0] = 0x3dc4, + .ns_reg[1] = 0x3dc8, + .bank_reg = 0x3dc0, + .s[0] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .s[1] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .p[0] = { + .pre_div_shift = 3, + .pre_div_width = 4, + }, + .p[1] = { + .pre_div_shift = 3, + .pre_div_width = 4, + }, + .mux_sel_bit = 0, + .freq_tbl = clk_tbl_nss_tcm, + .clkr = { + .enable_reg = 0x3dc0, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "nss_tcm_src", + .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + }, + }, +}; + +static struct clk_branch nss_tcm_clk = { + .halt_reg = 0x3c20, + .halt_bit = 14, + .clkr = { + .enable_reg = 0x3dd0, + .enable_mask = BIT(6) | BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "nss_tcm_clk", + .parent_names = (const char *[]){ + "nss_tcm_src", + }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static const struct freq_tbl clk_tbl_nss[] = { + { 110000000, P_PLL18, 1, 1, 5 }, + { 275000000, P_PLL18, 2, 0, 0 }, + { 550000000, P_PLL18, 1, 0, 0 }, + { 733000000, P_PLL18, 1, 0, 0 }, + { } +}; + +static struct clk_dyn_rcg ubi32_core1_src_clk = { + .ns_reg[0] = 0x3d2c, + .ns_reg[1] = 0x3d30, + .md_reg[0] = 0x3d24, + .md_reg[1] = 0x3d28, + .bank_reg = 0x3d20, + .mn[0] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .mn[1] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .s[0] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .s[1] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .p[0] = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .p[1] = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .mux_sel_bit = 0, + .freq_tbl = clk_tbl_nss, + .clkr = { + .enable_reg = 0x3d20, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "ubi32_core1_src_clk", + .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + }, + }, +}; + +static struct clk_dyn_rcg ubi32_core2_src_clk = { + .ns_reg[0] = 0x3d4c, + .ns_reg[1] = 0x3d50, + .md_reg[0] = 0x3d44, + .md_reg[1] = 0x3d48, + .bank_reg = 0x3d40, + .mn[0] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .mn[1] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 5, + .n_val_shift = 16, + .m_val_shift = 16, + .width = 8, + }, + .s[0] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .s[1] = { + .src_sel_shift = 0, + .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map, + }, + .p[0] = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .p[1] = { + .pre_div_shift = 3, + .pre_div_width = 2, + }, + .mux_sel_bit = 0, + .freq_tbl = clk_tbl_nss, + .clkr = { + .enable_reg = 0x3d40, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "ubi32_core2_src_clk", + .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + }, + }, +}; + static struct clk_regmap *gcc_ipq806x_clks[] = { [PLL0] = &pll0.clkr, [PLL0_VOTE] = &pll0_vote, @@ -2211,6 +2728,7 @@ static struct clk_regmap *gcc_ipq806x_clks[] = { [PLL8_VOTE] = &pll8_vote, [PLL14] = &pll14.clkr, [PLL14_VOTE] = &pll14_vote, + [PLL18] = &pll18.clkr, [GSBI1_UART_SRC] = &gsbi1_uart_src.clkr, [GSBI1_UART_CLK] = &gsbi1_uart_clk.clkr, [GSBI2_UART_SRC] = &gsbi2_uart_src.clkr, @@ -2307,6 +2825,18 @@ static struct clk_regmap *gcc_ipq806x_clks[] = { [USB_FS1_SYSTEM_CLK] = &usb_fs1_sys_clk.clkr, [EBI2_CLK] = &ebi2_clk.clkr, [EBI2_AON_CLK] = &ebi2_aon_clk.clkr, + [GMAC_CORE1_CLK_SRC] = &gmac_core1_src.clkr, + [GMAC_CORE1_CLK] = &gmac_core1_clk.clkr, + [GMAC_CORE2_CLK_SRC] = &gmac_core2_src.clkr, + [GMAC_CORE2_CLK] = &gmac_core2_clk.clkr, + [GMAC_CORE3_CLK_SRC] = &gmac_core3_src.clkr, + [GMAC_CORE3_CLK] = &gmac_core3_clk.clkr, + [GMAC_CORE4_CLK_SRC] = &gmac_core4_src.clkr, + [GMAC_CORE4_CLK] = &gmac_core4_clk.clkr, + [UBI32_CORE1_CLK_SRC] = &ubi32_core1_src_clk.clkr, + [UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr, + [NSSTCM_CLK_SRC] = &nss_tcm_src.clkr, + [NSSTCM_CLK] = &nss_tcm_clk.clkr, }; static const struct qcom_reset_map gcc_ipq806x_resets[] = { @@ -2425,6 +2955,48 @@ static const struct qcom_reset_map gcc_ipq806x_resets[] = { [USB30_1_PHY_RESET] = { 0x3b58, 0 }, [NSSFB0_RESET] = { 0x3b60, 6 }, [NSSFB1_RESET] = { 0x3b60, 7 }, + [UBI32_CORE1_CLKRST_CLAMP_RESET] = { 0x3d3c, 3}, + [UBI32_CORE1_CLAMP_RESET] = { 0x3d3c, 2 }, + [UBI32_CORE1_AHB_RESET] = { 0x3d3c, 1 }, + [UBI32_CORE1_AXI_RESET] = { 0x3d3c, 0 }, + [UBI32_CORE2_CLKRST_CLAMP_RESET] = { 0x3d5c, 3 }, + [UBI32_CORE2_CLAMP_RESET] = { 0x3d5c, 2 }, + [UBI32_CORE2_AHB_RESET] = { 0x3d5c, 1 }, + [UBI32_CORE2_AXI_RESET] = { 0x3d5c, 0 }, + [GMAC_CORE1_RESET] = { 0x3cbc, 0 }, + [GMAC_CORE2_RESET] = { 0x3cdc, 0 }, + [GMAC_CORE3_RESET] = { 0x3cfc, 0 }, + [GMAC_CORE4_RESET] = { 0x3d1c, 0 }, + [GMAC_AHB_RESET] = { 0x3e24, 0 }, + [NSS_CH0_RST_RX_CLK_N_RESET] = { 0x3b60, 0 }, + [NSS_CH0_RST_TX_CLK_N_RESET] = { 0x3b60, 1 }, + [NSS_CH0_RST_RX_125M_N_RESET] = { 0x3b60, 2 }, + [NSS_CH0_HW_RST_RX_125M_N_RESET] = { 0x3b60, 3 }, + [NSS_CH0_RST_TX_125M_N_RESET] = { 0x3b60, 4 }, + [NSS_CH1_RST_RX_CLK_N_RESET] = { 0x3b60, 5 }, + [NSS_CH1_RST_TX_CLK_N_RESET] = { 0x3b60, 6 }, + [NSS_CH1_RST_RX_125M_N_RESET] = { 0x3b60, 7 }, + [NSS_CH1_HW_RST_RX_125M_N_RESET] = { 0x3b60, 8 }, + [NSS_CH1_RST_TX_125M_N_RESET] = { 0x3b60, 9 }, + [NSS_CH2_RST_RX_CLK_N_RESET] = { 0x3b60, 10 }, + [NSS_CH2_RST_TX_CLK_N_RESET] = { 0x3b60, 11 }, + [NSS_CH2_RST_RX_125M_N_RESET] = { 0x3b60, 12 }, + [NSS_CH2_HW_RST_RX_125M_N_RESET] = { 0x3b60, 13 }, + [NSS_CH2_RST_TX_125M_N_RESET] = { 0x3b60, 14 }, + [NSS_CH3_RST_RX_CLK_N_RESET] = { 0x3b60, 15 }, + [NSS_CH3_RST_TX_CLK_N_RESET] = { 0x3b60, 16 }, + [NSS_CH3_RST_RX_125M_N_RESET] = { 0x3b60, 17 }, + [NSS_CH3_HW_RST_RX_125M_N_RESET] = { 0x3b60, 18 }, + [NSS_CH3_RST_TX_125M_N_RESET] = { 0x3b60, 19 }, + [NSS_RST_RX_250M_125M_N_RESET] = { 0x3b60, 20 }, + [NSS_RST_TX_250M_125M_N_RESET] = { 0x3b60, 21 }, + [NSS_QSGMII_TXPI_RST_N_RESET] = { 0x3b60, 22 }, + [NSS_QSGMII_CDR_RST_N_RESET] = { 0x3b60, 23 }, + [NSS_SGMII2_CDR_RST_N_RESET] = { 0x3b60, 24 }, + [NSS_SGMII3_CDR_RST_N_RESET] = { 0x3b60, 25 }, + [NSS_CAL_PRBS_RST_N_RESET] = { 0x3b60, 26 }, + [NSS_LCKDT_RST_N_RESET] = { 0x3b60, 27 }, + [NSS_SRDS_N_RESET] = { 0x3b60, 28 }, }; static const struct regmap_config gcc_ipq806x_regmap_config = { @@ -2453,6 +3025,8 @@ static int gcc_ipq806x_probe(struct platform_device *pdev) { struct clk *clk; struct device *dev = &pdev->dev; + struct regmap *regmap; + int ret; /* Temporary until RPM clocks supported */ clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 25000000); @@ -2463,7 +3037,25 @@ static int gcc_ipq806x_probe(struct platform_device *pdev) if (IS_ERR(clk)) return PTR_ERR(clk); - return qcom_cc_probe(pdev, &gcc_ipq806x_desc); + ret = qcom_cc_probe(pdev, &gcc_ipq806x_desc); + if (ret) + return ret; + + regmap = dev_get_regmap(dev, NULL); + if (!regmap) + return -ENODEV; + + /* Setup PLL18 static bits */ + regmap_update_bits(regmap, 0x31a4, 0xffffffc0, 0x40000400); + regmap_write(regmap, 0x31b0, 0x3080); + + /* Set GMAC footswitch sleep/wakeup values */ + regmap_write(regmap, 0x3cb8, 8); + regmap_write(regmap, 0x3cd8, 8); + regmap_write(regmap, 0x3cf8, 8); + regmap_write(regmap, 0x3d18, 8); + + return 0; } static int gcc_ipq806x_remove(struct platform_device *pdev) diff --git a/include/dt-bindings/clock/qcom,gcc-ipq806x.h b/include/dt-bindings/clock/qcom,gcc-ipq806x.h index ebd63fd05649..dc4254b8cbbc 100644 --- a/include/dt-bindings/clock/qcom,gcc-ipq806x.h +++ b/include/dt-bindings/clock/qcom,gcc-ipq806x.h @@ -289,5 +289,7 @@ #define UBI32_CORE1_CLK 279 #define UBI32_CORE2_CLK 280 #define EBI2_AON_CLK 281 +#define NSSTCM_CLK_SRC 282 +#define NSSTCM_CLK 283 #endif diff --git a/include/dt-bindings/reset/qcom,gcc-ipq806x.h b/include/dt-bindings/reset/qcom,gcc-ipq806x.h index 0ad5ef930b5d..de9c8140931a 100644 --- a/include/dt-bindings/reset/qcom,gcc-ipq806x.h +++ b/include/dt-bindings/reset/qcom,gcc-ipq806x.h @@ -129,4 +129,47 @@ #define USB30_1_PHY_RESET 112 #define NSSFB0_RESET 113 #define NSSFB1_RESET 114 +#define UBI32_CORE1_CLKRST_CLAMP_RESET 115 +#define UBI32_CORE1_CLAMP_RESET 116 +#define UBI32_CORE1_AHB_RESET 117 +#define UBI32_CORE1_AXI_RESET 118 +#define UBI32_CORE2_CLKRST_CLAMP_RESET 119 +#define UBI32_CORE2_CLAMP_RESET 120 +#define UBI32_CORE2_AHB_RESET 121 +#define UBI32_CORE2_AXI_RESET 122 +#define GMAC_CORE1_RESET 123 +#define GMAC_CORE2_RESET 124 +#define GMAC_CORE3_RESET 125 +#define GMAC_CORE4_RESET 126 +#define GMAC_AHB_RESET 127 +#define NSS_CH0_RST_RX_CLK_N_RESET 128 +#define NSS_CH0_RST_TX_CLK_N_RESET 129 +#define NSS_CH0_RST_RX_125M_N_RESET 130 +#define NSS_CH0_HW_RST_RX_125M_N_RESET 131 +#define NSS_CH0_RST_TX_125M_N_RESET 132 +#define NSS_CH1_RST_RX_CLK_N_RESET 133 +#define NSS_CH1_RST_TX_CLK_N_RESET 134 +#define NSS_CH1_RST_RX_125M_N_RESET 135 +#define NSS_CH1_HW_RST_RX_125M_N_RESET 136 +#define NSS_CH1_RST_TX_125M_N_RESET 137 +#define NSS_CH2_RST_RX_CLK_N_RESET 138 +#define NSS_CH2_RST_TX_CLK_N_RESET 139 +#define NSS_CH2_RST_RX_125M_N_RESET 140 +#define NSS_CH2_HW_RST_RX_125M_N_RESET 141 +#define NSS_CH2_RST_TX_125M_N_RESET 142 +#define NSS_CH3_RST_RX_CLK_N_RESET 143 +#define NSS_CH3_RST_TX_CLK_N_RESET 144 +#define NSS_CH3_RST_RX_125M_N_RESET 145 +#define NSS_CH3_HW_RST_RX_125M_N_RESET 146 +#define NSS_CH3_RST_TX_125M_N_RESET 147 +#define NSS_RST_RX_250M_125M_N_RESET 148 +#define NSS_RST_TX_250M_125M_N_RESET 149 +#define NSS_QSGMII_TXPI_RST_N_RESET 150 +#define NSS_QSGMII_CDR_RST_N_RESET 151 +#define NSS_SGMII2_CDR_RST_N_RESET 152 +#define NSS_SGMII3_CDR_RST_N_RESET 153 +#define NSS_CAL_PRBS_RST_N_RESET 154 +#define NSS_LCKDT_RST_N_RESET 155 +#define NSS_SRDS_N_RESET 156 + #endif -- cgit v1.2.3 From 5790cf3c00c2f92aacba348e13f8a9a8f5dd96bd Mon Sep 17 00:00:00 2001 From: Mathieu Olivari Date: Wed, 27 May 2015 11:02:47 -0700 Subject: stmmac: add phy-handle support to the platform layer On stmmac driver, PHY specification in device-tree was done using the non-standard property "snps,phy-addr". Specifying a PHY on a different MDIO bus that the one within the stmmac controller doesn't seem to be possible when device-tree is used. This change adds support for the phy-handle property, as specified in Documentation/devicetree/bindings/net/ethernet.txt. Signed-off-by: Mathieu Olivari Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 28 ++++++++++++++-------- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 6 ++++- include/linux/stmmac.h | 1 + 3 files changed, 24 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index e4f273976071..31c64169f2ec 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -52,6 +52,7 @@ #include "stmmac_ptp.h" #include "stmmac.h" #include +#include #define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x) @@ -816,18 +817,25 @@ static int stmmac_init_phy(struct net_device *dev) priv->speed = 0; priv->oldduplex = -1; - if (priv->plat->phy_bus_name) - snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x", - priv->plat->phy_bus_name, priv->plat->bus_id); - else - snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", - priv->plat->bus_id); + if (priv->plat->phy_node) { + phydev = of_phy_connect(dev, priv->plat->phy_node, + &stmmac_adjust_link, 0, interface); + } else { + if (priv->plat->phy_bus_name) + snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x", + priv->plat->phy_bus_name, priv->plat->bus_id); + else + snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", + priv->plat->bus_id); - snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, - priv->plat->phy_addr); - pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id_fmt); + snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, + priv->plat->phy_addr); + pr_debug("stmmac_init_phy: trying to attach to %s\n", + phy_id_fmt); - phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, interface); + phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, + interface); + } if (IS_ERR(phydev)) { pr_err("%s: Could not attach to PHY\n", dev->name); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 1664c0186f5b..8d23155a1a7e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "stmmac.h" #include "stmmac_platform.h" @@ -144,13 +145,16 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, /* Default to phy auto-detection */ plat->phy_addr = -1; + /* If we find a phy-handle property, use it as the PHY */ + plat->phy_node = of_parse_phandle(np, "phy-handle", 0); + /* "snps,phy-addr" is not a standard property. Mark it as deprecated * and warn of its use. Remove this when phy node support is added. */ if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0) dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n"); - if (plat->phy_bus_name) + if (plat->phy_node || plat->phy_bus_name) plat->mdio_bus_data = NULL; else plat->mdio_bus_data = diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index 7f484a239f53..c735f5c91eea 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -99,6 +99,7 @@ struct plat_stmmacenet_data { int phy_addr; int interface; struct stmmac_mdio_bus_data *mdio_bus_data; + struct device_node *phy_node; struct stmmac_dma_cfg *dma_cfg; int clk_csr; int has_gmac; -- cgit v1.2.3 From 37e82c2f974b72c9ab49c787ef7b5bb1aec12768 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Wed, 27 May 2015 15:30:39 -0700 Subject: bpf: allow BPF programs access skb->skb_iif and skb->dev->ifindex fields classic BPF already exposes skb->dev->ifindex via SKF_AD_IFINDEX extension. Allow eBPF program to access it as well. Note that classic aborts execution of the program if 'skb->dev == NULL' (which is inconvenient for program writers), whereas eBPF returns zero in such case. Also expose the 'skb_iif' field, since programs triggered by redirected packet need to known the original interface index. Summary: __skb->ifindex -> skb->dev->ifindex __skb->ingress_ifindex -> skb->skb_iif Signed-off-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/uapi/linux/bpf.h | 2 ++ net/core/filter.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index f0a9af8b4dae..72f3080afa1e 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -236,6 +236,8 @@ struct __sk_buff { __u32 vlan_tci; __u32 vlan_proto; __u32 priority; + __u32 ingress_ifindex; + __u32 ifindex; }; #endif /* _UAPI__LINUX_BPF_H__ */ diff --git a/net/core/filter.c b/net/core/filter.c index 3adcca6f17a4..2c30d6632d66 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1499,6 +1499,24 @@ static u32 sk_filter_convert_ctx_access(int dst_reg, int src_reg, int ctx_off, offsetof(struct sk_buff, priority)); break; + case offsetof(struct __sk_buff, ingress_ifindex): + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, skb_iif) != 4); + + *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, + offsetof(struct sk_buff, skb_iif)); + break; + + case offsetof(struct __sk_buff, ifindex): + BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4); + + *insn++ = BPF_LDX_MEM(bytes_to_bpf_size(FIELD_SIZEOF(struct sk_buff, dev)), + dst_reg, src_reg, + offsetof(struct sk_buff, dev)); + *insn++ = BPF_JMP_IMM(BPF_JEQ, dst_reg, 0, 1); + *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, dst_reg, + offsetof(struct net_device, ifindex)); + break; + case offsetof(struct __sk_buff, mark): return convert_skb_access(SKF_AD_MARK, dst_reg, src_reg, insn); -- cgit v1.2.3 From f4fb874cf076f9eafdd15c0a88cd0f0397b95e43 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 27 May 2015 21:07:26 -0400 Subject: if_vlan: fix vlaue -> value typo Fixes "vlaue" for "value" in include/linux/if_vlan.h. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- include/linux/if_vlan.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index b9ab677c0c0a..a40d29846ac2 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -416,7 +416,7 @@ static inline void __vlan_hwaccel_put_tag(struct sk_buff *skb, /** * __vlan_get_tag - get the VLAN ID that is part of the payload * @skb: skbuff to query - * @vlan_tci: buffer to store vlaue + * @vlan_tci: buffer to store value * * Returns error if the skb is not of VLAN type */ @@ -435,7 +435,7 @@ static inline int __vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci) /** * __vlan_hwaccel_get_tag - get the VLAN ID that is in @skb->cb[] * @skb: skbuff to query - * @vlan_tci: buffer to store vlaue + * @vlan_tci: buffer to store value * * Returns error if @skb->vlan_tci is not set correctly */ @@ -456,7 +456,7 @@ static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb, /** * vlan_get_tag - get the VLAN ID from the skb * @skb: skbuff to query - * @vlan_tci: buffer to store vlaue + * @vlan_tci: buffer to store value * * Returns error if the skb is not VLAN tagged */ -- cgit v1.2.3 From d588cf8f618d7b316743a0bc99fede20f7a01bb7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 3 May 2015 08:50:52 +0200 Subject: target: Fix se_tpg_tfo->tf_subsys regression + remove tf_subsystem There is just one configfs subsystem in the target code, so we might as well add two helpers to reference / unreference it from the core code instead of passing pointers to it around. This fixes a regression introduced for v4.1-rc1 with commit 9ac8928e6, where configfs_depend_item() callers using se_tpg_tfo->tf_subsys would fail, because the assignment from the original target_core_subsystem[] is no longer happening at target_register_template() time. (Fix target_core_exit_configfs pointer dereference - Sagi) Signed-off-by: Christoph Hellwig Reported-by: Himanshu Madhani Signed-off-by: Nicholas Bellinger --- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 6 ++---- drivers/target/target_core_configfs.c | 30 ++++++++++++++---------------- drivers/target/target_core_internal.h | 3 --- drivers/target/target_core_pr.c | 32 +++++++------------------------- drivers/target/target_core_xcopy.c | 15 ++++++--------- drivers/vhost/scsi.c | 6 ++---- include/target/target_core_configfs.h | 2 -- include/target/target_core_fabric.h | 4 +++- 8 files changed, 34 insertions(+), 64 deletions(-) (limited to 'include') diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 68c2002e78bf..5c9e680aa375 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1020,8 +1020,7 @@ static void tcm_qla2xxx_depend_tpg(struct work_struct *work) struct se_portal_group *se_tpg = &base_tpg->se_tpg; struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha; - if (!configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys, - &se_tpg->tpg_group.cg_item)) { + if (!target_depend_item(&se_tpg->tpg_group.cg_item)) { atomic_set(&base_tpg->lport_tpg_enabled, 1); qlt_enable_vha(base_vha); } @@ -1037,8 +1036,7 @@ static void tcm_qla2xxx_undepend_tpg(struct work_struct *work) if (!qlt_stop_phase1(base_vha->vha_tgt.qla_tgt)) { atomic_set(&base_tpg->lport_tpg_enabled, 0); - configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys, - &se_tpg->tpg_group.cg_item); + target_undepend_item(&se_tpg->tpg_group.cg_item); } complete(&base_tpg->tpg_base_comp); } diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index ddaf76a4ac2a..1580077971f8 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -212,10 +212,6 @@ static struct config_group *target_core_register_fabric( pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:" " %s\n", tf->tf_group.cg_item.ci_name); - /* - * Setup tf_ops.tf_subsys pointer for usage with configfs_depend_item() - */ - tf->tf_ops.tf_subsys = tf->tf_subsys; tf->tf_fabric = &tf->tf_group.cg_item; pr_debug("Target_Core_ConfigFS: REGISTER -> Set tf->tf_fabric" " for %s\n", name); @@ -291,10 +287,17 @@ static struct configfs_subsystem target_core_fabrics = { }, }; -struct configfs_subsystem *target_core_subsystem[] = { - &target_core_fabrics, - NULL, -}; +int target_depend_item(struct config_item *item) +{ + return configfs_depend_item(&target_core_fabrics, item); +} +EXPORT_SYMBOL(target_depend_item); + +void target_undepend_item(struct config_item *item) +{ + return configfs_undepend_item(&target_core_fabrics, item); +} +EXPORT_SYMBOL(target_undepend_item); /*############################################################################## // Start functions called by external Target Fabrics Modules @@ -467,7 +470,6 @@ int target_register_template(const struct target_core_fabric_ops *fo) * struct target_fabric_configfs->tf_cit_tmpl */ tf->tf_module = fo->module; - tf->tf_subsys = target_core_subsystem[0]; snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", fo->name); tf->tf_ops = *fo; @@ -2870,7 +2872,7 @@ static int __init target_core_init_configfs(void) { struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL; struct config_group *lu_gp_cg = NULL; - struct configfs_subsystem *subsys; + struct configfs_subsystem *subsys = &target_core_fabrics; struct t10_alua_lu_gp *lu_gp; int ret; @@ -2878,7 +2880,6 @@ static int __init target_core_init_configfs(void) " Engine: %s on %s/%s on "UTS_RELEASE"\n", TARGET_CORE_VERSION, utsname()->sysname, utsname()->machine); - subsys = target_core_subsystem[0]; config_group_init(&subsys->su_group); mutex_init(&subsys->su_mutex); @@ -3008,13 +3009,10 @@ out_global: static void __exit target_core_exit_configfs(void) { - struct configfs_subsystem *subsys; struct config_group *hba_cg, *alua_cg, *lu_gp_cg; struct config_item *item; int i; - subsys = target_core_subsystem[0]; - lu_gp_cg = &alua_lu_gps_group; for (i = 0; lu_gp_cg->default_groups[i]; i++) { item = &lu_gp_cg->default_groups[i]->cg_item; @@ -3045,8 +3043,8 @@ static void __exit target_core_exit_configfs(void) * We expect subsys->su_group.default_groups to be released * by configfs subsystem provider logic.. */ - configfs_unregister_subsystem(subsys); - kfree(subsys->su_group.default_groups); + configfs_unregister_subsystem(&target_core_fabrics); + kfree(target_core_fabrics.su_group.default_groups); core_alua_free_lu_gp(default_lu_gp); default_lu_gp = NULL; diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 874a9bc988d8..68bd7f5d9f73 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -4,9 +4,6 @@ /* target_core_alua.c */ extern struct t10_alua_lu_gp *default_lu_gp; -/* target_core_configfs.c */ -extern struct configfs_subsystem *target_core_subsystem[]; - /* target_core_device.c */ extern struct mutex g_device_mutex; extern struct list_head g_device_list; diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index c1aa9655e96e..b7c81acf08d0 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -1367,41 +1367,26 @@ void core_scsi3_free_all_registrations( static int core_scsi3_tpg_depend_item(struct se_portal_group *tpg) { - return configfs_depend_item(tpg->se_tpg_tfo->tf_subsys, - &tpg->tpg_group.cg_item); + return target_depend_item(&tpg->tpg_group.cg_item); } static void core_scsi3_tpg_undepend_item(struct se_portal_group *tpg) { - configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys, - &tpg->tpg_group.cg_item); - + target_undepend_item(&tpg->tpg_group.cg_item); atomic_dec_mb(&tpg->tpg_pr_ref_count); } static int core_scsi3_nodeacl_depend_item(struct se_node_acl *nacl) { - struct se_portal_group *tpg = nacl->se_tpg; - if (nacl->dynamic_node_acl) return 0; - - return configfs_depend_item(tpg->se_tpg_tfo->tf_subsys, - &nacl->acl_group.cg_item); + return target_depend_item(&nacl->acl_group.cg_item); } static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl) { - struct se_portal_group *tpg = nacl->se_tpg; - - if (nacl->dynamic_node_acl) { - atomic_dec_mb(&nacl->acl_pr_ref_count); - return; - } - - configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys, - &nacl->acl_group.cg_item); - + if (!nacl->dynamic_node_acl) + target_undepend_item(&nacl->acl_group.cg_item); atomic_dec_mb(&nacl->acl_pr_ref_count); } @@ -1419,8 +1404,7 @@ static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve) nacl = lun_acl->se_lun_nacl; tpg = nacl->se_tpg; - return configfs_depend_item(tpg->se_tpg_tfo->tf_subsys, - &lun_acl->se_lun_group.cg_item); + return target_depend_item(&lun_acl->se_lun_group.cg_item); } static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) @@ -1438,9 +1422,7 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) nacl = lun_acl->se_lun_nacl; tpg = nacl->se_tpg; - configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys, - &lun_acl->se_lun_group.cg_item); - + target_undepend_item(&lun_acl->se_lun_group.cg_item); atomic_dec_mb(&se_deve->pr_ref_count); } diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index a600ff15dcfd..8fd680ac941b 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -58,7 +58,6 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op bool src) { struct se_device *se_dev; - struct configfs_subsystem *subsys = target_core_subsystem[0]; unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn; int rc; @@ -90,8 +89,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op " se_dev\n", xop->src_dev); } - rc = configfs_depend_item(subsys, - &se_dev->dev_group.cg_item); + rc = target_depend_item(&se_dev->dev_group.cg_item); if (rc != 0) { pr_err("configfs_depend_item attempt failed:" " %d for se_dev: %p\n", rc, se_dev); @@ -99,8 +97,8 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op return rc; } - pr_debug("Called configfs_depend_item for subsys: %p se_dev: %p" - " se_dev->se_dev_group: %p\n", subsys, se_dev, + pr_debug("Called configfs_depend_item for se_dev: %p" + " se_dev->se_dev_group: %p\n", se_dev, &se_dev->dev_group); mutex_unlock(&g_device_mutex); @@ -373,7 +371,6 @@ static int xcopy_pt_get_cmd_state(struct se_cmd *se_cmd) static void xcopy_pt_undepend_remotedev(struct xcopy_op *xop) { - struct configfs_subsystem *subsys = target_core_subsystem[0]; struct se_device *remote_dev; if (xop->op_origin == XCOL_SOURCE_RECV_OP) @@ -381,11 +378,11 @@ static void xcopy_pt_undepend_remotedev(struct xcopy_op *xop) else remote_dev = xop->src_dev; - pr_debug("Calling configfs_undepend_item for subsys: %p" + pr_debug("Calling configfs_undepend_item for" " remote_dev: %p remote_dev->dev_group: %p\n", - subsys, remote_dev, &remote_dev->dev_group.cg_item); + remote_dev, &remote_dev->dev_group.cg_item); - configfs_undepend_item(subsys, &remote_dev->dev_group.cg_item); + target_undepend_item(&remote_dev->dev_group.cg_item); } static void xcopy_pt_release_cmd(struct se_cmd *se_cmd) diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 5e19bb53b3a9..ea32b386797f 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1409,8 +1409,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, * dependency now. */ se_tpg = &tpg->se_tpg; - ret = configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys, - &se_tpg->tpg_group.cg_item); + ret = target_depend_item(&se_tpg->tpg_group.cg_item); if (ret) { pr_warn("configfs_depend_item() failed: %d\n", ret); kfree(vs_tpg); @@ -1513,8 +1512,7 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs, * to allow vhost-scsi WWPN se_tpg->tpg_group shutdown to occur. */ se_tpg = &tpg->se_tpg; - configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys, - &se_tpg->tpg_group.cg_item); + target_undepend_item(&se_tpg->tpg_group.cg_item); } if (match) { for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) { diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index 25bb04c4209e..b99c01170392 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h @@ -40,8 +40,6 @@ struct target_fabric_configfs { struct config_item *tf_fabric; /* Passed from fabric modules */ struct config_item_type *tf_fabric_cit; - /* Pointer to target core subsystem */ - struct configfs_subsystem *tf_subsys; /* Pointer to fabric's struct module */ struct module *tf_module; struct target_core_fabric_ops tf_ops; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 17c7f5ac7ea0..0f4dc3768587 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -4,7 +4,6 @@ struct target_core_fabric_ops { struct module *module; const char *name; - struct configfs_subsystem *tf_subsys; char *(*get_fabric_name)(void); u8 (*get_fabric_proto_ident)(struct se_portal_group *); char *(*tpg_get_wwn)(struct se_portal_group *); @@ -109,6 +108,9 @@ struct target_core_fabric_ops { int target_register_template(const struct target_core_fabric_ops *fo); void target_unregister_template(const struct target_core_fabric_ops *fo); +int target_depend_item(struct config_item *item); +void target_undepend_item(struct config_item *item); + struct se_session *transport_init_session(enum target_prot_op); int transport_alloc_session_tags(struct se_session *, unsigned int, unsigned int); -- cgit v1.2.3 From 64ffaa2159b752e6c263dc57eaaaed7367d37493 Mon Sep 17 00:00:00 2001 From: Amir Vadai Date: Thu, 28 May 2015 22:28:38 +0300 Subject: net/mlx5_core,mlx5_ib: Do not use vmap() on coherent memory As David Daney pointed in mlx4_core driver [1], mlx5_core is also misusing the DMA-API. This patch is removing the code that vmap() memory allocated by dma_alloc_coherent(). After this patch, users of this drivers might fail allocating resources on memory fragmeneted systems. This will be fixed later on. [1] - https://patchwork.ozlabs.org/patch/458531/ CC: David Daney Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/cq.c | 3 +- drivers/infiniband/hw/mlx5/qp.c | 2 +- drivers/infiniband/hw/mlx5/srq.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/alloc.c | 96 +++++-------------------- drivers/net/ethernet/mellanox/mlx5/core/eq.c | 3 +- include/linux/mlx5/driver.h | 9 +-- 6 files changed, 22 insertions(+), 93 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 2ee6b1051975..4e88b18cf62e 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -590,8 +590,7 @@ static int alloc_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf, { int err; - err = mlx5_buf_alloc(dev->mdev, nent * cqe_size, - PAGE_SIZE * 2, &buf->buf); + err = mlx5_buf_alloc(dev->mdev, nent * cqe_size, &buf->buf); if (err) return err; diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index d35f62d4f4c5..426eb88dfa49 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -768,7 +768,7 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev, qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift; qp->buf_size = err + (qp->rq.wqe_cnt << qp->rq.wqe_shift); - err = mlx5_buf_alloc(dev->mdev, qp->buf_size, PAGE_SIZE * 2, &qp->buf); + err = mlx5_buf_alloc(dev->mdev, qp->buf_size, &qp->buf); if (err) { mlx5_ib_dbg(dev, "err %d\n", err); goto err_uuar; diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 02d77a29764d..4242e1ded868 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -165,7 +165,7 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq, return err; } - if (mlx5_buf_alloc(dev->mdev, buf_size, PAGE_SIZE * 2, &srq->buf)) { + if (mlx5_buf_alloc(dev->mdev, buf_size, &srq->buf)) { mlx5_ib_dbg(dev, "buf alloc failed\n"); err = -ENOMEM; goto err_db; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c index ac0f7bf4be95..0715b497511f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c @@ -42,95 +42,36 @@ #include "mlx5_core.h" /* Handling for queue buffers -- we allocate a bunch of memory and - * register it in a memory region at HCA virtual address 0. If the - * requested size is > max_direct, we split the allocation into - * multiple pages, so we don't require too much contiguous memory. + * register it in a memory region at HCA virtual address 0. */ -int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, int max_direct, - struct mlx5_buf *buf) +int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf) { dma_addr_t t; buf->size = size; - if (size <= max_direct) { - buf->nbufs = 1; - buf->npages = 1; - buf->page_shift = (u8)get_order(size) + PAGE_SHIFT; - buf->direct.buf = dma_zalloc_coherent(&dev->pdev->dev, - size, &t, GFP_KERNEL); - if (!buf->direct.buf) - return -ENOMEM; - - buf->direct.map = t; - - while (t & ((1 << buf->page_shift) - 1)) { - --buf->page_shift; - buf->npages *= 2; - } - } else { - int i; - - buf->direct.buf = NULL; - buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE; - buf->npages = buf->nbufs; - buf->page_shift = PAGE_SHIFT; - buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list), - GFP_KERNEL); - if (!buf->page_list) - return -ENOMEM; - - for (i = 0; i < buf->nbufs; i++) { - buf->page_list[i].buf = - dma_zalloc_coherent(&dev->pdev->dev, PAGE_SIZE, - &t, GFP_KERNEL); - if (!buf->page_list[i].buf) - goto err_free; - - buf->page_list[i].map = t; - } - - if (BITS_PER_LONG == 64) { - struct page **pages; - pages = kmalloc(sizeof(*pages) * buf->nbufs, GFP_KERNEL); - if (!pages) - goto err_free; - for (i = 0; i < buf->nbufs; i++) - pages[i] = virt_to_page(buf->page_list[i].buf); - buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL); - kfree(pages); - if (!buf->direct.buf) - goto err_free; - } - } + buf->npages = 1; + buf->page_shift = (u8)get_order(size) + PAGE_SHIFT; + buf->direct.buf = dma_zalloc_coherent(&dev->pdev->dev, + size, &t, GFP_KERNEL); + if (!buf->direct.buf) + return -ENOMEM; - return 0; + buf->direct.map = t; -err_free: - mlx5_buf_free(dev, buf); + while (t & ((1 << buf->page_shift) - 1)) { + --buf->page_shift; + buf->npages *= 2; + } - return -ENOMEM; + return 0; } EXPORT_SYMBOL_GPL(mlx5_buf_alloc); void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf) { - int i; - - if (buf->nbufs == 1) - dma_free_coherent(&dev->pdev->dev, buf->size, buf->direct.buf, - buf->direct.map); - else { - if (BITS_PER_LONG == 64) - vunmap(buf->direct.buf); - - for (i = 0; i < buf->nbufs; i++) - if (buf->page_list[i].buf) - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, - buf->page_list[i].buf, - buf->page_list[i].map); - kfree(buf->page_list); - } + dma_free_coherent(&dev->pdev->dev, buf->size, buf->direct.buf, + buf->direct.map); } EXPORT_SYMBOL_GPL(mlx5_buf_free); @@ -230,10 +171,7 @@ void mlx5_fill_page_array(struct mlx5_buf *buf, __be64 *pas) int i; for (i = 0; i < buf->npages; i++) { - if (buf->nbufs == 1) - addr = buf->direct.map + (i << buf->page_shift); - else - addr = buf->page_list[i].map; + addr = buf->direct.map + (i << buf->page_shift); pas[i] = cpu_to_be64(addr); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 58800e4f3958..3f511bd84489 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -346,8 +346,7 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx, int inlen; eq->nent = roundup_pow_of_two(nent + MLX5_NUM_SPARE_EQE); - err = mlx5_buf_alloc(dev, eq->nent * MLX5_EQE_SIZE, 2 * PAGE_SIZE, - &eq->buf); + err = mlx5_buf_alloc(dev, eq->nent * MLX5_EQE_SIZE, &eq->buf); if (err) return err; diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 9a90e7523dc2..c4cf25ffcc16 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -334,8 +334,6 @@ struct mlx5_buf_list { struct mlx5_buf { struct mlx5_buf_list direct; - struct mlx5_buf_list *page_list; - int nbufs; int npages; int size; u8 page_shift; @@ -586,11 +584,7 @@ struct mlx5_pas { static inline void *mlx5_buf_offset(struct mlx5_buf *buf, int offset) { - if (likely(BITS_PER_LONG == 64 || buf->nbufs == 1)) return buf->direct.buf + offset; - else - return buf->page_list[offset >> PAGE_SHIFT].buf + - (offset & (PAGE_SIZE - 1)); } extern struct workqueue_struct *mlx5_core_wq; @@ -669,8 +663,7 @@ void mlx5_health_cleanup(void); void __init mlx5_health_init(void); void mlx5_start_health_poll(struct mlx5_core_dev *dev); void mlx5_stop_health_poll(struct mlx5_core_dev *dev); -int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, int max_direct, - struct mlx5_buf *buf); +int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf); void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf); struct mlx5_cmd_mailbox *mlx5_alloc_cmd_mailbox_chain(struct mlx5_core_dev *dev, gfp_t flags, int npages); -- cgit v1.2.3 From db058a186f98b057c19c42f7b10d9a96fd3b5d59 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 28 May 2015 22:28:39 +0300 Subject: net/mlx5_core: Set irq affinity hints Preparation for upcoming ethernet driver. - Move msix array from eq_table struct to priv since its not related to eq_table - Intorduce irq_info struct to hold all irq information - Move name from mlx5_eq to irq_info struct since it is irq property. - Set IRQ affinity hints Signed-off-by: Achiad Shochat Signed-off-by: Rana Shahout Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/eq.c | 16 ++-- drivers/net/ethernet/mellanox/mlx5/core/main.c | 111 ++++++++++++++++++++++--- include/linux/mlx5/driver.h | 11 ++- 3 files changed, 117 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 3f511bd84489..516efc25fc4f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -339,7 +339,7 @@ static void init_eq_buf(struct mlx5_eq *eq) int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx, int nent, u64 mask, const char *name, struct mlx5_uar *uar) { - struct mlx5_eq_table *table = &dev->priv.eq_table; + struct mlx5_priv *priv = &dev->priv; struct mlx5_create_eq_mbox_in *in; struct mlx5_create_eq_mbox_out out; int err; @@ -377,14 +377,15 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx, goto err_in; } - snprintf(eq->name, MLX5_MAX_EQ_NAME, "%s@pci:%s", + snprintf(priv->irq_info[vecidx].name, MLX5_MAX_IRQ_NAME, "%s@pci:%s", name, pci_name(dev->pdev)); + eq->eqn = out.eq_number; eq->irqn = vecidx; eq->dev = dev; eq->doorbell = uar->map + MLX5_EQ_DOORBEL_OFFSET; - err = request_irq(table->msix_arr[vecidx].vector, mlx5_msix_handler, 0, - eq->name, eq); + err = request_irq(priv->msix_arr[vecidx].vector, mlx5_msix_handler, 0, + priv->irq_info[vecidx].name, eq); if (err) goto err_eq; @@ -400,7 +401,7 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx, return 0; err_irq: - free_irq(table->msix_arr[vecidx].vector, eq); + free_irq(priv->msix_arr[vecidx].vector, eq); err_eq: mlx5_cmd_destroy_eq(dev, eq->eqn); @@ -416,16 +417,15 @@ EXPORT_SYMBOL_GPL(mlx5_create_map_eq); int mlx5_destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq) { - struct mlx5_eq_table *table = &dev->priv.eq_table; int err; mlx5_debug_eq_remove(dev, eq); - free_irq(table->msix_arr[eq->irqn].vector, eq); + free_irq(dev->priv.msix_arr[eq->irqn].vector, eq); err = mlx5_cmd_destroy_eq(dev, eq->eqn); if (err) mlx5_core_warn(dev, "failed to destroy a previously created eq: eqn %d\n", eq->eqn); - synchronize_irq(table->msix_arr[eq->irqn].vector); + synchronize_irq(dev->priv.msix_arr[eq->irqn].vector); mlx5_buf_free(dev, &eq->buf); return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 28425e5ea91f..55085b01b4ce 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -208,7 +209,8 @@ static void release_bar(struct pci_dev *pdev) static int mlx5_enable_msix(struct mlx5_core_dev *dev) { - struct mlx5_eq_table *table = &dev->priv.eq_table; + struct mlx5_priv *priv = &dev->priv; + struct mlx5_eq_table *table = &priv->eq_table; int num_eqs = 1 << dev->caps.gen.log_max_eq; int nvec; int i; @@ -218,14 +220,16 @@ static int mlx5_enable_msix(struct mlx5_core_dev *dev) if (nvec <= MLX5_EQ_VEC_COMP_BASE) return -ENOMEM; - table->msix_arr = kzalloc(nvec * sizeof(*table->msix_arr), GFP_KERNEL); - if (!table->msix_arr) - return -ENOMEM; + priv->msix_arr = kcalloc(nvec, sizeof(*priv->msix_arr), GFP_KERNEL); + + priv->irq_info = kcalloc(nvec, sizeof(*priv->irq_info), GFP_KERNEL); + if (!priv->msix_arr || !priv->irq_info) + goto err_free_msix; for (i = 0; i < nvec; i++) - table->msix_arr[i].entry = i; + priv->msix_arr[i].entry = i; - nvec = pci_enable_msix_range(dev->pdev, table->msix_arr, + nvec = pci_enable_msix_range(dev->pdev, priv->msix_arr, MLX5_EQ_VEC_COMP_BASE + 1, nvec); if (nvec < 0) return nvec; @@ -233,14 +237,20 @@ static int mlx5_enable_msix(struct mlx5_core_dev *dev) table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE; return 0; + +err_free_msix: + kfree(priv->irq_info); + kfree(priv->msix_arr); + return -ENOMEM; } static void mlx5_disable_msix(struct mlx5_core_dev *dev) { - struct mlx5_eq_table *table = &dev->priv.eq_table; + struct mlx5_priv *priv = &dev->priv; pci_disable_msix(dev->pdev); - kfree(table->msix_arr); + kfree(priv->irq_info); + kfree(priv->msix_arr); } struct mlx5_reg_host_endianess { @@ -507,6 +517,77 @@ static int mlx5_core_disable_hca(struct mlx5_core_dev *dev) return 0; } +static int mlx5_irq_set_affinity_hint(struct mlx5_core_dev *mdev, int i) +{ + struct mlx5_priv *priv = &mdev->priv; + struct msix_entry *msix = priv->msix_arr; + int irq = msix[i + MLX5_EQ_VEC_COMP_BASE].vector; + int numa_node = dev_to_node(&mdev->pdev->dev); + int err; + + if (!zalloc_cpumask_var(&priv->irq_info[i].mask, GFP_KERNEL)) { + mlx5_core_warn(mdev, "zalloc_cpumask_var failed"); + return -ENOMEM; + } + + err = cpumask_set_cpu_local_first(i, numa_node, priv->irq_info[i].mask); + if (err) { + mlx5_core_warn(mdev, "cpumask_set_cpu_local_first failed"); + goto err_clear_mask; + } + + err = irq_set_affinity_hint(irq, priv->irq_info[i].mask); + if (err) { + mlx5_core_warn(mdev, "irq_set_affinity_hint failed,irq 0x%.4x", + irq); + goto err_clear_mask; + } + + return 0; + +err_clear_mask: + free_cpumask_var(priv->irq_info[i].mask); + return err; +} + +static void mlx5_irq_clear_affinity_hint(struct mlx5_core_dev *mdev, int i) +{ + struct mlx5_priv *priv = &mdev->priv; + struct msix_entry *msix = priv->msix_arr; + int irq = msix[i + MLX5_EQ_VEC_COMP_BASE].vector; + + irq_set_affinity_hint(irq, NULL); + free_cpumask_var(priv->irq_info[i].mask); +} + +static int mlx5_irq_set_affinity_hints(struct mlx5_core_dev *mdev) +{ + int err; + int i; + + for (i = 0; i < mdev->priv.eq_table.num_comp_vectors; i++) { + err = mlx5_irq_set_affinity_hint(mdev, i); + if (err) + goto err_out; + } + + return 0; + +err_out: + for (i--; i >= 0; i--) + mlx5_irq_clear_affinity_hint(mdev, i); + + return err; +} + +static void mlx5_irq_clear_affinity_hints(struct mlx5_core_dev *mdev) +{ + int i; + + for (i = 0; i < mdev->priv.eq_table.num_comp_vectors; i++) + mlx5_irq_clear_affinity_hint(mdev, i); +} + int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn, int *irqn) { struct mlx5_eq_table *table = &dev->priv.eq_table; @@ -549,7 +630,7 @@ static void free_comp_eqs(struct mlx5_core_dev *dev) static int alloc_comp_eqs(struct mlx5_core_dev *dev) { struct mlx5_eq_table *table = &dev->priv.eq_table; - char name[MLX5_MAX_EQ_NAME]; + char name[MLX5_MAX_IRQ_NAME]; struct mlx5_eq *eq; int ncomp_vec; int nent; @@ -566,7 +647,7 @@ static int alloc_comp_eqs(struct mlx5_core_dev *dev) goto clean; } - snprintf(name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i); + snprintf(name, MLX5_MAX_IRQ_NAME, "mlx5_comp%d", i); err = mlx5_create_map_eq(dev, eq, i + MLX5_EQ_VEC_COMP_BASE, nent, 0, name, &dev->priv.uuari.uars[0]); @@ -730,6 +811,12 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) goto err_stop_eqs; } + err = mlx5_irq_set_affinity_hints(dev); + if (err) { + dev_err(&pdev->dev, "Failed to alloc affinity hint cpumask\n"); + goto err_free_comp_eqs; + } + MLX5_INIT_DOORBELL_LOCK(&priv->cq_uar_lock); mlx5_init_cq_table(dev); @@ -739,6 +826,9 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) return 0; +err_free_comp_eqs: + free_comp_eqs(dev); + err_stop_eqs: mlx5_stop_eqs(dev); @@ -793,6 +883,7 @@ static void mlx5_dev_cleanup(struct mlx5_core_dev *dev) mlx5_cleanup_srq_table(dev); mlx5_cleanup_qp_table(dev); mlx5_cleanup_cq_table(dev); + mlx5_irq_clear_affinity_hints(dev); free_comp_eqs(dev); mlx5_stop_eqs(dev); mlx5_free_uuars(dev, &priv->uuari); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index c4cf25ffcc16..9e8979502826 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -85,7 +85,7 @@ enum { }; enum { - MLX5_MAX_EQ_NAME = 32 + MLX5_MAX_IRQ_NAME = 32 }; enum { @@ -349,7 +349,6 @@ struct mlx5_eq { u8 eqn; int nent; u64 mask; - char name[MLX5_MAX_EQ_NAME]; struct list_head list; int index; struct mlx5_rsc_debug *dbg; @@ -412,7 +411,6 @@ struct mlx5_eq_table { struct mlx5_eq pages_eq; struct mlx5_eq async_eq; struct mlx5_eq cmd_eq; - struct msix_entry *msix_arr; int num_comp_vectors; /* protect EQs list */ @@ -465,9 +463,16 @@ struct mlx5_mr_table { struct radix_tree_root tree; }; +struct mlx5_irq_info { + cpumask_var_t mask; + char name[MLX5_MAX_IRQ_NAME]; +}; + struct mlx5_priv { char name[MLX5_MAX_NAME_LEN]; struct mlx5_eq_table eq_table; + struct msix_entry *msix_arr; + struct mlx5_irq_info *irq_info; struct mlx5_uuar_info uuari; MLX5_DECLARE_DOORBELL_LOCK(cq_uar_lock); -- cgit v1.2.3 From e281682bf29438848daac11627216bceb1507b71 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 28 May 2015 22:28:40 +0300 Subject: net/mlx5_core: HW data structs/types definitions cleanup mlx5_ifc.h was heavily modified here since it is now generated by a script from the device specification (PRM rev 0.25). This specification is backward compatible to existing hardware. Some structures/fields were added here in order to enable the Ethernet functionality of the driver. Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 17 +- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/main.c | 7 +- drivers/net/ethernet/mellanox/mlx5/core/mcg.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/uar.c | 37 + include/linux/mlx5/device.h | 113 +- include/linux/mlx5/driver.h | 4 +- include/linux/mlx5/mlx5_ifc.h | 6608 +++++++++++++++++++++++- include/linux/mlx5/qp.h | 25 + 9 files changed, 6705 insertions(+), 110 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index e3273faf4568..2f22cd2de2b0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -390,8 +390,17 @@ const char *mlx5_command_str(int command) case MLX5_CMD_OP_ARM_RQ: return "ARM_RQ"; - case MLX5_CMD_OP_RESIZE_SRQ: - return "RESIZE_SRQ"; + case MLX5_CMD_OP_CREATE_XRC_SRQ: + return "CREATE_XRC_SRQ"; + + case MLX5_CMD_OP_DESTROY_XRC_SRQ: + return "DESTROY_XRC_SRQ"; + + case MLX5_CMD_OP_QUERY_XRC_SRQ: + return "QUERY_XRC_SRQ"; + + case MLX5_CMD_OP_ARM_XRC_SRQ: + return "ARM_XRC_SRQ"; case MLX5_CMD_OP_ALLOC_PD: return "ALLOC_PD"; @@ -408,8 +417,8 @@ const char *mlx5_command_str(int command) case MLX5_CMD_OP_ATTACH_TO_MCG: return "ATTACH_TO_MCG"; - case MLX5_CMD_OP_DETACH_FROM_MCG: - return "DETACH_FROM_MCG"; + case MLX5_CMD_OP_DETTACH_FROM_MCG: + return "DETTACH_FROM_MCG"; case MLX5_CMD_OP_ALLOC_XRCD: return "ALLOC_XRCD"; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 4b4cda3bcc5f..ef9b7695decd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -95,7 +95,7 @@ int mlx5_query_odp_caps(struct mlx5_core_dev *dev, struct mlx5_odp_caps *caps) goto out; } - memcpy(caps, MLX5_ADDR_OF(query_hca_cap_out, out, capability_struct), + memcpy(caps, MLX5_ADDR_OF(query_hca_cap_out, out, capability), sizeof(*caps)); mlx5_core_dbg(dev, "on-demand paging capabilities:\nrc: %08x\nuc: %08x\nud: %08x\n", diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 55085b01b4ce..a652cb93ceaa 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -319,8 +319,7 @@ static void fw2drv_caps(struct mlx5_caps *caps, void *out) gen->max_srq_wqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_srq_sz); gen->max_wqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_qp_sz); gen->log_max_qp = MLX5_GET_PR(cmd_hca_cap, out, log_max_qp); - gen->log_max_strq = MLX5_GET_PR(cmd_hca_cap, out, log_max_strq_sz); - gen->log_max_srq = MLX5_GET_PR(cmd_hca_cap, out, log_max_srqs); + gen->log_max_srq = MLX5_GET_PR(cmd_hca_cap, out, log_max_srq); gen->max_cqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_cq_sz); gen->log_max_cq = MLX5_GET_PR(cmd_hca_cap, out, log_max_cq); gen->max_eqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_eq_sz); @@ -391,7 +390,7 @@ int mlx5_core_get_caps(struct mlx5_core_dev *dev, struct mlx5_caps *caps, goto query_ex; } mlx5_core_dbg(dev, "%s\n", caps_opmod_str(opmod)); - fw2drv_caps(caps, MLX5_ADDR_OF(query_hca_cap_out, out, capability_struct)); + fw2drv_caps(caps, MLX5_ADDR_OF(query_hca_cap_out, out, capability)); query_ex: kfree(out); @@ -453,7 +452,7 @@ static int handle_hca_cap(struct mlx5_core_dev *dev) /* disable checksum */ cur_caps->gen.flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM; - copy_rw_fields(MLX5_ADDR_OF(set_hca_cap_in, set_ctx, hca_capability_struct), + copy_rw_fields(MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability), cur_caps); err = set_caps(dev, set_ctx, set_sz); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mcg.c b/drivers/net/ethernet/mellanox/mlx5/core/mcg.c index d79fd85d1dd5..d5a0c2d61a18 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/mcg.c @@ -91,7 +91,7 @@ int mlx5_core_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn) memset(&in, 0, sizeof(in)); memset(&out, 0, sizeof(out)); - in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DETACH_FROM_MCG); + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DETTACH_FROM_MCG); memcpy(in.gid, mgid, sizeof(*mgid)); in.qpn = cpu_to_be32(qpn); err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/uar.c b/drivers/net/ethernet/mellanox/mlx5/core/uar.c index 5a89bb1d678a..ba58f6d7c761 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/uar.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/uar.c @@ -223,3 +223,40 @@ int mlx5_free_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari) return 0; } + +int mlx5_alloc_map_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar) +{ + phys_addr_t pfn; + phys_addr_t uar_bar_start; + int err; + + err = mlx5_cmd_alloc_uar(mdev, &uar->index); + if (err) { + mlx5_core_warn(mdev, "mlx5_cmd_alloc_uar() failed, %d\n", err); + return err; + } + + uar_bar_start = pci_resource_start(mdev->pdev, 0); + pfn = (uar_bar_start >> PAGE_SHIFT) + uar->index; + uar->map = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE); + if (!uar->map) { + mlx5_core_warn(mdev, "ioremap() failed, %d\n", err); + err = -ENOMEM; + goto err_free_uar; + } + + return 0; + +err_free_uar: + mlx5_cmd_free_uar(mdev, uar->index); + + return err; +} +EXPORT_SYMBOL(mlx5_alloc_map_uar); + +void mlx5_unmap_free_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar) +{ + iounmap(uar->map); + mlx5_cmd_free_uar(mdev, uar->index); +} +EXPORT_SYMBOL(mlx5_unmap_free_uar); diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index abf65c790421..feebed7b392b 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -35,6 +35,7 @@ #include #include +#include #if defined(__LITTLE_ENDIAN) #define MLX5_SET_HOST_ENDIANNESS 0 @@ -70,6 +71,14 @@ << __mlx5_dw_bit_off(typ, fld))); \ } while (0) +#define MLX5_SET_TO_ONES(typ, p, fld) do { \ + BUILD_BUG_ON(__mlx5_st_sz_bits(typ) % 32); \ + *((__be32 *)(p) + __mlx5_dw_off(typ, fld)) = \ + cpu_to_be32((be32_to_cpu(*((__be32 *)(p) + __mlx5_dw_off(typ, fld))) & \ + (~__mlx5_dw_mask(typ, fld))) | ((__mlx5_mask(typ, fld)) \ + << __mlx5_dw_bit_off(typ, fld))); \ +} while (0) + #define MLX5_GET(typ, p, fld) ((be32_to_cpu(*((__be32 *)(p) +\ __mlx5_dw_off(typ, fld))) >> __mlx5_dw_bit_off(typ, fld)) & \ __mlx5_mask(typ, fld)) @@ -264,6 +273,7 @@ enum { MLX5_OPCODE_RDMA_WRITE_IMM = 0x09, MLX5_OPCODE_SEND = 0x0a, MLX5_OPCODE_SEND_IMM = 0x0b, + MLX5_OPCODE_LSO = 0x0e, MLX5_OPCODE_RDMA_READ = 0x10, MLX5_OPCODE_ATOMIC_CS = 0x11, MLX5_OPCODE_ATOMIC_FA = 0x12, @@ -541,6 +551,10 @@ struct mlx5_cmd_prot_block { u8 sig; }; +enum { + MLX5_CQE_SYND_FLUSHED_IN_ERROR = 5, +}; + struct mlx5_err_cqe { u8 rsvd0[32]; __be32 srqn; @@ -554,13 +568,22 @@ struct mlx5_err_cqe { }; struct mlx5_cqe64 { - u8 rsvd0[17]; + u8 rsvd0[4]; + u8 lro_tcppsh_abort_dupack; + u8 lro_min_ttl; + __be16 lro_tcp_win; + __be32 lro_ack_seq_num; + __be32 rss_hash_result; + u8 rss_hash_type; u8 ml_path; - u8 rsvd20[4]; + u8 rsvd20[2]; + __be16 check_sum; __be16 slid; __be32 flags_rqpn; - u8 rsvd28[4]; - __be32 srqn; + u8 hds_ip_ext; + u8 l4_hdr_type_etc; + __be16 vlan_info; + __be32 srqn; /* [31:24]: lro_num_seg, [23:0]: srqn */ __be32 imm_inval_pkey; u8 rsvd40[4]; __be32 byte_cnt; @@ -571,6 +594,40 @@ struct mlx5_cqe64 { u8 op_own; }; +static inline int get_cqe_lro_tcppsh(struct mlx5_cqe64 *cqe) +{ + return (cqe->lro_tcppsh_abort_dupack >> 6) & 1; +} + +static inline u8 get_cqe_l4_hdr_type(struct mlx5_cqe64 *cqe) +{ + return (cqe->l4_hdr_type_etc >> 4) & 0x7; +} + +static inline int cqe_has_vlan(struct mlx5_cqe64 *cqe) +{ + return !!(cqe->l4_hdr_type_etc & 0x1); +} + +enum { + CQE_L4_HDR_TYPE_NONE = 0x0, + CQE_L4_HDR_TYPE_TCP_NO_ACK = 0x1, + CQE_L4_HDR_TYPE_UDP = 0x2, + CQE_L4_HDR_TYPE_TCP_ACK_NO_DATA = 0x3, + CQE_L4_HDR_TYPE_TCP_ACK_AND_DATA = 0x4, +}; + +enum { + CQE_RSS_HTYPE_IP = 0x3 << 6, + CQE_RSS_HTYPE_L4 = 0x3 << 2, +}; + +enum { + CQE_L2_OK = 1 << 0, + CQE_L3_OK = 1 << 1, + CQE_L4_OK = 1 << 2, +}; + struct mlx5_sig_err_cqe { u8 rsvd0[16]; __be32 expected_trans_sig; @@ -996,4 +1053,52 @@ struct mlx5_destroy_psv_out { u8 rsvd[8]; }; +#define MLX5_CMD_OP_MAX 0x920 + +enum { + VPORT_STATE_DOWN = 0x0, + VPORT_STATE_UP = 0x1, +}; + +enum { + MLX5_L3_PROT_TYPE_IPV4 = 0, + MLX5_L3_PROT_TYPE_IPV6 = 1, +}; + +enum { + MLX5_L4_PROT_TYPE_TCP = 0, + MLX5_L4_PROT_TYPE_UDP = 1, +}; + +enum { + MLX5_HASH_FIELD_SEL_SRC_IP = 1 << 0, + MLX5_HASH_FIELD_SEL_DST_IP = 1 << 1, + MLX5_HASH_FIELD_SEL_L4_SPORT = 1 << 2, + MLX5_HASH_FIELD_SEL_L4_DPORT = 1 << 3, + MLX5_HASH_FIELD_SEL_IPSEC_SPI = 1 << 4, +}; + +enum { + MLX5_MATCH_OUTER_HEADERS = 1 << 0, + MLX5_MATCH_MISC_PARAMETERS = 1 << 1, + MLX5_MATCH_INNER_HEADERS = 1 << 2, + +}; + +enum { + MLX5_FLOW_TABLE_TYPE_NIC_RCV = 0, + MLX5_FLOW_TABLE_TYPE_ESWITCH = 4, +}; + +enum { + MLX5_FLOW_CONTEXT_DEST_TYPE_VPORT = 0, + MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE = 1, + MLX5_FLOW_CONTEXT_DEST_TYPE_TIR = 2, +}; + +enum { + MLX5_RQC_RQ_TYPE_MEMORY_RQ_INLINE = 0x0, + MLX5_RQC_RQ_TYPE_MEMORY_RQ_RPM = 0x1, +}; + #endif /* MLX5_DEVICE_H */ diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 9e8979502826..3fd4fdc1ba16 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -44,7 +44,6 @@ #include #include -#include enum { MLX5_BOARD_ID_LEN = 64, @@ -278,7 +277,6 @@ struct mlx5_general_caps { u8 log_max_mkey; u8 log_max_pd; u8 log_max_srq; - u8 log_max_strq; u8 log_max_mrw_sz; u8 log_max_bsf_list_size; u8 log_max_klm_list_size; @@ -664,6 +662,8 @@ int mlx5_cmd_alloc_uar(struct mlx5_core_dev *dev, u32 *uarn); int mlx5_cmd_free_uar(struct mlx5_core_dev *dev, u32 uarn); int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari); int mlx5_free_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari); +int mlx5_alloc_map_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar); +void mlx5_unmap_free_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar); void mlx5_health_cleanup(void); void __init mlx5_health_init(void); void mlx5_start_health_poll(struct mlx5_core_dev *dev); diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index cb3ad17edd1f..b27e9f6e090a 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -28,11 +28,44 @@ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. - */ - +*/ #ifndef MLX5_IFC_H #define MLX5_IFC_H +enum { + MLX5_EVENT_TYPE_CODING_COMPLETION_EVENTS = 0x0, + MLX5_EVENT_TYPE_CODING_PATH_MIGRATED_SUCCEEDED = 0x1, + MLX5_EVENT_TYPE_CODING_COMMUNICATION_ESTABLISHED = 0x2, + MLX5_EVENT_TYPE_CODING_SEND_QUEUE_DRAINED = 0x3, + MLX5_EVENT_TYPE_CODING_LAST_WQE_REACHED = 0x13, + MLX5_EVENT_TYPE_CODING_SRQ_LIMIT = 0x14, + MLX5_EVENT_TYPE_CODING_DCT_ALL_CONNECTIONS_CLOSED = 0x1c, + MLX5_EVENT_TYPE_CODING_DCT_ACCESS_KEY_VIOLATION = 0x1d, + MLX5_EVENT_TYPE_CODING_CQ_ERROR = 0x4, + MLX5_EVENT_TYPE_CODING_LOCAL_WQ_CATASTROPHIC_ERROR = 0x5, + MLX5_EVENT_TYPE_CODING_PATH_MIGRATION_FAILED = 0x7, + MLX5_EVENT_TYPE_CODING_PAGE_FAULT_EVENT = 0xc, + MLX5_EVENT_TYPE_CODING_INVALID_REQUEST_LOCAL_WQ_ERROR = 0x10, + MLX5_EVENT_TYPE_CODING_LOCAL_ACCESS_VIOLATION_WQ_ERROR = 0x11, + MLX5_EVENT_TYPE_CODING_LOCAL_SRQ_CATASTROPHIC_ERROR = 0x12, + MLX5_EVENT_TYPE_CODING_INTERNAL_ERROR = 0x8, + MLX5_EVENT_TYPE_CODING_PORT_STATE_CHANGE = 0x9, + MLX5_EVENT_TYPE_CODING_GPIO_EVENT = 0x15, + MLX5_EVENT_TYPE_CODING_REMOTE_CONFIGURATION_PROTOCOL_EVENT = 0x19, + MLX5_EVENT_TYPE_CODING_DOORBELL_BLUEFLAME_CONGESTION_EVENT = 0x1a, + MLX5_EVENT_TYPE_CODING_STALL_VL_EVENT = 0x1b, + MLX5_EVENT_TYPE_CODING_DROPPED_PACKET_LOGGED_EVENT = 0x1f, + MLX5_EVENT_TYPE_CODING_COMMAND_INTERFACE_COMPLETION = 0xa, + MLX5_EVENT_TYPE_CODING_PAGE_REQUEST = 0xb +}; + +enum { + MLX5_MODIFY_TIR_BITMASK_LRO = 0x0, + MLX5_MODIFY_TIR_BITMASK_INDIRECT_TABLE = 0x1, + MLX5_MODIFY_TIR_BITMASK_HASH = 0x2, + MLX5_MODIFY_TIR_BITMASK_TUNNELED_OFFLOAD_EN = 0x3 +}; + enum { MLX5_CMD_OP_QUERY_HCA_CAP = 0x100, MLX5_CMD_OP_QUERY_ADAPTER = 0x101, @@ -43,6 +76,8 @@ enum { MLX5_CMD_OP_QUERY_PAGES = 0x107, MLX5_CMD_OP_MANAGE_PAGES = 0x108, MLX5_CMD_OP_SET_HCA_CAP = 0x109, + MLX5_CMD_OP_QUERY_ISSI = 0x10a, + MLX5_CMD_OP_SET_ISSI = 0x10b, MLX5_CMD_OP_CREATE_MKEY = 0x200, MLX5_CMD_OP_QUERY_MKEY = 0x201, MLX5_CMD_OP_DESTROY_MKEY = 0x202, @@ -66,6 +101,7 @@ enum { MLX5_CMD_OP_2ERR_QP = 0x507, MLX5_CMD_OP_2RST_QP = 0x50a, MLX5_CMD_OP_QUERY_QP = 0x50b, + MLX5_CMD_OP_SQD_RTS_QP = 0x50c, MLX5_CMD_OP_INIT2INIT_QP = 0x50e, MLX5_CMD_OP_CREATE_PSV = 0x600, MLX5_CMD_OP_DESTROY_PSV = 0x601, @@ -73,7 +109,10 @@ enum { MLX5_CMD_OP_DESTROY_SRQ = 0x701, MLX5_CMD_OP_QUERY_SRQ = 0x702, MLX5_CMD_OP_ARM_RQ = 0x703, - MLX5_CMD_OP_RESIZE_SRQ = 0x704, + MLX5_CMD_OP_CREATE_XRC_SRQ = 0x705, + MLX5_CMD_OP_DESTROY_XRC_SRQ = 0x706, + MLX5_CMD_OP_QUERY_XRC_SRQ = 0x707, + MLX5_CMD_OP_ARM_XRC_SRQ = 0x708, MLX5_CMD_OP_CREATE_DCT = 0x710, MLX5_CMD_OP_DESTROY_DCT = 0x711, MLX5_CMD_OP_DRAIN_DCT = 0x712, @@ -85,8 +124,12 @@ enum { MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT = 0x753, MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT = 0x754, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT = 0x755, - MLX5_CMD_OP_QUERY_RCOE_ADDRESS = 0x760, + MLX5_CMD_OP_QUERY_ROCE_ADDRESS = 0x760, MLX5_CMD_OP_SET_ROCE_ADDRESS = 0x761, + MLX5_CMD_OP_QUERY_HCA_VPORT_CONTEXT = 0x762, + MLX5_CMD_OP_MODIFY_HCA_VPORT_CONTEXT = 0x763, + MLX5_CMD_OP_QUERY_HCA_VPORT_GID = 0x764, + MLX5_CMD_OP_QUERY_HCA_VPORT_PKEY = 0x765, MLX5_CMD_OP_QUERY_VPORT_COUNTER = 0x770, MLX5_CMD_OP_ALLOC_Q_COUNTER = 0x771, MLX5_CMD_OP_DEALLOC_Q_COUNTER = 0x772, @@ -98,7 +141,7 @@ enum { MLX5_CMD_OP_CONFIG_INT_MODERATION = 0x804, MLX5_CMD_OP_ACCESS_REG = 0x805, MLX5_CMD_OP_ATTACH_TO_MCG = 0x806, - MLX5_CMD_OP_DETACH_FROM_MCG = 0x807, + MLX5_CMD_OP_DETTACH_FROM_MCG = 0x807, MLX5_CMD_OP_GET_DROPPED_PACKET_LOG = 0x80a, MLX5_CMD_OP_MAD_IFC = 0x50d, MLX5_CMD_OP_QUERY_MAD_DEMUX = 0x80b, @@ -106,23 +149,22 @@ enum { MLX5_CMD_OP_NOP = 0x80d, MLX5_CMD_OP_ALLOC_XRCD = 0x80e, MLX5_CMD_OP_DEALLOC_XRCD = 0x80f, - MLX5_CMD_OP_SET_BURST_SIZE = 0x812, - MLX5_CMD_OP_QUERY_BURST_SZIE = 0x813, - MLX5_CMD_OP_ACTIVATE_TRACER = 0x814, - MLX5_CMD_OP_DEACTIVATE_TRACER = 0x815, - MLX5_CMD_OP_CREATE_SNIFFER_RULE = 0x820, - MLX5_CMD_OP_DESTROY_SNIFFER_RULE = 0x821, - MLX5_CMD_OP_QUERY_CONG_PARAMS = 0x822, - MLX5_CMD_OP_MODIFY_CONG_PARAMS = 0x823, - MLX5_CMD_OP_QUERY_CONG_STATISTICS = 0x824, + MLX5_CMD_OP_ALLOC_TRANSPORT_DOMAIN = 0x816, + MLX5_CMD_OP_DEALLOC_TRANSPORT_DOMAIN = 0x817, + MLX5_CMD_OP_QUERY_CONG_STATUS = 0x822, + MLX5_CMD_OP_MODIFY_CONG_STATUS = 0x823, + MLX5_CMD_OP_QUERY_CONG_PARAMS = 0x824, + MLX5_CMD_OP_MODIFY_CONG_PARAMS = 0x825, + MLX5_CMD_OP_QUERY_CONG_STATISTICS = 0x826, + MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT = 0x827, + MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT = 0x828, + MLX5_CMD_OP_SET_L2_TABLE_ENTRY = 0x829, + MLX5_CMD_OP_QUERY_L2_TABLE_ENTRY = 0x82a, + MLX5_CMD_OP_DELETE_L2_TABLE_ENTRY = 0x82b, MLX5_CMD_OP_CREATE_TIR = 0x900, MLX5_CMD_OP_MODIFY_TIR = 0x901, MLX5_CMD_OP_DESTROY_TIR = 0x902, MLX5_CMD_OP_QUERY_TIR = 0x903, - MLX5_CMD_OP_CREATE_TIS = 0x912, - MLX5_CMD_OP_MODIFY_TIS = 0x913, - MLX5_CMD_OP_DESTROY_TIS = 0x914, - MLX5_CMD_OP_QUERY_TIS = 0x915, MLX5_CMD_OP_CREATE_SQ = 0x904, MLX5_CMD_OP_MODIFY_SQ = 0x905, MLX5_CMD_OP_DESTROY_SQ = 0x906, @@ -135,9 +177,430 @@ enum { MLX5_CMD_OP_MODIFY_RMP = 0x90d, MLX5_CMD_OP_DESTROY_RMP = 0x90e, MLX5_CMD_OP_QUERY_RMP = 0x90f, - MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY = 0x910, - MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY = 0x911, - MLX5_CMD_OP_MAX = 0x911 + MLX5_CMD_OP_CREATE_TIS = 0x912, + MLX5_CMD_OP_MODIFY_TIS = 0x913, + MLX5_CMD_OP_DESTROY_TIS = 0x914, + MLX5_CMD_OP_QUERY_TIS = 0x915, + MLX5_CMD_OP_CREATE_RQT = 0x916, + MLX5_CMD_OP_MODIFY_RQT = 0x917, + MLX5_CMD_OP_DESTROY_RQT = 0x918, + MLX5_CMD_OP_QUERY_RQT = 0x919, + MLX5_CMD_OP_CREATE_FLOW_TABLE = 0x930, + MLX5_CMD_OP_DESTROY_FLOW_TABLE = 0x931, + MLX5_CMD_OP_QUERY_FLOW_TABLE = 0x932, + MLX5_CMD_OP_CREATE_FLOW_GROUP = 0x933, + MLX5_CMD_OP_DESTROY_FLOW_GROUP = 0x934, + MLX5_CMD_OP_QUERY_FLOW_GROUP = 0x935, + MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY = 0x936, + MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY = 0x937, + MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY = 0x938 +}; + +struct mlx5_ifc_flow_table_fields_supported_bits { + u8 outer_dmac[0x1]; + u8 outer_smac[0x1]; + u8 outer_ether_type[0x1]; + u8 reserved_0[0x1]; + u8 outer_first_prio[0x1]; + u8 outer_first_cfi[0x1]; + u8 outer_first_vid[0x1]; + u8 reserved_1[0x1]; + u8 outer_second_prio[0x1]; + u8 outer_second_cfi[0x1]; + u8 outer_second_vid[0x1]; + u8 reserved_2[0x1]; + u8 outer_sip[0x1]; + u8 outer_dip[0x1]; + u8 outer_frag[0x1]; + u8 outer_ip_protocol[0x1]; + u8 outer_ip_ecn[0x1]; + u8 outer_ip_dscp[0x1]; + u8 outer_udp_sport[0x1]; + u8 outer_udp_dport[0x1]; + u8 outer_tcp_sport[0x1]; + u8 outer_tcp_dport[0x1]; + u8 outer_tcp_flags[0x1]; + u8 outer_gre_protocol[0x1]; + u8 outer_gre_key[0x1]; + u8 outer_vxlan_vni[0x1]; + u8 reserved_3[0x5]; + u8 source_eswitch_port[0x1]; + + u8 inner_dmac[0x1]; + u8 inner_smac[0x1]; + u8 inner_ether_type[0x1]; + u8 reserved_4[0x1]; + u8 inner_first_prio[0x1]; + u8 inner_first_cfi[0x1]; + u8 inner_first_vid[0x1]; + u8 reserved_5[0x1]; + u8 inner_second_prio[0x1]; + u8 inner_second_cfi[0x1]; + u8 inner_second_vid[0x1]; + u8 reserved_6[0x1]; + u8 inner_sip[0x1]; + u8 inner_dip[0x1]; + u8 inner_frag[0x1]; + u8 inner_ip_protocol[0x1]; + u8 inner_ip_ecn[0x1]; + u8 inner_ip_dscp[0x1]; + u8 inner_udp_sport[0x1]; + u8 inner_udp_dport[0x1]; + u8 inner_tcp_sport[0x1]; + u8 inner_tcp_dport[0x1]; + u8 inner_tcp_flags[0x1]; + u8 reserved_7[0x9]; + + u8 reserved_8[0x40]; +}; + +struct mlx5_ifc_flow_table_prop_layout_bits { + u8 ft_support[0x1]; + u8 reserved_0[0x1f]; + + u8 reserved_1[0x2]; + u8 log_max_ft_size[0x6]; + u8 reserved_2[0x10]; + u8 max_ft_level[0x8]; + + u8 reserved_3[0x20]; + + u8 reserved_4[0x18]; + u8 log_max_ft_num[0x8]; + + u8 reserved_5[0x18]; + u8 log_max_destination[0x8]; + + u8 reserved_6[0x18]; + u8 log_max_flow[0x8]; + + u8 reserved_7[0x40]; + + struct mlx5_ifc_flow_table_fields_supported_bits ft_field_support; + + struct mlx5_ifc_flow_table_fields_supported_bits ft_field_bitmask_support; +}; + +struct mlx5_ifc_odp_per_transport_service_cap_bits { + u8 send[0x1]; + u8 receive[0x1]; + u8 write[0x1]; + u8 read[0x1]; + u8 reserved_0[0x1]; + u8 srq_receive[0x1]; + u8 reserved_1[0x1a]; +}; + +struct mlx5_ifc_fte_match_set_lyr_2_4_bits { + u8 smac_47_16[0x20]; + + u8 smac_15_0[0x10]; + u8 ethertype[0x10]; + + u8 dmac_47_16[0x20]; + + u8 dmac_15_0[0x10]; + u8 first_prio[0x3]; + u8 first_cfi[0x1]; + u8 first_vid[0xc]; + + u8 ip_protocol[0x8]; + u8 ip_dscp[0x6]; + u8 ip_ecn[0x2]; + u8 vlan_tag[0x1]; + u8 reserved_0[0x1]; + u8 frag[0x1]; + u8 reserved_1[0x4]; + u8 tcp_flags[0x9]; + + u8 tcp_sport[0x10]; + u8 tcp_dport[0x10]; + + u8 reserved_2[0x20]; + + u8 udp_sport[0x10]; + u8 udp_dport[0x10]; + + u8 src_ip[4][0x20]; + + u8 dst_ip[4][0x20]; +}; + +struct mlx5_ifc_fte_match_set_misc_bits { + u8 reserved_0[0x20]; + + u8 reserved_1[0x10]; + u8 source_port[0x10]; + + u8 outer_second_prio[0x3]; + u8 outer_second_cfi[0x1]; + u8 outer_second_vid[0xc]; + u8 inner_second_prio[0x3]; + u8 inner_second_cfi[0x1]; + u8 inner_second_vid[0xc]; + + u8 outer_second_vlan_tag[0x1]; + u8 inner_second_vlan_tag[0x1]; + u8 reserved_2[0xe]; + u8 gre_protocol[0x10]; + + u8 gre_key_h[0x18]; + u8 gre_key_l[0x8]; + + u8 vxlan_vni[0x18]; + u8 reserved_3[0x8]; + + u8 reserved_4[0x20]; + + u8 reserved_5[0xc]; + u8 outer_ipv6_flow_label[0x14]; + + u8 reserved_6[0xc]; + u8 inner_ipv6_flow_label[0x14]; + + u8 reserved_7[0xe0]; +}; + +struct mlx5_ifc_cmd_pas_bits { + u8 pa_h[0x20]; + + u8 pa_l[0x14]; + u8 reserved_0[0xc]; +}; + +struct mlx5_ifc_uint64_bits { + u8 hi[0x20]; + + u8 lo[0x20]; +}; + +enum { + MLX5_ADS_STAT_RATE_NO_LIMIT = 0x0, + MLX5_ADS_STAT_RATE_2_5GBPS = 0x7, + MLX5_ADS_STAT_RATE_10GBPS = 0x8, + MLX5_ADS_STAT_RATE_30GBPS = 0x9, + MLX5_ADS_STAT_RATE_5GBPS = 0xa, + MLX5_ADS_STAT_RATE_20GBPS = 0xb, + MLX5_ADS_STAT_RATE_40GBPS = 0xc, + MLX5_ADS_STAT_RATE_60GBPS = 0xd, + MLX5_ADS_STAT_RATE_80GBPS = 0xe, + MLX5_ADS_STAT_RATE_120GBPS = 0xf, +}; + +struct mlx5_ifc_ads_bits { + u8 fl[0x1]; + u8 free_ar[0x1]; + u8 reserved_0[0xe]; + u8 pkey_index[0x10]; + + u8 reserved_1[0x8]; + u8 grh[0x1]; + u8 mlid[0x7]; + u8 rlid[0x10]; + + u8 ack_timeout[0x5]; + u8 reserved_2[0x3]; + u8 src_addr_index[0x8]; + u8 reserved_3[0x4]; + u8 stat_rate[0x4]; + u8 hop_limit[0x8]; + + u8 reserved_4[0x4]; + u8 tclass[0x8]; + u8 flow_label[0x14]; + + u8 rgid_rip[16][0x8]; + + u8 reserved_5[0x4]; + u8 f_dscp[0x1]; + u8 f_ecn[0x1]; + u8 reserved_6[0x1]; + u8 f_eth_prio[0x1]; + u8 ecn[0x2]; + u8 dscp[0x6]; + u8 udp_sport[0x10]; + + u8 dei_cfi[0x1]; + u8 eth_prio[0x3]; + u8 sl[0x4]; + u8 port[0x8]; + u8 rmac_47_32[0x10]; + + u8 rmac_31_0[0x20]; +}; + +struct mlx5_ifc_flow_table_nic_cap_bits { + u8 reserved_0[0x200]; + + struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_receive; + + u8 reserved_1[0x200]; + + struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_receive_sniffer; + + struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_transmit; + + u8 reserved_2[0x200]; + + struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_transmit_sniffer; + + u8 reserved_3[0x7200]; +}; + +struct mlx5_ifc_per_protocol_networking_offload_caps_bits { + u8 csum_cap[0x1]; + u8 vlan_cap[0x1]; + u8 lro_cap[0x1]; + u8 lro_psh_flag[0x1]; + u8 lro_time_stamp[0x1]; + u8 reserved_0[0x6]; + u8 max_lso_cap[0x5]; + u8 reserved_1[0x4]; + u8 rss_ind_tbl_cap[0x4]; + u8 reserved_2[0x3]; + u8 tunnel_lso_const_out_ip_id[0x1]; + u8 reserved_3[0x2]; + u8 tunnel_statless_gre[0x1]; + u8 tunnel_stateless_vxlan[0x1]; + + u8 reserved_4[0x20]; + + u8 reserved_5[0x10]; + u8 lro_min_mss_size[0x10]; + + u8 reserved_6[0x120]; + + u8 lro_timer_supported_periods[4][0x20]; + + u8 reserved_7[0x600]; +}; + +struct mlx5_ifc_roce_cap_bits { + u8 roce_apm[0x1]; + u8 reserved_0[0x1f]; + + u8 reserved_1[0x60]; + + u8 reserved_2[0xc]; + u8 l3_type[0x4]; + u8 reserved_3[0x8]; + u8 roce_version[0x8]; + + u8 reserved_4[0x10]; + u8 r_roce_dest_udp_port[0x10]; + + u8 r_roce_max_src_udp_port[0x10]; + u8 r_roce_min_src_udp_port[0x10]; + + u8 reserved_5[0x10]; + u8 roce_address_table_size[0x10]; + + u8 reserved_6[0x700]; +}; + +enum { + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_QP_1_BYTE = 0x0, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_QP_2_BYTES = 0x2, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_QP_4_BYTES = 0x4, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_QP_8_BYTES = 0x8, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_QP_16_BYTES = 0x10, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_QP_32_BYTES = 0x20, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_QP_64_BYTES = 0x40, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_QP_128_BYTES = 0x80, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_QP_256_BYTES = 0x100, +}; + +enum { + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_DC_1_BYTE = 0x1, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_DC_2_BYTES = 0x2, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_DC_4_BYTES = 0x4, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_DC_8_BYTES = 0x8, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_DC_16_BYTES = 0x10, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_DC_32_BYTES = 0x20, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_DC_64_BYTES = 0x40, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_DC_128_BYTES = 0x80, + MLX5_ATOMIC_CAPS_ATOMIC_SIZE_DC_256_BYTES = 0x100, +}; + +struct mlx5_ifc_atomic_caps_bits { + u8 reserved_0[0x40]; + + u8 atomic_req_endianness[0x1]; + u8 reserved_1[0x1f]; + + u8 reserved_2[0x20]; + + u8 reserved_3[0x10]; + u8 atomic_operations[0x10]; + + u8 reserved_4[0x10]; + u8 atomic_size_qp[0x10]; + + u8 reserved_5[0x10]; + u8 atomic_size_dc[0x10]; + + u8 reserved_6[0x720]; +}; + +struct mlx5_ifc_odp_cap_bits { + u8 reserved_0[0x40]; + + u8 sig[0x1]; + u8 reserved_1[0x1f]; + + u8 reserved_2[0x20]; + + struct mlx5_ifc_odp_per_transport_service_cap_bits rc_odp_caps; + + struct mlx5_ifc_odp_per_transport_service_cap_bits uc_odp_caps; + + struct mlx5_ifc_odp_per_transport_service_cap_bits ud_odp_caps; + + u8 reserved_3[0x720]; +}; + +enum { + MLX5_WQ_TYPE_LINKED_LIST = 0x0, + MLX5_WQ_TYPE_CYCLIC = 0x1, + MLX5_WQ_TYPE_STRQ = 0x2, +}; + +enum { + MLX5_WQ_END_PAD_MODE_NONE = 0x0, + MLX5_WQ_END_PAD_MODE_ALIGN = 0x1, +}; + +enum { + MLX5_CMD_HCA_CAP_GID_TABLE_SIZE_8_GID_ENTRIES = 0x0, + MLX5_CMD_HCA_CAP_GID_TABLE_SIZE_16_GID_ENTRIES = 0x1, + MLX5_CMD_HCA_CAP_GID_TABLE_SIZE_32_GID_ENTRIES = 0x2, + MLX5_CMD_HCA_CAP_GID_TABLE_SIZE_64_GID_ENTRIES = 0x3, + MLX5_CMD_HCA_CAP_GID_TABLE_SIZE_128_GID_ENTRIES = 0x4, +}; + +enum { + MLX5_CMD_HCA_CAP_PKEY_TABLE_SIZE_128_ENTRIES = 0x0, + MLX5_CMD_HCA_CAP_PKEY_TABLE_SIZE_256_ENTRIES = 0x1, + MLX5_CMD_HCA_CAP_PKEY_TABLE_SIZE_512_ENTRIES = 0x2, + MLX5_CMD_HCA_CAP_PKEY_TABLE_SIZE_1K_ENTRIES = 0x3, + MLX5_CMD_HCA_CAP_PKEY_TABLE_SIZE_2K_ENTRIES = 0x4, + MLX5_CMD_HCA_CAP_PKEY_TABLE_SIZE_4K_ENTRIES = 0x5, +}; + +enum { + MLX5_CMD_HCA_CAP_PORT_TYPE_IB = 0x0, + MLX5_CMD_HCA_CAP_PORT_TYPE_ETHERNET = 0x1, +}; + +enum { + MLX5_CMD_HCA_CAP_CMDIF_CHECKSUM_DISABLED = 0x0, + MLX5_CMD_HCA_CAP_CMDIF_CHECKSUM_INITIAL_STATE = 0x1, + MLX5_CMD_HCA_CAP_CMDIF_CHECKSUM_ENABLED = 0x3, +}; + +enum { + MLX5_CAP_PORT_TYPE_IB = 0x0, + MLX5_CAP_PORT_TYPE_ETH = 0x1, }; struct mlx5_ifc_cmd_hca_cap_bits { @@ -148,9 +611,8 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 reserved_1[0xb]; u8 log_max_qp[0x5]; - u8 log_max_strq_sz[0x8]; - u8 reserved_2[0x3]; - u8 log_max_srqs[0x5]; + u8 reserved_2[0xb]; + u8 log_max_srq[0x5]; u8 reserved_3[0x10]; u8 reserved_4[0x8]; @@ -185,165 +647,6123 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 pad_cap[0x1]; u8 cc_query_allowed[0x1]; u8 cc_modify_allowed[0x1]; - u8 reserved_15[0x1d]; + u8 reserved_15[0xd]; + u8 gid_table_size[0x10]; - u8 reserved_16[0x6]; + u8 out_of_seq_cnt[0x1]; + u8 vport_counters[0x1]; + u8 reserved_16[0x4]; u8 max_qp_cnt[0xa]; u8 pkey_table_size[0x10]; - u8 eswitch_owner[0x1]; - u8 reserved_17[0xa]; + u8 vport_group_manager[0x1]; + u8 vhca_group_manager[0x1]; + u8 ib_virt[0x1]; + u8 eth_virt[0x1]; + u8 reserved_17[0x1]; + u8 ets[0x1]; + u8 nic_flow_table[0x1]; + u8 reserved_18[0x4]; u8 local_ca_ack_delay[0x5]; - u8 reserved_18[0x8]; + u8 reserved_19[0x6]; + u8 port_type[0x2]; u8 num_ports[0x8]; - u8 reserved_19[0x3]; + u8 reserved_20[0x3]; u8 log_max_msg[0x5]; - u8 reserved_20[0x18]; + u8 reserved_21[0x18]; u8 stat_rate_support[0x10]; - u8 reserved_21[0x10]; + u8 reserved_22[0xc]; + u8 cqe_version[0x4]; - u8 reserved_22[0x10]; + u8 compact_address_vector[0x1]; + u8 reserved_23[0xe]; + u8 drain_sigerr[0x1]; u8 cmdif_checksum[0x2]; u8 sigerr_cqe[0x1]; - u8 reserved_23[0x1]; + u8 reserved_24[0x1]; u8 wq_signature[0x1]; u8 sctr_data_cqe[0x1]; - u8 reserved_24[0x1]; + u8 reserved_25[0x1]; u8 sho[0x1]; u8 tph[0x1]; u8 rf[0x1]; - u8 dc[0x1]; - u8 reserved_25[0x2]; + u8 dct[0x1]; + u8 reserved_26[0x1]; + u8 eth_net_offloads[0x1]; u8 roce[0x1]; u8 atomic[0x1]; - u8 rsz_srq[0x1]; + u8 reserved_27[0x1]; u8 cq_oi[0x1]; u8 cq_resize[0x1]; u8 cq_moderation[0x1]; - u8 sniffer_rule_flow[0x1]; - u8 sniffer_rule_vport[0x1]; - u8 sniffer_rule_phy[0x1]; - u8 reserved_26[0x1]; + u8 reserved_28[0x3]; + u8 cq_eq_remap[0x1]; u8 pg[0x1]; u8 block_lb_mc[0x1]; - u8 reserved_27[0x3]; + u8 reserved_29[0x1]; + u8 scqe_break_moderation[0x1]; + u8 reserved_30[0x1]; u8 cd[0x1]; - u8 reserved_28[0x1]; + u8 reserved_31[0x1]; u8 apm[0x1]; - u8 reserved_29[0x7]; + u8 reserved_32[0x7]; u8 qkv[0x1]; u8 pkv[0x1]; - u8 reserved_30[0x4]; + u8 reserved_33[0x4]; u8 xrc[0x1]; u8 ud[0x1]; u8 uc[0x1]; u8 rc[0x1]; - u8 reserved_31[0xa]; + u8 reserved_34[0xa]; u8 uar_sz[0x6]; - u8 reserved_32[0x8]; + u8 reserved_35[0x8]; u8 log_pg_sz[0x8]; u8 bf[0x1]; - u8 reserved_33[0xa]; + u8 reserved_36[0x1]; + u8 pad_tx_eth_packet[0x1]; + u8 reserved_37[0x8]; u8 log_bf_reg_size[0x5]; - u8 reserved_34[0x10]; + u8 reserved_38[0x10]; - u8 reserved_35[0x10]; + u8 reserved_39[0x10]; u8 max_wqe_sz_sq[0x10]; - u8 reserved_36[0x10]; + u8 reserved_40[0x10]; u8 max_wqe_sz_rq[0x10]; - u8 reserved_37[0x10]; + u8 reserved_41[0x10]; u8 max_wqe_sz_sq_dc[0x10]; - u8 reserved_38[0x7]; + u8 reserved_42[0x7]; u8 max_qp_mcg[0x19]; - u8 reserved_39[0x18]; + u8 reserved_43[0x18]; u8 log_max_mcg[0x8]; - u8 reserved_40[0xb]; + u8 reserved_44[0x3]; + u8 log_max_transport_domain[0x5]; + u8 reserved_45[0x3]; u8 log_max_pd[0x5]; - u8 reserved_41[0xb]; + u8 reserved_46[0xb]; u8 log_max_xrcd[0x5]; - u8 reserved_42[0x20]; + u8 reserved_47[0x20]; - u8 reserved_43[0x3]; + u8 reserved_48[0x3]; u8 log_max_rq[0x5]; - u8 reserved_44[0x3]; + u8 reserved_49[0x3]; u8 log_max_sq[0x5]; - u8 reserved_45[0x3]; + u8 reserved_50[0x3]; u8 log_max_tir[0x5]; - u8 reserved_46[0x3]; + u8 reserved_51[0x3]; u8 log_max_tis[0x5]; - u8 reserved_47[0x13]; - u8 log_max_rq_per_tir[0x5]; - u8 reserved_48[0x3]; + u8 basic_cyclic_rcv_wqe[0x1]; + u8 reserved_52[0x2]; + u8 log_max_rmp[0x5]; + u8 reserved_53[0x3]; + u8 log_max_rqt[0x5]; + u8 reserved_54[0x3]; + u8 log_max_rqt_size[0x5]; + u8 reserved_55[0x3]; u8 log_max_tis_per_sq[0x5]; - u8 reserved_49[0xe0]; + u8 reserved_56[0x3]; + u8 log_max_stride_sz_rq[0x5]; + u8 reserved_57[0x3]; + u8 log_min_stride_sz_rq[0x5]; + u8 reserved_58[0x3]; + u8 log_max_stride_sz_sq[0x5]; + u8 reserved_59[0x3]; + u8 log_min_stride_sz_sq[0x5]; + + u8 reserved_60[0x1b]; + u8 log_max_wq_sz[0x5]; + + u8 reserved_61[0xa0]; - u8 reserved_50[0x10]; + u8 reserved_62[0x3]; + u8 log_max_l2_table[0x5]; + u8 reserved_63[0x8]; u8 log_uar_page_sz[0x10]; - u8 reserved_51[0x100]; + u8 reserved_64[0x100]; - u8 reserved_52[0x1f]; + u8 reserved_65[0x1f]; u8 cqe_zip[0x1]; u8 cqe_zip_timeout[0x10]; u8 cqe_zip_max_num[0x10]; - u8 reserved_53[0x220]; + u8 reserved_66[0x220]; }; -struct mlx5_ifc_set_hca_cap_in_bits { - u8 opcode[0x10]; - u8 reserved_0[0x10]; +enum { + MLX5_DEST_FORMAT_STRUCT_DESTINATION_TYPE_FLOW_TABLE_ = 0x1, + MLX5_DEST_FORMAT_STRUCT_DESTINATION_TYPE_TIR = 0x2, +}; - u8 reserved_1[0x10]; - u8 op_mod[0x10]; +struct mlx5_ifc_dest_format_struct_bits { + u8 destination_type[0x8]; + u8 destination_id[0x18]; - u8 reserved_2[0x40]; + u8 reserved_0[0x20]; +}; + +struct mlx5_ifc_fte_match_param_bits { + struct mlx5_ifc_fte_match_set_lyr_2_4_bits outer_headers; + + struct mlx5_ifc_fte_match_set_misc_bits misc_parameters; + + struct mlx5_ifc_fte_match_set_lyr_2_4_bits inner_headers; - struct mlx5_ifc_cmd_hca_cap_bits hca_capability_struct; + u8 reserved_0[0xa00]; }; -struct mlx5_ifc_query_hca_cap_in_bits { - u8 opcode[0x10]; - u8 reserved_0[0x10]; +enum { + MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_SRC_IP = 0x0, + MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_DST_IP = 0x1, + MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_SPORT = 0x2, + MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_DPORT = 0x3, + MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_IPSEC_SPI = 0x4, +}; - u8 reserved_1[0x10]; - u8 op_mod[0x10]; +struct mlx5_ifc_rx_hash_field_select_bits { + u8 l3_prot_type[0x1]; + u8 l4_prot_type[0x1]; + u8 selected_fields[0x1e]; +}; - u8 reserved_2[0x40]; +enum { + MLX5_WQ_WQ_TYPE_WQ_LINKED_LIST = 0x0, + MLX5_WQ_WQ_TYPE_WQ_CYCLIC = 0x1, }; -struct mlx5_ifc_query_hca_cap_out_bits { - u8 status[0x8]; +enum { + MLX5_WQ_END_PADDING_MODE_END_PAD_NONE = 0x0, + MLX5_WQ_END_PADDING_MODE_END_PAD_ALIGN = 0x1, +}; + +struct mlx5_ifc_wq_bits { + u8 wq_type[0x4]; + u8 wq_signature[0x1]; + u8 end_padding_mode[0x2]; + u8 cd_slave[0x1]; u8 reserved_0[0x18]; - u8 syndrome[0x20]; + u8 hds_skip_first_sge[0x1]; + u8 log2_hds_buf_size[0x3]; + u8 reserved_1[0x7]; + u8 page_offset[0x5]; + u8 lwm[0x10]; - u8 reserved_1[0x40]; + u8 reserved_2[0x8]; + u8 pd[0x18]; + + u8 reserved_3[0x8]; + u8 uar_page[0x18]; + + u8 dbr_addr[0x40]; + + u8 hw_counter[0x20]; + + u8 sw_counter[0x20]; + + u8 reserved_4[0xc]; + u8 log_wq_stride[0x4]; + u8 reserved_5[0x3]; + u8 log_wq_pg_sz[0x5]; + u8 reserved_6[0x3]; + u8 log_wq_sz[0x5]; + + u8 reserved_7[0x4e0]; - u8 capability_struct[256][0x8]; + struct mlx5_ifc_cmd_pas_bits pas[0]; }; -struct mlx5_ifc_set_hca_cap_out_bits { - u8 status[0x8]; - u8 reserved_0[0x18]; +struct mlx5_ifc_rq_num_bits { + u8 reserved_0[0x8]; + u8 rq_num[0x18]; +}; - u8 syndrome[0x20]; +struct mlx5_ifc_mac_address_layout_bits { + u8 reserved_0[0x10]; + u8 mac_addr_47_32[0x10]; - u8 reserved_1[0x40]; + u8 mac_addr_31_0[0x20]; +}; + +struct mlx5_ifc_cong_control_r_roce_ecn_np_bits { + u8 reserved_0[0xa0]; + + u8 min_time_between_cnps[0x20]; + + u8 reserved_1[0x12]; + u8 cnp_dscp[0x6]; + u8 reserved_2[0x5]; + u8 cnp_802p_prio[0x3]; + + u8 reserved_3[0x720]; +}; + +struct mlx5_ifc_cong_control_r_roce_ecn_rp_bits { + u8 reserved_0[0x60]; + + u8 reserved_1[0x4]; + u8 clamp_tgt_rate[0x1]; + u8 reserved_2[0x3]; + u8 clamp_tgt_rate_after_time_inc[0x1]; + u8 reserved_3[0x17]; + + u8 reserved_4[0x20]; + + u8 rpg_time_reset[0x20]; + + u8 rpg_byte_reset[0x20]; + + u8 rpg_threshold[0x20]; + + u8 rpg_max_rate[0x20]; + + u8 rpg_ai_rate[0x20]; + + u8 rpg_hai_rate[0x20]; + + u8 rpg_gd[0x20]; + + u8 rpg_min_dec_fac[0x20]; + + u8 rpg_min_rate[0x20]; + + u8 reserved_5[0xe0]; + + u8 rate_to_set_on_first_cnp[0x20]; + + u8 dce_tcp_g[0x20]; + + u8 dce_tcp_rtt[0x20]; + + u8 rate_reduce_monitor_period[0x20]; + + u8 reserved_6[0x20]; + + u8 initial_alpha_value[0x20]; + + u8 reserved_7[0x4a0]; +}; + +struct mlx5_ifc_cong_control_802_1qau_rp_bits { + u8 reserved_0[0x80]; + + u8 rppp_max_rps[0x20]; + + u8 rpg_time_reset[0x20]; + + u8 rpg_byte_reset[0x20]; + + u8 rpg_threshold[0x20]; + + u8 rpg_max_rate[0x20]; + + u8 rpg_ai_rate[0x20]; + + u8 rpg_hai_rate[0x20]; + + u8 rpg_gd[0x20]; + + u8 rpg_min_dec_fac[0x20]; + + u8 rpg_min_rate[0x20]; + + u8 reserved_1[0x640]; +}; + +enum { + MLX5_RESIZE_FIELD_SELECT_RESIZE_FIELD_SELECT_LOG_CQ_SIZE = 0x1, + MLX5_RESIZE_FIELD_SELECT_RESIZE_FIELD_SELECT_PAGE_OFFSET = 0x2, + MLX5_RESIZE_FIELD_SELECT_RESIZE_FIELD_SELECT_LOG_PAGE_SIZE = 0x4, +}; + +struct mlx5_ifc_resize_field_select_bits { + u8 resize_field_select[0x20]; +}; + +enum { + MLX5_MODIFY_FIELD_SELECT_MODIFY_FIELD_SELECT_CQ_PERIOD = 0x1, + MLX5_MODIFY_FIELD_SELECT_MODIFY_FIELD_SELECT_CQ_MAX_COUNT = 0x2, + MLX5_MODIFY_FIELD_SELECT_MODIFY_FIELD_SELECT_OI = 0x4, + MLX5_MODIFY_FIELD_SELECT_MODIFY_FIELD_SELECT_C_EQN = 0x8, +}; + +struct mlx5_ifc_modify_field_select_bits { + u8 modify_field_select[0x20]; +}; + +struct mlx5_ifc_field_select_r_roce_np_bits { + u8 field_select_r_roce_np[0x20]; +}; + +struct mlx5_ifc_field_select_r_roce_rp_bits { + u8 field_select_r_roce_rp[0x20]; +}; + +enum { + MLX5_FIELD_SELECT_802_1QAU_RP_FIELD_SELECT_8021QAURP_RPPP_MAX_RPS = 0x4, + MLX5_FIELD_SELECT_802_1QAU_RP_FIELD_SELECT_8021QAURP_RPG_TIME_RESET = 0x8, + MLX5_FIELD_SELECT_802_1QAU_RP_FIELD_SELECT_8021QAURP_RPG_BYTE_RESET = 0x10, + MLX5_FIELD_SELECT_802_1QAU_RP_FIELD_SELECT_8021QAURP_RPG_THRESHOLD = 0x20, + MLX5_FIELD_SELECT_802_1QAU_RP_FIELD_SELECT_8021QAURP_RPG_MAX_RATE = 0x40, + MLX5_FIELD_SELECT_802_1QAU_RP_FIELD_SELECT_8021QAURP_RPG_AI_RATE = 0x80, + MLX5_FIELD_SELECT_802_1QAU_RP_FIELD_SELECT_8021QAURP_RPG_HAI_RATE = 0x100, + MLX5_FIELD_SELECT_802_1QAU_RP_FIELD_SELECT_8021QAURP_RPG_GD = 0x200, + MLX5_FIELD_SELECT_802_1QAU_RP_FIELD_SELECT_8021QAURP_RPG_MIN_DEC_FAC = 0x400, + MLX5_FIELD_SELECT_802_1QAU_RP_FIELD_SELECT_8021QAURP_RPG_MIN_RATE = 0x800, +}; + +struct mlx5_ifc_field_select_802_1qau_rp_bits { + u8 field_select_8021qaurp[0x20]; +}; + +struct mlx5_ifc_phys_layer_cntrs_bits { + u8 time_since_last_clear_high[0x20]; + + u8 time_since_last_clear_low[0x20]; + + u8 symbol_errors_high[0x20]; + + u8 symbol_errors_low[0x20]; + + u8 sync_headers_errors_high[0x20]; + + u8 sync_headers_errors_low[0x20]; + + u8 edpl_bip_errors_lane0_high[0x20]; + + u8 edpl_bip_errors_lane0_low[0x20]; + + u8 edpl_bip_errors_lane1_high[0x20]; + + u8 edpl_bip_errors_lane1_low[0x20]; + + u8 edpl_bip_errors_lane2_high[0x20]; + + u8 edpl_bip_errors_lane2_low[0x20]; + + u8 edpl_bip_errors_lane3_high[0x20]; + + u8 edpl_bip_errors_lane3_low[0x20]; + + u8 fc_fec_corrected_blocks_lane0_high[0x20]; + + u8 fc_fec_corrected_blocks_lane0_low[0x20]; + + u8 fc_fec_corrected_blocks_lane1_high[0x20]; + + u8 fc_fec_corrected_blocks_lane1_low[0x20]; + + u8 fc_fec_corrected_blocks_lane2_high[0x20]; + + u8 fc_fec_corrected_blocks_lane2_low[0x20]; + + u8 fc_fec_corrected_blocks_lane3_high[0x20]; + + u8 fc_fec_corrected_blocks_lane3_low[0x20]; + + u8 fc_fec_uncorrectable_blocks_lane0_high[0x20]; + + u8 fc_fec_uncorrectable_blocks_lane0_low[0x20]; + + u8 fc_fec_uncorrectable_blocks_lane1_high[0x20]; + + u8 fc_fec_uncorrectable_blocks_lane1_low[0x20]; + + u8 fc_fec_uncorrectable_blocks_lane2_high[0x20]; + + u8 fc_fec_uncorrectable_blocks_lane2_low[0x20]; + + u8 fc_fec_uncorrectable_blocks_lane3_high[0x20]; + + u8 fc_fec_uncorrectable_blocks_lane3_low[0x20]; + + u8 rs_fec_corrected_blocks_high[0x20]; + + u8 rs_fec_corrected_blocks_low[0x20]; + + u8 rs_fec_uncorrectable_blocks_high[0x20]; + + u8 rs_fec_uncorrectable_blocks_low[0x20]; + + u8 rs_fec_no_errors_blocks_high[0x20]; + + u8 rs_fec_no_errors_blocks_low[0x20]; + + u8 rs_fec_single_error_blocks_high[0x20]; + + u8 rs_fec_single_error_blocks_low[0x20]; + + u8 rs_fec_corrected_symbols_total_high[0x20]; + + u8 rs_fec_corrected_symbols_total_low[0x20]; + + u8 rs_fec_corrected_symbols_lane0_high[0x20]; + + u8 rs_fec_corrected_symbols_lane0_low[0x20]; + + u8 rs_fec_corrected_symbols_lane1_high[0x20]; + + u8 rs_fec_corrected_symbols_lane1_low[0x20]; + + u8 rs_fec_corrected_symbols_lane2_high[0x20]; + + u8 rs_fec_corrected_symbols_lane2_low[0x20]; + + u8 rs_fec_corrected_symbols_lane3_high[0x20]; + + u8 rs_fec_corrected_symbols_lane3_low[0x20]; + + u8 link_down_events[0x20]; + + u8 successful_recovery_events[0x20]; + + u8 reserved_0[0x180]; +}; + +struct mlx5_ifc_eth_per_traffic_grp_data_layout_bits { + u8 transmit_queue_high[0x20]; + + u8 transmit_queue_low[0x20]; + + u8 reserved_0[0x780]; +}; + +struct mlx5_ifc_eth_per_prio_grp_data_layout_bits { + u8 rx_octets_high[0x20]; + + u8 rx_octets_low[0x20]; + + u8 reserved_0[0xc0]; + + u8 rx_frames_high[0x20]; + + u8 rx_frames_low[0x20]; + + u8 tx_octets_high[0x20]; + + u8 tx_octets_low[0x20]; + + u8 reserved_1[0xc0]; + + u8 tx_frames_high[0x20]; + + u8 tx_frames_low[0x20]; + + u8 rx_pause_high[0x20]; + + u8 rx_pause_low[0x20]; + + u8 rx_pause_duration_high[0x20]; + + u8 rx_pause_duration_low[0x20]; + + u8 tx_pause_high[0x20]; + + u8 tx_pause_low[0x20]; + + u8 tx_pause_duration_high[0x20]; + + u8 tx_pause_duration_low[0x20]; + + u8 rx_pause_transition_high[0x20]; + + u8 rx_pause_transition_low[0x20]; + + u8 reserved_2[0x400]; +}; + +struct mlx5_ifc_eth_extended_cntrs_grp_data_layout_bits { + u8 port_transmit_wait_high[0x20]; + + u8 port_transmit_wait_low[0x20]; + + u8 reserved_0[0x780]; +}; + +struct mlx5_ifc_eth_3635_cntrs_grp_data_layout_bits { + u8 dot3stats_alignment_errors_high[0x20]; + + u8 dot3stats_alignment_errors_low[0x20]; + + u8 dot3stats_fcs_errors_high[0x20]; + + u8 dot3stats_fcs_errors_low[0x20]; + + u8 dot3stats_single_collision_frames_high[0x20]; + + u8 dot3stats_single_collision_frames_low[0x20]; + + u8 dot3stats_multiple_collision_frames_high[0x20]; + + u8 dot3stats_multiple_collision_frames_low[0x20]; + + u8 dot3stats_sqe_test_errors_high[0x20]; + + u8 dot3stats_sqe_test_errors_low[0x20]; + + u8 dot3stats_deferred_transmissions_high[0x20]; + + u8 dot3stats_deferred_transmissions_low[0x20]; + + u8 dot3stats_late_collisions_high[0x20]; + + u8 dot3stats_late_collisions_low[0x20]; + + u8 dot3stats_excessive_collisions_high[0x20]; + + u8 dot3stats_excessive_collisions_low[0x20]; + + u8 dot3stats_internal_mac_transmit_errors_high[0x20]; + + u8 dot3stats_internal_mac_transmit_errors_low[0x20]; + + u8 dot3stats_carrier_sense_errors_high[0x20]; + + u8 dot3stats_carrier_sense_errors_low[0x20]; + + u8 dot3stats_frame_too_longs_high[0x20]; + + u8 dot3stats_frame_too_longs_low[0x20]; + + u8 dot3stats_internal_mac_receive_errors_high[0x20]; + + u8 dot3stats_internal_mac_receive_errors_low[0x20]; + + u8 dot3stats_symbol_errors_high[0x20]; + + u8 dot3stats_symbol_errors_low[0x20]; + + u8 dot3control_in_unknown_opcodes_high[0x20]; + + u8 dot3control_in_unknown_opcodes_low[0x20]; + + u8 dot3in_pause_frames_high[0x20]; + + u8 dot3in_pause_frames_low[0x20]; + + u8 dot3out_pause_frames_high[0x20]; + + u8 dot3out_pause_frames_low[0x20]; + + u8 reserved_0[0x3c0]; +}; + +struct mlx5_ifc_eth_2819_cntrs_grp_data_layout_bits { + u8 ether_stats_drop_events_high[0x20]; + + u8 ether_stats_drop_events_low[0x20]; + + u8 ether_stats_octets_high[0x20]; + + u8 ether_stats_octets_low[0x20]; + + u8 ether_stats_pkts_high[0x20]; + + u8 ether_stats_pkts_low[0x20]; + + u8 ether_stats_broadcast_pkts_high[0x20]; + + u8 ether_stats_broadcast_pkts_low[0x20]; + + u8 ether_stats_multicast_pkts_high[0x20]; + + u8 ether_stats_multicast_pkts_low[0x20]; + + u8 ether_stats_crc_align_errors_high[0x20]; + + u8 ether_stats_crc_align_errors_low[0x20]; + + u8 ether_stats_undersize_pkts_high[0x20]; + + u8 ether_stats_undersize_pkts_low[0x20]; + + u8 ether_stats_oversize_pkts_high[0x20]; + + u8 ether_stats_oversize_pkts_low[0x20]; + + u8 ether_stats_fragments_high[0x20]; + + u8 ether_stats_fragments_low[0x20]; + + u8 ether_stats_jabbers_high[0x20]; + + u8 ether_stats_jabbers_low[0x20]; + + u8 ether_stats_collisions_high[0x20]; + + u8 ether_stats_collisions_low[0x20]; + + u8 ether_stats_pkts64octets_high[0x20]; + + u8 ether_stats_pkts64octets_low[0x20]; + + u8 ether_stats_pkts65to127octets_high[0x20]; + + u8 ether_stats_pkts65to127octets_low[0x20]; + + u8 ether_stats_pkts128to255octets_high[0x20]; + + u8 ether_stats_pkts128to255octets_low[0x20]; + + u8 ether_stats_pkts256to511octets_high[0x20]; + + u8 ether_stats_pkts256to511octets_low[0x20]; + + u8 ether_stats_pkts512to1023octets_high[0x20]; + + u8 ether_stats_pkts512to1023octets_low[0x20]; + + u8 ether_stats_pkts1024to1518octets_high[0x20]; + + u8 ether_stats_pkts1024to1518octets_low[0x20]; + + u8 ether_stats_pkts1519to2047octets_high[0x20]; + + u8 ether_stats_pkts1519to2047octets_low[0x20]; + + u8 ether_stats_pkts2048to4095octets_high[0x20]; + + u8 ether_stats_pkts2048to4095octets_low[0x20]; + + u8 ether_stats_pkts4096to8191octets_high[0x20]; + + u8 ether_stats_pkts4096to8191octets_low[0x20]; + + u8 ether_stats_pkts8192to10239octets_high[0x20]; + + u8 ether_stats_pkts8192to10239octets_low[0x20]; + + u8 reserved_0[0x280]; +}; + +struct mlx5_ifc_eth_2863_cntrs_grp_data_layout_bits { + u8 if_in_octets_high[0x20]; + + u8 if_in_octets_low[0x20]; + + u8 if_in_ucast_pkts_high[0x20]; + + u8 if_in_ucast_pkts_low[0x20]; + + u8 if_in_discards_high[0x20]; + + u8 if_in_discards_low[0x20]; + + u8 if_in_errors_high[0x20]; + + u8 if_in_errors_low[0x20]; + + u8 if_in_unknown_protos_high[0x20]; + + u8 if_in_unknown_protos_low[0x20]; + + u8 if_out_octets_high[0x20]; + + u8 if_out_octets_low[0x20]; + + u8 if_out_ucast_pkts_high[0x20]; + + u8 if_out_ucast_pkts_low[0x20]; + + u8 if_out_discards_high[0x20]; + + u8 if_out_discards_low[0x20]; + + u8 if_out_errors_high[0x20]; + + u8 if_out_errors_low[0x20]; + + u8 if_in_multicast_pkts_high[0x20]; + + u8 if_in_multicast_pkts_low[0x20]; + + u8 if_in_broadcast_pkts_high[0x20]; + + u8 if_in_broadcast_pkts_low[0x20]; + + u8 if_out_multicast_pkts_high[0x20]; + + u8 if_out_multicast_pkts_low[0x20]; + + u8 if_out_broadcast_pkts_high[0x20]; + + u8 if_out_broadcast_pkts_low[0x20]; + + u8 reserved_0[0x480]; +}; + +struct mlx5_ifc_eth_802_3_cntrs_grp_data_layout_bits { + u8 a_frames_transmitted_ok_high[0x20]; + + u8 a_frames_transmitted_ok_low[0x20]; + + u8 a_frames_received_ok_high[0x20]; + + u8 a_frames_received_ok_low[0x20]; + + u8 a_frame_check_sequence_errors_high[0x20]; + + u8 a_frame_check_sequence_errors_low[0x20]; + + u8 a_alignment_errors_high[0x20]; + + u8 a_alignment_errors_low[0x20]; + + u8 a_octets_transmitted_ok_high[0x20]; + + u8 a_octets_transmitted_ok_low[0x20]; + + u8 a_octets_received_ok_high[0x20]; + + u8 a_octets_received_ok_low[0x20]; + + u8 a_multicast_frames_xmitted_ok_high[0x20]; + + u8 a_multicast_frames_xmitted_ok_low[0x20]; + + u8 a_broadcast_frames_xmitted_ok_high[0x20]; + + u8 a_broadcast_frames_xmitted_ok_low[0x20]; + + u8 a_multicast_frames_received_ok_high[0x20]; + + u8 a_multicast_frames_received_ok_low[0x20]; + + u8 a_broadcast_frames_received_ok_high[0x20]; + + u8 a_broadcast_frames_received_ok_low[0x20]; + + u8 a_in_range_length_errors_high[0x20]; + + u8 a_in_range_length_errors_low[0x20]; + + u8 a_out_of_range_length_field_high[0x20]; + + u8 a_out_of_range_length_field_low[0x20]; + + u8 a_frame_too_long_errors_high[0x20]; + + u8 a_frame_too_long_errors_low[0x20]; + + u8 a_symbol_error_during_carrier_high[0x20]; + + u8 a_symbol_error_during_carrier_low[0x20]; + + u8 a_mac_control_frames_transmitted_high[0x20]; + + u8 a_mac_control_frames_transmitted_low[0x20]; + + u8 a_mac_control_frames_received_high[0x20]; + + u8 a_mac_control_frames_received_low[0x20]; + + u8 a_unsupported_opcodes_received_high[0x20]; + + u8 a_unsupported_opcodes_received_low[0x20]; + + u8 a_pause_mac_ctrl_frames_received_high[0x20]; + + u8 a_pause_mac_ctrl_frames_received_low[0x20]; + + u8 a_pause_mac_ctrl_frames_transmitted_high[0x20]; + + u8 a_pause_mac_ctrl_frames_transmitted_low[0x20]; + + u8 reserved_0[0x300]; +}; + +struct mlx5_ifc_cmd_inter_comp_event_bits { + u8 command_completion_vector[0x20]; + + u8 reserved_0[0xc0]; +}; + +struct mlx5_ifc_stall_vl_event_bits { + u8 reserved_0[0x18]; + u8 port_num[0x1]; + u8 reserved_1[0x3]; + u8 vl[0x4]; + + u8 reserved_2[0xa0]; +}; + +struct mlx5_ifc_db_bf_congestion_event_bits { + u8 event_subtype[0x8]; + u8 reserved_0[0x8]; + u8 congestion_level[0x8]; + u8 reserved_1[0x8]; + + u8 reserved_2[0xa0]; +}; + +struct mlx5_ifc_gpio_event_bits { + u8 reserved_0[0x60]; + + u8 gpio_event_hi[0x20]; + + u8 gpio_event_lo[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_port_state_change_event_bits { + u8 reserved_0[0x40]; + + u8 port_num[0x4]; + u8 reserved_1[0x1c]; + + u8 reserved_2[0x80]; +}; + +struct mlx5_ifc_dropped_packet_logged_bits { + u8 reserved_0[0xe0]; +}; + +enum { + MLX5_CQ_ERROR_SYNDROME_CQ_OVERRUN = 0x1, + MLX5_CQ_ERROR_SYNDROME_CQ_ACCESS_VIOLATION_ERROR = 0x2, +}; + +struct mlx5_ifc_cq_error_bits { + u8 reserved_0[0x8]; + u8 cqn[0x18]; + + u8 reserved_1[0x20]; + + u8 reserved_2[0x18]; + u8 syndrome[0x8]; + + u8 reserved_3[0x80]; +}; + +struct mlx5_ifc_rdma_page_fault_event_bits { + u8 bytes_committed[0x20]; + + u8 r_key[0x20]; + + u8 reserved_0[0x10]; + u8 packet_len[0x10]; + + u8 rdma_op_len[0x20]; + + u8 rdma_va[0x40]; + + u8 reserved_1[0x5]; + u8 rdma[0x1]; + u8 write[0x1]; + u8 requestor[0x1]; + u8 qp_number[0x18]; +}; + +struct mlx5_ifc_wqe_associated_page_fault_event_bits { + u8 bytes_committed[0x20]; + + u8 reserved_0[0x10]; + u8 wqe_index[0x10]; + + u8 reserved_1[0x10]; + u8 len[0x10]; + + u8 reserved_2[0x60]; + + u8 reserved_3[0x5]; + u8 rdma[0x1]; + u8 write_read[0x1]; + u8 requestor[0x1]; + u8 qpn[0x18]; +}; + +struct mlx5_ifc_qp_events_bits { + u8 reserved_0[0xa0]; + + u8 type[0x8]; + u8 reserved_1[0x18]; + + u8 reserved_2[0x8]; + u8 qpn_rqn_sqn[0x18]; +}; + +struct mlx5_ifc_dct_events_bits { + u8 reserved_0[0xc0]; + + u8 reserved_1[0x8]; + u8 dct_number[0x18]; +}; + +struct mlx5_ifc_comp_event_bits { + u8 reserved_0[0xc0]; + + u8 reserved_1[0x8]; + u8 cq_number[0x18]; +}; + +enum { + MLX5_QPC_STATE_RST = 0x0, + MLX5_QPC_STATE_INIT = 0x1, + MLX5_QPC_STATE_RTR = 0x2, + MLX5_QPC_STATE_RTS = 0x3, + MLX5_QPC_STATE_SQER = 0x4, + MLX5_QPC_STATE_ERR = 0x6, + MLX5_QPC_STATE_SQD = 0x7, + MLX5_QPC_STATE_SUSPENDED = 0x9, +}; + +enum { + MLX5_QPC_ST_RC = 0x0, + MLX5_QPC_ST_UC = 0x1, + MLX5_QPC_ST_UD = 0x2, + MLX5_QPC_ST_XRC = 0x3, + MLX5_QPC_ST_DCI = 0x5, + MLX5_QPC_ST_QP0 = 0x7, + MLX5_QPC_ST_QP1 = 0x8, + MLX5_QPC_ST_RAW_DATAGRAM = 0x9, + MLX5_QPC_ST_REG_UMR = 0xc, +}; + +enum { + MLX5_QPC_PM_STATE_ARMED = 0x0, + MLX5_QPC_PM_STATE_REARM = 0x1, + MLX5_QPC_PM_STATE_RESERVED = 0x2, + MLX5_QPC_PM_STATE_MIGRATED = 0x3, +}; + +enum { + MLX5_QPC_END_PADDING_MODE_SCATTER_AS_IS = 0x0, + MLX5_QPC_END_PADDING_MODE_PAD_TO_CACHE_LINE_ALIGNMENT = 0x1, +}; + +enum { + MLX5_QPC_MTU_256_BYTES = 0x1, + MLX5_QPC_MTU_512_BYTES = 0x2, + MLX5_QPC_MTU_1K_BYTES = 0x3, + MLX5_QPC_MTU_2K_BYTES = 0x4, + MLX5_QPC_MTU_4K_BYTES = 0x5, + MLX5_QPC_MTU_RAW_ETHERNET_QP = 0x7, +}; + +enum { + MLX5_QPC_ATOMIC_MODE_IB_SPEC = 0x1, + MLX5_QPC_ATOMIC_MODE_ONLY_8B = 0x2, + MLX5_QPC_ATOMIC_MODE_UP_TO_8B = 0x3, + MLX5_QPC_ATOMIC_MODE_UP_TO_16B = 0x4, + MLX5_QPC_ATOMIC_MODE_UP_TO_32B = 0x5, + MLX5_QPC_ATOMIC_MODE_UP_TO_64B = 0x6, + MLX5_QPC_ATOMIC_MODE_UP_TO_128B = 0x7, + MLX5_QPC_ATOMIC_MODE_UP_TO_256B = 0x8, +}; + +enum { + MLX5_QPC_CS_REQ_DISABLE = 0x0, + MLX5_QPC_CS_REQ_UP_TO_32B = 0x11, + MLX5_QPC_CS_REQ_UP_TO_64B = 0x22, +}; + +enum { + MLX5_QPC_CS_RES_DISABLE = 0x0, + MLX5_QPC_CS_RES_UP_TO_32B = 0x1, + MLX5_QPC_CS_RES_UP_TO_64B = 0x2, +}; + +struct mlx5_ifc_qpc_bits { + u8 state[0x4]; + u8 reserved_0[0x4]; + u8 st[0x8]; + u8 reserved_1[0x3]; + u8 pm_state[0x2]; + u8 reserved_2[0x7]; + u8 end_padding_mode[0x2]; + u8 reserved_3[0x2]; + + u8 wq_signature[0x1]; + u8 block_lb_mc[0x1]; + u8 atomic_like_write_en[0x1]; + u8 latency_sensitive[0x1]; + u8 reserved_4[0x1]; + u8 drain_sigerr[0x1]; + u8 reserved_5[0x2]; + u8 pd[0x18]; + + u8 mtu[0x3]; + u8 log_msg_max[0x5]; + u8 reserved_6[0x1]; + u8 log_rq_size[0x4]; + u8 log_rq_stride[0x3]; + u8 no_sq[0x1]; + u8 log_sq_size[0x4]; + u8 reserved_7[0x6]; + u8 rlky[0x1]; + u8 reserved_8[0x4]; + + u8 counter_set_id[0x8]; + u8 uar_page[0x18]; + + u8 reserved_9[0x8]; + u8 user_index[0x18]; + + u8 reserved_10[0x3]; + u8 log_page_size[0x5]; + u8 remote_qpn[0x18]; + + struct mlx5_ifc_ads_bits primary_address_path; + + struct mlx5_ifc_ads_bits secondary_address_path; + + u8 log_ack_req_freq[0x4]; + u8 reserved_11[0x4]; + u8 log_sra_max[0x3]; + u8 reserved_12[0x2]; + u8 retry_count[0x3]; + u8 rnr_retry[0x3]; + u8 reserved_13[0x1]; + u8 fre[0x1]; + u8 cur_rnr_retry[0x3]; + u8 cur_retry_count[0x3]; + u8 reserved_14[0x5]; + + u8 reserved_15[0x20]; + + u8 reserved_16[0x8]; + u8 next_send_psn[0x18]; + + u8 reserved_17[0x8]; + u8 cqn_snd[0x18]; + + u8 reserved_18[0x40]; + + u8 reserved_19[0x8]; + u8 last_acked_psn[0x18]; + + u8 reserved_20[0x8]; + u8 ssn[0x18]; + + u8 reserved_21[0x8]; + u8 log_rra_max[0x3]; + u8 reserved_22[0x1]; + u8 atomic_mode[0x4]; + u8 rre[0x1]; + u8 rwe[0x1]; + u8 rae[0x1]; + u8 reserved_23[0x1]; + u8 page_offset[0x6]; + u8 reserved_24[0x3]; + u8 cd_slave_receive[0x1]; + u8 cd_slave_send[0x1]; + u8 cd_master[0x1]; + + u8 reserved_25[0x3]; + u8 min_rnr_nak[0x5]; + u8 next_rcv_psn[0x18]; + + u8 reserved_26[0x8]; + u8 xrcd[0x18]; + + u8 reserved_27[0x8]; + u8 cqn_rcv[0x18]; + + u8 dbr_addr[0x40]; + + u8 q_key[0x20]; + + u8 reserved_28[0x5]; + u8 rq_type[0x3]; + u8 srqn_rmpn[0x18]; + + u8 reserved_29[0x8]; + u8 rmsn[0x18]; + + u8 hw_sq_wqebb_counter[0x10]; + u8 sw_sq_wqebb_counter[0x10]; + + u8 hw_rq_counter[0x20]; + + u8 sw_rq_counter[0x20]; + + u8 reserved_30[0x20]; + + u8 reserved_31[0xf]; + u8 cgs[0x1]; + u8 cs_req[0x8]; + u8 cs_res[0x8]; + + u8 dc_access_key[0x40]; + + u8 reserved_32[0xc0]; +}; + +struct mlx5_ifc_roce_addr_layout_bits { + u8 source_l3_address[16][0x8]; + + u8 reserved_0[0x3]; + u8 vlan_valid[0x1]; + u8 vlan_id[0xc]; + u8 source_mac_47_32[0x10]; + + u8 source_mac_31_0[0x20]; + + u8 reserved_1[0x14]; + u8 roce_l3_type[0x4]; + u8 roce_version[0x8]; + + u8 reserved_2[0x20]; +}; + +union mlx5_ifc_hca_cap_union_bits { + struct mlx5_ifc_cmd_hca_cap_bits cmd_hca_cap; + struct mlx5_ifc_odp_cap_bits odp_cap; + struct mlx5_ifc_atomic_caps_bits atomic_caps; + struct mlx5_ifc_roce_cap_bits roce_cap; + struct mlx5_ifc_per_protocol_networking_offload_caps_bits per_protocol_networking_offload_caps; + struct mlx5_ifc_flow_table_nic_cap_bits flow_table_nic_cap; + u8 reserved_0[0x8000]; +}; + +enum { + MLX5_FLOW_CONTEXT_ACTION_ALLOW = 0x1, + MLX5_FLOW_CONTEXT_ACTION_DROP = 0x2, + MLX5_FLOW_CONTEXT_ACTION_FWD_DEST = 0x4, +}; + +struct mlx5_ifc_flow_context_bits { + u8 reserved_0[0x20]; + + u8 group_id[0x20]; + + u8 reserved_1[0x8]; + u8 flow_tag[0x18]; + + u8 reserved_2[0x10]; + u8 action[0x10]; + + u8 reserved_3[0x8]; + u8 destination_list_size[0x18]; + + u8 reserved_4[0x160]; + + struct mlx5_ifc_fte_match_param_bits match_value; + + u8 reserved_5[0x600]; + + struct mlx5_ifc_dest_format_struct_bits destination[0]; +}; + +enum { + MLX5_XRC_SRQC_STATE_GOOD = 0x0, + MLX5_XRC_SRQC_STATE_ERROR = 0x1, +}; + +struct mlx5_ifc_xrc_srqc_bits { + u8 state[0x4]; + u8 log_xrc_srq_size[0x4]; + u8 reserved_0[0x18]; + + u8 wq_signature[0x1]; + u8 cont_srq[0x1]; + u8 reserved_1[0x1]; + u8 rlky[0x1]; + u8 basic_cyclic_rcv_wqe[0x1]; + u8 log_rq_stride[0x3]; + u8 xrcd[0x18]; + + u8 page_offset[0x6]; + u8 reserved_2[0x2]; + u8 cqn[0x18]; + + u8 reserved_3[0x20]; + + u8 user_index_equal_xrc_srqn[0x1]; + u8 reserved_4[0x1]; + u8 log_page_size[0x6]; + u8 user_index[0x18]; + + u8 reserved_5[0x20]; + + u8 reserved_6[0x8]; + u8 pd[0x18]; + + u8 lwm[0x10]; + u8 wqe_cnt[0x10]; + + u8 reserved_7[0x40]; + + u8 db_record_addr_h[0x20]; + + u8 db_record_addr_l[0x1e]; + u8 reserved_8[0x2]; + + u8 reserved_9[0x80]; +}; + +struct mlx5_ifc_traffic_counter_bits { + u8 packets[0x40]; + + u8 octets[0x40]; +}; + +struct mlx5_ifc_tisc_bits { + u8 reserved_0[0xc]; + u8 prio[0x4]; + u8 reserved_1[0x10]; + + u8 reserved_2[0x100]; + + u8 reserved_3[0x8]; + u8 transport_domain[0x18]; + + u8 reserved_4[0x3c0]; +}; + +enum { + MLX5_TIRC_DISP_TYPE_DIRECT = 0x0, + MLX5_TIRC_DISP_TYPE_INDIRECT = 0x1, +}; + +enum { + MLX5_TIRC_LRO_ENABLE_MASK_IPV4_LRO = 0x1, + MLX5_TIRC_LRO_ENABLE_MASK_IPV6_LRO = 0x2, +}; + +enum { + MLX5_TIRC_RX_HASH_FN_HASH_NONE = 0x0, + MLX5_TIRC_RX_HASH_FN_HASH_INVERTED_XOR8 = 0x1, + MLX5_TIRC_RX_HASH_FN_HASH_TOEPLITZ = 0x2, +}; + +enum { + MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST_ = 0x1, + MLX5_TIRC_SELF_LB_BLOCK_BLOCK_MULTICAST_ = 0x2, +}; + +struct mlx5_ifc_tirc_bits { + u8 reserved_0[0x20]; + + u8 disp_type[0x4]; + u8 reserved_1[0x1c]; + + u8 reserved_2[0x40]; + + u8 reserved_3[0x4]; + u8 lro_timeout_period_usecs[0x10]; + u8 lro_enable_mask[0x4]; + u8 lro_max_ip_payload_size[0x8]; + + u8 reserved_4[0x40]; + + u8 reserved_5[0x8]; + u8 inline_rqn[0x18]; + + u8 rx_hash_symmetric[0x1]; + u8 reserved_6[0x1]; + u8 tunneled_offload_en[0x1]; + u8 reserved_7[0x5]; + u8 indirect_table[0x18]; + + u8 rx_hash_fn[0x4]; + u8 reserved_8[0x2]; + u8 self_lb_block[0x2]; + u8 transport_domain[0x18]; + + u8 rx_hash_toeplitz_key[10][0x20]; + + struct mlx5_ifc_rx_hash_field_select_bits rx_hash_field_selector_outer; + + struct mlx5_ifc_rx_hash_field_select_bits rx_hash_field_selector_inner; + + u8 reserved_9[0x4c0]; +}; + +enum { + MLX5_SRQC_STATE_GOOD = 0x0, + MLX5_SRQC_STATE_ERROR = 0x1, +}; + +struct mlx5_ifc_srqc_bits { + u8 state[0x4]; + u8 log_srq_size[0x4]; + u8 reserved_0[0x18]; + + u8 wq_signature[0x1]; + u8 cont_srq[0x1]; + u8 reserved_1[0x1]; + u8 rlky[0x1]; + u8 reserved_2[0x1]; + u8 log_rq_stride[0x3]; + u8 xrcd[0x18]; + + u8 page_offset[0x6]; + u8 reserved_3[0x2]; + u8 cqn[0x18]; + + u8 reserved_4[0x20]; + + u8 reserved_5[0x2]; + u8 log_page_size[0x6]; + u8 reserved_6[0x18]; + + u8 reserved_7[0x20]; + + u8 reserved_8[0x8]; + u8 pd[0x18]; + + u8 lwm[0x10]; + u8 wqe_cnt[0x10]; + + u8 reserved_9[0x40]; + + u8 db_record_addr_h[0x20]; + + u8 db_record_addr_l[0x1e]; + u8 reserved_10[0x2]; + + u8 reserved_11[0x80]; +}; + +enum { + MLX5_SQC_STATE_RST = 0x0, + MLX5_SQC_STATE_RDY = 0x1, + MLX5_SQC_STATE_ERR = 0x3, +}; + +struct mlx5_ifc_sqc_bits { + u8 rlky[0x1]; + u8 cd_master[0x1]; + u8 fre[0x1]; + u8 flush_in_error_en[0x1]; + u8 reserved_0[0x4]; + u8 state[0x4]; + u8 reserved_1[0x14]; + + u8 reserved_2[0x8]; + u8 user_index[0x18]; + + u8 reserved_3[0x8]; + u8 cqn[0x18]; + + u8 reserved_4[0xa0]; + + u8 tis_lst_sz[0x10]; + u8 reserved_5[0x10]; + + u8 reserved_6[0x40]; + + u8 reserved_7[0x8]; + u8 tis_num_0[0x18]; + + struct mlx5_ifc_wq_bits wq; +}; + +struct mlx5_ifc_rqtc_bits { + u8 reserved_0[0xa0]; + + u8 reserved_1[0x10]; + u8 rqt_max_size[0x10]; + + u8 reserved_2[0x10]; + u8 rqt_actual_size[0x10]; + + u8 reserved_3[0x6a0]; + + struct mlx5_ifc_rq_num_bits rq_num[0]; +}; + +enum { + MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_INLINE = 0x0, + MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_RMP = 0x1, +}; + +enum { + MLX5_RQC_STATE_RST = 0x0, + MLX5_RQC_STATE_RDY = 0x1, + MLX5_RQC_STATE_ERR = 0x3, +}; + +struct mlx5_ifc_rqc_bits { + u8 rlky[0x1]; + u8 reserved_0[0x2]; + u8 vsd[0x1]; + u8 mem_rq_type[0x4]; + u8 state[0x4]; + u8 reserved_1[0x1]; + u8 flush_in_error_en[0x1]; + u8 reserved_2[0x12]; + + u8 reserved_3[0x8]; + u8 user_index[0x18]; + + u8 reserved_4[0x8]; + u8 cqn[0x18]; + + u8 counter_set_id[0x8]; + u8 reserved_5[0x18]; + + u8 reserved_6[0x8]; + u8 rmpn[0x18]; + + u8 reserved_7[0xe0]; + + struct mlx5_ifc_wq_bits wq; +}; + +enum { + MLX5_RMPC_STATE_RDY = 0x1, + MLX5_RMPC_STATE_ERR = 0x3, +}; + +struct mlx5_ifc_rmpc_bits { + u8 reserved_0[0x8]; + u8 state[0x4]; + u8 reserved_1[0x14]; + + u8 basic_cyclic_rcv_wqe[0x1]; + u8 reserved_2[0x1f]; + + u8 reserved_3[0x140]; + + struct mlx5_ifc_wq_bits wq; +}; + +enum { + MLX5_NIC_VPORT_CONTEXT_ALLOWED_LIST_TYPE_CURRENT_UC_MAC_ADDRESS = 0x0, +}; + +struct mlx5_ifc_nic_vport_context_bits { + u8 reserved_0[0x1f]; + u8 roce_en[0x1]; + + u8 reserved_1[0x760]; + + u8 reserved_2[0x5]; + u8 allowed_list_type[0x3]; + u8 reserved_3[0xc]; + u8 allowed_list_size[0xc]; + + struct mlx5_ifc_mac_address_layout_bits permanent_address; + + u8 reserved_4[0x20]; + + u8 current_uc_mac_address[0][0x40]; +}; + +enum { + MLX5_MKC_ACCESS_MODE_PA = 0x0, + MLX5_MKC_ACCESS_MODE_MTT = 0x1, + MLX5_MKC_ACCESS_MODE_KLMS = 0x2, +}; + +struct mlx5_ifc_mkc_bits { + u8 reserved_0[0x1]; + u8 free[0x1]; + u8 reserved_1[0xd]; + u8 small_fence_on_rdma_read_response[0x1]; + u8 umr_en[0x1]; + u8 a[0x1]; + u8 rw[0x1]; + u8 rr[0x1]; + u8 lw[0x1]; + u8 lr[0x1]; + u8 access_mode[0x2]; + u8 reserved_2[0x8]; + + u8 qpn[0x18]; + u8 mkey_7_0[0x8]; + + u8 reserved_3[0x20]; + + u8 length64[0x1]; + u8 bsf_en[0x1]; + u8 sync_umr[0x1]; + u8 reserved_4[0x2]; + u8 expected_sigerr_count[0x1]; + u8 reserved_5[0x1]; + u8 en_rinval[0x1]; + u8 pd[0x18]; + + u8 start_addr[0x40]; + + u8 len[0x40]; + + u8 bsf_octword_size[0x20]; + + u8 reserved_6[0x80]; + + u8 translations_octword_size[0x20]; + + u8 reserved_7[0x1b]; + u8 log_page_size[0x5]; + + u8 reserved_8[0x20]; +}; + +struct mlx5_ifc_pkey_bits { + u8 reserved_0[0x10]; + u8 pkey[0x10]; +}; + +struct mlx5_ifc_array128_auto_bits { + u8 array128_auto[16][0x8]; +}; + +struct mlx5_ifc_hca_vport_context_bits { + u8 field_select[0x20]; + + u8 reserved_0[0xe0]; + + u8 sm_virt_aware[0x1]; + u8 has_smi[0x1]; + u8 has_raw[0x1]; + u8 grh_required[0x1]; + u8 reserved_1[0x10]; + u8 port_state_policy[0x4]; + u8 phy_port_state[0x4]; + u8 vport_state[0x4]; + + u8 reserved_2[0x60]; + + u8 port_guid[0x40]; + + u8 node_guid[0x40]; + + u8 cap_mask1[0x20]; + + u8 cap_mask1_field_select[0x20]; + + u8 cap_mask2[0x20]; + + u8 cap_mask2_field_select[0x20]; + + u8 reserved_3[0x80]; + + u8 lid[0x10]; + u8 reserved_4[0x4]; + u8 init_type_reply[0x4]; + u8 lmc[0x3]; + u8 subnet_timeout[0x5]; + + u8 sm_lid[0x10]; + u8 sm_sl[0x4]; + u8 reserved_5[0xc]; + + u8 qkey_violation_counter[0x10]; + u8 pkey_violation_counter[0x10]; + + u8 reserved_6[0xca0]; +}; + +enum { + MLX5_EQC_STATUS_OK = 0x0, + MLX5_EQC_STATUS_EQ_WRITE_FAILURE = 0xa, +}; + +enum { + MLX5_EQC_ST_ARMED = 0x9, + MLX5_EQC_ST_FIRED = 0xa, +}; + +struct mlx5_ifc_eqc_bits { + u8 status[0x4]; + u8 reserved_0[0x9]; + u8 ec[0x1]; + u8 oi[0x1]; + u8 reserved_1[0x5]; + u8 st[0x4]; + u8 reserved_2[0x8]; + + u8 reserved_3[0x20]; + + u8 reserved_4[0x14]; + u8 page_offset[0x6]; + u8 reserved_5[0x6]; + + u8 reserved_6[0x3]; + u8 log_eq_size[0x5]; + u8 uar_page[0x18]; + + u8 reserved_7[0x20]; + + u8 reserved_8[0x18]; + u8 intr[0x8]; + + u8 reserved_9[0x3]; + u8 log_page_size[0x5]; + u8 reserved_10[0x18]; + + u8 reserved_11[0x60]; + + u8 reserved_12[0x8]; + u8 consumer_counter[0x18]; + + u8 reserved_13[0x8]; + u8 producer_counter[0x18]; + + u8 reserved_14[0x80]; +}; + +enum { + MLX5_DCTC_STATE_ACTIVE = 0x0, + MLX5_DCTC_STATE_DRAINING = 0x1, + MLX5_DCTC_STATE_DRAINED = 0x2, +}; + +enum { + MLX5_DCTC_CS_RES_DISABLE = 0x0, + MLX5_DCTC_CS_RES_NA = 0x1, + MLX5_DCTC_CS_RES_UP_TO_64B = 0x2, +}; + +enum { + MLX5_DCTC_MTU_256_BYTES = 0x1, + MLX5_DCTC_MTU_512_BYTES = 0x2, + MLX5_DCTC_MTU_1K_BYTES = 0x3, + MLX5_DCTC_MTU_2K_BYTES = 0x4, + MLX5_DCTC_MTU_4K_BYTES = 0x5, +}; + +struct mlx5_ifc_dctc_bits { + u8 reserved_0[0x4]; + u8 state[0x4]; + u8 reserved_1[0x18]; + + u8 reserved_2[0x8]; + u8 user_index[0x18]; + + u8 reserved_3[0x8]; + u8 cqn[0x18]; + + u8 counter_set_id[0x8]; + u8 atomic_mode[0x4]; + u8 rre[0x1]; + u8 rwe[0x1]; + u8 rae[0x1]; + u8 atomic_like_write_en[0x1]; + u8 latency_sensitive[0x1]; + u8 rlky[0x1]; + u8 free_ar[0x1]; + u8 reserved_4[0xd]; + + u8 reserved_5[0x8]; + u8 cs_res[0x8]; + u8 reserved_6[0x3]; + u8 min_rnr_nak[0x5]; + u8 reserved_7[0x8]; + + u8 reserved_8[0x8]; + u8 srqn[0x18]; + + u8 reserved_9[0x8]; + u8 pd[0x18]; + + u8 tclass[0x8]; + u8 reserved_10[0x4]; + u8 flow_label[0x14]; + + u8 dc_access_key[0x40]; + + u8 reserved_11[0x5]; + u8 mtu[0x3]; + u8 port[0x8]; + u8 pkey_index[0x10]; + + u8 reserved_12[0x8]; + u8 my_addr_index[0x8]; + u8 reserved_13[0x8]; + u8 hop_limit[0x8]; + + u8 dc_access_key_violation_count[0x20]; + + u8 reserved_14[0x14]; + u8 dei_cfi[0x1]; + u8 eth_prio[0x3]; + u8 ecn[0x2]; + u8 dscp[0x6]; + + u8 reserved_15[0x40]; +}; + +enum { + MLX5_CQC_STATUS_OK = 0x0, + MLX5_CQC_STATUS_CQ_OVERFLOW = 0x9, + MLX5_CQC_STATUS_CQ_WRITE_FAIL = 0xa, +}; + +enum { + MLX5_CQC_CQE_SZ_64_BYTES = 0x0, + MLX5_CQC_CQE_SZ_128_BYTES = 0x1, +}; + +enum { + MLX5_CQC_ST_SOLICITED_NOTIFICATION_REQUEST_ARMED = 0x6, + MLX5_CQC_ST_NOTIFICATION_REQUEST_ARMED = 0x9, + MLX5_CQC_ST_FIRED = 0xa, +}; + +struct mlx5_ifc_cqc_bits { + u8 status[0x4]; + u8 reserved_0[0x4]; + u8 cqe_sz[0x3]; + u8 cc[0x1]; + u8 reserved_1[0x1]; + u8 scqe_break_moderation_en[0x1]; + u8 oi[0x1]; + u8 reserved_2[0x2]; + u8 cqe_zip_en[0x1]; + u8 mini_cqe_res_format[0x2]; + u8 st[0x4]; + u8 reserved_3[0x8]; + + u8 reserved_4[0x20]; + + u8 reserved_5[0x14]; + u8 page_offset[0x6]; + u8 reserved_6[0x6]; + + u8 reserved_7[0x3]; + u8 log_cq_size[0x5]; + u8 uar_page[0x18]; + + u8 reserved_8[0x4]; + u8 cq_period[0xc]; + u8 cq_max_count[0x10]; + + u8 reserved_9[0x18]; + u8 c_eqn[0x8]; + + u8 reserved_10[0x3]; + u8 log_page_size[0x5]; + u8 reserved_11[0x18]; + + u8 reserved_12[0x20]; + + u8 reserved_13[0x8]; + u8 last_notified_index[0x18]; + + u8 reserved_14[0x8]; + u8 last_solicit_index[0x18]; + + u8 reserved_15[0x8]; + u8 consumer_counter[0x18]; + + u8 reserved_16[0x8]; + u8 producer_counter[0x18]; + + u8 reserved_17[0x40]; + + u8 dbr_addr[0x40]; +}; + +union mlx5_ifc_cong_control_roce_ecn_auto_bits { + struct mlx5_ifc_cong_control_802_1qau_rp_bits cong_control_802_1qau_rp; + struct mlx5_ifc_cong_control_r_roce_ecn_rp_bits cong_control_r_roce_ecn_rp; + struct mlx5_ifc_cong_control_r_roce_ecn_np_bits cong_control_r_roce_ecn_np; + u8 reserved_0[0x800]; +}; + +struct mlx5_ifc_query_adapter_param_block_bits { + u8 reserved_0[0xe0]; + + u8 reserved_1[0x10]; + u8 vsd_vendor_id[0x10]; + + u8 vsd[208][0x8]; + + u8 vsd_contd_psid[16][0x8]; +}; + +union mlx5_ifc_modify_field_select_resize_field_select_auto_bits { + struct mlx5_ifc_modify_field_select_bits modify_field_select; + struct mlx5_ifc_resize_field_select_bits resize_field_select; + u8 reserved_0[0x20]; +}; + +union mlx5_ifc_field_select_802_1_r_roce_auto_bits { + struct mlx5_ifc_field_select_802_1qau_rp_bits field_select_802_1qau_rp; + struct mlx5_ifc_field_select_r_roce_rp_bits field_select_r_roce_rp; + struct mlx5_ifc_field_select_r_roce_np_bits field_select_r_roce_np; + u8 reserved_0[0x20]; +}; + +union mlx5_ifc_eth_cntrs_grp_data_layout_auto_bits { + struct mlx5_ifc_eth_802_3_cntrs_grp_data_layout_bits eth_802_3_cntrs_grp_data_layout; + struct mlx5_ifc_eth_2863_cntrs_grp_data_layout_bits eth_2863_cntrs_grp_data_layout; + struct mlx5_ifc_eth_2819_cntrs_grp_data_layout_bits eth_2819_cntrs_grp_data_layout; + struct mlx5_ifc_eth_3635_cntrs_grp_data_layout_bits eth_3635_cntrs_grp_data_layout; + struct mlx5_ifc_eth_extended_cntrs_grp_data_layout_bits eth_extended_cntrs_grp_data_layout; + struct mlx5_ifc_eth_per_prio_grp_data_layout_bits eth_per_prio_grp_data_layout; + struct mlx5_ifc_eth_per_traffic_grp_data_layout_bits eth_per_traffic_grp_data_layout; + struct mlx5_ifc_phys_layer_cntrs_bits phys_layer_cntrs; + u8 reserved_0[0x7c0]; +}; + +union mlx5_ifc_event_auto_bits { + struct mlx5_ifc_comp_event_bits comp_event; + struct mlx5_ifc_dct_events_bits dct_events; + struct mlx5_ifc_qp_events_bits qp_events; + struct mlx5_ifc_wqe_associated_page_fault_event_bits wqe_associated_page_fault_event; + struct mlx5_ifc_rdma_page_fault_event_bits rdma_page_fault_event; + struct mlx5_ifc_cq_error_bits cq_error; + struct mlx5_ifc_dropped_packet_logged_bits dropped_packet_logged; + struct mlx5_ifc_port_state_change_event_bits port_state_change_event; + struct mlx5_ifc_gpio_event_bits gpio_event; + struct mlx5_ifc_db_bf_congestion_event_bits db_bf_congestion_event; + struct mlx5_ifc_stall_vl_event_bits stall_vl_event; + struct mlx5_ifc_cmd_inter_comp_event_bits cmd_inter_comp_event; + u8 reserved_0[0xe0]; +}; + +struct mlx5_ifc_health_buffer_bits { + u8 reserved_0[0x100]; + + u8 assert_existptr[0x20]; + + u8 assert_callra[0x20]; + + u8 reserved_1[0x40]; + + u8 fw_version[0x20]; + + u8 hw_id[0x20]; + + u8 reserved_2[0x20]; + + u8 irisc_index[0x8]; + u8 synd[0x8]; + u8 ext_synd[0x10]; +}; + +struct mlx5_ifc_register_loopback_control_bits { + u8 no_lb[0x1]; + u8 reserved_0[0x7]; + u8 port[0x8]; + u8 reserved_1[0x10]; + + u8 reserved_2[0x60]; +}; + +struct mlx5_ifc_teardown_hca_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +enum { + MLX5_TEARDOWN_HCA_IN_PROFILE_GRACEFUL_CLOSE = 0x0, + MLX5_TEARDOWN_HCA_IN_PROFILE_PANIC_CLOSE = 0x1, +}; + +struct mlx5_ifc_teardown_hca_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x10]; + u8 profile[0x10]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_sqerr2rts_qp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_sqerr2rts_qp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; + + u8 opt_param_mask[0x20]; + + u8 reserved_4[0x20]; + + struct mlx5_ifc_qpc_bits qpc; + + u8 reserved_5[0x80]; +}; + +struct mlx5_ifc_sqd2rts_qp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_sqd2rts_qp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; + + u8 opt_param_mask[0x20]; + + u8 reserved_4[0x20]; + + struct mlx5_ifc_qpc_bits qpc; + + u8 reserved_5[0x80]; +}; + +struct mlx5_ifc_set_roce_address_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_set_roce_address_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 roce_address_index[0x10]; + u8 reserved_2[0x10]; + + u8 reserved_3[0x20]; + + struct mlx5_ifc_roce_addr_layout_bits roce_address; +}; + +struct mlx5_ifc_set_mad_demux_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +enum { + MLX5_SET_MAD_DEMUX_IN_DEMUX_MODE_PASS_ALL = 0x0, + MLX5_SET_MAD_DEMUX_IN_DEMUX_MODE_SELECTIVE = 0x2, +}; + +struct mlx5_ifc_set_mad_demux_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x20]; + + u8 reserved_3[0x6]; + u8 demux_mode[0x2]; + u8 reserved_4[0x18]; +}; + +struct mlx5_ifc_set_l2_table_entry_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_set_l2_table_entry_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x60]; + + u8 reserved_3[0x8]; + u8 table_index[0x18]; + + u8 reserved_4[0x20]; + + u8 reserved_5[0x13]; + u8 vlan_valid[0x1]; + u8 vlan[0xc]; + + struct mlx5_ifc_mac_address_layout_bits mac_address; + + u8 reserved_6[0xc0]; +}; + +struct mlx5_ifc_set_issi_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_set_issi_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x10]; + u8 current_issi[0x10]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_set_hca_cap_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_set_hca_cap_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + union mlx5_ifc_hca_cap_union_bits capability; +}; + +struct mlx5_ifc_set_fte_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_set_fte_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + u8 table_type[0x8]; + u8 reserved_3[0x18]; + + u8 reserved_4[0x8]; + u8 table_id[0x18]; + + u8 reserved_5[0x40]; + + u8 flow_index[0x20]; + + u8 reserved_6[0xe0]; + + struct mlx5_ifc_flow_context_bits flow_context; +}; + +struct mlx5_ifc_rts2rts_qp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_rts2rts_qp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; + + u8 opt_param_mask[0x20]; + + u8 reserved_4[0x20]; + + struct mlx5_ifc_qpc_bits qpc; + + u8 reserved_5[0x80]; +}; + +struct mlx5_ifc_rtr2rts_qp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_rtr2rts_qp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; + + u8 opt_param_mask[0x20]; + + u8 reserved_4[0x20]; + + struct mlx5_ifc_qpc_bits qpc; + + u8 reserved_5[0x80]; +}; + +struct mlx5_ifc_rst2init_qp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_rst2init_qp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; + + u8 opt_param_mask[0x20]; + + u8 reserved_4[0x20]; + + struct mlx5_ifc_qpc_bits qpc; + + u8 reserved_5[0x80]; +}; + +struct mlx5_ifc_query_xrc_srq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + struct mlx5_ifc_xrc_srqc_bits xrc_srq_context_entry; + + u8 reserved_2[0x600]; + + u8 pas[0][0x40]; +}; + +struct mlx5_ifc_query_xrc_srq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 xrc_srqn[0x18]; + + u8 reserved_3[0x20]; +}; + +enum { + MLX5_QUERY_VPORT_STATE_OUT_STATE_DOWN = 0x0, + MLX5_QUERY_VPORT_STATE_OUT_STATE_UP = 0x1, +}; + +struct mlx5_ifc_query_vport_state_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x20]; + + u8 reserved_2[0x18]; + u8 admin_state[0x4]; + u8 state[0x4]; +}; + +enum { + MLX5_QUERY_VPORT_STATE_IN_OP_MOD_VNIC_VPORT = 0x0, +}; + +struct mlx5_ifc_query_vport_state_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 other_vport[0x1]; + u8 reserved_2[0xf]; + u8 vport_number[0x10]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_vport_counter_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + struct mlx5_ifc_traffic_counter_bits received_errors; + + struct mlx5_ifc_traffic_counter_bits transmit_errors; + + struct mlx5_ifc_traffic_counter_bits received_ib_unicast; + + struct mlx5_ifc_traffic_counter_bits transmitted_ib_unicast; + + struct mlx5_ifc_traffic_counter_bits received_ib_multicast; + + struct mlx5_ifc_traffic_counter_bits transmitted_ib_multicast; + + struct mlx5_ifc_traffic_counter_bits received_eth_broadcast; + + struct mlx5_ifc_traffic_counter_bits transmitted_eth_broadcast; + + struct mlx5_ifc_traffic_counter_bits received_eth_unicast; + + struct mlx5_ifc_traffic_counter_bits transmitted_eth_unicast; + + struct mlx5_ifc_traffic_counter_bits received_eth_multicast; + + struct mlx5_ifc_traffic_counter_bits transmitted_eth_multicast; + + u8 reserved_2[0xa00]; +}; + +enum { + MLX5_QUERY_VPORT_COUNTER_IN_OP_MOD_VPORT_COUNTERS = 0x0, +}; + +struct mlx5_ifc_query_vport_counter_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 other_vport[0x1]; + u8 reserved_2[0xf]; + u8 vport_number[0x10]; + + u8 reserved_3[0x60]; + + u8 clear[0x1]; + u8 reserved_4[0x1f]; + + u8 reserved_5[0x20]; +}; + +struct mlx5_ifc_query_tis_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + struct mlx5_ifc_tisc_bits tis_context; +}; + +struct mlx5_ifc_query_tis_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 tisn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_tir_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0xc0]; + + struct mlx5_ifc_tirc_bits tir_context; +}; + +struct mlx5_ifc_query_tir_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 tirn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_srq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + struct mlx5_ifc_srqc_bits srq_context_entry; + + u8 reserved_2[0x600]; + + u8 pas[0][0x40]; +}; + +struct mlx5_ifc_query_srq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 srqn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_sq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0xc0]; + + struct mlx5_ifc_sqc_bits sq_context; +}; + +struct mlx5_ifc_query_sq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 sqn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_special_contexts_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x20]; + + u8 resd_lkey[0x20]; +}; + +struct mlx5_ifc_query_special_contexts_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_query_rqt_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0xc0]; + + struct mlx5_ifc_rqtc_bits rqt_context; +}; + +struct mlx5_ifc_query_rqt_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 rqtn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_rq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0xc0]; + + struct mlx5_ifc_rqc_bits rq_context; +}; + +struct mlx5_ifc_query_rq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 rqn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_roce_address_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + struct mlx5_ifc_roce_addr_layout_bits roce_address; +}; + +struct mlx5_ifc_query_roce_address_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 roce_address_index[0x10]; + u8 reserved_2[0x10]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_rmp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0xc0]; + + struct mlx5_ifc_rmpc_bits rmp_context; +}; + +struct mlx5_ifc_query_rmp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 rmpn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_qp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + u8 opt_param_mask[0x20]; + + u8 reserved_2[0x20]; + + struct mlx5_ifc_qpc_bits qpc; + + u8 reserved_3[0x80]; + + u8 pas[0][0x40]; +}; + +struct mlx5_ifc_query_qp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_q_counter_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + u8 rx_write_requests[0x20]; + + u8 reserved_2[0x20]; + + u8 rx_read_requests[0x20]; + + u8 reserved_3[0x20]; + + u8 rx_atomic_requests[0x20]; + + u8 reserved_4[0x20]; + + u8 rx_dct_connect[0x20]; + + u8 reserved_5[0x20]; + + u8 out_of_buffer[0x20]; + + u8 reserved_6[0x20]; + + u8 out_of_sequence[0x20]; + + u8 reserved_7[0x620]; +}; + +struct mlx5_ifc_query_q_counter_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x80]; + + u8 clear[0x1]; + u8 reserved_3[0x1f]; + + u8 reserved_4[0x18]; + u8 counter_set_id[0x8]; +}; + +struct mlx5_ifc_query_pages_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x10]; + u8 function_id[0x10]; + + u8 num_pages[0x20]; +}; + +enum { + MLX5_QUERY_PAGES_IN_OP_MOD_BOOT_PAGES = 0x1, + MLX5_QUERY_PAGES_IN_OP_MOD_INIT_PAGES = 0x2, + MLX5_QUERY_PAGES_IN_OP_MOD_REGULAR_PAGES = 0x3, +}; + +struct mlx5_ifc_query_pages_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x10]; + u8 function_id[0x10]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_nic_vport_context_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + struct mlx5_ifc_nic_vport_context_bits nic_vport_context; +}; + +struct mlx5_ifc_query_nic_vport_context_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 other_vport[0x1]; + u8 reserved_2[0xf]; + u8 vport_number[0x10]; + + u8 reserved_3[0x5]; + u8 allowed_list_type[0x3]; + u8 reserved_4[0x18]; +}; + +struct mlx5_ifc_query_mkey_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + struct mlx5_ifc_mkc_bits memory_key_mkey_entry; + + u8 reserved_2[0x600]; + + u8 bsf0_klm0_pas_mtt0_1[16][0x8]; + + u8 bsf1_klm1_pas_mtt2_3[16][0x8]; +}; + +struct mlx5_ifc_query_mkey_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 mkey_index[0x18]; + + u8 pg_access[0x1]; + u8 reserved_3[0x1f]; +}; + +struct mlx5_ifc_query_mad_demux_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + u8 mad_dumux_parameters_block[0x20]; +}; + +struct mlx5_ifc_query_mad_demux_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_query_l2_table_entry_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0xa0]; + + u8 reserved_2[0x13]; + u8 vlan_valid[0x1]; + u8 vlan[0xc]; + + struct mlx5_ifc_mac_address_layout_bits mac_address; + + u8 reserved_3[0xc0]; +}; + +struct mlx5_ifc_query_l2_table_entry_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x60]; + + u8 reserved_3[0x8]; + u8 table_index[0x18]; + + u8 reserved_4[0x140]; +}; + +struct mlx5_ifc_query_issi_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x10]; + u8 current_issi[0x10]; + + u8 reserved_2[0xa0]; + + u8 supported_issi_reserved[76][0x8]; + u8 supported_issi_dw0[0x20]; +}; + +struct mlx5_ifc_query_issi_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_query_hca_vport_pkey_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + struct mlx5_ifc_pkey_bits pkey[0]; +}; + +struct mlx5_ifc_query_hca_vport_pkey_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 other_vport[0x1]; + u8 reserved_2[0xf]; + u8 vport_number[0x10]; + + u8 reserved_3[0x10]; + u8 pkey_index[0x10]; +}; + +struct mlx5_ifc_query_hca_vport_gid_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x20]; + + u8 gids_num[0x10]; + u8 reserved_2[0x10]; + + struct mlx5_ifc_array128_auto_bits gid[0]; +}; + +struct mlx5_ifc_query_hca_vport_gid_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 other_vport[0x1]; + u8 reserved_2[0xf]; + u8 vport_number[0x10]; + + u8 reserved_3[0x10]; + u8 gid_index[0x10]; +}; + +struct mlx5_ifc_query_hca_vport_context_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + struct mlx5_ifc_hca_vport_context_bits hca_vport_context; +}; + +struct mlx5_ifc_query_hca_vport_context_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 other_vport[0x1]; + u8 reserved_2[0xf]; + u8 vport_number[0x10]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_hca_cap_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + union mlx5_ifc_hca_cap_union_bits capability; +}; + +struct mlx5_ifc_query_hca_cap_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_query_flow_table_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x80]; + + u8 reserved_2[0x8]; + u8 level[0x8]; + u8 reserved_3[0x8]; + u8 log_size[0x8]; + + u8 reserved_4[0x120]; +}; + +struct mlx5_ifc_query_flow_table_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + u8 table_type[0x8]; + u8 reserved_3[0x18]; + + u8 reserved_4[0x8]; + u8 table_id[0x18]; + + u8 reserved_5[0x140]; +}; + +struct mlx5_ifc_query_fte_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x1c0]; + + struct mlx5_ifc_flow_context_bits flow_context; +}; + +struct mlx5_ifc_query_fte_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + u8 table_type[0x8]; + u8 reserved_3[0x18]; + + u8 reserved_4[0x8]; + u8 table_id[0x18]; + + u8 reserved_5[0x40]; + + u8 flow_index[0x20]; + + u8 reserved_6[0xe0]; +}; + +enum { + MLX5_QUERY_FLOW_GROUP_OUT_MATCH_CRITERIA_ENABLE_OUTER_HEADERS = 0x0, + MLX5_QUERY_FLOW_GROUP_OUT_MATCH_CRITERIA_ENABLE_MISC_PARAMETERS = 0x1, + MLX5_QUERY_FLOW_GROUP_OUT_MATCH_CRITERIA_ENABLE_INNER_HEADERS = 0x2, +}; + +struct mlx5_ifc_query_flow_group_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0xa0]; + + u8 start_flow_index[0x20]; + + u8 reserved_2[0x20]; + + u8 end_flow_index[0x20]; + + u8 reserved_3[0xa0]; + + u8 reserved_4[0x18]; + u8 match_criteria_enable[0x8]; + + struct mlx5_ifc_fte_match_param_bits match_criteria; + + u8 reserved_5[0xe00]; +}; + +struct mlx5_ifc_query_flow_group_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + u8 table_type[0x8]; + u8 reserved_3[0x18]; + + u8 reserved_4[0x8]; + u8 table_id[0x18]; + + u8 group_id[0x20]; + + u8 reserved_5[0x120]; +}; + +struct mlx5_ifc_query_eq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + struct mlx5_ifc_eqc_bits eq_context_entry; + + u8 reserved_2[0x40]; + + u8 event_bitmask[0x40]; + + u8 reserved_3[0x580]; + + u8 pas[0][0x40]; +}; + +struct mlx5_ifc_query_eq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x18]; + u8 eq_number[0x8]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_dct_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + struct mlx5_ifc_dctc_bits dct_context_entry; + + u8 reserved_2[0x180]; +}; + +struct mlx5_ifc_query_dct_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 dctn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_cq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + struct mlx5_ifc_cqc_bits cq_context; + + u8 reserved_2[0x600]; + + u8 pas[0][0x40]; +}; + +struct mlx5_ifc_query_cq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 cqn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_cong_status_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x20]; + + u8 enable[0x1]; + u8 tag_enable[0x1]; + u8 reserved_2[0x1e]; +}; + +struct mlx5_ifc_query_cong_status_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x18]; + u8 priority[0x4]; + u8 cong_protocol[0x4]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_cong_statistics_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + u8 cur_flows[0x20]; + + u8 sum_flows[0x20]; + + u8 cnp_ignored_high[0x20]; + + u8 cnp_ignored_low[0x20]; + + u8 cnp_handled_high[0x20]; + + u8 cnp_handled_low[0x20]; + + u8 reserved_2[0x100]; + + u8 time_stamp_high[0x20]; + + u8 time_stamp_low[0x20]; + + u8 accumulators_period[0x20]; + + u8 ecn_marked_roce_packets_high[0x20]; + + u8 ecn_marked_roce_packets_low[0x20]; + + u8 cnps_sent_high[0x20]; + + u8 cnps_sent_low[0x20]; + + u8 reserved_3[0x560]; +}; + +struct mlx5_ifc_query_cong_statistics_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 clear[0x1]; + u8 reserved_2[0x1f]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_cong_params_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + union mlx5_ifc_cong_control_roce_ecn_auto_bits congestion_parameters; +}; + +struct mlx5_ifc_query_cong_params_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x1c]; + u8 cong_protocol[0x4]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_query_adapter_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + struct mlx5_ifc_query_adapter_param_block_bits query_adapter_struct; +}; + +struct mlx5_ifc_query_adapter_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_qp_2rst_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_qp_2rst_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_qp_2err_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_qp_2err_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_page_fault_resume_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_page_fault_resume_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 error[0x1]; + u8 reserved_2[0x4]; + u8 rdma[0x1]; + u8 read_write[0x1]; + u8 req_res[0x1]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_nop_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_nop_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_modify_vport_state_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_modify_vport_state_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 other_vport[0x1]; + u8 reserved_2[0xf]; + u8 vport_number[0x10]; + + u8 reserved_3[0x18]; + u8 admin_state[0x4]; + u8 reserved_4[0x4]; +}; + +struct mlx5_ifc_modify_tis_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_modify_tis_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 tisn[0x18]; + + u8 reserved_3[0x20]; + + u8 modify_bitmask[0x40]; + + u8 reserved_4[0x40]; + + struct mlx5_ifc_tisc_bits ctx; +}; + +struct mlx5_ifc_modify_tir_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_modify_tir_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 tirn[0x18]; + + u8 reserved_3[0x20]; + + u8 modify_bitmask[0x40]; + + u8 reserved_4[0x40]; + + struct mlx5_ifc_tirc_bits ctx; +}; + +struct mlx5_ifc_modify_sq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_modify_sq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 sq_state[0x4]; + u8 reserved_2[0x4]; + u8 sqn[0x18]; + + u8 reserved_3[0x20]; + + u8 modify_bitmask[0x40]; + + u8 reserved_4[0x40]; + + struct mlx5_ifc_sqc_bits ctx; +}; + +struct mlx5_ifc_modify_rqt_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_modify_rqt_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 rqtn[0x18]; + + u8 reserved_3[0x20]; + + u8 modify_bitmask[0x40]; + + u8 reserved_4[0x40]; + + struct mlx5_ifc_rqtc_bits ctx; +}; + +struct mlx5_ifc_modify_rq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_modify_rq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 rq_state[0x4]; + u8 reserved_2[0x4]; + u8 rqn[0x18]; + + u8 reserved_3[0x20]; + + u8 modify_bitmask[0x40]; + + u8 reserved_4[0x40]; + + struct mlx5_ifc_rqc_bits ctx; +}; + +struct mlx5_ifc_modify_rmp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_modify_rmp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 rmp_state[0x4]; + u8 reserved_2[0x4]; + u8 rmpn[0x18]; + + u8 reserved_3[0x20]; + + u8 modify_bitmask[0x40]; + + u8 reserved_4[0x40]; + + struct mlx5_ifc_rmpc_bits ctx; +}; + +struct mlx5_ifc_modify_nic_vport_context_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_modify_nic_vport_field_select_bits { + u8 reserved_0[0x1c]; + u8 permanent_address[0x1]; + u8 addresses_list[0x1]; + u8 roce_en[0x1]; + u8 reserved_1[0x1]; +}; + +struct mlx5_ifc_modify_nic_vport_context_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 other_vport[0x1]; + u8 reserved_2[0xf]; + u8 vport_number[0x10]; + + struct mlx5_ifc_modify_nic_vport_field_select_bits field_select; + + u8 reserved_3[0x780]; + + struct mlx5_ifc_nic_vport_context_bits nic_vport_context; +}; + +struct mlx5_ifc_modify_hca_vport_context_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_modify_hca_vport_context_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 other_vport[0x1]; + u8 reserved_2[0xf]; + u8 vport_number[0x10]; + + u8 reserved_3[0x20]; + + struct mlx5_ifc_hca_vport_context_bits hca_vport_context; +}; + +struct mlx5_ifc_modify_cq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +enum { + MLX5_MODIFY_CQ_IN_OP_MOD_MODIFY_CQ = 0x0, + MLX5_MODIFY_CQ_IN_OP_MOD_RESIZE_CQ = 0x1, +}; + +struct mlx5_ifc_modify_cq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 cqn[0x18]; + + union mlx5_ifc_modify_field_select_resize_field_select_auto_bits modify_field_select_resize_field_select; + + struct mlx5_ifc_cqc_bits cq_context; + + u8 reserved_3[0x600]; + + u8 pas[0][0x40]; +}; + +struct mlx5_ifc_modify_cong_status_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_modify_cong_status_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x18]; + u8 priority[0x4]; + u8 cong_protocol[0x4]; + + u8 enable[0x1]; + u8 tag_enable[0x1]; + u8 reserved_3[0x1e]; +}; + +struct mlx5_ifc_modify_cong_params_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_modify_cong_params_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x1c]; + u8 cong_protocol[0x4]; + + union mlx5_ifc_field_select_802_1_r_roce_auto_bits field_select; + + u8 reserved_3[0x80]; + + union mlx5_ifc_cong_control_roce_ecn_auto_bits congestion_parameters; +}; + +struct mlx5_ifc_manage_pages_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 output_num_entries[0x20]; + + u8 reserved_1[0x20]; + + u8 pas[0][0x40]; +}; + +enum { + MLX5_MANAGE_PAGES_IN_OP_MOD_ALLOCATION_FAIL = 0x0, + MLX5_MANAGE_PAGES_IN_OP_MOD_ALLOCATION_SUCCESS = 0x1, + MLX5_MANAGE_PAGES_IN_OP_MOD_HCA_RETURN_PAGES = 0x2, +}; + +struct mlx5_ifc_manage_pages_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x10]; + u8 function_id[0x10]; + + u8 input_num_entries[0x20]; + + u8 pas[0][0x40]; +}; + +struct mlx5_ifc_mad_ifc_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + u8 response_mad_packet[256][0x8]; +}; + +struct mlx5_ifc_mad_ifc_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 remote_lid[0x10]; + u8 reserved_2[0x8]; + u8 port[0x8]; + + u8 reserved_3[0x20]; + + u8 mad[256][0x8]; +}; + +struct mlx5_ifc_init_hca_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_init_hca_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_init2rtr_qp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_init2rtr_qp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; + + u8 opt_param_mask[0x20]; + + u8 reserved_4[0x20]; + + struct mlx5_ifc_qpc_bits qpc; + + u8 reserved_5[0x80]; +}; + +struct mlx5_ifc_init2init_qp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_init2init_qp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; + + u8 opt_param_mask[0x20]; + + u8 reserved_4[0x20]; + + struct mlx5_ifc_qpc_bits qpc; + + u8 reserved_5[0x80]; +}; + +struct mlx5_ifc_get_dropped_packet_log_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + u8 packet_headers_log[128][0x8]; + + u8 packet_syndrome[64][0x8]; +}; + +struct mlx5_ifc_get_dropped_packet_log_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_gen_eqe_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x18]; + u8 eq_number[0x8]; + + u8 reserved_3[0x20]; + + u8 eqe[64][0x8]; +}; + +struct mlx5_ifc_gen_eq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_enable_hca_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x20]; +}; + +struct mlx5_ifc_enable_hca_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x10]; + u8 function_id[0x10]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_drain_dct_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_drain_dct_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 dctn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_disable_hca_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x20]; +}; + +struct mlx5_ifc_disable_hca_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x10]; + u8 function_id[0x10]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_detach_from_mcg_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_detach_from_mcg_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; + + u8 multicast_gid[16][0x8]; +}; + +struct mlx5_ifc_destroy_xrc_srq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_xrc_srq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 xrc_srqn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_destroy_tis_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_tis_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 tisn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_destroy_tir_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_tir_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 tirn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_destroy_srq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_srq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 srqn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_destroy_sq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_sq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 sqn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_destroy_rqt_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_rqt_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 rqtn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_destroy_rq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_rq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 rqn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_destroy_rmp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_rmp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 rmpn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_destroy_qp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_qp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_destroy_psv_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_psv_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 psvn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_destroy_mkey_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_mkey_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 mkey_index[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_destroy_flow_table_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_flow_table_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + u8 table_type[0x8]; + u8 reserved_3[0x18]; + + u8 reserved_4[0x8]; + u8 table_id[0x18]; + + u8 reserved_5[0x140]; +}; + +struct mlx5_ifc_destroy_flow_group_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_flow_group_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + u8 table_type[0x8]; + u8 reserved_3[0x18]; + + u8 reserved_4[0x8]; + u8 table_id[0x18]; + + u8 group_id[0x20]; + + u8 reserved_5[0x120]; +}; + +struct mlx5_ifc_destroy_eq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_eq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x18]; + u8 eq_number[0x8]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_destroy_dct_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_dct_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 dctn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_destroy_cq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_destroy_cq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 cqn[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_delete_vxlan_udp_dport_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_delete_vxlan_udp_dport_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x20]; + + u8 reserved_3[0x10]; + u8 vxlan_udp_port[0x10]; +}; + +struct mlx5_ifc_delete_l2_table_entry_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_delete_l2_table_entry_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x60]; + + u8 reserved_3[0x8]; + u8 table_index[0x18]; + + u8 reserved_4[0x140]; +}; + +struct mlx5_ifc_delete_fte_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_delete_fte_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + u8 table_type[0x8]; + u8 reserved_3[0x18]; + + u8 reserved_4[0x8]; + u8 table_id[0x18]; + + u8 reserved_5[0x40]; + + u8 flow_index[0x20]; + + u8 reserved_6[0xe0]; +}; + +struct mlx5_ifc_dealloc_xrcd_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_dealloc_xrcd_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 xrcd[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_dealloc_uar_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_dealloc_uar_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 uar[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_dealloc_transport_domain_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_dealloc_transport_domain_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 transport_domain[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_dealloc_q_counter_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_dealloc_q_counter_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x18]; + u8 counter_set_id[0x8]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_dealloc_pd_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_dealloc_pd_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 pd[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_create_xrc_srq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 xrc_srqn[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_xrc_srq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + struct mlx5_ifc_xrc_srqc_bits xrc_srq_context_entry; + + u8 reserved_3[0x600]; + + u8 pas[0][0x40]; +}; + +struct mlx5_ifc_create_tis_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 tisn[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_tis_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0xc0]; + + struct mlx5_ifc_tisc_bits ctx; +}; + +struct mlx5_ifc_create_tir_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 tirn[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_tir_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0xc0]; + + struct mlx5_ifc_tirc_bits ctx; +}; + +struct mlx5_ifc_create_srq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 srqn[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_srq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + struct mlx5_ifc_srqc_bits srq_context_entry; + + u8 reserved_3[0x600]; + + u8 pas[0][0x40]; +}; + +struct mlx5_ifc_create_sq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 sqn[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_sq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0xc0]; + + struct mlx5_ifc_sqc_bits ctx; +}; + +struct mlx5_ifc_create_rqt_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 rqtn[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_rqt_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0xc0]; + + struct mlx5_ifc_rqtc_bits rqt_context; +}; + +struct mlx5_ifc_create_rq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 rqn[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_rq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0xc0]; + + struct mlx5_ifc_rqc_bits ctx; +}; + +struct mlx5_ifc_create_rmp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 rmpn[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_rmp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0xc0]; + + struct mlx5_ifc_rmpc_bits ctx; +}; + +struct mlx5_ifc_create_qp_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 qpn[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_qp_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + u8 opt_param_mask[0x20]; + + u8 reserved_3[0x20]; + + struct mlx5_ifc_qpc_bits qpc; + + u8 reserved_4[0x80]; + + u8 pas[0][0x40]; +}; + +struct mlx5_ifc_create_psv_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + u8 reserved_2[0x8]; + u8 psv0_index[0x18]; + + u8 reserved_3[0x8]; + u8 psv1_index[0x18]; + + u8 reserved_4[0x8]; + u8 psv2_index[0x18]; + + u8 reserved_5[0x8]; + u8 psv3_index[0x18]; +}; + +struct mlx5_ifc_create_psv_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 num_psv[0x4]; + u8 reserved_2[0x4]; + u8 pd[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_create_mkey_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 mkey_index[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_mkey_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x20]; + + u8 pg_access[0x1]; + u8 reserved_3[0x1f]; + + struct mlx5_ifc_mkc_bits memory_key_mkey_entry; + + u8 reserved_4[0x80]; + + u8 translations_octword_actual_size[0x20]; + + u8 reserved_5[0x560]; + + u8 klm_pas_mtt[0][0x20]; +}; + +struct mlx5_ifc_create_flow_table_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 table_id[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_flow_table_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + u8 table_type[0x8]; + u8 reserved_3[0x18]; + + u8 reserved_4[0x20]; + + u8 reserved_5[0x8]; + u8 level[0x8]; + u8 reserved_6[0x8]; + u8 log_size[0x8]; + + u8 reserved_7[0x120]; +}; + +struct mlx5_ifc_create_flow_group_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 group_id[0x18]; + + u8 reserved_2[0x20]; +}; + +enum { + MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS = 0x0, + MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_MISC_PARAMETERS = 0x1, + MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_INNER_HEADERS = 0x2, +}; + +struct mlx5_ifc_create_flow_group_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + u8 table_type[0x8]; + u8 reserved_3[0x18]; + + u8 reserved_4[0x8]; + u8 table_id[0x18]; + + u8 reserved_5[0x20]; + + u8 start_flow_index[0x20]; + + u8 reserved_6[0x20]; + + u8 end_flow_index[0x20]; + + u8 reserved_7[0xa0]; + + u8 reserved_8[0x18]; + u8 match_criteria_enable[0x8]; + + struct mlx5_ifc_fte_match_param_bits match_criteria; + + u8 reserved_9[0xe00]; +}; + +struct mlx5_ifc_create_eq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x18]; + u8 eq_number[0x8]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_eq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + struct mlx5_ifc_eqc_bits eq_context_entry; + + u8 reserved_3[0x40]; + + u8 event_bitmask[0x40]; + + u8 reserved_4[0x580]; + + u8 pas[0][0x40]; +}; + +struct mlx5_ifc_create_dct_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 dctn[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_dct_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + struct mlx5_ifc_dctc_bits dct_context_entry; + + u8 reserved_3[0x180]; +}; + +struct mlx5_ifc_create_cq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 cqn[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_create_cq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + struct mlx5_ifc_cqc_bits cq_context; + + u8 reserved_3[0x600]; + + u8 pas[0][0x40]; +}; + +struct mlx5_ifc_config_int_moderation_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x4]; + u8 min_delay[0xc]; + u8 int_vector[0x10]; + + u8 reserved_2[0x20]; +}; + +enum { + MLX5_CONFIG_INT_MODERATION_IN_OP_MOD_WRITE = 0x0, + MLX5_CONFIG_INT_MODERATION_IN_OP_MOD_READ = 0x1, +}; + +struct mlx5_ifc_config_int_moderation_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x4]; + u8 min_delay[0xc]; + u8 int_vector[0x10]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_attach_to_mcg_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_attach_to_mcg_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 qpn[0x18]; + + u8 reserved_3[0x20]; + + u8 multicast_gid[16][0x8]; +}; + +struct mlx5_ifc_arm_xrc_srq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +enum { + MLX5_ARM_XRC_SRQ_IN_OP_MOD_XRC_SRQ = 0x1, +}; + +struct mlx5_ifc_arm_xrc_srq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 xrc_srqn[0x18]; + + u8 reserved_3[0x10]; + u8 lwm[0x10]; +}; + +struct mlx5_ifc_arm_rq_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +enum { + MLX5_ARM_RQ_IN_OP_MOD_SRQ_ = 0x1, +}; + +struct mlx5_ifc_arm_rq_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 srq_number[0x18]; + + u8 reserved_3[0x10]; + u8 lwm[0x10]; +}; + +struct mlx5_ifc_arm_dct_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_arm_dct_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x8]; + u8 dct_number[0x18]; + + u8 reserved_3[0x20]; +}; + +struct mlx5_ifc_alloc_xrcd_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 xrcd[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_alloc_xrcd_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_alloc_uar_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 uar[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_alloc_uar_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_alloc_transport_domain_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 transport_domain[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_alloc_transport_domain_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_alloc_q_counter_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x18]; + u8 counter_set_id[0x8]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_alloc_q_counter_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_alloc_pd_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x8]; + u8 pd[0x18]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_alloc_pd_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_add_vxlan_udp_dport_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +struct mlx5_ifc_add_vxlan_udp_dport_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x20]; + + u8 reserved_3[0x10]; + u8 vxlan_udp_port[0x10]; +}; + +struct mlx5_ifc_access_register_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + u8 register_data[0][0x20]; +}; + +enum { + MLX5_ACCESS_REGISTER_IN_OP_MOD_WRITE = 0x0, + MLX5_ACCESS_REGISTER_IN_OP_MOD_READ = 0x1, +}; + +struct mlx5_ifc_access_register_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x10]; + u8 register_id[0x10]; + + u8 argument[0x20]; + + u8 register_data[0][0x20]; +}; + +struct mlx5_ifc_sltp_reg_bits { + u8 status[0x4]; + u8 version[0x4]; + u8 local_port[0x8]; + u8 pnat[0x2]; + u8 reserved_0[0x2]; + u8 lane[0x4]; + u8 reserved_1[0x8]; + + u8 reserved_2[0x20]; + + u8 reserved_3[0x7]; + u8 polarity[0x1]; + u8 ob_tap0[0x8]; + u8 ob_tap1[0x8]; + u8 ob_tap2[0x8]; + + u8 reserved_4[0xc]; + u8 ob_preemp_mode[0x4]; + u8 ob_reg[0x8]; + u8 ob_bias[0x8]; + + u8 reserved_5[0x20]; +}; + +struct mlx5_ifc_slrg_reg_bits { + u8 status[0x4]; + u8 version[0x4]; + u8 local_port[0x8]; + u8 pnat[0x2]; + u8 reserved_0[0x2]; + u8 lane[0x4]; + u8 reserved_1[0x8]; + + u8 time_to_link_up[0x10]; + u8 reserved_2[0xc]; + u8 grade_lane_speed[0x4]; + + u8 grade_version[0x8]; + u8 grade[0x18]; + + u8 reserved_3[0x4]; + u8 height_grade_type[0x4]; + u8 height_grade[0x18]; + + u8 height_dz[0x10]; + u8 height_dv[0x10]; + + u8 reserved_4[0x10]; + u8 height_sigma[0x10]; + + u8 reserved_5[0x20]; + + u8 reserved_6[0x4]; + u8 phase_grade_type[0x4]; + u8 phase_grade[0x18]; + + u8 reserved_7[0x8]; + u8 phase_eo_pos[0x8]; + u8 reserved_8[0x8]; + u8 phase_eo_neg[0x8]; + + u8 ffe_set_tested[0x10]; + u8 test_errors_per_lane[0x10]; +}; + +struct mlx5_ifc_pvlc_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0x10]; + + u8 reserved_2[0x1c]; + u8 vl_hw_cap[0x4]; + + u8 reserved_3[0x1c]; + u8 vl_admin[0x4]; + + u8 reserved_4[0x1c]; + u8 vl_operational[0x4]; +}; + +struct mlx5_ifc_pude_reg_bits { + u8 swid[0x8]; + u8 local_port[0x8]; + u8 reserved_0[0x4]; + u8 admin_status[0x4]; + u8 reserved_1[0x4]; + u8 oper_status[0x4]; + + u8 reserved_2[0x60]; +}; + +struct mlx5_ifc_ptys_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0xd]; + u8 proto_mask[0x3]; + + u8 reserved_2[0x40]; + + u8 eth_proto_capability[0x20]; + + u8 ib_link_width_capability[0x10]; + u8 ib_proto_capability[0x10]; + + u8 reserved_3[0x20]; + + u8 eth_proto_admin[0x20]; + + u8 ib_link_width_admin[0x10]; + u8 ib_proto_admin[0x10]; + + u8 reserved_4[0x20]; + + u8 eth_proto_oper[0x20]; + + u8 ib_link_width_oper[0x10]; + u8 ib_proto_oper[0x10]; + + u8 reserved_5[0x20]; + + u8 eth_proto_lp_advertise[0x20]; + + u8 reserved_6[0x60]; +}; + +struct mlx5_ifc_ptas_reg_bits { + u8 reserved_0[0x20]; + + u8 algorithm_options[0x10]; + u8 reserved_1[0x4]; + u8 repetitions_mode[0x4]; + u8 num_of_repetitions[0x8]; + + u8 grade_version[0x8]; + u8 height_grade_type[0x4]; + u8 phase_grade_type[0x4]; + u8 height_grade_weight[0x8]; + u8 phase_grade_weight[0x8]; + + u8 gisim_measure_bits[0x10]; + u8 adaptive_tap_measure_bits[0x10]; + + u8 ber_bath_high_error_threshold[0x10]; + u8 ber_bath_mid_error_threshold[0x10]; + + u8 ber_bath_low_error_threshold[0x10]; + u8 one_ratio_high_threshold[0x10]; + + u8 one_ratio_high_mid_threshold[0x10]; + u8 one_ratio_low_mid_threshold[0x10]; + + u8 one_ratio_low_threshold[0x10]; + u8 ndeo_error_threshold[0x10]; + + u8 mixer_offset_step_size[0x10]; + u8 reserved_2[0x8]; + u8 mix90_phase_for_voltage_bath[0x8]; + + u8 mixer_offset_start[0x10]; + u8 mixer_offset_end[0x10]; + + u8 reserved_3[0x15]; + u8 ber_test_time[0xb]; +}; + +struct mlx5_ifc_pspa_reg_bits { + u8 swid[0x8]; + u8 local_port[0x8]; + u8 sub_port[0x8]; + u8 reserved_0[0x8]; + + u8 reserved_1[0x20]; +}; + +struct mlx5_ifc_pqdr_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0x5]; + u8 prio[0x3]; + u8 reserved_2[0x6]; + u8 mode[0x2]; + + u8 reserved_3[0x20]; + + u8 reserved_4[0x10]; + u8 min_threshold[0x10]; + + u8 reserved_5[0x10]; + u8 max_threshold[0x10]; + + u8 reserved_6[0x10]; + u8 mark_probability_denominator[0x10]; + + u8 reserved_7[0x60]; +}; + +struct mlx5_ifc_ppsc_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0x10]; + + u8 reserved_2[0x60]; + + u8 reserved_3[0x1c]; + u8 wrps_admin[0x4]; + + u8 reserved_4[0x1c]; + u8 wrps_status[0x4]; + + u8 reserved_5[0x8]; + u8 up_threshold[0x8]; + u8 reserved_6[0x8]; + u8 down_threshold[0x8]; + + u8 reserved_7[0x20]; + + u8 reserved_8[0x1c]; + u8 srps_admin[0x4]; + + u8 reserved_9[0x1c]; + u8 srps_status[0x4]; + + u8 reserved_10[0x40]; +}; + +struct mlx5_ifc_pplr_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0x10]; + + u8 reserved_2[0x8]; + u8 lb_cap[0x8]; + u8 reserved_3[0x8]; + u8 lb_en[0x8]; +}; + +struct mlx5_ifc_pplm_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0x10]; + + u8 reserved_2[0x20]; + + u8 port_profile_mode[0x8]; + u8 static_port_profile[0x8]; + u8 active_port_profile[0x8]; + u8 reserved_3[0x8]; + + u8 retransmission_active[0x8]; + u8 fec_mode_active[0x18]; + + u8 reserved_4[0x20]; +}; + +struct mlx5_ifc_ppcnt_reg_bits { + u8 swid[0x8]; + u8 local_port[0x8]; + u8 pnat[0x2]; + u8 reserved_0[0x8]; + u8 grp[0x6]; + + u8 clr[0x1]; + u8 reserved_1[0x1c]; + u8 prio_tc[0x3]; + + union mlx5_ifc_eth_cntrs_grp_data_layout_auto_bits counter_set; +}; + +struct mlx5_ifc_ppad_reg_bits { + u8 reserved_0[0x3]; + u8 single_mac[0x1]; + u8 reserved_1[0x4]; + u8 local_port[0x8]; + u8 mac_47_32[0x10]; + + u8 mac_31_0[0x20]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_pmtu_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0x10]; + + u8 max_mtu[0x10]; + u8 reserved_2[0x10]; + + u8 admin_mtu[0x10]; + u8 reserved_3[0x10]; + + u8 oper_mtu[0x10]; + u8 reserved_4[0x10]; +}; + +struct mlx5_ifc_pmpr_reg_bits { + u8 reserved_0[0x8]; + u8 module[0x8]; + u8 reserved_1[0x10]; + + u8 reserved_2[0x18]; + u8 attenuation_5g[0x8]; + + u8 reserved_3[0x18]; + u8 attenuation_7g[0x8]; + + u8 reserved_4[0x18]; + u8 attenuation_12g[0x8]; +}; + +struct mlx5_ifc_pmpe_reg_bits { + u8 reserved_0[0x8]; + u8 module[0x8]; + u8 reserved_1[0xc]; + u8 module_status[0x4]; + + u8 reserved_2[0x60]; +}; + +struct mlx5_ifc_pmpc_reg_bits { + u8 module_state_updated[32][0x8]; +}; + +struct mlx5_ifc_pmlpn_reg_bits { + u8 reserved_0[0x4]; + u8 mlpn_status[0x4]; + u8 local_port[0x8]; + u8 reserved_1[0x10]; + + u8 e[0x1]; + u8 reserved_2[0x1f]; +}; + +struct mlx5_ifc_pmlp_reg_bits { + u8 rxtx[0x1]; + u8 reserved_0[0x7]; + u8 local_port[0x8]; + u8 reserved_1[0x8]; + u8 width[0x8]; + + u8 lane0_module_mapping[0x20]; + + u8 lane1_module_mapping[0x20]; + + u8 lane2_module_mapping[0x20]; + + u8 lane3_module_mapping[0x20]; + + u8 reserved_2[0x160]; +}; + +struct mlx5_ifc_pmaos_reg_bits { + u8 reserved_0[0x8]; + u8 module[0x8]; + u8 reserved_1[0x4]; + u8 admin_status[0x4]; + u8 reserved_2[0x4]; + u8 oper_status[0x4]; + + u8 ase[0x1]; + u8 ee[0x1]; + u8 reserved_3[0x1c]; + u8 e[0x2]; + + u8 reserved_4[0x40]; +}; + +struct mlx5_ifc_plpc_reg_bits { + u8 reserved_0[0x4]; + u8 profile_id[0xc]; + u8 reserved_1[0x4]; + u8 proto_mask[0x4]; + u8 reserved_2[0x8]; + + u8 reserved_3[0x10]; + u8 lane_speed[0x10]; + + u8 reserved_4[0x17]; + u8 lpbf[0x1]; + u8 fec_mode_policy[0x8]; + + u8 retransmission_capability[0x8]; + u8 fec_mode_capability[0x18]; + + u8 retransmission_support_admin[0x8]; + u8 fec_mode_support_admin[0x18]; + + u8 retransmission_request_admin[0x8]; + u8 fec_mode_request_admin[0x18]; + + u8 reserved_5[0x80]; +}; + +struct mlx5_ifc_plib_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0x8]; + u8 ib_port[0x8]; + + u8 reserved_2[0x60]; +}; + +struct mlx5_ifc_plbf_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0xd]; + u8 lbf_mode[0x3]; + + u8 reserved_2[0x20]; +}; + +struct mlx5_ifc_pipg_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0x10]; + + u8 dic[0x1]; + u8 reserved_2[0x19]; + u8 ipg[0x4]; + u8 reserved_3[0x2]; +}; + +struct mlx5_ifc_pifr_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0x10]; + + u8 reserved_2[0xe0]; + + u8 port_filter[8][0x20]; + + u8 port_filter_update_en[8][0x20]; +}; + +struct mlx5_ifc_pfcc_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0x10]; + + u8 ppan[0x4]; + u8 reserved_2[0x4]; + u8 prio_mask_tx[0x8]; + u8 reserved_3[0x8]; + u8 prio_mask_rx[0x8]; + + u8 pptx[0x1]; + u8 aptx[0x1]; + u8 reserved_4[0x6]; + u8 pfctx[0x8]; + u8 reserved_5[0x10]; + + u8 pprx[0x1]; + u8 aprx[0x1]; + u8 reserved_6[0x6]; + u8 pfcrx[0x8]; + u8 reserved_7[0x10]; + + u8 reserved_8[0x80]; +}; + +struct mlx5_ifc_pelc_reg_bits { + u8 op[0x4]; + u8 reserved_0[0x4]; + u8 local_port[0x8]; + u8 reserved_1[0x10]; + + u8 op_admin[0x8]; + u8 op_capability[0x8]; + u8 op_request[0x8]; + u8 op_active[0x8]; + + u8 admin[0x40]; + + u8 capability[0x40]; + + u8 request[0x40]; + + u8 active[0x40]; + + u8 reserved_2[0x80]; +}; + +struct mlx5_ifc_peir_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0x10]; + + u8 reserved_2[0xc]; + u8 error_count[0x4]; + u8 reserved_3[0x10]; + + u8 reserved_4[0xc]; + u8 lane[0x4]; + u8 reserved_5[0x8]; + u8 error_type[0x8]; +}; + +struct mlx5_ifc_pcap_reg_bits { + u8 reserved_0[0x8]; + u8 local_port[0x8]; + u8 reserved_1[0x10]; + + u8 port_capability_mask[4][0x20]; +}; + +struct mlx5_ifc_paos_reg_bits { + u8 swid[0x8]; + u8 local_port[0x8]; + u8 reserved_0[0x4]; + u8 admin_status[0x4]; + u8 reserved_1[0x4]; + u8 oper_status[0x4]; + + u8 ase[0x1]; + u8 ee[0x1]; + u8 reserved_2[0x1c]; + u8 e[0x2]; + + u8 reserved_3[0x40]; +}; + +struct mlx5_ifc_pamp_reg_bits { + u8 reserved_0[0x8]; + u8 opamp_group[0x8]; + u8 reserved_1[0xc]; + u8 opamp_group_type[0x4]; + + u8 start_index[0x10]; + u8 reserved_2[0x4]; + u8 num_of_indices[0xc]; + + u8 index_data[18][0x10]; +}; + +struct mlx5_ifc_lane_2_module_mapping_bits { + u8 reserved_0[0x6]; + u8 rx_lane[0x2]; + u8 reserved_1[0x6]; + u8 tx_lane[0x2]; + u8 reserved_2[0x8]; + u8 module[0x8]; +}; + +struct mlx5_ifc_bufferx_reg_bits { + u8 reserved_0[0x6]; + u8 lossy[0x1]; + u8 epsb[0x1]; + u8 reserved_1[0xc]; + u8 size[0xc]; + + u8 xoff_threshold[0x10]; + u8 xon_threshold[0x10]; +}; + +struct mlx5_ifc_set_node_in_bits { + u8 node_description[64][0x8]; +}; + +struct mlx5_ifc_register_power_settings_bits { + u8 reserved_0[0x18]; + u8 power_settings_level[0x8]; + + u8 reserved_1[0x60]; +}; + +struct mlx5_ifc_register_host_endianness_bits { + u8 he[0x1]; + u8 reserved_0[0x1f]; + + u8 reserved_1[0x60]; +}; + +struct mlx5_ifc_umr_pointer_desc_argument_bits { + u8 reserved_0[0x20]; + + u8 mkey[0x20]; + + u8 addressh_63_32[0x20]; + + u8 addressl_31_0[0x20]; +}; + +struct mlx5_ifc_ud_adrs_vector_bits { + u8 dc_key[0x40]; + + u8 ext[0x1]; + u8 reserved_0[0x7]; + u8 destination_qp_dct[0x18]; + + u8 static_rate[0x4]; + u8 sl_eth_prio[0x4]; + u8 fl[0x1]; + u8 mlid[0x7]; + u8 rlid_udp_sport[0x10]; + + u8 reserved_1[0x20]; + + u8 rmac_47_16[0x20]; + + u8 rmac_15_0[0x10]; + u8 tclass[0x8]; + u8 hop_limit[0x8]; + + u8 reserved_2[0x1]; + u8 grh[0x1]; + u8 reserved_3[0x2]; + u8 src_addr_index[0x8]; + u8 flow_label[0x14]; + + u8 rgid_rip[16][0x8]; +}; + +struct mlx5_ifc_pages_req_event_bits { + u8 reserved_0[0x10]; + u8 function_id[0x10]; + + u8 num_pages[0x20]; + + u8 reserved_1[0xa0]; +}; + +struct mlx5_ifc_eqe_bits { + u8 reserved_0[0x8]; + u8 event_type[0x8]; + u8 reserved_1[0x8]; + u8 event_sub_type[0x8]; + + u8 reserved_2[0xe0]; + + union mlx5_ifc_event_auto_bits event_data; + + u8 reserved_3[0x10]; + u8 signature[0x8]; + u8 reserved_4[0x7]; + u8 owner[0x1]; +}; + +enum { + MLX5_CMD_QUEUE_ENTRY_TYPE_PCIE_CMD_IF_TRANSPORT = 0x7, +}; + +struct mlx5_ifc_cmd_queue_entry_bits { + u8 type[0x8]; + u8 reserved_0[0x18]; + + u8 input_length[0x20]; + + u8 input_mailbox_pointer_63_32[0x20]; + + u8 input_mailbox_pointer_31_9[0x17]; + u8 reserved_1[0x9]; + + u8 command_input_inline_data[16][0x8]; + + u8 command_output_inline_data[16][0x8]; + + u8 output_mailbox_pointer_63_32[0x20]; + + u8 output_mailbox_pointer_31_9[0x17]; + u8 reserved_2[0x9]; + + u8 output_length[0x20]; + + u8 token[0x8]; + u8 signature[0x8]; + u8 reserved_3[0x8]; + u8 status[0x7]; + u8 ownership[0x1]; +}; + +struct mlx5_ifc_cmd_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 command_output[0x20]; +}; + +struct mlx5_ifc_cmd_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 command[0][0x20]; +}; + +struct mlx5_ifc_cmd_if_box_bits { + u8 mailbox_data[512][0x8]; + + u8 reserved_0[0x180]; + + u8 next_pointer_63_32[0x20]; + + u8 next_pointer_31_10[0x16]; + u8 reserved_1[0xa]; + + u8 block_number[0x20]; + + u8 reserved_2[0x8]; + u8 token[0x8]; + u8 ctrl_signature[0x8]; + u8 signature[0x8]; +}; + +struct mlx5_ifc_mtt_bits { + u8 ptag_63_32[0x20]; + + u8 ptag_31_8[0x18]; + u8 reserved_0[0x6]; + u8 wr_en[0x1]; + u8 rd_en[0x1]; +}; + +enum { + MLX5_INITIAL_SEG_NIC_INTERFACE_FULL_DRIVER = 0x0, + MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED = 0x1, + MLX5_INITIAL_SEG_NIC_INTERFACE_NO_DRAM_NIC = 0x2, +}; + +enum { + MLX5_INITIAL_SEG_NIC_INTERFACE_SUPPORTED_FULL_DRIVER = 0x0, + MLX5_INITIAL_SEG_NIC_INTERFACE_SUPPORTED_DISABLED = 0x1, + MLX5_INITIAL_SEG_NIC_INTERFACE_SUPPORTED_NO_DRAM_NIC = 0x2, +}; + +enum { + MLX5_INITIAL_SEG_HEALTH_SYNDROME_FW_INTERNAL_ERR = 0x1, + MLX5_INITIAL_SEG_HEALTH_SYNDROME_DEAD_IRISC = 0x7, + MLX5_INITIAL_SEG_HEALTH_SYNDROME_HW_FATAL_ERR = 0x8, + MLX5_INITIAL_SEG_HEALTH_SYNDROME_FW_CRC_ERR = 0x9, + MLX5_INITIAL_SEG_HEALTH_SYNDROME_ICM_FETCH_PCI_ERR = 0xa, + MLX5_INITIAL_SEG_HEALTH_SYNDROME_ICM_PAGE_ERR = 0xb, + MLX5_INITIAL_SEG_HEALTH_SYNDROME_ASYNCHRONOUS_EQ_BUF_OVERRUN = 0xc, + MLX5_INITIAL_SEG_HEALTH_SYNDROME_EQ_IN_ERR = 0xd, + MLX5_INITIAL_SEG_HEALTH_SYNDROME_EQ_INV = 0xe, + MLX5_INITIAL_SEG_HEALTH_SYNDROME_FFSER_ERR = 0xf, + MLX5_INITIAL_SEG_HEALTH_SYNDROME_HIGH_TEMP_ERR = 0x10, +}; + +struct mlx5_ifc_initial_seg_bits { + u8 fw_rev_minor[0x10]; + u8 fw_rev_major[0x10]; + + u8 cmd_interface_rev[0x10]; + u8 fw_rev_subminor[0x10]; + + u8 reserved_0[0x40]; + + u8 cmdq_phy_addr_63_32[0x20]; + + u8 cmdq_phy_addr_31_12[0x14]; + u8 reserved_1[0x2]; + u8 nic_interface[0x2]; + u8 log_cmdq_size[0x4]; + u8 log_cmdq_stride[0x4]; + + u8 command_doorbell_vector[0x20]; + + u8 reserved_2[0xf00]; + + u8 initializing[0x1]; + u8 reserved_3[0x4]; + u8 nic_interface_supported[0x3]; + u8 reserved_4[0x18]; + + struct mlx5_ifc_health_buffer_bits health_buffer; + + u8 no_dram_nic_offset[0x20]; + + u8 reserved_5[0x6e40]; + + u8 reserved_6[0x1f]; + u8 clear_int[0x1]; + + u8 health_syndrome[0x8]; + u8 health_counter[0x18]; + + u8 reserved_7[0x17fc0]; +}; + +union mlx5_ifc_ports_control_registers_document_bits { + struct mlx5_ifc_bufferx_reg_bits bufferx_reg; + struct mlx5_ifc_eth_2819_cntrs_grp_data_layout_bits eth_2819_cntrs_grp_data_layout; + struct mlx5_ifc_eth_2863_cntrs_grp_data_layout_bits eth_2863_cntrs_grp_data_layout; + struct mlx5_ifc_eth_3635_cntrs_grp_data_layout_bits eth_3635_cntrs_grp_data_layout; + struct mlx5_ifc_eth_802_3_cntrs_grp_data_layout_bits eth_802_3_cntrs_grp_data_layout; + struct mlx5_ifc_eth_extended_cntrs_grp_data_layout_bits eth_extended_cntrs_grp_data_layout; + struct mlx5_ifc_eth_per_prio_grp_data_layout_bits eth_per_prio_grp_data_layout; + struct mlx5_ifc_eth_per_traffic_grp_data_layout_bits eth_per_traffic_grp_data_layout; + struct mlx5_ifc_lane_2_module_mapping_bits lane_2_module_mapping; + struct mlx5_ifc_pamp_reg_bits pamp_reg; + struct mlx5_ifc_paos_reg_bits paos_reg; + struct mlx5_ifc_pcap_reg_bits pcap_reg; + struct mlx5_ifc_peir_reg_bits peir_reg; + struct mlx5_ifc_pelc_reg_bits pelc_reg; + struct mlx5_ifc_pfcc_reg_bits pfcc_reg; + struct mlx5_ifc_phys_layer_cntrs_bits phys_layer_cntrs; + struct mlx5_ifc_pifr_reg_bits pifr_reg; + struct mlx5_ifc_pipg_reg_bits pipg_reg; + struct mlx5_ifc_plbf_reg_bits plbf_reg; + struct mlx5_ifc_plib_reg_bits plib_reg; + struct mlx5_ifc_plpc_reg_bits plpc_reg; + struct mlx5_ifc_pmaos_reg_bits pmaos_reg; + struct mlx5_ifc_pmlp_reg_bits pmlp_reg; + struct mlx5_ifc_pmlpn_reg_bits pmlpn_reg; + struct mlx5_ifc_pmpc_reg_bits pmpc_reg; + struct mlx5_ifc_pmpe_reg_bits pmpe_reg; + struct mlx5_ifc_pmpr_reg_bits pmpr_reg; + struct mlx5_ifc_pmtu_reg_bits pmtu_reg; + struct mlx5_ifc_ppad_reg_bits ppad_reg; + struct mlx5_ifc_ppcnt_reg_bits ppcnt_reg; + struct mlx5_ifc_pplm_reg_bits pplm_reg; + struct mlx5_ifc_pplr_reg_bits pplr_reg; + struct mlx5_ifc_ppsc_reg_bits ppsc_reg; + struct mlx5_ifc_pqdr_reg_bits pqdr_reg; + struct mlx5_ifc_pspa_reg_bits pspa_reg; + struct mlx5_ifc_ptas_reg_bits ptas_reg; + struct mlx5_ifc_ptys_reg_bits ptys_reg; + struct mlx5_ifc_pude_reg_bits pude_reg; + struct mlx5_ifc_pvlc_reg_bits pvlc_reg; + struct mlx5_ifc_slrg_reg_bits slrg_reg; + struct mlx5_ifc_sltp_reg_bits sltp_reg; + u8 reserved_0[0x60e0]; +}; + +union mlx5_ifc_debug_enhancements_document_bits { + struct mlx5_ifc_health_buffer_bits health_buffer; + u8 reserved_0[0x200]; +}; + +union mlx5_ifc_uplink_pci_interface_document_bits { + struct mlx5_ifc_initial_seg_bits initial_seg; + u8 reserved_0[0x20060]; }; #endif /* MLX5_IFC_H */ diff --git a/include/linux/mlx5/qp.h b/include/linux/mlx5/qp.h index 310b5f7fd6ae..f079fb1a31f7 100644 --- a/include/linux/mlx5/qp.h +++ b/include/linux/mlx5/qp.h @@ -134,13 +134,21 @@ enum { enum { MLX5_WQE_CTRL_CQ_UPDATE = 2 << 2, + MLX5_WQE_CTRL_CQ_UPDATE_AND_EQE = 3 << 2, MLX5_WQE_CTRL_SOLICITED = 1 << 1, }; enum { + MLX5_SEND_WQE_DS = 16, MLX5_SEND_WQE_BB = 64, }; +#define MLX5_SEND_WQEBB_NUM_DS (MLX5_SEND_WQE_BB / MLX5_SEND_WQE_DS) + +enum { + MLX5_SEND_WQE_MAX_WQEBBS = 16, +}; + enum { MLX5_WQE_FMR_PERM_LOCAL_READ = 1 << 27, MLX5_WQE_FMR_PERM_LOCAL_WRITE = 1 << 28, @@ -200,6 +208,23 @@ struct mlx5_wqe_ctrl_seg { #define MLX5_WQE_CTRL_WQE_INDEX_MASK 0x00ffff00 #define MLX5_WQE_CTRL_WQE_INDEX_SHIFT 8 +enum { + MLX5_ETH_WQE_L3_INNER_CSUM = 1 << 4, + MLX5_ETH_WQE_L4_INNER_CSUM = 1 << 5, + MLX5_ETH_WQE_L3_CSUM = 1 << 6, + MLX5_ETH_WQE_L4_CSUM = 1 << 7, +}; + +struct mlx5_wqe_eth_seg { + u8 rsvd0[4]; + u8 cs_flags; + u8 rsvd1; + __be16 mss; + __be32 rsvd2; + __be16 inline_hdr_sz; + u8 inline_hdr_start[2]; +}; + struct mlx5_wqe_xrc_seg { __be32 xrc_srqn; u8 rsvd[12]; -- cgit v1.2.3 From 938fe83c8dcbbf294d167e6163200a8540ae43c4 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 28 May 2015 22:28:41 +0300 Subject: net/mlx5_core: New device capabilities handling - Query all supported types of dev caps on driver load. - Store the Cap data outbox per cap type into driver private data. - Introduce new Macros to access/dump stored caps (using the auto generated data types). - Obsolete SW representation of dev caps (no need for SW copy for each cap). - Modify IB driver to use new macros for checking caps. Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/cq.c | 8 +- drivers/infiniband/hw/mlx5/mad.c | 2 +- drivers/infiniband/hw/mlx5/main.c | 113 ++++++++------- drivers/infiniband/hw/mlx5/mlx5_ib.h | 6 +- drivers/infiniband/hw/mlx5/mr.c | 3 +- drivers/infiniband/hw/mlx5/odp.c | 47 +++---- drivers/infiniband/hw/mlx5/qp.c | 84 +++++------ drivers/infiniband/hw/mlx5/srq.c | 7 +- drivers/net/ethernet/mellanox/mlx5/core/eq.c | 4 +- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 90 +++++++----- drivers/net/ethernet/mellanox/mlx5/core/main.c | 154 +++++++-------------- .../net/ethernet/mellanox/mlx5/core/mlx5_core.h | 10 +- drivers/net/ethernet/mellanox/mlx5/core/uar.c | 7 +- include/linux/mlx5/device.h | 66 ++++++++- include/linux/mlx5/driver.h | 58 +------- 15 files changed, 310 insertions(+), 349 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 4e88b18cf62e..e2bea9ab93b3 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -753,7 +753,7 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, int entries, return ERR_PTR(-EINVAL); entries = roundup_pow_of_two(entries + 1); - if (entries > dev->mdev->caps.gen.max_cqes) + if (entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz))) return ERR_PTR(-EINVAL); cq = kzalloc(sizeof(*cq), GFP_KERNEL); @@ -920,7 +920,7 @@ int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) int err; u32 fsel; - if (!(dev->mdev->caps.gen.flags & MLX5_DEV_CAP_FLAG_CQ_MODER)) + if (!MLX5_CAP_GEN(dev->mdev, cq_moderation)) return -ENOSYS; in = kzalloc(sizeof(*in), GFP_KERNEL); @@ -1075,7 +1075,7 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) int uninitialized_var(cqe_size); unsigned long flags; - if (!(dev->mdev->caps.gen.flags & MLX5_DEV_CAP_FLAG_RESIZE_CQ)) { + if (!MLX5_CAP_GEN(dev->mdev, cq_resize)) { pr_info("Firmware does not support resize CQ\n"); return -ENOSYS; } @@ -1084,7 +1084,7 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) return -EINVAL; entries = roundup_pow_of_two(entries + 1); - if (entries > dev->mdev->caps.gen.max_cqes + 1) + if (entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz)) + 1) return -EINVAL; if (entries == ibcq->cqe + 1) diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c index 9cf9a37bb5ff..f2d9e70818d7 100644 --- a/drivers/infiniband/hw/mlx5/mad.c +++ b/drivers/infiniband/hw/mlx5/mad.c @@ -129,7 +129,7 @@ int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port) packet_error = be16_to_cpu(out_mad->status); - dev->mdev->caps.gen.ext_port_cap[port - 1] = (!err && !packet_error) ? + dev->mdev->port_caps[port - 1].ext_port_cap = (!err && !packet_error) ? MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO : 0; out: diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 57c9809e8b87..9075649f30fc 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -66,15 +66,13 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, struct ib_device_attr *props) { struct mlx5_ib_dev *dev = to_mdev(ibdev); + struct mlx5_core_dev *mdev = dev->mdev; struct ib_smp *in_mad = NULL; struct ib_smp *out_mad = NULL; - struct mlx5_general_caps *gen; int err = -ENOMEM; int max_rq_sg; int max_sq_sg; - u64 flags; - gen = &dev->mdev->caps.gen; in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL); out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL); if (!in_mad || !out_mad) @@ -96,18 +94,18 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, IB_DEVICE_PORT_ACTIVE_EVENT | IB_DEVICE_SYS_IMAGE_GUID | IB_DEVICE_RC_RNR_NAK_GEN; - flags = gen->flags; - if (flags & MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR) + + if (MLX5_CAP_GEN(mdev, pkv)) props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR; - if (flags & MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR) + if (MLX5_CAP_GEN(mdev, qkv)) props->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR; - if (flags & MLX5_DEV_CAP_FLAG_APM) + if (MLX5_CAP_GEN(mdev, apm)) props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG; props->device_cap_flags |= IB_DEVICE_LOCAL_DMA_LKEY; - if (flags & MLX5_DEV_CAP_FLAG_XRC) + if (MLX5_CAP_GEN(mdev, xrc)) props->device_cap_flags |= IB_DEVICE_XRC; props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS; - if (flags & MLX5_DEV_CAP_FLAG_SIG_HAND_OVER) { + if (MLX5_CAP_GEN(mdev, sho)) { props->device_cap_flags |= IB_DEVICE_SIGNATURE_HANDOVER; /* At this stage no support for signature handover */ props->sig_prot_cap = IB_PROT_T10DIF_TYPE_1 | @@ -116,7 +114,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, props->sig_guard_cap = IB_GUARD_T10DIF_CRC | IB_GUARD_T10DIF_CSUM; } - if (flags & MLX5_DEV_CAP_FLAG_BLOCK_MCAST) + if (MLX5_CAP_GEN(mdev, block_lb_mc)) props->device_cap_flags |= IB_DEVICE_BLOCK_MULTICAST_LOOPBACK; props->vendor_id = be32_to_cpup((__be32 *)(out_mad->data + 36)) & @@ -126,37 +124,38 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, memcpy(&props->sys_image_guid, out_mad->data + 4, 8); props->max_mr_size = ~0ull; - props->page_size_cap = gen->min_page_sz; - props->max_qp = 1 << gen->log_max_qp; - props->max_qp_wr = gen->max_wqes; - max_rq_sg = gen->max_rq_desc_sz / sizeof(struct mlx5_wqe_data_seg); - max_sq_sg = (gen->max_sq_desc_sz - sizeof(struct mlx5_wqe_ctrl_seg)) / - sizeof(struct mlx5_wqe_data_seg); + props->page_size_cap = 1ull << MLX5_CAP_GEN(mdev, log_pg_sz); + props->max_qp = 1 << MLX5_CAP_GEN(mdev, log_max_qp); + props->max_qp_wr = 1 << MLX5_CAP_GEN(mdev, log_max_qp_sz); + max_rq_sg = MLX5_CAP_GEN(mdev, max_wqe_sz_rq) / + sizeof(struct mlx5_wqe_data_seg); + max_sq_sg = (MLX5_CAP_GEN(mdev, max_wqe_sz_sq) - + sizeof(struct mlx5_wqe_ctrl_seg)) / + sizeof(struct mlx5_wqe_data_seg); props->max_sge = min(max_rq_sg, max_sq_sg); - props->max_cq = 1 << gen->log_max_cq; - props->max_cqe = gen->max_cqes - 1; - props->max_mr = 1 << gen->log_max_mkey; - props->max_pd = 1 << gen->log_max_pd; - props->max_qp_rd_atom = 1 << gen->log_max_ra_req_qp; - props->max_qp_init_rd_atom = 1 << gen->log_max_ra_res_qp; - props->max_srq = 1 << gen->log_max_srq; - props->max_srq_wr = gen->max_srq_wqes - 1; - props->local_ca_ack_delay = gen->local_ca_ack_delay; + props->max_cq = 1 << MLX5_CAP_GEN(mdev, log_max_cq); + props->max_cqe = (1 << MLX5_CAP_GEN(mdev, log_max_eq_sz)) - 1; + props->max_mr = 1 << MLX5_CAP_GEN(mdev, log_max_mkey); + props->max_pd = 1 << MLX5_CAP_GEN(mdev, log_max_pd); + props->max_qp_rd_atom = 1 << MLX5_CAP_GEN(mdev, log_max_ra_req_qp); + props->max_qp_init_rd_atom = 1 << MLX5_CAP_GEN(mdev, log_max_ra_res_qp); + props->max_srq = 1 << MLX5_CAP_GEN(mdev, log_max_srq); + props->max_srq_wr = (1 << MLX5_CAP_GEN(mdev, log_max_srq_sz)) - 1; + props->local_ca_ack_delay = MLX5_CAP_GEN(mdev, local_ca_ack_delay); props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; props->max_srq_sge = max_rq_sg - 1; props->max_fast_reg_page_list_len = (unsigned int)-1; - props->local_ca_ack_delay = gen->local_ca_ack_delay; props->atomic_cap = IB_ATOMIC_NONE; props->masked_atomic_cap = IB_ATOMIC_NONE; props->max_pkeys = be16_to_cpup((__be16 *)(out_mad->data + 28)); - props->max_mcast_grp = 1 << gen->log_max_mcg; - props->max_mcast_qp_attach = gen->max_qp_mcg; + props->max_mcast_grp = 1 << MLX5_CAP_GEN(mdev, log_max_mcg); + props->max_mcast_qp_attach = MLX5_CAP_GEN(mdev, max_qp_mcg); props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * props->max_mcast_grp; props->max_map_per_fmr = INT_MAX; /* no limit in ConnectIB */ #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - if (dev->mdev->caps.gen.flags & MLX5_DEV_CAP_FLAG_ON_DMND_PG) + if (MLX5_CAP_GEN(mdev, pg)) props->device_cap_flags |= IB_DEVICE_ON_DEMAND_PAGING; props->odp_caps = dev->odp_caps; #endif @@ -172,14 +171,13 @@ int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props) { struct mlx5_ib_dev *dev = to_mdev(ibdev); + struct mlx5_core_dev *mdev = dev->mdev; struct ib_smp *in_mad = NULL; struct ib_smp *out_mad = NULL; - struct mlx5_general_caps *gen; int ext_active_speed; int err = -ENOMEM; - gen = &dev->mdev->caps.gen; - if (port < 1 || port > gen->num_ports) { + if (port < 1 || port > MLX5_CAP_GEN(mdev, num_ports)) { mlx5_ib_warn(dev, "invalid port number %d\n", port); return -EINVAL; } @@ -210,8 +208,8 @@ int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, props->phys_state = out_mad->data[33] >> 4; props->port_cap_flags = be32_to_cpup((__be32 *)(out_mad->data + 20)); props->gid_tbl_len = out_mad->data[50]; - props->max_msg_sz = 1 << gen->log_max_msg; - props->pkey_tbl_len = gen->port[port - 1].pkey_table_len; + props->max_msg_sz = 1 << MLX5_CAP_GEN(mdev, log_max_msg); + props->pkey_tbl_len = mdev->port_caps[port - 1].pkey_table_len; props->bad_pkey_cntr = be16_to_cpup((__be16 *)(out_mad->data + 46)); props->qkey_viol_cntr = be16_to_cpup((__be16 *)(out_mad->data + 48)); props->active_width = out_mad->data[31] & 0xf; @@ -238,7 +236,7 @@ int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, /* If reported active speed is QDR, check if is FDR-10 */ if (props->active_speed == 4) { - if (gen->ext_port_cap[port - 1] & + if (mdev->port_caps[port - 1].ext_port_cap & MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO) { init_query_mad(in_mad); in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO; @@ -392,7 +390,6 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, struct mlx5_ib_alloc_ucontext_req_v2 req; struct mlx5_ib_alloc_ucontext_resp resp; struct mlx5_ib_ucontext *context; - struct mlx5_general_caps *gen; struct mlx5_uuar_info *uuari; struct mlx5_uar *uars; int gross_uuars; @@ -403,7 +400,6 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, int i; size_t reqlen; - gen = &dev->mdev->caps.gen; if (!dev->ib_active) return ERR_PTR(-EAGAIN); @@ -436,14 +432,14 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, num_uars = req.total_num_uuars / MLX5_NON_FP_BF_REGS_PER_PAGE; gross_uuars = num_uars * MLX5_BF_REGS_PER_PAGE; - resp.qp_tab_size = 1 << gen->log_max_qp; - resp.bf_reg_size = gen->bf_reg_size; - resp.cache_line_size = L1_CACHE_BYTES; - resp.max_sq_desc_sz = gen->max_sq_desc_sz; - resp.max_rq_desc_sz = gen->max_rq_desc_sz; - resp.max_send_wqebb = gen->max_wqes; - resp.max_recv_wr = gen->max_wqes; - resp.max_srq_recv_wr = gen->max_srq_wqes; + resp.qp_tab_size = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp); + resp.bf_reg_size = 1 << MLX5_CAP_GEN(dev->mdev, log_bf_reg_size); + resp.cache_line_size = L1_CACHE_BYTES; + resp.max_sq_desc_sz = MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq); + resp.max_rq_desc_sz = MLX5_CAP_GEN(dev->mdev, max_wqe_sz_rq); + resp.max_send_wqebb = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz); + resp.max_recv_wr = 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz); + resp.max_srq_recv_wr = 1 << MLX5_CAP_GEN(dev->mdev, log_max_srq_sz); context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) @@ -493,7 +489,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, mutex_init(&context->db_page_mutex); resp.tot_uuars = req.total_num_uuars; - resp.num_ports = gen->num_ports; + resp.num_ports = MLX5_CAP_GEN(dev->mdev, num_ports); err = ib_copy_to_udata(udata, &resp, sizeof(resp) - sizeof(resp.reserved)); if (err) @@ -895,11 +891,9 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context, static void get_ext_port_caps(struct mlx5_ib_dev *dev) { - struct mlx5_general_caps *gen; int port; - gen = &dev->mdev->caps.gen; - for (port = 1; port <= gen->num_ports; port++) + for (port = 1; port <= MLX5_CAP_GEN(dev->mdev, num_ports); port++) mlx5_query_ext_port_caps(dev, port); } @@ -907,11 +901,9 @@ static int get_port_caps(struct mlx5_ib_dev *dev) { struct ib_device_attr *dprops = NULL; struct ib_port_attr *pprops = NULL; - struct mlx5_general_caps *gen; int err = -ENOMEM; int port; - gen = &dev->mdev->caps.gen; pprops = kmalloc(sizeof(*pprops), GFP_KERNEL); if (!pprops) goto out; @@ -926,14 +918,17 @@ static int get_port_caps(struct mlx5_ib_dev *dev) goto out; } - for (port = 1; port <= gen->num_ports; port++) { + for (port = 1; port <= MLX5_CAP_GEN(dev->mdev, num_ports); port++) { err = mlx5_ib_query_port(&dev->ib_dev, port, pprops); if (err) { - mlx5_ib_warn(dev, "query_port %d failed %d\n", port, err); + mlx5_ib_warn(dev, "query_port %d failed %d\n", + port, err); break; } - gen->port[port - 1].pkey_table_len = dprops->max_pkeys; - gen->port[port - 1].gid_table_len = pprops->gid_tbl_len; + dev->mdev->port_caps[port - 1].pkey_table_len = + dprops->max_pkeys; + dev->mdev->port_caps[port - 1].gid_table_len = + pprops->gid_tbl_len; mlx5_ib_dbg(dev, "pkey_table_len %d, gid_table_len %d\n", dprops->max_pkeys, pprops->gid_tbl_len); } @@ -1207,8 +1202,8 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) strlcpy(dev->ib_dev.name, "mlx5_%d", IB_DEVICE_NAME_MAX); dev->ib_dev.owner = THIS_MODULE; dev->ib_dev.node_type = RDMA_NODE_IB_CA; - dev->ib_dev.local_dma_lkey = mdev->caps.gen.reserved_lkey; - dev->num_ports = mdev->caps.gen.num_ports; + dev->ib_dev.local_dma_lkey = 0 /* not supported for now */; + dev->num_ports = MLX5_CAP_GEN(mdev, num_ports); dev->ib_dev.phys_port_cnt = dev->num_ports; dev->ib_dev.num_comp_vectors = dev->mdev->priv.eq_table.num_comp_vectors; @@ -1286,9 +1281,9 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) dev->ib_dev.free_fast_reg_page_list = mlx5_ib_free_fast_reg_page_list; dev->ib_dev.check_mr_status = mlx5_ib_check_mr_status; - mlx5_ib_internal_query_odp_caps(dev); + mlx5_ib_internal_fill_odp_caps(dev); - if (mdev->caps.gen.flags & MLX5_DEV_CAP_FLAG_XRC) { + if (MLX5_CAP_GEN(mdev, xrc)) { dev->ib_dev.alloc_xrcd = mlx5_ib_alloc_xrcd; dev->ib_dev.dealloc_xrcd = mlx5_ib_dealloc_xrcd; dev->ib_dev.uverbs_cmd_mask |= diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index dff1cfcdf476..0c441add0464 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -617,7 +617,7 @@ int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask, #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING extern struct workqueue_struct *mlx5_ib_page_fault_wq; -int mlx5_ib_internal_query_odp_caps(struct mlx5_ib_dev *dev); +void mlx5_ib_internal_fill_odp_caps(struct mlx5_ib_dev *dev); void mlx5_ib_mr_pfault_handler(struct mlx5_ib_qp *qp, struct mlx5_ib_pfault *pfault); void mlx5_ib_odp_create_qp(struct mlx5_ib_qp *qp); @@ -631,9 +631,9 @@ void mlx5_ib_invalidate_range(struct ib_umem *umem, unsigned long start, unsigned long end); #else /* CONFIG_INFINIBAND_ON_DEMAND_PAGING */ -static inline int mlx5_ib_internal_query_odp_caps(struct mlx5_ib_dev *dev) +static inline void mlx5_ib_internal_fill_odp_caps(struct mlx5_ib_dev *dev) { - return 0; + return; } static inline void mlx5_ib_odp_create_qp(struct mlx5_ib_qp *qp) {} diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 71c593583864..bc9a0de897cb 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -975,8 +975,7 @@ static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr, struct mlx5_ib_mr *mr; int inlen; int err; - bool pg_cap = !!(dev->mdev->caps.gen.flags & - MLX5_DEV_CAP_FLAG_ON_DMND_PG); + bool pg_cap = !!(MLX5_CAP_GEN(dev->mdev, pg)); mr = kzalloc(sizeof(*mr), GFP_KERNEL); if (!mr) diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c index 5099db08afd2..aa8391e75385 100644 --- a/drivers/infiniband/hw/mlx5/odp.c +++ b/drivers/infiniband/hw/mlx5/odp.c @@ -109,40 +109,33 @@ void mlx5_ib_invalidate_range(struct ib_umem *umem, unsigned long start, ib_umem_odp_unmap_dma_pages(umem, start, end); } -#define COPY_ODP_BIT_MLX_TO_IB(reg, ib_caps, field_name, bit_name) do { \ - if (be32_to_cpu(reg.field_name) & MLX5_ODP_SUPPORT_##bit_name) \ - ib_caps->field_name |= IB_ODP_SUPPORT_##bit_name; \ -} while (0) - -int mlx5_ib_internal_query_odp_caps(struct mlx5_ib_dev *dev) +void mlx5_ib_internal_fill_odp_caps(struct mlx5_ib_dev *dev) { - int err; - struct mlx5_odp_caps hw_caps; struct ib_odp_caps *caps = &dev->odp_caps; memset(caps, 0, sizeof(*caps)); - if (!(dev->mdev->caps.gen.flags & MLX5_DEV_CAP_FLAG_ON_DMND_PG)) - return 0; - - err = mlx5_query_odp_caps(dev->mdev, &hw_caps); - if (err) - goto out; + if (!MLX5_CAP_GEN(dev->mdev, pg)) + return; caps->general_caps = IB_ODP_SUPPORT; - COPY_ODP_BIT_MLX_TO_IB(hw_caps, caps, per_transport_caps.ud_odp_caps, - SEND); - COPY_ODP_BIT_MLX_TO_IB(hw_caps, caps, per_transport_caps.rc_odp_caps, - SEND); - COPY_ODP_BIT_MLX_TO_IB(hw_caps, caps, per_transport_caps.rc_odp_caps, - RECV); - COPY_ODP_BIT_MLX_TO_IB(hw_caps, caps, per_transport_caps.rc_odp_caps, - WRITE); - COPY_ODP_BIT_MLX_TO_IB(hw_caps, caps, per_transport_caps.rc_odp_caps, - READ); - -out: - return err; + + if (MLX5_CAP_ODP(dev->mdev, ud_odp_caps.send)) + caps->per_transport_caps.ud_odp_caps |= IB_ODP_SUPPORT_SEND; + + if (MLX5_CAP_ODP(dev->mdev, rc_odp_caps.send)) + caps->per_transport_caps.rc_odp_caps |= IB_ODP_SUPPORT_SEND; + + if (MLX5_CAP_ODP(dev->mdev, rc_odp_caps.receive)) + caps->per_transport_caps.rc_odp_caps |= IB_ODP_SUPPORT_RECV; + + if (MLX5_CAP_ODP(dev->mdev, rc_odp_caps.write)) + caps->per_transport_caps.rc_odp_caps |= IB_ODP_SUPPORT_WRITE; + + if (MLX5_CAP_ODP(dev->mdev, rc_odp_caps.read)) + caps->per_transport_caps.rc_odp_caps |= IB_ODP_SUPPORT_READ; + + return; } static struct mlx5_ib_mr *mlx5_ib_odp_find_mr_lkey(struct mlx5_ib_dev *dev, diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 426eb88dfa49..15fd485d1ad9 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -220,13 +220,11 @@ static void mlx5_ib_qp_event(struct mlx5_core_qp *qp, int type) static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap, int has_rq, struct mlx5_ib_qp *qp, struct mlx5_ib_create_qp *ucmd) { - struct mlx5_general_caps *gen; int wqe_size; int wq_size; - gen = &dev->mdev->caps.gen; /* Sanity check RQ size before proceeding */ - if (cap->max_recv_wr > gen->max_wqes) + if (cap->max_recv_wr > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) return -EINVAL; if (!has_rq) { @@ -246,10 +244,11 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap, wq_size = roundup_pow_of_two(cap->max_recv_wr) * wqe_size; wq_size = max_t(int, wq_size, MLX5_SEND_WQE_BB); qp->rq.wqe_cnt = wq_size / wqe_size; - if (wqe_size > gen->max_rq_desc_sz) { + if (wqe_size > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_rq)) { mlx5_ib_dbg(dev, "wqe_size %d, max %d\n", wqe_size, - gen->max_rq_desc_sz); + MLX5_CAP_GEN(dev->mdev, + max_wqe_sz_rq)); return -EINVAL; } qp->rq.wqe_shift = ilog2(wqe_size); @@ -330,11 +329,9 @@ static int calc_send_wqe(struct ib_qp_init_attr *attr) static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, struct mlx5_ib_qp *qp) { - struct mlx5_general_caps *gen; int wqe_size; int wq_size; - gen = &dev->mdev->caps.gen; if (!attr->cap.max_send_wr) return 0; @@ -343,9 +340,9 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, if (wqe_size < 0) return wqe_size; - if (wqe_size > gen->max_sq_desc_sz) { + if (wqe_size > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)) { mlx5_ib_dbg(dev, "wqe_size(%d) > max_sq_desc_sz(%d)\n", - wqe_size, gen->max_sq_desc_sz); + wqe_size, MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)); return -EINVAL; } @@ -358,9 +355,10 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size); qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB; - if (qp->sq.wqe_cnt > gen->max_wqes) { + if (qp->sq.wqe_cnt > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) { mlx5_ib_dbg(dev, "wqe count(%d) exceeds limits(%d)\n", - qp->sq.wqe_cnt, gen->max_wqes); + qp->sq.wqe_cnt, + 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz)); return -ENOMEM; } qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB); @@ -375,13 +373,11 @@ static int set_user_buf_size(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, struct mlx5_ib_create_qp *ucmd) { - struct mlx5_general_caps *gen; int desc_sz = 1 << qp->sq.wqe_shift; - gen = &dev->mdev->caps.gen; - if (desc_sz > gen->max_sq_desc_sz) { + if (desc_sz > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)) { mlx5_ib_warn(dev, "desc_sz %d, max_sq_desc_sz %d\n", - desc_sz, gen->max_sq_desc_sz); + desc_sz, MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)); return -EINVAL; } @@ -393,9 +389,10 @@ static int set_user_buf_size(struct mlx5_ib_dev *dev, qp->sq.wqe_cnt = ucmd->sq_wqe_count; - if (qp->sq.wqe_cnt > gen->max_wqes) { + if (qp->sq.wqe_cnt > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) { mlx5_ib_warn(dev, "wqe_cnt %d, max_wqes %d\n", - qp->sq.wqe_cnt, gen->max_wqes); + qp->sq.wqe_cnt, + 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz)); return -EINVAL; } @@ -866,22 +863,21 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, struct ib_udata *udata, struct mlx5_ib_qp *qp) { struct mlx5_ib_resources *devr = &dev->devr; + struct mlx5_core_dev *mdev = dev->mdev; struct mlx5_ib_create_qp_resp resp; struct mlx5_create_qp_mbox_in *in; - struct mlx5_general_caps *gen; struct mlx5_ib_create_qp ucmd; int inlen = sizeof(*in); int err; mlx5_ib_odp_create_qp(qp); - gen = &dev->mdev->caps.gen; mutex_init(&qp->mutex); spin_lock_init(&qp->sq.lock); spin_lock_init(&qp->rq.lock); if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) { - if (!(gen->flags & MLX5_DEV_CAP_FLAG_BLOCK_MCAST)) { + if (!MLX5_CAP_GEN(mdev, block_lb_mc)) { mlx5_ib_dbg(dev, "block multicast loopback isn't supported\n"); return -EINVAL; } else { @@ -914,15 +910,17 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, if (pd) { if (pd->uobject) { + __u32 max_wqes = + 1 << MLX5_CAP_GEN(mdev, log_max_qp_sz); mlx5_ib_dbg(dev, "requested sq_wqe_count (%d)\n", ucmd.sq_wqe_count); if (ucmd.rq_wqe_shift != qp->rq.wqe_shift || ucmd.rq_wqe_count != qp->rq.wqe_cnt) { mlx5_ib_dbg(dev, "invalid rq params\n"); return -EINVAL; } - if (ucmd.sq_wqe_count > gen->max_wqes) { + if (ucmd.sq_wqe_count > max_wqes) { mlx5_ib_dbg(dev, "requested sq_wqe_count (%d) > max allowed (%d)\n", - ucmd.sq_wqe_count, gen->max_wqes); + ucmd.sq_wqe_count, max_wqes); return -EINVAL; } err = create_user_qp(dev, pd, qp, udata, &in, &resp, &inlen); @@ -1226,7 +1224,6 @@ struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *init_attr, struct ib_udata *udata) { - struct mlx5_general_caps *gen; struct mlx5_ib_dev *dev; struct mlx5_ib_qp *qp; u16 xrcdn = 0; @@ -1244,12 +1241,11 @@ struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd, } dev = to_mdev(to_mxrcd(init_attr->xrcd)->ibxrcd.device); } - gen = &dev->mdev->caps.gen; switch (init_attr->qp_type) { case IB_QPT_XRC_TGT: case IB_QPT_XRC_INI: - if (!(gen->flags & MLX5_DEV_CAP_FLAG_XRC)) { + if (!MLX5_CAP_GEN(dev->mdev, xrc)) { mlx5_ib_dbg(dev, "XRC not supported\n"); return ERR_PTR(-ENOSYS); } @@ -1356,9 +1352,6 @@ enum { static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate) { - struct mlx5_general_caps *gen; - - gen = &dev->mdev->caps.gen; if (rate == IB_RATE_PORT_CURRENT) { return 0; } else if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_300_GBPS) { @@ -1366,7 +1359,7 @@ static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate) } else { while (rate != IB_RATE_2_5_GBPS && !(1 << (rate + MLX5_STAT_RATE_OFFSET) & - gen->stat_rate_support)) + MLX5_CAP_GEN(dev->mdev, stat_rate_support))) --rate; } @@ -1377,10 +1370,8 @@ static int mlx5_set_path(struct mlx5_ib_dev *dev, const struct ib_ah_attr *ah, struct mlx5_qp_path *path, u8 port, int attr_mask, u32 path_flags, const struct ib_qp_attr *attr) { - struct mlx5_general_caps *gen; int err; - gen = &dev->mdev->caps.gen; path->fl = (path_flags & MLX5_PATH_FLAG_FL) ? 0x80 : 0; path->free_ar = (path_flags & MLX5_PATH_FLAG_FREE_AR) ? 0x80 : 0; @@ -1391,9 +1382,11 @@ static int mlx5_set_path(struct mlx5_ib_dev *dev, const struct ib_ah_attr *ah, path->rlid = cpu_to_be16(ah->dlid); if (ah->ah_flags & IB_AH_GRH) { - if (ah->grh.sgid_index >= gen->port[port - 1].gid_table_len) { + if (ah->grh.sgid_index >= + dev->mdev->port_caps[port - 1].gid_table_len) { pr_err("sgid_index (%u) too large. max is %d\n", - ah->grh.sgid_index, gen->port[port - 1].gid_table_len); + ah->grh.sgid_index, + dev->mdev->port_caps[port - 1].gid_table_len); return -EINVAL; } path->grh_mlid |= 1 << 7; @@ -1570,7 +1563,6 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, struct mlx5_ib_qp *qp = to_mqp(ibqp); struct mlx5_ib_cq *send_cq, *recv_cq; struct mlx5_qp_context *context; - struct mlx5_general_caps *gen; struct mlx5_modify_qp_mbox_in *in; struct mlx5_ib_pd *pd; enum mlx5_qp_state mlx5_cur, mlx5_new; @@ -1579,7 +1571,6 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, int mlx5_st; int err; - gen = &dev->mdev->caps.gen; in = kzalloc(sizeof(*in), GFP_KERNEL); if (!in) return -ENOMEM; @@ -1619,7 +1610,8 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, err = -EINVAL; goto out; } - context->mtu_msgmax = (attr->path_mtu << 5) | gen->log_max_msg; + context->mtu_msgmax = (attr->path_mtu << 5) | + (u8)MLX5_CAP_GEN(dev->mdev, log_max_msg); } if (attr_mask & IB_QP_DEST_QPN) @@ -1777,11 +1769,9 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, struct mlx5_ib_dev *dev = to_mdev(ibqp->device); struct mlx5_ib_qp *qp = to_mqp(ibqp); enum ib_qp_state cur_state, new_state; - struct mlx5_general_caps *gen; int err = -EINVAL; int port; - gen = &dev->mdev->caps.gen; mutex_lock(&qp->mutex); cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state; @@ -1793,21 +1783,25 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, goto out; if ((attr_mask & IB_QP_PORT) && - (attr->port_num == 0 || attr->port_num > gen->num_ports)) + (attr->port_num == 0 || + attr->port_num > MLX5_CAP_GEN(dev->mdev, num_ports))) goto out; if (attr_mask & IB_QP_PKEY_INDEX) { port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port; - if (attr->pkey_index >= gen->port[port - 1].pkey_table_len) + if (attr->pkey_index >= + dev->mdev->port_caps[port - 1].pkey_table_len) goto out; } if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && - attr->max_rd_atomic > (1 << gen->log_max_ra_res_qp)) + attr->max_rd_atomic > + (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_res_qp))) goto out; if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && - attr->max_dest_rd_atomic > (1 << gen->log_max_ra_req_qp)) + attr->max_dest_rd_atomic > + (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_req_qp))) goto out; if (cur_state == new_state && cur_state == IB_QPS_RESET) { @@ -3009,7 +3003,7 @@ static void to_ib_ah_attr(struct mlx5_ib_dev *ibdev, struct ib_ah_attr *ib_ah_at ib_ah_attr->port_num = path->port; if (ib_ah_attr->port_num == 0 || - ib_ah_attr->port_num > dev->caps.gen.num_ports) + ib_ah_attr->port_num > MLX5_CAP_GEN(dev, num_ports)) return; ib_ah_attr->sl = path->sl & 0xf; @@ -3135,12 +3129,10 @@ struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev, struct ib_udata *udata) { struct mlx5_ib_dev *dev = to_mdev(ibdev); - struct mlx5_general_caps *gen; struct mlx5_ib_xrcd *xrcd; int err; - gen = &dev->mdev->caps.gen; - if (!(gen->flags & MLX5_DEV_CAP_FLAG_XRC)) + if (!MLX5_CAP_GEN(dev->mdev, xrc)) return ERR_PTR(-ENOSYS); xrcd = kmalloc(sizeof(*xrcd), GFP_KERNEL); diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 4242e1ded868..e8e8e942fa4a 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -236,7 +236,6 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, struct ib_udata *udata) { struct mlx5_ib_dev *dev = to_mdev(pd->device); - struct mlx5_general_caps *gen; struct mlx5_ib_srq *srq; int desc_size; int buf_size; @@ -245,13 +244,13 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, int uninitialized_var(inlen); int is_xrc; u32 flgs, xrcdn; + __u32 max_srq_wqes = 1 << MLX5_CAP_GEN(dev->mdev, log_max_srq_sz); - gen = &dev->mdev->caps.gen; /* Sanity check SRQ size before proceeding */ - if (init_attr->attr.max_wr >= gen->max_srq_wqes) { + if (init_attr->attr.max_wr >= max_srq_wqes) { mlx5_ib_dbg(dev, "max_wr %d, cap %d\n", init_attr->attr.max_wr, - gen->max_srq_wqes); + max_srq_wqes); return ERR_PTR(-EINVAL); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 516efc25fc4f..a40b96d4c662 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -455,7 +455,7 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev) u32 async_event_mask = MLX5_ASYNC_EVENT_MASK; int err; - if (dev->caps.gen.flags & MLX5_DEV_CAP_FLAG_ON_DMND_PG) + if (MLX5_CAP_GEN(dev, pg)) async_event_mask |= (1ull << MLX5_EVENT_TYPE_PAGE_FAULT); err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD, @@ -478,7 +478,7 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev) err = mlx5_create_map_eq(dev, &table->pages_eq, MLX5_EQ_VEC_PAGES, - dev->caps.gen.max_vf + 1, + /* TODO: sriov max_vf + */ 1, 1 << MLX5_EVENT_TYPE_PAGE_REQUEST, "mlx5_pages_eq", &dev->priv.uuari.uars[0]); if (err) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index ef9b7695decd..801ccadd709a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -64,50 +64,74 @@ out_out: return err; } -int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev, struct mlx5_caps *caps) +int mlx5_query_hca_caps(struct mlx5_core_dev *dev) { - return mlx5_core_get_caps(dev, caps, HCA_CAP_OPMOD_GET_CUR); -} - -int mlx5_query_odp_caps(struct mlx5_core_dev *dev, struct mlx5_odp_caps *caps) -{ - u8 in[MLX5_ST_SZ_BYTES(query_hca_cap_in)]; - int out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out); - void *out; int err; - if (!(dev->caps.gen.flags & MLX5_DEV_CAP_FLAG_ON_DMND_PG)) - return -ENOTSUPP; + err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL, HCA_CAP_OPMOD_GET_CUR); + if (err) + return err; - memset(in, 0, sizeof(in)); - out = kzalloc(out_sz, GFP_KERNEL); - if (!out) - return -ENOMEM; - MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); - MLX5_SET(query_hca_cap_in, in, op_mod, HCA_CAP_OPMOD_GET_ODP_CUR); - err = mlx5_cmd_exec(dev, in, sizeof(in), out, out_sz); + err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL, HCA_CAP_OPMOD_GET_MAX); if (err) - goto out; + return err; - err = mlx5_cmd_status_to_err_v2(out); - if (err) { - mlx5_core_warn(dev, "query cur hca ODP caps failed, %d\n", err); - goto out; + if (MLX5_CAP_GEN(dev, eth_net_offloads)) { + err = mlx5_core_get_caps(dev, MLX5_CAP_ETHERNET_OFFLOADS, + HCA_CAP_OPMOD_GET_CUR); + if (err) + return err; + err = mlx5_core_get_caps(dev, MLX5_CAP_ETHERNET_OFFLOADS, + HCA_CAP_OPMOD_GET_MAX); + if (err) + return err; } - memcpy(caps, MLX5_ADDR_OF(query_hca_cap_out, out, capability), - sizeof(*caps)); + if (MLX5_CAP_GEN(dev, pg)) { + err = mlx5_core_get_caps(dev, MLX5_CAP_ODP, + HCA_CAP_OPMOD_GET_CUR); + if (err) + return err; + err = mlx5_core_get_caps(dev, MLX5_CAP_ODP, + HCA_CAP_OPMOD_GET_MAX); + if (err) + return err; + } - mlx5_core_dbg(dev, "on-demand paging capabilities:\nrc: %08x\nuc: %08x\nud: %08x\n", - be32_to_cpu(caps->per_transport_caps.rc_odp_caps), - be32_to_cpu(caps->per_transport_caps.uc_odp_caps), - be32_to_cpu(caps->per_transport_caps.ud_odp_caps)); + if (MLX5_CAP_GEN(dev, atomic)) { + err = mlx5_core_get_caps(dev, MLX5_CAP_ATOMIC, + HCA_CAP_OPMOD_GET_CUR); + if (err) + return err; + err = mlx5_core_get_caps(dev, MLX5_CAP_ATOMIC, + HCA_CAP_OPMOD_GET_MAX); + if (err) + return err; + } -out: - kfree(out); - return err; + if (MLX5_CAP_GEN(dev, roce)) { + err = mlx5_core_get_caps(dev, MLX5_CAP_ROCE, + HCA_CAP_OPMOD_GET_CUR); + if (err) + return err; + err = mlx5_core_get_caps(dev, MLX5_CAP_ROCE, + HCA_CAP_OPMOD_GET_MAX); + if (err) + return err; + } + + if (MLX5_CAP_GEN(dev, nic_flow_table)) { + err = mlx5_core_get_caps(dev, MLX5_CAP_FLOW_TABLE, + HCA_CAP_OPMOD_GET_CUR); + if (err) + return err; + err = mlx5_core_get_caps(dev, MLX5_CAP_FLOW_TABLE, + HCA_CAP_OPMOD_GET_MAX); + if (err) + return err; + } + return 0; } -EXPORT_SYMBOL(mlx5_query_odp_caps); int mlx5_cmd_init_hca(struct mlx5_core_dev *dev) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index a652cb93ceaa..e7b7b123a128 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -211,11 +211,12 @@ static int mlx5_enable_msix(struct mlx5_core_dev *dev) { struct mlx5_priv *priv = &dev->priv; struct mlx5_eq_table *table = &priv->eq_table; - int num_eqs = 1 << dev->caps.gen.log_max_eq; + int num_eqs = 1 << MLX5_CAP_GEN(dev, log_max_eq); int nvec; int i; - nvec = dev->caps.gen.num_ports * num_online_cpus() + MLX5_EQ_VEC_COMP_BASE; + nvec = MLX5_CAP_GEN(dev, num_ports) * num_online_cpus() + + MLX5_EQ_VEC_COMP_BASE; nvec = min_t(int, nvec, num_eqs); if (nvec <= MLX5_EQ_VEC_COMP_BASE) return -ENOMEM; @@ -287,97 +288,28 @@ static u16 to_fw_pkey_sz(u32 size) } } -/* selectively copy writable fields clearing any reserved area - */ -static void copy_rw_fields(void *to, struct mlx5_caps *from) -{ - __be64 *flags_off = (__be64 *)MLX5_ADDR_OF(cmd_hca_cap, to, reserved_22); - u64 v64; - - MLX5_SET(cmd_hca_cap, to, log_max_qp, from->gen.log_max_qp); - MLX5_SET(cmd_hca_cap, to, log_max_ra_req_qp, from->gen.log_max_ra_req_qp); - MLX5_SET(cmd_hca_cap, to, log_max_ra_res_qp, from->gen.log_max_ra_res_qp); - MLX5_SET(cmd_hca_cap, to, pkey_table_size, from->gen.pkey_table_size); - MLX5_SET(cmd_hca_cap, to, pkey_table_size, to_fw_pkey_sz(from->gen.pkey_table_size)); - MLX5_SET(cmd_hca_cap, to, log_uar_page_sz, PAGE_SHIFT - 12); - v64 = from->gen.flags & MLX5_CAP_BITS_RW_MASK; - *flags_off = cpu_to_be64(v64); -} - -static u16 get_pkey_table_size(int pkey) +static u16 to_sw_pkey_sz(int pkey_sz) { - if (pkey > MLX5_MAX_LOG_PKEY_TABLE) + if (pkey_sz > MLX5_MAX_LOG_PKEY_TABLE) return 0; - return MLX5_MIN_PKEY_TABLE_SIZE << pkey; -} - -static void fw2drv_caps(struct mlx5_caps *caps, void *out) -{ - struct mlx5_general_caps *gen = &caps->gen; - - gen->max_srq_wqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_srq_sz); - gen->max_wqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_qp_sz); - gen->log_max_qp = MLX5_GET_PR(cmd_hca_cap, out, log_max_qp); - gen->log_max_srq = MLX5_GET_PR(cmd_hca_cap, out, log_max_srq); - gen->max_cqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_cq_sz); - gen->log_max_cq = MLX5_GET_PR(cmd_hca_cap, out, log_max_cq); - gen->max_eqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_eq_sz); - gen->log_max_mkey = MLX5_GET_PR(cmd_hca_cap, out, log_max_mkey); - gen->log_max_eq = MLX5_GET_PR(cmd_hca_cap, out, log_max_eq); - gen->max_indirection = MLX5_GET_PR(cmd_hca_cap, out, max_indirection); - gen->log_max_mrw_sz = MLX5_GET_PR(cmd_hca_cap, out, log_max_mrw_sz); - gen->log_max_bsf_list_size = MLX5_GET_PR(cmd_hca_cap, out, log_max_bsf_list_size); - gen->log_max_klm_list_size = MLX5_GET_PR(cmd_hca_cap, out, log_max_klm_list_size); - gen->log_max_ra_req_dc = MLX5_GET_PR(cmd_hca_cap, out, log_max_ra_req_dc); - gen->log_max_ra_res_dc = MLX5_GET_PR(cmd_hca_cap, out, log_max_ra_res_dc); - gen->log_max_ra_req_qp = MLX5_GET_PR(cmd_hca_cap, out, log_max_ra_req_qp); - gen->log_max_ra_res_qp = MLX5_GET_PR(cmd_hca_cap, out, log_max_ra_res_qp); - gen->max_qp_counters = MLX5_GET_PR(cmd_hca_cap, out, max_qp_cnt); - gen->pkey_table_size = get_pkey_table_size(MLX5_GET_PR(cmd_hca_cap, out, pkey_table_size)); - gen->local_ca_ack_delay = MLX5_GET_PR(cmd_hca_cap, out, local_ca_ack_delay); - gen->num_ports = MLX5_GET_PR(cmd_hca_cap, out, num_ports); - gen->log_max_msg = MLX5_GET_PR(cmd_hca_cap, out, log_max_msg); - gen->stat_rate_support = MLX5_GET_PR(cmd_hca_cap, out, stat_rate_support); - gen->flags = be64_to_cpu(*(__be64 *)MLX5_ADDR_OF(cmd_hca_cap, out, reserved_22)); - pr_debug("flags = 0x%llx\n", gen->flags); - gen->uar_sz = MLX5_GET_PR(cmd_hca_cap, out, uar_sz); - gen->min_log_pg_sz = MLX5_GET_PR(cmd_hca_cap, out, log_pg_sz); - gen->bf_reg_size = MLX5_GET_PR(cmd_hca_cap, out, bf); - gen->bf_reg_size = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_bf_reg_size); - gen->max_sq_desc_sz = MLX5_GET_PR(cmd_hca_cap, out, max_wqe_sz_sq); - gen->max_rq_desc_sz = MLX5_GET_PR(cmd_hca_cap, out, max_wqe_sz_rq); - gen->max_dc_sq_desc_sz = MLX5_GET_PR(cmd_hca_cap, out, max_wqe_sz_sq_dc); - gen->max_qp_mcg = MLX5_GET_PR(cmd_hca_cap, out, max_qp_mcg); - gen->log_max_pd = MLX5_GET_PR(cmd_hca_cap, out, log_max_pd); - gen->log_max_xrcd = MLX5_GET_PR(cmd_hca_cap, out, log_max_xrcd); - gen->log_uar_page_sz = MLX5_GET_PR(cmd_hca_cap, out, log_uar_page_sz); -} - -static const char *caps_opmod_str(u16 opmod) -{ - switch (opmod) { - case HCA_CAP_OPMOD_GET_MAX: - return "GET_MAX"; - case HCA_CAP_OPMOD_GET_CUR: - return "GET_CUR"; - default: - return "Invalid"; - } + return MLX5_MIN_PKEY_TABLE_SIZE << pkey_sz; } -int mlx5_core_get_caps(struct mlx5_core_dev *dev, struct mlx5_caps *caps, - u16 opmod) +int mlx5_core_get_caps(struct mlx5_core_dev *dev, enum mlx5_cap_type cap_type, + enum mlx5_cap_mode cap_mode) { u8 in[MLX5_ST_SZ_BYTES(query_hca_cap_in)]; int out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out); - void *out; + void *out, *hca_caps; + u16 opmod = (cap_type << 1) | (cap_mode & 0x01); int err; memset(in, 0, sizeof(in)); out = kzalloc(out_sz, GFP_KERNEL); if (!out) return -ENOMEM; + MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); MLX5_SET(query_hca_cap_in, in, op_mod, opmod); err = mlx5_cmd_exec(dev, in, sizeof(in), out, out_sz); @@ -386,12 +318,30 @@ int mlx5_core_get_caps(struct mlx5_core_dev *dev, struct mlx5_caps *caps, err = mlx5_cmd_status_to_err_v2(out); if (err) { - mlx5_core_warn(dev, "query max hca cap failed, %d\n", err); + mlx5_core_warn(dev, + "QUERY_HCA_CAP : type(%x) opmode(%x) Failed(%d)\n", + cap_type, cap_mode, err); goto query_ex; } - mlx5_core_dbg(dev, "%s\n", caps_opmod_str(opmod)); - fw2drv_caps(caps, MLX5_ADDR_OF(query_hca_cap_out, out, capability)); + hca_caps = MLX5_ADDR_OF(query_hca_cap_out, out, capability); + + switch (cap_mode) { + case HCA_CAP_OPMOD_GET_MAX: + memcpy(dev->hca_caps_max[cap_type], hca_caps, + MLX5_UN_SZ_BYTES(hca_cap_union)); + break; + case HCA_CAP_OPMOD_GET_CUR: + memcpy(dev->hca_caps_cur[cap_type], hca_caps, + MLX5_UN_SZ_BYTES(hca_cap_union)); + break; + default: + mlx5_core_warn(dev, + "Tried to query dev cap type(%x) with wrong opmode(%x)\n", + cap_type, cap_mode); + err = -EINVAL; + break; + } query_ex: kfree(out); return err; @@ -418,49 +368,45 @@ static int handle_hca_cap(struct mlx5_core_dev *dev) { void *set_ctx = NULL; struct mlx5_profile *prof = dev->profile; - struct mlx5_caps *cur_caps = NULL; - struct mlx5_caps *max_caps = NULL; int err = -ENOMEM; int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in); + void *set_hca_cap; set_ctx = kzalloc(set_sz, GFP_KERNEL); if (!set_ctx) goto query_ex; - max_caps = kzalloc(sizeof(*max_caps), GFP_KERNEL); - if (!max_caps) - goto query_ex; - - cur_caps = kzalloc(sizeof(*cur_caps), GFP_KERNEL); - if (!cur_caps) - goto query_ex; - - err = mlx5_core_get_caps(dev, max_caps, HCA_CAP_OPMOD_GET_MAX); + err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL, HCA_CAP_OPMOD_GET_MAX); if (err) goto query_ex; - err = mlx5_core_get_caps(dev, cur_caps, HCA_CAP_OPMOD_GET_CUR); + err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL, HCA_CAP_OPMOD_GET_CUR); if (err) goto query_ex; + set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, + capability); + memcpy(set_hca_cap, dev->hca_caps_cur[MLX5_CAP_GENERAL], + MLX5_ST_SZ_BYTES(cmd_hca_cap)); + + mlx5_core_dbg(dev, "Current Pkey table size %d Setting new size %d\n", + to_sw_pkey_sz(MLX5_CAP_GEN(dev, pkey_table_size)), + 128); /* we limit the size of the pkey table to 128 entries for now */ - cur_caps->gen.pkey_table_size = 128; + MLX5_SET(cmd_hca_cap, set_hca_cap, pkey_table_size, + to_fw_pkey_sz(128)); if (prof->mask & MLX5_PROF_MASK_QP_SIZE) - cur_caps->gen.log_max_qp = prof->log_max_qp; + MLX5_SET(cmd_hca_cap, set_hca_cap, log_max_qp, + prof->log_max_qp); - /* disable checksum */ - cur_caps->gen.flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM; + /* disable cmdif checksum */ + MLX5_SET(cmd_hca_cap, set_hca_cap, cmdif_checksum, 0); - copy_rw_fields(MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability), - cur_caps); err = set_caps(dev, set_ctx, set_sz); query_ex: - kfree(cur_caps); - kfree(max_caps); kfree(set_ctx); - return err; } @@ -768,7 +714,7 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) mlx5_start_health_poll(dev); - err = mlx5_cmd_query_hca_cap(dev, &dev->caps); + err = mlx5_query_hca_caps(dev); if (err) { dev_err(&pdev->dev, "query hca failed\n"); goto err_stop_poll; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index a051b906afdf..b986f1c258bc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -65,9 +65,15 @@ enum { MLX5_CMD_TIME, /* print command execution time */ }; +static inline int mlx5_cmd_exec_check_status(struct mlx5_core_dev *dev, u32 *in, + int in_size, u32 *out, + int out_size) +{ + mlx5_cmd_exec(dev, in, in_size, out, out_size); + return mlx5_cmd_status_to_err((struct mlx5_outbox_hdr *)out); +} -int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev, - struct mlx5_caps *caps); +int mlx5_query_hca_caps(struct mlx5_core_dev *dev); int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev); int mlx5_cmd_init_hca(struct mlx5_core_dev *dev); int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/uar.c b/drivers/net/ethernet/mellanox/mlx5/core/uar.c index ba58f6d7c761..9ef85873ceea 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/uar.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/uar.c @@ -175,12 +175,13 @@ int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari) for (i = 0; i < tot_uuars; i++) { bf = &uuari->bfs[i]; - bf->buf_size = dev->caps.gen.bf_reg_size / 2; + bf->buf_size = (1 << MLX5_CAP_GEN(dev, log_bf_reg_size)) / 2; bf->uar = &uuari->uars[i / MLX5_BF_REGS_PER_PAGE]; bf->regreg = uuari->uars[i / MLX5_BF_REGS_PER_PAGE].map; bf->reg = NULL; /* Add WC support */ - bf->offset = (i % MLX5_BF_REGS_PER_PAGE) * dev->caps.gen.bf_reg_size + - MLX5_BF_OFFSET; + bf->offset = (i % MLX5_BF_REGS_PER_PAGE) * + (1 << MLX5_CAP_GEN(dev, log_bf_reg_size)) + + MLX5_BF_OFFSET; bf->need_lock = need_uuar_lock(i); spin_lock_init(&bf->lock); spin_lock_init(&bf->lock32); diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index feebed7b392b..4ee52bf1f959 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -59,6 +59,8 @@ #define MLX5_FLD_SZ_BYTES(typ, fld) (__mlx5_bit_sz(typ, fld) / 8) #define MLX5_ST_SZ_BYTES(typ) (sizeof(struct mlx5_ifc_##typ##_bits) / 8) #define MLX5_ST_SZ_DW(typ) (sizeof(struct mlx5_ifc_##typ##_bits) / 32) +#define MLX5_UN_SZ_BYTES(typ) (sizeof(union mlx5_ifc_##typ##_bits) / 8) +#define MLX5_UN_SZ_DW(typ) (sizeof(union mlx5_ifc_##typ##_bits) / 32) #define MLX5_BYTE_OFF(typ, fld) (__mlx5_bit_off(typ, fld) / 8) #define MLX5_ADDR_OF(typ, p, fld) ((char *)(p) + MLX5_BYTE_OFF(typ, fld)) @@ -322,13 +324,6 @@ enum { MLX5_CAP_OFF_CMDIF_CSUM = 46, }; -enum { - HCA_CAP_OPMOD_GET_MAX = 0, - HCA_CAP_OPMOD_GET_CUR = 1, - HCA_CAP_OPMOD_GET_ODP_MAX = 4, - HCA_CAP_OPMOD_GET_ODP_CUR = 5 -}; - struct mlx5_inbox_hdr { __be16 opcode; u8 rsvd[4]; @@ -1101,4 +1096,61 @@ enum { MLX5_RQC_RQ_TYPE_MEMORY_RQ_RPM = 0x1, }; +/* MLX5 DEV CAPs */ + +/* TODO: EAT.ME */ +enum mlx5_cap_mode { + HCA_CAP_OPMOD_GET_MAX = 0, + HCA_CAP_OPMOD_GET_CUR = 1, +}; + +enum mlx5_cap_type { + MLX5_CAP_GENERAL = 0, + MLX5_CAP_ETHERNET_OFFLOADS, + MLX5_CAP_ODP, + MLX5_CAP_ATOMIC, + MLX5_CAP_ROCE, + MLX5_CAP_IPOIB_OFFLOADS, + MLX5_CAP_EOIB_OFFLOADS, + MLX5_CAP_FLOW_TABLE, + /* NUM OF CAP Types */ + MLX5_CAP_NUM +}; + +/* GET Dev Caps macros */ +#define MLX5_CAP_GEN(mdev, cap) \ + MLX5_GET(cmd_hca_cap, mdev->hca_caps_cur[MLX5_CAP_GENERAL], cap) + +#define MLX5_CAP_GEN_MAX(mdev, cap) \ + MLX5_GET(cmd_hca_cap, mdev->hca_caps_max[MLX5_CAP_GENERAL], cap) + +#define MLX5_CAP_ETH(mdev, cap) \ + MLX5_GET(per_protocol_networking_offload_caps,\ + mdev->hca_caps_cur[MLX5_CAP_ETHERNET_OFFLOADS], cap) + +#define MLX5_CAP_ETH_MAX(mdev, cap) \ + MLX5_GET(per_protocol_networking_offload_caps,\ + mdev->hca_caps_max[MLX5_CAP_ETHERNET_OFFLOADS], cap) + +#define MLX5_CAP_ROCE(mdev, cap) \ + MLX5_GET(roce_cap, mdev->hca_caps_cur[MLX5_CAP_ROCE], cap) + +#define MLX5_CAP_ROCE_MAX(mdev, cap) \ + MLX5_GET(roce_cap, mdev->hca_caps_max[MLX5_CAP_ROCE], cap) + +#define MLX5_CAP_ATOMIC(mdev, cap) \ + MLX5_GET(atomic_caps, mdev->hca_caps_cur[MLX5_CAP_ATOMIC], cap) + +#define MLX5_CAP_ATOMIC_MAX(mdev, cap) \ + MLX5_GET(atomic_caps, mdev->hca_caps_max[MLX5_CAP_ATOMIC], cap) + +#define MLX5_CAP_FLOWTABLE(mdev, cap) \ + MLX5_GET(flow_table_nic_cap, mdev->hca_caps_cur[MLX5_CAP_FLOW_TABLE], cap) + +#define MLX5_CAP_FLOWTABLE_MAX(mdev, cap) \ + MLX5_GET(flow_table_nic_cap, mdev->hca_caps_max[MLX5_CAP_FLOW_TABLE], cap) + +#define MLX5_CAP_ODP(mdev, cap)\ + MLX5_GET(odp_cap, mdev->hca_caps_cur[MLX5_CAP_ODP], cap) + #endif /* MLX5_DEVICE_H */ diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 3fd4fdc1ba16..6b9199163633 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -268,55 +268,7 @@ struct mlx5_cmd { struct mlx5_port_caps { int gid_table_len; int pkey_table_len; -}; - -struct mlx5_general_caps { - u8 log_max_eq; - u8 log_max_cq; - u8 log_max_qp; - u8 log_max_mkey; - u8 log_max_pd; - u8 log_max_srq; - u8 log_max_mrw_sz; - u8 log_max_bsf_list_size; - u8 log_max_klm_list_size; - u32 max_cqes; - int max_wqes; - u32 max_eqes; - u32 max_indirection; - int max_sq_desc_sz; - int max_rq_desc_sz; - int max_dc_sq_desc_sz; - u64 flags; - u16 stat_rate_support; - int log_max_msg; - int num_ports; - u8 log_max_ra_res_qp; - u8 log_max_ra_req_qp; - int max_srq_wqes; - int bf_reg_size; - int bf_regs_per_page; - struct mlx5_port_caps port[MLX5_MAX_PORTS]; - u8 ext_port_cap[MLX5_MAX_PORTS]; - int max_vf; - u32 reserved_lkey; - u8 local_ca_ack_delay; - u8 log_max_mcg; - u32 max_qp_mcg; - int min_page_sz; - int pd_cap; - u32 max_qp_counters; - u32 pkey_table_size; - u8 log_max_ra_req_dc; - u8 log_max_ra_res_dc; - u32 uar_sz; - u8 min_log_pg_sz; - u8 log_max_xrcd; - u16 log_uar_page_sz; -}; - -struct mlx5_caps { - struct mlx5_general_caps gen; + u8 ext_port_cap; }; struct mlx5_cmd_mailbox { @@ -521,7 +473,9 @@ struct mlx5_core_dev { u8 rev_id; char board_id[MLX5_BOARD_ID_LEN]; struct mlx5_cmd cmd; - struct mlx5_caps caps; + struct mlx5_port_caps port_caps[MLX5_MAX_PORTS]; + u32 hca_caps_cur[MLX5_CAP_NUM][MLX5_UN_SZ_DW(hca_cap_union)]; + u32 hca_caps_max[MLX5_CAP_NUM][MLX5_UN_SZ_DW(hca_cap_union)]; phys_addr_t iseg_base; struct mlx5_init_seg __iomem *iseg; void (*event) (struct mlx5_core_dev *dev, @@ -651,8 +605,8 @@ void mlx5_cmd_use_events(struct mlx5_core_dev *dev); void mlx5_cmd_use_polling(struct mlx5_core_dev *dev); int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr); int mlx5_cmd_status_to_err_v2(void *ptr); -int mlx5_core_get_caps(struct mlx5_core_dev *dev, struct mlx5_caps *caps, - u16 opmod); +int mlx5_core_get_caps(struct mlx5_core_dev *dev, enum mlx5_cap_type cap_type, + enum mlx5_cap_mode cap_mode); int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out, int out_size); int mlx5_cmd_exec_cb(struct mlx5_core_dev *dev, void *in, int in_size, -- cgit v1.2.3 From adb0c9545bce6f1b1d563e988e6ee5531861d449 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 28 May 2015 22:28:42 +0300 Subject: net/mlx5_core: Implement access functions of ptys register fields Those registers will be used by the ethtool to set/get settings. Signed-off-by: Rana Shahout Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/port.c | 77 ++++++++++++++++++++++++++ include/linux/mlx5/driver.h | 14 +++++ 2 files changed, 91 insertions(+) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 49e90f2612d8..6e2d99cc3b61 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -102,3 +102,80 @@ int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps) return err; } EXPORT_SYMBOL_GPL(mlx5_set_port_caps); + +int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys, + int ptys_size, int proto_mask) +{ + u32 in[MLX5_ST_SZ_DW(ptys_reg)]; + int err; + + memset(in, 0, sizeof(in)); + MLX5_SET(ptys_reg, in, local_port, 1); + MLX5_SET(ptys_reg, in, proto_mask, proto_mask); + + err = mlx5_core_access_reg(dev, in, sizeof(in), ptys, + ptys_size, MLX5_REG_PTYS, 0, 0); + + return err; +} +EXPORT_SYMBOL_GPL(mlx5_query_port_ptys); + +int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev, + u32 *proto_cap, int proto_mask) +{ + u32 out[MLX5_ST_SZ_DW(ptys_reg)]; + int err; + + err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask); + if (err) + return err; + + if (proto_mask == MLX5_PTYS_EN) + *proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability); + else + *proto_cap = MLX5_GET(ptys_reg, out, ib_proto_capability); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx5_query_port_proto_cap); + +int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev, + u32 *proto_admin, int proto_mask) +{ + u32 out[MLX5_ST_SZ_DW(ptys_reg)]; + int err; + + err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask); + if (err) + return err; + + if (proto_mask == MLX5_PTYS_EN) + *proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin); + else + *proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin); + +int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin, + int proto_mask) +{ + u32 in[MLX5_ST_SZ_DW(ptys_reg)]; + u32 out[MLX5_ST_SZ_DW(ptys_reg)]; + int err; + + memset(in, 0, sizeof(in)); + + MLX5_SET(ptys_reg, in, local_port, 1); + MLX5_SET(ptys_reg, in, proto_mask, proto_mask); + if (proto_mask == MLX5_PTYS_EN) + MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin); + else + MLX5_SET(ptys_reg, in, ib_proto_admin, proto_admin); + + err = mlx5_core_access_reg(dev, in, sizeof(in), out, + sizeof(out), MLX5_REG_PTYS, 0, 1); + return err; +} +EXPORT_SYMBOL_GPL(mlx5_set_port_proto); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 6b9199163633..266d5498a270 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -504,6 +504,11 @@ enum { MLX5_COMP_EQ_SIZE = 1024, }; +enum { + MLX5_PTYS_IB = 1 << 0, + MLX5_PTYS_EN = 1 << 2, +}; + struct mlx5_db_pgdir { struct list_head list; DECLARE_BITMAP(bitmap, MLX5_DB_PER_PAGE); @@ -686,7 +691,16 @@ void mlx5_qp_debugfs_cleanup(struct mlx5_core_dev *dev); int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in, int size_in, void *data_out, int size_out, u16 reg_num, int arg, int write); + int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps); +int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys, + int ptys_size, int proto_mask); +int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev, + u32 *proto_cap, int proto_mask); +int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev, + u32 *proto_admin, int proto_mask); +int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin, + int proto_mask); int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq); void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq); -- cgit v1.2.3 From 4c916a798058c1acf5a980438416020932c24aca Mon Sep 17 00:00:00 2001 From: Rana Shahout Date: Thu, 28 May 2015 22:28:43 +0300 Subject: net/mlx5_core: Implement get/set port status Implemet get/set port status low level functions to be exposed by the netdev. Signed-off-by: Rana Shahout Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/port.c | 32 ++++++++++++++++++++++++++ include/linux/mlx5/driver.h | 8 +++++++ 2 files changed, 40 insertions(+) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 6e2d99cc3b61..742a6fb8debe 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -179,3 +179,35 @@ int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin, return err; } EXPORT_SYMBOL_GPL(mlx5_set_port_proto); + +int mlx5_set_port_status(struct mlx5_core_dev *dev, + enum mlx5_port_status status) +{ + u32 in[MLX5_ST_SZ_DW(paos_reg)]; + u32 out[MLX5_ST_SZ_DW(paos_reg)]; + + memset(in, 0, sizeof(in)); + + MLX5_SET(paos_reg, in, admin_status, status); + MLX5_SET(paos_reg, in, ase, 1); + + return mlx5_core_access_reg(dev, in, sizeof(in), out, + sizeof(out), MLX5_REG_PAOS, 0, 1); +} + +int mlx5_query_port_status(struct mlx5_core_dev *dev, u8 *status) +{ + u32 in[MLX5_ST_SZ_DW(paos_reg)]; + u32 out[MLX5_ST_SZ_DW(paos_reg)]; + int err; + + memset(in, 0, sizeof(in)); + + err = mlx5_core_access_reg(dev, in, sizeof(in), out, + sizeof(out), MLX5_REG_PAOS, 0, 0); + if (err) + return err; + + *status = MLX5_GET(paos_reg, out, oper_status); + return err; +} diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 266d5498a270..6438444ab361 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -149,6 +149,11 @@ enum mlx5_dev_event { MLX5_DEV_EVENT_CLIENT_REREG, }; +enum mlx5_port_status { + MLX5_PORT_UP = 1 << 1, + MLX5_PORT_DOWN = 1 << 2, +}; + struct mlx5_uuar_info { struct mlx5_uar *uars; int num_uars; @@ -701,6 +706,9 @@ int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev, u32 *proto_admin, int proto_mask); int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin, int proto_mask); +int mlx5_set_port_status(struct mlx5_core_dev *dev, + enum mlx5_port_status status); +int mlx5_query_port_status(struct mlx5_core_dev *dev, u8 *status); int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq); void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq); -- cgit v1.2.3 From 90b3e38d048f09b22fb50bcd460cea65fd00b2d7 Mon Sep 17 00:00:00 2001 From: Rana Shahout Date: Thu, 28 May 2015 22:28:44 +0300 Subject: net/mlx5_core: Modify CQ moderation parameters Introduce mlx5_core_modify_cq_moderation() to be used by the netdev, to set hardware coalescing. Signed-off-by: Rana Shahout Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/cq.c | 18 ++++++++++++++++++ include/linux/mlx5/cq.h | 3 +++ 2 files changed, 21 insertions(+) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c index eb0cf81f5f45..04ab7e445eae 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c @@ -219,6 +219,24 @@ int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, } EXPORT_SYMBOL(mlx5_core_modify_cq); +int mlx5_core_modify_cq_moderation(struct mlx5_core_dev *dev, + struct mlx5_core_cq *cq, + u16 cq_period, + u16 cq_max_count) +{ + struct mlx5_modify_cq_mbox_in in; + + memset(&in, 0, sizeof(in)); + + in.cqn = cpu_to_be32(cq->cqn); + in.ctx.cq_period = cpu_to_be16(cq_period); + in.ctx.cq_max_count = cpu_to_be16(cq_max_count); + in.field_select = cpu_to_be32(MLX5_CQ_MODIFY_PERIOD | + MLX5_CQ_MODIFY_COUNT); + + return mlx5_core_modify_cq(dev, cq, &in, sizeof(in)); +} + int mlx5_init_cq_table(struct mlx5_core_dev *dev) { struct mlx5_cq_table *table = &dev->priv.cq_table; diff --git a/include/linux/mlx5/cq.h b/include/linux/mlx5/cq.h index 2695ced222df..abc4767695e4 100644 --- a/include/linux/mlx5/cq.h +++ b/include/linux/mlx5/cq.h @@ -169,6 +169,9 @@ int mlx5_core_query_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, struct mlx5_query_cq_mbox_out *out); int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, struct mlx5_modify_cq_mbox_in *in, int in_sz); +int mlx5_core_modify_cq_moderation(struct mlx5_core_dev *dev, + struct mlx5_core_cq *cq, u16 cq_period, + u16 cq_max_count); int mlx5_debug_cq_add(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq); void mlx5_debug_cq_remove(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq); -- cgit v1.2.3 From e725440e75da8c4d617a31c4e38216acc55c24e3 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 28 May 2015 22:28:45 +0300 Subject: net/mlx5_core: Set/Query port MTU commands Introduce set/Query low level functions to access MTU in hardware. To be used by the netdev. Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/port.c | 53 ++++++++++++++++++++++++++ include/linux/mlx5/driver.h | 4 ++ 2 files changed, 57 insertions(+) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 742a6fb8debe..7d3d0f9f328d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -211,3 +211,56 @@ int mlx5_query_port_status(struct mlx5_core_dev *dev, u8 *status) *status = MLX5_GET(paos_reg, out, oper_status); return err; } + +static int mlx5_query_port_mtu(struct mlx5_core_dev *dev, + int *admin_mtu, int *max_mtu, int *oper_mtu) +{ + u32 in[MLX5_ST_SZ_DW(pmtu_reg)]; + u32 out[MLX5_ST_SZ_DW(pmtu_reg)]; + int err; + + memset(in, 0, sizeof(in)); + + MLX5_SET(pmtu_reg, in, local_port, 1); + + err = mlx5_core_access_reg(dev, in, sizeof(in), out, + sizeof(out), MLX5_REG_PMTU, 0, 0); + if (err) + return err; + + if (max_mtu) + *max_mtu = MLX5_GET(pmtu_reg, out, max_mtu); + if (oper_mtu) + *oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu); + if (admin_mtu) + *admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu); + + return 0; +} + +int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu) +{ + u32 in[MLX5_ST_SZ_DW(pmtu_reg)]; + u32 out[MLX5_ST_SZ_DW(pmtu_reg)]; + + memset(in, 0, sizeof(in)); + + MLX5_SET(pmtu_reg, in, admin_mtu, mtu); + MLX5_SET(pmtu_reg, in, local_port, 1); + + return mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), + MLX5_REG_PMTU, 0, 1); +} +EXPORT_SYMBOL_GPL(mlx5_set_port_mtu); + +int mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu) +{ + return mlx5_query_port_mtu(dev, NULL, max_mtu, NULL); +} +EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu); + +int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu) +{ + return mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu); +} +EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 6438444ab361..51738472657e 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -710,6 +710,10 @@ int mlx5_set_port_status(struct mlx5_core_dev *dev, enum mlx5_port_status status); int mlx5_query_port_status(struct mlx5_core_dev *dev, u8 *status); +int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu); +int mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu); +int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu); + int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq); void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq); int mlx5_core_eq_query(struct mlx5_core_dev *dev, struct mlx5_eq *eq, -- cgit v1.2.3 From afb736e9330ad6b2b6935d2f53ded784eb73f12d Mon Sep 17 00:00:00 2001 From: Amir Vadai Date: Thu, 28 May 2015 22:28:47 +0300 Subject: net/mlx5: Ethernet resource handling files This patch contains the resource handling files: - flow_table.c: This file contains the code to handle the low level API to configure hardware flow table. It is separated from the flow_table_en.c, because it will be used in the future by Raw Ethernet QP in mlx5_ib too. - en_flow_table.[ch]: Ethernet flow steering handling. The flow table object contain a mapping between flow specs and TIRs. This mechanism will be used also to configure e-switch in the future, when SR-IOV support will be added. - transobj.[ch] - Low level functions to create/modify/destroy the transport objects: RQ/SQ/TIR/TIS - vport.[ch] - Handle attributes of a virtual port (vPort) in the embedded switch. Currently this switch is a passthrough, until SR-IOV support will be added. Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- .../ethernet/mellanox/mlx5/core/en_flow_table.c | 858 +++++++++++++++++++++ .../net/ethernet/mellanox/mlx5/core/flow_table.c | 422 ++++++++++ drivers/net/ethernet/mellanox/mlx5/core/transobj.c | 169 ++++ drivers/net/ethernet/mellanox/mlx5/core/transobj.h | 47 ++ drivers/net/ethernet/mellanox/mlx5/core/vport.c | 84 ++ drivers/net/ethernet/mellanox/mlx5/core/vport.h | 41 + include/linux/mlx5/flow_table.h | 54 ++ 7 files changed, 1675 insertions(+) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/flow_table.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/transobj.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/transobj.h create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/vport.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/vport.h create mode 100644 include/linux/mlx5/flow_table.h (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c new file mode 100644 index 000000000000..6feebda4b3e4 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c @@ -0,0 +1,858 @@ +/* + * Copyright (c) 2015, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include "en.h" + +enum { + MLX5E_FULLMATCH = 0, + MLX5E_ALLMULTI = 1, + MLX5E_PROMISC = 2, +}; + +enum { + MLX5E_UC = 0, + MLX5E_MC_IPV4 = 1, + MLX5E_MC_IPV6 = 2, + MLX5E_MC_OTHER = 3, +}; + +enum { + MLX5E_ACTION_NONE = 0, + MLX5E_ACTION_ADD = 1, + MLX5E_ACTION_DEL = 2, +}; + +struct mlx5e_eth_addr_hash_node { + struct hlist_node hlist; + u8 action; + struct mlx5e_eth_addr_info ai; +}; + +static inline int mlx5e_hash_eth_addr(u8 *addr) +{ + return addr[5]; +} + +static void mlx5e_add_eth_addr_to_hash(struct hlist_head *hash, u8 *addr) +{ + struct mlx5e_eth_addr_hash_node *hn; + int ix = mlx5e_hash_eth_addr(addr); + int found = 0; + + hlist_for_each_entry(hn, &hash[ix], hlist) + if (ether_addr_equal_64bits(hn->ai.addr, addr)) { + found = 1; + break; + } + + if (found) { + hn->action = MLX5E_ACTION_NONE; + return; + } + + hn = kzalloc(sizeof(*hn), GFP_ATOMIC); + if (!hn) + return; + + ether_addr_copy(hn->ai.addr, addr); + hn->action = MLX5E_ACTION_ADD; + + hlist_add_head(&hn->hlist, &hash[ix]); +} + +static void mlx5e_del_eth_addr_from_hash(struct mlx5e_eth_addr_hash_node *hn) +{ + hlist_del(&hn->hlist); + kfree(hn); +} + +static void mlx5e_del_eth_addr_from_flow_table(struct mlx5e_priv *priv, + struct mlx5e_eth_addr_info *ai) +{ + void *ft = priv->ft.main; + + if (ai->tt_vec & (1 << MLX5E_TT_IPV6_TCP)) + mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_TCP]); + + if (ai->tt_vec & (1 << MLX5E_TT_IPV4_TCP)) + mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_TCP]); + + if (ai->tt_vec & (1 << MLX5E_TT_IPV6_UDP)) + mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_UDP]); + + if (ai->tt_vec & (1 << MLX5E_TT_IPV4_UDP)) + mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_UDP]); + + if (ai->tt_vec & (1 << MLX5E_TT_IPV6)) + mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6]); + + if (ai->tt_vec & (1 << MLX5E_TT_IPV4)) + mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4]); + + if (ai->tt_vec & (1 << MLX5E_TT_ANY)) + mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_ANY]); +} + +static int mlx5e_get_eth_addr_type(u8 *addr) +{ + if (is_unicast_ether_addr(addr)) + return MLX5E_UC; + + if ((addr[0] == 0x01) && + (addr[1] == 0x00) && + (addr[2] == 0x5e) && + !(addr[3] & 0x80)) + return MLX5E_MC_IPV4; + + if ((addr[0] == 0x33) && + (addr[1] == 0x33)) + return MLX5E_MC_IPV6; + + return MLX5E_MC_OTHER; +} + +static u32 mlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type) +{ + int eth_addr_type; + u32 ret; + + switch (type) { + case MLX5E_FULLMATCH: + eth_addr_type = mlx5e_get_eth_addr_type(ai->addr); + switch (eth_addr_type) { + case MLX5E_UC: + ret = + (1 << MLX5E_TT_IPV4_TCP) | + (1 << MLX5E_TT_IPV6_TCP) | + (1 << MLX5E_TT_IPV4_UDP) | + (1 << MLX5E_TT_IPV6_UDP) | + (1 << MLX5E_TT_IPV4) | + (1 << MLX5E_TT_IPV6) | + (1 << MLX5E_TT_ANY) | + 0; + break; + + case MLX5E_MC_IPV4: + ret = + (1 << MLX5E_TT_IPV4_UDP) | + (1 << MLX5E_TT_IPV4) | + 0; + break; + + case MLX5E_MC_IPV6: + ret = + (1 << MLX5E_TT_IPV6_UDP) | + (1 << MLX5E_TT_IPV6) | + 0; + break; + + case MLX5E_MC_OTHER: + ret = + (1 << MLX5E_TT_ANY) | + 0; + break; + } + + break; + + case MLX5E_ALLMULTI: + ret = + (1 << MLX5E_TT_IPV4_UDP) | + (1 << MLX5E_TT_IPV6_UDP) | + (1 << MLX5E_TT_IPV4) | + (1 << MLX5E_TT_IPV6) | + (1 << MLX5E_TT_ANY) | + 0; + break; + + default: /* MLX5E_PROMISC */ + ret = + (1 << MLX5E_TT_IPV4_TCP) | + (1 << MLX5E_TT_IPV6_TCP) | + (1 << MLX5E_TT_IPV4_UDP) | + (1 << MLX5E_TT_IPV6_UDP) | + (1 << MLX5E_TT_IPV4) | + (1 << MLX5E_TT_IPV6) | + (1 << MLX5E_TT_ANY) | + 0; + break; + } + + return ret; +} + +static int __mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, + struct mlx5e_eth_addr_info *ai, int type, + void *flow_context, void *match_criteria) +{ + u8 match_criteria_enable = 0; + void *match_value; + void *dest; + u8 *dmac; + u8 *match_criteria_dmac; + void *ft = priv->ft.main; + u32 *tirn = priv->tirn; + u32 tt_vec; + int err; + + match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value); + dmac = MLX5_ADDR_OF(fte_match_param, match_value, + outer_headers.dmac_47_16); + match_criteria_dmac = MLX5_ADDR_OF(fte_match_param, match_criteria, + outer_headers.dmac_47_16); + dest = MLX5_ADDR_OF(flow_context, flow_context, destination); + + MLX5_SET(flow_context, flow_context, action, + MLX5_FLOW_CONTEXT_ACTION_FWD_DEST); + MLX5_SET(flow_context, flow_context, destination_list_size, 1); + MLX5_SET(dest_format_struct, dest, destination_type, + MLX5_FLOW_CONTEXT_DEST_TYPE_TIR); + + switch (type) { + case MLX5E_FULLMATCH: + match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + memset(match_criteria_dmac, 0xff, ETH_ALEN); + ether_addr_copy(dmac, ai->addr); + break; + + case MLX5E_ALLMULTI: + match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + match_criteria_dmac[0] = 0x01; + dmac[0] = 0x01; + break; + + case MLX5E_PROMISC: + break; + } + + tt_vec = mlx5e_get_tt_vec(ai, type); + + if (tt_vec & (1 << MLX5E_TT_ANY)) { + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_ANY]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + &ai->ft_ix[MLX5E_TT_ANY]); + if (err) { + mlx5e_del_eth_addr_from_flow_table(priv, ai); + return err; + } + ai->tt_vec |= (1 << MLX5E_TT_ANY); + } + + match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + MLX5_SET_TO_ONES(fte_match_param, match_criteria, + outer_headers.ethertype); + + if (tt_vec & (1 << MLX5E_TT_IPV4)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IP); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV4]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + &ai->ft_ix[MLX5E_TT_IPV4]); + if (err) { + mlx5e_del_eth_addr_from_flow_table(priv, ai); + return err; + } + ai->tt_vec |= (1 << MLX5E_TT_IPV4); + } + + if (tt_vec & (1 << MLX5E_TT_IPV6)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IPV6); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV6]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + &ai->ft_ix[MLX5E_TT_IPV6]); + if (err) { + mlx5e_del_eth_addr_from_flow_table(priv, ai); + return err; + } + ai->tt_vec |= (1 << MLX5E_TT_IPV6); + } + + MLX5_SET_TO_ONES(fte_match_param, match_criteria, + outer_headers.ip_protocol); + MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, + IPPROTO_UDP); + + if (tt_vec & (1 << MLX5E_TT_IPV4_UDP)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IP); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV4_UDP]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + &ai->ft_ix[MLX5E_TT_IPV4_UDP]); + if (err) { + mlx5e_del_eth_addr_from_flow_table(priv, ai); + return err; + } + ai->tt_vec |= (1 << MLX5E_TT_IPV4_UDP); + } + + if (tt_vec & (1 << MLX5E_TT_IPV6_UDP)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IPV6); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV6_UDP]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + &ai->ft_ix[MLX5E_TT_IPV6_UDP]); + if (err) { + mlx5e_del_eth_addr_from_flow_table(priv, ai); + return err; + } + ai->tt_vec |= (1 << MLX5E_TT_IPV6_UDP); + } + + MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, + IPPROTO_TCP); + + if (tt_vec & (1 << MLX5E_TT_IPV4_TCP)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IP); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV4_TCP]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + &ai->ft_ix[MLX5E_TT_IPV4_TCP]); + if (err) { + mlx5e_del_eth_addr_from_flow_table(priv, ai); + return err; + } + ai->tt_vec |= (1 << MLX5E_TT_IPV4_TCP); + } + + if (tt_vec & (1 << MLX5E_TT_IPV6_TCP)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IPV6); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV6_TCP]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + &ai->ft_ix[MLX5E_TT_IPV6_TCP]); + if (err) { + mlx5e_del_eth_addr_from_flow_table(priv, ai); + return err; + } + ai->tt_vec |= (1 << MLX5E_TT_IPV6_TCP); + } + + return 0; +} + +static int mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, + struct mlx5e_eth_addr_info *ai, int type) +{ + u32 *flow_context; + u32 *match_criteria; + int err; + + flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context) + + MLX5_ST_SZ_BYTES(dest_format_struct)); + match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); + if (!flow_context || !match_criteria) { + netdev_err(priv->netdev, "%s: alloc failed\n", __func__); + err = -ENOMEM; + goto add_eth_addr_rule_out; + } + + err = __mlx5e_add_eth_addr_rule(priv, ai, type, flow_context, + match_criteria); + if (err) + netdev_err(priv->netdev, "%s: failed\n", __func__); + +add_eth_addr_rule_out: + kvfree(match_criteria); + kvfree(flow_context); + return err; +} + +enum mlx5e_vlan_rule_type { + MLX5E_VLAN_RULE_TYPE_UNTAGGED, + MLX5E_VLAN_RULE_TYPE_ANY_VID, + MLX5E_VLAN_RULE_TYPE_MATCH_VID, +}; + +static int mlx5e_add_vlan_rule(struct mlx5e_priv *priv, + enum mlx5e_vlan_rule_type rule_type, u16 vid) +{ + u8 match_criteria_enable = 0; + u32 *flow_context; + void *match_value; + void *dest; + u32 *match_criteria; + u32 *ft_ix; + int err; + + flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context) + + MLX5_ST_SZ_BYTES(dest_format_struct)); + match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); + if (!flow_context || !match_criteria) { + netdev_err(priv->netdev, "%s: alloc failed\n", __func__); + err = -ENOMEM; + goto add_vlan_rule_out; + } + match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value); + dest = MLX5_ADDR_OF(flow_context, flow_context, destination); + + MLX5_SET(flow_context, flow_context, action, + MLX5_FLOW_CONTEXT_ACTION_FWD_DEST); + MLX5_SET(flow_context, flow_context, destination_list_size, 1); + MLX5_SET(dest_format_struct, dest, destination_type, + MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE); + MLX5_SET(dest_format_struct, dest, destination_id, + mlx5_get_flow_table_id(priv->ft.main)); + + match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + MLX5_SET_TO_ONES(fte_match_param, match_criteria, + outer_headers.vlan_tag); + + switch (rule_type) { + case MLX5E_VLAN_RULE_TYPE_UNTAGGED: + ft_ix = &priv->vlan.untagged_rule_ft_ix; + break; + case MLX5E_VLAN_RULE_TYPE_ANY_VID: + ft_ix = &priv->vlan.any_vlan_rule_ft_ix; + MLX5_SET(fte_match_param, match_value, outer_headers.vlan_tag, + 1); + break; + default: /* MLX5E_VLAN_RULE_TYPE_MATCH_VID */ + ft_ix = &priv->vlan.active_vlans_ft_ix[vid]; + MLX5_SET(fte_match_param, match_value, outer_headers.vlan_tag, + 1); + MLX5_SET_TO_ONES(fte_match_param, match_criteria, + outer_headers.first_vid); + MLX5_SET(fte_match_param, match_value, outer_headers.first_vid, + vid); + break; + } + + err = mlx5_add_flow_table_entry(priv->ft.vlan, match_criteria_enable, + match_criteria, flow_context, ft_ix); + if (err) + netdev_err(priv->netdev, "%s: failed\n", __func__); + +add_vlan_rule_out: + kvfree(match_criteria); + kvfree(flow_context); + return err; +} + +static void mlx5e_del_vlan_rule(struct mlx5e_priv *priv, + enum mlx5e_vlan_rule_type rule_type, u16 vid) +{ + switch (rule_type) { + case MLX5E_VLAN_RULE_TYPE_UNTAGGED: + mlx5_del_flow_table_entry(priv->ft.vlan, + priv->vlan.untagged_rule_ft_ix); + break; + case MLX5E_VLAN_RULE_TYPE_ANY_VID: + mlx5_del_flow_table_entry(priv->ft.vlan, + priv->vlan.any_vlan_rule_ft_ix); + break; + case MLX5E_VLAN_RULE_TYPE_MATCH_VID: + mlx5_del_flow_table_entry(priv->ft.vlan, + priv->vlan.active_vlans_ft_ix[vid]); + break; + } +} + +void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv) +{ + WARN_ON(!mutex_is_locked(&priv->state_lock)); + + if (priv->vlan.filter_disabled) { + priv->vlan.filter_disabled = false; + if (test_bit(MLX5E_STATE_OPENED, &priv->state)) + mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, + 0); + } +} + +void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv) +{ + WARN_ON(!mutex_is_locked(&priv->state_lock)); + + if (!priv->vlan.filter_disabled) { + priv->vlan.filter_disabled = true; + if (test_bit(MLX5E_STATE_OPENED, &priv->state)) + mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, + 0); + } +} + +int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto, + u16 vid) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + int err = 0; + + mutex_lock(&priv->state_lock); + + set_bit(vid, priv->vlan.active_vlans); + if (test_bit(MLX5E_STATE_OPENED, &priv->state)) + err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, + vid); + + mutex_unlock(&priv->state_lock); + + return err; +} + +int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto, + u16 vid) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + + mutex_lock(&priv->state_lock); + + clear_bit(vid, priv->vlan.active_vlans); + if (test_bit(MLX5E_STATE_OPENED, &priv->state)) + mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); + + mutex_unlock(&priv->state_lock); + + return 0; +} + +int mlx5e_add_all_vlan_rules(struct mlx5e_priv *priv) +{ + u16 vid; + int err; + + for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID) { + err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, + vid); + if (err) + return err; + } + + err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); + if (err) + return err; + + if (priv->vlan.filter_disabled) { + err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, + 0); + if (err) + return err; + } + + return 0; +} + +void mlx5e_del_all_vlan_rules(struct mlx5e_priv *priv) +{ + u16 vid; + + if (priv->vlan.filter_disabled) + mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0); + + mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); + + for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID) + mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); +} + +#define mlx5e_for_each_hash_node(hn, tmp, hash, i) \ + for (i = 0; i < MLX5E_ETH_ADDR_HASH_SIZE; i++) \ + hlist_for_each_entry_safe(hn, tmp, &hash[i], hlist) + +static void mlx5e_execute_action(struct mlx5e_priv *priv, + struct mlx5e_eth_addr_hash_node *hn) +{ + switch (hn->action) { + case MLX5E_ACTION_ADD: + mlx5e_add_eth_addr_rule(priv, &hn->ai, MLX5E_FULLMATCH); + hn->action = MLX5E_ACTION_NONE; + break; + + case MLX5E_ACTION_DEL: + mlx5e_del_eth_addr_from_flow_table(priv, &hn->ai); + mlx5e_del_eth_addr_from_hash(hn); + break; + } +} + +static void mlx5e_sync_netdev_addr(struct mlx5e_priv *priv) +{ + struct net_device *netdev = priv->netdev; + struct netdev_hw_addr *ha; + + netif_addr_lock_bh(netdev); + + mlx5e_add_eth_addr_to_hash(priv->eth_addr.netdev_uc, + priv->netdev->dev_addr); + + netdev_for_each_uc_addr(ha, netdev) + mlx5e_add_eth_addr_to_hash(priv->eth_addr.netdev_uc, ha->addr); + + netdev_for_each_mc_addr(ha, netdev) + mlx5e_add_eth_addr_to_hash(priv->eth_addr.netdev_mc, ha->addr); + + netif_addr_unlock_bh(netdev); +} + +static void mlx5e_apply_netdev_addr(struct mlx5e_priv *priv) +{ + struct mlx5e_eth_addr_hash_node *hn; + struct hlist_node *tmp; + int i; + + mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_uc, i) + mlx5e_execute_action(priv, hn); + + mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_mc, i) + mlx5e_execute_action(priv, hn); +} + +static void mlx5e_handle_netdev_addr(struct mlx5e_priv *priv) +{ + struct mlx5e_eth_addr_hash_node *hn; + struct hlist_node *tmp; + int i; + + mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_uc, i) + hn->action = MLX5E_ACTION_DEL; + mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_mc, i) + hn->action = MLX5E_ACTION_DEL; + + if (test_bit(MLX5E_STATE_OPENED, &priv->state)) + mlx5e_sync_netdev_addr(priv); + + mlx5e_apply_netdev_addr(priv); +} + +void mlx5e_set_rx_mode_core(struct mlx5e_priv *priv) +{ + struct mlx5e_eth_addr_db *ea = &priv->eth_addr; + struct net_device *ndev = priv->netdev; + + bool rx_mode_enable = test_bit(MLX5E_STATE_OPENED, &priv->state); + bool promisc_enabled = rx_mode_enable && (ndev->flags & IFF_PROMISC); + bool allmulti_enabled = rx_mode_enable && (ndev->flags & IFF_ALLMULTI); + bool broadcast_enabled = rx_mode_enable; + + bool enable_promisc = !ea->promisc_enabled && promisc_enabled; + bool disable_promisc = ea->promisc_enabled && !promisc_enabled; + bool enable_allmulti = !ea->allmulti_enabled && allmulti_enabled; + bool disable_allmulti = ea->allmulti_enabled && !allmulti_enabled; + bool enable_broadcast = !ea->broadcast_enabled && broadcast_enabled; + bool disable_broadcast = ea->broadcast_enabled && !broadcast_enabled; + + if (enable_promisc) + mlx5e_add_eth_addr_rule(priv, &ea->promisc, MLX5E_PROMISC); + if (enable_allmulti) + mlx5e_add_eth_addr_rule(priv, &ea->allmulti, MLX5E_ALLMULTI); + if (enable_broadcast) + mlx5e_add_eth_addr_rule(priv, &ea->broadcast, MLX5E_FULLMATCH); + + mlx5e_handle_netdev_addr(priv); + + if (disable_broadcast) + mlx5e_del_eth_addr_from_flow_table(priv, &ea->broadcast); + if (disable_allmulti) + mlx5e_del_eth_addr_from_flow_table(priv, &ea->allmulti); + if (disable_promisc) + mlx5e_del_eth_addr_from_flow_table(priv, &ea->promisc); + + ea->promisc_enabled = promisc_enabled; + ea->allmulti_enabled = allmulti_enabled; + ea->broadcast_enabled = broadcast_enabled; +} + +void mlx5e_set_rx_mode_work(struct work_struct *work) +{ + struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv, + set_rx_mode_work); + + mutex_lock(&priv->state_lock); + if (test_bit(MLX5E_STATE_OPENED, &priv->state)) + mlx5e_set_rx_mode_core(priv); + mutex_unlock(&priv->state_lock); +} + +void mlx5e_init_eth_addr(struct mlx5e_priv *priv) +{ + ether_addr_copy(priv->eth_addr.broadcast.addr, priv->netdev->broadcast); +} + +static int mlx5e_create_main_flow_table(struct mlx5e_priv *priv) +{ + struct mlx5_flow_table_group *g; + u8 *dmac; + + g = kcalloc(9, sizeof(*g), GFP_KERNEL); + + g[0].log_sz = 2; + g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, + outer_headers.ethertype); + MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, + outer_headers.ip_protocol); + + g[1].log_sz = 1; + g[1].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + MLX5_SET_TO_ONES(fte_match_param, g[1].match_criteria, + outer_headers.ethertype); + + g[2].log_sz = 0; + + g[3].log_sz = 14; + g[3].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + dmac = MLX5_ADDR_OF(fte_match_param, g[3].match_criteria, + outer_headers.dmac_47_16); + memset(dmac, 0xff, ETH_ALEN); + MLX5_SET_TO_ONES(fte_match_param, g[3].match_criteria, + outer_headers.ethertype); + MLX5_SET_TO_ONES(fte_match_param, g[3].match_criteria, + outer_headers.ip_protocol); + + g[4].log_sz = 13; + g[4].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + dmac = MLX5_ADDR_OF(fte_match_param, g[4].match_criteria, + outer_headers.dmac_47_16); + memset(dmac, 0xff, ETH_ALEN); + MLX5_SET_TO_ONES(fte_match_param, g[4].match_criteria, + outer_headers.ethertype); + + g[5].log_sz = 11; + g[5].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + dmac = MLX5_ADDR_OF(fte_match_param, g[5].match_criteria, + outer_headers.dmac_47_16); + memset(dmac, 0xff, ETH_ALEN); + + g[6].log_sz = 2; + g[6].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + dmac = MLX5_ADDR_OF(fte_match_param, g[6].match_criteria, + outer_headers.dmac_47_16); + dmac[0] = 0x01; + MLX5_SET_TO_ONES(fte_match_param, g[6].match_criteria, + outer_headers.ethertype); + MLX5_SET_TO_ONES(fte_match_param, g[6].match_criteria, + outer_headers.ip_protocol); + + g[7].log_sz = 1; + g[7].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + dmac = MLX5_ADDR_OF(fte_match_param, g[7].match_criteria, + outer_headers.dmac_47_16); + dmac[0] = 0x01; + MLX5_SET_TO_ONES(fte_match_param, g[7].match_criteria, + outer_headers.ethertype); + + g[8].log_sz = 0; + g[8].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + dmac = MLX5_ADDR_OF(fte_match_param, g[8].match_criteria, + outer_headers.dmac_47_16); + dmac[0] = 0x01; + priv->ft.main = mlx5_create_flow_table(priv->mdev, 1, + MLX5_FLOW_TABLE_TYPE_NIC_RCV, + 9, g); + kfree(g); + + return priv->ft.main ? 0 : -ENOMEM; +} + +static void mlx5e_destroy_main_flow_table(struct mlx5e_priv *priv) +{ + mlx5_destroy_flow_table(priv->ft.main); +} + +static int mlx5e_create_vlan_flow_table(struct mlx5e_priv *priv) +{ + struct mlx5_flow_table_group *g; + + g = kcalloc(2, sizeof(*g), GFP_KERNEL); + if (!g) + return -ENOMEM; + + g[0].log_sz = 12; + g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, + outer_headers.vlan_tag); + MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, + outer_headers.first_vid); + + /* untagged + any vlan id */ + g[1].log_sz = 1; + g[1].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + MLX5_SET_TO_ONES(fte_match_param, g[1].match_criteria, + outer_headers.vlan_tag); + + priv->ft.vlan = mlx5_create_flow_table(priv->mdev, 0, + MLX5_FLOW_TABLE_TYPE_NIC_RCV, + 2, g); + + kfree(g); + return priv->ft.vlan ? 0 : -ENOMEM; +} + +static void mlx5e_destroy_vlan_flow_table(struct mlx5e_priv *priv) +{ + mlx5_destroy_flow_table(priv->ft.vlan); +} + +int mlx5e_open_flow_table(struct mlx5e_priv *priv) +{ + int err; + + err = mlx5e_create_main_flow_table(priv); + if (err) + return err; + + err = mlx5e_create_vlan_flow_table(priv); + if (err) + goto err_destroy_main_flow_table; + + return 0; + +err_destroy_main_flow_table: + mlx5e_destroy_main_flow_table(priv); + + return err; +} + +void mlx5e_close_flow_table(struct mlx5e_priv *priv) +{ + mlx5e_destroy_vlan_flow_table(priv); + mlx5e_destroy_main_flow_table(priv); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/flow_table.c b/drivers/net/ethernet/mellanox/mlx5/core/flow_table.c new file mode 100644 index 000000000000..ca90b9bc3b95 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/flow_table.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include "mlx5_core.h" + +struct mlx5_ftg { + struct mlx5_flow_table_group g; + u32 id; + u32 start_ix; +}; + +struct mlx5_flow_table { + struct mlx5_core_dev *dev; + u8 level; + u8 type; + u32 id; + struct mutex mutex; /* sync bitmap alloc */ + u16 num_groups; + struct mlx5_ftg *group; + unsigned long *bitmap; + u32 size; +}; + +static int mlx5_set_flow_entry_cmd(struct mlx5_flow_table *ft, u32 group_ix, + u32 flow_index, void *flow_context) +{ + u32 out[MLX5_ST_SZ_DW(set_fte_out)]; + u32 *in; + void *in_flow_context; + int fcdls = + MLX5_GET(flow_context, flow_context, destination_list_size) * + MLX5_ST_SZ_BYTES(dest_format_struct); + int inlen = MLX5_ST_SZ_BYTES(set_fte_in) + fcdls; + int err; + + in = mlx5_vzalloc(inlen); + if (!in) { + mlx5_core_warn(ft->dev, "failed to allocate inbox\n"); + return -ENOMEM; + } + + MLX5_SET(set_fte_in, in, table_type, ft->type); + MLX5_SET(set_fte_in, in, table_id, ft->id); + MLX5_SET(set_fte_in, in, flow_index, flow_index); + MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); + + in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context); + memcpy(in_flow_context, flow_context, + MLX5_ST_SZ_BYTES(flow_context) + fcdls); + + MLX5_SET(flow_context, in_flow_context, group_id, + ft->group[group_ix].id); + + memset(out, 0, sizeof(out)); + err = mlx5_cmd_exec_check_status(ft->dev, in, inlen, out, + sizeof(out)); + kvfree(in); + + return err; +} + +static void mlx5_del_flow_entry_cmd(struct mlx5_flow_table *ft, u32 flow_index) +{ + u32 in[MLX5_ST_SZ_DW(delete_fte_in)]; + u32 out[MLX5_ST_SZ_DW(delete_fte_out)]; + + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + +#define MLX5_SET_DFTEI(p, x, v) MLX5_SET(delete_fte_in, p, x, v) + MLX5_SET_DFTEI(in, table_type, ft->type); + MLX5_SET_DFTEI(in, table_id, ft->id); + MLX5_SET_DFTEI(in, flow_index, flow_index); + MLX5_SET_DFTEI(in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY); + + mlx5_cmd_exec_check_status(ft->dev, in, sizeof(in), out, sizeof(out)); +} + +static void mlx5_destroy_flow_group_cmd(struct mlx5_flow_table *ft, int i) +{ + u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)]; + u32 out[MLX5_ST_SZ_DW(destroy_flow_group_out)]; + + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + +#define MLX5_SET_DFGI(p, x, v) MLX5_SET(destroy_flow_group_in, p, x, v) + MLX5_SET_DFGI(in, table_type, ft->type); + MLX5_SET_DFGI(in, table_id, ft->id); + MLX5_SET_DFGI(in, opcode, MLX5_CMD_OP_DESTROY_FLOW_GROUP); + MLX5_SET_DFGI(in, group_id, ft->group[i].id); + mlx5_cmd_exec_check_status(ft->dev, in, sizeof(in), out, sizeof(out)); +} + +static int mlx5_create_flow_group_cmd(struct mlx5_flow_table *ft, int i) +{ + u32 out[MLX5_ST_SZ_DW(create_flow_group_out)]; + u32 *in; + void *in_match_criteria; + int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); + struct mlx5_flow_table_group *g = &ft->group[i].g; + u32 start_ix = ft->group[i].start_ix; + u32 end_ix = start_ix + (1 << g->log_sz) - 1; + int err; + + in = mlx5_vzalloc(inlen); + if (!in) { + mlx5_core_warn(ft->dev, "failed to allocate inbox\n"); + return -ENOMEM; + } + in_match_criteria = MLX5_ADDR_OF(create_flow_group_in, in, + match_criteria); + + memset(out, 0, sizeof(out)); + +#define MLX5_SET_CFGI(p, x, v) MLX5_SET(create_flow_group_in, p, x, v) + MLX5_SET_CFGI(in, table_type, ft->type); + MLX5_SET_CFGI(in, table_id, ft->id); + MLX5_SET_CFGI(in, opcode, MLX5_CMD_OP_CREATE_FLOW_GROUP); + MLX5_SET_CFGI(in, start_flow_index, start_ix); + MLX5_SET_CFGI(in, end_flow_index, end_ix); + MLX5_SET_CFGI(in, match_criteria_enable, g->match_criteria_enable); + + memcpy(in_match_criteria, g->match_criteria, + MLX5_ST_SZ_BYTES(fte_match_param)); + + err = mlx5_cmd_exec_check_status(ft->dev, in, inlen, out, + sizeof(out)); + if (!err) + ft->group[i].id = MLX5_GET(create_flow_group_out, out, + group_id); + + kvfree(in); + + return err; +} + +static void mlx5_destroy_flow_table_groups(struct mlx5_flow_table *ft) +{ + int i; + + for (i = 0; i < ft->num_groups; i++) + mlx5_destroy_flow_group_cmd(ft, i); +} + +static int mlx5_create_flow_table_groups(struct mlx5_flow_table *ft) +{ + int err; + int i; + + for (i = 0; i < ft->num_groups; i++) { + err = mlx5_create_flow_group_cmd(ft, i); + if (err) + goto err_destroy_flow_table_groups; + } + + return 0; + +err_destroy_flow_table_groups: + for (i--; i >= 0; i--) + mlx5_destroy_flow_group_cmd(ft, i); + + return err; +} + +static int mlx5_create_flow_table_cmd(struct mlx5_flow_table *ft) +{ + u32 in[MLX5_ST_SZ_DW(create_flow_table_in)]; + u32 out[MLX5_ST_SZ_DW(create_flow_table_out)]; + int err; + + memset(in, 0, sizeof(in)); + + MLX5_SET(create_flow_table_in, in, table_type, ft->type); + MLX5_SET(create_flow_table_in, in, level, ft->level); + MLX5_SET(create_flow_table_in, in, log_size, order_base_2(ft->size)); + + MLX5_SET(create_flow_table_in, in, opcode, + MLX5_CMD_OP_CREATE_FLOW_TABLE); + + memset(out, 0, sizeof(out)); + err = mlx5_cmd_exec_check_status(ft->dev, in, sizeof(in), out, + sizeof(out)); + if (err) + return err; + + ft->id = MLX5_GET(create_flow_table_out, out, table_id); + + return 0; +} + +static void mlx5_destroy_flow_table_cmd(struct mlx5_flow_table *ft) +{ + u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)]; + u32 out[MLX5_ST_SZ_DW(destroy_flow_table_out)]; + + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + +#define MLX5_SET_DFTI(p, x, v) MLX5_SET(destroy_flow_table_in, p, x, v) + MLX5_SET_DFTI(in, table_type, ft->type); + MLX5_SET_DFTI(in, table_id, ft->id); + MLX5_SET_DFTI(in, opcode, MLX5_CMD_OP_DESTROY_FLOW_TABLE); + + mlx5_cmd_exec_check_status(ft->dev, in, sizeof(in), out, sizeof(out)); +} + +static int mlx5_find_group(struct mlx5_flow_table *ft, u8 match_criteria_enable, + u32 *match_criteria, int *group_ix) +{ + void *mc_outer = MLX5_ADDR_OF(fte_match_param, match_criteria, + outer_headers); + void *mc_misc = MLX5_ADDR_OF(fte_match_param, match_criteria, + misc_parameters); + void *mc_inner = MLX5_ADDR_OF(fte_match_param, match_criteria, + inner_headers); + int mc_outer_sz = MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4); + int mc_misc_sz = MLX5_ST_SZ_BYTES(fte_match_set_misc); + int mc_inner_sz = MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4); + int i; + + for (i = 0; i < ft->num_groups; i++) { + struct mlx5_flow_table_group *g = &ft->group[i].g; + void *gmc_outer = MLX5_ADDR_OF(fte_match_param, + g->match_criteria, + outer_headers); + void *gmc_misc = MLX5_ADDR_OF(fte_match_param, + g->match_criteria, + misc_parameters); + void *gmc_inner = MLX5_ADDR_OF(fte_match_param, + g->match_criteria, + inner_headers); + + if (g->match_criteria_enable != match_criteria_enable) + continue; + + if (match_criteria_enable & MLX5_MATCH_OUTER_HEADERS) + if (memcmp(mc_outer, gmc_outer, mc_outer_sz)) + continue; + + if (match_criteria_enable & MLX5_MATCH_MISC_PARAMETERS) + if (memcmp(mc_misc, gmc_misc, mc_misc_sz)) + continue; + + if (match_criteria_enable & MLX5_MATCH_INNER_HEADERS) + if (memcmp(mc_inner, gmc_inner, mc_inner_sz)) + continue; + + *group_ix = i; + return 0; + } + + return -EINVAL; +} + +static int alloc_flow_index(struct mlx5_flow_table *ft, int group_ix, u32 *ix) +{ + struct mlx5_ftg *g = &ft->group[group_ix]; + int err = 0; + + mutex_lock(&ft->mutex); + + *ix = find_next_zero_bit(ft->bitmap, ft->size, g->start_ix); + if (*ix >= (g->start_ix + (1 << g->g.log_sz))) + err = -ENOSPC; + else + __set_bit(*ix, ft->bitmap); + + mutex_unlock(&ft->mutex); + + return err; +} + +static void mlx5_free_flow_index(struct mlx5_flow_table *ft, u32 ix) +{ + __clear_bit(ix, ft->bitmap); +} + +int mlx5_add_flow_table_entry(void *flow_table, u8 match_criteria_enable, + void *match_criteria, void *flow_context, + u32 *flow_index) +{ + struct mlx5_flow_table *ft = flow_table; + int group_ix; + int err; + + err = mlx5_find_group(ft, match_criteria_enable, match_criteria, + &group_ix); + if (err) { + mlx5_core_warn(ft->dev, "mlx5_find_group failed\n"); + return err; + } + + err = alloc_flow_index(ft, group_ix, flow_index); + if (err) { + mlx5_core_warn(ft->dev, "alloc_flow_index failed\n"); + return err; + } + + return mlx5_set_flow_entry_cmd(ft, group_ix, *flow_index, flow_context); +} +EXPORT_SYMBOL(mlx5_add_flow_table_entry); + +void mlx5_del_flow_table_entry(void *flow_table, u32 flow_index) +{ + struct mlx5_flow_table *ft = flow_table; + + mlx5_del_flow_entry_cmd(ft, flow_index); + mlx5_free_flow_index(ft, flow_index); +} +EXPORT_SYMBOL(mlx5_del_flow_table_entry); + +void *mlx5_create_flow_table(struct mlx5_core_dev *dev, u8 level, u8 table_type, + u16 num_groups, + struct mlx5_flow_table_group *group) +{ + struct mlx5_flow_table *ft; + u32 start_ix = 0; + u32 ft_size = 0; + void *gr; + void *bm; + int err; + int i; + + for (i = 0; i < num_groups; i++) + ft_size += (1 << group[i].log_sz); + + ft = kzalloc(sizeof(*ft), GFP_KERNEL); + gr = kcalloc(num_groups, sizeof(struct mlx5_ftg), GFP_KERNEL); + bm = kcalloc(BITS_TO_LONGS(ft_size), sizeof(uintptr_t), GFP_KERNEL); + if (!ft || !gr || !bm) + goto err_free_ft; + + ft->group = gr; + ft->bitmap = bm; + ft->num_groups = num_groups; + ft->level = level; + ft->type = table_type; + ft->size = ft_size; + ft->dev = dev; + mutex_init(&ft->mutex); + + for (i = 0; i < ft->num_groups; i++) { + memcpy(&ft->group[i].g, &group[i], sizeof(*group)); + ft->group[i].start_ix = start_ix; + start_ix += 1 << group[i].log_sz; + } + + err = mlx5_create_flow_table_cmd(ft); + if (err) + goto err_free_ft; + + err = mlx5_create_flow_table_groups(ft); + if (err) + goto err_destroy_flow_table_cmd; + + return ft; + +err_destroy_flow_table_cmd: + mlx5_destroy_flow_table_cmd(ft); + +err_free_ft: + mlx5_core_warn(dev, "failed to alloc flow table\n"); + kfree(bm); + kfree(gr); + kfree(ft); + + return NULL; +} +EXPORT_SYMBOL(mlx5_create_flow_table); + +void mlx5_destroy_flow_table(void *flow_table) +{ + struct mlx5_flow_table *ft = flow_table; + + mlx5_destroy_flow_table_groups(ft); + mlx5_destroy_flow_table_cmd(ft); + kfree(ft->bitmap); + kfree(ft->group); + kfree(ft); +} +EXPORT_SYMBOL(mlx5_destroy_flow_table); + +u32 mlx5_get_flow_table_id(void *flow_table) +{ + struct mlx5_flow_table *ft = flow_table; + + return ft->id; +} +EXPORT_SYMBOL(mlx5_get_flow_table_id); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c new file mode 100644 index 000000000000..3c555d708af1 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "mlx5_core.h" +#include "transobj.h" + +int mlx5_create_rq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *rqn) +{ + u32 out[MLX5_ST_SZ_DW(create_rq_out)]; + int err; + + MLX5_SET(create_rq_in, in, opcode, MLX5_CMD_OP_CREATE_RQ); + + memset(out, 0, sizeof(out)); + err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); + if (!err) + *rqn = MLX5_GET(create_rq_out, out, rqn); + + return err; +} + +int mlx5_modify_rq(struct mlx5_core_dev *dev, u32 rqn, u32 *in, int inlen) +{ + u32 out[MLX5_ST_SZ_DW(modify_rq_out)]; + + MLX5_SET(modify_rq_in, in, rqn, rqn); + MLX5_SET(modify_rq_in, in, opcode, MLX5_CMD_OP_MODIFY_RQ); + + memset(out, 0, sizeof(out)); + return mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); +} + +void mlx5_destroy_rq(struct mlx5_core_dev *dev, u32 rqn) +{ + u32 in[MLX5_ST_SZ_DW(destroy_rq_in)]; + u32 out[MLX5_ST_SZ_DW(destroy_rq_out)]; + + memset(in, 0, sizeof(in)); + + MLX5_SET(destroy_rq_in, in, opcode, MLX5_CMD_OP_DESTROY_RQ); + MLX5_SET(destroy_rq_in, in, rqn, rqn); + + mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out)); +} + +int mlx5_create_sq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *sqn) +{ + u32 out[MLX5_ST_SZ_DW(create_sq_out)]; + int err; + + MLX5_SET(create_sq_in, in, opcode, MLX5_CMD_OP_CREATE_SQ); + + memset(out, 0, sizeof(out)); + err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); + if (!err) + *sqn = MLX5_GET(create_sq_out, out, sqn); + + return err; +} + +int mlx5_modify_sq(struct mlx5_core_dev *dev, u32 sqn, u32 *in, int inlen) +{ + u32 out[MLX5_ST_SZ_DW(modify_sq_out)]; + + MLX5_SET(modify_sq_in, in, sqn, sqn); + MLX5_SET(modify_sq_in, in, opcode, MLX5_CMD_OP_MODIFY_SQ); + + memset(out, 0, sizeof(out)); + return mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); +} + +void mlx5_destroy_sq(struct mlx5_core_dev *dev, u32 sqn) +{ + u32 in[MLX5_ST_SZ_DW(destroy_sq_in)]; + u32 out[MLX5_ST_SZ_DW(destroy_sq_out)]; + + memset(in, 0, sizeof(in)); + + MLX5_SET(destroy_sq_in, in, opcode, MLX5_CMD_OP_DESTROY_SQ); + MLX5_SET(destroy_sq_in, in, sqn, sqn); + + mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out)); +} + +int mlx5_create_tir(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *tirn) +{ + u32 out[MLX5_ST_SZ_DW(create_tir_out)]; + int err; + + MLX5_SET(create_tir_in, in, opcode, MLX5_CMD_OP_CREATE_TIR); + + memset(out, 0, sizeof(out)); + err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); + if (!err) + *tirn = MLX5_GET(create_tir_out, out, tirn); + + return err; +} + +void mlx5_destroy_tir(struct mlx5_core_dev *dev, u32 tirn) +{ + u32 in[MLX5_ST_SZ_DW(destroy_tir_out)]; + u32 out[MLX5_ST_SZ_DW(destroy_tir_out)]; + + memset(in, 0, sizeof(in)); + + MLX5_SET(destroy_tir_in, in, opcode, MLX5_CMD_OP_DESTROY_TIR); + MLX5_SET(destroy_tir_in, in, tirn, tirn); + + mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out)); +} + +int mlx5_create_tis(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *tisn) +{ + u32 out[MLX5_ST_SZ_DW(create_tis_out)]; + int err; + + MLX5_SET(create_tis_in, in, opcode, MLX5_CMD_OP_CREATE_TIS); + + memset(out, 0, sizeof(out)); + err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); + if (!err) + *tisn = MLX5_GET(create_tis_out, out, tisn); + + return err; +} + +void mlx5_destroy_tis(struct mlx5_core_dev *dev, u32 tisn) +{ + u32 in[MLX5_ST_SZ_DW(destroy_tis_out)]; + u32 out[MLX5_ST_SZ_DW(destroy_tis_out)]; + + memset(in, 0, sizeof(in)); + + MLX5_SET(destroy_tis_in, in, opcode, MLX5_CMD_OP_DESTROY_TIS); + MLX5_SET(destroy_tis_in, in, tisn, tisn); + + mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out)); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.h b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h new file mode 100644 index 000000000000..1bc898cc4933 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __TRANSOBJ_H__ +#define __TRANSOBJ_H__ + +int mlx5_create_rq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *rqn); +int mlx5_modify_rq(struct mlx5_core_dev *dev, u32 rqn, u32 *in, int inlen); +void mlx5_destroy_rq(struct mlx5_core_dev *dev, u32 rqn); +int mlx5_create_sq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *sqn); +int mlx5_modify_sq(struct mlx5_core_dev *dev, u32 sqn, u32 *in, int inlen); +void mlx5_destroy_sq(struct mlx5_core_dev *dev, u32 sqn); +int mlx5_create_tir(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *tirn); +void mlx5_destroy_tir(struct mlx5_core_dev *dev, u32 tirn); +int mlx5_create_tis(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *tisn); +void mlx5_destroy_tis(struct mlx5_core_dev *dev, u32 tisn); + +#endif /* __TRANSOBJ_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c new file mode 100644 index 000000000000..ba374b9a6c87 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include "vport.h" +#include "mlx5_core.h" + +u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod) +{ + u32 in[MLX5_ST_SZ_DW(query_vport_state_in)]; + u32 out[MLX5_ST_SZ_DW(query_vport_state_out)]; + int err; + + memset(in, 0, sizeof(in)); + + MLX5_SET(query_vport_state_in, in, opcode, + MLX5_CMD_OP_QUERY_VPORT_STATE); + MLX5_SET(query_vport_state_in, in, op_mod, opmod); + + err = mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out, + sizeof(out)); + if (err) + mlx5_core_warn(mdev, "MLX5_CMD_OP_QUERY_VPORT_STATE failed\n"); + + return MLX5_GET(query_vport_state_out, out, state); +} + +void mlx5_query_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr) +{ + u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)]; + u32 *out; + int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out); + u8 *out_addr; + + out = mlx5_vzalloc(outlen); + if (!out) + return; + + out_addr = MLX5_ADDR_OF(query_nic_vport_context_out, out, + nic_vport_context.permanent_address); + + memset(in, 0, sizeof(in)); + + MLX5_SET(query_nic_vport_context_in, in, opcode, + MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT); + + memset(out, 0, outlen); + mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out, outlen); + + ether_addr_copy(addr, &out_addr[2]); + + kvfree(out); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.h b/drivers/net/ethernet/mellanox/mlx5/core/vport.h new file mode 100644 index 000000000000..c05ca2c3419d --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __MLX5_VPORT_H__ +#define __MLX5_VPORT_H__ + +#include + +u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod); +void mlx5_query_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr); + +#endif /* __MLX5_VPORT_H__ */ diff --git a/include/linux/mlx5/flow_table.h b/include/linux/mlx5/flow_table.h new file mode 100644 index 000000000000..5f922c6d4fc2 --- /dev/null +++ b/include/linux/mlx5/flow_table.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX5_FLOW_TABLE_H +#define MLX5_FLOW_TABLE_H + +#include + +struct mlx5_flow_table_group { + u8 log_sz; + u8 match_criteria_enable; + u32 match_criteria[MLX5_ST_SZ_DW(fte_match_param)]; +}; + +void *mlx5_create_flow_table(struct mlx5_core_dev *dev, u8 level, u8 table_type, + u16 num_groups, + struct mlx5_flow_table_group *group); +void mlx5_destroy_flow_table(void *flow_table); +int mlx5_add_flow_table_entry(void *flow_table, u8 match_criteria_enable, + void *match_criteria, void *flow_context, + u32 *flow_index); +void mlx5_del_flow_table_entry(void *flow_table, u32 flow_index); +u32 mlx5_get_flow_table_id(void *flow_table); + +#endif /* MLX5_FLOW_TABLE_H */ -- cgit v1.2.3 From f62b8bb8f2d30582f30f51e85a8c0e1260125d7e Mon Sep 17 00:00:00 2001 From: Amir Vadai Date: Thu, 28 May 2015 22:28:48 +0300 Subject: net/mlx5: Extend mlx5_core to support ConnectX-4 Ethernet functionality This is the Ethernet part of the driver for the Mellanox ConnectX(R)-4 Single/Dual-Port Adapter supporting 100Gb/s with VPI. The driver extends the existing mlx5 driver with Ethernet functionality. This patch contains the driver entry points but does not include transmit and receive (see the previous patch in the series) routines. It also adds the option MLX5_CORE_EN to Kconfig to enable/disable the Ethernet functionality. Currently, Kconfig is programmed to make Ethernet and Infiniband functionality mutally exclusive. Also changed MLX5_INFINIBAND to be depandant on MLX5_CORE instead of selecting it, since MLX5_CORE could be selected without MLX5_INFINIBAND being selected. Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/Kconfig | 4 +- drivers/net/ethernet/mellanox/mlx5/core/Kconfig | 14 +- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 3 + drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 19 - drivers/net/ethernet/mellanox/mlx5/core/en.h | 520 ++++++ .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 679 +++++++ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 1899 ++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/main.c | 74 +- .../net/ethernet/mellanox/mlx5/core/mlx5_core.h | 9 +- include/linux/mlx5/device.h | 19 + include/linux/mlx5/driver.h | 1 + 11 files changed, 3213 insertions(+), 28 deletions(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en.h create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_main.c (limited to 'include') diff --git a/drivers/infiniband/hw/mlx5/Kconfig b/drivers/infiniband/hw/mlx5/Kconfig index 10df386c6344..bce263b92821 100644 --- a/drivers/infiniband/hw/mlx5/Kconfig +++ b/drivers/infiniband/hw/mlx5/Kconfig @@ -1,8 +1,6 @@ config MLX5_INFINIBAND tristate "Mellanox Connect-IB HCA support" - depends on NETDEVICES && ETHERNET && PCI - select NET_VENDOR_MELLANOX - select MLX5_CORE + depends on NETDEVICES && ETHERNET && PCI && MLX5_CORE ---help--- This driver provides low-level InfiniBand support for Mellanox Connect-IB PCI Express host channel adapters (HCAs). diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig index 8ff57e8e3e91..0d7aef040fb0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig +++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig @@ -3,6 +3,18 @@ # config MLX5_CORE - tristate + tristate "Mellanox Technologies ConnectX-4 and Connect-IB core driver" depends on PCI default n + ---help--- + Core driver for low level functionality of the ConnectX-4 and + Connect-IB cards by Mellanox Technologies. + +config MLX5_CORE_EN + bool "Mellanox Technologies ConnectX-4 Ethernet support" + depends on MLX5_INFINIBAND=n && NETDEVICES && ETHERNET && PCI && MLX5_CORE + default n + ---help--- + Ethernet support in Mellanox Technologies ConnectX-4 NIC. + Ethernet and Infiniband support in ConnectX-4 are currently mutually + exclusive. diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 105780bb980b..87e9e606596a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -3,3 +3,6 @@ obj-$(CONFIG_MLX5_CORE) += mlx5_core.o mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \ mad.o +mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o flow_table.o vport.o transobj.o \ + en_main.o en_flow_table.o en_ethtool.o en_tx.o en_rx.o \ + en_txrx.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 2f22cd2de2b0..75ff58dc1ff5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -75,25 +75,6 @@ enum { MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR = 0x10, }; -enum { - MLX5_CMD_STAT_OK = 0x0, - MLX5_CMD_STAT_INT_ERR = 0x1, - MLX5_CMD_STAT_BAD_OP_ERR = 0x2, - MLX5_CMD_STAT_BAD_PARAM_ERR = 0x3, - MLX5_CMD_STAT_BAD_SYS_STATE_ERR = 0x4, - MLX5_CMD_STAT_BAD_RES_ERR = 0x5, - MLX5_CMD_STAT_RES_BUSY = 0x6, - MLX5_CMD_STAT_LIM_ERR = 0x8, - MLX5_CMD_STAT_BAD_RES_STATE_ERR = 0x9, - MLX5_CMD_STAT_IX_ERR = 0xa, - MLX5_CMD_STAT_NO_RES_ERR = 0xf, - MLX5_CMD_STAT_BAD_INP_LEN_ERR = 0x50, - MLX5_CMD_STAT_BAD_OUTP_LEN_ERR = 0x51, - MLX5_CMD_STAT_BAD_QP_STATE_ERR = 0x10, - MLX5_CMD_STAT_BAD_PKT_ERR = 0x30, - MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR = 0x40, -}; - static struct mlx5_cmd_work_ent *alloc_cmd(struct mlx5_cmd *cmd, struct mlx5_cmd_msg *in, struct mlx5_cmd_msg *out, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h new file mode 100644 index 000000000000..cbb3c7cb53f7 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -0,0 +1,520 @@ +/* + * Copyright (c) 2015, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include "vport.h" +#include "wq.h" +#include "transobj.h" +#include "mlx5_core.h" + +#define MLX5E_MAX_NUM_TC 8 + +#define MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE 0x7 +#define MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE 0xa +#define MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE 0xd + +#define MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE 0x7 +#define MLX5E_PARAMS_DEFAULT_LOG_RQ_SIZE 0xa +#define MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE 0xd + +#define MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ (16 * 1024) +#define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC 0x10 +#define MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS 0x20 +#define MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC 0x10 +#define MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS 0x20 +#define MLX5E_PARAMS_DEFAULT_MIN_RX_WQES 0x80 +#define MLX5E_PARAMS_DEFAULT_RX_HASH_LOG_TBL_SZ 0x7 +#define MLX5E_PARAMS_MIN_MTU 46 + +#define MLX5E_TX_CQ_POLL_BUDGET 128 +#define MLX5E_UPDATE_STATS_INTERVAL 200 /* msecs */ + +static const char vport_strings[][ETH_GSTRING_LEN] = { + /* vport statistics */ + "rx_packets", + "rx_bytes", + "tx_packets", + "tx_bytes", + "rx_error_packets", + "rx_error_bytes", + "tx_error_packets", + "tx_error_bytes", + "rx_unicast_packets", + "rx_unicast_bytes", + "tx_unicast_packets", + "tx_unicast_bytes", + "rx_multicast_packets", + "rx_multicast_bytes", + "tx_multicast_packets", + "tx_multicast_bytes", + "rx_broadcast_packets", + "rx_broadcast_bytes", + "tx_broadcast_packets", + "tx_broadcast_bytes", + + /* SW counters */ + "tso_packets", + "tso_bytes", + "lro_packets", + "lro_bytes", + "rx_csum_good", + "rx_csum_none", + "tx_csum_offload", + "tx_queue_stopped", + "tx_queue_wake", + "tx_queue_dropped", + "rx_wqe_err", +}; + +struct mlx5e_vport_stats { + /* HW counters */ + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; + u64 rx_error_packets; + u64 rx_error_bytes; + u64 tx_error_packets; + u64 tx_error_bytes; + u64 rx_unicast_packets; + u64 rx_unicast_bytes; + u64 tx_unicast_packets; + u64 tx_unicast_bytes; + u64 rx_multicast_packets; + u64 rx_multicast_bytes; + u64 tx_multicast_packets; + u64 tx_multicast_bytes; + u64 rx_broadcast_packets; + u64 rx_broadcast_bytes; + u64 tx_broadcast_packets; + u64 tx_broadcast_bytes; + + /* SW counters */ + u64 tso_packets; + u64 tso_bytes; + u64 lro_packets; + u64 lro_bytes; + u64 rx_csum_good; + u64 rx_csum_none; + u64 tx_csum_offload; + u64 tx_queue_stopped; + u64 tx_queue_wake; + u64 tx_queue_dropped; + u64 rx_wqe_err; + +#define NUM_VPORT_COUNTERS 31 +}; + +static const char rq_stats_strings[][ETH_GSTRING_LEN] = { + "packets", + "csum_none", + "lro_packets", + "lro_bytes", + "wqe_err" +}; + +struct mlx5e_rq_stats { + u64 packets; + u64 csum_none; + u64 lro_packets; + u64 lro_bytes; + u64 wqe_err; +#define NUM_RQ_STATS 5 +}; + +static const char sq_stats_strings[][ETH_GSTRING_LEN] = { + "packets", + "tso_packets", + "tso_bytes", + "csum_offload_none", + "stopped", + "wake", + "dropped", + "nop" +}; + +struct mlx5e_sq_stats { + u64 packets; + u64 tso_packets; + u64 tso_bytes; + u64 csum_offload_none; + u64 stopped; + u64 wake; + u64 dropped; + u64 nop; +#define NUM_SQ_STATS 8 +}; + +struct mlx5e_stats { + struct mlx5e_vport_stats vport; +}; + +struct mlx5e_params { + u8 log_sq_size; + u8 log_rq_size; + u16 num_channels; + u8 default_vlan_prio; + u8 num_tc; + u16 rx_cq_moderation_usec; + u16 rx_cq_moderation_pkts; + u16 tx_cq_moderation_usec; + u16 tx_cq_moderation_pkts; + u16 min_rx_wqes; + u16 rx_hash_log_tbl_sz; + bool lro_en; + u32 lro_wqe_sz; +}; + +enum { + MLX5E_RQ_STATE_POST_WQES_ENABLE, +}; + +enum cq_flags { + MLX5E_CQ_HAS_CQES = 1, +}; + +struct mlx5e_cq { + /* data path - accessed per cqe */ + struct mlx5_cqwq wq; + void *sqrq; + unsigned long flags; + + /* data path - accessed per napi poll */ + struct napi_struct *napi; + struct mlx5_core_cq mcq; + struct mlx5e_channel *channel; + + /* control */ + struct mlx5_wq_ctrl wq_ctrl; +} ____cacheline_aligned_in_smp; + +struct mlx5e_rq { + /* data path */ + struct mlx5_wq_ll wq; + u32 wqe_sz; + struct sk_buff **skb; + + struct device *pdev; + struct net_device *netdev; + struct mlx5e_rq_stats stats; + struct mlx5e_cq cq; + + unsigned long state; + int ix; + + /* control */ + struct mlx5_wq_ctrl wq_ctrl; + u32 rqn; + struct mlx5e_channel *channel; +} ____cacheline_aligned_in_smp; + +struct mlx5e_tx_skb_cb { + u32 num_bytes; + u8 num_wqebbs; + u8 num_dma; +}; + +#define MLX5E_TX_SKB_CB(__skb) ((struct mlx5e_tx_skb_cb *)__skb->cb) + +struct mlx5e_sq_dma { + dma_addr_t addr; + u32 size; +}; + +enum { + MLX5E_SQ_STATE_WAKE_TXQ_ENABLE, +}; + +struct mlx5e_sq { + /* data path */ + + /* dirtied @completion */ + u16 cc; + u32 dma_fifo_cc; + + /* dirtied @xmit */ + u16 pc ____cacheline_aligned_in_smp; + u32 dma_fifo_pc; + u32 bf_offset; + struct mlx5e_sq_stats stats; + + struct mlx5e_cq cq; + + /* pointers to per packet info: write@xmit, read@completion */ + struct sk_buff **skb; + struct mlx5e_sq_dma *dma_fifo; + + /* read only */ + struct mlx5_wq_cyc wq; + u32 dma_fifo_mask; + void __iomem *uar_map; + struct netdev_queue *txq; + u32 sqn; + u32 bf_buf_size; + struct device *pdev; + __be32 mkey_be; + unsigned long state; + + /* control path */ + struct mlx5_wq_ctrl wq_ctrl; + struct mlx5_uar uar; + struct mlx5e_channel *channel; + int tc; +} ____cacheline_aligned_in_smp; + +static inline bool mlx5e_sq_has_room_for(struct mlx5e_sq *sq, u16 n) +{ + return (((sq->wq.sz_m1 & (sq->cc - sq->pc)) >= n) || + (sq->cc == sq->pc)); +} + +enum channel_flags { + MLX5E_CHANNEL_NAPI_SCHED = 1, +}; + +struct mlx5e_channel { + /* data path */ + struct mlx5e_rq rq; + struct mlx5e_sq sq[MLX5E_MAX_NUM_TC]; + struct napi_struct napi; + struct device *pdev; + struct net_device *netdev; + __be32 mkey_be; + u8 num_tc; + unsigned long flags; + + /* control */ + struct mlx5e_priv *priv; + int ix; + int cpu; +}; + +enum mlx5e_traffic_types { + MLX5E_TT_IPV4_TCP = 0, + MLX5E_TT_IPV6_TCP = 1, + MLX5E_TT_IPV4_UDP = 2, + MLX5E_TT_IPV6_UDP = 3, + MLX5E_TT_IPV4 = 4, + MLX5E_TT_IPV6 = 5, + MLX5E_TT_ANY = 6, + MLX5E_NUM_TT = 7, +}; + +enum { + MLX5E_RQT_SPREADING = 0, + MLX5E_RQT_DEFAULT_RQ = 1, + MLX5E_NUM_RQT = 2, +}; + +struct mlx5e_eth_addr_info { + u8 addr[ETH_ALEN + 2]; + u32 tt_vec; + u32 ft_ix[MLX5E_NUM_TT]; /* flow table index per traffic type */ +}; + +#define MLX5E_ETH_ADDR_HASH_SIZE (1 << BITS_PER_BYTE) + +struct mlx5e_eth_addr_db { + struct hlist_head netdev_uc[MLX5E_ETH_ADDR_HASH_SIZE]; + struct hlist_head netdev_mc[MLX5E_ETH_ADDR_HASH_SIZE]; + struct mlx5e_eth_addr_info broadcast; + struct mlx5e_eth_addr_info allmulti; + struct mlx5e_eth_addr_info promisc; + bool broadcast_enabled; + bool allmulti_enabled; + bool promisc_enabled; +}; + +enum { + MLX5E_STATE_ASYNC_EVENTS_ENABLE, + MLX5E_STATE_OPENED, +}; + +struct mlx5e_vlan_db { + unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; + u32 active_vlans_ft_ix[VLAN_N_VID]; + u32 untagged_rule_ft_ix; + u32 any_vlan_rule_ft_ix; + bool filter_disabled; +}; + +struct mlx5e_flow_table { + void *vlan; + void *main; +}; + +struct mlx5e_priv { + /* priv data path fields - start */ + int order_base_2_num_channels; + int queue_mapping_channel_mask; + int num_tc; + int default_vlan_prio; + /* priv data path fields - end */ + + unsigned long state; + struct mutex state_lock; /* Protects Interface state */ + struct mlx5_uar cq_uar; + u32 pdn; + struct mlx5_core_mr mr; + + struct mlx5e_channel **channel; + u32 tisn[MLX5E_MAX_NUM_TC]; + u32 rqtn; + u32 tirn[MLX5E_NUM_TT]; + + struct mlx5e_flow_table ft; + struct mlx5e_eth_addr_db eth_addr; + struct mlx5e_vlan_db vlan; + + struct mlx5e_params params; + spinlock_t async_events_spinlock; /* sync hw events */ + struct work_struct update_carrier_work; + struct work_struct set_rx_mode_work; + struct delayed_work update_stats_work; + + struct mlx5_core_dev *mdev; + struct net_device *netdev; + struct mlx5e_stats stats; +}; + +#define MLX5E_NET_IP_ALIGN 2 + +struct mlx5e_tx_wqe { + struct mlx5_wqe_ctrl_seg ctrl; + struct mlx5_wqe_eth_seg eth; +}; + +struct mlx5e_rx_wqe { + struct mlx5_wqe_srq_next_seg next; + struct mlx5_wqe_data_seg data; +}; + +enum mlx5e_link_mode { + MLX5E_1000BASE_CX_SGMII = 0, + MLX5E_1000BASE_KX = 1, + MLX5E_10GBASE_CX4 = 2, + MLX5E_10GBASE_KX4 = 3, + MLX5E_10GBASE_KR = 4, + MLX5E_20GBASE_KR2 = 5, + MLX5E_40GBASE_CR4 = 6, + MLX5E_40GBASE_KR4 = 7, + MLX5E_56GBASE_R4 = 8, + MLX5E_10GBASE_CR = 12, + MLX5E_10GBASE_SR = 13, + MLX5E_10GBASE_ER = 14, + MLX5E_40GBASE_SR4 = 15, + MLX5E_40GBASE_LR4 = 16, + MLX5E_100GBASE_CR4 = 20, + MLX5E_100GBASE_SR4 = 21, + MLX5E_100GBASE_KR4 = 22, + MLX5E_100GBASE_LR4 = 23, + MLX5E_100BASE_TX = 24, + MLX5E_100BASE_T = 25, + MLX5E_10GBASE_T = 26, + MLX5E_25GBASE_CR = 27, + MLX5E_25GBASE_KR = 28, + MLX5E_25GBASE_SR = 29, + MLX5E_50GBASE_CR2 = 30, + MLX5E_50GBASE_KR2 = 31, + MLX5E_LINK_MODES_NUMBER, +}; + +#define MLX5E_PROT_MASK(link_mode) (1 << link_mode) + +u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback); +netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t mlx5e_xmit_multi_tc(struct sk_buff *skb, struct net_device *dev); + +void mlx5e_completion_event(struct mlx5_core_cq *mcq); +void mlx5e_cq_error_event(struct mlx5_core_cq *mcq, enum mlx5_event event); +int mlx5e_napi_poll(struct napi_struct *napi, int budget); +bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq); +bool mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget); +bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq); +struct mlx5_cqe64 *mlx5e_get_cqe(struct mlx5e_cq *cq); + +void mlx5e_update_stats(struct mlx5e_priv *priv); + +int mlx5e_open_flow_table(struct mlx5e_priv *priv); +void mlx5e_close_flow_table(struct mlx5e_priv *priv); +void mlx5e_init_eth_addr(struct mlx5e_priv *priv); +void mlx5e_set_rx_mode_core(struct mlx5e_priv *priv); +void mlx5e_set_rx_mode_work(struct work_struct *work); + +int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto, + u16 vid); +int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto, + u16 vid); +void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv); +void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv); +int mlx5e_add_all_vlan_rules(struct mlx5e_priv *priv); +void mlx5e_del_all_vlan_rules(struct mlx5e_priv *priv); + +int mlx5e_open_locked(struct net_device *netdev); +int mlx5e_close_locked(struct net_device *netdev); +int mlx5e_update_priv_params(struct mlx5e_priv *priv, + struct mlx5e_params *new_params); + +static inline void mlx5e_tx_notify_hw(struct mlx5e_sq *sq, + struct mlx5e_tx_wqe *wqe) +{ + /* ensure wqe is visible to device before updating doorbell record */ + dma_wmb(); + + *sq->wq.db = cpu_to_be32(sq->pc); + + /* ensure doorbell record is visible to device before ringing the + * doorbell + */ + wmb(); + + mlx5_write64((__be32 *)&wqe->ctrl, + sq->uar_map + MLX5_BF_OFFSET + sq->bf_offset, + NULL); + + sq->bf_offset ^= sq->bf_buf_size; +} + +static inline void mlx5e_cq_arm(struct mlx5e_cq *cq) +{ + struct mlx5_core_cq *mcq; + + mcq = &cq->mcq; + mlx5_cq_arm(mcq, MLX5_CQ_DB_REQ_NOT, mcq->uar->map, NULL, cq->wq.cc); +} + +extern const struct ethtool_ops mlx5e_ethtool_ops; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c new file mode 100644 index 000000000000..de7aec8abca1 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -0,0 +1,679 @@ +/* + * Copyright (c) 2015, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "en.h" + +static void mlx5e_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *drvinfo) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + struct mlx5_core_dev *mdev = priv->mdev; + + strlcpy(drvinfo->driver, DRIVER_NAME, sizeof(drvinfo->driver)); + strlcpy(drvinfo->version, DRIVER_VERSION " (" DRIVER_RELDATE ")", + sizeof(drvinfo->version)); + snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), + "%d.%d.%d", + fw_rev_maj(mdev), fw_rev_min(mdev), fw_rev_sub(mdev)); + strlcpy(drvinfo->bus_info, pci_name(mdev->pdev), + sizeof(drvinfo->bus_info)); +} + +static const struct { + u32 supported; + u32 advertised; + u32 speed; +} ptys2ethtool_table[MLX5E_LINK_MODES_NUMBER] = { + [MLX5E_1000BASE_CX_SGMII] = { + .supported = SUPPORTED_1000baseKX_Full, + .advertised = ADVERTISED_1000baseKX_Full, + .speed = 1000, + }, + [MLX5E_1000BASE_KX] = { + .supported = SUPPORTED_1000baseKX_Full, + .advertised = ADVERTISED_1000baseKX_Full, + .speed = 1000, + }, + [MLX5E_10GBASE_CX4] = { + .supported = SUPPORTED_10000baseKX4_Full, + .advertised = ADVERTISED_10000baseKX4_Full, + .speed = 10000, + }, + [MLX5E_10GBASE_KX4] = { + .supported = SUPPORTED_10000baseKX4_Full, + .advertised = ADVERTISED_10000baseKX4_Full, + .speed = 10000, + }, + [MLX5E_10GBASE_KR] = { + .supported = SUPPORTED_10000baseKR_Full, + .advertised = ADVERTISED_10000baseKR_Full, + .speed = 10000, + }, + [MLX5E_20GBASE_KR2] = { + .supported = SUPPORTED_20000baseKR2_Full, + .advertised = ADVERTISED_20000baseKR2_Full, + .speed = 20000, + }, + [MLX5E_40GBASE_CR4] = { + .supported = SUPPORTED_40000baseCR4_Full, + .advertised = ADVERTISED_40000baseCR4_Full, + .speed = 40000, + }, + [MLX5E_40GBASE_KR4] = { + .supported = SUPPORTED_40000baseKR4_Full, + .advertised = ADVERTISED_40000baseKR4_Full, + .speed = 40000, + }, + [MLX5E_56GBASE_R4] = { + .supported = SUPPORTED_56000baseKR4_Full, + .advertised = ADVERTISED_56000baseKR4_Full, + .speed = 56000, + }, + [MLX5E_10GBASE_CR] = { + .supported = SUPPORTED_10000baseKR_Full, + .advertised = ADVERTISED_10000baseKR_Full, + .speed = 10000, + }, + [MLX5E_10GBASE_SR] = { + .supported = SUPPORTED_10000baseKR_Full, + .advertised = ADVERTISED_10000baseKR_Full, + .speed = 10000, + }, + [MLX5E_10GBASE_ER] = { + .supported = SUPPORTED_10000baseKR_Full, + .advertised = ADVERTISED_10000baseKR_Full, + .speed = 10000, + }, + [MLX5E_40GBASE_SR4] = { + .supported = SUPPORTED_40000baseSR4_Full, + .advertised = ADVERTISED_40000baseSR4_Full, + .speed = 40000, + }, + [MLX5E_40GBASE_LR4] = { + .supported = SUPPORTED_40000baseLR4_Full, + .advertised = ADVERTISED_40000baseLR4_Full, + .speed = 40000, + }, + [MLX5E_100GBASE_CR4] = { + .speed = 100000, + }, + [MLX5E_100GBASE_SR4] = { + .speed = 100000, + }, + [MLX5E_100GBASE_KR4] = { + .speed = 100000, + }, + [MLX5E_100GBASE_LR4] = { + .speed = 100000, + }, + [MLX5E_100BASE_TX] = { + .speed = 100, + }, + [MLX5E_100BASE_T] = { + .supported = SUPPORTED_100baseT_Full, + .advertised = ADVERTISED_100baseT_Full, + .speed = 100, + }, + [MLX5E_10GBASE_T] = { + .supported = SUPPORTED_10000baseT_Full, + .advertised = ADVERTISED_10000baseT_Full, + .speed = 1000, + }, + [MLX5E_25GBASE_CR] = { + .speed = 25000, + }, + [MLX5E_25GBASE_KR] = { + .speed = 25000, + }, + [MLX5E_25GBASE_SR] = { + .speed = 25000, + }, + [MLX5E_50GBASE_CR2] = { + .speed = 50000, + }, + [MLX5E_50GBASE_KR2] = { + .speed = 50000, + }, +}; + +static int mlx5e_get_sset_count(struct net_device *dev, int sset) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + + switch (sset) { + case ETH_SS_STATS: + return NUM_VPORT_COUNTERS + + priv->params.num_channels * NUM_RQ_STATS + + priv->params.num_channels * priv->num_tc * + NUM_SQ_STATS; + /* fallthrough */ + default: + return -EOPNOTSUPP; + } +} + +static void mlx5e_get_strings(struct net_device *dev, + uint32_t stringset, uint8_t *data) +{ + int i, j, tc, idx = 0; + struct mlx5e_priv *priv = netdev_priv(dev); + + switch (stringset) { + case ETH_SS_PRIV_FLAGS: + break; + + case ETH_SS_TEST: + break; + + case ETH_SS_STATS: + /* VPORT counters */ + for (i = 0; i < NUM_VPORT_COUNTERS; i++) + strcpy(data + (idx++) * ETH_GSTRING_LEN, + vport_strings[i]); + + /* per channel counters */ + for (i = 0; i < priv->params.num_channels; i++) + for (j = 0; j < NUM_RQ_STATS; j++) + sprintf(data + (idx++) * ETH_GSTRING_LEN, + "rx%d_%s", i, rq_stats_strings[j]); + + for (i = 0; i < priv->params.num_channels; i++) + for (tc = 0; tc < priv->num_tc; tc++) + for (j = 0; j < NUM_SQ_STATS; j++) + sprintf(data + + (idx++) * ETH_GSTRING_LEN, + "tx%d_%d_%s", i, tc, + sq_stats_strings[j]); + break; + } +} + +static void mlx5e_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + int i, j, tc, idx = 0; + + if (!data) + return; + + mutex_lock(&priv->state_lock); + if (test_bit(MLX5E_STATE_OPENED, &priv->state)) + mlx5e_update_stats(priv); + mutex_unlock(&priv->state_lock); + + for (i = 0; i < NUM_VPORT_COUNTERS; i++) + data[idx++] = ((u64 *)&priv->stats.vport)[i]; + + /* per channel counters */ + for (i = 0; i < priv->params.num_channels; i++) + for (j = 0; j < NUM_RQ_STATS; j++) + data[idx++] = !test_bit(MLX5E_STATE_OPENED, + &priv->state) ? 0 : + ((u64 *)&priv->channel[i]->rq.stats)[j]; + + for (i = 0; i < priv->params.num_channels; i++) + for (tc = 0; tc < priv->num_tc; tc++) + for (j = 0; j < NUM_SQ_STATS; j++) + data[idx++] = !test_bit(MLX5E_STATE_OPENED, + &priv->state) ? 0 : + ((u64 *)&priv->channel[i]->sq[tc].stats)[j]; +} + +static void mlx5e_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *param) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + + param->rx_max_pending = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE; + param->tx_max_pending = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE; + param->rx_pending = 1 << priv->params.log_rq_size; + param->tx_pending = 1 << priv->params.log_sq_size; +} + +static int mlx5e_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *param) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + struct mlx5e_params new_params; + u16 min_rx_wqes; + u8 log_rq_size; + u8 log_sq_size; + int err = 0; + + if (param->rx_jumbo_pending) { + netdev_info(dev, "%s: rx_jumbo_pending not supported\n", + __func__); + return -EINVAL; + } + if (param->rx_mini_pending) { + netdev_info(dev, "%s: rx_mini_pending not supported\n", + __func__); + return -EINVAL; + } + if (param->rx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) { + netdev_info(dev, "%s: rx_pending (%d) < min (%d)\n", + __func__, param->rx_pending, + 1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE); + return -EINVAL; + } + if (param->rx_pending > (1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE)) { + netdev_info(dev, "%s: rx_pending (%d) > max (%d)\n", + __func__, param->rx_pending, + 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE); + return -EINVAL; + } + if (param->tx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) { + netdev_info(dev, "%s: tx_pending (%d) < min (%d)\n", + __func__, param->tx_pending, + 1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE); + return -EINVAL; + } + if (param->tx_pending > (1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE)) { + netdev_info(dev, "%s: tx_pending (%d) > max (%d)\n", + __func__, param->tx_pending, + 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE); + return -EINVAL; + } + + log_rq_size = order_base_2(param->rx_pending); + log_sq_size = order_base_2(param->tx_pending); + min_rx_wqes = min_t(u16, param->rx_pending - 1, + MLX5E_PARAMS_DEFAULT_MIN_RX_WQES); + + if (log_rq_size == priv->params.log_rq_size && + log_sq_size == priv->params.log_sq_size && + min_rx_wqes == priv->params.min_rx_wqes) + return 0; + + mutex_lock(&priv->state_lock); + new_params = priv->params; + new_params.log_rq_size = log_rq_size; + new_params.log_sq_size = log_sq_size; + new_params.min_rx_wqes = min_rx_wqes; + err = mlx5e_update_priv_params(priv, &new_params); + mutex_unlock(&priv->state_lock); + + return err; +} + +static void mlx5e_get_channels(struct net_device *dev, + struct ethtool_channels *ch) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + int ncv = priv->mdev->priv.eq_table.num_comp_vectors; + + ch->max_combined = ncv; + ch->combined_count = priv->params.num_channels; +} + +static int mlx5e_set_channels(struct net_device *dev, + struct ethtool_channels *ch) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + int ncv = priv->mdev->priv.eq_table.num_comp_vectors; + unsigned int count = ch->combined_count; + struct mlx5e_params new_params; + int err = 0; + + if (!count) { + netdev_info(dev, "%s: combined_count=0 not supported\n", + __func__); + return -EINVAL; + } + if (ch->rx_count || ch->tx_count) { + netdev_info(dev, "%s: separate rx/tx count not supported\n", + __func__); + return -EINVAL; + } + if (count > ncv) { + netdev_info(dev, "%s: count (%d) > max (%d)\n", + __func__, count, ncv); + return -EINVAL; + } + + if (priv->params.num_channels == count) + return 0; + + mutex_lock(&priv->state_lock); + new_params = priv->params; + new_params.num_channels = count; + err = mlx5e_update_priv_params(priv, &new_params); + mutex_unlock(&priv->state_lock); + + return err; +} + +static int mlx5e_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *coal) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + + coal->rx_coalesce_usecs = priv->params.rx_cq_moderation_usec; + coal->rx_max_coalesced_frames = priv->params.rx_cq_moderation_pkts; + coal->tx_coalesce_usecs = priv->params.tx_cq_moderation_usec; + coal->tx_max_coalesced_frames = priv->params.tx_cq_moderation_pkts; + + return 0; +} + +static int mlx5e_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *coal) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5e_channel *c; + int tc; + int i; + + priv->params.tx_cq_moderation_usec = coal->tx_coalesce_usecs; + priv->params.tx_cq_moderation_pkts = coal->tx_max_coalesced_frames; + priv->params.rx_cq_moderation_usec = coal->rx_coalesce_usecs; + priv->params.rx_cq_moderation_pkts = coal->rx_max_coalesced_frames; + + for (i = 0; i < priv->params.num_channels; ++i) { + c = priv->channel[i]; + + for (tc = 0; tc < c->num_tc; tc++) { + mlx5_core_modify_cq_moderation(mdev, + &c->sq[tc].cq.mcq, + coal->tx_coalesce_usecs, + coal->tx_max_coalesced_frames); + } + + mlx5_core_modify_cq_moderation(mdev, &c->rq.cq.mcq, + coal->rx_coalesce_usecs, + coal->rx_max_coalesced_frames); + } + + return 0; +} + +static u32 ptys2ethtool_supported_link(u32 eth_proto_cap) +{ + int i; + u32 supported_modes = 0; + + for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { + if (eth_proto_cap & MLX5E_PROT_MASK(i)) + supported_modes |= ptys2ethtool_table[i].supported; + } + return supported_modes; +} + +static u32 ptys2ethtool_adver_link(u32 eth_proto_cap) +{ + int i; + u32 advertising_modes = 0; + + for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { + if (eth_proto_cap & MLX5E_PROT_MASK(i)) + advertising_modes |= ptys2ethtool_table[i].advertised; + } + return advertising_modes; +} + +static u32 ptys2ethtool_supported_port(u32 eth_proto_cap) +{ + if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_10GBASE_CR) + | MLX5E_PROT_MASK(MLX5E_10GBASE_SR) + | MLX5E_PROT_MASK(MLX5E_40GBASE_CR4) + | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4) + | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4) + | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) { + return SUPPORTED_FIBRE; + } + + if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_100GBASE_KR4) + | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4) + | MLX5E_PROT_MASK(MLX5E_10GBASE_KR) + | MLX5E_PROT_MASK(MLX5E_10GBASE_KX4) + | MLX5E_PROT_MASK(MLX5E_1000BASE_KX))) { + return SUPPORTED_Backplane; + } + return 0; +} + +static void get_speed_duplex(struct net_device *netdev, + u32 eth_proto_oper, + struct ethtool_cmd *cmd) +{ + int i; + u32 speed = SPEED_UNKNOWN; + u8 duplex = DUPLEX_UNKNOWN; + + if (!netif_carrier_ok(netdev)) + goto out; + + for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { + if (eth_proto_oper & MLX5E_PROT_MASK(i)) { + speed = ptys2ethtool_table[i].speed; + duplex = DUPLEX_FULL; + break; + } + } +out: + ethtool_cmd_speed_set(cmd, speed); + cmd->duplex = duplex; +} + +static void get_supported(u32 eth_proto_cap, u32 *supported) +{ + *supported |= ptys2ethtool_supported_port(eth_proto_cap); + *supported |= ptys2ethtool_supported_link(eth_proto_cap); + *supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; +} + +static void get_advertising(u32 eth_proto_cap, u8 tx_pause, + u8 rx_pause, u32 *advertising) +{ + *advertising |= ptys2ethtool_adver_link(eth_proto_cap); + *advertising |= tx_pause ? ADVERTISED_Pause : 0; + *advertising |= (tx_pause ^ rx_pause) ? ADVERTISED_Asym_Pause : 0; +} + +static u8 get_connector_port(u32 eth_proto) +{ + if (eth_proto & (MLX5E_PROT_MASK(MLX5E_10GBASE_SR) + | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4) + | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4) + | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) { + return PORT_FIBRE; + } + + if (eth_proto & (MLX5E_PROT_MASK(MLX5E_40GBASE_CR4) + | MLX5E_PROT_MASK(MLX5E_10GBASE_CR) + | MLX5E_PROT_MASK(MLX5E_100GBASE_CR4))) { + return PORT_DA; + } + + if (eth_proto & (MLX5E_PROT_MASK(MLX5E_10GBASE_KX4) + | MLX5E_PROT_MASK(MLX5E_10GBASE_KR) + | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4) + | MLX5E_PROT_MASK(MLX5E_100GBASE_KR4))) { + return PORT_NONE; + } + + return PORT_OTHER; +} + +static void get_lp_advertising(u32 eth_proto_lp, u32 *lp_advertising) +{ + *lp_advertising = ptys2ethtool_adver_link(eth_proto_lp); +} + +static int mlx5e_get_settings(struct net_device *netdev, + struct ethtool_cmd *cmd) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + struct mlx5_core_dev *mdev = priv->mdev; + u32 out[MLX5_ST_SZ_DW(ptys_reg)]; + u32 eth_proto_cap; + u32 eth_proto_admin; + u32 eth_proto_lp; + u32 eth_proto_oper; + int err; + + err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN); + + if (err) { + netdev_err(netdev, "%s: query port ptys failed: %d\n", + __func__, err); + goto err_query_ptys; + } + + eth_proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability); + eth_proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin); + eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); + eth_proto_lp = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise); + + cmd->supported = 0; + cmd->advertising = 0; + + get_supported(eth_proto_cap, &cmd->supported); + get_advertising(eth_proto_admin, 0, 0, &cmd->advertising); + get_speed_duplex(netdev, eth_proto_oper, cmd); + + eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap; + + cmd->port = get_connector_port(eth_proto_oper); + get_lp_advertising(eth_proto_lp, &cmd->lp_advertising); + + cmd->transceiver = XCVR_INTERNAL; + +err_query_ptys: + return err; +} + +static u32 mlx5e_ethtool2ptys_adver_link(u32 link_modes) +{ + u32 i, ptys_modes = 0; + + for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { + if (ptys2ethtool_table[i].advertised & link_modes) + ptys_modes |= MLX5E_PROT_MASK(i); + } + + return ptys_modes; +} + +static u32 mlx5e_ethtool2ptys_speed_link(u32 speed) +{ + u32 i, speed_links = 0; + + for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { + if (ptys2ethtool_table[i].speed == speed) + speed_links |= MLX5E_PROT_MASK(i); + } + + return speed_links; +} + +static int mlx5e_set_settings(struct net_device *netdev, + struct ethtool_cmd *cmd) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + struct mlx5_core_dev *mdev = priv->mdev; + u32 link_modes; + u32 speed; + u32 eth_proto_cap, eth_proto_admin; + u8 port_status; + int err; + + speed = ethtool_cmd_speed(cmd); + + link_modes = cmd->autoneg == AUTONEG_ENABLE ? + mlx5e_ethtool2ptys_adver_link(cmd->advertising) : + mlx5e_ethtool2ptys_speed_link(speed); + + err = mlx5_query_port_proto_cap(mdev, ð_proto_cap, MLX5_PTYS_EN); + if (err) { + netdev_err(netdev, "%s: query port eth proto cap failed: %d\n", + __func__, err); + goto out; + } + + link_modes = link_modes & eth_proto_cap; + if (!link_modes) { + netdev_err(netdev, "%s: Not supported link mode(s) requested", + __func__); + err = -EINVAL; + goto out; + } + + err = mlx5_query_port_proto_admin(mdev, ð_proto_admin, MLX5_PTYS_EN); + if (err) { + netdev_err(netdev, "%s: query port eth proto admin failed: %d\n", + __func__, err); + goto out; + } + + if (link_modes == eth_proto_admin) + goto out; + + err = mlx5_set_port_proto(mdev, link_modes, MLX5_PTYS_EN); + if (err) { + netdev_err(netdev, "%s: set port eth proto admin failed: %d\n", + __func__, err); + goto out; + } + + err = mlx5_query_port_status(mdev, &port_status); + if (err) + goto out; + + if (port_status == MLX5_PORT_DOWN) + return 0; + + err = mlx5_set_port_status(mdev, MLX5_PORT_DOWN); + if (err) + goto out; + err = mlx5_set_port_status(mdev, MLX5_PORT_UP); +out: + return err; +} + +const struct ethtool_ops mlx5e_ethtool_ops = { + .get_drvinfo = mlx5e_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_strings = mlx5e_get_strings, + .get_sset_count = mlx5e_get_sset_count, + .get_ethtool_stats = mlx5e_get_ethtool_stats, + .get_ringparam = mlx5e_get_ringparam, + .set_ringparam = mlx5e_set_ringparam, + .get_channels = mlx5e_get_channels, + .set_channels = mlx5e_set_channels, + .get_coalesce = mlx5e_get_coalesce, + .set_coalesce = mlx5e_set_coalesce, + .get_settings = mlx5e_get_settings, + .set_settings = mlx5e_set_settings, +}; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c new file mode 100644 index 000000000000..eee829d119f9 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -0,0 +1,1899 @@ +/* + * Copyright (c) 2015, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "en.h" + +struct mlx5e_rq_param { + u32 rqc[MLX5_ST_SZ_DW(rqc)]; + struct mlx5_wq_param wq; +}; + +struct mlx5e_sq_param { + u32 sqc[MLX5_ST_SZ_DW(sqc)]; + struct mlx5_wq_param wq; +}; + +struct mlx5e_cq_param { + u32 cqc[MLX5_ST_SZ_DW(cqc)]; + struct mlx5_wq_param wq; + u16 eq_ix; +}; + +struct mlx5e_channel_param { + struct mlx5e_rq_param rq; + struct mlx5e_sq_param sq; + struct mlx5e_cq_param rx_cq; + struct mlx5e_cq_param tx_cq; +}; + +static void mlx5e_update_carrier(struct mlx5e_priv *priv) +{ + struct mlx5_core_dev *mdev = priv->mdev; + u8 port_state; + + port_state = mlx5_query_vport_state(mdev, + MLX5_QUERY_VPORT_STATE_IN_OP_MOD_VNIC_VPORT); + + if (port_state == VPORT_STATE_UP) + netif_carrier_on(priv->netdev); + else + netif_carrier_off(priv->netdev); +} + +static void mlx5e_update_carrier_work(struct work_struct *work) +{ + struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv, + update_carrier_work); + + mutex_lock(&priv->state_lock); + if (test_bit(MLX5E_STATE_OPENED, &priv->state)) + mlx5e_update_carrier(priv); + mutex_unlock(&priv->state_lock); +} + +void mlx5e_update_stats(struct mlx5e_priv *priv) +{ + struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5e_vport_stats *s = &priv->stats.vport; + struct mlx5e_rq_stats *rq_stats; + struct mlx5e_sq_stats *sq_stats; + u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)]; + u32 *out; + int outlen = MLX5_ST_SZ_BYTES(query_vport_counter_out); + u64 tx_offload_none; + int i, j; + + out = mlx5_vzalloc(outlen); + if (!out) + return; + + /* Collect firts the SW counters and then HW for consistency */ + s->tso_packets = 0; + s->tso_bytes = 0; + s->tx_queue_stopped = 0; + s->tx_queue_wake = 0; + s->tx_queue_dropped = 0; + tx_offload_none = 0; + s->lro_packets = 0; + s->lro_bytes = 0; + s->rx_csum_none = 0; + s->rx_wqe_err = 0; + for (i = 0; i < priv->params.num_channels; i++) { + rq_stats = &priv->channel[i]->rq.stats; + + s->lro_packets += rq_stats->lro_packets; + s->lro_bytes += rq_stats->lro_bytes; + s->rx_csum_none += rq_stats->csum_none; + s->rx_wqe_err += rq_stats->wqe_err; + + for (j = 0; j < priv->num_tc; j++) { + sq_stats = &priv->channel[i]->sq[j].stats; + + s->tso_packets += sq_stats->tso_packets; + s->tso_bytes += sq_stats->tso_bytes; + s->tx_queue_stopped += sq_stats->stopped; + s->tx_queue_wake += sq_stats->wake; + s->tx_queue_dropped += sq_stats->dropped; + tx_offload_none += sq_stats->csum_offload_none; + } + } + + /* HW counters */ + memset(in, 0, sizeof(in)); + + MLX5_SET(query_vport_counter_in, in, opcode, + MLX5_CMD_OP_QUERY_VPORT_COUNTER); + MLX5_SET(query_vport_counter_in, in, op_mod, 0); + MLX5_SET(query_vport_counter_in, in, other_vport, 0); + + memset(out, 0, outlen); + + if (mlx5_cmd_exec(mdev, in, sizeof(in), out, outlen)) + goto free_out; + +#define MLX5_GET_CTR(p, x) \ + MLX5_GET64(query_vport_counter_out, p, x) + + s->rx_error_packets = + MLX5_GET_CTR(out, received_errors.packets); + s->rx_error_bytes = + MLX5_GET_CTR(out, received_errors.octets); + s->tx_error_packets = + MLX5_GET_CTR(out, transmit_errors.packets); + s->tx_error_bytes = + MLX5_GET_CTR(out, transmit_errors.octets); + + s->rx_unicast_packets = + MLX5_GET_CTR(out, received_eth_unicast.packets); + s->rx_unicast_bytes = + MLX5_GET_CTR(out, received_eth_unicast.octets); + s->tx_unicast_packets = + MLX5_GET_CTR(out, transmitted_eth_unicast.packets); + s->tx_unicast_bytes = + MLX5_GET_CTR(out, transmitted_eth_unicast.octets); + + s->rx_multicast_packets = + MLX5_GET_CTR(out, received_eth_multicast.packets); + s->rx_multicast_bytes = + MLX5_GET_CTR(out, received_eth_multicast.octets); + s->tx_multicast_packets = + MLX5_GET_CTR(out, transmitted_eth_multicast.packets); + s->tx_multicast_bytes = + MLX5_GET_CTR(out, transmitted_eth_multicast.octets); + + s->rx_broadcast_packets = + MLX5_GET_CTR(out, received_eth_broadcast.packets); + s->rx_broadcast_bytes = + MLX5_GET_CTR(out, received_eth_broadcast.octets); + s->tx_broadcast_packets = + MLX5_GET_CTR(out, transmitted_eth_broadcast.packets); + s->tx_broadcast_bytes = + MLX5_GET_CTR(out, transmitted_eth_broadcast.octets); + + s->rx_packets = + s->rx_unicast_packets + + s->rx_multicast_packets + + s->rx_broadcast_packets; + s->rx_bytes = + s->rx_unicast_bytes + + s->rx_multicast_bytes + + s->rx_broadcast_bytes; + s->tx_packets = + s->tx_unicast_packets + + s->tx_multicast_packets + + s->tx_broadcast_packets; + s->tx_bytes = + s->tx_unicast_bytes + + s->tx_multicast_bytes + + s->tx_broadcast_bytes; + + /* Update calculated offload counters */ + s->tx_csum_offload = s->tx_packets - tx_offload_none; + s->rx_csum_good = s->rx_packets - s->rx_csum_none; + +free_out: + kvfree(out); +} + +static void mlx5e_update_stats_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct mlx5e_priv *priv = container_of(dwork, struct mlx5e_priv, + update_stats_work); + mutex_lock(&priv->state_lock); + if (test_bit(MLX5E_STATE_OPENED, &priv->state)) { + mlx5e_update_stats(priv); + schedule_delayed_work(dwork, + msecs_to_jiffies( + MLX5E_UPDATE_STATS_INTERVAL)); + } + mutex_unlock(&priv->state_lock); +} + +static void __mlx5e_async_event(struct mlx5e_priv *priv, + enum mlx5_dev_event event) +{ + switch (event) { + case MLX5_DEV_EVENT_PORT_UP: + case MLX5_DEV_EVENT_PORT_DOWN: + schedule_work(&priv->update_carrier_work); + break; + + default: + break; + } +} + +static void mlx5e_async_event(struct mlx5_core_dev *mdev, void *vpriv, + enum mlx5_dev_event event, unsigned long param) +{ + struct mlx5e_priv *priv = vpriv; + + spin_lock(&priv->async_events_spinlock); + if (test_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state)) + __mlx5e_async_event(priv, event); + spin_unlock(&priv->async_events_spinlock); +} + +static void mlx5e_enable_async_events(struct mlx5e_priv *priv) +{ + set_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state); +} + +static void mlx5e_disable_async_events(struct mlx5e_priv *priv) +{ + spin_lock_irq(&priv->async_events_spinlock); + clear_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state); + spin_unlock_irq(&priv->async_events_spinlock); +} + +static void mlx5e_send_nop(struct mlx5e_sq *sq) +{ + struct mlx5_wq_cyc *wq = &sq->wq; + + u16 pi = sq->pc & wq->sz_m1; + struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(wq, pi); + + struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl; + + memset(cseg, 0, sizeof(*cseg)); + + cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | MLX5_OPCODE_NOP); + cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | 0x01); + cseg->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE; + + sq->skb[pi] = NULL; + sq->pc++; + mlx5e_tx_notify_hw(sq, wqe); +} + +static int mlx5e_create_rq(struct mlx5e_channel *c, + struct mlx5e_rq_param *param, + struct mlx5e_rq *rq) +{ + struct mlx5e_priv *priv = c->priv; + struct mlx5_core_dev *mdev = priv->mdev; + void *rqc = param->rqc; + void *rqc_wq = MLX5_ADDR_OF(rqc, rqc, wq); + int wq_sz; + int err; + int i; + + err = mlx5_wq_ll_create(mdev, ¶m->wq, rqc_wq, &rq->wq, + &rq->wq_ctrl); + if (err) + return err; + + rq->wq.db = &rq->wq.db[MLX5_RCV_DBR]; + + wq_sz = mlx5_wq_ll_get_size(&rq->wq); + rq->skb = kzalloc_node(wq_sz * sizeof(*rq->skb), GFP_KERNEL, + cpu_to_node(c->cpu)); + if (!rq->skb) { + err = -ENOMEM; + goto err_rq_wq_destroy; + } + + rq->wqe_sz = (priv->params.lro_en) ? priv->params.lro_wqe_sz : + priv->netdev->mtu + ETH_HLEN + VLAN_HLEN; + + for (i = 0; i < wq_sz; i++) { + struct mlx5e_rx_wqe *wqe = mlx5_wq_ll_get_wqe(&rq->wq, i); + + wqe->data.lkey = c->mkey_be; + wqe->data.byte_count = cpu_to_be32(rq->wqe_sz); + } + + rq->pdev = c->pdev; + rq->netdev = c->netdev; + rq->channel = c; + rq->ix = c->ix; + + return 0; + +err_rq_wq_destroy: + mlx5_wq_destroy(&rq->wq_ctrl); + + return err; +} + +static void mlx5e_destroy_rq(struct mlx5e_rq *rq) +{ + kfree(rq->skb); + mlx5_wq_destroy(&rq->wq_ctrl); +} + +static int mlx5e_enable_rq(struct mlx5e_rq *rq, struct mlx5e_rq_param *param) +{ + struct mlx5e_channel *c = rq->channel; + struct mlx5e_priv *priv = c->priv; + struct mlx5_core_dev *mdev = priv->mdev; + + void *in; + void *rqc; + void *wq; + int inlen; + int err; + + inlen = MLX5_ST_SZ_BYTES(create_rq_in) + + sizeof(u64) * rq->wq_ctrl.buf.npages; + in = mlx5_vzalloc(inlen); + if (!in) + return -ENOMEM; + + rqc = MLX5_ADDR_OF(create_rq_in, in, ctx); + wq = MLX5_ADDR_OF(rqc, rqc, wq); + + memcpy(rqc, param->rqc, sizeof(param->rqc)); + + MLX5_SET(rqc, rqc, cqn, c->rq.cq.mcq.cqn); + MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RST); + MLX5_SET(rqc, rqc, flush_in_error_en, 1); + MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_LINKED_LIST); + MLX5_SET(wq, wq, log_wq_pg_sz, rq->wq_ctrl.buf.page_shift - + PAGE_SHIFT); + MLX5_SET64(wq, wq, dbr_addr, rq->wq_ctrl.db.dma); + + mlx5_fill_page_array(&rq->wq_ctrl.buf, + (__be64 *)MLX5_ADDR_OF(wq, wq, pas)); + + err = mlx5_create_rq(mdev, in, inlen, &rq->rqn); + + kvfree(in); + + return err; +} + +static int mlx5e_modify_rq(struct mlx5e_rq *rq, int curr_state, int next_state) +{ + struct mlx5e_channel *c = rq->channel; + struct mlx5e_priv *priv = c->priv; + struct mlx5_core_dev *mdev = priv->mdev; + + void *in; + void *rqc; + int inlen; + int err; + + inlen = MLX5_ST_SZ_BYTES(modify_rq_in); + in = mlx5_vzalloc(inlen); + if (!in) + return -ENOMEM; + + rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx); + + MLX5_SET(modify_rq_in, in, rq_state, curr_state); + MLX5_SET(rqc, rqc, state, next_state); + + err = mlx5_modify_rq(mdev, rq->rqn, in, inlen); + + kvfree(in); + + return err; +} + +static void mlx5e_disable_rq(struct mlx5e_rq *rq) +{ + struct mlx5e_channel *c = rq->channel; + struct mlx5e_priv *priv = c->priv; + struct mlx5_core_dev *mdev = priv->mdev; + + mlx5_destroy_rq(mdev, rq->rqn); +} + +static int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq) +{ + struct mlx5e_channel *c = rq->channel; + struct mlx5e_priv *priv = c->priv; + struct mlx5_wq_ll *wq = &rq->wq; + int i; + + for (i = 0; i < 1000; i++) { + if (wq->cur_sz >= priv->params.min_rx_wqes) + return 0; + + msleep(20); + } + + return -ETIMEDOUT; +} + +static int mlx5e_open_rq(struct mlx5e_channel *c, + struct mlx5e_rq_param *param, + struct mlx5e_rq *rq) +{ + int err; + + err = mlx5e_create_rq(c, param, rq); + if (err) + return err; + + err = mlx5e_enable_rq(rq, param); + if (err) + goto err_destroy_rq; + + err = mlx5e_modify_rq(rq, MLX5_RQC_STATE_RST, MLX5_RQC_STATE_RDY); + if (err) + goto err_disable_rq; + + set_bit(MLX5E_RQ_STATE_POST_WQES_ENABLE, &rq->state); + mlx5e_send_nop(&c->sq[0]); /* trigger mlx5e_post_rx_wqes() */ + + return 0; + +err_disable_rq: + mlx5e_disable_rq(rq); +err_destroy_rq: + mlx5e_destroy_rq(rq); + + return err; +} + +static void mlx5e_close_rq(struct mlx5e_rq *rq) +{ + clear_bit(MLX5E_RQ_STATE_POST_WQES_ENABLE, &rq->state); + napi_synchronize(&rq->channel->napi); /* prevent mlx5e_post_rx_wqes */ + + mlx5e_modify_rq(rq, MLX5_RQC_STATE_RDY, MLX5_RQC_STATE_ERR); + while (!mlx5_wq_ll_is_empty(&rq->wq)) + msleep(20); + + /* avoid destroying rq before mlx5e_poll_rx_cq() is done with it */ + napi_synchronize(&rq->channel->napi); + + mlx5e_disable_rq(rq); + mlx5e_destroy_rq(rq); +} + +static void mlx5e_free_sq_db(struct mlx5e_sq *sq) +{ + kfree(sq->dma_fifo); + kfree(sq->skb); +} + +static int mlx5e_alloc_sq_db(struct mlx5e_sq *sq, int numa) +{ + int wq_sz = mlx5_wq_cyc_get_size(&sq->wq); + int df_sz = wq_sz * MLX5_SEND_WQEBB_NUM_DS; + + sq->skb = kzalloc_node(wq_sz * sizeof(*sq->skb), GFP_KERNEL, numa); + sq->dma_fifo = kzalloc_node(df_sz * sizeof(*sq->dma_fifo), GFP_KERNEL, + numa); + + if (!sq->skb || !sq->dma_fifo) { + mlx5e_free_sq_db(sq); + return -ENOMEM; + } + + sq->dma_fifo_mask = df_sz - 1; + + return 0; +} + +static int mlx5e_create_sq(struct mlx5e_channel *c, + int tc, + struct mlx5e_sq_param *param, + struct mlx5e_sq *sq) +{ + struct mlx5e_priv *priv = c->priv; + struct mlx5_core_dev *mdev = priv->mdev; + + void *sqc = param->sqc; + void *sqc_wq = MLX5_ADDR_OF(sqc, sqc, wq); + int err; + + err = mlx5_alloc_map_uar(mdev, &sq->uar); + if (err) + return err; + + err = mlx5_wq_cyc_create(mdev, ¶m->wq, sqc_wq, &sq->wq, + &sq->wq_ctrl); + if (err) + goto err_unmap_free_uar; + + sq->wq.db = &sq->wq.db[MLX5_SND_DBR]; + sq->uar_map = sq->uar.map; + sq->bf_buf_size = (1 << MLX5_CAP_GEN(mdev, log_bf_reg_size)) / 2; + + if (mlx5e_alloc_sq_db(sq, cpu_to_node(c->cpu))) + goto err_sq_wq_destroy; + + sq->txq = netdev_get_tx_queue(priv->netdev, + c->ix + tc * priv->params.num_channels); + + sq->pdev = c->pdev; + sq->mkey_be = c->mkey_be; + sq->channel = c; + sq->tc = tc; + + return 0; + +err_sq_wq_destroy: + mlx5_wq_destroy(&sq->wq_ctrl); + +err_unmap_free_uar: + mlx5_unmap_free_uar(mdev, &sq->uar); + + return err; +} + +static void mlx5e_destroy_sq(struct mlx5e_sq *sq) +{ + struct mlx5e_channel *c = sq->channel; + struct mlx5e_priv *priv = c->priv; + + mlx5e_free_sq_db(sq); + mlx5_wq_destroy(&sq->wq_ctrl); + mlx5_unmap_free_uar(priv->mdev, &sq->uar); +} + +static int mlx5e_enable_sq(struct mlx5e_sq *sq, struct mlx5e_sq_param *param) +{ + struct mlx5e_channel *c = sq->channel; + struct mlx5e_priv *priv = c->priv; + struct mlx5_core_dev *mdev = priv->mdev; + + void *in; + void *sqc; + void *wq; + int inlen; + int err; + + inlen = MLX5_ST_SZ_BYTES(create_sq_in) + + sizeof(u64) * sq->wq_ctrl.buf.npages; + in = mlx5_vzalloc(inlen); + if (!in) + return -ENOMEM; + + sqc = MLX5_ADDR_OF(create_sq_in, in, ctx); + wq = MLX5_ADDR_OF(sqc, sqc, wq); + + memcpy(sqc, param->sqc, sizeof(param->sqc)); + + MLX5_SET(sqc, sqc, user_index, sq->tc); + MLX5_SET(sqc, sqc, tis_num_0, priv->tisn[sq->tc]); + MLX5_SET(sqc, sqc, cqn, c->sq[sq->tc].cq.mcq.cqn); + MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST); + MLX5_SET(sqc, sqc, tis_lst_sz, 1); + MLX5_SET(sqc, sqc, flush_in_error_en, 1); + + MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC); + MLX5_SET(wq, wq, uar_page, sq->uar.index); + MLX5_SET(wq, wq, log_wq_pg_sz, sq->wq_ctrl.buf.page_shift - + PAGE_SHIFT); + MLX5_SET64(wq, wq, dbr_addr, sq->wq_ctrl.db.dma); + + mlx5_fill_page_array(&sq->wq_ctrl.buf, + (__be64 *)MLX5_ADDR_OF(wq, wq, pas)); + + err = mlx5_create_sq(mdev, in, inlen, &sq->sqn); + + kvfree(in); + + return err; +} + +static int mlx5e_modify_sq(struct mlx5e_sq *sq, int curr_state, int next_state) +{ + struct mlx5e_channel *c = sq->channel; + struct mlx5e_priv *priv = c->priv; + struct mlx5_core_dev *mdev = priv->mdev; + + void *in; + void *sqc; + int inlen; + int err; + + inlen = MLX5_ST_SZ_BYTES(modify_sq_in); + in = mlx5_vzalloc(inlen); + if (!in) + return -ENOMEM; + + sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx); + + MLX5_SET(modify_sq_in, in, sq_state, curr_state); + MLX5_SET(sqc, sqc, state, next_state); + + err = mlx5_modify_sq(mdev, sq->sqn, in, inlen); + + kvfree(in); + + return err; +} + +static void mlx5e_disable_sq(struct mlx5e_sq *sq) +{ + struct mlx5e_channel *c = sq->channel; + struct mlx5e_priv *priv = c->priv; + struct mlx5_core_dev *mdev = priv->mdev; + + mlx5_destroy_sq(mdev, sq->sqn); +} + +static int mlx5e_open_sq(struct mlx5e_channel *c, + int tc, + struct mlx5e_sq_param *param, + struct mlx5e_sq *sq) +{ + int err; + + err = mlx5e_create_sq(c, tc, param, sq); + if (err) + return err; + + err = mlx5e_enable_sq(sq, param); + if (err) + goto err_destroy_sq; + + err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY); + if (err) + goto err_disable_sq; + + set_bit(MLX5E_SQ_STATE_WAKE_TXQ_ENABLE, &sq->state); + netdev_tx_reset_queue(sq->txq); + netif_tx_start_queue(sq->txq); + + return 0; + +err_disable_sq: + mlx5e_disable_sq(sq); +err_destroy_sq: + mlx5e_destroy_sq(sq); + + return err; +} + +static inline void netif_tx_disable_queue(struct netdev_queue *txq) +{ + __netif_tx_lock_bh(txq); + netif_tx_stop_queue(txq); + __netif_tx_unlock_bh(txq); +} + +static void mlx5e_close_sq(struct mlx5e_sq *sq) +{ + clear_bit(MLX5E_SQ_STATE_WAKE_TXQ_ENABLE, &sq->state); + napi_synchronize(&sq->channel->napi); /* prevent netif_tx_wake_queue */ + netif_tx_disable_queue(sq->txq); + + /* ensure hw is notified of all pending wqes */ + if (mlx5e_sq_has_room_for(sq, 1)) + mlx5e_send_nop(sq); + + mlx5e_modify_sq(sq, MLX5_SQC_STATE_RDY, MLX5_SQC_STATE_ERR); + while (sq->cc != sq->pc) /* wait till sq is empty */ + msleep(20); + + /* avoid destroying sq before mlx5e_poll_tx_cq() is done with it */ + napi_synchronize(&sq->channel->napi); + + mlx5e_disable_sq(sq); + mlx5e_destroy_sq(sq); +} + +static int mlx5e_create_cq(struct mlx5e_channel *c, + struct mlx5e_cq_param *param, + struct mlx5e_cq *cq) +{ + struct mlx5e_priv *priv = c->priv; + struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5_core_cq *mcq = &cq->mcq; + int eqn_not_used; + int irqn; + int err; + u32 i; + + param->wq.numa = cpu_to_node(c->cpu); + param->eq_ix = c->ix; + + err = mlx5_cqwq_create(mdev, ¶m->wq, param->cqc, &cq->wq, + &cq->wq_ctrl); + if (err) + return err; + + mlx5_vector2eqn(mdev, param->eq_ix, &eqn_not_used, &irqn); + + cq->napi = &c->napi; + + mcq->cqe_sz = 64; + mcq->set_ci_db = cq->wq_ctrl.db.db; + mcq->arm_db = cq->wq_ctrl.db.db + 1; + *mcq->set_ci_db = 0; + *mcq->arm_db = 0; + mcq->vector = param->eq_ix; + mcq->comp = mlx5e_completion_event; + mcq->event = mlx5e_cq_error_event; + mcq->irqn = irqn; + mcq->uar = &priv->cq_uar; + + for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) { + struct mlx5_cqe64 *cqe = mlx5_cqwq_get_wqe(&cq->wq, i); + + cqe->op_own = 0xf1; + } + + cq->channel = c; + + return 0; +} + +static void mlx5e_destroy_cq(struct mlx5e_cq *cq) +{ + mlx5_wq_destroy(&cq->wq_ctrl); +} + +static int mlx5e_enable_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param) +{ + struct mlx5e_channel *c = cq->channel; + struct mlx5e_priv *priv = c->priv; + struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5_core_cq *mcq = &cq->mcq; + + void *in; + void *cqc; + int inlen; + int irqn_not_used; + int eqn; + int err; + + inlen = MLX5_ST_SZ_BYTES(create_cq_in) + + sizeof(u64) * cq->wq_ctrl.buf.npages; + in = mlx5_vzalloc(inlen); + if (!in) + return -ENOMEM; + + cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context); + + memcpy(cqc, param->cqc, sizeof(param->cqc)); + + mlx5_fill_page_array(&cq->wq_ctrl.buf, + (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas)); + + mlx5_vector2eqn(mdev, param->eq_ix, &eqn, &irqn_not_used); + + MLX5_SET(cqc, cqc, c_eqn, eqn); + MLX5_SET(cqc, cqc, uar_page, mcq->uar->index); + MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift - + PAGE_SHIFT); + MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma); + + err = mlx5_core_create_cq(mdev, mcq, in, inlen); + + kvfree(in); + + if (err) + return err; + + mlx5e_cq_arm(cq); + + return 0; +} + +static void mlx5e_disable_cq(struct mlx5e_cq *cq) +{ + struct mlx5e_channel *c = cq->channel; + struct mlx5e_priv *priv = c->priv; + struct mlx5_core_dev *mdev = priv->mdev; + + mlx5_core_destroy_cq(mdev, &cq->mcq); +} + +static int mlx5e_open_cq(struct mlx5e_channel *c, + struct mlx5e_cq_param *param, + struct mlx5e_cq *cq, + u16 moderation_usecs, + u16 moderation_frames) +{ + int err; + struct mlx5e_priv *priv = c->priv; + struct mlx5_core_dev *mdev = priv->mdev; + + err = mlx5e_create_cq(c, param, cq); + if (err) + return err; + + err = mlx5e_enable_cq(cq, param); + if (err) + goto err_destroy_cq; + + err = mlx5_core_modify_cq_moderation(mdev, &cq->mcq, + moderation_usecs, + moderation_frames); + if (err) + goto err_destroy_cq; + + return 0; + +err_destroy_cq: + mlx5e_destroy_cq(cq); + + return err; +} + +static void mlx5e_close_cq(struct mlx5e_cq *cq) +{ + mlx5e_disable_cq(cq); + mlx5e_destroy_cq(cq); +} + +static int mlx5e_get_cpu(struct mlx5e_priv *priv, int ix) +{ + return cpumask_first(priv->mdev->priv.irq_info[ix].mask); +} + +static int mlx5e_open_tx_cqs(struct mlx5e_channel *c, + struct mlx5e_channel_param *cparam) +{ + struct mlx5e_priv *priv = c->priv; + int err; + int tc; + + for (tc = 0; tc < c->num_tc; tc++) { + err = mlx5e_open_cq(c, &cparam->tx_cq, &c->sq[tc].cq, + priv->params.tx_cq_moderation_usec, + priv->params.tx_cq_moderation_pkts); + if (err) + goto err_close_tx_cqs; + + c->sq[tc].cq.sqrq = &c->sq[tc]; + } + + return 0; + +err_close_tx_cqs: + for (tc--; tc >= 0; tc--) + mlx5e_close_cq(&c->sq[tc].cq); + + return err; +} + +static void mlx5e_close_tx_cqs(struct mlx5e_channel *c) +{ + int tc; + + for (tc = 0; tc < c->num_tc; tc++) + mlx5e_close_cq(&c->sq[tc].cq); +} + +static int mlx5e_open_sqs(struct mlx5e_channel *c, + struct mlx5e_channel_param *cparam) +{ + int err; + int tc; + + for (tc = 0; tc < c->num_tc; tc++) { + err = mlx5e_open_sq(c, tc, &cparam->sq, &c->sq[tc]); + if (err) + goto err_close_sqs; + } + + return 0; + +err_close_sqs: + for (tc--; tc >= 0; tc--) + mlx5e_close_sq(&c->sq[tc]); + + return err; +} + +static void mlx5e_close_sqs(struct mlx5e_channel *c) +{ + int tc; + + for (tc = 0; tc < c->num_tc; tc++) + mlx5e_close_sq(&c->sq[tc]); +} + +static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, + struct mlx5e_channel_param *cparam, + struct mlx5e_channel **cp) +{ + struct net_device *netdev = priv->netdev; + int cpu = mlx5e_get_cpu(priv, ix); + struct mlx5e_channel *c; + int err; + + c = kzalloc_node(sizeof(*c), GFP_KERNEL, cpu_to_node(cpu)); + if (!c) + return -ENOMEM; + + c->priv = priv; + c->ix = ix; + c->cpu = cpu; + c->pdev = &priv->mdev->pdev->dev; + c->netdev = priv->netdev; + c->mkey_be = cpu_to_be32(priv->mr.key); + c->num_tc = priv->num_tc; + + netif_napi_add(netdev, &c->napi, mlx5e_napi_poll, 64); + + err = mlx5e_open_tx_cqs(c, cparam); + if (err) + goto err_napi_del; + + err = mlx5e_open_cq(c, &cparam->rx_cq, &c->rq.cq, + priv->params.rx_cq_moderation_usec, + priv->params.rx_cq_moderation_pkts); + if (err) + goto err_close_tx_cqs; + c->rq.cq.sqrq = &c->rq; + + napi_enable(&c->napi); + + err = mlx5e_open_sqs(c, cparam); + if (err) + goto err_disable_napi; + + err = mlx5e_open_rq(c, &cparam->rq, &c->rq); + if (err) + goto err_close_sqs; + + netif_set_xps_queue(netdev, get_cpu_mask(c->cpu), ix); + *cp = c; + + return 0; + +err_close_sqs: + mlx5e_close_sqs(c); + +err_disable_napi: + napi_disable(&c->napi); + mlx5e_close_cq(&c->rq.cq); + +err_close_tx_cqs: + mlx5e_close_tx_cqs(c); + +err_napi_del: + netif_napi_del(&c->napi); + kfree(c); + + return err; +} + +static void mlx5e_close_channel(struct mlx5e_channel *c) +{ + mlx5e_close_rq(&c->rq); + mlx5e_close_sqs(c); + napi_disable(&c->napi); + mlx5e_close_cq(&c->rq.cq); + mlx5e_close_tx_cqs(c); + netif_napi_del(&c->napi); + kfree(c); +} + +static void mlx5e_build_rq_param(struct mlx5e_priv *priv, + struct mlx5e_rq_param *param) +{ + void *rqc = param->rqc; + void *wq = MLX5_ADDR_OF(rqc, rqc, wq); + + MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_LINKED_LIST); + MLX5_SET(wq, wq, end_padding_mode, MLX5_WQ_END_PAD_MODE_ALIGN); + MLX5_SET(wq, wq, log_wq_stride, ilog2(sizeof(struct mlx5e_rx_wqe))); + MLX5_SET(wq, wq, log_wq_sz, priv->params.log_rq_size); + MLX5_SET(wq, wq, pd, priv->pdn); + + param->wq.numa = dev_to_node(&priv->mdev->pdev->dev); + param->wq.linear = 1; +} + +static void mlx5e_build_sq_param(struct mlx5e_priv *priv, + struct mlx5e_sq_param *param) +{ + void *sqc = param->sqc; + void *wq = MLX5_ADDR_OF(sqc, sqc, wq); + + MLX5_SET(wq, wq, log_wq_sz, priv->params.log_sq_size); + MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB)); + MLX5_SET(wq, wq, pd, priv->pdn); + + param->wq.numa = dev_to_node(&priv->mdev->pdev->dev); +} + +static void mlx5e_build_common_cq_param(struct mlx5e_priv *priv, + struct mlx5e_cq_param *param) +{ + void *cqc = param->cqc; + + MLX5_SET(cqc, cqc, uar_page, priv->cq_uar.index); +} + +static void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv, + struct mlx5e_cq_param *param) +{ + void *cqc = param->cqc; + + MLX5_SET(cqc, cqc, log_cq_size, priv->params.log_rq_size); + + mlx5e_build_common_cq_param(priv, param); +} + +static void mlx5e_build_tx_cq_param(struct mlx5e_priv *priv, + struct mlx5e_cq_param *param) +{ + void *cqc = param->cqc; + + MLX5_SET(cqc, cqc, log_cq_size, priv->params.log_sq_size); + + mlx5e_build_common_cq_param(priv, param); +} + +static void mlx5e_build_channel_param(struct mlx5e_priv *priv, + struct mlx5e_channel_param *cparam) +{ + memset(cparam, 0, sizeof(*cparam)); + + mlx5e_build_rq_param(priv, &cparam->rq); + mlx5e_build_sq_param(priv, &cparam->sq); + mlx5e_build_rx_cq_param(priv, &cparam->rx_cq); + mlx5e_build_tx_cq_param(priv, &cparam->tx_cq); +} + +static int mlx5e_open_channels(struct mlx5e_priv *priv) +{ + struct mlx5e_channel_param cparam; + int err; + int i; + int j; + + priv->channel = kcalloc(priv->params.num_channels, + sizeof(struct mlx5e_channel *), GFP_KERNEL); + if (!priv->channel) + return -ENOMEM; + + mlx5e_build_channel_param(priv, &cparam); + for (i = 0; i < priv->params.num_channels; i++) { + err = mlx5e_open_channel(priv, i, &cparam, &priv->channel[i]); + if (err) + goto err_close_channels; + } + + for (j = 0; j < priv->params.num_channels; j++) { + err = mlx5e_wait_for_min_rx_wqes(&priv->channel[j]->rq); + if (err) + goto err_close_channels; + } + + return 0; + +err_close_channels: + for (i--; i >= 0; i--) + mlx5e_close_channel(priv->channel[i]); + + kfree(priv->channel); + + return err; +} + +static void mlx5e_close_channels(struct mlx5e_priv *priv) +{ + int i; + + for (i = 0; i < priv->params.num_channels; i++) + mlx5e_close_channel(priv->channel[i]); + + kfree(priv->channel); +} + +static int mlx5e_open_tis(struct mlx5e_priv *priv, int tc) +{ + struct mlx5_core_dev *mdev = priv->mdev; + u32 in[MLX5_ST_SZ_DW(create_tis_in)]; + void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx); + + memset(in, 0, sizeof(in)); + + MLX5_SET(tisc, tisc, prio, tc); + + return mlx5_create_tis(mdev, in, sizeof(in), &priv->tisn[tc]); +} + +static void mlx5e_close_tis(struct mlx5e_priv *priv, int tc) +{ + mlx5_destroy_tis(priv->mdev, priv->tisn[tc]); +} + +static int mlx5e_open_tises(struct mlx5e_priv *priv) +{ + int num_tc = priv->num_tc; + int err; + int tc; + + for (tc = 0; tc < num_tc; tc++) { + err = mlx5e_open_tis(priv, tc); + if (err) + goto err_close_tises; + } + + return 0; + +err_close_tises: + for (tc--; tc >= 0; tc--) + mlx5e_close_tis(priv, tc); + + return err; +} + +static void mlx5e_close_tises(struct mlx5e_priv *priv) +{ + int num_tc = priv->num_tc; + int tc; + + for (tc = 0; tc < num_tc; tc++) + mlx5e_close_tis(priv, tc); +} + +static int mlx5e_open_rqt(struct mlx5e_priv *priv) +{ + struct mlx5_core_dev *mdev = priv->mdev; + u32 *in; + u32 out[MLX5_ST_SZ_DW(create_rqt_out)]; + void *rqtc; + int inlen; + int err; + int sz; + int i; + + sz = 1 << priv->params.rx_hash_log_tbl_sz; + + inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz; + in = mlx5_vzalloc(inlen); + if (!in) + return -ENOMEM; + + rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context); + + MLX5_SET(rqtc, rqtc, rqt_actual_size, sz); + MLX5_SET(rqtc, rqtc, rqt_max_size, sz); + + for (i = 0; i < sz; i++) { + int ix = i % priv->params.num_channels; + + MLX5_SET(rqtc, rqtc, rq_num[i], priv->channel[ix]->rq.rqn); + } + + MLX5_SET(create_rqt_in, in, opcode, MLX5_CMD_OP_CREATE_RQT); + + memset(out, 0, sizeof(out)); + err = mlx5_cmd_exec_check_status(mdev, in, inlen, out, sizeof(out)); + if (!err) + priv->rqtn = MLX5_GET(create_rqt_out, out, rqtn); + + kvfree(in); + + return err; +} + +static void mlx5e_close_rqt(struct mlx5e_priv *priv) +{ + u32 in[MLX5_ST_SZ_DW(destroy_rqt_in)]; + u32 out[MLX5_ST_SZ_DW(destroy_rqt_out)]; + + memset(in, 0, sizeof(in)); + + MLX5_SET(destroy_rqt_in, in, opcode, MLX5_CMD_OP_DESTROY_RQT); + MLX5_SET(destroy_rqt_in, in, rqtn, priv->rqtn); + + mlx5_cmd_exec_check_status(priv->mdev, in, sizeof(in), out, + sizeof(out)); +} + +static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) +{ + void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer); + +#define ROUGH_MAX_L2_L3_HDR_SZ 256 + +#define MLX5_HASH_IP (MLX5_HASH_FIELD_SEL_SRC_IP |\ + MLX5_HASH_FIELD_SEL_DST_IP) + +#define MLX5_HASH_ALL (MLX5_HASH_FIELD_SEL_SRC_IP |\ + MLX5_HASH_FIELD_SEL_DST_IP |\ + MLX5_HASH_FIELD_SEL_L4_SPORT |\ + MLX5_HASH_FIELD_SEL_L4_DPORT) + + if (priv->params.lro_en) { + MLX5_SET(tirc, tirc, lro_enable_mask, + MLX5_TIRC_LRO_ENABLE_MASK_IPV4_LRO | + MLX5_TIRC_LRO_ENABLE_MASK_IPV6_LRO); + MLX5_SET(tirc, tirc, lro_max_ip_payload_size, + (priv->params.lro_wqe_sz - + ROUGH_MAX_L2_L3_HDR_SZ) >> 8); + MLX5_SET(tirc, tirc, lro_timeout_period_usecs, + MLX5_CAP_ETH(priv->mdev, + lro_timer_supported_periods[3])); + } + + switch (tt) { + case MLX5E_TT_ANY: + MLX5_SET(tirc, tirc, disp_type, + MLX5_TIRC_DISP_TYPE_DIRECT); + MLX5_SET(tirc, tirc, inline_rqn, + priv->channel[0]->rq.rqn); + break; + default: + MLX5_SET(tirc, tirc, disp_type, + MLX5_TIRC_DISP_TYPE_INDIRECT); + MLX5_SET(tirc, tirc, indirect_table, + priv->rqtn); + MLX5_SET(tirc, tirc, rx_hash_fn, + MLX5_TIRC_RX_HASH_FN_HASH_TOEPLITZ); + MLX5_SET(tirc, tirc, rx_hash_symmetric, 1); + netdev_rss_key_fill(MLX5_ADDR_OF(tirc, tirc, + rx_hash_toeplitz_key), + MLX5_FLD_SZ_BYTES(tirc, + rx_hash_toeplitz_key)); + break; + } + + switch (tt) { + case MLX5E_TT_IPV4_TCP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV4); + MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, + MLX5_L4_PROT_TYPE_TCP); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_ALL); + break; + + case MLX5E_TT_IPV6_TCP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV6); + MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, + MLX5_L4_PROT_TYPE_TCP); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_ALL); + break; + + case MLX5E_TT_IPV4_UDP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV4); + MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, + MLX5_L4_PROT_TYPE_UDP); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_ALL); + break; + + case MLX5E_TT_IPV6_UDP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV6); + MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, + MLX5_L4_PROT_TYPE_UDP); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_ALL); + break; + + case MLX5E_TT_IPV4: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV4); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP); + break; + + case MLX5E_TT_IPV6: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV6); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP); + break; + } +} + +static int mlx5e_open_tir(struct mlx5e_priv *priv, int tt) +{ + struct mlx5_core_dev *mdev = priv->mdev; + u32 *in; + void *tirc; + int inlen; + int err; + + inlen = MLX5_ST_SZ_BYTES(create_tir_in); + in = mlx5_vzalloc(inlen); + if (!in) + return -ENOMEM; + + tirc = MLX5_ADDR_OF(create_tir_in, in, ctx); + + mlx5e_build_tir_ctx(priv, tirc, tt); + + err = mlx5_create_tir(mdev, in, inlen, &priv->tirn[tt]); + + kvfree(in); + + return err; +} + +static void mlx5e_close_tir(struct mlx5e_priv *priv, int tt) +{ + mlx5_destroy_tir(priv->mdev, priv->tirn[tt]); +} + +static int mlx5e_open_tirs(struct mlx5e_priv *priv) +{ + int err; + int i; + + for (i = 0; i < MLX5E_NUM_TT; i++) { + err = mlx5e_open_tir(priv, i); + if (err) + goto err_close_tirs; + } + + return 0; + +err_close_tirs: + for (i--; i >= 0; i--) + mlx5e_close_tir(priv, i); + + return err; +} + +static void mlx5e_close_tirs(struct mlx5e_priv *priv) +{ + int i; + + for (i = 0; i < MLX5E_NUM_TT; i++) + mlx5e_close_tir(priv, i); +} + +int mlx5e_open_locked(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + struct mlx5_core_dev *mdev = priv->mdev; + int actual_mtu; + int num_txqs; + int err; + + num_txqs = roundup_pow_of_two(priv->params.num_channels) * + priv->params.num_tc; + netif_set_real_num_tx_queues(netdev, num_txqs); + netif_set_real_num_rx_queues(netdev, priv->params.num_channels); + + err = mlx5_set_port_mtu(mdev, netdev->mtu); + if (err) { + netdev_err(netdev, "%s: mlx5_set_port_mtu failed %d\n", + __func__, err); + return err; + } + + err = mlx5_query_port_oper_mtu(mdev, &actual_mtu); + if (err) { + netdev_err(netdev, "%s: mlx5_query_port_oper_mtu failed %d\n", + __func__, err); + return err; + } + + if (actual_mtu != netdev->mtu) + netdev_warn(netdev, "%s: Failed to set MTU to %d\n", + __func__, netdev->mtu); + + netdev->mtu = actual_mtu; + + err = mlx5e_open_tises(priv); + if (err) { + netdev_err(netdev, "%s: mlx5e_open_tises failed, %d\n", + __func__, err); + return err; + } + + err = mlx5e_open_channels(priv); + if (err) { + netdev_err(netdev, "%s: mlx5e_open_channels failed, %d\n", + __func__, err); + goto err_close_tises; + } + + err = mlx5e_open_rqt(priv); + if (err) { + netdev_err(netdev, "%s: mlx5e_open_rqt failed, %d\n", + __func__, err); + goto err_close_channels; + } + + err = mlx5e_open_tirs(priv); + if (err) { + netdev_err(netdev, "%s: mlx5e_open_tir failed, %d\n", + __func__, err); + goto err_close_rqls; + } + + err = mlx5e_open_flow_table(priv); + if (err) { + netdev_err(netdev, "%s: mlx5e_open_flow_table failed, %d\n", + __func__, err); + goto err_close_tirs; + } + + err = mlx5e_add_all_vlan_rules(priv); + if (err) { + netdev_err(netdev, "%s: mlx5e_add_all_vlan_rules failed, %d\n", + __func__, err); + goto err_close_flow_table; + } + + mlx5e_init_eth_addr(priv); + + set_bit(MLX5E_STATE_OPENED, &priv->state); + + mlx5e_update_carrier(priv); + mlx5e_set_rx_mode_core(priv); + + schedule_delayed_work(&priv->update_stats_work, 0); + return 0; + +err_close_flow_table: + mlx5e_close_flow_table(priv); + +err_close_tirs: + mlx5e_close_tirs(priv); + +err_close_rqls: + mlx5e_close_rqt(priv); + +err_close_channels: + mlx5e_close_channels(priv); + +err_close_tises: + mlx5e_close_tises(priv); + + return err; +} + +static int mlx5e_open(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + int err; + + mutex_lock(&priv->state_lock); + err = mlx5e_open_locked(netdev); + mutex_unlock(&priv->state_lock); + + return err; +} + +int mlx5e_close_locked(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + + clear_bit(MLX5E_STATE_OPENED, &priv->state); + + mlx5e_set_rx_mode_core(priv); + mlx5e_del_all_vlan_rules(priv); + netif_carrier_off(priv->netdev); + mlx5e_close_flow_table(priv); + mlx5e_close_tirs(priv); + mlx5e_close_rqt(priv); + mlx5e_close_channels(priv); + mlx5e_close_tises(priv); + + return 0; +} + +static int mlx5e_close(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + int err; + + mutex_lock(&priv->state_lock); + err = mlx5e_close_locked(netdev); + mutex_unlock(&priv->state_lock); + + return err; +} + +int mlx5e_update_priv_params(struct mlx5e_priv *priv, + struct mlx5e_params *new_params) +{ + int err = 0; + int was_opened; + + WARN_ON(!mutex_is_locked(&priv->state_lock)); + + was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); + if (was_opened) + mlx5e_close_locked(priv->netdev); + + priv->params = *new_params; + + if (was_opened) + err = mlx5e_open_locked(priv->netdev); + + return err; +} + +static struct rtnl_link_stats64 * +mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + struct mlx5e_vport_stats *vstats = &priv->stats.vport; + + stats->rx_packets = vstats->rx_packets; + stats->rx_bytes = vstats->rx_bytes; + stats->tx_packets = vstats->tx_packets; + stats->tx_bytes = vstats->tx_bytes; + stats->multicast = vstats->rx_multicast_packets + + vstats->tx_multicast_packets; + stats->tx_errors = vstats->tx_error_packets; + stats->rx_errors = vstats->rx_error_packets; + stats->tx_dropped = vstats->tx_queue_dropped; + stats->rx_crc_errors = 0; + stats->rx_length_errors = 0; + + return stats; +} + +static void mlx5e_set_rx_mode(struct net_device *dev) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + + schedule_work(&priv->set_rx_mode_work); +} + +static int mlx5e_set_mac(struct net_device *netdev, void *addr) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + struct sockaddr *saddr = addr; + + if (!is_valid_ether_addr(saddr->sa_data)) + return -EADDRNOTAVAIL; + + netif_addr_lock_bh(netdev); + ether_addr_copy(netdev->dev_addr, saddr->sa_data); + netif_addr_unlock_bh(netdev); + + schedule_work(&priv->set_rx_mode_work); + + return 0; +} + +static int mlx5e_set_features(struct net_device *netdev, + netdev_features_t features) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + netdev_features_t changes = features ^ netdev->features; + struct mlx5e_params new_params; + bool update_params = false; + + mutex_lock(&priv->state_lock); + new_params = priv->params; + + if (changes & NETIF_F_LRO) { + new_params.lro_en = !!(features & NETIF_F_LRO); + update_params = true; + } + + if (update_params) + mlx5e_update_priv_params(priv, &new_params); + + if (changes & NETIF_F_HW_VLAN_CTAG_FILTER) { + if (features & NETIF_F_HW_VLAN_CTAG_FILTER) + mlx5e_enable_vlan_filter(priv); + else + mlx5e_disable_vlan_filter(priv); + } + + mutex_unlock(&priv->state_lock); + + return 0; +} + +static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + struct mlx5_core_dev *mdev = priv->mdev; + int max_mtu; + int err = 0; + + err = mlx5_query_port_max_mtu(mdev, &max_mtu); + if (err) + return err; + + if (new_mtu > max_mtu || new_mtu < MLX5E_PARAMS_MIN_MTU) { + netdev_err(netdev, "%s: Bad MTU size, mtu must be [%d-%d]\n", + __func__, MLX5E_PARAMS_MIN_MTU, max_mtu); + return -EINVAL; + } + + mutex_lock(&priv->state_lock); + netdev->mtu = new_mtu; + err = mlx5e_update_priv_params(priv, &priv->params); + mutex_unlock(&priv->state_lock); + + return err; +} + +static struct net_device_ops mlx5e_netdev_ops = { + .ndo_open = mlx5e_open, + .ndo_stop = mlx5e_close, + .ndo_start_xmit = mlx5e_xmit, + .ndo_get_stats64 = mlx5e_get_stats, + .ndo_set_rx_mode = mlx5e_set_rx_mode, + .ndo_set_mac_address = mlx5e_set_mac, + .ndo_vlan_rx_add_vid = mlx5e_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = mlx5e_vlan_rx_kill_vid, + .ndo_set_features = mlx5e_set_features, + .ndo_change_mtu = mlx5e_change_mtu, +}; + +static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev) +{ + if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH) + return -ENOTSUPP; + if (!MLX5_CAP_GEN(mdev, eth_net_offloads) || + !MLX5_CAP_GEN(mdev, nic_flow_table) || + !MLX5_CAP_ETH(mdev, csum_cap) || + !MLX5_CAP_ETH(mdev, max_lso_cap) || + !MLX5_CAP_ETH(mdev, vlan_cap) || + !MLX5_CAP_ETH(mdev, rss_ind_tbl_cap)) { + mlx5_core_warn(mdev, + "Not creating net device, some required device capabilities are missing\n"); + return -ENOTSUPP; + } + return 0; +} + +static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev, + struct net_device *netdev, + int num_comp_vectors) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + + priv->params.log_sq_size = + MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE; + priv->params.log_rq_size = + MLX5E_PARAMS_DEFAULT_LOG_RQ_SIZE; + priv->params.rx_cq_moderation_usec = + MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC; + priv->params.rx_cq_moderation_pkts = + MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS; + priv->params.tx_cq_moderation_usec = + MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC; + priv->params.tx_cq_moderation_pkts = + MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS; + priv->params.min_rx_wqes = + MLX5E_PARAMS_DEFAULT_MIN_RX_WQES; + priv->params.rx_hash_log_tbl_sz = + (order_base_2(num_comp_vectors) > + MLX5E_PARAMS_DEFAULT_RX_HASH_LOG_TBL_SZ) ? + order_base_2(num_comp_vectors) : + MLX5E_PARAMS_DEFAULT_RX_HASH_LOG_TBL_SZ; + priv->params.num_tc = 1; + priv->params.default_vlan_prio = 0; + + priv->params.lro_en = false && !!MLX5_CAP_ETH(priv->mdev, lro_cap); + priv->params.lro_wqe_sz = + MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ; + + priv->mdev = mdev; + priv->netdev = netdev; + priv->params.num_channels = num_comp_vectors; + priv->order_base_2_num_channels = order_base_2(num_comp_vectors); + priv->queue_mapping_channel_mask = + roundup_pow_of_two(num_comp_vectors) - 1; + priv->num_tc = priv->params.num_tc; + priv->default_vlan_prio = priv->params.default_vlan_prio; + + spin_lock_init(&priv->async_events_spinlock); + mutex_init(&priv->state_lock); + + INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work); + INIT_WORK(&priv->set_rx_mode_work, mlx5e_set_rx_mode_work); + INIT_DELAYED_WORK(&priv->update_stats_work, mlx5e_update_stats_work); +} + +static void mlx5e_set_netdev_dev_addr(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + + mlx5_query_vport_mac_address(priv->mdev, netdev->dev_addr); +} + +static void mlx5e_build_netdev(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + struct mlx5_core_dev *mdev = priv->mdev; + + SET_NETDEV_DEV(netdev, &mdev->pdev->dev); + + if (priv->num_tc > 1) { + mlx5e_netdev_ops.ndo_select_queue = mlx5e_select_queue; + mlx5e_netdev_ops.ndo_start_xmit = mlx5e_xmit_multi_tc; + } + + netdev->netdev_ops = &mlx5e_netdev_ops; + netdev->watchdog_timeo = 15 * HZ; + + netdev->ethtool_ops = &mlx5e_ethtool_ops; + + netdev->vlan_features |= NETIF_F_IP_CSUM; + netdev->vlan_features |= NETIF_F_IPV6_CSUM; + netdev->vlan_features |= NETIF_F_GRO; + netdev->vlan_features |= NETIF_F_TSO; + netdev->vlan_features |= NETIF_F_TSO6; + netdev->vlan_features |= NETIF_F_RXCSUM; + netdev->vlan_features |= NETIF_F_RXHASH; + + if (!!MLX5_CAP_ETH(mdev, lro_cap)) + netdev->vlan_features |= NETIF_F_LRO; + + netdev->hw_features = netdev->vlan_features; + netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX; + netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX; + netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; + + netdev->features = netdev->hw_features; + if (!priv->params.lro_en) + netdev->features &= ~NETIF_F_LRO; + + netdev->features |= NETIF_F_HIGHDMA; + + netdev->priv_flags |= IFF_UNICAST_FLT; + + mlx5e_set_netdev_dev_addr(netdev); +} + +static int mlx5e_create_mkey(struct mlx5e_priv *priv, u32 pdn, + struct mlx5_core_mr *mr) +{ + struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5_create_mkey_mbox_in *in; + int err; + + in = mlx5_vzalloc(sizeof(*in)); + if (!in) + return -ENOMEM; + + in->seg.flags = MLX5_PERM_LOCAL_WRITE | + MLX5_PERM_LOCAL_READ | + MLX5_ACCESS_MODE_PA; + in->seg.flags_pd = cpu_to_be32(pdn | MLX5_MKEY_LEN64); + in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); + + err = mlx5_core_create_mkey(mdev, mr, in, sizeof(*in), NULL, NULL, + NULL); + + kvfree(in); + + return err; +} + +static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev) +{ + struct net_device *netdev; + struct mlx5e_priv *priv; + int ncv = mdev->priv.eq_table.num_comp_vectors; + int err; + + if (mlx5e_check_required_hca_cap(mdev)) + return NULL; + + netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv), + roundup_pow_of_two(ncv) * MLX5E_MAX_NUM_TC, + ncv); + if (!netdev) { + mlx5_core_err(mdev, "alloc_etherdev_mqs() failed\n"); + return NULL; + } + + mlx5e_build_netdev_priv(mdev, netdev, ncv); + mlx5e_build_netdev(netdev); + + netif_carrier_off(netdev); + + priv = netdev_priv(netdev); + + err = mlx5_alloc_map_uar(mdev, &priv->cq_uar); + if (err) { + netdev_err(netdev, "%s: mlx5_alloc_map_uar failed, %d\n", + __func__, err); + goto err_free_netdev; + } + + err = mlx5_core_alloc_pd(mdev, &priv->pdn); + if (err) { + netdev_err(netdev, "%s: mlx5_core_alloc_pd failed, %d\n", + __func__, err); + goto err_unmap_free_uar; + } + + err = mlx5e_create_mkey(priv, priv->pdn, &priv->mr); + if (err) { + netdev_err(netdev, "%s: mlx5e_create_mkey failed, %d\n", + __func__, err); + goto err_dealloc_pd; + } + + err = register_netdev(netdev); + if (err) { + netdev_err(netdev, "%s: register_netdev failed, %d\n", + __func__, err); + goto err_destroy_mkey; + } + + mlx5e_enable_async_events(priv); + + return priv; + +err_destroy_mkey: + mlx5_core_destroy_mkey(mdev, &priv->mr); + +err_dealloc_pd: + mlx5_core_dealloc_pd(mdev, priv->pdn); + +err_unmap_free_uar: + mlx5_unmap_free_uar(mdev, &priv->cq_uar); + +err_free_netdev: + free_netdev(netdev); + + return NULL; +} + +static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv) +{ + struct mlx5e_priv *priv = vpriv; + struct net_device *netdev = priv->netdev; + + unregister_netdev(netdev); + mlx5_core_destroy_mkey(priv->mdev, &priv->mr); + mlx5_core_dealloc_pd(priv->mdev, priv->pdn); + mlx5_unmap_free_uar(priv->mdev, &priv->cq_uar); + mlx5e_disable_async_events(priv); + flush_scheduled_work(); + free_netdev(netdev); +} + +static void *mlx5e_get_netdev(void *vpriv) +{ + struct mlx5e_priv *priv = vpriv; + + return priv->netdev; +} + +static struct mlx5_interface mlx5e_interface = { + .add = mlx5e_create_netdev, + .remove = mlx5e_destroy_netdev, + .event = mlx5e_async_event, + .protocol = MLX5_INTERFACE_PROTOCOL_ETH, + .get_dev = mlx5e_get_netdev, +}; + +void mlx5e_init(void) +{ + mlx5_register_interface(&mlx5e_interface); +} + +void mlx5e_cleanup(void) +{ + mlx5_unregister_interface(&mlx5e_interface); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index e7b7b123a128..1c37f587426d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -48,10 +48,6 @@ #include #include "mlx5_core.h" -#define DRIVER_NAME "mlx5_core" -#define DRIVER_VERSION "3.0" -#define DRIVER_RELDATE "January 2015" - MODULE_AUTHOR("Eli Cohen "); MODULE_DESCRIPTION("Mellanox Connect-IB, ConnectX-4 core driver"); MODULE_LICENSE("Dual BSD/GPL"); @@ -614,6 +610,61 @@ clean: return err; } +#ifdef CONFIG_MLX5_CORE_EN +static int mlx5_core_set_issi(struct mlx5_core_dev *dev) +{ + u32 query_in[MLX5_ST_SZ_DW(query_issi_in)]; + u32 query_out[MLX5_ST_SZ_DW(query_issi_out)]; + u32 set_in[MLX5_ST_SZ_DW(set_issi_in)]; + u32 set_out[MLX5_ST_SZ_DW(set_issi_out)]; + int err; + u32 sup_issi; + + memset(query_in, 0, sizeof(query_in)); + memset(query_out, 0, sizeof(query_out)); + + MLX5_SET(query_issi_in, query_in, opcode, MLX5_CMD_OP_QUERY_ISSI); + + err = mlx5_cmd_exec_check_status(dev, query_in, sizeof(query_in), + query_out, sizeof(query_out)); + if (err) { + if (((struct mlx5_outbox_hdr *)query_out)->status == + MLX5_CMD_STAT_BAD_OP_ERR) { + pr_debug("Only ISSI 0 is supported\n"); + return 0; + } + + pr_err("failed to query ISSI\n"); + return err; + } + + sup_issi = MLX5_GET(query_issi_out, query_out, supported_issi_dw0); + + if (sup_issi & (1 << 1)) { + memset(set_in, 0, sizeof(set_in)); + memset(set_out, 0, sizeof(set_out)); + + MLX5_SET(set_issi_in, set_in, opcode, MLX5_CMD_OP_SET_ISSI); + MLX5_SET(set_issi_in, set_in, current_issi, 1); + + err = mlx5_cmd_exec_check_status(dev, set_in, sizeof(set_in), + set_out, sizeof(set_out)); + if (err) { + pr_err("failed to set ISSI=1\n"); + return err; + } + + dev->issi = 1; + + return 0; + } else if (sup_issi & (1 << 0)) { + return 0; + } + + return -ENOTSUPP; +} +#endif + static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) { struct mlx5_priv *priv = &dev->priv; @@ -676,6 +727,14 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) goto err_pagealloc_cleanup; } +#ifdef CONFIG_MLX5_CORE_EN + err = mlx5_core_set_issi(dev); + if (err) { + dev_err(&pdev->dev, "failed to set issi\n"); + goto err_disable_hca; + } +#endif + err = mlx5_satisfy_startup_pages(dev, 1); if (err) { dev_err(&pdev->dev, "failed to allocate boot pages\n"); @@ -1084,6 +1143,10 @@ static int __init init(void) if (err) goto err_health; +#ifdef CONFIG_MLX5_CORE_EN + mlx5e_init(); +#endif + return 0; err_health: @@ -1096,6 +1159,9 @@ err_debug: static void __exit cleanup(void) { +#ifdef CONFIG_MLX5_CORE_EN + mlx5e_cleanup(); +#endif pci_unregister_driver(&mlx5_core_driver); mlx5_health_cleanup(); destroy_workqueue(mlx5_core_wq); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index b986f1c258bc..6983c1047255 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -37,6 +37,10 @@ #include #include +#define DRIVER_NAME "mlx5_core" +#define DRIVER_VERSION "3.0-1" +#define DRIVER_RELDATE "January 2015" + extern int mlx5_core_debug_mask; #define mlx5_core_dbg(dev, format, ...) \ @@ -78,4 +82,7 @@ int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev); int mlx5_cmd_init_hca(struct mlx5_core_dev *dev); int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev); +void mlx5e_init(void); +void mlx5e_cleanup(void); + #endif /* __MLX5_CORE_H__ */ diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 4ee52bf1f959..b288c538347a 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -1153,4 +1153,23 @@ enum mlx5_cap_type { #define MLX5_CAP_ODP(mdev, cap)\ MLX5_GET(odp_cap, mdev->hca_caps_cur[MLX5_CAP_ODP], cap) +enum { + MLX5_CMD_STAT_OK = 0x0, + MLX5_CMD_STAT_INT_ERR = 0x1, + MLX5_CMD_STAT_BAD_OP_ERR = 0x2, + MLX5_CMD_STAT_BAD_PARAM_ERR = 0x3, + MLX5_CMD_STAT_BAD_SYS_STATE_ERR = 0x4, + MLX5_CMD_STAT_BAD_RES_ERR = 0x5, + MLX5_CMD_STAT_RES_BUSY = 0x6, + MLX5_CMD_STAT_LIM_ERR = 0x8, + MLX5_CMD_STAT_BAD_RES_STATE_ERR = 0x9, + MLX5_CMD_STAT_IX_ERR = 0xa, + MLX5_CMD_STAT_NO_RES_ERR = 0xf, + MLX5_CMD_STAT_BAD_INP_LEN_ERR = 0x50, + MLX5_CMD_STAT_BAD_OUTP_LEN_ERR = 0x51, + MLX5_CMD_STAT_BAD_QP_STATE_ERR = 0x10, + MLX5_CMD_STAT_BAD_PKT_ERR = 0x30, + MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR = 0x40, +}; + #endif /* MLX5_DEVICE_H */ diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 51738472657e..7fa26f03acc1 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -489,6 +489,7 @@ struct mlx5_core_dev { struct mlx5_priv priv; struct mlx5_profile *profile; atomic_t num_qps; + u32 issi; }; struct mlx5_db { -- cgit v1.2.3 From 7bfea53b5c936d706d0bf60ec218fa72cde77121 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Tue, 19 May 2015 14:44:40 -0700 Subject: target: Move passthrough CDB parsing into a common function Aside from whether they handle BIDI ops or not, parsing of the CDB by kernel and user SCSI passthrough modules should be identical. Move this into a new passthrough_parse_cdb() and call it from tcm-pscsi and tcm-user. Reported-by: Christoph Hellwig Reviewed-by: Ilias Tsitsimpis Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 74 ++++++++++++++++++++++++++++++++++++ drivers/target/target_core_pscsi.c | 53 +------------------------- drivers/target/target_core_user.c | 43 +-------------------- include/target/target_core_backend.h | 2 + 4 files changed, 78 insertions(+), 94 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 7faa6aef9a4d..56b20dc54087 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1707,3 +1708,76 @@ void core_dev_release_virtual_lun0(void) target_free_device(g_lun0_dev); core_delete_hba(hba); } + +/* + * Common CDB parsing for kernel and user passthrough. + */ +sense_reason_t +passthrough_parse_cdb(struct se_cmd *cmd, + sense_reason_t (*exec_cmd)(struct se_cmd *cmd)) +{ + unsigned char *cdb = cmd->t_task_cdb; + + /* + * Clear a lun set in the cdb if the initiator talking to use spoke + * and old standards version, as we can't assume the underlying device + * won't choke up on it. + */ + switch (cdb[0]) { + case READ_10: /* SBC - RDProtect */ + case READ_12: /* SBC - RDProtect */ + case READ_16: /* SBC - RDProtect */ + case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */ + case VERIFY: /* SBC - VRProtect */ + case VERIFY_16: /* SBC - VRProtect */ + case WRITE_VERIFY: /* SBC - VRProtect */ + case WRITE_VERIFY_12: /* SBC - VRProtect */ + case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */ + break; + default: + cdb[1] &= 0x1f; /* clear logical unit number */ + break; + } + + /* + * For REPORT LUNS we always need to emulate the response, for everything + * else, pass it up. + */ + if (cdb[0] == REPORT_LUNS) { + cmd->execute_cmd = spc_emulate_report_luns; + return TCM_NO_SENSE; + } + + /* Set DATA_CDB flag for ops that should have it */ + switch (cdb[0]) { + case READ_6: + case READ_10: + case READ_12: + case READ_16: + case WRITE_6: + case WRITE_10: + case WRITE_12: + case WRITE_16: + case WRITE_VERIFY: + case WRITE_VERIFY_12: + case 0x8e: /* WRITE_VERIFY_16 */ + case COMPARE_AND_WRITE: + case XDWRITEREAD_10: + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + case VARIABLE_LENGTH_CMD: + switch (get_unaligned_be16(&cdb[8])) { + case READ_32: + case WRITE_32: + case 0x0c: /* WRITE_VERIFY_32 */ + case XDWRITEREAD_32: + cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; + break; + } + } + + cmd->execute_cmd = exec_cmd; + + return TCM_NO_SENSE; +} +EXPORT_SYMBOL(passthrough_parse_cdb); diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 4073869d2090..53bd0eb57095 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -973,64 +973,13 @@ fail: return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } -/* - * Clear a lun set in the cdb if the initiator talking to use spoke - * and old standards version, as we can't assume the underlying device - * won't choke up on it. - */ -static inline void pscsi_clear_cdb_lun(unsigned char *cdb) -{ - switch (cdb[0]) { - case READ_10: /* SBC - RDProtect */ - case READ_12: /* SBC - RDProtect */ - case READ_16: /* SBC - RDProtect */ - case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */ - case VERIFY: /* SBC - VRProtect */ - case VERIFY_16: /* SBC - VRProtect */ - case WRITE_VERIFY: /* SBC - VRProtect */ - case WRITE_VERIFY_12: /* SBC - VRProtect */ - case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */ - break; - default: - cdb[1] &= 0x1f; /* clear logical unit number */ - break; - } -} - static sense_reason_t pscsi_parse_cdb(struct se_cmd *cmd) { - unsigned char *cdb = cmd->t_task_cdb; - if (cmd->se_cmd_flags & SCF_BIDI) return TCM_UNSUPPORTED_SCSI_OPCODE; - pscsi_clear_cdb_lun(cdb); - - /* - * For REPORT LUNS we always need to emulate the response, for everything - * else the default for pSCSI is to pass the command to the underlying - * LLD / physical hardware. - */ - switch (cdb[0]) { - case REPORT_LUNS: - cmd->execute_cmd = spc_emulate_report_luns; - return 0; - case READ_6: - case READ_10: - case READ_12: - case READ_16: - case WRITE_6: - case WRITE_10: - case WRITE_12: - case WRITE_16: - case WRITE_VERIFY: - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - /* FALLTHROUGH*/ - default: - cmd->execute_cmd = pscsi_execute_cmd; - return 0; - } + return passthrough_parse_cdb(cmd, pscsi_execute_cmd); } static sense_reason_t diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 90e084ea7b92..2768ea2cfd7a 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1049,48 +1049,7 @@ tcmu_pass_op(struct se_cmd *se_cmd) static sense_reason_t tcmu_parse_cdb(struct se_cmd *cmd) { - unsigned char *cdb = cmd->t_task_cdb; - - /* - * For REPORT LUNS we always need to emulate the response, for everything - * else, pass it up. - */ - if (cdb[0] == REPORT_LUNS) { - cmd->execute_cmd = spc_emulate_report_luns; - return TCM_NO_SENSE; - } - - /* Set DATA_CDB flag for ops that should have it */ - switch (cdb[0]) { - case READ_6: - case READ_10: - case READ_12: - case READ_16: - case WRITE_6: - case WRITE_10: - case WRITE_12: - case WRITE_16: - case WRITE_VERIFY: - case WRITE_VERIFY_12: - case 0x8e: /* WRITE_VERIFY_16 */ - case COMPARE_AND_WRITE: - case XDWRITEREAD_10: - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - case VARIABLE_LENGTH_CMD: - switch (get_unaligned_be16(&cdb[8])) { - case READ_32: - case WRITE_32: - case 0x0c: /* WRITE_VERIFY_32 */ - case XDWRITEREAD_32: - cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - break; - } - } - - cmd->execute_cmd = tcmu_pass_op; - - return TCM_NO_SENSE; + return passthrough_parse_cdb(cmd, tcmu_pass_op); } DEF_TB_DEV_ATTRIB_RO(tcmu, hw_pi_prot_type); diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index d61be7297b2c..563e11970152 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -138,5 +138,7 @@ int se_dev_set_queue_depth(struct se_device *, u32); int se_dev_set_max_sectors(struct se_device *, u32); int se_dev_set_optimal_sectors(struct se_device *, u32); int se_dev_set_block_size(struct se_device *, u32); +sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd, + sense_reason_t (*exec_cmd)(struct se_cmd *cmd)); #endif /* TARGET_CORE_BACKEND_H */ -- cgit v1.2.3 From a3541703ebbf99d499656b15987175f6579b42ac Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Tue, 19 May 2015 14:44:41 -0700 Subject: target: Use a PASSTHROUGH flag instead of transport_types It seems like we only care if a transport is passthrough or not. Convert transport_type to a flags field and replace TRANSPORT_PLUGIN_* with a flag, TRANSPORT_FLAG_PASSTHROUGH. Signed-off-by: Andy Grover Reviewed-by: Ilias Tsitsimpis Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 4 ++-- drivers/target/target_core_configfs.c | 10 +++++----- drivers/target/target_core_device.c | 4 ++-- drivers/target/target_core_file.c | 1 - drivers/target/target_core_iblock.c | 1 - drivers/target/target_core_pr.c | 2 +- drivers/target/target_core_pscsi.c | 2 +- drivers/target/target_core_rd.c | 1 - drivers/target/target_core_transport.c | 6 +++--- drivers/target/target_core_user.c | 2 +- include/target/target_core_backend.h | 6 ++---- 11 files changed, 17 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 75cbde1f7c5b..4f8d4d459aa4 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -704,7 +704,7 @@ target_alua_state_check(struct se_cmd *cmd) if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE) return 0; - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return 0; if (!port) @@ -2377,7 +2377,7 @@ ssize_t core_alua_store_secondary_write_metadata( int core_setup_alua(struct se_device *dev) { - if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV && + if (!(dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) && !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) { struct t10_alua_lu_gp_member *lu_gp_mem; diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 1580077971f8..e7b0430a0575 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -811,7 +811,7 @@ static ssize_t target_core_dev_pr_show_attr_res_holder(struct se_device *dev, { int ret; - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return sprintf(page, "Passthrough\n"); spin_lock(&dev->dev_reservation_lock); @@ -962,7 +962,7 @@ SE_DEV_PR_ATTR_RO(res_pr_type); static ssize_t target_core_dev_pr_show_attr_res_type( struct se_device *dev, char *page) { - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return sprintf(page, "SPC_PASSTHROUGH\n"); else if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) return sprintf(page, "SPC2_RESERVATIONS\n"); @@ -975,7 +975,7 @@ SE_DEV_PR_ATTR_RO(res_type); static ssize_t target_core_dev_pr_show_attr_res_aptpl_active( struct se_device *dev, char *page) { - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return 0; return sprintf(page, "APTPL Bit Status: %s\n", @@ -990,7 +990,7 @@ SE_DEV_PR_ATTR_RO(res_aptpl_active); static ssize_t target_core_dev_pr_show_attr_res_aptpl_metadata( struct se_device *dev, char *page) { - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return 0; return sprintf(page, "Ready to process PR APTPL metadata..\n"); @@ -1037,7 +1037,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( u16 port_rpti = 0, tpgt = 0; u8 type = 0, scope; - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return 0; if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) return 0; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 56b20dc54087..ce5f768181ff 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -528,7 +528,7 @@ static void core_export_port( list_add_tail(&port->sep_list, &dev->dev_sep_list); spin_unlock(&dev->se_port_lock); - if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV && + if (!(dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) && !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) { tg_pt_gp_mem = core_alua_allocate_tg_pt_gp_mem(port); if (IS_ERR(tg_pt_gp_mem) || !tg_pt_gp_mem) { @@ -1604,7 +1604,7 @@ int target_configure_device(struct se_device *dev) * anything virtual (IBLOCK, FILEIO, RAMDISK), but not for TCM/pSCSI * passthrough because this is being provided by the backend LLD. */ - if (dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) { + if (!(dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)) { strncpy(&dev->t10_wwn.vendor[0], "LIO-ORG", 8); strncpy(&dev->t10_wwn.model[0], dev->transport->inquiry_prod, 16); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index f7e6e51aed36..3f27bfd816d8 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -958,7 +958,6 @@ static struct se_subsystem_api fileio_template = { .inquiry_prod = "FILEIO", .inquiry_rev = FD_VERSION, .owner = THIS_MODULE, - .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV, .attach_hba = fd_attach_hba, .detach_hba = fd_detach_hba, .alloc_device = fd_alloc_device, diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 1b7947c2510f..8c965683789f 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -904,7 +904,6 @@ static struct se_subsystem_api iblock_template = { .inquiry_prod = "IBLOCK", .inquiry_rev = IBLOCK_VERSION, .owner = THIS_MODULE, - .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV, .attach_hba = iblock_attach_hba, .detach_hba = iblock_detach_hba, .alloc_device = iblock_alloc_device, diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index b7c81acf08d0..a15411c79ae9 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -4093,7 +4093,7 @@ target_check_reservation(struct se_cmd *cmd) return 0; if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE) return 0; - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return 0; spin_lock(&dev->dev_reservation_lock); diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 53bd0eb57095..ecc5eaef13d6 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -1141,7 +1141,7 @@ static struct configfs_attribute *pscsi_backend_dev_attrs[] = { static struct se_subsystem_api pscsi_template = { .name = "pscsi", .owner = THIS_MODULE, - .transport_type = TRANSPORT_PLUGIN_PHBA_PDEV, + .transport_flags = TRANSPORT_FLAG_PASSTHROUGH, .attach_hba = pscsi_attach_hba, .detach_hba = pscsi_detach_hba, .pmode_enable_hba = pscsi_pmode_enable_hba, diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index a263bf5fab8d..d16489b6a1a4 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -733,7 +733,6 @@ static struct se_subsystem_api rd_mcp_template = { .name = "rd_mcp", .inquiry_prod = "RAMDISK-MCP", .inquiry_rev = RD_MCP_VERSION, - .transport_type = TRANSPORT_PLUGIN_VHBA_VDEV, .attach_hba = rd_attach_hba, .detach_hba = rd_detach_hba, .alloc_device = rd_alloc_device, diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 90c92f04a586..675f2d9d1f14 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1196,7 +1196,7 @@ transport_check_alloc_task_attr(struct se_cmd *cmd) * Check if SAM Task Attribute emulation is enabled for this * struct se_device storage object */ - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return 0; if (cmd->sam_task_attr == TCM_ACA_TAG) { @@ -1787,7 +1787,7 @@ static bool target_handle_task_attr(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return false; /* @@ -1912,7 +1912,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return; if (cmd->sam_task_attr == TCM_SIMPLE_TAG) { diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 2768ea2cfd7a..07d2996d8c1f 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1077,7 +1077,7 @@ static struct se_subsystem_api tcmu_template = { .inquiry_prod = "USER", .inquiry_rev = TCMU_VERSION, .owner = THIS_MODULE, - .transport_type = TRANSPORT_PLUGIN_PHBA_PDEV, + .transport_flags = TRANSPORT_FLAG_PASSTHROUGH, .attach_hba = tcmu_attach_hba, .detach_hba = tcmu_detach_hba, .alloc_device = tcmu_alloc_device, diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 563e11970152..5f1225706993 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -1,9 +1,7 @@ #ifndef TARGET_CORE_BACKEND_H #define TARGET_CORE_BACKEND_H -#define TRANSPORT_PLUGIN_PHBA_PDEV 1 -#define TRANSPORT_PLUGIN_VHBA_PDEV 2 -#define TRANSPORT_PLUGIN_VHBA_VDEV 3 +#define TRANSPORT_FLAG_PASSTHROUGH 1 struct target_backend_cits { struct config_item_type tb_dev_cit; @@ -22,7 +20,7 @@ struct se_subsystem_api { char inquiry_rev[4]; struct module *owner; - u8 transport_type; + u8 transport_flags; int (*attach_hba)(struct se_hba *, u32); void (*detach_hba)(struct se_hba *); -- cgit v1.2.3 From c66fa19c405a36673d4aab13658c8246413d5c0f Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Sun, 31 May 2015 09:30:16 +0300 Subject: net/mlx4: Add EQ pool Previously, mlx4_en allocated EQs and used them exclusively. This affected RoCE performance, as applications which are events sensitive were limited to use only the legacy EQs. Change that by introducing an EQ pool. This pool is managed by mlx4_core. EQs are assigned to ports (when there are limited number of EQs, multiple ports could be assigned to the same EQs). An exception to this rule is the ASYNC EQ which handles various events. Legacy EQs are completely removed as all EQs could be shared. When a consumer (mlx4_ib/mlx4_en) requests an EQ, it asks for EQ serving on a specific port. The core driver calculates which EQ should be assigned to that request. Because IRQs are shared between IB and Ethernet modules, their names only include the PCI device BDF address. Signed-off-by: Matan Barak Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx4/main.c | 71 ++--- drivers/infiniband/hw/mlx4/mlx4_ib.h | 1 - drivers/net/ethernet/mellanox/mlx4/cq.c | 10 +- drivers/net/ethernet/mellanox/mlx4/en_cq.c | 48 ++-- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 7 +- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 13 +- drivers/net/ethernet/mellanox/mlx4/eq.c | 353 +++++++++++++++---------- drivers/net/ethernet/mellanox/mlx4/main.c | 74 ++++-- drivers/net/ethernet/mellanox/mlx4/mlx4.h | 11 +- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 2 +- include/linux/mlx4/device.h | 11 +- 11 files changed, 342 insertions(+), 259 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 8c96c71e7bab..024b0f745035 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -2041,77 +2041,52 @@ static void init_pkeys(struct mlx4_ib_dev *ibdev) static void mlx4_ib_alloc_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev) { - char name[80]; - int eq_per_port = 0; - int added_eqs = 0; - int total_eqs = 0; - int i, j, eq; - - /* Legacy mode or comp_pool is not large enough */ - if (dev->caps.comp_pool == 0 || - dev->caps.num_ports > dev->caps.comp_pool) - return; - - eq_per_port = dev->caps.comp_pool / dev->caps.num_ports; - - /* Init eq table */ - added_eqs = 0; - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) - added_eqs += eq_per_port; - - total_eqs = dev->caps.num_comp_vectors + added_eqs; + int i, j, eq = 0, total_eqs = 0; - ibdev->eq_table = kzalloc(total_eqs * sizeof(int), GFP_KERNEL); + ibdev->eq_table = kcalloc(dev->caps.num_comp_vectors, + sizeof(ibdev->eq_table[0]), GFP_KERNEL); if (!ibdev->eq_table) return; - ibdev->eq_added = added_eqs; - - eq = 0; - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) { - for (j = 0; j < eq_per_port; j++) { - snprintf(name, sizeof(name), "mlx4-ib-%d-%d@%s", - i, j, dev->persist->pdev->bus->name); - /* Set IRQ for specific name (per ring) */ - if (mlx4_assign_eq(dev, name, NULL, - &ibdev->eq_table[eq])) { - /* Use legacy (same as mlx4_en driver) */ - pr_warn("Can't allocate EQ %d; reverting to legacy\n", eq); - ibdev->eq_table[eq] = - (eq % dev->caps.num_comp_vectors); - } - eq++; + for (i = 1; i <= dev->caps.num_ports; i++) { + for (j = 0; j < mlx4_get_eqs_per_port(dev, i); + j++, total_eqs++) { + if (i > 1 && mlx4_is_eq_shared(dev, total_eqs)) + continue; + ibdev->eq_table[eq] = total_eqs; + if (!mlx4_assign_eq(dev, i, + &ibdev->eq_table[eq])) + eq++; + else + ibdev->eq_table[eq] = -1; } } - /* Fill the reset of the vector with legacy EQ */ - for (i = 0, eq = added_eqs; i < dev->caps.num_comp_vectors; i++) - ibdev->eq_table[eq++] = i; + for (i = eq; i < dev->caps.num_comp_vectors; + ibdev->eq_table[i++] = -1) + ; /* Advertise the new number of EQs to clients */ - ibdev->ib_dev.num_comp_vectors = total_eqs; + ibdev->ib_dev.num_comp_vectors = eq; } static void mlx4_ib_free_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev) { int i; + int total_eqs = ibdev->ib_dev.num_comp_vectors; - /* no additional eqs were added */ + /* no eqs were allocated */ if (!ibdev->eq_table) return; /* Reset the advertised EQ number */ - ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors; + ibdev->ib_dev.num_comp_vectors = 0; - /* Free only the added eqs */ - for (i = 0; i < ibdev->eq_added; i++) { - /* Don't free legacy eqs if used */ - if (ibdev->eq_table[i] <= dev->caps.num_comp_vectors) - continue; + for (i = 0; i < total_eqs; i++) mlx4_release_eq(dev, ibdev->eq_table[i]); - } kfree(ibdev->eq_table); + ibdev->eq_table = NULL; } static void *mlx4_ib_add(struct mlx4_dev *dev) diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index fce3934372a1..ef80e6c99a68 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -523,7 +523,6 @@ struct mlx4_ib_dev { struct mlx4_ib_iboe iboe; int counters[MLX4_MAX_PORTS]; int *eq_table; - int eq_added; struct kobject *iov_parent; struct kobject *ports_parent; struct kobject *dev_ports_parent[MLX4_MFUNC_MAX]; diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c index e71f31387ac6..7431cd4d7390 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c @@ -292,7 +292,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, u64 mtt_addr; int err; - if (vector > dev->caps.num_comp_vectors + dev->caps.comp_pool) + if (vector >= dev->caps.num_comp_vectors) return -EINVAL; cq->vector = vector; @@ -319,7 +319,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, cq_context->flags |= cpu_to_be32(1 << 19); cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index); - cq_context->comp_eqn = priv->eq_table.eq[vector].eqn; + cq_context->comp_eqn = priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(vector)].eqn; cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; mtt_addr = mlx4_mtt_addr(dev, mtt); @@ -339,11 +339,11 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, init_completion(&cq->free); cq->comp = mlx4_add_cq_to_tasklet; cq->tasklet_ctx.priv = - &priv->eq_table.eq[cq->vector].tasklet_ctx; + &priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(vector)].tasklet_ctx; INIT_LIST_HEAD(&cq->tasklet_ctx.list); - cq->irq = priv->eq_table.eq[cq->vector].irq; + cq->irq = priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(vector)].irq; return 0; err_radix: @@ -368,7 +368,7 @@ void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq) if (err) mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn); - synchronize_irq(priv->eq_table.eq[cq->vector].irq); + synchronize_irq(priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(cq->vector)].irq); spin_lock_irq(&cq_table->lock); radix_tree_delete(&cq_table->tree, cq->cqn); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c index 22da4d0d0f05..d71c567eb076 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c @@ -66,6 +66,7 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv, cq->ring = ring; cq->is_tx = mode; + cq->vector = mdev->dev->caps.num_comp_vectors; /* Allocate HW buffers on provided NUMA node. * dev->numa_node is used in mtt range allocation flow. @@ -101,12 +102,7 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, int err = 0; char name[25]; int timestamp_en = 0; - struct cpu_rmap *rmap = -#ifdef CONFIG_RFS_ACCEL - priv->dev->rx_cpu_rmap; -#else - NULL; -#endif + bool assigned_eq = false; cq->dev = mdev->pndev[priv->port]; cq->mcq.set_ci_db = cq->wqres.db.db; @@ -116,23 +112,19 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, memset(cq->buf, 0, cq->buf_size); if (cq->is_tx == RX) { - if (mdev->dev->caps.comp_pool) { - if (!cq->vector) { - sprintf(name, "%s-%d", priv->dev->name, - cq->ring); - /* Set IRQ for specific name (per ring) */ - if (mlx4_assign_eq(mdev->dev, name, rmap, - &cq->vector)) { - cq->vector = (cq->ring + 1 + priv->port) - % mdev->dev->caps.num_comp_vectors; - mlx4_warn(mdev, "Failed assigning an EQ to %s, falling back to legacy EQ's\n", - name); - } - + if (!mlx4_is_eq_vector_valid(mdev->dev, priv->port, + cq->vector)) { + cq->vector = cq_idx; + + err = mlx4_assign_eq(mdev->dev, priv->port, + &cq->vector); + if (err) { + mlx4_err(mdev, "Failed assigning an EQ to %s\n", + name); + goto free_eq; } - } else { - cq->vector = (cq->ring + 1 + priv->port) % - mdev->dev->caps.num_comp_vectors; + + assigned_eq = true; } cq->irq_desc = @@ -159,7 +151,7 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, &mdev->priv_uar, cq->wqres.db.dma, &cq->mcq, cq->vector, 0, timestamp_en); if (err) - return err; + goto free_eq; cq->mcq.comp = cq->is_tx ? mlx4_en_tx_irq : mlx4_en_rx_irq; cq->mcq.event = mlx4_en_cq_event; @@ -182,6 +174,12 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, napi_enable(&cq->napi); return 0; + +free_eq: + if (assigned_eq) + mlx4_release_eq(mdev->dev, cq->vector); + cq->vector = mdev->dev->caps.num_comp_vectors; + return err; } void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq) @@ -191,9 +189,9 @@ void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq) mlx4_en_unmap_buffer(&cq->wqres.buf); mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); - if (priv->mdev->dev->caps.comp_pool && cq->vector) { + if (mlx4_is_eq_vector_valid(mdev->dev, priv->port, cq->vector) && + cq->is_tx == RX) mlx4_release_eq(priv->mdev->dev, cq->vector); - } cq->vector = 0; cq->buf_size = 0; cq->buf = NULL; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 32f5ec737472..455cecae5aa4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1958,7 +1958,6 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv) int i; #ifdef CONFIG_RFS_ACCEL - free_irq_cpu_rmap(priv->dev->rx_cpu_rmap); priv->dev->rx_cpu_rmap = NULL; #endif @@ -2016,11 +2015,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) } #ifdef CONFIG_RFS_ACCEL - if (priv->mdev->dev->caps.comp_pool) { - priv->dev->rx_cpu_rmap = alloc_irq_cpu_rmap(priv->mdev->dev->caps.comp_pool); - if (!priv->dev->rx_cpu_rmap) - goto err; - } + priv->dev->rx_cpu_rmap = mlx4_get_cpu_rmap(priv->mdev->dev, priv->port); #endif return 0; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 2a77a6b19121..35f726c17e48 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -337,15 +337,10 @@ void mlx4_en_set_num_rx_rings(struct mlx4_en_dev *mdev) struct mlx4_dev *dev = mdev->dev; mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { - if (!dev->caps.comp_pool) - num_of_eqs = max_t(int, MIN_RX_RINGS, - min_t(int, - dev->caps.num_comp_vectors, - DEF_RX_RINGS)); - else - num_of_eqs = min_t(int, MAX_MSIX_P_PORT, - dev->caps.comp_pool/ - dev->caps.num_ports) - 1; + num_of_eqs = max_t(int, MIN_RX_RINGS, + min_t(int, + mlx4_get_eqs_per_port(mdev->dev, i), + DEF_RX_RINGS)); num_rx_rings = mlx4_low_memory_profile() ? MIN_RX_RINGS : min_t(int, num_of_eqs, diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 80bcd648c5e0..2e6fc6a860a7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -895,8 +895,8 @@ static int mlx4_num_eq_uar(struct mlx4_dev *dev) * we need to map, take the difference of highest index and * the lowest index we'll use and add 1. */ - return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs + - dev->caps.comp_pool)/4 - dev->caps.reserved_eqs/4 + 1; + return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs) / 4 - + dev->caps.reserved_eqs / 4 + 1; } static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) @@ -1085,8 +1085,7 @@ static void mlx4_free_eq(struct mlx4_dev *dev, static void mlx4_free_irqs(struct mlx4_dev *dev) { struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; - struct mlx4_priv *priv = mlx4_priv(dev); - int i, vec; + int i; if (eq_table->have_irq) free_irq(dev->persist->pdev->irq, dev); @@ -1097,20 +1096,6 @@ static void mlx4_free_irqs(struct mlx4_dev *dev) eq_table->eq[i].have_irq = 0; } - for (i = 0; i < dev->caps.comp_pool; i++) { - /* - * Freeing the assigned irq's - * all bits should be 0, but we need to validate - */ - if (priv->msix_ctl.pool_bm & 1ULL << i) { - /* NO need protecting*/ - vec = dev->caps.num_comp_vectors + 1 + i; - free_irq(priv->eq_table.eq[vec].irq, - &priv->eq_table.eq[vec]); - } - } - - kfree(eq_table->irq_names); } @@ -1191,76 +1176,73 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) } priv->eq_table.irq_names = - kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1 + - dev->caps.comp_pool), + kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1), GFP_KERNEL); if (!priv->eq_table.irq_names) { err = -ENOMEM; - goto err_out_bitmap; + goto err_out_clr_int; } - for (i = 0; i < dev->caps.num_comp_vectors; ++i) { - err = mlx4_create_eq(dev, dev->caps.num_cqs - - dev->caps.reserved_cqs + - MLX4_NUM_SPARE_EQE, - (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, - &priv->eq_table.eq[i]); - if (err) { - --i; - goto err_out_unmap; - } - } - - err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE, - (dev->flags & MLX4_FLAG_MSI_X) ? dev->caps.num_comp_vectors : 0, - &priv->eq_table.eq[dev->caps.num_comp_vectors]); - if (err) - goto err_out_comp; - - /*if additional completion vectors poolsize is 0 this loop will not run*/ - for (i = dev->caps.num_comp_vectors + 1; - i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) { + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) { + if (i == MLX4_EQ_ASYNC) { + err = mlx4_create_eq(dev, + MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE, + 0, &priv->eq_table.eq[MLX4_EQ_ASYNC]); + } else { +#ifdef CONFIG_RFS_ACCEL + struct mlx4_eq *eq = &priv->eq_table.eq[i]; + int port = find_first_bit(eq->actv_ports.ports, + dev->caps.num_ports) + 1; + + if (port <= dev->caps.num_ports) { + struct mlx4_port_info *info = + &mlx4_priv(dev)->port[port]; + + if (!info->rmap) { + info->rmap = alloc_irq_cpu_rmap( + mlx4_get_eqs_per_port(dev, port)); + if (!info->rmap) { + mlx4_warn(dev, "Failed to allocate cpu rmap\n"); + err = -ENOMEM; + goto err_out_unmap; + } + } - err = mlx4_create_eq(dev, dev->caps.num_cqs - - dev->caps.reserved_cqs + - MLX4_NUM_SPARE_EQE, - (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, - &priv->eq_table.eq[i]); - if (err) { - --i; - goto err_out_unmap; + err = irq_cpu_rmap_add( + info->rmap, eq->irq); + if (err) + mlx4_warn(dev, "Failed adding irq rmap\n"); + } +#endif + err = mlx4_create_eq(dev, dev->caps.num_cqs - + dev->caps.reserved_cqs + + MLX4_NUM_SPARE_EQE, + (dev->flags & MLX4_FLAG_MSI_X) ? + i + 1 - !!(i > MLX4_EQ_ASYNC) : 0, + eq); } + if (err) + goto err_out_unmap; } - if (dev->flags & MLX4_FLAG_MSI_X) { const char *eq_name; - for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) { - if (i < dev->caps.num_comp_vectors) { - snprintf(priv->eq_table.irq_names + - i * MLX4_IRQNAME_SIZE, - MLX4_IRQNAME_SIZE, - "mlx4-comp-%d@pci:%s", i, - pci_name(dev->persist->pdev)); - } else { - snprintf(priv->eq_table.irq_names + - i * MLX4_IRQNAME_SIZE, - MLX4_IRQNAME_SIZE, - "mlx4-async@pci:%s", - pci_name(dev->persist->pdev)); - } + snprintf(priv->eq_table.irq_names + + MLX4_EQ_ASYNC * MLX4_IRQNAME_SIZE, + MLX4_IRQNAME_SIZE, + "mlx4-async@pci:%s", + pci_name(dev->persist->pdev)); + eq_name = priv->eq_table.irq_names + + MLX4_EQ_ASYNC * MLX4_IRQNAME_SIZE; - eq_name = priv->eq_table.irq_names + - i * MLX4_IRQNAME_SIZE; - err = request_irq(priv->eq_table.eq[i].irq, - mlx4_msi_x_interrupt, 0, eq_name, - priv->eq_table.eq + i); - if (err) - goto err_out_async; + err = request_irq(priv->eq_table.eq[MLX4_EQ_ASYNC].irq, + mlx4_msi_x_interrupt, 0, eq_name, + priv->eq_table.eq + MLX4_EQ_ASYNC); + if (err) + goto err_out_unmap; - priv->eq_table.eq[i].have_irq = 1; - } + priv->eq_table.eq[MLX4_EQ_ASYNC].have_irq = 1; } else { snprintf(priv->eq_table.irq_names, MLX4_IRQNAME_SIZE, @@ -1269,36 +1251,38 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) err = request_irq(dev->persist->pdev->irq, mlx4_interrupt, IRQF_SHARED, priv->eq_table.irq_names, dev); if (err) - goto err_out_async; + goto err_out_unmap; priv->eq_table.have_irq = 1; } err = mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0, - priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); + priv->eq_table.eq[MLX4_EQ_ASYNC].eqn); if (err) mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n", - priv->eq_table.eq[dev->caps.num_comp_vectors].eqn, err); + priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err); - for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) - eq_set_ci(&priv->eq_table.eq[i], 1); + /* arm ASYNC eq */ + eq_set_ci(&priv->eq_table.eq[MLX4_EQ_ASYNC], 1); return 0; -err_out_async: - mlx4_free_eq(dev, &priv->eq_table.eq[dev->caps.num_comp_vectors]); - -err_out_comp: - i = dev->caps.num_comp_vectors - 1; - err_out_unmap: - while (i >= 0) { - mlx4_free_eq(dev, &priv->eq_table.eq[i]); - --i; + while (i >= 0) + mlx4_free_eq(dev, &priv->eq_table.eq[i--]); +#ifdef CONFIG_RFS_ACCEL + for (i = 1; i <= dev->caps.num_ports; i++) { + if (mlx4_priv(dev)->port[i].rmap) { + free_irq_cpu_rmap(mlx4_priv(dev)->port[i].rmap); + mlx4_priv(dev)->port[i].rmap = NULL; + } } +#endif + mlx4_free_irqs(dev); + +err_out_clr_int: if (!mlx4_is_slave(dev)) mlx4_unmap_clr_int(dev); - mlx4_free_irqs(dev); err_out_bitmap: mlx4_unmap_uar(dev); @@ -1316,11 +1300,19 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev) int i; mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 1, - priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); + priv->eq_table.eq[MLX4_EQ_ASYNC].eqn); +#ifdef CONFIG_RFS_ACCEL + for (i = 1; i <= dev->caps.num_ports; i++) { + if (mlx4_priv(dev)->port[i].rmap) { + free_irq_cpu_rmap(mlx4_priv(dev)->port[i].rmap); + mlx4_priv(dev)->port[i].rmap = NULL; + } + } +#endif mlx4_free_irqs(dev); - for (i = 0; i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) mlx4_free_eq(dev, &priv->eq_table.eq[i]); if (!mlx4_is_slave(dev)) @@ -1371,87 +1363,166 @@ int mlx4_test_interrupts(struct mlx4_dev *dev) /* Return to default */ mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0, - priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); + priv->eq_table.eq[MLX4_EQ_ASYNC].eqn); return err; } EXPORT_SYMBOL(mlx4_test_interrupts); -int mlx4_assign_eq(struct mlx4_dev *dev, char *name, struct cpu_rmap *rmap, - int *vector) +bool mlx4_is_eq_vector_valid(struct mlx4_dev *dev, u8 port, int vector) { + struct mlx4_priv *priv = mlx4_priv(dev); + vector = MLX4_CQ_TO_EQ_VECTOR(vector); + if (vector < 0 || (vector >= dev->caps.num_comp_vectors + 1) || + (vector == MLX4_EQ_ASYNC)) + return false; + + return test_bit(port - 1, priv->eq_table.eq[vector].actv_ports.ports); +} +EXPORT_SYMBOL(mlx4_is_eq_vector_valid); + +u32 mlx4_get_eqs_per_port(struct mlx4_dev *dev, u8 port) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + unsigned int i; + unsigned int sum = 0; + + for (i = 0; i < dev->caps.num_comp_vectors + 1; i++) + sum += !!test_bit(port - 1, + priv->eq_table.eq[i].actv_ports.ports); + + return sum; +} +EXPORT_SYMBOL(mlx4_get_eqs_per_port); + +int mlx4_is_eq_shared(struct mlx4_dev *dev, int vector) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + vector = MLX4_CQ_TO_EQ_VECTOR(vector); + if (vector <= 0 || (vector >= dev->caps.num_comp_vectors + 1)) + return -EINVAL; + + return !!(bitmap_weight(priv->eq_table.eq[vector].actv_ports.ports, + dev->caps.num_ports) > 1); +} +EXPORT_SYMBOL(mlx4_is_eq_shared); + +struct cpu_rmap *mlx4_get_cpu_rmap(struct mlx4_dev *dev, int port) +{ + return mlx4_priv(dev)->port[port].rmap; +} +EXPORT_SYMBOL(mlx4_get_cpu_rmap); + +int mlx4_assign_eq(struct mlx4_dev *dev, u8 port, int *vector) +{ struct mlx4_priv *priv = mlx4_priv(dev); - int vec = 0, err = 0, i; + int err = 0, i = 0; + u32 min_ref_count_val = (u32)-1; + int requested_vector = MLX4_CQ_TO_EQ_VECTOR(*vector); + int *prequested_vector = NULL; + mutex_lock(&priv->msix_ctl.pool_lock); - for (i = 0; !vec && i < dev->caps.comp_pool; i++) { - if (~priv->msix_ctl.pool_bm & 1ULL << i) { - priv->msix_ctl.pool_bm |= 1ULL << i; - vec = dev->caps.num_comp_vectors + 1 + i; - snprintf(priv->eq_table.irq_names + - vec * MLX4_IRQNAME_SIZE, - MLX4_IRQNAME_SIZE, "%s", name); -#ifdef CONFIG_RFS_ACCEL - if (rmap) { - err = irq_cpu_rmap_add(rmap, - priv->eq_table.eq[vec].irq); - if (err) - mlx4_warn(dev, "Failed adding irq rmap\n"); + if (requested_vector < (dev->caps.num_comp_vectors + 1) && + (requested_vector >= 0) && + (requested_vector != MLX4_EQ_ASYNC)) { + if (test_bit(port - 1, + priv->eq_table.eq[requested_vector].actv_ports.ports)) { + prequested_vector = &requested_vector; + } else { + struct mlx4_eq *eq; + + for (i = 1; i < port; + requested_vector += mlx4_get_eqs_per_port(dev, i++)) + ; + + eq = &priv->eq_table.eq[requested_vector]; + if (requested_vector < dev->caps.num_comp_vectors + 1 && + test_bit(port - 1, eq->actv_ports.ports)) { + prequested_vector = &requested_vector; } -#endif - err = request_irq(priv->eq_table.eq[vec].irq, - mlx4_msi_x_interrupt, 0, - &priv->eq_table.irq_names[vec<<5], - priv->eq_table.eq + vec); - if (err) { - /*zero out bit by fliping it*/ - priv->msix_ctl.pool_bm ^= 1 << i; - vec = 0; - continue; - /*we dont want to break here*/ + } + } + + if (!prequested_vector) { + requested_vector = -1; + for (i = 0; min_ref_count_val && i < dev->caps.num_comp_vectors + 1; + i++) { + struct mlx4_eq *eq = &priv->eq_table.eq[i]; + + if (min_ref_count_val > eq->ref_count && + test_bit(port - 1, eq->actv_ports.ports)) { + min_ref_count_val = eq->ref_count; + requested_vector = i; } + } - eq_set_ci(&priv->eq_table.eq[vec], 1); + if (requested_vector < 0) { + err = -ENOSPC; + goto err_unlock; } + + prequested_vector = &requested_vector; } + + if (!test_bit(*prequested_vector, priv->msix_ctl.pool_bm) && + dev->flags & MLX4_FLAG_MSI_X) { + set_bit(*prequested_vector, priv->msix_ctl.pool_bm); + snprintf(priv->eq_table.irq_names + + *prequested_vector * MLX4_IRQNAME_SIZE, + MLX4_IRQNAME_SIZE, "mlx4-%d@%s", + *prequested_vector, dev_name(&dev->persist->pdev->dev)); + + err = request_irq(priv->eq_table.eq[*prequested_vector].irq, + mlx4_msi_x_interrupt, 0, + &priv->eq_table.irq_names[*prequested_vector << 5], + priv->eq_table.eq + *prequested_vector); + + if (err) { + clear_bit(*prequested_vector, priv->msix_ctl.pool_bm); + *prequested_vector = -1; + } else { + eq_set_ci(&priv->eq_table.eq[*prequested_vector], 1); + priv->eq_table.eq[*prequested_vector].have_irq = 1; + } + } + + if (!err && *prequested_vector >= 0) + priv->eq_table.eq[*prequested_vector].ref_count++; + +err_unlock: mutex_unlock(&priv->msix_ctl.pool_lock); - if (vec) { - *vector = vec; - } else { + if (!err && *prequested_vector >= 0) + *vector = MLX4_EQ_TO_CQ_VECTOR(*prequested_vector); + else *vector = 0; - err = (i == dev->caps.comp_pool) ? -ENOSPC : err; - } + return err; } EXPORT_SYMBOL(mlx4_assign_eq); -int mlx4_eq_get_irq(struct mlx4_dev *dev, int vec) +int mlx4_eq_get_irq(struct mlx4_dev *dev, int cq_vec) { struct mlx4_priv *priv = mlx4_priv(dev); - return priv->eq_table.eq[vec].irq; + return priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(cq_vec)].irq; } EXPORT_SYMBOL(mlx4_eq_get_irq); void mlx4_release_eq(struct mlx4_dev *dev, int vec) { struct mlx4_priv *priv = mlx4_priv(dev); - /*bm index*/ - int i = vec - dev->caps.num_comp_vectors - 1; - - if (likely(i >= 0)) { - /*sanity check , making sure were not trying to free irq's - Belonging to a legacy EQ*/ - mutex_lock(&priv->msix_ctl.pool_lock); - if (priv->msix_ctl.pool_bm & 1ULL << i) { - free_irq(priv->eq_table.eq[vec].irq, - &priv->eq_table.eq[vec]); - priv->msix_ctl.pool_bm &= ~(1ULL << i); - } - mutex_unlock(&priv->msix_ctl.pool_lock); - } + int eq_vec = MLX4_CQ_TO_EQ_VECTOR(vec); + + mutex_lock(&priv->msix_ctl.pool_lock); + priv->eq_table.eq[eq_vec].ref_count--; + /* once we allocated EQ, we don't release it because it might be binded + * to cpu_rmap. + */ + mutex_unlock(&priv->msix_ctl.pool_lock); } EXPORT_SYMBOL(mlx4_release_eq); diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 70d33f6e2a41..3ec5113c5a33 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2364,11 +2364,11 @@ static int mlx4_setup_hca(struct mlx4_dev *dev) if (err) { if (dev->flags & MLX4_FLAG_MSI_X) { mlx4_warn(dev, "NOP command failed to generate MSI-X interrupt IRQ %d)\n", - priv->eq_table.eq[dev->caps.num_comp_vectors].irq); + priv->eq_table.eq[MLX4_EQ_ASYNC].irq); mlx4_warn(dev, "Trying again without MSI-X\n"); } else { mlx4_err(dev, "NOP command failed to generate interrupt (IRQ %d), aborting\n", - priv->eq_table.eq[dev->caps.num_comp_vectors].irq); + priv->eq_table.eq[MLX4_EQ_ASYNC].irq); mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n"); } @@ -2486,9 +2486,10 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); struct msix_entry *entries; int i; + int port = 0; if (msi_x) { - int nreq = dev->caps.num_ports * num_online_cpus() + MSIX_LEGACY_SZ; + int nreq = dev->caps.num_ports * num_online_cpus() + 1; nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, nreq); @@ -2503,20 +2504,49 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) nreq = pci_enable_msix_range(dev->persist->pdev, entries, 2, nreq); - if (nreq < 0) { + if (nreq < 0 || nreq < MLX4_EQ_ASYNC) { kfree(entries); goto no_msi; - } else if (nreq < MSIX_LEGACY_SZ + - dev->caps.num_ports * MIN_MSIX_P_PORT) { - /*Working in legacy mode , all EQ's shared*/ - dev->caps.comp_pool = 0; - dev->caps.num_comp_vectors = nreq - 1; - } else { - dev->caps.comp_pool = nreq - MSIX_LEGACY_SZ; - dev->caps.num_comp_vectors = MSIX_LEGACY_SZ - 1; } - for (i = 0; i < nreq; ++i) - priv->eq_table.eq[i].irq = entries[i].vector; + /* 1 is reserved for events (asyncrounous EQ) */ + dev->caps.num_comp_vectors = nreq - 1; + + priv->eq_table.eq[MLX4_EQ_ASYNC].irq = entries[0].vector; + bitmap_zero(priv->eq_table.eq[MLX4_EQ_ASYNC].actv_ports.ports, + dev->caps.num_ports); + + for (i = 0; i < dev->caps.num_comp_vectors + 1; i++) { + if (i == MLX4_EQ_ASYNC) + continue; + + priv->eq_table.eq[i].irq = + entries[i + 1 - !!(i > MLX4_EQ_ASYNC)].vector; + + if (MLX4_IS_LEGACY_EQ_MODE(dev->caps)) { + bitmap_fill(priv->eq_table.eq[i].actv_ports.ports, + dev->caps.num_ports); + } else { + set_bit(port, + priv->eq_table.eq[i].actv_ports.ports); + } + /* We divide the Eqs evenly between the two ports. + * (dev->caps.num_comp_vectors / dev->caps.num_ports) + * refers to the number of Eqs per port + * (i.e eqs_per_port). Theoretically, we would like to + * write something like (i + 1) % eqs_per_port == 0. + * However, since there's an asynchronous Eq, we have + * to skip over it by comparing this condition to + * !!((i + 1) > MLX4_EQ_ASYNC). + */ + if ((dev->caps.num_comp_vectors > dev->caps.num_ports) && + ((i + 1) % + (dev->caps.num_comp_vectors / dev->caps.num_ports)) == + !!((i + 1) > MLX4_EQ_ASYNC)) + /* If dev->caps.num_comp_vectors < dev->caps.num_ports, + * everything is shared anyway. + */ + port++; + } dev->flags |= MLX4_FLAG_MSI_X; @@ -2526,10 +2556,15 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) no_msi: dev->caps.num_comp_vectors = 1; - dev->caps.comp_pool = 0; - for (i = 0; i < 2; ++i) + BUG_ON(MLX4_EQ_ASYNC >= 2); + for (i = 0; i < 2; ++i) { priv->eq_table.eq[i].irq = dev->persist->pdev->irq; + if (i != MLX4_EQ_ASYNC) { + bitmap_fill(priv->eq_table.eq[i].actv_ports.ports, + dev->caps.num_ports); + } + } } static int mlx4_init_port_info(struct mlx4_dev *dev, int port) @@ -2594,6 +2629,10 @@ static void mlx4_cleanup_port_info(struct mlx4_port_info *info) device_remove_file(&info->dev->persist->pdev->dev, &info->port_attr); device_remove_file(&info->dev->persist->pdev->dev, &info->port_mtu_attr); +#ifdef CONFIG_RFS_ACCEL + free_irq_cpu_rmap(info->rmap); + info->rmap = NULL; +#endif } static int mlx4_init_steering(struct mlx4_dev *dev) @@ -3024,7 +3063,7 @@ slave_start: if (err) goto err_master_mfunc; - priv->msix_ctl.pool_bm = 0; + bitmap_zero(priv->msix_ctl.pool_bm, MAX_MSIX); mutex_init(&priv->msix_ctl.pool_lock); mlx4_enable_msi_x(dev); @@ -3046,7 +3085,6 @@ slave_start: !mlx4_is_mfunc(dev)) { dev->flags &= ~MLX4_FLAG_MSI_X; dev->caps.num_comp_vectors = 1; - dev->caps.comp_pool = 0; pci_disable_msix(pdev); err = mlx4_setup_hca(dev); } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 502d3dd2c888..ff40098eaf4c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -287,6 +287,12 @@ struct mlx4_icm_table { #define MLX4_CQE_SIZE_MASK_STRIDE 0x3 #define MLX4_EQE_SIZE_MASK_STRIDE 0x30 +#define MLX4_EQ_ASYNC 0 +#define MLX4_EQ_TO_CQ_VECTOR(vector) ((vector) - \ + !!((int)(vector) >= MLX4_EQ_ASYNC)) +#define MLX4_CQ_TO_EQ_VECTOR(vector) ((vector) + \ + !!((int)(vector) >= MLX4_EQ_ASYNC)) + /* * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits. */ @@ -391,6 +397,8 @@ struct mlx4_eq { struct mlx4_buf_list *page_list; struct mlx4_mtt mtt; struct mlx4_eq_tasklet tasklet_ctx; + struct mlx4_active_ports actv_ports; + u32 ref_count; }; struct mlx4_slave_eqe { @@ -808,6 +816,7 @@ struct mlx4_port_info { struct mlx4_vlan_table vlan_table; struct mlx4_roce_gid_table gid_table; int base_qpn; + struct cpu_rmap *rmap; }; struct mlx4_sense { @@ -818,7 +827,7 @@ struct mlx4_sense { }; struct mlx4_msix_ctl { - u64 pool_bm; + DECLARE_BITMAP(pool_bm, MAX_MSIX); struct mutex pool_lock; }; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index d021f079f181..edd8fd69ec9a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -338,7 +338,7 @@ struct mlx4_en_cq { struct napi_struct napi; int size; int buf_size; - unsigned vector; + int vector; enum cq_type is_tx; u16 moder_time; u16 moder_cnt; diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 83e80ab94500..ad31e476873f 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -46,8 +46,9 @@ #define MAX_MSIX_P_PORT 17 #define MAX_MSIX 64 -#define MSIX_LEGACY_SZ 4 #define MIN_MSIX_P_PORT 5 +#define MLX4_IS_LEGACY_EQ_MODE(dev_cap) ((dev_cap).num_comp_vectors < \ + (dev_cap).num_ports * MIN_MSIX_P_PORT) #define MLX4_MAX_100M_UNITS_VAL 255 /* * work around: can't set values @@ -528,7 +529,6 @@ struct mlx4_caps { int num_eqs; int reserved_eqs; int num_comp_vectors; - int comp_pool; int num_mpts; int max_fmr_maps; int num_mtts; @@ -1332,10 +1332,13 @@ void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr); int mlx4_SYNC_TPT(struct mlx4_dev *dev); int mlx4_test_interrupts(struct mlx4_dev *dev); -int mlx4_assign_eq(struct mlx4_dev *dev, char *name, struct cpu_rmap *rmap, - int *vector); +u32 mlx4_get_eqs_per_port(struct mlx4_dev *dev, u8 port); +bool mlx4_is_eq_vector_valid(struct mlx4_dev *dev, u8 port, int vector); +struct cpu_rmap *mlx4_get_cpu_rmap(struct mlx4_dev *dev, int port); +int mlx4_assign_eq(struct mlx4_dev *dev, u8 port, int *vector); void mlx4_release_eq(struct mlx4_dev *dev, int vec); +int mlx4_is_eq_shared(struct mlx4_dev *dev, int vector); int mlx4_eq_get_irq(struct mlx4_dev *dev, int vec); int mlx4_get_phys_port_id(struct mlx4_dev *dev); -- cgit v1.2.3 From abf2e7d6e2e315b32ee00067a69aaad2cf4e1b3f Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Thu, 28 May 2015 19:26:02 -0700 Subject: bpf: add missing rcu protection when releasing programs from prog_array Normally the program attachment place (like sockets, qdiscs) takes care of rcu protection and calls bpf_prog_put() after a grace period. The programs stored inside prog_array may not be attached anywhere, so prog_array needs to take care of preserving rcu protection. Otherwise bpf_tail_call() will race with bpf_prog_put(). To solve that introduce bpf_prog_put_rcu() helper function and use it in 3 places where unattached program can decrement refcnt: closing program fd, deleting/replacing program in prog_array. Fixes: 04fd61ab36ec ("bpf: allow bpf programs to tail-call other bpf programs") Reported-by: Martin Schwidefsky Signed-off-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/linux/bpf.h | 6 +++++- kernel/bpf/arraymap.c | 4 ++-- kernel/bpf/syscall.c | 19 ++++++++++++++++++- 3 files changed, 25 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 8821b9a8689e..5f520f5f087e 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -123,7 +123,10 @@ struct bpf_prog_aux { const struct bpf_verifier_ops *ops; struct bpf_map **used_maps; struct bpf_prog *prog; - struct work_struct work; + union { + struct work_struct work; + struct rcu_head rcu; + }; }; struct bpf_array { @@ -153,6 +156,7 @@ void bpf_register_map_type(struct bpf_map_type_list *tl); struct bpf_prog *bpf_prog_get(u32 ufd); void bpf_prog_put(struct bpf_prog *prog); +void bpf_prog_put_rcu(struct bpf_prog *prog); struct bpf_map *bpf_map_get(struct fd f); void bpf_map_put(struct bpf_map *map); diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 614bcd4c1d74..cb31229a6fa4 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -202,7 +202,7 @@ static int prog_array_map_update_elem(struct bpf_map *map, void *key, old_prog = xchg(array->prog + index, prog); if (old_prog) - bpf_prog_put(old_prog); + bpf_prog_put_rcu(old_prog); return 0; } @@ -218,7 +218,7 @@ static int prog_array_map_delete_elem(struct bpf_map *map, void *key) old_prog = xchg(array->prog + index, NULL); if (old_prog) { - bpf_prog_put(old_prog); + bpf_prog_put_rcu(old_prog); return 0; } else { return -ENOENT; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 98a69bd83069..a1b14d197a4f 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -432,6 +432,23 @@ static void free_used_maps(struct bpf_prog_aux *aux) kfree(aux->used_maps); } +static void __prog_put_rcu(struct rcu_head *rcu) +{ + struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu); + + free_used_maps(aux); + bpf_prog_free(aux->prog); +} + +/* version of bpf_prog_put() that is called after a grace period */ +void bpf_prog_put_rcu(struct bpf_prog *prog) +{ + if (atomic_dec_and_test(&prog->aux->refcnt)) { + prog->aux->prog = prog; + call_rcu(&prog->aux->rcu, __prog_put_rcu); + } +} + void bpf_prog_put(struct bpf_prog *prog) { if (atomic_dec_and_test(&prog->aux->refcnt)) { @@ -445,7 +462,7 @@ static int bpf_prog_release(struct inode *inode, struct file *filp) { struct bpf_prog *prog = filp->private_data; - bpf_prog_put(prog); + bpf_prog_put_rcu(prog); return 0; } -- cgit v1.2.3 From 17ca8cbf49be3aa94bb1c2b7ee6545fd70094eb4 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 29 May 2015 23:23:06 +0200 Subject: ebpf: allow bpf_ktime_get_ns_proto also for networking As this is already exported from tracing side via commit d9847d310ab4 ("tracing: Allow BPF programs to call bpf_ktime_get_ns()"), we might as well want to move it to the core, so also networking users can make use of it, e.g. to measure diffs for certain flows from ingress/egress. Signed-off-by: Daniel Borkmann Cc: Alexei Starovoitov Cc: Ingo Molnar Signed-off-by: David S. Miller --- include/linux/bpf.h | 1 + kernel/bpf/core.c | 1 + kernel/bpf/helpers.c | 13 +++++++++++++ kernel/trace/bpf_trace.c | 12 ------------ net/core/filter.c | 2 ++ 5 files changed, 17 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 5f520f5f087e..ca854e5bb2f7 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -186,5 +186,6 @@ extern const struct bpf_func_proto bpf_map_delete_elem_proto; extern const struct bpf_func_proto bpf_get_prandom_u32_proto; extern const struct bpf_func_proto bpf_get_smp_processor_id_proto; extern const struct bpf_func_proto bpf_tail_call_proto; +extern const struct bpf_func_proto bpf_ktime_get_ns_proto; #endif /* _LINUX_BPF_H */ diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index d44b25cbe460..4548422d5f6c 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -734,6 +734,7 @@ const struct bpf_func_proto bpf_map_delete_elem_proto __weak; const struct bpf_func_proto bpf_get_prandom_u32_proto __weak; const struct bpf_func_proto bpf_get_smp_processor_id_proto __weak; +const struct bpf_func_proto bpf_ktime_get_ns_proto __weak; /* To execute LD_ABS/LD_IND instructions __bpf_prog_run() may call * skb_copy_bits(), so provide a weak definition of it for NET-less config. diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index bd7f5988ed9c..b3aaabdf9a50 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -13,6 +13,7 @@ #include #include #include +#include /* If kernel subsystem is allowing eBPF programs to call this function, * inside its own verifier_ops->get_func_proto() callback it should return @@ -111,3 +112,15 @@ const struct bpf_func_proto bpf_get_smp_processor_id_proto = { .gpl_only = false, .ret_type = RET_INTEGER, }; + +static u64 bpf_ktime_get_ns(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) +{ + /* NMI safe access to clock monotonic */ + return ktime_get_mono_fast_ns(); +} + +const struct bpf_func_proto bpf_ktime_get_ns_proto = { + .func = bpf_ktime_get_ns, + .gpl_only = true, + .ret_type = RET_INTEGER, +}; diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 646445e41bd4..50c4015a8ad3 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -79,18 +79,6 @@ static const struct bpf_func_proto bpf_probe_read_proto = { .arg3_type = ARG_ANYTHING, }; -static u64 bpf_ktime_get_ns(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) -{ - /* NMI safe access to clock monotonic */ - return ktime_get_mono_fast_ns(); -} - -static const struct bpf_func_proto bpf_ktime_get_ns_proto = { - .func = bpf_ktime_get_ns, - .gpl_only = true, - .ret_type = RET_INTEGER, -}; - /* * limited trace_printk() * only %d %u %x %ld %lu %lx %lld %llu %llx %p conversion specifiers allowed diff --git a/net/core/filter.c b/net/core/filter.c index 2c30d6632d66..b78a010a957f 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1423,6 +1423,8 @@ sk_filter_func_proto(enum bpf_func_id func_id) return &bpf_get_smp_processor_id_proto; case BPF_FUNC_tail_call: return &bpf_tail_call_proto; + case BPF_FUNC_ktime_get_ns: + return &bpf_ktime_get_ns_proto; default: return NULL; } -- cgit v1.2.3 From a28c257c9eb0bd76a4adcac97c07e34044ec71fb Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Fri, 29 May 2015 17:28:07 -0400 Subject: net/rds: Declare SO_RDS_TRANSPORT and RDS_TRANS_* constants in uapi/linux/rds.h User space applications that desire to explicitly select the underlying transport for a PF_RDS socket may do so by using the SO_RDS_TRANSPORT socket option at the SOL_RDS level before bind(). The integer argument provided to the socket option would be one of the RDS_TRANS_* values, e.g., RDS_TRANS_TCP. This commit exports the constant values need by such applications via Signed-off-by: Sowmini Varadhan Signed-off-by: David S. Miller --- include/uapi/linux/rds.h | 10 ++++++++++ net/rds/rds.h | 5 ----- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/rds.h b/include/uapi/linux/rds.h index 91950950aa59..0f9265cb2a96 100644 --- a/include/uapi/linux/rds.h +++ b/include/uapi/linux/rds.h @@ -38,6 +38,8 @@ #define RDS_IB_ABI_VERSION 0x301 +#define SOL_RDS 276 + /* * setsockopt/getsockopt for SOL_RDS */ @@ -48,6 +50,14 @@ #define RDS_RECVERR 5 #define RDS_CONG_MONITOR 6 #define RDS_GET_MR_FOR_DEST 7 +#define SO_RDS_TRANSPORT 8 + +/* supported values for SO_RDS_TRANSPORT */ +#define RDS_TRANS_IB 0 +#define RDS_TRANS_IWARP 1 +#define RDS_TRANS_TCP 2 +#define RDS_TRANS_COUNT 3 +#define RDS_TRANS_NONE (~0) /* * Control message types for SOL_RDS. diff --git a/net/rds/rds.h b/net/rds/rds.h index 0d41155a2258..76db508f73a1 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -408,11 +408,6 @@ struct rds_notifier { * should try hard not to block. */ -#define RDS_TRANS_IB 0 -#define RDS_TRANS_IWARP 1 -#define RDS_TRANS_TCP 2 -#define RDS_TRANS_COUNT 3 - struct rds_transport { char t_name[TRANSNAMSIZ]; struct list_head t_item; -- cgit v1.2.3 From 9f950415e4e28e7cfae2e416b43e862e8101d996 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Fri, 29 May 2015 13:47:07 -0400 Subject: tcp: fix child sockets to use system default congestion control if not set Linux 3.17 and earlier are explicitly engineered so that if the app doesn't specifically request a CC module on a listener before the SYN arrives, then the child gets the system default CC when the connection is established. See tcp_init_congestion_control() in 3.17 or earlier, which says "if no choice made yet assign the current value set as default". The change ("net: tcp: assign tcp cong_ops when tcp sk is created") altered these semantics, so that children got their parent listener's congestion control even if the system default had changed after the listener was created. This commit returns to those original semantics from 3.17 and earlier, since they are the original semantics from 2007 in 4d4d3d1e8 ("[TCP]: Congestion control initialization."), and some Linux congestion control workflows depend on that. In summary, if a listener socket specifically sets TCP_CONGESTION to "x", or the route locks the CC module to "x", then the child gets "x". Otherwise the child gets current system default from net.ipv4.tcp_congestion_control. That's the behavior in 3.17 and earlier, and this commit restores that. Fixes: 55d8694fa82c ("net: tcp: assign tcp cong_ops when tcp sk is created") Cc: Florian Westphal Cc: Daniel Borkmann Cc: Glenn Judd Cc: Stephen Hemminger Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: Yuchung Cheng Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/net/inet_connection_sock.h | 3 ++- net/ipv4/tcp_cong.c | 5 ++++- net/ipv4/tcp_minisocks.c | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index 497bc14cdb85..0320bbb7d7b5 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -98,7 +98,8 @@ struct inet_connection_sock { const struct tcp_congestion_ops *icsk_ca_ops; const struct inet_connection_sock_af_ops *icsk_af_ops; unsigned int (*icsk_sync_mss)(struct sock *sk, u32 pmtu); - __u8 icsk_ca_state:7, + __u8 icsk_ca_state:6, + icsk_ca_setsockopt:1, icsk_ca_dst_locked:1; __u8 icsk_retransmits; __u8 icsk_pending; diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 7a5ae50c80c8..84be008c945c 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -187,6 +187,7 @@ static void tcp_reinit_congestion_control(struct sock *sk, tcp_cleanup_congestion_control(sk); icsk->icsk_ca_ops = ca; + icsk->icsk_ca_setsockopt = 1; if (sk->sk_state != TCP_CLOSE && icsk->icsk_ca_ops->init) icsk->icsk_ca_ops->init(sk); @@ -335,8 +336,10 @@ int tcp_set_congestion_control(struct sock *sk, const char *name) rcu_read_lock(); ca = __tcp_ca_find_autoload(name); /* No change asking for existing value */ - if (ca == icsk->icsk_ca_ops) + if (ca == icsk->icsk_ca_ops) { + icsk->icsk_ca_setsockopt = 1; goto out; + } if (!ca) err = -ENOENT; else if (!((ca->flags & TCP_CONG_NON_RESTRICTED) || diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index b5732a54f2ad..17e7339ee5ca 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -420,7 +420,10 @@ void tcp_ca_openreq_child(struct sock *sk, const struct dst_entry *dst) rcu_read_unlock(); } - if (!ca_got_dst && !try_module_get(icsk->icsk_ca_ops->owner)) + /* If no valid choice made yet, assign current system default ca. */ + if (!ca_got_dst && + (!icsk->icsk_ca_setsockopt || + !try_module_get(icsk->icsk_ca_ops->owner))) tcp_assign_congestion_control(sk); tcp_set_ca_state(sk, TCP_CA_Open); -- cgit v1.2.3 From 8a7b19d8b542b87bccc3eaaf81dcc90a5ca48aea Mon Sep 17 00:00:00 2001 From: Mikko Rapeli Date: Sat, 30 May 2015 17:39:25 +0200 Subject: include/uapi/linux/virtio_balloon.h: include linux/virtio_types.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes userspace compilation error: error: unknown type name ‘__virtio16’ __virtio16 tag; Signed-off-by: Mikko Rapeli Signed-off-by: Michael S. Tsirkin --- include/uapi/linux/virtio_balloon.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/uapi/linux/virtio_balloon.h b/include/uapi/linux/virtio_balloon.h index 984169a819ee..d7f1cbc3766c 100644 --- a/include/uapi/linux/virtio_balloon.h +++ b/include/uapi/linux/virtio_balloon.h @@ -26,6 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include +#include #include #include -- cgit v1.2.3 From bdef7de4b8d9be4cf7bf5aea977f827310ab3ff0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 1 Jun 2015 14:56:09 -0700 Subject: net: Add priority to packet_offload objects. When we scan a packet for GRO processing, we want to see the most common packet types in the front of the offload_base list. So add a priority field so we can handle this properly. IPv4/IPv6 get the highest priority with the implicit zero priority field. Next comes ethernet with a priority of 10, and then we have the MPLS types with a priority of 15. Suggested-by: Eric Dumazet Suggested-by: Toshiaki Makita Signed-off-by: David S. Miller --- include/linux/netdevice.h | 1 + net/core/dev.c | 8 ++++++-- net/ethernet/eth.c | 1 + net/mpls/mpls_gso.c | 2 ++ 4 files changed, 10 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 51f8d2f5dc3f..6f5f71ff5169 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1997,6 +1997,7 @@ struct offload_callbacks { struct packet_offload { __be16 type; /* This is really htons(ether_type). */ + u16 priority; struct offload_callbacks callbacks; struct list_head list; }; diff --git a/net/core/dev.c b/net/core/dev.c index 594163d0c6eb..0602e917a305 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -469,10 +469,14 @@ EXPORT_SYMBOL(dev_remove_pack); */ void dev_add_offload(struct packet_offload *po) { - struct list_head *head = &offload_base; + struct packet_offload *elem; spin_lock(&offload_lock); - list_add_rcu(&po->list, head); + list_for_each_entry(elem, &offload_base, list) { + if (po->priority < elem->priority) + break; + } + list_add_rcu(&po->list, elem->list.prev); spin_unlock(&offload_lock); } EXPORT_SYMBOL(dev_add_offload); diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index c3325bd2f3fb..7d0e239a6755 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -470,6 +470,7 @@ EXPORT_SYMBOL(eth_gro_complete); static struct packet_offload eth_packet_offload __read_mostly = { .type = cpu_to_be16(ETH_P_TEB), + .priority = 10, .callbacks = { .gro_receive = eth_gro_receive, .gro_complete = eth_gro_complete, diff --git a/net/mpls/mpls_gso.c b/net/mpls/mpls_gso.c index 809df534a720..0183b32da942 100644 --- a/net/mpls/mpls_gso.c +++ b/net/mpls/mpls_gso.c @@ -62,6 +62,7 @@ out: static struct packet_offload mpls_mc_offload __read_mostly = { .type = cpu_to_be16(ETH_P_MPLS_MC), + .priority = 15, .callbacks = { .gso_segment = mpls_gso_segment, }, @@ -69,6 +70,7 @@ static struct packet_offload mpls_mc_offload __read_mostly = { static struct packet_offload mpls_uc_offload __read_mostly = { .type = cpu_to_be16(ETH_P_MPLS_UC), + .priority = 15, .callbacks = { .gso_segment = mpls_gso_segment, }, -- cgit v1.2.3 From ccea74457bbdafe33dce8bffcb5cb183aeb5f2bb Mon Sep 17 00:00:00 2001 From: Neil McKee Date: Tue, 26 May 2015 20:59:43 -0700 Subject: openvswitch: include datapath actions with sampled-packet upcall to userspace If new optional attribute OVS_USERSPACE_ATTR_ACTIONS is added to an OVS_ACTION_ATTR_USERSPACE action, then include the datapath actions in the upcall. This Directly associates the sampled packet with the path it takes through the virtual switch. Path information currently includes mangling, encapsulation and decapsulation actions for tunneling protocols GRE, VXLAN, Geneve, MPLS and QinQ, but this extension requires no further changes to accommodate datapath actions that may be added in the future. Adding path information enhances visibility into complex virtual networks. Signed-off-by: Neil McKee Signed-off-by: David S. Miller --- include/uapi/linux/openvswitch.h | 4 ++++ net/openvswitch/actions.c | 23 +++++++++++++++-------- net/openvswitch/datapath.c | 18 ++++++++++++++++-- net/openvswitch/datapath.h | 2 ++ 4 files changed, 37 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index bbd49a0c46c7..1dab77601c21 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h @@ -153,6 +153,8 @@ enum ovs_packet_cmd { * flow key against the kernel's. * @OVS_PACKET_ATTR_ACTIONS: Contains actions for the packet. Used * for %OVS_PACKET_CMD_EXECUTE. It has nested %OVS_ACTION_ATTR_* attributes. + * Also used in upcall when %OVS_ACTION_ATTR_USERSPACE has optional + * %OVS_USERSPACE_ATTR_ACTIONS attribute. * @OVS_PACKET_ATTR_USERDATA: Present for an %OVS_PACKET_CMD_ACTION * notification if the %OVS_ACTION_ATTR_USERSPACE action specified an * %OVS_USERSPACE_ATTR_USERDATA attribute, with the same length and content @@ -528,6 +530,7 @@ enum ovs_sample_attr { * copied to the %OVS_PACKET_CMD_ACTION message as %OVS_PACKET_ATTR_USERDATA. * @OVS_USERSPACE_ATTR_EGRESS_TUN_PORT: If present, u32 output port to get * tunnel info. + * @OVS_USERSPACE_ATTR_ACTIONS: If present, send actions with upcall. */ enum ovs_userspace_attr { OVS_USERSPACE_ATTR_UNSPEC, @@ -535,6 +538,7 @@ enum ovs_userspace_attr { OVS_USERSPACE_ATTR_USERDATA, /* Optional user-specified cookie. */ OVS_USERSPACE_ATTR_EGRESS_TUN_PORT, /* Optional, u32 output port * to get tunnel info. */ + OVS_USERSPACE_ATTR_ACTIONS, /* Optional flag to get actions. */ __OVS_USERSPACE_ATTR_MAX }; diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index b491c1c296fe..8a8c0b8b4f63 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -608,17 +608,16 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port) } static int output_userspace(struct datapath *dp, struct sk_buff *skb, - struct sw_flow_key *key, const struct nlattr *attr) + struct sw_flow_key *key, const struct nlattr *attr, + const struct nlattr *actions, int actions_len) { struct ovs_tunnel_info info; struct dp_upcall_info upcall; const struct nlattr *a; int rem; + memset(&upcall, 0, sizeof(upcall)); upcall.cmd = OVS_PACKET_CMD_ACTION; - upcall.userdata = NULL; - upcall.portid = 0; - upcall.egress_tun_info = NULL; for (a = nla_data(attr), rem = nla_len(attr); rem > 0; a = nla_next(a, &rem)) { @@ -647,6 +646,13 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, break; } + case OVS_USERSPACE_ATTR_ACTIONS: { + /* Include actions. */ + upcall.actions = actions; + upcall.actions_len = actions_len; + break; + } + } /* End of switch. */ } @@ -654,7 +660,8 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, } static int sample(struct datapath *dp, struct sk_buff *skb, - struct sw_flow_key *key, const struct nlattr *attr) + struct sw_flow_key *key, const struct nlattr *attr, + const struct nlattr *actions, int actions_len) { const struct nlattr *acts_list = NULL; const struct nlattr *a; @@ -688,7 +695,7 @@ static int sample(struct datapath *dp, struct sk_buff *skb, */ if (likely(nla_type(a) == OVS_ACTION_ATTR_USERSPACE && nla_is_last(a, rem))) - return output_userspace(dp, skb, key, a); + return output_userspace(dp, skb, key, a, actions, actions_len); skb = skb_clone(skb, GFP_ATOMIC); if (!skb) @@ -872,7 +879,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, break; case OVS_ACTION_ATTR_USERSPACE: - output_userspace(dp, skb, key, a); + output_userspace(dp, skb, key, a, attr, len); break; case OVS_ACTION_ATTR_HASH: @@ -916,7 +923,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, break; case OVS_ACTION_ATTR_SAMPLE: - err = sample(dp, skb, key, a); + err = sample(dp, skb, key, a, attr, len); break; } diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 3b90461317ec..ff8c4a4c1609 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -272,10 +272,9 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key) struct dp_upcall_info upcall; int error; + memset(&upcall, 0, sizeof(upcall)); upcall.cmd = OVS_PACKET_CMD_MISS; - upcall.userdata = NULL; upcall.portid = ovs_vport_find_upcall_portid(p, skb); - upcall.egress_tun_info = NULL; error = ovs_dp_upcall(dp, skb, key, &upcall); if (unlikely(error)) kfree_skb(skb); @@ -397,6 +396,10 @@ static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info, if (upcall_info->egress_tun_info) size += nla_total_size(ovs_tun_key_attr_size()); + /* OVS_PACKET_ATTR_ACTIONS */ + if (upcall_info->actions_len) + size += nla_total_size(upcall_info->actions_len); + return size; } @@ -478,6 +481,17 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, nla_nest_end(user_skb, nla); } + if (upcall_info->actions_len) { + nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_ACTIONS); + err = ovs_nla_put_actions(upcall_info->actions, + upcall_info->actions_len, + user_skb); + if (!err) + nla_nest_end(user_skb, nla); + else + nla_nest_cancel(user_skb, nla); + } + /* Only reserve room for attribute header, packet data is added * in skb_zerocopy() */ if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) { diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index 4ec4a480b147..cd691e935e08 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h @@ -116,6 +116,8 @@ struct ovs_skb_cb { struct dp_upcall_info { const struct ovs_tunnel_info *egress_tun_info; const struct nlattr *userdata; + const struct nlattr *actions; + int actions_len; u32 portid; u8 cmd; }; -- cgit v1.2.3 From 66e5133f19e901a044fa5eaeeb6ecff4545839e5 Mon Sep 17 00:00:00 2001 From: Toshiaki Makita Date: Mon, 1 Jun 2015 21:55:06 +0900 Subject: vlan: Add GRO support for non hardware accelerated vlan Currently packets with non-hardware-accelerated vlan cannot be handled by GRO. This causes low performance for 802.1ad and stacked vlan, as their vlan tags are currently not stripped by hardware. This patch adds GRO support for non-hardware-accelerated vlan and improves receive performance of them. Test Environment: vlan device (.1Q) on vlan device (.1ad) on ixgbe (82599) Result: - Before $ netperf -t TCP_STREAM -H 192.168.20.2 -l 60 Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 87380 16384 16384 60.00 5233.17 Rx side CPU usage: %usr %sys %irq %soft %idle 0.27 58.03 0.00 41.70 0.00 - After $ netperf -t TCP_STREAM -H 192.168.20.2 -l 60 Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 87380 16384 16384 60.00 7586.85 Rx side CPU usage: %usr %sys %irq %soft %idle 0.50 25.83 0.00 59.53 14.14 [ Register VLAN offloads with priority 10 -DaveM ] Signed-off-by: Toshiaki Makita Signed-off-by: David S. Miller --- include/linux/if_vlan.h | 20 +++++++++++ net/8021q/vlan.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) (limited to 'include') diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index a40d29846ac2..67ce5bd3b56a 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -628,4 +628,24 @@ static inline netdev_features_t vlan_features_check(const struct sk_buff *skb, return features; } +/** + * compare_vlan_header - Compare two vlan headers + * @h1: Pointer to vlan header + * @h2: Pointer to vlan header + * + * Compare two vlan headers, returns 0 if equal. + * + * Please note that alignment of h1 & h2 are only guaranteed to be 16 bits. + */ +static inline unsigned long compare_vlan_header(const struct vlan_hdr *h1, + const struct vlan_hdr *h2) +{ +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + return *(u32 *)h1 ^ *(u32 *)h2; +#else + return ((__force u32)h1->h_vlan_TCI ^ (__force u32)h2->h_vlan_TCI) | + ((__force u32)h1->h_vlan_encapsulated_proto ^ + (__force u32)h2->h_vlan_encapsulated_proto); +#endif +} #endif /* !(_LINUX_IF_VLAN_H_) */ diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 59555f0f8fc8..d2cd9de4b724 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -618,6 +618,92 @@ out: return err; } +static struct sk_buff **vlan_gro_receive(struct sk_buff **head, + struct sk_buff *skb) +{ + struct sk_buff *p, **pp = NULL; + struct vlan_hdr *vhdr; + unsigned int hlen, off_vlan; + const struct packet_offload *ptype; + __be16 type; + int flush = 1; + + off_vlan = skb_gro_offset(skb); + hlen = off_vlan + sizeof(*vhdr); + vhdr = skb_gro_header_fast(skb, off_vlan); + if (skb_gro_header_hard(skb, hlen)) { + vhdr = skb_gro_header_slow(skb, hlen, off_vlan); + if (unlikely(!vhdr)) + goto out; + } + + type = vhdr->h_vlan_encapsulated_proto; + + rcu_read_lock(); + ptype = gro_find_receive_by_type(type); + if (!ptype) + goto out_unlock; + + flush = 0; + + for (p = *head; p; p = p->next) { + struct vlan_hdr *vhdr2; + + if (!NAPI_GRO_CB(p)->same_flow) + continue; + + vhdr2 = (struct vlan_hdr *)(p->data + off_vlan); + if (compare_vlan_header(vhdr, vhdr2)) + NAPI_GRO_CB(p)->same_flow = 0; + } + + skb_gro_pull(skb, sizeof(*vhdr)); + skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr)); + pp = ptype->callbacks.gro_receive(head, skb); + +out_unlock: + rcu_read_unlock(); +out: + NAPI_GRO_CB(skb)->flush |= flush; + + return pp; +} + +static int vlan_gro_complete(struct sk_buff *skb, int nhoff) +{ + struct vlan_hdr *vhdr = (struct vlan_hdr *)(skb->data + nhoff); + __be16 type = vhdr->h_vlan_encapsulated_proto; + struct packet_offload *ptype; + int err = -ENOENT; + + rcu_read_lock(); + ptype = gro_find_complete_by_type(type); + if (ptype) + err = ptype->callbacks.gro_complete(skb, nhoff + sizeof(*vhdr)); + + rcu_read_unlock(); + return err; +} + +static struct packet_offload vlan_packet_offloads[] __read_mostly = { + { + .type = cpu_to_be16(ETH_P_8021Q), + .priority = 10, + .callbacks = { + .gro_receive = vlan_gro_receive, + .gro_complete = vlan_gro_complete, + }, + }, + { + .type = cpu_to_be16(ETH_P_8021AD), + .priority = 10, + .callbacks = { + .gro_receive = vlan_gro_receive, + .gro_complete = vlan_gro_complete, + }, + }, +}; + static int __net_init vlan_init_net(struct net *net) { struct vlan_net *vn = net_generic(net, vlan_net_id); @@ -645,6 +731,7 @@ static struct pernet_operations vlan_net_ops = { static int __init vlan_proto_init(void) { int err; + unsigned int i; pr_info("%s v%s\n", vlan_fullname, vlan_version); @@ -668,6 +755,9 @@ static int __init vlan_proto_init(void) if (err < 0) goto err5; + for (i = 0; i < ARRAY_SIZE(vlan_packet_offloads); i++) + dev_add_offload(&vlan_packet_offloads[i]); + vlan_ioctl_set(vlan_ioctl_handler); return 0; @@ -685,7 +775,13 @@ err0: static void __exit vlan_cleanup_module(void) { + unsigned int i; + vlan_ioctl_set(NULL); + + for (i = 0; i < ARRAY_SIZE(vlan_packet_offloads); i++) + dev_remove_offload(&vlan_packet_offloads[i]); + vlan_netlink_fini(); unregister_netdevice_notifier(&vlan_notifier_block); -- cgit v1.2.3 From 8760ce58353c2099be35ead62a572ee2d1e83b5b Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 1 Jun 2015 15:51:34 -0400 Subject: geneve: allow user to specify TTL for tunnel frames Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/geneve.c | 18 ++++++++++++++---- include/uapi/linux/if_link.h | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index b7eafa4c1a67..1675dfdbfa70 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -44,7 +44,8 @@ struct geneve_dev { struct net *net; /* netns for packet i/o */ struct net_device *dev; /* netdev for geneve tunnel */ struct geneve_sock *sock; /* socket used for geneve tunnel */ - u8 vni[3]; /* virtual network ID for tunnel */ + u8 vni[3]; /* virtual network ID for tunnel */ + u8 ttl; /* TTL override */ struct sockaddr_in remote; /* IPv4 address for link partner */ struct list_head next; /* geneve's per namespace list */ }; @@ -184,7 +185,7 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) struct flowi4 fl4; int err; __be16 sport; - __u8 tos, ttl = 0; + __u8 tos, ttl; iip = ip_hdr(skb); @@ -207,11 +208,12 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) goto rt_tx_error; } - /* TODO: tos and ttl should be configurable */ + /* TODO: tos should be configurable */ tos = ip_tunnel_ecn_encap(0, iip, skb); - if (IN_MULTICAST(ntohl(fl4.daddr))) + ttl = geneve->ttl; + if (!ttl && IN_MULTICAST(ntohl(fl4.daddr))) ttl = 1; ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); @@ -297,6 +299,7 @@ static void geneve_setup(struct net_device *dev) static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = { [IFLA_GENEVE_ID] = { .type = NLA_U32 }, [IFLA_GENEVE_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) }, + [IFLA_GENEVE_TTL] = { .type = NLA_U8 }, }; static int geneve_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -364,6 +367,9 @@ static int geneve_newlink(struct net *net, struct net_device *dev, if (err) return err; + if (data[IFLA_GENEVE_TTL]) + geneve->ttl = nla_get_u8(data[IFLA_GENEVE_TTL]); + list_add(&geneve->next, &gn->geneve_list); hlist_add_head_rcu(&geneve->hlist, &gn->vni_list[hash]); @@ -386,6 +392,7 @@ static size_t geneve_get_size(const struct net_device *dev) { return nla_total_size(sizeof(__u32)) + /* IFLA_GENEVE_ID */ nla_total_size(sizeof(struct in_addr)) + /* IFLA_GENEVE_REMOTE */ + nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL */ 0; } @@ -402,6 +409,9 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev) geneve->remote.sin_addr.s_addr)) goto nla_put_failure; + if (nla_put_u8(skb, IFLA_GENEVE_TTL, geneve->ttl)) + goto nla_put_failure; + return 0; nla_put_failure: diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index afccc9393fef..a834f31db915 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -395,6 +395,7 @@ enum { IFLA_GENEVE_UNSPEC, IFLA_GENEVE_ID, IFLA_GENEVE_REMOTE, + IFLA_GENEVE_TTL, __IFLA_GENEVE_MAX }; #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) -- cgit v1.2.3 From d89511251f6519599b109dc6cda87a6ab314ed8c Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 1 Jun 2015 15:51:35 -0400 Subject: geneve: allow user to specify TOS info for tunnel frames Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/geneve.c | 18 ++++++++++++++---- include/uapi/linux/if_link.h | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 1675dfdbfa70..78d49d186e05 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -46,6 +46,7 @@ struct geneve_dev { struct geneve_sock *sock; /* socket used for geneve tunnel */ u8 vni[3]; /* virtual network ID for tunnel */ u8 ttl; /* TTL override */ + u8 tos; /* TOS override */ struct sockaddr_in remote; /* IPv4 address for link partner */ struct list_head next; /* geneve's per namespace list */ }; @@ -194,7 +195,12 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) /* TODO: port min/max limits should be configurable */ sport = udp_flow_src_port(dev_net(dev), skb, 0, 0, true); + tos = geneve->tos; + if (tos == 1) + tos = ip_tunnel_get_dsfield(iip, skb); + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_tos = RT_TOS(tos); fl4.daddr = geneve->remote.sin_addr.s_addr; rt = ip_route_output_key(geneve->net, &fl4); if (IS_ERR(rt)) { @@ -208,9 +214,7 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) goto rt_tx_error; } - /* TODO: tos should be configurable */ - - tos = ip_tunnel_ecn_encap(0, iip, skb); + tos = ip_tunnel_ecn_encap(tos, iip, skb); ttl = geneve->ttl; if (!ttl && IN_MULTICAST(ntohl(fl4.daddr))) @@ -300,6 +304,7 @@ static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = { [IFLA_GENEVE_ID] = { .type = NLA_U32 }, [IFLA_GENEVE_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) }, [IFLA_GENEVE_TTL] = { .type = NLA_U8 }, + [IFLA_GENEVE_TOS] = { .type = NLA_U8 }, }; static int geneve_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -370,6 +375,9 @@ static int geneve_newlink(struct net *net, struct net_device *dev, if (data[IFLA_GENEVE_TTL]) geneve->ttl = nla_get_u8(data[IFLA_GENEVE_TTL]); + if (data[IFLA_GENEVE_TOS]) + geneve->tos = nla_get_u8(data[IFLA_GENEVE_TOS]); + list_add(&geneve->next, &gn->geneve_list); hlist_add_head_rcu(&geneve->hlist, &gn->vni_list[hash]); @@ -393,6 +401,7 @@ static size_t geneve_get_size(const struct net_device *dev) return nla_total_size(sizeof(__u32)) + /* IFLA_GENEVE_ID */ nla_total_size(sizeof(struct in_addr)) + /* IFLA_GENEVE_REMOTE */ nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL */ + nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TOS */ 0; } @@ -409,7 +418,8 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev) geneve->remote.sin_addr.s_addr)) goto nla_put_failure; - if (nla_put_u8(skb, IFLA_GENEVE_TTL, geneve->ttl)) + if (nla_put_u8(skb, IFLA_GENEVE_TTL, geneve->ttl) || + nla_put_u8(skb, IFLA_GENEVE_TOS, geneve->tos)) goto nla_put_failure; return 0; diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index a834f31db915..1737b7a8272b 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -396,6 +396,7 @@ enum { IFLA_GENEVE_ID, IFLA_GENEVE_REMOTE, IFLA_GENEVE_TTL, + IFLA_GENEVE_TOS, __IFLA_GENEVE_MAX }; #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) -- cgit v1.2.3 From 2a10154abcb75ad0d7b6bfea6210ac743ec60897 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Tue, 2 Jun 2015 09:34:37 -0500 Subject: net: phy: dp83867: Add TI dp83867 phy Add support for the TI dp83867 Gigabit ethernet phy device. The DP83867 is a robust, low power, fully featured Physical Layer transceiver with integrated PMD sublayers to support 10BASE-T, 100BASE-TX and 1000BASE-T Ethernet protocols. Signed-off-by: Dan Murphy Signed-off-by: David S. Miller --- .../devicetree/bindings/net/ti,dp83867.txt | 19 ++ drivers/net/phy/Kconfig | 6 +- drivers/net/phy/Makefile | 1 + drivers/net/phy/dp83867.c | 239 +++++++++++++++++++++ include/dt-bindings/net/ti-dp83867.h | 45 ++++ 5 files changed, 309 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/net/ti,dp83867.txt create mode 100644 drivers/net/phy/dp83867.c create mode 100644 include/dt-bindings/net/ti-dp83867.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/net/ti,dp83867.txt b/Documentation/devicetree/bindings/net/ti,dp83867.txt new file mode 100644 index 000000000000..46bb67a222ea --- /dev/null +++ b/Documentation/devicetree/bindings/net/ti,dp83867.txt @@ -0,0 +1,19 @@ +* Texas Instruments - dp83867 Giga bit ethernet phy + +Required properties: + - reg - The ID number for the phy, usually a small integer + - ti,rx_int_delay - RGMII Recieve Clock Delay - see dt-bindings/net/ti-dp83867.h + for applicable values + - ti,tx_int_delay - RGMII Transmit Clock Delay - see dt-bindings/net/ti-dp83867.h + for applicable values + - ti,fifo_depth - Transmitt FIFO depth- see dt-bindings/net/ti-dp83867.h + for applicable values + +Example: + + ethernet-phy@0 { + reg = <0>; + ti,rx_int_delay = ; + ti,tx_int_delay = ; + ti,fifo_depth = ; + }; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 7c0cb87d1f2f..cf18940f4e84 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -112,6 +112,11 @@ config MICREL_PHY ---help--- Supports the KSZ9021, VSC8201, KS8001 PHYs. +config DP83867_PHY + tristate "Drivers for Texas Instruments DP83867 Gigabit PHY" + ---help--- + Currently supports the DP83867 PHY. + config FIXED_PHY tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" depends on PHYLIB @@ -205,7 +210,6 @@ config MDIO_BCM_UNIMAC This hardware can be found in the Broadcom GENET Ethernet MAC controllers as well as some Broadcom Ethernet switches such as the Starfighter 2 switches. - endif # PHYLIB config MICREL_KS8995MA diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index e97e7f921862..fcc25a0c45cd 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o obj-$(CONFIG_NATIONAL_PHY) += national.o obj-$(CONFIG_DP83640_PHY) += dp83640.o +obj-$(CONFIG_DP83867_PHY) += dp83867.o obj-$(CONFIG_STE10XP) += ste10Xp.o obj-$(CONFIG_MICREL_PHY) += micrel.o obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c new file mode 100644 index 000000000000..ef0b4eb15f8d --- /dev/null +++ b/drivers/net/phy/dp83867.c @@ -0,0 +1,239 @@ +/* + * Driver for the Texas Instruments DP83867 PHY + * + * Copyright (C) 2015 Texas Instruments Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define DP83867_PHY_ID 0x2000a231 +#define DP83867_DEVADDR 0x1f + +#define MII_DP83867_PHYCTRL 0x10 +#define MII_DP83867_MICR 0x12 +#define MII_DP83867_ISR 0x13 +#define DP83867_CTRL 0x1f + +/* Extended Registers */ +#define DP83867_RGMIICTL 0x0032 +#define DP83867_RGMIIDCTL 0x0086 + +#define DP83867_SW_RESET BIT(15) +#define DP83867_SW_RESTART BIT(14) + +/* MICR Interrupt bits */ +#define MII_DP83867_MICR_AN_ERR_INT_EN BIT(15) +#define MII_DP83867_MICR_SPEED_CHNG_INT_EN BIT(14) +#define MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN BIT(13) +#define MII_DP83867_MICR_PAGE_RXD_INT_EN BIT(12) +#define MII_DP83867_MICR_AUTONEG_COMP_INT_EN BIT(11) +#define MII_DP83867_MICR_LINK_STS_CHNG_INT_EN BIT(10) +#define MII_DP83867_MICR_FALSE_CARRIER_INT_EN BIT(8) +#define MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN BIT(4) +#define MII_DP83867_MICR_WOL_INT_EN BIT(3) +#define MII_DP83867_MICR_XGMII_ERR_INT_EN BIT(2) +#define MII_DP83867_MICR_POL_CHNG_INT_EN BIT(1) +#define MII_DP83867_MICR_JABBER_INT_EN BIT(0) + +/* RGMIICTL bits */ +#define DP83867_RGMII_TX_CLK_DELAY_EN BIT(1) +#define DP83867_RGMII_RX_CLK_DELAY_EN BIT(0) + +/* PHY CTRL bits */ +#define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14 + +/* RGMIIDCTL bits */ +#define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4 + +struct dp83867_private { + int rx_id_delay; + int tx_id_delay; + int fifo_depth; +}; + +static int dp83867_ack_interrupt(struct phy_device *phydev) +{ + int err = phy_read(phydev, MII_DP83867_ISR); + + if (err < 0) + return err; + + return 0; +} + +static int dp83867_config_intr(struct phy_device *phydev) +{ + int micr_status; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + micr_status = phy_read(phydev, MII_DP83867_MICR); + if (micr_status < 0) + return micr_status; + + micr_status |= + (MII_DP83867_MICR_AN_ERR_INT_EN | + MII_DP83867_MICR_SPEED_CHNG_INT_EN | + MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN | + MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN); + + return phy_write(phydev, MII_DP83867_MICR, micr_status); + } + + micr_status = 0x0; + return phy_write(phydev, MII_DP83867_MICR, micr_status); +} + +#ifdef CONFIG_OF_MDIO +static int dp83867_of_init(struct phy_device *phydev) +{ + struct dp83867_private *dp83867 = phydev->priv; + struct device *dev = &phydev->dev; + struct device_node *of_node = dev->of_node; + int ret; + + if (!of_node && dev->parent->of_node) + of_node = dev->parent->of_node; + + if (!phydev->dev.of_node) + return -ENODEV; + + ret = of_property_read_u32(of_node, "ti,rx_int_delay", + &dp83867->rx_id_delay); + if (ret) + return ret; + + ret = of_property_read_u32(of_node, "ti,tx_int_delay", + &dp83867->tx_id_delay); + if (ret) + return ret; + + ret = of_property_read_u32(of_node, "ti,fifo_depth", + &dp83867->fifo_depth); + if (ret) + return ret; + + return 0; +} +#else +static int dp83867_of_init(struct phy_device *phydev) +{ + return 0; +} +#endif /* CONFIG_OF_MDIO */ + +static int dp83867_config_init(struct phy_device *phydev) +{ + struct dp83867_private *dp83867; + int ret; + u16 val, delay; + + if (!phydev->priv) { + dp83867 = devm_kzalloc(&phydev->dev, sizeof(*dp83867), + GFP_KERNEL); + if (!dp83867) + return -ENOMEM; + + phydev->priv = dp83867; + ret = dp83867_of_init(phydev); + if (ret) + return ret; + } else { + dp83867 = (struct dp83867_private *)phydev->priv; + } + + if (phy_interface_is_rgmii(phydev)) { + ret = phy_write(phydev, MII_DP83867_PHYCTRL, + (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT)); + if (ret) + return ret; + } + + if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) || + (phydev->interface <= PHY_INTERFACE_MODE_RGMII_RXID)) { + val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL, + DP83867_DEVADDR, phydev->addr); + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + val |= (DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN); + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + val |= DP83867_RGMII_TX_CLK_DELAY_EN; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) + val |= DP83867_RGMII_RX_CLK_DELAY_EN; + + phy_write_mmd_indirect(phydev, DP83867_RGMIICTL, + DP83867_DEVADDR, phydev->addr, val); + + delay = (dp83867->rx_id_delay | + (dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT)); + + phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL, + DP83867_DEVADDR, phydev->addr, delay); + } + + return 0; +} + +static int dp83867_phy_reset(struct phy_device *phydev) +{ + int err; + + err = phy_write(phydev, DP83867_CTRL, DP83867_SW_RESET); + if (err < 0) + return err; + + return dp83867_config_init(phydev); +} + +static struct phy_driver dp83867_driver[] = { + { + .phy_id = DP83867_PHY_ID, + .phy_id_mask = 0xfffffff0, + .name = "TI DP83867", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + + .config_init = dp83867_config_init, + .soft_reset = dp83867_phy_reset, + + /* IRQ related */ + .ack_interrupt = dp83867_ack_interrupt, + .config_intr = dp83867_config_intr, + + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, + + .driver = {.owner = THIS_MODULE,} + }, +}; +module_phy_driver(dp83867_driver); + +static struct mdio_device_id __maybe_unused dp83867_tbl[] = { + { DP83867_PHY_ID, 0xfffffff0 }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, dp83867_tbl); + +MODULE_DESCRIPTION("Texas Instruments DP83867 PHY driver"); +MODULE_AUTHOR("Dan Murphy + * + * Copyright: (C) 2015 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _DT_BINDINGS_TI_DP83867_H +#define _DT_BINDINGS_TI_DP83867_H + +/* PHY CTRL bits */ +#define DP83867_PHYCR_FIFO_DEPTH_3_B_NIB 0x00 +#define DP83867_PHYCR_FIFO_DEPTH_4_B_NIB 0x01 +#define DP83867_PHYCR_FIFO_DEPTH_6_B_NIB 0x02 +#define DP83867_PHYCR_FIFO_DEPTH_8_B_NIB 0x03 + +/* RGMIIDCTL internal delay for rx and tx */ +#define DP83867_RGMIIDCTL_250_PS 0x0 +#define DP83867_RGMIIDCTL_500_PS 0x1 +#define DP83867_RGMIIDCTL_750_PS 0x2 +#define DP83867_RGMIIDCTL_1_NS 0x3 +#define DP83867_RGMIIDCTL_1_25_NS 0x4 +#define DP83867_RGMIIDCTL_1_50_NS 0x5 +#define DP83867_RGMIIDCTL_1_75_NS 0x6 +#define DP83867_RGMIIDCTL_2_00_NS 0x7 +#define DP83867_RGMIIDCTL_2_25_NS 0x8 +#define DP83867_RGMIIDCTL_2_50_NS 0x9 +#define DP83867_RGMIIDCTL_2_75_NS 0xa +#define DP83867_RGMIIDCTL_3_00_NS 0xb +#define DP83867_RGMIIDCTL_3_25_NS 0xc +#define DP83867_RGMIIDCTL_3_50_NS 0xd +#define DP83867_RGMIIDCTL_3_75_NS 0xe +#define DP83867_RGMIIDCTL_4_00_NS 0xf + +#endif -- cgit v1.2.3 From 3896d655f4d491c67d669a15f275a39f713410f8 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 2 Jun 2015 16:03:14 -0700 Subject: bpf: introduce bpf_clone_redirect() helper Allow eBPF programs attached to classifier/actions to call bpf_clone_redirect(skb, ifindex, flags) helper which will mirror or redirect the packet by dynamic ifindex selection from within the program to a target device either at ingress or at egress. Can be used for various scenarios, for example, to load balance skbs into veths, split parts of the traffic to local taps, etc. Signed-off-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/uapi/linux/bpf.h | 10 ++++++++++ net/core/filter.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 72f3080afa1e..42aa19abab86 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -220,6 +220,16 @@ enum bpf_func_id { * Return: 0 on success */ BPF_FUNC_tail_call, + + /** + * bpf_clone_redirect(skb, ifindex, flags) - redirect to another netdev + * @skb: pointer to skb + * @ifindex: ifindex of the net device + * @flags: bit 0 - if set, redirect to ingress instead of egress + * other bits - reserved + * Return: 0 on success + */ + BPF_FUNC_clone_redirect, __BPF_FUNC_MAX_ID, }; diff --git a/net/core/filter.c b/net/core/filter.c index b78a010a957f..64c121c09655 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -46,6 +46,7 @@ #include #include #include +#include /** * sk_filter - run a packet through a socket filter @@ -1407,6 +1408,43 @@ const struct bpf_func_proto bpf_l4_csum_replace_proto = { .arg5_type = ARG_ANYTHING, }; +#define BPF_IS_REDIRECT_INGRESS(flags) ((flags) & 1) + +static u64 bpf_clone_redirect(u64 r1, u64 ifindex, u64 flags, u64 r4, u64 r5) +{ + struct sk_buff *skb = (struct sk_buff *) (long) r1, *skb2; + struct net_device *dev; + + dev = dev_get_by_index_rcu(dev_net(skb->dev), ifindex); + if (unlikely(!dev)) + return -EINVAL; + + if (unlikely(!(dev->flags & IFF_UP))) + return -EINVAL; + + skb2 = skb_clone(skb, GFP_ATOMIC); + if (unlikely(!skb2)) + return -ENOMEM; + + if (G_TC_AT(skb2->tc_verd) & AT_INGRESS) + skb_push(skb2, skb2->mac_len); + + if (BPF_IS_REDIRECT_INGRESS(flags)) + return dev_forward_skb(dev, skb2); + + skb2->dev = dev; + return dev_queue_xmit(skb2); +} + +const struct bpf_func_proto bpf_clone_redirect_proto = { + .func = bpf_clone_redirect, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_ANYTHING, +}; + static const struct bpf_func_proto * sk_filter_func_proto(enum bpf_func_id func_id) { @@ -1440,6 +1478,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id) return &bpf_l3_csum_replace_proto; case BPF_FUNC_l4_csum_replace: return &bpf_l4_csum_replace_proto; + case BPF_FUNC_clone_redirect: + return &bpf_clone_redirect_proto; default: return sk_filter_func_proto(func_id); } -- cgit v1.2.3 From 730fc4371333636a00fed32c587fc1e85c5367e2 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Jun 2015 09:16:37 -0700 Subject: mpls: Add definition for IPPROTO_MPLS Add uapi define for MPLS over IP. Acked-by: Jiri Pirko Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/uapi/linux/in.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h index 589ced069e8a..641338bef651 100644 --- a/include/uapi/linux/in.h +++ b/include/uapi/linux/in.h @@ -69,6 +69,8 @@ enum { #define IPPROTO_SCTP IPPROTO_SCTP IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */ #define IPPROTO_UDPLITE IPPROTO_UDPLITE + IPPROTO_MPLS = 137, /* MPLS in IP (RFC 4023) */ +#define IPPROTO_MPLS IPPROTO_MPLS IPPROTO_RAW = 255, /* Raw IP packets */ #define IPPROTO_RAW IPPROTO_RAW IPPROTO_MAX -- cgit v1.2.3 From 42aecaa9bb2bd57eb8d61b4565cee5d3640863fb Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Jun 2015 09:16:39 -0700 Subject: net: Get skb hash over flow_keys structure This patch changes flow hashing to use jhash2 over the flow_keys structure instead just doing jhash_3words over src, dst, and ports. This method will allow us take more input into the hashing function so that we can include full IPv6 addresses, VLAN, flow labels etc. without needing to resort to xor'ing which makes for a poor hash. Acked-by: Jiri Pirko Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/skbuff.h | 2 +- include/net/flow_dissector.h | 21 ++++++++++++++--- include/net/ip.h | 2 ++ include/net/ipv6.h | 2 ++ net/core/flow_dissector.c | 54 +++++++++++++++++++++++++++++++++----------- net/sched/cls_flower.c | 2 ++ 6 files changed, 66 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 6b41c15efa27..cc612fc0a894 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1943,7 +1943,7 @@ static inline void skb_probe_transport_header(struct sk_buff *skb, if (skb_transport_header_was_set(skb)) return; else if (skb_flow_dissect_flow_keys(skb, &keys)) - skb_set_transport_header(skb, keys.basic.thoff); + skb_set_transport_header(skb, keys.control.thoff); else skb_set_transport_header(skb, offset_hint); } diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index bac9c1421f58..cba6a10b214a 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -6,6 +6,15 @@ #include #include +/** + * struct flow_dissector_key_control: + * @thoff: Transport header offset + */ +struct flow_dissector_key_control { + u16 thoff; + u16 padding; +}; + /** * struct flow_dissector_key_basic: * @thoff: Transport header offset @@ -13,9 +22,9 @@ * @ip_proto: Transport header protocol (eg. TCP/UDP) */ struct flow_dissector_key_basic { - u16 thoff; __be16 n_proto; u8 ip_proto; + u8 padding; }; /** @@ -70,6 +79,7 @@ struct flow_dissector_key_eth_addrs { }; enum flow_dissector_key_id { + FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */ FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ FLOW_DISSECTOR_KEY_IPV4_ADDRS, /* struct flow_dissector_key_addrs */ FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, /* struct flow_dissector_key_addrs */ @@ -109,11 +119,16 @@ static inline bool skb_flow_dissect(const struct sk_buff *skb, } struct flow_keys { - struct flow_dissector_key_addrs addrs; - struct flow_dissector_key_ports ports; + struct flow_dissector_key_control control; +#define FLOW_KEYS_HASH_START_FIELD basic struct flow_dissector_key_basic basic; + struct flow_dissector_key_ports ports; + struct flow_dissector_key_addrs addrs; }; +#define FLOW_KEYS_HASH_OFFSET \ + offsetof(struct flow_keys, FLOW_KEYS_HASH_START_FIELD) + extern struct flow_dissector flow_keys_dissector; extern struct flow_dissector flow_keys_buf_dissector; diff --git a/include/net/ip.h b/include/net/ip.h index 9b976cf99122..16cfc87fed6c 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -360,6 +360,8 @@ static inline void inet_set_txhash(struct sock *sk) struct inet_sock *inet = inet_sk(sk); struct flow_keys keys; + memset(&keys, 0, sizeof(keys)); + keys.addrs.src = inet->inet_saddr; keys.addrs.dst = inet->inet_daddr; keys.ports.src = inet->inet_sport; diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 35d485c78080..474ca466a091 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -699,6 +699,8 @@ static inline void ip6_set_txhash(struct sock *sk) struct ipv6_pinfo *np = inet6_sk(sk); struct flow_keys keys; + memset(&keys, 0, sizeof(keys)); + keys.addrs.src = (__force __be32)ipv6_addr_hash(&np->saddr); keys.addrs.dst = (__force __be32)ipv6_addr_hash(&sk->sk_v6_daddr); keys.ports.src = inet->inet_sport; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 0763795bea8f..55b5f2962afa 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -57,9 +57,11 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector, flow_dissector->offset[key->key_id] = key->offset; } - /* Ensure that the dissector always includes basic key. That way - * we are able to avoid handling lack of it in fast path. + /* Ensure that the dissector always includes control and basic key. + * That way we are able to avoid handling lack of these in fast path. */ + BUG_ON(!skb_flow_dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_CONTROL)); BUG_ON(!skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_BASIC)); } @@ -120,6 +122,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, void *target_container, void *data, __be16 proto, int nhoff, int hlen) { + struct flow_dissector_key_control *key_control; struct flow_dissector_key_basic *key_basic; struct flow_dissector_key_addrs *key_addrs; struct flow_dissector_key_ports *key_ports; @@ -132,6 +135,13 @@ bool __skb_flow_dissect(const struct sk_buff *skb, hlen = skb_headlen(skb); } + /* It is ensured by skb_flow_dissector_init() that control key will + * be always present. + */ + key_control = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_CONTROL, + target_container); + /* It is ensured by skb_flow_dissector_init() that basic key will * be always present. */ @@ -219,7 +229,7 @@ flow_label: key_basic->n_proto = proto; key_basic->ip_proto = ip_proto; - key_basic->thoff = (u16)nhoff; + key_control->thoff = (u16)nhoff; if (skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS)) { @@ -275,7 +285,7 @@ flow_label: if (!hdr) return false; key_basic->n_proto = proto; - key_basic->thoff = (u16)nhoff; + key_control->thoff = (u16)nhoff; if (skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS)) { @@ -288,7 +298,7 @@ flow_label: return true; } case htons(ETH_P_FCOE): - key_basic->thoff = (u16)(nhoff + FCOE_HEADER_LEN); + key_control->thoff = (u16)(nhoff + FCOE_HEADER_LEN); /* fall through */ default: return false; @@ -345,7 +355,7 @@ flow_label: key_basic->n_proto = proto; key_basic->ip_proto = ip_proto; - key_basic->thoff = (u16) nhoff; + key_control->thoff = (u16)nhoff; if (skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS)) { @@ -366,9 +376,21 @@ static __always_inline void __flow_hash_secret_init(void) net_get_random_once(&hashrnd, sizeof(hashrnd)); } -static __always_inline u32 __flow_hash_3words(u32 a, u32 b, u32 c, u32 keyval) +static __always_inline u32 __flow_hash_words(u32 *words, u32 length, u32 keyval) +{ + return jhash2(words, length, keyval); +} + +static inline void *flow_keys_hash_start(struct flow_keys *flow) { - return jhash_3words(a, b, c, keyval); + BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % sizeof(u32)); + return (void *)flow + FLOW_KEYS_HASH_OFFSET; +} + +static inline size_t flow_keys_hash_length(struct flow_keys *flow) +{ + BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32)); + return (sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) / sizeof(u32); } static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) @@ -383,10 +405,8 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) swap(keys->ports.src, keys->ports.dst); } - hash = __flow_hash_3words((__force u32)keys->addrs.dst, - (__force u32)keys->addrs.src, - (__force u32)keys->ports.ports, - keyval); + hash = __flow_hash_words((u32 *)flow_keys_hash_start(keys), + flow_keys_hash_length(keys), keyval); if (!hash) hash = 1; @@ -473,7 +493,7 @@ EXPORT_SYMBOL(skb_get_hash_perturb); u32 __skb_get_poff(const struct sk_buff *skb, void *data, const struct flow_keys *keys, int hlen) { - u32 poff = keys->basic.thoff; + u32 poff = keys->control.thoff; switch (keys->basic.ip_proto) { case IPPROTO_TCP: { @@ -536,6 +556,10 @@ u32 skb_get_poff(const struct sk_buff *skb) } static const struct flow_dissector_key flow_keys_dissector_keys[] = { + { + .key_id = FLOW_DISSECTOR_KEY_CONTROL, + .offset = offsetof(struct flow_keys, control), + }, { .key_id = FLOW_DISSECTOR_KEY_BASIC, .offset = offsetof(struct flow_keys, basic), @@ -555,6 +579,10 @@ static const struct flow_dissector_key flow_keys_dissector_keys[] = { }; static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = { + { + .key_id = FLOW_DISSECTOR_KEY_CONTROL, + .offset = offsetof(struct flow_keys, control), + }, { .key_id = FLOW_DISSECTOR_KEY_BASIC, .offset = offsetof(struct flow_keys, basic), diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 8c8f34ef6980..5a7d66c59684 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -25,6 +25,7 @@ struct fl_flow_key { int indev_ifindex; + struct flow_dissector_key_control control; struct flow_dissector_key_basic basic; struct flow_dissector_key_eth_addrs eth; union { @@ -347,6 +348,7 @@ static void fl_init_dissector(struct cls_fl_head *head, struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX]; size_t cnt = 0; + FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control); FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic); FL_KEY_SET_IF_IN_RANGE(mask, keys, cnt, FLOW_DISSECTOR_KEY_ETH_ADDRS, eth); -- cgit v1.2.3 From c3f8324188fa80178f20c8209b492ca6191177e8 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Jun 2015 09:16:40 -0700 Subject: net: Add full IPv6 addresses to flow_keys This patch adds full IPv6 addresses into flow_keys and uses them as input to the flow hash function. The implementation supports either IPv4 or IPv6 addresses in a union, and selector is used to determine how may words to input to jhash2. We also add flow_get_u32_dst and flow_get_u32_src functions which are used to get a u32 representation of the source and destination addresses. For IPv6, ipv6_addr_hash is called. These functions retain getting the legacy values of src and dst in flow_keys. With this patch, Ethertype and IP protocol are now included in the flow hash input. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 9 +- drivers/net/ethernet/cisco/enic/enic_clsf.c | 8 +- drivers/net/ethernet/cisco/enic/enic_ethtool.c | 4 +- include/net/flow_dissector.h | 52 +++++++---- include/net/ip.h | 19 +++- include/net/ipv6.h | 21 ++++- net/core/flow_dissector.c | 116 +++++++++++++++++++++---- net/ethernet/eth.c | 2 +- net/sched/cls_flow.c | 14 ++- net/sched/cls_flower.c | 11 +-- 10 files changed, 193 insertions(+), 63 deletions(-) (limited to 'include') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2268438f3f63..19eb990d398c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3059,8 +3059,7 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph)))) return false; iph = ip_hdr(skb); - fk->addrs.src = iph->saddr; - fk->addrs.dst = iph->daddr; + iph_to_flow_copy_v4addrs(fk, iph); noff += iph->ihl << 2; if (!ip_is_fragment(iph)) proto = iph->protocol; @@ -3068,8 +3067,7 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph6)))) return false; iph6 = ipv6_hdr(skb); - fk->addrs.src = (__force __be32)ipv6_addr_hash(&iph6->saddr); - fk->addrs.dst = (__force __be32)ipv6_addr_hash(&iph6->daddr); + iph_to_flow_copy_v6addrs(fk, iph6); noff += sizeof(*iph6); proto = iph6->nexthdr; } else { @@ -3103,7 +3101,8 @@ u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb) hash = bond_eth_hash(skb); else hash = (__force u32)flow.ports.ports; - hash ^= (__force u32)flow.addrs.dst ^ (__force u32)flow.addrs.src; + hash ^= (__force u32)flow_get_u32_dst(&flow) ^ + (__force u32)flow_get_u32_src(&flow); hash ^= (hash >> 16); hash ^= (hash >> 8); diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index a31b57adcb37..d106186f4f4a 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -33,8 +33,8 @@ int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq) return -EPROTONOSUPPORT; }; data.type = FILTER_IPV4_5TUPLE; - data.u.ipv4.src_addr = ntohl(keys->addrs.src); - data.u.ipv4.dst_addr = ntohl(keys->addrs.dst); + data.u.ipv4.src_addr = ntohl(keys->addrs.v4addrs.src); + data.u.ipv4.dst_addr = ntohl(keys->addrs.v4addrs.dst); data.u.ipv4.src_port = ntohs(keys->ports.src); data.u.ipv4.dst_port = ntohs(keys->ports.dst); data.u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE; @@ -158,8 +158,8 @@ static struct enic_rfs_fltr_node *htbl_key_search(struct hlist_head *h, struct enic_rfs_fltr_node *tpos; hlist_for_each_entry(tpos, h, node) - if (tpos->keys.addrs.src == k->addrs.src && - tpos->keys.addrs.dst == k->addrs.dst && + if (tpos->keys.addrs.v4addrs.src == k->addrs.v4addrs.src && + tpos->keys.addrs.v4addrs.dst == k->addrs.v4addrs.dst && tpos->keys.ports.ports == k->ports.ports && tpos->keys.basic.ip_proto == k->basic.ip_proto && tpos->keys.basic.n_proto == k->basic.n_proto) diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c index 117c0968dd0b..73874b2575bf 100644 --- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c +++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c @@ -346,10 +346,10 @@ static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd) break; } - fsp->h_u.tcp_ip4_spec.ip4src = n->keys.addrs.src; + fsp->h_u.tcp_ip4_spec.ip4src = flow_get_u32_src(&n->keys); fsp->m_u.tcp_ip4_spec.ip4src = (__u32)~0; - fsp->h_u.tcp_ip4_spec.ip4dst = n->keys.addrs.dst; + fsp->h_u.tcp_ip4_spec.ip4dst = flow_get_u32_dst(&n->keys); fsp->m_u.tcp_ip4_spec.ip4dst = (__u32)~0; fsp->h_u.tcp_ip4_spec.psrc = n->keys.ports.src; diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index cba6a10b214a..306d4613abbb 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -12,7 +12,7 @@ */ struct flow_dissector_key_control { u16 thoff; - u16 padding; + u16 addr_type; }; /** @@ -28,18 +28,39 @@ struct flow_dissector_key_basic { }; /** - * struct flow_dissector_key_addrs: - * @src: source ip address in case of IPv4 - * For IPv6 it contains 32bit hash of src address - * @dst: destination ip address in case of IPv4 - * For IPv6 it contains 32bit hash of dst address + * struct flow_dissector_key_ipv4_addrs: + * @src: source ip address + * @dst: destination ip address */ -struct flow_dissector_key_addrs { +struct flow_dissector_key_ipv4_addrs { /* (src,dst) must be grouped, in the same way than in IP header */ __be32 src; __be32 dst; }; +/** + * struct flow_dissector_key_ipv6_addrs: + * @src: source ip address + * @dst: destination ip address + */ +struct flow_dissector_key_ipv6_addrs { + /* (src,dst) must be grouped, in the same way than in IP header */ + struct in6_addr src; + struct in6_addr dst; +}; + +/** + * struct flow_dissector_key_addrs: + * @v4addrs: IPv4 addresses + * @v6addrs: IPv6 addresses + */ +struct flow_dissector_key_addrs { + union { + struct flow_dissector_key_ipv4_addrs v4addrs; + struct flow_dissector_key_ipv6_addrs v6addrs; + }; +}; + /** * flow_dissector_key_tp_ports: * @ports: port numbers of Transport header @@ -56,16 +77,6 @@ struct flow_dissector_key_ports { }; }; -/** - * struct flow_dissector_key_ipv6_addrs: - * @src: source ip address - * @dst: destination ip address - */ -struct flow_dissector_key_ipv6_addrs { - /* (src,dst) must be grouped, in the same way than in IP header */ - struct in6_addr src; - struct in6_addr dst; -}; /** * struct flow_dissector_key_eth_addrs: @@ -81,10 +92,10 @@ struct flow_dissector_key_eth_addrs { enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */ FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ - FLOW_DISSECTOR_KEY_IPV4_ADDRS, /* struct flow_dissector_key_addrs */ + FLOW_DISSECTOR_KEY_IPV4_ADDRS, /* struct flow_dissector_key_ipv4_addrs */ + FLOW_DISSECTOR_KEY_IPV6_ADDRS, /* struct flow_dissector_key_ipv6_addrs */ FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, /* struct flow_dissector_key_addrs */ FLOW_DISSECTOR_KEY_PORTS, /* struct flow_dissector_key_ports */ - FLOW_DISSECTOR_KEY_IPV6_ADDRS, /* struct flow_dissector_key_ipv6_addrs */ FLOW_DISSECTOR_KEY_ETH_ADDRS, /* struct flow_dissector_key_eth_addrs */ FLOW_DISSECTOR_KEY_MAX, @@ -129,6 +140,9 @@ struct flow_keys { #define FLOW_KEYS_HASH_OFFSET \ offsetof(struct flow_keys, FLOW_KEYS_HASH_START_FIELD) +__be32 flow_get_u32_src(const struct flow_keys *flow); +__be32 flow_get_u32_dst(const struct flow_keys *flow); + extern struct flow_dissector flow_keys_dissector; extern struct flow_dissector flow_keys_buf_dissector; diff --git a/include/net/ip.h b/include/net/ip.h index 16cfc87fed6c..0750a186ea63 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -355,6 +355,20 @@ static inline __wsum inet_compute_pseudo(struct sk_buff *skb, int proto) skb->len, proto, 0); } +/* copy IPv4 saddr & daddr to flow_keys, possibly using 64bit load/store + * Equivalent to : flow->v4addrs.src = iph->saddr; + * flow->v4addrs.dst = iph->daddr; + */ +static inline void iph_to_flow_copy_v4addrs(struct flow_keys *flow, + const struct iphdr *iph) +{ + BUILD_BUG_ON(offsetof(typeof(flow->addrs), v4addrs.dst) != + offsetof(typeof(flow->addrs), v4addrs.src) + + sizeof(flow->addrs.v4addrs.src)); + memcpy(&flow->addrs.v4addrs, &iph->saddr, sizeof(flow->addrs.v4addrs)); + flow->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; +} + static inline void inet_set_txhash(struct sock *sk) { struct inet_sock *inet = inet_sk(sk); @@ -362,8 +376,9 @@ static inline void inet_set_txhash(struct sock *sk) memset(&keys, 0, sizeof(keys)); - keys.addrs.src = inet->inet_saddr; - keys.addrs.dst = inet->inet_daddr; + keys.addrs.v4addrs.src = inet->inet_saddr; + keys.addrs.v4addrs.dst = inet->inet_daddr; + keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; keys.ports.src = inet->inet_sport; keys.ports.dst = inet->inet_dport; diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 474ca466a091..82dbdb092a5d 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -692,6 +692,20 @@ static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6, return hlimit; } +/* copy IPv6 saddr & daddr to flow_keys, possibly using 64bit load/store + * Equivalent to : flow->v6addrs.src = iph->saddr; + * flow->v6addrs.dst = iph->daddr; + */ +static inline void iph_to_flow_copy_v6addrs(struct flow_keys *flow, + const struct ipv6hdr *iph) +{ + BUILD_BUG_ON(offsetof(typeof(flow->addrs), v6addrs.dst) != + offsetof(typeof(flow->addrs), v6addrs.src) + + sizeof(flow->addrs.v6addrs.src)); + memcpy(&flow->addrs.v6addrs, &iph->saddr, sizeof(flow->addrs.v6addrs)); + flow->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; +} + #if IS_ENABLED(CONFIG_IPV6) static inline void ip6_set_txhash(struct sock *sk) { @@ -701,8 +715,11 @@ static inline void ip6_set_txhash(struct sock *sk) memset(&keys, 0, sizeof(keys)); - keys.addrs.src = (__force __be32)ipv6_addr_hash(&np->saddr); - keys.addrs.dst = (__force __be32)ipv6_addr_hash(&sk->sk_v6_daddr); + memcpy(&keys.addrs.v6addrs.src, &np->saddr, + sizeof(keys.addrs.v6addrs.src)); + memcpy(&keys.addrs.v6addrs.dst, &sk->sk_v6_daddr, + sizeof(keys.addrs.v6addrs.dst)); + keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; keys.ports.src = inet->inet_sport; keys.ports.dst = inet->inet_dport; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 55b5f2962afa..ca9d22488cfb 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -178,10 +178,12 @@ ip: if (!skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) break; + key_addrs = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_IPV4_ADDRS, - target_container); - memcpy(key_addrs, &iph->saddr, sizeof(*key_addrs)); + FLOW_DISSECTOR_KEY_IPV4_ADDRS, target_container); + memcpy(&key_addrs->v4addrs, &iph->saddr, + sizeof(key_addrs->v4addrs)); + key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; break; } case htons(ETH_P_IPV6): { @@ -203,8 +205,11 @@ ipv6: FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, target_container); - key_addrs->src = (__force __be32)ipv6_addr_hash(&iph->saddr); - key_addrs->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); + key_addrs->v4addrs.src = + (__force __be32)ipv6_addr_hash(&iph->saddr); + key_addrs->v4addrs.dst = + (__force __be32)ipv6_addr_hash(&iph->daddr); + key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; goto flow_label; } if (skb_flow_dissector_uses_key(flow_dissector, @@ -216,6 +221,7 @@ ipv6: target_container); memcpy(key_ipv6_addrs, &iph->saddr, sizeof(*key_ipv6_addrs)); + key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; goto flow_label; } break; @@ -292,8 +298,9 @@ flow_label: key_addrs = skb_flow_dissector_target(flow_dissector, FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, target_container); - key_addrs->src = hdr->srcnode; - key_addrs->dst = 0; + key_addrs->v4addrs.src = hdr->srcnode; + key_addrs->v4addrs.dst = 0; + key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; } return true; } @@ -389,21 +396,88 @@ static inline void *flow_keys_hash_start(struct flow_keys *flow) static inline size_t flow_keys_hash_length(struct flow_keys *flow) { + size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs); BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32)); - return (sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) / sizeof(u32); + BUILD_BUG_ON(offsetof(typeof(*flow), addrs) != + sizeof(*flow) - sizeof(flow->addrs)); + + switch (flow->control.addr_type) { + case FLOW_DISSECTOR_KEY_IPV4_ADDRS: + diff -= sizeof(flow->addrs.v4addrs); + break; + case FLOW_DISSECTOR_KEY_IPV6_ADDRS: + diff -= sizeof(flow->addrs.v6addrs); + break; + } + return (sizeof(*flow) - diff) / sizeof(u32); +} + +__be32 flow_get_u32_src(const struct flow_keys *flow) +{ + switch (flow->control.addr_type) { + case FLOW_DISSECTOR_KEY_IPV4_ADDRS: + return flow->addrs.v4addrs.src; + case FLOW_DISSECTOR_KEY_IPV6_ADDRS: + return (__force __be32)ipv6_addr_hash( + &flow->addrs.v6addrs.src); + default: + return 0; + } +} +EXPORT_SYMBOL(flow_get_u32_src); + +__be32 flow_get_u32_dst(const struct flow_keys *flow) +{ + switch (flow->control.addr_type) { + case FLOW_DISSECTOR_KEY_IPV4_ADDRS: + return flow->addrs.v4addrs.dst; + case FLOW_DISSECTOR_KEY_IPV6_ADDRS: + return (__force __be32)ipv6_addr_hash( + &flow->addrs.v6addrs.dst); + default: + return 0; + } +} +EXPORT_SYMBOL(flow_get_u32_dst); + +static inline void __flow_hash_consistentify(struct flow_keys *keys) +{ + int addr_diff, i; + + switch (keys->control.addr_type) { + case FLOW_DISSECTOR_KEY_IPV4_ADDRS: + addr_diff = (__force u32)keys->addrs.v4addrs.dst - + (__force u32)keys->addrs.v4addrs.src; + if ((addr_diff < 0) || + (addr_diff == 0 && + ((__force u16)keys->ports.dst < + (__force u16)keys->ports.src))) { + swap(keys->addrs.v4addrs.src, keys->addrs.v4addrs.dst); + swap(keys->ports.src, keys->ports.dst); + } + break; + case FLOW_DISSECTOR_KEY_IPV6_ADDRS: + addr_diff = memcmp(&keys->addrs.v6addrs.dst, + &keys->addrs.v6addrs.src, + sizeof(keys->addrs.v6addrs.dst)); + if ((addr_diff < 0) || + (addr_diff == 0 && + ((__force u16)keys->ports.dst < + (__force u16)keys->ports.src))) { + for (i = 0; i < 4; i++) + swap(keys->addrs.v6addrs.src.s6_addr32[i], + keys->addrs.v6addrs.dst.s6_addr32[i]); + swap(keys->ports.src, keys->ports.dst); + } + break; + } } static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) { u32 hash; - /* get a consistent hash (same value on both flow directions) */ - if (((__force u32)keys->addrs.dst < (__force u32)keys->addrs.src) || - (((__force u32)keys->addrs.dst == (__force u32)keys->addrs.src) && - ((__force u16)keys->ports.dst < (__force u16)keys->ports.src))) { - swap(keys->addrs.dst, keys->addrs.src); - swap(keys->ports.src, keys->ports.dst); - } + __flow_hash_consistentify(keys); hash = __flow_hash_words((u32 *)flow_keys_hash_start(keys), flow_keys_hash_length(keys), keyval); @@ -451,8 +525,8 @@ void make_flow_keys_digest(struct flow_keys_digest *digest, data->n_proto = flow->basic.n_proto; data->ip_proto = flow->basic.ip_proto; data->ports = flow->ports.ports; - data->src = flow->addrs.src; - data->dst = flow->addrs.dst; + data->src = flow->addrs.v4addrs.src; + data->dst = flow->addrs.v4addrs.dst; } EXPORT_SYMBOL(make_flow_keys_digest); @@ -566,11 +640,15 @@ static const struct flow_dissector_key flow_keys_dissector_keys[] = { }, { .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS, - .offset = offsetof(struct flow_keys, addrs), + .offset = offsetof(struct flow_keys, addrs.v4addrs), + }, + { + .key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS, + .offset = offsetof(struct flow_keys, addrs.v6addrs), }, { .key_id = FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, - .offset = offsetof(struct flow_keys, addrs), + .offset = offsetof(struct flow_keys, addrs.v4addrs), }, { .key_id = FLOW_DISSECTOR_KEY_PORTS, diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 7d0e239a6755..77e0f0e7a88e 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -133,7 +133,7 @@ u32 eth_get_headlen(void *data, unsigned int len) /* parse any remaining L2/L3 headers, check for L4 */ if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto, sizeof(*eth), len)) - return max_t(u32, keys.basic.thoff, sizeof(*eth)); + return max_t(u32, keys.control.thoff, sizeof(*eth)); /* parse for any L4 headers */ return min_t(u32, __skb_get_poff(NULL, data, &keys, len), len); diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index b4359924846c..76bc3a20ffdb 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -68,15 +68,21 @@ static inline u32 addr_fold(void *addr) static u32 flow_get_src(const struct sk_buff *skb, const struct flow_keys *flow) { - if (flow->addrs.src) - return ntohl(flow->addrs.src); + __be32 src = flow_get_u32_src(flow); + + if (src) + return ntohl(src); + return addr_fold(skb->sk); } static u32 flow_get_dst(const struct sk_buff *skb, const struct flow_keys *flow) { - if (flow->addrs.dst) - return ntohl(flow->addrs.dst); + __be32 dst = flow_get_u32_dst(flow); + + if (dst) + return ntohl(dst); + return addr_fold(skb_dst(skb)) ^ (__force u16) tc_skb_protocol(skb); } diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 5a7d66c59684..b92d3f49c23e 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -28,8 +28,9 @@ struct fl_flow_key { struct flow_dissector_key_control control; struct flow_dissector_key_basic basic; struct flow_dissector_key_eth_addrs eth; + struct flow_dissector_key_addrs ipaddrs; union { - struct flow_dissector_key_addrs ipv4; + struct flow_dissector_key_ipv4_addrs ipv4; struct flow_dissector_key_ipv6_addrs ipv6; }; struct flow_dissector_key_ports tp; @@ -260,14 +261,14 @@ static int fl_set_key(struct net *net, struct nlattr **tb, &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, sizeof(key->basic.ip_proto)); } - if (key->basic.n_proto == htons(ETH_P_IP)) { + if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, sizeof(key->ipv4.src)); fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, sizeof(key->ipv4.dst)); - } else if (key->basic.n_proto == htons(ETH_P_IPV6)) { + } else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, sizeof(key->ipv6.src)); @@ -610,7 +611,7 @@ static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, sizeof(key->basic.ip_proto))) goto nla_put_failure; - if (key->basic.n_proto == htons(ETH_P_IP) && + if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, sizeof(key->ipv4.src)) || @@ -618,7 +619,7 @@ static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, sizeof(key->ipv4.dst)))) goto nla_put_failure; - else if (key->basic.n_proto == htons(ETH_P_IPV6) && + else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, sizeof(key->ipv6.src)) || -- cgit v1.2.3 From 9f24908901c5f4b1e3b07548106b1790af933476 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Jun 2015 09:16:41 -0700 Subject: net: Add keys for TIPC address Add a new flow key for TIPC addresses. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 10 ++++++++++ net/core/flow_dissector.c | 18 +++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 306d4613abbb..3ee606a54775 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -49,6 +49,14 @@ struct flow_dissector_key_ipv6_addrs { struct in6_addr dst; }; +/** + * struct flow_dissector_key_tipc_addrs: + * @srcnode: source node address + */ +struct flow_dissector_key_tipc_addrs { + __be32 srcnode; +}; + /** * struct flow_dissector_key_addrs: * @v4addrs: IPv4 addresses @@ -58,6 +66,7 @@ struct flow_dissector_key_addrs { union { struct flow_dissector_key_ipv4_addrs v4addrs; struct flow_dissector_key_ipv6_addrs v6addrs; + struct flow_dissector_key_tipc_addrs tipcaddrs; }; }; @@ -97,6 +106,7 @@ enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, /* struct flow_dissector_key_addrs */ FLOW_DISSECTOR_KEY_PORTS, /* struct flow_dissector_key_ports */ FLOW_DISSECTOR_KEY_ETH_ADDRS, /* struct flow_dissector_key_eth_addrs */ + FLOW_DISSECTOR_KEY_TIPC_ADDRS, /* struct flow_dissector_key_tipc_addrs */ FLOW_DISSECTOR_KEY_MAX, }; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index ca9d22488cfb..91861c3d45a7 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -294,13 +294,12 @@ flow_label: key_control->thoff = (u16)nhoff; if (skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS)) { + FLOW_DISSECTOR_KEY_TIPC_ADDRS)) { key_addrs = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, + FLOW_DISSECTOR_KEY_TIPC_ADDRS, target_container); - key_addrs->v4addrs.src = hdr->srcnode; - key_addrs->v4addrs.dst = 0; - key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; + key_addrs->tipcaddrs.srcnode = hdr->srcnode; + key_control->addr_type = FLOW_DISSECTOR_KEY_TIPC_ADDRS; } return true; } @@ -408,6 +407,9 @@ static inline size_t flow_keys_hash_length(struct flow_keys *flow) case FLOW_DISSECTOR_KEY_IPV6_ADDRS: diff -= sizeof(flow->addrs.v6addrs); break; + case FLOW_DISSECTOR_KEY_TIPC_ADDRS: + diff -= sizeof(flow->addrs.tipcaddrs); + break; } return (sizeof(*flow) - diff) / sizeof(u32); } @@ -420,6 +422,8 @@ __be32 flow_get_u32_src(const struct flow_keys *flow) case FLOW_DISSECTOR_KEY_IPV6_ADDRS: return (__force __be32)ipv6_addr_hash( &flow->addrs.v6addrs.src); + case FLOW_DISSECTOR_KEY_TIPC_ADDRS: + return flow->addrs.tipcaddrs.srcnode; default: return 0; } @@ -650,6 +654,10 @@ static const struct flow_dissector_key flow_keys_dissector_keys[] = { .key_id = FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, .offset = offsetof(struct flow_keys, addrs.v4addrs), }, + { + .key_id = FLOW_DISSECTOR_KEY_TIPC_ADDRS, + .offset = offsetof(struct flow_keys, addrs.tipcaddrs), + }, { .key_id = FLOW_DISSECTOR_KEY_PORTS, .offset = offsetof(struct flow_keys, ports), -- cgit v1.2.3 From 45b47fd00ca14df869979dbbe14324625ec93552 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Jun 2015 09:16:42 -0700 Subject: net: Get rid of IPv6 hash addresses flow keys We don't need to return the IPv6 address hash as part of flow keys. In general, using the IPv6 address hash is risky in a hash value since the underlying use of xor provides no entropy. If someone really needs the hash value they can get it from the full IPv6 addresses in flow keys (e.g. from flow_get_u32_src). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 1 - net/core/flow_dissector.c | 17 ----------------- 2 files changed, 18 deletions(-) (limited to 'include') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 3ee606a54775..59f00f90fc6b 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -103,7 +103,6 @@ enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ FLOW_DISSECTOR_KEY_IPV4_ADDRS, /* struct flow_dissector_key_ipv4_addrs */ FLOW_DISSECTOR_KEY_IPV6_ADDRS, /* struct flow_dissector_key_ipv6_addrs */ - FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, /* struct flow_dissector_key_addrs */ FLOW_DISSECTOR_KEY_PORTS, /* struct flow_dissector_key_ports */ FLOW_DISSECTOR_KEY_ETH_ADDRS, /* struct flow_dissector_key_eth_addrs */ FLOW_DISSECTOR_KEY_TIPC_ADDRS, /* struct flow_dissector_key_tipc_addrs */ diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 91861c3d45a7..5348a468de78 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -199,19 +199,6 @@ ipv6: ip_proto = iph->nexthdr; nhoff += sizeof(struct ipv6hdr); - if (skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS)) { - key_addrs = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, - target_container); - - key_addrs->v4addrs.src = - (__force __be32)ipv6_addr_hash(&iph->saddr); - key_addrs->v4addrs.dst = - (__force __be32)ipv6_addr_hash(&iph->daddr); - key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; - goto flow_label; - } if (skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IPV6_ADDRS)) { struct flow_dissector_key_ipv6_addrs *key_ipv6_addrs; @@ -650,10 +637,6 @@ static const struct flow_dissector_key flow_keys_dissector_keys[] = { .key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS, .offset = offsetof(struct flow_keys, addrs.v6addrs), }, - { - .key_id = FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, - .offset = offsetof(struct flow_keys, addrs.v4addrs), - }, { .key_id = FLOW_DISSECTOR_KEY_TIPC_ADDRS, .offset = offsetof(struct flow_keys, addrs.tipcaddrs), -- cgit v1.2.3 From d34af823ff401c312541aa613c49ea4b872bde9e Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Jun 2015 09:16:43 -0700 Subject: net: Add VLAN ID to flow_keys In flow_dissector set vlan_id in flow_keys when VLAN is found. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 6 ++++++ net/core/flow_dissector.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+) (limited to 'include') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 59f00f90fc6b..08480fbb9035 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -27,6 +27,10 @@ struct flow_dissector_key_basic { u8 padding; }; +struct flow_dissector_key_tags { + u32 vlan_id:12; +}; + /** * struct flow_dissector_key_ipv4_addrs: * @src: source ip address @@ -106,6 +110,7 @@ enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_PORTS, /* struct flow_dissector_key_ports */ FLOW_DISSECTOR_KEY_ETH_ADDRS, /* struct flow_dissector_key_eth_addrs */ FLOW_DISSECTOR_KEY_TIPC_ADDRS, /* struct flow_dissector_key_tipc_addrs */ + FLOW_DISSECTOR_KEY_VLANID, /* struct flow_dissector_key_flow_tags */ FLOW_DISSECTOR_KEY_MAX, }; @@ -142,6 +147,7 @@ struct flow_keys { struct flow_dissector_key_control control; #define FLOW_KEYS_HASH_START_FIELD basic struct flow_dissector_key_basic basic; + struct flow_dissector_key_tags tags; struct flow_dissector_key_ports ports; struct flow_dissector_key_addrs addrs; }; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 5348a468de78..5c66cb2e66df 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -126,6 +126,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector_key_basic *key_basic; struct flow_dissector_key_addrs *key_addrs; struct flow_dissector_key_ports *key_ports; + struct flow_dissector_key_tags *key_tags; u8 ip_proto; if (!data) { @@ -246,6 +247,15 @@ flow_label: if (!vlan) return false; + if (skb_flow_dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_VLANID)) { + key_tags = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_VLANID, + target_container); + + key_tags->vlan_id = skb_vlan_tag_get_id(skb); + } + proto = vlan->h_vlan_encapsulated_proto; nhoff += sizeof(*vlan); goto again; @@ -645,6 +655,10 @@ static const struct flow_dissector_key flow_keys_dissector_keys[] = { .key_id = FLOW_DISSECTOR_KEY_PORTS, .offset = offsetof(struct flow_keys, ports), }, + { + .key_id = FLOW_DISSECTOR_KEY_VLANID, + .offset = offsetof(struct flow_keys, tags), + }, }; static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = { -- cgit v1.2.3 From 87ee9e52ffeb168803a76cc07734425227cc2268 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Jun 2015 09:16:44 -0700 Subject: net: Add IPv6 flow label to flow_keys In flow_dissector set the flow label in flow_keys for IPv6. This also removes the shortcircuiting of flow dissection when a non-zero label is present, the flow label can be considered to provide additional entropy for a hash. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 4 +++- net/core/flow_dissector.c | 29 ++++++++++------------------- 2 files changed, 13 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 08480fbb9035..14d8483d836e 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -28,7 +28,8 @@ struct flow_dissector_key_basic { }; struct flow_dissector_key_tags { - u32 vlan_id:12; + u32 vlan_id:12, + flow_label:20; }; /** @@ -111,6 +112,7 @@ enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_ETH_ADDRS, /* struct flow_dissector_key_eth_addrs */ FLOW_DISSECTOR_KEY_TIPC_ADDRS, /* struct flow_dissector_key_tipc_addrs */ FLOW_DISSECTOR_KEY_VLANID, /* struct flow_dissector_key_flow_tags */ + FLOW_DISSECTOR_KEY_FLOW_LABEL, /* struct flow_dissector_key_flow_tags */ FLOW_DISSECTOR_KEY_MAX, }; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 5c66cb2e66df..70f0567b6be9 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -210,30 +210,17 @@ ipv6: memcpy(key_ipv6_addrs, &iph->saddr, sizeof(*key_ipv6_addrs)); key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; - goto flow_label; } - break; -flow_label: + flow_label = ip6_flowlabel(iph); if (flow_label) { - /* Awesome, IPv6 packet has a flow label so we can - * use that to represent the ports without any - * further dissection. - */ - - key_basic->n_proto = proto; - key_basic->ip_proto = ip_proto; - key_control->thoff = (u16)nhoff; - if (skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_PORTS)) { - key_ports = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_PORTS, - target_container); - key_ports->ports = flow_label; + FLOW_DISSECTOR_KEY_FLOW_LABEL)) { + key_tags = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_FLOW_LABEL, + target_container); + key_tags->flow_label = ntohl(flow_label); } - - return true; } break; @@ -659,6 +646,10 @@ static const struct flow_dissector_key flow_keys_dissector_keys[] = { .key_id = FLOW_DISSECTOR_KEY_VLANID, .offset = offsetof(struct flow_keys, tags), }, + { + .key_id = FLOW_DISSECTOR_KEY_FLOW_LABEL, + .offset = offsetof(struct flow_keys, tags), + }, }; static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = { -- cgit v1.2.3 From 1fdd512c92003cf2d671ba22753d13302bf8cd1d Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Jun 2015 09:16:45 -0700 Subject: net: Add GRE keyid in flow_keys In flow dissector if a GRE header contains a keyid this is saved in the new keyid field of flow_keys. The GRE keyid is then represented in the flow hash function input. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 6 ++++++ net/core/flow_dissector.c | 24 +++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 14d8483d836e..6c5e8d262607 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -32,6 +32,10 @@ struct flow_dissector_key_tags { flow_label:20; }; +struct flow_dissector_key_keyid { + __be32 keyid; +}; + /** * struct flow_dissector_key_ipv4_addrs: * @src: source ip address @@ -113,6 +117,7 @@ enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_TIPC_ADDRS, /* struct flow_dissector_key_tipc_addrs */ FLOW_DISSECTOR_KEY_VLANID, /* struct flow_dissector_key_flow_tags */ FLOW_DISSECTOR_KEY_FLOW_LABEL, /* struct flow_dissector_key_flow_tags */ + FLOW_DISSECTOR_KEY_GRE_KEYID, /* struct flow_dissector_key_keyid */ FLOW_DISSECTOR_KEY_MAX, }; @@ -150,6 +155,7 @@ struct flow_keys { #define FLOW_KEYS_HASH_START_FIELD basic struct flow_dissector_key_basic basic; struct flow_dissector_key_tags tags; + struct flow_dissector_key_keyid keyid; struct flow_dissector_key_ports ports; struct flow_dissector_key_addrs addrs; }; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 70f0567b6be9..7ddc0a7b3da5 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -127,6 +127,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector_key_addrs *key_addrs; struct flow_dissector_key_ports *key_ports; struct flow_dissector_key_tags *key_tags; + struct flow_dissector_key_keyid *key_keyid; u8 ip_proto; if (!data) { @@ -315,8 +316,25 @@ ipv6: nhoff += 4; if (hdr->flags & GRE_CSUM) nhoff += 4; - if (hdr->flags & GRE_KEY) + if (hdr->flags & GRE_KEY) { + const __be32 *keyid; + __be32 _keyid; + + keyid = __skb_header_pointer(skb, nhoff, sizeof(_keyid), + data, hlen, &_keyid); + + if (!keyid) + return false; + + if (skb_flow_dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_GRE_KEYID)) { + key_keyid = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_GRE_KEYID, + target_container); + key_keyid->keyid = *keyid; + } nhoff += 4; + } if (hdr->flags & GRE_SEQ) nhoff += 4; if (proto == htons(ETH_P_TEB)) { @@ -650,6 +668,10 @@ static const struct flow_dissector_key flow_keys_dissector_keys[] = { .key_id = FLOW_DISSECTOR_KEY_FLOW_LABEL, .offset = offsetof(struct flow_keys, tags), }, + { + .key_id = FLOW_DISSECTOR_KEY_GRE_KEYID, + .offset = offsetof(struct flow_keys, keyid), + }, }; static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = { -- cgit v1.2.3 From b3baa0fbd02a1a9d493d8cb92ae4a4491b9e9d13 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Jun 2015 09:16:46 -0700 Subject: mpls: Add MPLS entropy label in flow_keys In flow dissector if an MPLS header contains an entropy label this is saved in the new keyid field of flow_keys. The entropy label is then represented in the flow hash function input. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 1 + net/core/flow_dissector.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) (limited to 'include') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 6c5e8d262607..1a8c22419936 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -118,6 +118,7 @@ enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_VLANID, /* struct flow_dissector_key_flow_tags */ FLOW_DISSECTOR_KEY_FLOW_LABEL, /* struct flow_dissector_key_flow_tags */ FLOW_DISSECTOR_KEY_GRE_KEYID, /* struct flow_dissector_key_keyid */ + FLOW_DISSECTOR_KEY_MPLS_ENTROPY, /* struct flow_dissector_key_keyid */ FLOW_DISSECTOR_KEY_MAX, }; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 7ddc0a7b3da5..77e22e4fc898 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -288,6 +289,37 @@ ipv6: } return true; } + + case htons(ETH_P_MPLS_UC): + case htons(ETH_P_MPLS_MC): { + struct mpls_label *hdr, _hdr[2]; +mpls: + hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, + hlen, &_hdr); + if (!hdr) + return false; + + if ((ntohl(hdr[0].entry) & MPLS_LS_LABEL_MASK) == + MPLS_LABEL_ENTROPY) { + if (skb_flow_dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_MPLS_ENTROPY)) { + key_keyid = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_MPLS_ENTROPY, + target_container); + key_keyid->keyid = hdr[1].entry & + htonl(MPLS_LS_LABEL_MASK); + } + + key_basic->n_proto = proto; + key_basic->ip_proto = ip_proto; + key_control->thoff = (u16)nhoff; + + return true; + } + + return true; + } + case htons(ETH_P_FCOE): key_control->thoff = (u16)(nhoff + FCOE_HEADER_LEN); /* fall through */ @@ -357,6 +389,9 @@ ipv6: case IPPROTO_IPV6: proto = htons(ETH_P_IPV6); goto ipv6; + case IPPROTO_MPLS: + proto = htons(ETH_P_MPLS_UC); + goto mpls; default: break; } -- cgit v1.2.3 From 01949d0109ee5fae33752f0db99a36f1619e1873 Mon Sep 17 00:00:00 2001 From: Haggai Abramonvsky Date: Thu, 4 Jun 2015 19:30:38 +0300 Subject: net/mlx5_core: Enable XRCs and SRQs when using ISSI > 0 When working in ISSI > 0 mode, the model exposed by the device for XRCs and SRQs is different. XRCs use XRC SRQs and plain SRQs are based on RPM (Receive Memory Pool). Add helper functions to create, modify, query, and arm XRC SRQs and RMPs. Signed-off-by: Haggai Abramovsky Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/srq.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 4 +- drivers/net/ethernet/mellanox/mlx5/core/srq.c | 444 ++++++++++++++++++--- drivers/net/ethernet/mellanox/mlx5/core/transobj.c | 154 +++++++ drivers/net/ethernet/mellanox/mlx5/core/transobj.h | 11 + include/linux/mlx5/driver.h | 6 +- include/linux/mlx5/mlx5_ifc.h | 16 +- 7 files changed, 564 insertions(+), 73 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index e8e8e942fa4a..e008505e96e9 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -302,7 +302,7 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, in->ctx.pd = cpu_to_be32(to_mpd(pd)->pdn); in->ctx.db_record = cpu_to_be64(srq->db.dma); - err = mlx5_core_create_srq(dev->mdev, &srq->msrq, in, inlen); + err = mlx5_core_create_srq(dev->mdev, &srq->msrq, in, inlen, is_xrc); kvfree(in); if (err) { mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 87e9e606596a..07540f732df1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_MLX5_CORE) += mlx5_core.o mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \ - mad.o -mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o flow_table.o vport.o transobj.o \ + mad.o transobj.o +mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o flow_table.o vport.o \ en_main.o en_flow_table.o en_ethtool.o en_tx.o en_rx.o \ en_txrx.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/srq.c b/drivers/net/ethernet/mellanox/mlx5/core/srq.c index f9d25dcd03c1..c48f504ccbeb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/srq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/srq.c @@ -37,6 +37,7 @@ #include #include #include "mlx5_core.h" +#include "transobj.h" void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type) { @@ -62,6 +63,74 @@ void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type) complete(&srq->free); } +static int get_pas_size(void *srqc) +{ + u32 log_page_size = MLX5_GET(srqc, srqc, log_page_size) + 12; + u32 log_srq_size = MLX5_GET(srqc, srqc, log_srq_size); + u32 log_rq_stride = MLX5_GET(srqc, srqc, log_rq_stride); + u32 page_offset = MLX5_GET(srqc, srqc, page_offset); + u32 po_quanta = 1 << (log_page_size - 6); + u32 rq_sz = 1 << (log_srq_size + 4 + log_rq_stride); + u32 page_size = 1 << log_page_size; + u32 rq_sz_po = rq_sz + (page_offset * po_quanta); + u32 rq_num_pas = (rq_sz_po + page_size - 1) / page_size; + + return rq_num_pas * sizeof(u64); +} + +static void rmpc_srqc_reformat(void *srqc, void *rmpc, bool srqc_to_rmpc) +{ + void *wq = MLX5_ADDR_OF(rmpc, rmpc, wq); + + if (srqc_to_rmpc) { + switch (MLX5_GET(srqc, srqc, state)) { + case MLX5_SRQC_STATE_GOOD: + MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY); + break; + case MLX5_SRQC_STATE_ERROR: + MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_ERR); + break; + default: + pr_warn("%s: %d: Unknown srq state = 0x%x\n", __func__, + __LINE__, MLX5_GET(srqc, srqc, state)); + MLX5_SET(rmpc, rmpc, state, MLX5_GET(srqc, srqc, state)); + } + + MLX5_SET(wq, wq, wq_signature, MLX5_GET(srqc, srqc, wq_signature)); + MLX5_SET(wq, wq, log_wq_pg_sz, MLX5_GET(srqc, srqc, log_page_size)); + MLX5_SET(wq, wq, log_wq_stride, MLX5_GET(srqc, srqc, log_rq_stride) + 4); + MLX5_SET(wq, wq, log_wq_sz, MLX5_GET(srqc, srqc, log_srq_size)); + MLX5_SET(wq, wq, page_offset, MLX5_GET(srqc, srqc, page_offset)); + MLX5_SET(wq, wq, lwm, MLX5_GET(srqc, srqc, lwm)); + MLX5_SET(wq, wq, pd, MLX5_GET(srqc, srqc, pd)); + MLX5_SET64(wq, wq, dbr_addr, MLX5_GET64(srqc, srqc, dbr_addr)); + } else { + switch (MLX5_GET(rmpc, rmpc, state)) { + case MLX5_RMPC_STATE_RDY: + MLX5_SET(srqc, srqc, state, MLX5_SRQC_STATE_GOOD); + break; + case MLX5_RMPC_STATE_ERR: + MLX5_SET(srqc, srqc, state, MLX5_SRQC_STATE_ERROR); + break; + default: + pr_warn("%s: %d: Unknown rmp state = 0x%x\n", + __func__, __LINE__, + MLX5_GET(rmpc, rmpc, state)); + MLX5_SET(srqc, srqc, state, + MLX5_GET(rmpc, rmpc, state)); + } + + MLX5_SET(srqc, srqc, wq_signature, MLX5_GET(wq, wq, wq_signature)); + MLX5_SET(srqc, srqc, log_page_size, MLX5_GET(wq, wq, log_wq_pg_sz)); + MLX5_SET(srqc, srqc, log_rq_stride, MLX5_GET(wq, wq, log_wq_stride) - 4); + MLX5_SET(srqc, srqc, log_srq_size, MLX5_GET(wq, wq, log_wq_sz)); + MLX5_SET(srqc, srqc, page_offset, MLX5_GET(wq, wq, page_offset)); + MLX5_SET(srqc, srqc, lwm, MLX5_GET(wq, wq, lwm)); + MLX5_SET(srqc, srqc, pd, MLX5_GET(wq, wq, pd)); + MLX5_SET64(srqc, srqc, dbr_addr, MLX5_GET64(wq, wq, dbr_addr)); + } +} + struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn) { struct mlx5_srq_table *table = &dev->priv.srq_table; @@ -79,26 +148,311 @@ struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn) } EXPORT_SYMBOL(mlx5_core_get_srq); -int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, - struct mlx5_create_srq_mbox_in *in, int inlen) +static int create_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, + struct mlx5_create_srq_mbox_in *in, int inlen) { struct mlx5_create_srq_mbox_out out; - struct mlx5_srq_table *table = &dev->priv.srq_table; - struct mlx5_destroy_srq_mbox_in din; - struct mlx5_destroy_srq_mbox_out dout; int err; memset(&out, 0, sizeof(out)); + in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_SRQ); - err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out)); - if (err) - return err; - if (out.hdr.status) - return mlx5_cmd_status_to_err(&out.hdr); + err = mlx5_cmd_exec_check_status(dev, (u32 *)in, inlen, (u32 *)(&out), + sizeof(out)); srq->srqn = be32_to_cpu(out.srqn) & 0xffffff; + return err; +} + +static int destroy_srq_cmd(struct mlx5_core_dev *dev, + struct mlx5_core_srq *srq) +{ + struct mlx5_destroy_srq_mbox_in in; + struct mlx5_destroy_srq_mbox_out out; + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ); + in.srqn = cpu_to_be32(srq->srqn); + + return mlx5_cmd_exec_check_status(dev, (u32 *)(&in), sizeof(in), + (u32 *)(&out), sizeof(out)); +} + +static int arm_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, + u16 lwm, int is_srq) +{ + struct mlx5_arm_srq_mbox_in in; + struct mlx5_arm_srq_mbox_out out; + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ARM_RQ); + in.hdr.opmod = cpu_to_be16(!!is_srq); + in.srqn = cpu_to_be32(srq->srqn); + in.lwm = cpu_to_be16(lwm); + + return mlx5_cmd_exec_check_status(dev, (u32 *)(&in), + sizeof(in), (u32 *)(&out), + sizeof(out)); +} + +static int query_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, + struct mlx5_query_srq_mbox_out *out) +{ + struct mlx5_query_srq_mbox_in in; + + memset(&in, 0, sizeof(in)); + + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SRQ); + in.srqn = cpu_to_be32(srq->srqn); + + return mlx5_cmd_exec_check_status(dev, (u32 *)(&in), sizeof(in), + (u32 *)out, sizeof(*out)); +} + +static int create_xrc_srq_cmd(struct mlx5_core_dev *dev, + struct mlx5_core_srq *srq, + struct mlx5_create_srq_mbox_in *in, + int srq_inlen) +{ + u32 create_out[MLX5_ST_SZ_DW(create_xrc_srq_out)]; + void *create_in; + void *srqc; + void *xrc_srqc; + void *pas; + int pas_size; + int inlen; + int err; + + srqc = MLX5_ADDR_OF(create_srq_in, in, srq_context_entry); + pas_size = get_pas_size(srqc); + inlen = MLX5_ST_SZ_BYTES(create_xrc_srq_in) + pas_size; + create_in = mlx5_vzalloc(inlen); + if (!create_in) + return -ENOMEM; + + xrc_srqc = MLX5_ADDR_OF(create_xrc_srq_in, create_in, + xrc_srq_context_entry); + pas = MLX5_ADDR_OF(create_xrc_srq_in, create_in, pas); + + memcpy(xrc_srqc, srqc, MLX5_ST_SZ_BYTES(srqc)); + memcpy(pas, in->pas, pas_size); + /* 0xffffff means we ask to work with cqe version 0 */ + MLX5_SET(xrc_srqc, xrc_srqc, user_index, 0xffffff); + MLX5_SET(create_xrc_srq_in, create_in, opcode, + MLX5_CMD_OP_CREATE_XRC_SRQ); + + memset(create_out, 0, sizeof(create_out)); + err = mlx5_cmd_exec_check_status(dev, create_in, inlen, create_out, + sizeof(create_out)); + if (err) + goto out; + + srq->srqn = MLX5_GET(create_xrc_srq_out, create_out, xrc_srqn); +out: + kvfree(create_in); + return err; +} + +static int destroy_xrc_srq_cmd(struct mlx5_core_dev *dev, + struct mlx5_core_srq *srq) +{ + u32 xrcsrq_in[MLX5_ST_SZ_DW(destroy_xrc_srq_in)]; + u32 xrcsrq_out[MLX5_ST_SZ_DW(destroy_xrc_srq_out)]; + + memset(xrcsrq_in, 0, sizeof(xrcsrq_in)); + memset(xrcsrq_out, 0, sizeof(xrcsrq_out)); + + MLX5_SET(destroy_xrc_srq_in, xrcsrq_in, opcode, + MLX5_CMD_OP_DESTROY_XRC_SRQ); + MLX5_SET(destroy_xrc_srq_in, xrcsrq_in, xrc_srqn, srq->srqn); + + return mlx5_cmd_exec_check_status(dev, xrcsrq_in, sizeof(xrcsrq_in), + xrcsrq_out, sizeof(xrcsrq_out)); +} + +static int arm_xrc_srq_cmd(struct mlx5_core_dev *dev, + struct mlx5_core_srq *srq, u16 lwm) +{ + u32 xrcsrq_in[MLX5_ST_SZ_DW(arm_xrc_srq_in)]; + u32 xrcsrq_out[MLX5_ST_SZ_DW(arm_xrc_srq_out)]; + + memset(xrcsrq_in, 0, sizeof(xrcsrq_in)); + memset(xrcsrq_out, 0, sizeof(xrcsrq_out)); + + MLX5_SET(arm_xrc_srq_in, xrcsrq_in, opcode, MLX5_CMD_OP_ARM_XRC_SRQ); + MLX5_SET(arm_xrc_srq_in, xrcsrq_in, op_mod, MLX5_ARM_XRC_SRQ_IN_OP_MOD_XRC_SRQ); + MLX5_SET(arm_xrc_srq_in, xrcsrq_in, xrc_srqn, srq->srqn); + MLX5_SET(arm_xrc_srq_in, xrcsrq_in, lwm, lwm); + + return mlx5_cmd_exec_check_status(dev, xrcsrq_in, sizeof(xrcsrq_in), + xrcsrq_out, sizeof(xrcsrq_out)); +} + +static int query_xrc_srq_cmd(struct mlx5_core_dev *dev, + struct mlx5_core_srq *srq, + struct mlx5_query_srq_mbox_out *out) +{ + u32 xrcsrq_in[MLX5_ST_SZ_DW(query_xrc_srq_in)]; + u32 *xrcsrq_out; + void *srqc; + void *xrc_srqc; + int err; + + xrcsrq_out = mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_xrc_srq_out)); + if (!xrcsrq_out) + return -ENOMEM; + memset(xrcsrq_in, 0, sizeof(xrcsrq_in)); + + MLX5_SET(query_xrc_srq_in, xrcsrq_in, opcode, + MLX5_CMD_OP_QUERY_XRC_SRQ); + MLX5_SET(query_xrc_srq_in, xrcsrq_in, xrc_srqn, srq->srqn); + err = mlx5_cmd_exec_check_status(dev, xrcsrq_in, sizeof(xrcsrq_in), + xrcsrq_out, + MLX5_ST_SZ_BYTES(query_xrc_srq_out)); + if (err) + goto out; + + xrc_srqc = MLX5_ADDR_OF(query_xrc_srq_out, xrcsrq_out, + xrc_srq_context_entry); + srqc = MLX5_ADDR_OF(query_srq_out, out, srq_context_entry); + memcpy(srqc, xrc_srqc, MLX5_ST_SZ_BYTES(srqc)); + +out: + kvfree(xrcsrq_out); + return err; +} + +static int create_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, + struct mlx5_create_srq_mbox_in *in, int srq_inlen) +{ + void *create_in; + void *rmpc; + void *srqc; + int pas_size; + int inlen; + int err; + + srqc = MLX5_ADDR_OF(create_srq_in, in, srq_context_entry); + pas_size = get_pas_size(srqc); + inlen = MLX5_ST_SZ_BYTES(create_rmp_in) + pas_size; + create_in = mlx5_vzalloc(inlen); + if (!create_in) + return -ENOMEM; + + rmpc = MLX5_ADDR_OF(create_rmp_in, create_in, ctx); + + memcpy(MLX5_ADDR_OF(rmpc, rmpc, wq.pas), in->pas, pas_size); + rmpc_srqc_reformat(srqc, rmpc, true); + + err = mlx5_core_create_rmp(dev, create_in, inlen, &srq->srqn); + + kvfree(create_in); + return err; +} + +static int destroy_rmp_cmd(struct mlx5_core_dev *dev, + struct mlx5_core_srq *srq) +{ + return mlx5_core_destroy_rmp(dev, srq->srqn); +} + +static int arm_rmp_cmd(struct mlx5_core_dev *dev, + struct mlx5_core_srq *srq, + u16 lwm) +{ + void *in; + void *rmpc; + void *wq; + void *bitmask; + int err; + + in = mlx5_vzalloc(MLX5_ST_SZ_BYTES(modify_rmp_in)); + if (!in) + return -ENOMEM; + + rmpc = MLX5_ADDR_OF(modify_rmp_in, in, ctx); + bitmask = MLX5_ADDR_OF(modify_rmp_in, in, bitmask); + wq = MLX5_ADDR_OF(rmpc, rmpc, wq); + + MLX5_SET(modify_rmp_in, in, rmp_state, MLX5_RMPC_STATE_RDY); + MLX5_SET(modify_rmp_in, in, rmpn, srq->srqn); + MLX5_SET(wq, wq, lwm, lwm); + MLX5_SET(rmp_bitmask, bitmask, lwm, 1); + MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY); + + err = mlx5_core_modify_rmp(dev, in, MLX5_ST_SZ_BYTES(modify_rmp_in)); + + kvfree(in); + return err; +} + +static int query_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, + struct mlx5_query_srq_mbox_out *out) +{ + u32 *rmp_out; + void *rmpc; + void *srqc; + int err; + + rmp_out = mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_rmp_out)); + if (!rmp_out) + return -ENOMEM; + + err = mlx5_core_query_rmp(dev, srq->srqn, rmp_out); + if (err) + goto out; + + srqc = MLX5_ADDR_OF(query_srq_out, out, srq_context_entry); + rmpc = MLX5_ADDR_OF(query_rmp_out, rmp_out, rmp_context); + rmpc_srqc_reformat(srqc, rmpc, false); + +out: + kvfree(rmp_out); + return err; +} + +static int create_srq_split(struct mlx5_core_dev *dev, + struct mlx5_core_srq *srq, + struct mlx5_create_srq_mbox_in *in, + int inlen, int is_xrc) +{ + if (!dev->issi) + return create_srq_cmd(dev, srq, in, inlen); + else if (srq->common.res == MLX5_RES_XSRQ) + return create_xrc_srq_cmd(dev, srq, in, inlen); + else + return create_rmp_cmd(dev, srq, in, inlen); +} + +static int destroy_srq_split(struct mlx5_core_dev *dev, + struct mlx5_core_srq *srq) +{ + if (!dev->issi) + return destroy_srq_cmd(dev, srq); + else if (srq->common.res == MLX5_RES_XSRQ) + return destroy_xrc_srq_cmd(dev, srq); + else + return destroy_rmp_cmd(dev, srq); +} + +int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, + struct mlx5_create_srq_mbox_in *in, int inlen, + int is_xrc) +{ + int err; + struct mlx5_srq_table *table = &dev->priv.srq_table; + + srq->common.res = is_xrc ? MLX5_RES_XSRQ : MLX5_RES_SRQ; + + err = create_srq_split(dev, srq, in, inlen, is_xrc); + if (err) + return err; + atomic_set(&srq->refcount, 1); init_completion(&srq->free); @@ -107,25 +461,20 @@ int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, spin_unlock_irq(&table->lock); if (err) { mlx5_core_warn(dev, "err %d, srqn 0x%x\n", err, srq->srqn); - goto err_cmd; + goto err_destroy_srq_split; } return 0; -err_cmd: - memset(&din, 0, sizeof(din)); - memset(&dout, 0, sizeof(dout)); - din.srqn = cpu_to_be32(srq->srqn); - din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ); - mlx5_cmd_exec(dev, &din, sizeof(din), &dout, sizeof(dout)); +err_destroy_srq_split: + destroy_srq_split(dev, srq); + return err; } EXPORT_SYMBOL(mlx5_core_create_srq); int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq) { - struct mlx5_destroy_srq_mbox_in in; - struct mlx5_destroy_srq_mbox_out out; struct mlx5_srq_table *table = &dev->priv.srq_table; struct mlx5_core_srq *tmp; int err; @@ -142,17 +491,10 @@ int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq) return -EINVAL; } - memset(&in, 0, sizeof(in)); - memset(&out, 0, sizeof(out)); - in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ); - in.srqn = cpu_to_be32(srq->srqn); - err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); + err = destroy_srq_split(dev, srq); if (err) return err; - if (out.hdr.status) - return mlx5_cmd_status_to_err(&out.hdr); - if (atomic_dec_and_test(&srq->refcount)) complete(&srq->free); wait_for_completion(&srq->free); @@ -164,48 +506,24 @@ EXPORT_SYMBOL(mlx5_core_destroy_srq); int mlx5_core_query_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, struct mlx5_query_srq_mbox_out *out) { - struct mlx5_query_srq_mbox_in in; - int err; - - memset(&in, 0, sizeof(in)); - memset(out, 0, sizeof(*out)); - - in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SRQ); - in.srqn = cpu_to_be32(srq->srqn); - err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out)); - if (err) - return err; - - if (out->hdr.status) - return mlx5_cmd_status_to_err(&out->hdr); - - return err; + if (!dev->issi) + return query_srq_cmd(dev, srq, out); + else if (srq->common.res == MLX5_RES_XSRQ) + return query_xrc_srq_cmd(dev, srq, out); + else + return query_rmp_cmd(dev, srq, out); } EXPORT_SYMBOL(mlx5_core_query_srq); int mlx5_core_arm_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, u16 lwm, int is_srq) { - struct mlx5_arm_srq_mbox_in in; - struct mlx5_arm_srq_mbox_out out; - int err; - - memset(&in, 0, sizeof(in)); - memset(&out, 0, sizeof(out)); - - in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ARM_RQ); - in.hdr.opmod = cpu_to_be16(!!is_srq); - in.srqn = cpu_to_be32(srq->srqn); - in.lwm = cpu_to_be16(lwm); - - err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); - if (err) - return err; - - if (out.hdr.status) - return mlx5_cmd_status_to_err(&out.hdr); - - return err; + if (!dev->issi) + return arm_srq_cmd(dev, srq, lwm, is_srq); + else if (srq->common.res == MLX5_RES_XSRQ) + return arm_xrc_srq_cmd(dev, srq, lwm); + else + return arm_rmp_cmd(dev, srq, lwm); } EXPORT_SYMBOL(mlx5_core_arm_srq); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c index d918816ac4d8..7a120283de2c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c @@ -169,3 +169,157 @@ void mlx5_core_destroy_tis(struct mlx5_core_dev *dev, u32 tisn) mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out)); } + +int mlx5_core_create_rmp(struct mlx5_core_dev *dev, u32 *in, int inlen, + u32 *rmpn) +{ + u32 out[MLX5_ST_SZ_DW(create_rmp_out)]; + int err; + + MLX5_SET(create_rmp_in, in, opcode, MLX5_CMD_OP_CREATE_RMP); + + memset(out, 0, sizeof(out)); + err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); + if (!err) + *rmpn = MLX5_GET(create_rmp_out, out, rmpn); + + return err; +} + +int mlx5_core_modify_rmp(struct mlx5_core_dev *dev, u32 *in, int inlen) +{ + u32 out[MLX5_ST_SZ_DW(modify_rmp_out)]; + + MLX5_SET(modify_rmp_in, in, opcode, MLX5_CMD_OP_MODIFY_RMP); + + memset(out, 0, sizeof(out)); + return mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); +} + +int mlx5_core_destroy_rmp(struct mlx5_core_dev *dev, u32 rmpn) +{ + u32 in[MLX5_ST_SZ_DW(destroy_rmp_in)]; + u32 out[MLX5_ST_SZ_DW(destroy_rmp_out)]; + + memset(in, 0, sizeof(in)); + + MLX5_SET(destroy_rmp_in, in, opcode, MLX5_CMD_OP_DESTROY_RMP); + MLX5_SET(destroy_rmp_in, in, rmpn, rmpn); + + return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, + sizeof(out)); +} + +int mlx5_core_query_rmp(struct mlx5_core_dev *dev, u32 rmpn, u32 *out) +{ + u32 in[MLX5_ST_SZ_DW(query_rmp_in)]; + int outlen = MLX5_ST_SZ_BYTES(query_rmp_out); + + memset(in, 0, sizeof(in)); + MLX5_SET(query_rmp_in, in, opcode, MLX5_CMD_OP_QUERY_RMP); + MLX5_SET(query_rmp_in, in, rmpn, rmpn); + + return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, outlen); +} + +int mlx5_core_arm_rmp(struct mlx5_core_dev *dev, u32 rmpn, u16 lwm) +{ + void *in; + void *rmpc; + void *wq; + void *bitmask; + int err; + + in = mlx5_vzalloc(MLX5_ST_SZ_BYTES(modify_rmp_in)); + if (!in) + return -ENOMEM; + + rmpc = MLX5_ADDR_OF(modify_rmp_in, in, ctx); + bitmask = MLX5_ADDR_OF(modify_rmp_in, in, bitmask); + wq = MLX5_ADDR_OF(rmpc, rmpc, wq); + + MLX5_SET(modify_rmp_in, in, rmp_state, MLX5_RMPC_STATE_RDY); + MLX5_SET(modify_rmp_in, in, rmpn, rmpn); + MLX5_SET(wq, wq, lwm, lwm); + MLX5_SET(rmp_bitmask, bitmask, lwm, 1); + MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY); + + err = mlx5_core_modify_rmp(dev, in, MLX5_ST_SZ_BYTES(modify_rmp_in)); + + kvfree(in); + + return err; +} + +int mlx5_core_create_xsrq(struct mlx5_core_dev *dev, u32 *in, int inlen, + u32 *xsrqn) +{ + u32 out[MLX5_ST_SZ_DW(create_xrc_srq_out)]; + int err; + + MLX5_SET(create_xrc_srq_in, in, opcode, MLX5_CMD_OP_CREATE_XRC_SRQ); + + memset(out, 0, sizeof(out)); + err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); + if (!err) + *xsrqn = MLX5_GET(create_xrc_srq_out, out, xrc_srqn); + + return err; +} + +int mlx5_core_destroy_xsrq(struct mlx5_core_dev *dev, u32 xsrqn) +{ + u32 in[MLX5_ST_SZ_DW(destroy_xrc_srq_in)]; + u32 out[MLX5_ST_SZ_DW(destroy_xrc_srq_out)]; + + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + + MLX5_SET(destroy_xrc_srq_in, in, opcode, MLX5_CMD_OP_DESTROY_XRC_SRQ); + MLX5_SET(destroy_xrc_srq_in, in, xrc_srqn, xsrqn); + + return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, + sizeof(out)); +} + +int mlx5_core_query_xsrq(struct mlx5_core_dev *dev, u32 xsrqn, u32 *out) +{ + u32 in[MLX5_ST_SZ_DW(query_xrc_srq_in)]; + void *srqc; + void *xrc_srqc; + int err; + + memset(in, 0, sizeof(in)); + MLX5_SET(query_xrc_srq_in, in, opcode, MLX5_CMD_OP_QUERY_XRC_SRQ); + MLX5_SET(query_xrc_srq_in, in, xrc_srqn, xsrqn); + + err = mlx5_cmd_exec_check_status(dev, in, sizeof(in), + out, + MLX5_ST_SZ_BYTES(query_xrc_srq_out)); + if (!err) { + xrc_srqc = MLX5_ADDR_OF(query_xrc_srq_out, out, + xrc_srq_context_entry); + srqc = MLX5_ADDR_OF(query_srq_out, out, srq_context_entry); + memcpy(srqc, xrc_srqc, MLX5_ST_SZ_BYTES(srqc)); + } + + return err; +} + +int mlx5_core_arm_xsrq(struct mlx5_core_dev *dev, u32 xsrqn, u16 lwm) +{ + u32 in[MLX5_ST_SZ_DW(arm_xrc_srq_in)]; + u32 out[MLX5_ST_SZ_DW(arm_xrc_srq_out)]; + + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + + MLX5_SET(arm_xrc_srq_in, in, opcode, MLX5_CMD_OP_ARM_XRC_SRQ); + MLX5_SET(arm_xrc_srq_in, in, xrc_srqn, xsrqn); + MLX5_SET(arm_xrc_srq_in, in, lwm, lwm); + MLX5_SET(arm_xrc_srq_in, in, op_mod, + MLX5_ARM_XRC_SRQ_IN_OP_MOD_XRC_SRQ); + + return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, + sizeof(out)); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.h b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h index b71d77f61a1d..90322c11361f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h @@ -47,5 +47,16 @@ void mlx5_core_destroy_tir(struct mlx5_core_dev *dev, u32 tirn); int mlx5_core_create_tis(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *tisn); void mlx5_core_destroy_tis(struct mlx5_core_dev *dev, u32 tisn); +int mlx5_core_create_rmp(struct mlx5_core_dev *dev, u32 *in, int inlen, + u32 *rmpn); +int mlx5_core_modify_rmp(struct mlx5_core_dev *dev, u32 *in, int inlen); +int mlx5_core_destroy_rmp(struct mlx5_core_dev *dev, u32 rmpn); +int mlx5_core_query_rmp(struct mlx5_core_dev *dev, u32 rmpn, u32 *out); +int mlx5_core_arm_rmp(struct mlx5_core_dev *dev, u32 rmpn, u16 lwm); +int mlx5_core_create_xsrq(struct mlx5_core_dev *dev, u32 *in, int inlen, + u32 *rmpn); +int mlx5_core_destroy_xsrq(struct mlx5_core_dev *dev, u32 rmpn); +int mlx5_core_query_xsrq(struct mlx5_core_dev *dev, u32 rmpn, u32 *out); +int mlx5_core_arm_xsrq(struct mlx5_core_dev *dev, u32 rmpn, u16 lwm); #endif /* __TRANSOBJ_H__ */ diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 7fa26f03acc1..ba9f212c94bb 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -339,6 +339,8 @@ struct mlx5_core_mr { enum mlx5_res_type { MLX5_RES_QP, + MLX5_RES_SRQ, + MLX5_RES_XSRQ, }; struct mlx5_core_rsc_common { @@ -348,6 +350,7 @@ struct mlx5_core_rsc_common { }; struct mlx5_core_srq { + struct mlx5_core_rsc_common common; /* must be first */ u32 srqn; int max; int max_gs; @@ -640,7 +643,8 @@ struct mlx5_cmd_mailbox *mlx5_alloc_cmd_mailbox_chain(struct mlx5_core_dev *dev, void mlx5_free_cmd_mailbox_chain(struct mlx5_core_dev *dev, struct mlx5_cmd_mailbox *head); int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, - struct mlx5_create_srq_mbox_in *in, int inlen); + struct mlx5_create_srq_mbox_in *in, int inlen, + int is_xrc); int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq); int mlx5_core_query_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, struct mlx5_query_srq_mbox_out *out); diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index b27e9f6e090a..dbe2b32c0539 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -2022,12 +2022,9 @@ struct mlx5_ifc_srqc_bits { u8 reserved_9[0x40]; - u8 db_record_addr_h[0x20]; - - u8 db_record_addr_l[0x1e]; - u8 reserved_10[0x2]; + u8 dbr_addr[0x40]; - u8 reserved_11[0x80]; + u8 reserved_10[0x80]; }; enum { @@ -4167,6 +4164,13 @@ struct mlx5_ifc_modify_rmp_out_bits { u8 reserved_1[0x40]; }; +struct mlx5_ifc_rmp_bitmask_bits { + u8 reserved[0x20]; + + u8 reserved1[0x1f]; + u8 lwm[0x1]; +}; + struct mlx5_ifc_modify_rmp_in_bits { u8 opcode[0x10]; u8 reserved_0[0x10]; @@ -4180,7 +4184,7 @@ struct mlx5_ifc_modify_rmp_in_bits { u8 reserved_3[0x20]; - u8 modify_bitmask[0x40]; + struct mlx5_ifc_rmp_bitmask_bits bitmask; u8 reserved_4[0x40]; -- cgit v1.2.3 From d18a9470f89727f870db944a36223bf1bb15bdc1 Mon Sep 17 00:00:00 2001 From: Majd Dibbiny Date: Thu, 4 Jun 2015 19:30:40 +0300 Subject: net/mlx5_core: Make the vport helpers available for the IB driver too Move the vport header file to be under include/linux/mlx5, such that the mlx5 IB can use it as well. Also add nic_ prefix to the vport NIC commands to differeniate between HCA vport commands and NIC vport commands. Signed-off-by: Majd Dibbiny Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/vport.c | 6 ++-- drivers/net/ethernet/mellanox/mlx5/core/vport.h | 41 ----------------------- include/linux/mlx5/vport.h | 41 +++++++++++++++++++++++ 5 files changed, 47 insertions(+), 45 deletions(-) delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/vport.h create mode 100644 include/linux/mlx5/vport.h (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index cbb3c7cb53f7..e9edb7210de1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -35,7 +35,7 @@ #include #include #include -#include "vport.h" +#include #include "wq.h" #include "transobj.h" #include "mlx5_core.h" diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 1b592913d4d7..edba09cca600 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1715,7 +1715,7 @@ static void mlx5e_set_netdev_dev_addr(struct net_device *netdev) { struct mlx5e_priv *priv = netdev_priv(netdev); - mlx5_query_vport_mac_address(priv->mdev, netdev->dev_addr); + mlx5_query_nic_vport_mac_address(priv->mdev, netdev->dev_addr); } static void mlx5e_build_netdev(struct net_device *netdev) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index ba374b9a6c87..32c4e03f6d3c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -33,7 +33,7 @@ #include #include #include -#include "vport.h" +#include #include "mlx5_core.h" u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod) @@ -55,8 +55,9 @@ u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod) return MLX5_GET(query_vport_state_out, out, state); } +EXPORT_SYMBOL(mlx5_query_vport_state); -void mlx5_query_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr) +void mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr) { u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)]; u32 *out; @@ -82,3 +83,4 @@ void mlx5_query_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr) kvfree(out); } +EXPORT_SYMBOL(mlx5_query_nic_vport_mac_address); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.h b/drivers/net/ethernet/mellanox/mlx5/core/vport.h deleted file mode 100644 index c05ca2c3419d..000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __MLX5_VPORT_H__ -#define __MLX5_VPORT_H__ - -#include - -u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod); -void mlx5_query_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr); - -#endif /* __MLX5_VPORT_H__ */ diff --git a/include/linux/mlx5/vport.h b/include/linux/mlx5/vport.h new file mode 100644 index 000000000000..99d0e9f85432 --- /dev/null +++ b/include/linux/mlx5/vport.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __MLX5_VPORT_H__ +#define __MLX5_VPORT_H__ + +#include + +u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod); +void mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr); + +#endif /* __MLX5_VPORT_H__ */ -- cgit v1.2.3 From 707c4602cda6624940761b66a4119f1909492385 Mon Sep 17 00:00:00 2001 From: Majd Dibbiny Date: Thu, 4 Jun 2015 19:30:41 +0300 Subject: net/mlx5_core: Add new query HCA vport commands Added the implementation for the following commands: 1. QUERY_HCA_VPORT_GID 2. QUERY_HCA_VPORT_PKEY 3. QUERY_HCA_VPORT_CONTEXT They will be needed when we move to work with ISSI > 0 in the IB driver too. Signed-off-by: Majd Dibbiny Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 4 +- drivers/net/ethernet/mellanox/mlx5/core/main.c | 10 +- drivers/net/ethernet/mellanox/mlx5/core/vport.c | 259 +++++++++++++++++++++++ include/linux/mlx5/device.h | 13 ++ include/linux/mlx5/driver.h | 45 ++++ include/linux/mlx5/mlx5_ifc.h | 23 +- include/linux/mlx5/vport.h | 14 ++ 7 files changed, 349 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 07540f732df1..26a68b8af2c5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_MLX5_CORE) += mlx5_core.o mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \ - mad.o transobj.o -mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o flow_table.o vport.o \ + mad.o transobj.o vport.o +mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o flow_table.o \ en_main.o en_flow_table.o en_ethtool.o en_tx.o en_rx.o \ en_txrx.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 11c7216a2517..58354122dfe4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -284,14 +284,6 @@ static u16 to_fw_pkey_sz(u32 size) } } -static u16 to_sw_pkey_sz(int pkey_sz) -{ - if (pkey_sz > MLX5_MAX_LOG_PKEY_TABLE) - return 0; - - return MLX5_MIN_PKEY_TABLE_SIZE << pkey_sz; -} - int mlx5_core_get_caps(struct mlx5_core_dev *dev, enum mlx5_cap_type cap_type, enum mlx5_cap_mode cap_mode) { @@ -386,7 +378,7 @@ static int handle_hca_cap(struct mlx5_core_dev *dev) MLX5_ST_SZ_BYTES(cmd_hca_cap)); mlx5_core_dbg(dev, "Current Pkey table size %d Setting new size %d\n", - to_sw_pkey_sz(MLX5_CAP_GEN(dev, pkey_table_size)), + mlx5_to_sw_pkey_sz(MLX5_CAP_GEN(dev, pkey_table_size)), 128); /* we limit the size of the pkey table to 128 entries for now */ MLX5_SET(cmd_hca_cap, set_hca_cap, pkey_table_size, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index 32c4e03f6d3c..20150ffa8b16 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -84,3 +84,262 @@ void mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr) kvfree(out); } EXPORT_SYMBOL(mlx5_query_nic_vport_mac_address); + +int mlx5_query_hca_vport_gid(struct mlx5_core_dev *dev, u8 other_vport, + u8 port_num, u16 vf_num, u16 gid_index, + union ib_gid *gid) +{ + int in_sz = MLX5_ST_SZ_BYTES(query_hca_vport_gid_in); + int out_sz = MLX5_ST_SZ_BYTES(query_hca_vport_gid_out); + int is_group_manager; + void *out = NULL; + void *in = NULL; + union ib_gid *tmp; + int tbsz; + int nout; + int err; + + is_group_manager = MLX5_CAP_GEN(dev, vport_group_manager); + tbsz = mlx5_get_gid_table_len(MLX5_CAP_GEN(dev, gid_table_size)); + mlx5_core_dbg(dev, "vf_num %d, index %d, gid_table_size %d\n", + vf_num, gid_index, tbsz); + + if (gid_index > tbsz && gid_index != 0xffff) + return -EINVAL; + + if (gid_index == 0xffff) + nout = tbsz; + else + nout = 1; + + out_sz += nout * sizeof(*gid); + + in = kzalloc(in_sz, GFP_KERNEL); + out = kzalloc(out_sz, GFP_KERNEL); + if (!in || !out) { + err = -ENOMEM; + goto out; + } + + MLX5_SET(query_hca_vport_gid_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_VPORT_GID); + if (other_vport) { + if (is_group_manager) { + MLX5_SET(query_hca_vport_gid_in, in, vport_number, vf_num); + MLX5_SET(query_hca_vport_gid_in, in, other_vport, 1); + } else { + err = -EPERM; + goto out; + } + } + MLX5_SET(query_hca_vport_gid_in, in, gid_index, gid_index); + + if (MLX5_CAP_GEN(dev, num_ports) == 2) + MLX5_SET(query_hca_vport_gid_in, in, port_num, port_num); + + err = mlx5_cmd_exec(dev, in, in_sz, out, out_sz); + if (err) + goto out; + + err = mlx5_cmd_status_to_err_v2(out); + if (err) + goto out; + + tmp = out + MLX5_ST_SZ_BYTES(query_hca_vport_gid_out); + gid->global.subnet_prefix = tmp->global.subnet_prefix; + gid->global.interface_id = tmp->global.interface_id; + +out: + kfree(in); + kfree(out); + return err; +} +EXPORT_SYMBOL_GPL(mlx5_query_hca_vport_gid); + +int mlx5_query_hca_vport_pkey(struct mlx5_core_dev *dev, u8 other_vport, + u8 port_num, u16 vf_num, u16 pkey_index, + u16 *pkey) +{ + int in_sz = MLX5_ST_SZ_BYTES(query_hca_vport_pkey_in); + int out_sz = MLX5_ST_SZ_BYTES(query_hca_vport_pkey_out); + int is_group_manager; + void *out = NULL; + void *in = NULL; + void *pkarr; + int nout; + int tbsz; + int err; + int i; + + is_group_manager = MLX5_CAP_GEN(dev, vport_group_manager); + + tbsz = mlx5_to_sw_pkey_sz(MLX5_CAP_GEN(dev, pkey_table_size)); + if (pkey_index > tbsz && pkey_index != 0xffff) + return -EINVAL; + + if (pkey_index == 0xffff) + nout = tbsz; + else + nout = 1; + + out_sz += nout * MLX5_ST_SZ_BYTES(pkey); + + in = kzalloc(in_sz, GFP_KERNEL); + out = kzalloc(out_sz, GFP_KERNEL); + if (!in || !out) { + err = -ENOMEM; + goto out; + } + + MLX5_SET(query_hca_vport_pkey_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_VPORT_PKEY); + if (other_vport) { + if (is_group_manager) { + MLX5_SET(query_hca_vport_pkey_in, in, vport_number, vf_num); + MLX5_SET(query_hca_vport_pkey_in, in, other_vport, 1); + } else { + err = -EPERM; + goto out; + } + } + MLX5_SET(query_hca_vport_pkey_in, in, pkey_index, pkey_index); + + if (MLX5_CAP_GEN(dev, num_ports) == 2) + MLX5_SET(query_hca_vport_pkey_in, in, port_num, port_num); + + err = mlx5_cmd_exec(dev, in, in_sz, out, out_sz); + if (err) + goto out; + + err = mlx5_cmd_status_to_err_v2(out); + if (err) + goto out; + + pkarr = MLX5_ADDR_OF(query_hca_vport_pkey_out, out, pkey); + for (i = 0; i < nout; i++, pkey++, pkarr += MLX5_ST_SZ_BYTES(pkey)) + *pkey = MLX5_GET_PR(pkey, pkarr, pkey); + +out: + kfree(in); + kfree(out); + return err; +} +EXPORT_SYMBOL_GPL(mlx5_query_hca_vport_pkey); + +int mlx5_query_hca_vport_context(struct mlx5_core_dev *dev, + u8 other_vport, u8 port_num, + u16 vf_num, + struct mlx5_hca_vport_context *rep) +{ + int out_sz = MLX5_ST_SZ_BYTES(query_hca_vport_context_out); + int in[MLX5_ST_SZ_DW(query_hca_vport_context_in)]; + int is_group_manager; + void *out; + void *ctx; + int err; + + is_group_manager = MLX5_CAP_GEN(dev, vport_group_manager); + + memset(in, 0, sizeof(in)); + out = kzalloc(out_sz, GFP_KERNEL); + if (!out) + return -ENOMEM; + + MLX5_SET(query_hca_vport_context_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_VPORT_CONTEXT); + + if (other_vport) { + if (is_group_manager) { + MLX5_SET(query_hca_vport_context_in, in, other_vport, 1); + MLX5_SET(query_hca_vport_context_in, in, vport_number, vf_num); + } else { + err = -EPERM; + goto ex; + } + } + + if (MLX5_CAP_GEN(dev, num_ports) == 2) + MLX5_SET(query_hca_vport_context_in, in, port_num, port_num); + + err = mlx5_cmd_exec(dev, in, sizeof(in), out, out_sz); + if (err) + goto ex; + err = mlx5_cmd_status_to_err_v2(out); + if (err) + goto ex; + + ctx = MLX5_ADDR_OF(query_hca_vport_context_out, out, hca_vport_context); + rep->field_select = MLX5_GET_PR(hca_vport_context, ctx, field_select); + rep->sm_virt_aware = MLX5_GET_PR(hca_vport_context, ctx, sm_virt_aware); + rep->has_smi = MLX5_GET_PR(hca_vport_context, ctx, has_smi); + rep->has_raw = MLX5_GET_PR(hca_vport_context, ctx, has_raw); + rep->policy = MLX5_GET_PR(hca_vport_context, ctx, vport_state_policy); + rep->phys_state = MLX5_GET_PR(hca_vport_context, ctx, + port_physical_state); + rep->vport_state = MLX5_GET_PR(hca_vport_context, ctx, vport_state); + rep->port_physical_state = MLX5_GET_PR(hca_vport_context, ctx, + port_physical_state); + rep->port_guid = MLX5_GET64_PR(hca_vport_context, ctx, port_guid); + rep->node_guid = MLX5_GET64_PR(hca_vport_context, ctx, node_guid); + rep->cap_mask1 = MLX5_GET_PR(hca_vport_context, ctx, cap_mask1); + rep->cap_mask1_perm = MLX5_GET_PR(hca_vport_context, ctx, + cap_mask1_field_select); + rep->cap_mask2 = MLX5_GET_PR(hca_vport_context, ctx, cap_mask2); + rep->cap_mask2_perm = MLX5_GET_PR(hca_vport_context, ctx, + cap_mask2_field_select); + rep->lid = MLX5_GET_PR(hca_vport_context, ctx, lid); + rep->init_type_reply = MLX5_GET_PR(hca_vport_context, ctx, + init_type_reply); + rep->lmc = MLX5_GET_PR(hca_vport_context, ctx, lmc); + rep->subnet_timeout = MLX5_GET_PR(hca_vport_context, ctx, + subnet_timeout); + rep->sm_lid = MLX5_GET_PR(hca_vport_context, ctx, sm_lid); + rep->sm_sl = MLX5_GET_PR(hca_vport_context, ctx, sm_sl); + rep->qkey_violation_counter = MLX5_GET_PR(hca_vport_context, ctx, + qkey_violation_counter); + rep->pkey_violation_counter = MLX5_GET_PR(hca_vport_context, ctx, + pkey_violation_counter); + rep->grh_required = MLX5_GET_PR(hca_vport_context, ctx, grh_required); + rep->sys_image_guid = MLX5_GET64_PR(hca_vport_context, ctx, + system_image_guid); + +ex: + kfree(out); + return err; +} +EXPORT_SYMBOL_GPL(mlx5_query_hca_vport_context); + +int mlx5_query_hca_vport_system_image_guid(struct mlx5_core_dev *dev, + __be64 *sys_image_guid) +{ + struct mlx5_hca_vport_context *rep; + int err; + + rep = kzalloc(sizeof(*rep), GFP_KERNEL); + if (!rep) + return -ENOMEM; + + err = mlx5_query_hca_vport_context(dev, 0, 1, 0, rep); + if (!err) + *sys_image_guid = rep->sys_image_guid; + + kfree(rep); + return err; +} +EXPORT_SYMBOL_GPL(mlx5_query_hca_vport_system_image_guid); + +int mlx5_query_hca_vport_node_guid(struct mlx5_core_dev *dev, + u64 *node_guid) +{ + struct mlx5_hca_vport_context *rep; + int err; + + rep = kzalloc(sizeof(*rep), GFP_KERNEL); + if (!rep) + return -ENOMEM; + + err = mlx5_query_hca_vport_context(dev, 0, 1, 0, rep); + if (!err) + *node_guid = rep->node_guid; + + kfree(rep); + return err; +} +EXPORT_SYMBOL_GPL(mlx5_query_hca_vport_node_guid); diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index b288c538347a..b2c43508a737 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -99,6 +99,12 @@ __mlx5_mask(typ, fld)) #define MLX5_GET64(typ, p, fld) be64_to_cpu(*((__be64 *)(p) + __mlx5_64_off(typ, fld))) +#define MLX5_GET64_PR(typ, p, fld) ({ \ + u64 ___t = MLX5_GET64(typ, p, fld); \ + pr_debug(#fld " = 0x%llx\n", ___t); \ + ___t; \ +}) + enum { MLX5_MAX_COMMANDS = 32, MLX5_CMD_DATA_BLOCK_SIZE = 512, @@ -1172,4 +1178,11 @@ enum { MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR = 0x40, }; +static inline u16 mlx5_to_sw_pkey_sz(int pkey_sz) +{ + if (pkey_sz > MLX5_MAX_LOG_PKEY_TABLE) + return 0; + return MLX5_MIN_PKEY_TABLE_SIZE << pkey_sz; +} + #endif /* MLX5_DEVICE_H */ diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index ba9f212c94bb..8ab8b8af5c32 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -553,6 +553,41 @@ struct mlx5_pas { u8 log_sz; }; +enum port_state_policy { + MLX5_AAA_000 +}; + +enum phy_port_state { + MLX5_AAA_111 +}; + +struct mlx5_hca_vport_context { + u32 field_select; + bool sm_virt_aware; + bool has_smi; + bool has_raw; + enum port_state_policy policy; + enum phy_port_state phys_state; + enum ib_port_state vport_state; + u8 port_physical_state; + u64 sys_image_guid; + u64 port_guid; + u64 node_guid; + u32 cap_mask1; + u32 cap_mask1_perm; + u32 cap_mask2; + u32 cap_mask2_perm; + u16 lid; + u8 init_type_reply; /* bitmask: see ib spec 14.2.5.6 InitTypeReply */ + u8 lmc; + u8 subnet_timeout; + u16 sm_lid; + u8 sm_sl; + u16 qkey_violation_counter; + u16 pkey_violation_counter; + bool grh_required; +}; + static inline void *mlx5_buf_offset(struct mlx5_buf *buf, int offset) { return buf->direct.buf + offset; @@ -792,4 +827,14 @@ struct mlx5_profile { } mr_cache[MAX_MR_CACHE_ENTRIES]; }; +static inline int mlx5_get_gid_table_len(u16 param) +{ + if (param > 4) { + pr_warn("gid table length is zero\n"); + return 0; + } + + return 8 * (1 << param); +} + #endif /* MLX5_DRIVER_H */ diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index dbe2b32c0539..f06d054ad021 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -2221,12 +2221,15 @@ struct mlx5_ifc_hca_vport_context_bits { u8 has_smi[0x1]; u8 has_raw[0x1]; u8 grh_required[0x1]; - u8 reserved_1[0x10]; - u8 port_state_policy[0x4]; - u8 phy_port_state[0x4]; + u8 reserved_1[0xc]; + u8 port_physical_state[0x4]; + u8 vport_state_policy[0x4]; + u8 port_state[0x4]; u8 vport_state[0x4]; - u8 reserved_2[0x60]; + u8 reserved_2[0x20]; + + u8 system_image_guid[0x40]; u8 port_guid[0x40]; @@ -3490,7 +3493,8 @@ struct mlx5_ifc_query_hca_vport_pkey_in_bits { u8 op_mod[0x10]; u8 other_vport[0x1]; - u8 reserved_2[0xf]; + u8 reserved_2[0xb]; + u8 port_num[0x4]; u8 vport_number[0x10]; u8 reserved_3[0x10]; @@ -3519,7 +3523,8 @@ struct mlx5_ifc_query_hca_vport_gid_in_bits { u8 op_mod[0x10]; u8 other_vport[0x1]; - u8 reserved_2[0xf]; + u8 reserved_2[0xb]; + u8 port_num[0x4]; u8 vport_number[0x10]; u8 reserved_3[0x10]; @@ -3545,7 +3550,8 @@ struct mlx5_ifc_query_hca_vport_context_in_bits { u8 op_mod[0x10]; u8 other_vport[0x1]; - u8 reserved_2[0xf]; + u8 reserved_2[0xb]; + u8 port_num[0x4]; u8 vport_number[0x10]; u8 reserved_3[0x20]; @@ -4243,7 +4249,8 @@ struct mlx5_ifc_modify_hca_vport_context_in_bits { u8 op_mod[0x10]; u8 other_vport[0x1]; - u8 reserved_2[0xf]; + u8 reserved_2[0xb]; + u8 port_num[0x4]; u8 vport_number[0x10]; u8 reserved_3[0x20]; diff --git a/include/linux/mlx5/vport.h b/include/linux/mlx5/vport.h index 99d0e9f85432..67882a834efb 100644 --- a/include/linux/mlx5/vport.h +++ b/include/linux/mlx5/vport.h @@ -37,5 +37,19 @@ u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod); void mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev, u8 *addr); +int mlx5_query_hca_vport_gid(struct mlx5_core_dev *dev, u8 other_vport, + u8 port_num, u16 vf_num, u16 gid_index, + union ib_gid *gid); +int mlx5_query_hca_vport_pkey(struct mlx5_core_dev *dev, u8 other_vport, + u8 port_num, u16 vf_num, u16 pkey_index, + u16 *pkey); +int mlx5_query_hca_vport_context(struct mlx5_core_dev *dev, + u8 other_vport, u8 port_num, + u16 vf_num, + struct mlx5_hca_vport_context *rep); +int mlx5_query_hca_vport_system_image_guid(struct mlx5_core_dev *dev, + __be64 *sys_image_guid); +int mlx5_query_hca_vport_node_guid(struct mlx5_core_dev *dev, + u64 *node_guid); #endif /* __MLX5_VPORT_H__ */ -- cgit v1.2.3 From 211e6c80e5a68ef39a81484583e8efbf9774627d Mon Sep 17 00:00:00 2001 From: Majd Dibbiny Date: Thu, 4 Jun 2015 19:30:42 +0300 Subject: net/mlx5_core: Get vendor-id using the query adapter command Add two wrapper functions to the query adapter command: 1. mlx5_query_board_id -- replaces the old mlx5_cmd_query_adapter. 2. mlx5_core_query_vendor_id -- retrieves the vendor_id from the query_adapter command. Signed-off-by: Majd Dibbiny Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 59 ++++++++++++++++------ drivers/net/ethernet/mellanox/mlx5/core/main.c | 4 +- .../net/ethernet/mellanox/mlx5/core/mlx5_core.h | 2 +- include/linux/mlx5/driver.h | 1 + include/linux/mlx5/mlx5_ifc.h | 7 ++- 5 files changed, 53 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 801ccadd709a..ba87442ef776 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -35,34 +35,63 @@ #include #include "mlx5_core.h" -int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev) +int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev, u32 *out, int outlen) { - struct mlx5_cmd_query_adapter_mbox_out *out; - struct mlx5_cmd_query_adapter_mbox_in in; + u32 in[MLX5_ST_SZ_DW(query_adapter_in)]; + + memset(in, 0, sizeof(in)); + + MLX5_SET(query_adapter_in, in, opcode, MLX5_CMD_OP_QUERY_ADAPTER); + + return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, outlen); +} + +int mlx5_query_board_id(struct mlx5_core_dev *dev) +{ + u32 *out; + int outlen = MLX5_ST_SZ_BYTES(query_adapter_out); int err; - out = kzalloc(sizeof(*out), GFP_KERNEL); + out = kzalloc(outlen, GFP_KERNEL); if (!out) return -ENOMEM; - memset(&in, 0, sizeof(in)); - in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_ADAPTER); - err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out)); + err = mlx5_cmd_query_adapter(dev, out, outlen); if (err) - goto out_out; + goto out; - if (out->hdr.status) { - err = mlx5_cmd_status_to_err(&out->hdr); - goto out_out; - } + memcpy(dev->board_id, + MLX5_ADDR_OF(query_adapter_out, out, + query_adapter_struct.vsd_contd_psid), + MLX5_FLD_SZ_BYTES(query_adapter_out, + query_adapter_struct.vsd_contd_psid)); - memcpy(dev->board_id, out->vsd_psid, sizeof(out->vsd_psid)); - -out_out: +out: kfree(out); + return err; +} + +int mlx5_core_query_vendor_id(struct mlx5_core_dev *mdev, u32 *vendor_id) +{ + u32 *out; + int outlen = MLX5_ST_SZ_BYTES(query_adapter_out); + int err; + + out = kzalloc(outlen, GFP_KERNEL); + if (!out) + return -ENOMEM; + err = mlx5_cmd_query_adapter(mdev, out, outlen); + if (err) + goto out; + + *vendor_id = MLX5_GET(query_adapter_out, out, + query_adapter_struct.ieee_vendor_id); +out: + kfree(out); return err; } +EXPORT_SYMBOL(mlx5_core_query_vendor_id); int mlx5_query_hca_caps(struct mlx5_core_dev *dev) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 58354122dfe4..afad529838de 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -768,9 +768,9 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) goto err_stop_poll; } - err = mlx5_cmd_query_adapter(dev); + err = mlx5_query_board_id(dev); if (err) { - dev_err(&pdev->dev, "query adapter failed\n"); + dev_err(&pdev->dev, "query board id failed\n"); goto err_stop_poll; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 6983c1047255..fc88ecaecb4b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -78,7 +78,7 @@ static inline int mlx5_cmd_exec_check_status(struct mlx5_core_dev *dev, u32 *in, } int mlx5_query_hca_caps(struct mlx5_core_dev *dev); -int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev); +int mlx5_query_board_id(struct mlx5_core_dev *dev); int mlx5_cmd_init_hca(struct mlx5_core_dev *dev); int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 8ab8b8af5c32..b90fb9336d21 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -817,6 +817,7 @@ struct mlx5_interface { void *mlx5_get_protocol_dev(struct mlx5_core_dev *mdev, int protocol); int mlx5_register_interface(struct mlx5_interface *intf); void mlx5_unregister_interface(struct mlx5_interface *intf); +int mlx5_core_query_vendor_id(struct mlx5_core_dev *mdev, u32 *vendor_id); struct mlx5_profile { u64 mask; diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index f06d054ad021..6d2f6fee041c 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -2470,9 +2470,12 @@ union mlx5_ifc_cong_control_roce_ecn_auto_bits { }; struct mlx5_ifc_query_adapter_param_block_bits { - u8 reserved_0[0xe0]; + u8 reserved_0[0xc0]; - u8 reserved_1[0x10]; + u8 reserved_1[0x8]; + u8 ieee_vendor_id[0x18]; + + u8 reserved_2[0x10]; u8 vsd_vendor_id[0x10]; u8 vsd[208][0x8]; -- cgit v1.2.3 From e760152d08da78aa160e68ac90bf8f3f10aff462 Mon Sep 17 00:00:00 2001 From: Majd Dibbiny Date: Thu, 4 Jun 2015 19:30:43 +0300 Subject: net/mlx5_core: Use port number in the query port mtu helpers Extend the function prototypes for max and operational mtu to take the local port number. In the Ethernet driver is this hard coded to one, since ConnectX4 Ethernet devices are always function-per-port. The IB driver also serves older devices (ConnectIB) which isn't such, and hence the part can vary. Signed-off-by: Majd Dibbiny Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/port.c | 15 +++++++++------ include/linux/mlx5/driver.h | 6 ++++-- 3 files changed, 15 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index edba09cca600..7348c5173aa9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1386,7 +1386,7 @@ int mlx5e_open_locked(struct net_device *netdev) return err; } - err = mlx5_query_port_oper_mtu(mdev, &actual_mtu); + err = mlx5_query_port_oper_mtu(mdev, &actual_mtu, 1); if (err) { netdev_err(netdev, "%s: mlx5_query_port_oper_mtu failed %d\n", __func__, err); @@ -1614,7 +1614,7 @@ static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu) int max_mtu; int err = 0; - err = mlx5_query_port_max_mtu(mdev, &max_mtu); + err = mlx5_query_port_max_mtu(mdev, &max_mtu, 1); if (err) return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 7d3d0f9f328d..d9498aae5ab5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -213,7 +213,8 @@ int mlx5_query_port_status(struct mlx5_core_dev *dev, u8 *status) } static int mlx5_query_port_mtu(struct mlx5_core_dev *dev, - int *admin_mtu, int *max_mtu, int *oper_mtu) + int *admin_mtu, int *max_mtu, int *oper_mtu, + u8 local_port) { u32 in[MLX5_ST_SZ_DW(pmtu_reg)]; u32 out[MLX5_ST_SZ_DW(pmtu_reg)]; @@ -221,7 +222,7 @@ static int mlx5_query_port_mtu(struct mlx5_core_dev *dev, memset(in, 0, sizeof(in)); - MLX5_SET(pmtu_reg, in, local_port, 1); + MLX5_SET(pmtu_reg, in, local_port, local_port); err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), MLX5_REG_PMTU, 0, 0); @@ -253,14 +254,16 @@ int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu) } EXPORT_SYMBOL_GPL(mlx5_set_port_mtu); -int mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu) +int mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu, + u8 local_port) { - return mlx5_query_port_mtu(dev, NULL, max_mtu, NULL); + return mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, local_port); } EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu); -int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu) +int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu, + u8 local_port) { - return mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu); + return mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, local_port); } EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index b90fb9336d21..cd09784b6999 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -751,8 +751,10 @@ int mlx5_set_port_status(struct mlx5_core_dev *dev, int mlx5_query_port_status(struct mlx5_core_dev *dev, u8 *status); int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu); -int mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu); -int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu); +int mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu, + u8 local_port); +int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu, + u8 local_port); int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq); void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq); -- cgit v1.2.3 From a05bdefa4081d43f9c86c3bb693d0492a21590da Mon Sep 17 00:00:00 2001 From: Majd Dibbiny Date: Thu, 4 Jun 2015 19:30:44 +0300 Subject: net/mlx5_core: Use port number when querying port ptys Until now, mlx5_query_port_ptys always queried port number one. Added new argument in the function's prototype so we can also query the second port. This will be needed when thr helper will be invoked from the IB driver on non FPP (Function-Per-Port) devices. Signed-off-by: Majd Dibbiny Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/port.c | 8 ++++---- include/linux/mlx5/driver.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index de7aec8abca1..388938482ff9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -543,7 +543,7 @@ static int mlx5e_get_settings(struct net_device *netdev, u32 eth_proto_oper; int err; - err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN); + err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1); if (err) { netdev_err(netdev, "%s: query port ptys failed: %d\n", diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index d9498aae5ab5..cbbce40d853c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -104,13 +104,13 @@ int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps) EXPORT_SYMBOL_GPL(mlx5_set_port_caps); int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys, - int ptys_size, int proto_mask) + int ptys_size, int proto_mask, u8 local_port) { u32 in[MLX5_ST_SZ_DW(ptys_reg)]; int err; memset(in, 0, sizeof(in)); - MLX5_SET(ptys_reg, in, local_port, 1); + MLX5_SET(ptys_reg, in, local_port, local_port); MLX5_SET(ptys_reg, in, proto_mask, proto_mask); err = mlx5_core_access_reg(dev, in, sizeof(in), ptys, @@ -126,7 +126,7 @@ int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev, u32 out[MLX5_ST_SZ_DW(ptys_reg)]; int err; - err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask); + err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1); if (err) return err; @@ -145,7 +145,7 @@ int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev, u32 out[MLX5_ST_SZ_DW(ptys_reg)]; int err; - err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask); + err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1); if (err) return err; diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index cd09784b6999..e4b814f64014 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -739,7 +739,7 @@ int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in, int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps); int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys, - int ptys_size, int proto_mask); + int ptys_size, int proto_mask, u8 local_port); int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev, u32 *proto_cap, int proto_mask); int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev, -- cgit v1.2.3 From a124d13ef59e09941fc0924fd7c29ae6d7cd77a3 Mon Sep 17 00:00:00 2001 From: Majd Dibbiny Date: Thu, 4 Jun 2015 19:30:45 +0300 Subject: net/mlx5_core: Add more query port helpers Add the following helpers: 1. mlx5_query_port_proto_oper -- queries the port speed port mask 2. mlx5_query_port_link_width_oper - queries the port link with bitmask 3. mlx5_query_port_vl_hw_cap - queries the Virtual Lanes supported on this port These helpers will be used from the IB driver when working in ISSI > 0 mode. Signed-off-by: Majd Dibbiny Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/port.c | 67 ++++++++++++++++++++++++++ include/linux/mlx5/driver.h | 8 +++ 2 files changed, 75 insertions(+) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index cbbce40d853c..619d3baf19ea 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -158,6 +158,42 @@ int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev, } EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin); +int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev, + u8 *link_width_oper, u8 local_port) +{ + u32 out[MLX5_ST_SZ_DW(ptys_reg)]; + int err; + + err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB, local_port); + if (err) + return err; + + *link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx5_query_port_link_width_oper); + +int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev, + u8 *proto_oper, int proto_mask, + u8 local_port) +{ + u32 out[MLX5_ST_SZ_DW(ptys_reg)]; + int err; + + err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, local_port); + if (err) + return err; + + if (proto_mask == MLX5_PTYS_EN) + *proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); + else + *proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx5_query_port_proto_oper); + int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin, int proto_mask) { @@ -267,3 +303,34 @@ int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu, return mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, local_port); } EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu); + +static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc, + int pvlc_size, u8 local_port) +{ + u32 in[MLX5_ST_SZ_DW(pvlc_reg)]; + int err; + + memset(in, 0, sizeof(in)); + MLX5_SET(ptys_reg, in, local_port, local_port); + + err = mlx5_core_access_reg(dev, in, sizeof(in), pvlc, + pvlc_size, MLX5_REG_PVLC, 0, 0); + + return err; +} + +int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev, + u8 *vl_hw_cap, u8 local_port) +{ + u32 out[MLX5_ST_SZ_DW(pvlc_reg)]; + int err; + + err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port); + if (err) + return err; + + *vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index e4b814f64014..6093bde16b94 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -107,6 +107,7 @@ enum { MLX5_REG_PUDE = 0x5009, MLX5_REG_PMPE = 0x5010, MLX5_REG_PELC = 0x500e, + MLX5_REG_PVLC = 0x500f, MLX5_REG_PMLP = 0, /* TBD */ MLX5_REG_NODE_DESC = 0x6001, MLX5_REG_HOST_ENDIANNESS = 0x7004, @@ -744,6 +745,11 @@ int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev, u32 *proto_cap, int proto_mask); int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev, u32 *proto_admin, int proto_mask); +int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev, + u8 *link_width_oper, u8 local_port); +int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev, + u8 *proto_oper, int proto_mask, + u8 local_port); int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin, int proto_mask); int mlx5_set_port_status(struct mlx5_core_dev *dev, @@ -755,6 +761,8 @@ int mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu, u8 local_port); int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu, u8 local_port); +int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev, + u8 *vl_hw_cap, u8 local_port); int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq); void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq); -- cgit v1.2.3 From 90c337da1524863838658078ec34241f45d8394d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 6 Jun 2015 21:17:57 -0700 Subject: inet: add IP_BIND_ADDRESS_NO_PORT to overcome bind(0) limitations When an application needs to force a source IP on an active TCP socket it has to use bind(IP, port=x). As most applications do not want to deal with already used ports, x is often set to 0, meaning the kernel is in charge to find an available port. But kernel does not know yet if this socket is going to be a listener or be connected. It has very limited choices (no full knowledge of final 4-tuple for a connect()) With limited ephemeral port range (about 32K ports), it is very easy to fill the space. This patch adds a new SOL_IP socket option, asking kernel to ignore the 0 port provided by application in bind(IP, port=0) and only remember the given IP address. The port will be automatically chosen at connect() time, in a way that allows sharing a source port as long as the 4-tuples are unique. This new feature is available for both IPv4 and IPv6 (Thanks Neal) Tested: Wrote a test program and checked its behavior on IPv4 and IPv6. strace(1) shows sequences of bind(IP=127.0.0.2, port=0) followed by connect(). Also getsockname() show that the port is still 0 right after bind() but properly allocated after connect(). socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 5 setsockopt(5, SOL_IP, IP_BIND_ADDRESS_NO_PORT, [1], 4) = 0 bind(5, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("127.0.0.2")}, 16) = 0 getsockname(5, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("127.0.0.2")}, [16]) = 0 connect(5, {sa_family=AF_INET, sin_port=htons(53174), sin_addr=inet_addr("127.0.0.3")}, 16) = 0 getsockname(5, {sa_family=AF_INET, sin_port=htons(38050), sin_addr=inet_addr("127.0.0.2")}, [16]) = 0 IPv6 test : socket(PF_INET6, SOCK_STREAM, IPPROTO_IP) = 7 setsockopt(7, SOL_IP, IP_BIND_ADDRESS_NO_PORT, [1], 4) = 0 bind(7, {sa_family=AF_INET6, sin6_port=htons(0), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0 getsockname(7, {sa_family=AF_INET6, sin6_port=htons(0), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 0 connect(7, {sa_family=AF_INET6, sin6_port=htons(57300), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0 getsockname(7, {sa_family=AF_INET6, sin6_port=htons(60964), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 0 I was able to bind()/connect() a million concurrent IPv4 sockets, instead of ~32000 before patch. lpaa23:~# ulimit -n 1000010 lpaa23:~# ./bind --connect --num-flows=1000000 & 1000000 sockets lpaa23:~# grep TCP /proc/net/sockstat TCP: inuse 2000063 orphan 0 tw 47 alloc 2000157 mem 66 Check that a given source port is indeed used by many different connections : lpaa23:~# ss -t src :40000 | head -10 State Recv-Q Send-Q Local Address:Port Peer Address:Port ESTAB 0 0 127.0.0.2:40000 127.0.202.33:44983 ESTAB 0 0 127.0.0.2:40000 127.2.27.240:44983 ESTAB 0 0 127.0.0.2:40000 127.2.98.5:44983 ESTAB 0 0 127.0.0.2:40000 127.0.124.196:44983 ESTAB 0 0 127.0.0.2:40000 127.2.139.38:44983 ESTAB 0 0 127.0.0.2:40000 127.1.59.80:44983 ESTAB 0 0 127.0.0.2:40000 127.3.6.228:44983 ESTAB 0 0 127.0.0.2:40000 127.0.38.53:44983 ESTAB 0 0 127.0.0.2:40000 127.1.197.10:44983 Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/inet_sock.h | 1 + include/uapi/linux/in.h | 1 + net/ipv4/af_inet.c | 3 ++- net/ipv4/ip_sockglue.c | 7 +++++++ net/ipv6/af_inet6.c | 3 ++- 5 files changed, 13 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index b6c3737da4e9..47eb67b08abd 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -187,6 +187,7 @@ struct inet_sock { transparent:1, mc_all:1, nodefrag:1; + __u8 bind_address_no_port:1; __u8 rcv_tos; __u8 convert_csum; int uc_index; diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h index 641338bef651..83d6236a2f08 100644 --- a/include/uapi/linux/in.h +++ b/include/uapi/linux/in.h @@ -112,6 +112,7 @@ struct in_addr { #define IP_MINTTL 21 #define IP_NODEFRAG 22 #define IP_CHECKSUM 23 +#define IP_BIND_ADDRESS_NO_PORT 24 /* IP_MTU_DISCOVER values */ #define IP_PMTUDISC_DONT 0 /* Never send DF frames */ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 6ad0f7a711c9..cc858ef44451 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -488,7 +488,8 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) inet->inet_saddr = 0; /* Use device */ /* Make sure we are allowed to bind here. */ - if (sk->sk_prot->get_port(sk, snum)) { + if ((snum || !inet->bind_address_no_port) && + sk->sk_prot->get_port(sk, snum)) { inet->inet_saddr = inet->inet_rcv_saddr = 0; err = -EADDRINUSE; goto out_release_sock; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 7cfb0893f263..04ae2992a5cd 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -582,6 +582,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, case IP_TRANSPARENT: case IP_MINTTL: case IP_NODEFRAG: + case IP_BIND_ADDRESS_NO_PORT: case IP_UNICAST_IF: case IP_MULTICAST_TTL: case IP_MULTICAST_ALL: @@ -732,6 +733,9 @@ static int do_ip_setsockopt(struct sock *sk, int level, } inet->nodefrag = val ? 1 : 0; break; + case IP_BIND_ADDRESS_NO_PORT: + inet->bind_address_no_port = val ? 1 : 0; + break; case IP_MTU_DISCOVER: if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_OMIT) goto e_inval; @@ -1324,6 +1328,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, case IP_NODEFRAG: val = inet->nodefrag; break; + case IP_BIND_ADDRESS_NO_PORT: + val = inet->bind_address_no_port; + break; case IP_MTU_DISCOVER: val = inet->pmtudisc; break; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index f3866c0b6cfe..7de52b65173f 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -362,7 +362,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) np->saddr = addr->sin6_addr; /* Make sure we are allowed to bind here. */ - if (sk->sk_prot->get_port(sk, snum)) { + if ((snum || !inet->bind_address_no_port) && + sk->sk_prot->get_port(sk, snum)) { inet_reset_saddr(sk); err = -EADDRINUSE; goto out; -- cgit v1.2.3 From d691f9e8d4405c334aa10d556e73c8bf44cb0e01 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Thu, 4 Jun 2015 10:11:54 -0700 Subject: bpf: allow programs to write to certain skb fields allow programs read/write skb->mark, tc_index fields and ((struct qdisc_skb_cb *)cb)->data. mark and tc_index are generically useful in TC. cb[0]-cb[4] are primarily used to pass arguments from one program to another called via bpf_tail_call() which can be seen in sockex3_kern.c example. All fields of 'struct __sk_buff' are readable to socket and tc_cls_act progs. mark, tc_index are writeable from tc_cls_act only. cb[0]-cb[4] are writeable by both sockets and tc_cls_act. Add verifier tests and improve sample code. Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/bpf.h | 3 +- include/uapi/linux/bpf.h | 2 + kernel/bpf/verifier.c | 37 +++++++++++++----- net/core/filter.c | 94 +++++++++++++++++++++++++++++++++++++++------ samples/bpf/sockex3_kern.c | 35 ++++++----------- samples/bpf/test_verifier.c | 84 +++++++++++++++++++++++++++++++++++++++- 6 files changed, 207 insertions(+), 48 deletions(-) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index ca854e5bb2f7..2235aee8096a 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -105,7 +105,8 @@ struct bpf_verifier_ops { */ bool (*is_valid_access)(int off, int size, enum bpf_access_type type); - u32 (*convert_ctx_access)(int dst_reg, int src_reg, int ctx_off, + u32 (*convert_ctx_access)(enum bpf_access_type type, int dst_reg, + int src_reg, int ctx_off, struct bpf_insn *insn); }; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 42aa19abab86..602f05b7a275 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -248,6 +248,8 @@ struct __sk_buff { __u32 priority; __u32 ingress_ifindex; __u32 ifindex; + __u32 tc_index; + __u32 cb[5]; }; #endif /* _UAPI__LINUX_BPF_H__ */ diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index cfd9a40b9a5a..039d866fd36a 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1692,6 +1692,8 @@ static int do_check(struct verifier_env *env) } } else if (class == BPF_STX) { + enum bpf_reg_type dst_reg_type; + if (BPF_MODE(insn->code) == BPF_XADD) { err = check_xadd(env, insn); if (err) @@ -1700,11 +1702,6 @@ static int do_check(struct verifier_env *env) continue; } - if (BPF_MODE(insn->code) != BPF_MEM || - insn->imm != 0) { - verbose("BPF_STX uses reserved fields\n"); - return -EINVAL; - } /* check src1 operand */ err = check_reg_arg(regs, insn->src_reg, SRC_OP); if (err) @@ -1714,6 +1711,8 @@ static int do_check(struct verifier_env *env) if (err) return err; + dst_reg_type = regs[insn->dst_reg].type; + /* check that memory (dst_reg + off) is writeable */ err = check_mem_access(env, insn->dst_reg, insn->off, BPF_SIZE(insn->code), BPF_WRITE, @@ -1721,6 +1720,15 @@ static int do_check(struct verifier_env *env) if (err) return err; + if (insn->imm == 0) { + insn->imm = dst_reg_type; + } else if (dst_reg_type != insn->imm && + (dst_reg_type == PTR_TO_CTX || + insn->imm == PTR_TO_CTX)) { + verbose("same insn cannot be used with different pointers\n"); + return -EINVAL; + } + } else if (class == BPF_ST) { if (BPF_MODE(insn->code) != BPF_MEM || insn->src_reg != BPF_REG_0) { @@ -1839,12 +1847,18 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env) for (i = 0; i < insn_cnt; i++, insn++) { if (BPF_CLASS(insn->code) == BPF_LDX && - (BPF_MODE(insn->code) != BPF_MEM || - insn->imm != 0)) { + (BPF_MODE(insn->code) != BPF_MEM || insn->imm != 0)) { verbose("BPF_LDX uses reserved fields\n"); return -EINVAL; } + if (BPF_CLASS(insn->code) == BPF_STX && + ((BPF_MODE(insn->code) != BPF_MEM && + BPF_MODE(insn->code) != BPF_XADD) || insn->imm != 0)) { + verbose("BPF_STX uses reserved fields\n"); + return -EINVAL; + } + if (insn[0].code == (BPF_LD | BPF_IMM | BPF_DW)) { struct bpf_map *map; struct fd f; @@ -1967,12 +1981,17 @@ static int convert_ctx_accesses(struct verifier_env *env) struct bpf_prog *new_prog; u32 cnt; int i; + enum bpf_access_type type; if (!env->prog->aux->ops->convert_ctx_access) return 0; for (i = 0; i < insn_cnt; i++, insn++) { - if (insn->code != (BPF_LDX | BPF_MEM | BPF_W)) + if (insn->code == (BPF_LDX | BPF_MEM | BPF_W)) + type = BPF_READ; + else if (insn->code == (BPF_STX | BPF_MEM | BPF_W)) + type = BPF_WRITE; + else continue; if (insn->imm != PTR_TO_CTX) { @@ -1982,7 +2001,7 @@ static int convert_ctx_accesses(struct verifier_env *env) } cnt = env->prog->aux->ops-> - convert_ctx_access(insn->dst_reg, insn->src_reg, + convert_ctx_access(type, insn->dst_reg, insn->src_reg, insn->off, insn_buf); if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf)) { verbose("bpf verifier is misconfigured\n"); diff --git a/net/core/filter.c b/net/core/filter.c index 36a69e33d76b..d271c06bf01f 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -46,6 +46,7 @@ #include #include #include +#include /** * sk_filter - run a packet through a socket filter @@ -1463,13 +1464,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id) } } -static bool sk_filter_is_valid_access(int off, int size, - enum bpf_access_type type) +static bool __is_valid_access(int off, int size, enum bpf_access_type type) { - /* only read is allowed */ - if (type != BPF_READ) - return false; - /* check bounds */ if (off < 0 || off >= sizeof(struct __sk_buff)) return false; @@ -1485,8 +1481,42 @@ static bool sk_filter_is_valid_access(int off, int size, return true; } -static u32 sk_filter_convert_ctx_access(int dst_reg, int src_reg, int ctx_off, - struct bpf_insn *insn_buf) +static bool sk_filter_is_valid_access(int off, int size, + enum bpf_access_type type) +{ + if (type == BPF_WRITE) { + switch (off) { + case offsetof(struct __sk_buff, cb[0]) ... + offsetof(struct __sk_buff, cb[4]): + break; + default: + return false; + } + } + + return __is_valid_access(off, size, type); +} + +static bool tc_cls_act_is_valid_access(int off, int size, + enum bpf_access_type type) +{ + if (type == BPF_WRITE) { + switch (off) { + case offsetof(struct __sk_buff, mark): + case offsetof(struct __sk_buff, tc_index): + case offsetof(struct __sk_buff, cb[0]) ... + offsetof(struct __sk_buff, cb[4]): + break; + default: + return false; + } + } + return __is_valid_access(off, size, type); +} + +static u32 bpf_net_convert_ctx_access(enum bpf_access_type type, int dst_reg, + int src_reg, int ctx_off, + struct bpf_insn *insn_buf) { struct bpf_insn *insn = insn_buf; @@ -1538,7 +1568,15 @@ static u32 sk_filter_convert_ctx_access(int dst_reg, int src_reg, int ctx_off, break; case offsetof(struct __sk_buff, mark): - return convert_skb_access(SKF_AD_MARK, dst_reg, src_reg, insn); + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4); + + if (type == BPF_WRITE) + *insn++ = BPF_STX_MEM(BPF_W, dst_reg, src_reg, + offsetof(struct sk_buff, mark)); + else + *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, + offsetof(struct sk_buff, mark)); + break; case offsetof(struct __sk_buff, pkt_type): return convert_skb_access(SKF_AD_PKTTYPE, dst_reg, src_reg, insn); @@ -1553,6 +1591,38 @@ static u32 sk_filter_convert_ctx_access(int dst_reg, int src_reg, int ctx_off, case offsetof(struct __sk_buff, vlan_tci): return convert_skb_access(SKF_AD_VLAN_TAG, dst_reg, src_reg, insn); + + case offsetof(struct __sk_buff, cb[0]) ... + offsetof(struct __sk_buff, cb[4]): + BUILD_BUG_ON(FIELD_SIZEOF(struct qdisc_skb_cb, data) < 20); + + ctx_off -= offsetof(struct __sk_buff, cb[0]); + ctx_off += offsetof(struct sk_buff, cb); + ctx_off += offsetof(struct qdisc_skb_cb, data); + if (type == BPF_WRITE) + *insn++ = BPF_STX_MEM(BPF_W, dst_reg, src_reg, ctx_off); + else + *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, ctx_off); + break; + + case offsetof(struct __sk_buff, tc_index): +#ifdef CONFIG_NET_SCHED + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, tc_index) != 2); + + if (type == BPF_WRITE) + *insn++ = BPF_STX_MEM(BPF_H, dst_reg, src_reg, + offsetof(struct sk_buff, tc_index)); + else + *insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg, + offsetof(struct sk_buff, tc_index)); + break; +#else + if (type == BPF_WRITE) + *insn++ = BPF_MOV64_REG(dst_reg, dst_reg); + else + *insn++ = BPF_MOV64_IMM(dst_reg, 0); + break; +#endif } return insn - insn_buf; @@ -1561,13 +1631,13 @@ static u32 sk_filter_convert_ctx_access(int dst_reg, int src_reg, int ctx_off, static const struct bpf_verifier_ops sk_filter_ops = { .get_func_proto = sk_filter_func_proto, .is_valid_access = sk_filter_is_valid_access, - .convert_ctx_access = sk_filter_convert_ctx_access, + .convert_ctx_access = bpf_net_convert_ctx_access, }; static const struct bpf_verifier_ops tc_cls_act_ops = { .get_func_proto = tc_cls_act_func_proto, - .is_valid_access = sk_filter_is_valid_access, - .convert_ctx_access = sk_filter_convert_ctx_access, + .is_valid_access = tc_cls_act_is_valid_access, + .convert_ctx_access = bpf_net_convert_ctx_access, }; static struct bpf_prog_type_list sk_filter_type __read_mostly = { diff --git a/samples/bpf/sockex3_kern.c b/samples/bpf/sockex3_kern.c index 2625b987944f..41ae2fd21b13 100644 --- a/samples/bpf/sockex3_kern.c +++ b/samples/bpf/sockex3_kern.c @@ -89,7 +89,6 @@ static inline __u32 ipv6_addr_hash(struct __sk_buff *ctx, __u64 off) struct globals { struct flow_keys flow; - __u32 nhoff; }; struct bpf_map_def SEC("maps") percpu_map = { @@ -139,7 +138,7 @@ static void update_stats(struct __sk_buff *skb, struct globals *g) static __always_inline void parse_ip_proto(struct __sk_buff *skb, struct globals *g, __u32 ip_proto) { - __u32 nhoff = g->nhoff; + __u32 nhoff = skb->cb[0]; int poff; switch (ip_proto) { @@ -165,7 +164,7 @@ static __always_inline void parse_ip_proto(struct __sk_buff *skb, if (gre_flags & GRE_SEQ) nhoff += 4; - g->nhoff = nhoff; + skb->cb[0] = nhoff; parse_eth_proto(skb, gre_proto); break; } @@ -195,7 +194,7 @@ PROG(PARSE_IP)(struct __sk_buff *skb) if (!g) return 0; - nhoff = g->nhoff; + nhoff = skb->cb[0]; if (unlikely(ip_is_fragment(skb, nhoff))) return 0; @@ -210,7 +209,7 @@ PROG(PARSE_IP)(struct __sk_buff *skb) verlen = load_byte(skb, nhoff + 0/*offsetof(struct iphdr, ihl)*/); nhoff += (verlen & 0xF) << 2; - g->nhoff = nhoff; + skb->cb[0] = nhoff; parse_ip_proto(skb, g, ip_proto); return 0; } @@ -223,7 +222,7 @@ PROG(PARSE_IPV6)(struct __sk_buff *skb) if (!g) return 0; - nhoff = g->nhoff; + nhoff = skb->cb[0]; ip_proto = load_byte(skb, nhoff + offsetof(struct ipv6hdr, nexthdr)); @@ -233,25 +232,21 @@ PROG(PARSE_IPV6)(struct __sk_buff *skb) nhoff + offsetof(struct ipv6hdr, daddr)); nhoff += sizeof(struct ipv6hdr); - g->nhoff = nhoff; + skb->cb[0] = nhoff; parse_ip_proto(skb, g, ip_proto); return 0; } PROG(PARSE_VLAN)(struct __sk_buff *skb) { - struct globals *g = this_cpu_globals(); __u32 nhoff, proto; - if (!g) - return 0; - - nhoff = g->nhoff; + nhoff = skb->cb[0]; proto = load_half(skb, nhoff + offsetof(struct vlan_hdr, h_vlan_encapsulated_proto)); nhoff += sizeof(struct vlan_hdr); - g->nhoff = nhoff; + skb->cb[0] = nhoff; parse_eth_proto(skb, proto); @@ -260,17 +255,13 @@ PROG(PARSE_VLAN)(struct __sk_buff *skb) PROG(PARSE_MPLS)(struct __sk_buff *skb) { - struct globals *g = this_cpu_globals(); __u32 nhoff, label; - if (!g) - return 0; - - nhoff = g->nhoff; + nhoff = skb->cb[0]; label = load_word(skb, nhoff); nhoff += sizeof(struct mpls_label); - g->nhoff = nhoff; + skb->cb[0] = nhoff; if (label & MPLS_LS_S_MASK) { __u8 verlen = load_byte(skb, nhoff); @@ -288,14 +279,10 @@ PROG(PARSE_MPLS)(struct __sk_buff *skb) SEC("socket/0") int main_prog(struct __sk_buff *skb) { - struct globals *g = this_cpu_globals(); __u32 nhoff = ETH_HLEN; __u32 proto = load_half(skb, 12); - if (!g) - return 0; - - g->nhoff = nhoff; + skb->cb[0] = nhoff; parse_eth_proto(skb, proto); return 0; } diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c index 12f3780af73f..693605997abc 100644 --- a/samples/bpf/test_verifier.c +++ b/samples/bpf/test_verifier.c @@ -29,6 +29,7 @@ struct bpf_test { ACCEPT, REJECT } result; + enum bpf_prog_type prog_type; }; static struct bpf_test tests[] = { @@ -743,6 +744,84 @@ static struct bpf_test tests[] = { .errstr = "different pointers", .result = REJECT, }, + { + "check skb->mark is not writeable by sockets", + .insns = { + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, + offsetof(struct __sk_buff, mark)), + BPF_EXIT_INSN(), + }, + .errstr = "invalid bpf_context access", + .result = REJECT, + }, + { + "check skb->tc_index is not writeable by sockets", + .insns = { + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, + offsetof(struct __sk_buff, tc_index)), + BPF_EXIT_INSN(), + }, + .errstr = "invalid bpf_context access", + .result = REJECT, + }, + { + "check non-u32 access to cb", + .insns = { + BPF_STX_MEM(BPF_H, BPF_REG_1, BPF_REG_1, + offsetof(struct __sk_buff, cb[0])), + BPF_EXIT_INSN(), + }, + .errstr = "invalid bpf_context access", + .result = REJECT, + }, + { + "check out of range skb->cb access", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, + offsetof(struct __sk_buff, cb[60])), + BPF_EXIT_INSN(), + }, + .errstr = "invalid bpf_context access", + .result = REJECT, + .prog_type = BPF_PROG_TYPE_SCHED_ACT, + }, + { + "write skb fields from socket prog", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, + offsetof(struct __sk_buff, cb[4])), + BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1), + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, + offsetof(struct __sk_buff, mark)), + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, + offsetof(struct __sk_buff, tc_index)), + BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, + offsetof(struct __sk_buff, cb[0])), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, + offsetof(struct __sk_buff, cb[2])), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + }, + { + "write skb fields from tc_cls_act prog", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, + offsetof(struct __sk_buff, cb[0])), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct __sk_buff, mark)), + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, + offsetof(struct __sk_buff, tc_index)), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct __sk_buff, tc_index)), + BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, + offsetof(struct __sk_buff, cb[3])), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, }; static int probe_filter_length(struct bpf_insn *fp) @@ -775,6 +854,7 @@ static int test(void) for (i = 0; i < ARRAY_SIZE(tests); i++) { struct bpf_insn *prog = tests[i].insns; + int prog_type = tests[i].prog_type; int prog_len = probe_filter_length(prog); int *fixup = tests[i].fixup; int map_fd = -1; @@ -789,8 +869,8 @@ static int test(void) } printf("#%d %s ", i, tests[i].descr); - prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog, - prog_len * sizeof(struct bpf_insn), + prog_fd = bpf_prog_load(prog_type ?: BPF_PROG_TYPE_SOCKET_FILTER, + prog, prog_len * sizeof(struct bpf_insn), "GPL", 0); if (tests[i].result == ACCEPT) { -- cgit v1.2.3 From b80c0e78582d4a3a004dc1ade4eb06babc6a4eea Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 4 Jun 2015 18:30:43 -0700 Subject: tcp: get_cookie_sock() consolidation IPv4 and IPv6 share same implementation of get_cookie_sock(), and there is no point inlining it. We add tcp_ prefix to the common helper name and export it. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/tcp.h | 3 +++ net/ipv4/syncookies.c | 10 +++++----- net/ipv6/syncookies.c | 19 +------------------ 3 files changed, 9 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index 2bb2bad21d5c..978cebedd3fc 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -469,6 +469,9 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size); void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb); /* From syncookies.c */ +struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, + struct request_sock *req, + struct dst_entry *dst); int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th, u32 cookie); struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index df849e5a10f1..d70b1f603692 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -219,9 +219,9 @@ int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th, } EXPORT_SYMBOL_GPL(__cookie_v4_check); -static struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb, - struct request_sock *req, - struct dst_entry *dst) +struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, + struct request_sock *req, + struct dst_entry *dst) { struct inet_connection_sock *icsk = inet_csk(sk); struct sock *child; @@ -235,7 +235,7 @@ static struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb, } return child; } - +EXPORT_SYMBOL(tcp_get_cookie_sock); /* * when syncookies are in effect and tcp timestamps are enabled we stored @@ -391,7 +391,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) ireq->rcv_wscale = rcv_wscale; ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), &rt->dst); - ret = get_cookie_sock(sk, skb, req, &rt->dst); + ret = tcp_get_cookie_sock(sk, skb, req, &rt->dst); /* ip_queue_xmit() depends on our flow being setup * Normal sockets get it right from inet_csk_route_child_sock() */ diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 21bc2eb53c57..0909f4e0d53c 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -41,23 +41,6 @@ static __u16 const msstab[] = { 9000 - 60, }; -static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb, - struct request_sock *req, - struct dst_entry *dst) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct sock *child; - - child = icsk->icsk_af_ops->syn_recv_sock(sk, skb, req, dst); - if (child) { - atomic_set(&req->rsk_refcnt, 1); - inet_csk_reqsk_queue_add(sk, req, child); - } else { - reqsk_free(req); - } - return child; -} - static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], ipv6_cookie_scratch); @@ -264,7 +247,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ireq->rcv_wscale = rcv_wscale; ireq->ecn_ok = cookie_ecn_ok(&tcp_opt, sock_net(sk), dst); - ret = get_cookie_sock(sk, skb, req, dst); + ret = tcp_get_cookie_sock(sk, skb, req, dst); out: return ret; out_free: -- cgit v1.2.3 From 7cf7fa529d0b6b514949cc67b39e3ce406c37006 Mon Sep 17 00:00:00 2001 From: Majd Dibbiny Date: Sun, 7 Jun 2015 15:44:23 +0300 Subject: net/mlx5_core: Fix static checker warnings around system guid query flow Fix static checker warnings in the flow of system guid query. Fixes: 707c4602cda6 ('net/mlx5_core: Add new query HCA vport commands') Signed-off-by: Majd Dibbiny Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 3 ++- drivers/net/ethernet/mellanox/mlx5/core/vport.c | 2 +- include/linux/mlx5/vport.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index ba87442ef776..9335e5ae18cc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -35,7 +35,8 @@ #include #include "mlx5_core.h" -int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev, u32 *out, int outlen) +static int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev, u32 *out, + int outlen) { u32 in[MLX5_ST_SZ_DW(query_adapter_in)]; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index 20150ffa8b16..b94177ebcf3a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -307,7 +307,7 @@ ex: EXPORT_SYMBOL_GPL(mlx5_query_hca_vport_context); int mlx5_query_hca_vport_system_image_guid(struct mlx5_core_dev *dev, - __be64 *sys_image_guid) + u64 *sys_image_guid) { struct mlx5_hca_vport_context *rep; int err; diff --git a/include/linux/mlx5/vport.h b/include/linux/mlx5/vport.h index 67882a834efb..967e0fd06e89 100644 --- a/include/linux/mlx5/vport.h +++ b/include/linux/mlx5/vport.h @@ -48,7 +48,7 @@ int mlx5_query_hca_vport_context(struct mlx5_core_dev *dev, u16 vf_num, struct mlx5_hca_vport_context *rep); int mlx5_query_hca_vport_system_image_guid(struct mlx5_core_dev *dev, - __be64 *sys_image_guid); + u64 *sys_image_guid); int mlx5_query_hca_vport_node_guid(struct mlx5_core_dev *dev, u64 *node_guid); -- cgit v1.2.3