Merge "USB: msm_otg: Increase data contact detection timeout"
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 12f6d03..ecc972e 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -248,7 +248,7 @@
CONFIG_BT_HCIUART_IBS=y
CONFIG_BT_HCIUART_ATH3K=y
CONFIG_MSM_BT_POWER=y
-CONFIG_CFG80211=m
+CONFIG_CFG80211=y
# CONFIG_CFG80211_WEXT is not set
CONFIG_RFKILL=y
CONFIG_GENLOCK=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 3ca9a06..0359acb 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -252,7 +252,7 @@
CONFIG_BT_HCIUART_H4=y
CONFIG_BT_HCIUART_IBS=y
CONFIG_MSM_BT_POWER=y
-CONFIG_CFG80211=m
+CONFIG_CFG80211=y
# CONFIG_CFG80211_WEXT is not set
CONFIG_RFKILL=y
CONFIG_GENLOCK=y
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index a3a70eb..dd0b345 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -494,7 +494,7 @@
kfree(info);
fail:
- if (rx_len_cached == 0) {
+ if (rx_len_cached == 0 && !in_global_reset) {
DMUX_LOG_KERR("%s: rescheduling\n", __func__);
schedule_delayed_work(&queue_rx_work, msecs_to_jiffies(100));
}
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 56c3241..265f7f0 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -246,7 +246,7 @@
static struct msm_panel_common_pdata mdp_pdata = {
.gpio = MDP_VSYNC_GPIO,
- .mdp_max_clk = 200000000,
+ .mdp_max_clk = 266667000,
.mdp_bus_scale_table = &mdp_bus_scale_pdata,
.mdp_rev = MDP_REV_44,
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index f2a5118..743bdb4 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1640,6 +1640,27 @@
},
};
+static struct msm_bus_vectors qseecom_enable_dfab_sfpb_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_ADM_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 70000000UL,
+ .ib = 70000000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_ADM_PORT1,
+ .dst = MSM_BUS_SLAVE_GSBI1_UART,
+ .ab = 2480000000UL,
+ .ib = 2480000000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_SPDM,
+ .dst = MSM_BUS_SLAVE_SPDM,
+ .ib = (64 * 8) * 1000000UL,
+ .ab = (64 * 8) * 100000UL,
+ },
+};
+
static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = {
{
ARRAY_SIZE(qseecom_clks_init_vectors),
@@ -1653,6 +1674,10 @@
ARRAY_SIZE(qseecom_enable_sfpb_vectors),
qseecom_enable_sfpb_vectors,
},
+ {
+ ARRAY_SIZE(qseecom_enable_dfab_sfpb_vectors),
+ qseecom_enable_dfab_sfpb_vectors,
+ },
};
static struct msm_bus_scale_pdata qseecom_bus_pdata = {
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index ff02e87..8af0062 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -231,7 +231,7 @@
.src = MSM_BUS_MASTER_VFE,
.dst = MSM_BUS_SLAVE_EBI_CH0,
.ab = 27648000,
- .ib = 110592000,
+ .ib = 2656000000UL,
},
{
.src = MSM_BUS_MASTER_VPE,
@@ -251,8 +251,8 @@
{
.src = MSM_BUS_MASTER_VFE,
.dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 274406400,
- .ib = 561807360,
+ .ab = 600000000,
+ .ib = 2656000000UL,
},
{
.src = MSM_BUS_MASTER_VPE,
@@ -272,8 +272,8 @@
{
.src = MSM_BUS_MASTER_VFE,
.dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 274423680,
- .ib = 1097694720,
+ .ab = 600000000,
+ .ib = 2656000000UL,
},
{
.src = MSM_BUS_MASTER_VPE,
@@ -293,8 +293,8 @@
{
.src = MSM_BUS_MASTER_VFE,
.dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 302071680,
- .ib = 1208286720,
+ .ab = 600000000,
+ .ib = 2656000000UL,
},
{
.src = MSM_BUS_MASTER_VPE,
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index 578c665..b11bf4d 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -167,8 +167,10 @@
if (cpu_is_msm8930aa())
kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 450000000;
- else if (cpu_is_msm8930ab())
+ else if (cpu_is_msm8930ab()) {
kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 500000000;
+ grp3d_max_vectors[0].ib = KGSL_CONVERT_TO_MBPS(4800);
+ }
/* Set up the chip ID based on the SoC version */
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8038.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
index c65b9ea..b14d74c 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8038.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -489,7 +489,7 @@
/* ID a_on pd ss min_uV max_uV supply sys_uA freq fm ss_fm */
RPM_SMPS(S1, 0, 1, 1, 500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
RPM_SMPS(S2, 1, 1, 1, 1400000, 1400000, NULL, 100000, 1p60, AUTO, LPM),
- RPM_SMPS(S3, 0, 1, 1, 1150000, 1150000, NULL, 100000, 3p20, AUTO, LPM),
+ RPM_SMPS(S3, 0, 1, 1, 1150000, 1150000, NULL, 100000, 3p20, AUTO, AUTO),
RPM_SMPS(S4, 1, 1, 1, 1950000, 2200000, NULL, 100000, 1p60, AUTO, LPM),
/* ID a_on pd ss min_uV max_uV supply sys_uA init_ip */
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 76bb715..7446573 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1060,6 +1060,27 @@
},
};
+static struct msm_bus_vectors qseecom_enable_dfab_sfpb_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ib = (492 * 8) * 1000000UL,
+ .ab = (492 * 8) * 100000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_SPS,
+ .ib = (492 * 8) * 1000000UL,
+ .ab = (492 * 8) * 100000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_SPDM,
+ .dst = MSM_BUS_SLAVE_SPDM,
+ .ib = (64 * 8) * 1000000UL,
+ .ab = (64 * 8) * 100000UL,
+ },
+};
+
static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = {
{
ARRAY_SIZE(qseecom_clks_init_vectors),
@@ -1073,6 +1094,10 @@
ARRAY_SIZE(qseecom_enable_sfpb_vectors),
qseecom_enable_sfpb_vectors,
},
+ {
+ ARRAY_SIZE(qseecom_enable_dfab_sfpb_vectors),
+ qseecom_enable_dfab_sfpb_vectors,
+ },
};
static struct msm_bus_scale_pdata qseecom_bus_pdata = {
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index f3b1cfd..d5855fe 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -15,6 +15,7 @@
#include <linux/gpio.h>
#include <mach/camera.h>
#include <mach/msm_bus_board.h>
+#include <mach/socinfo.h>
#include <mach/gpiomux.h>
#include "devices.h"
#include "board-8960.h"
@@ -184,6 +185,23 @@
},
};
+static struct msm_gpiomux_config msm8960_cam_2d_configs_sglte[] = {
+ {
+ .gpio = 20,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+ {
+ .gpio = 21,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[8],
+ },
+ },
+};
+
#define VFE_CAMIF_TIMER1_GPIO 2
#define VFE_CAMIF_TIMER2_GPIO 3
#define VFE_CAMIF_TIMER3_GPIO_INT 4
@@ -783,6 +801,16 @@
void __init msm8960_init_cam(void)
{
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+ msm_8960_front_cam_gpio_conf.cam_gpiomux_conf_tbl =
+ msm8960_cam_2d_configs_sglte;
+ msm_8960_front_cam_gpio_conf.cam_gpiomux_conf_tbl_size =
+ ARRAY_SIZE(msm8960_cam_2d_configs_sglte);
+ msm_8960_back_cam_gpio_conf.cam_gpiomux_conf_tbl =
+ msm8960_cam_2d_configs_sglte;
+ msm_8960_back_cam_gpio_conf.cam_gpiomux_conf_tbl_size =
+ ARRAY_SIZE(msm8960_cam_2d_configs_sglte);
+ }
msm_gpiomux_install(msm8960_cam_common_configs,
ARRAY_SIZE(msm8960_cam_common_configs));
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index ac26bcd..97d0105 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1171,6 +1171,27 @@
},
};
+static struct msm_bus_vectors qseecom_enable_dfab_sfpb_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ib = (492 * 8) * 1000000UL,
+ .ab = (492 * 8) * 100000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_SPS,
+ .ib = (492 * 8) * 1000000UL,
+ .ab = (492 * 8) * 100000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_SPDM,
+ .dst = MSM_BUS_SLAVE_SPDM,
+ .ib = (64 * 8) * 1000000UL,
+ .ab = (64 * 8) * 100000UL,
+ },
+};
+
static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = {
{
ARRAY_SIZE(qseecom_clks_init_vectors),
@@ -1184,6 +1205,10 @@
ARRAY_SIZE(qseecom_enable_sfpb_vectors),
qseecom_enable_sfpb_vectors,
},
+ {
+ ARRAY_SIZE(qseecom_enable_dfab_sfpb_vectors),
+ qseecom_enable_dfab_sfpb_vectors,
+ },
};
static struct msm_bus_scale_pdata qseecom_bus_pdata = {
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index bf8a0b0..4b58798 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -1223,8 +1223,6 @@
.b = {
.ctl_reg = AHB_EN3_REG,
.en_mask = BIT(1),
- .hwcg_reg = AHB_EN3_REG,
- .hwcg_mask = BIT(0),
.reset_reg = SW_RESET_AHB2_REG,
.reset_mask = BIT(2),
.halt_reg = DBG_BUS_VEC_J_REG,
@@ -6361,8 +6359,8 @@
writel_relaxed(0x3C7097F9, AHB_EN2_REG);
}
- if (cpu_is_apq8064() || cpu_is_apq8064ab())
- rmwreg(0x00000001, AHB_EN3_REG, 0x00000001);
+ if (soc_class_is_apq8064())
+ rmwreg(0x00000000, AHB_EN3_REG, 0x00000001);
/* Deassert all locally-owned MM AHB resets. */
rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
@@ -6384,7 +6382,7 @@
rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
- if (cpu_is_apq8064() || cpu_is_apq8064ab())
+ if (soc_class_is_apq8064())
rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627() ||
cpu_is_msm8930ab())
@@ -6423,8 +6421,7 @@
rmwreg(0x80FF0000, VFE_CC_REG, 0xE0FF4010);
rmwreg(0x800000FF, VFE_CC2_REG, 0xE00000FF);
rmwreg(0x80FF0000, VPE_CC_REG, 0xE0FF0010);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_apq8064()
- || cpu_is_apq8064ab()) {
+ if (cpu_is_msm8960ab() || cpu_is_msm8960() || soc_class_is_apq8064()) {
rmwreg(0x80FF0000, DSI2_BYTE_CC_REG, 0xE0FF0010);
rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
rmwreg(0x80FF0000, JPEGD_CC_REG, 0xE0FF0010);
@@ -6442,7 +6439,7 @@
rmwreg(0x80FF0000, GFX2D0_CC_REG, 0xE0FF0010);
rmwreg(0x80FF0000, GFX2D1_CC_REG, 0xE0FF0010);
}
- if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
+ if (soc_class_is_apq8064()) {
rmwreg(0x00000000, TV_CC_REG, 0x00004010);
rmwreg(0x80FF0000, VCAP_CC_REG, 0xE0FF1010);
}
@@ -6453,7 +6450,7 @@
* and wake-up value to max.
*/
rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
- if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
+ if (soc_class_is_apq8064()) {
rmwreg(0x0000004F, USB_HS3_HCLK_FS_REG, 0x0000007F);
rmwreg(0x0000004F, USB_HS4_HCLK_FS_REG, 0x0000007F);
}
@@ -6475,8 +6472,7 @@
/* Source the dsi_byte_clks from the DSI PHY PLLs */
rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_apq8064()
- || cpu_is_apq8064ab())
+ if (cpu_is_msm8960ab() || cpu_is_msm8960() || soc_class_is_apq8064())
rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
/* Source the dsi1_esc_clk from the DSI1 PHY PLLs */
@@ -6486,7 +6482,7 @@
* Source the sata_phy_ref_clk from PXO and set predivider of
* sata_pmalive_clk to 1.
*/
- if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
+ if (soc_class_is_apq8064()) {
rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
}
@@ -6495,7 +6491,7 @@
* TODO: Programming below PLLs and prng_clk is temporary and
* needs to be removed after bootloaders program them.
*/
- if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
+ if (soc_class_is_apq8064()) {
u32 is_pll_enabled;
/* Program pxo_src_clk to source from PXO */
@@ -6524,7 +6520,7 @@
writel_relaxed(0x2B, PRNG_CLK_NS_REG);
}
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_apq8064aa()) {
/* Program PLL15 to 975MHz with ref clk = 27MHz */
configure_sr_pll(&pll15_config, &pll15_regs, 0);
} else if (cpu_is_apq8064ab()) {
@@ -6561,7 +6557,7 @@
/* Initialize clock registers. */
reg_init();
- if (cpu_is_apq8064() || cpu_is_apq8064ab())
+ if (soc_class_is_apq8064())
vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
/* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
@@ -6605,7 +6601,7 @@
* Change the freq tables for and voltage requirements for
* clocks which differ between chips.
*/
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_apq8064aa()) {
gfx3d_clk.c.fmax = fmax_gfx3d_8064;
}
if (cpu_is_apq8064ab()) {
@@ -6613,13 +6609,13 @@
}
if ((cpu_is_apq8064() &&
SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) ||
- cpu_is_apq8064ab()) {
+ cpu_is_apq8064ab() || cpu_is_apq8064aa()) {
vcodec_clk.c.fmax = fmax_vcodec_8064v2;
ce3_src_clk.c.fmax = fmax_ce3_8064v2;
sdc1_clk.c.fmax = fmax_sdc1_8064v2;
}
- if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
+ if (soc_class_is_apq8064()) {
ijpeg_clk.c.fmax = fmax_ijpeg_8064;
mdp_clk.c.fmax = fmax_mdp_8064;
tv_src_clk.c.fmax = fmax_tv_src_8064;
@@ -6692,7 +6688,7 @@
clk_set_rate(&tsif_ref_clk.c, 105000);
clk_set_rate(&tssc_clk.c, 27000000);
clk_set_rate(&usb_hs1_xcvr_clk.c, 60000000);
- if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
+ if (soc_class_is_apq8064()) {
clk_set_rate(&usb_hs3_xcvr_clk.c, 60000000);
clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
}
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 9accd8c..3973b09 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -143,12 +143,12 @@
MSM_RPM_MAP(8930, PM8038_CLK2_0, PM8038_CLK2, 2),
MSM_RPM_MAP(8930, PM8038_LVS1, PM8038_LVS1, 1),
MSM_RPM_MAP(8930, PM8038_LVS2, PM8038_LVS2, 1),
- MSM_RPM_MAP(8930, NCP_0, NCP, 2),
- MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
- MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
- MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
- MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
- MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, NCP_0, NCP, 2),
+ MSM_RPM_MAP_PMIC(8930, 8038, CXO_BUFFERS, CXO_BUFFERS, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, HDMI_SWITCH, HDMI_SWITCH, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, QDSS_CLK, QDSS_CLK, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
},
.target_status = {
MSM_RPM_STATUS_ID_MAP(8930, VERSION_MAJOR),
@@ -369,12 +369,12 @@
MSM_RPM_MAP(8930, PM8917_LVS5, PM8917_LVS5, 1),
MSM_RPM_MAP(8930, PM8917_LVS6, PM8917_LVS6, 1),
MSM_RPM_MAP(8930, PM8917_LVS7, PM8917_LVS7, 1),
- MSM_RPM_MAP(8930, NCP_0, NCP, 2),
- MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
- MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
- MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
- MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
- MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, NCP_0, NCP, 2),
+ MSM_RPM_MAP_PMIC(8930, 8917, CXO_BUFFERS, CXO_BUFFERS, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, HDMI_SWITCH, HDMI_SWITCH, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, QDSS_CLK, QDSS_CLK, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
},
.target_status = {
MSM_RPM_STATUS_ID_MAP(8930, VERSION_MAJOR),
diff --git a/arch/arm/mach-msm/gss-8064.c b/arch/arm/mach-msm/gss-8064.c
index ba6af61..dea1af5 100644
--- a/arch/arm/mach-msm/gss-8064.c
+++ b/arch/arm/mach-msm/gss-8064.c
@@ -200,7 +200,7 @@
{
int ret;
- if (!(cpu_is_apq8064() || cpu_is_apq8064ab()))
+ if (!(soc_class_is_apq8064()))
return -ENODEV;
ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
diff --git a/arch/arm/mach-msm/include/mach/bam_dmux.h b/arch/arm/mach-msm/include/mach/bam_dmux.h
index f02a882..f11b72c 100644
--- a/arch/arm/mach-msm/include/mach/bam_dmux.h
+++ b/arch/arm/mach-msm/include/mach/bam_dmux.h
@@ -28,6 +28,18 @@
BAM_DMUX_DATA_RMNET_6,
BAM_DMUX_DATA_RMNET_7,
BAM_DMUX_USB_RMNET_0,
+ BAM_DMUX_RESERVED_0, /* 9..11 are reserved*/
+ BAM_DMUX_RESERVED_1,
+ BAM_DMUX_RESERVED_2,
+ BAM_DMUX_DATA_REV_RMNET_0,
+ BAM_DMUX_DATA_REV_RMNET_1,
+ BAM_DMUX_DATA_REV_RMNET_2,
+ BAM_DMUX_DATA_REV_RMNET_3,
+ BAM_DMUX_DATA_REV_RMNET_4,
+ BAM_DMUX_DATA_REV_RMNET_5,
+ BAM_DMUX_DATA_REV_RMNET_6,
+ BAM_DMUX_DATA_REV_RMNET_7,
+ BAM_DMUX_DATA_REV_RMNET_8,
BAM_DMUX_NUM_CHANNELS
};
diff --git a/arch/arm/mach-msm/include/mach/rpm-8930.h b/arch/arm/mach-msm/include/mach/rpm-8930.h
index 4ac9192..bc1b918 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8930.h
@@ -219,182 +219,190 @@
MSM_RPM_8930_ID_MM_FABRIC_ARB_0 + 10,
/* PMIC 8038 */
- MSM_RPM_8930_ID_PM8038_S1_0 = 90,
- MSM_RPM_8930_ID_PM8038_S1_1 = 91,
- MSM_RPM_8930_ID_PM8038_S2_0 = 92,
- MSM_RPM_8930_ID_PM8038_S2_1 = 93,
- MSM_RPM_8930_ID_PM8038_S3_0 = 94,
- MSM_RPM_8930_ID_PM8038_S3_1 = 95,
- MSM_RPM_8930_ID_PM8038_S4_0 = 96,
- MSM_RPM_8930_ID_PM8038_S4_1 = 97,
- MSM_RPM_8930_ID_PM8038_S5_0 = 98,
- MSM_RPM_8930_ID_PM8038_S5_1 = 99,
- MSM_RPM_8930_ID_PM8038_S6_0 = 100,
- MSM_RPM_8930_ID_PM8038_S6_1 = 101,
- MSM_RPM_8930_ID_PM8038_L1_0 = 102,
- MSM_RPM_8930_ID_PM8038_L1_1 = 103,
- MSM_RPM_8930_ID_PM8038_L2_0 = 104,
- MSM_RPM_8930_ID_PM8038_L2_1 = 105,
- MSM_RPM_8930_ID_PM8038_L3_0 = 106,
- MSM_RPM_8930_ID_PM8038_L3_1 = 107,
- MSM_RPM_8930_ID_PM8038_L4_0 = 108,
- MSM_RPM_8930_ID_PM8038_L4_1 = 109,
- MSM_RPM_8930_ID_PM8038_L5_0 = 110,
- MSM_RPM_8930_ID_PM8038_L5_1 = 111,
- MSM_RPM_8930_ID_PM8038_L6_0 = 112,
- MSM_RPM_8930_ID_PM8038_L6_1 = 113,
- MSM_RPM_8930_ID_PM8038_L7_0 = 114,
- MSM_RPM_8930_ID_PM8038_L7_1 = 115,
- MSM_RPM_8930_ID_PM8038_L8_0 = 116,
- MSM_RPM_8930_ID_PM8038_L8_1 = 117,
- MSM_RPM_8930_ID_PM8038_L9_0 = 118,
- MSM_RPM_8930_ID_PM8038_L9_1 = 119,
- MSM_RPM_8930_ID_PM8038_L10_0 = 120,
- MSM_RPM_8930_ID_PM8038_L10_1 = 121,
- MSM_RPM_8930_ID_PM8038_L11_0 = 122,
- MSM_RPM_8930_ID_PM8038_L11_1 = 123,
- MSM_RPM_8930_ID_PM8038_L12_0 = 124,
- MSM_RPM_8930_ID_PM8038_L12_1 = 125,
- MSM_RPM_8930_ID_PM8038_L13_0 = 126,
- MSM_RPM_8930_ID_PM8038_L13_1 = 127,
- MSM_RPM_8930_ID_PM8038_L14_0 = 128,
- MSM_RPM_8930_ID_PM8038_L14_1 = 129,
- MSM_RPM_8930_ID_PM8038_L15_0 = 130,
- MSM_RPM_8930_ID_PM8038_L15_1 = 131,
- MSM_RPM_8930_ID_PM8038_L16_0 = 132,
- MSM_RPM_8930_ID_PM8038_L16_1 = 133,
- MSM_RPM_8930_ID_PM8038_L17_0 = 134,
- MSM_RPM_8930_ID_PM8038_L17_1 = 135,
- MSM_RPM_8930_ID_PM8038_L18_0 = 136,
- MSM_RPM_8930_ID_PM8038_L18_1 = 137,
- MSM_RPM_8930_ID_PM8038_L19_0 = 138,
- MSM_RPM_8930_ID_PM8038_L19_1 = 139,
- MSM_RPM_8930_ID_PM8038_L20_0 = 140,
- MSM_RPM_8930_ID_PM8038_L20_1 = 141,
- MSM_RPM_8930_ID_PM8038_L21_0 = 142,
- MSM_RPM_8930_ID_PM8038_L21_1 = 143,
- MSM_RPM_8930_ID_PM8038_L22_0 = 144,
- MSM_RPM_8930_ID_PM8038_L22_1 = 145,
- MSM_RPM_8930_ID_PM8038_L23_0 = 146,
- MSM_RPM_8930_ID_PM8038_L23_1 = 147,
- MSM_RPM_8930_ID_PM8038_L24_0 = 148,
- MSM_RPM_8930_ID_PM8038_L24_1 = 149,
- MSM_RPM_8930_ID_PM8038_L25_0 = 150,
- MSM_RPM_8930_ID_PM8038_L25_1 = 151,
- MSM_RPM_8930_ID_PM8038_L26_0 = 152,
- MSM_RPM_8930_ID_PM8038_L26_1 = 153,
- MSM_RPM_8930_ID_PM8038_L27_0 = 154,
- MSM_RPM_8930_ID_PM8038_L27_1 = 155,
- MSM_RPM_8930_ID_PM8038_CLK1_0 = 156,
- MSM_RPM_8930_ID_PM8038_CLK1_1 = 157,
- MSM_RPM_8930_ID_PM8038_CLK2_0 = 158,
- MSM_RPM_8930_ID_PM8038_CLK2_1 = 159,
- MSM_RPM_8930_ID_PM8038_LVS1 = 160,
- MSM_RPM_8930_ID_PM8038_LVS2 = 161,
+ MSM_RPM_8930_ID_PM8038_S1_0 = 90,
+ MSM_RPM_8930_ID_PM8038_S1_1 = 91,
+ MSM_RPM_8930_ID_PM8038_S2_0 = 92,
+ MSM_RPM_8930_ID_PM8038_S2_1 = 93,
+ MSM_RPM_8930_ID_PM8038_S3_0 = 94,
+ MSM_RPM_8930_ID_PM8038_S3_1 = 95,
+ MSM_RPM_8930_ID_PM8038_S4_0 = 96,
+ MSM_RPM_8930_ID_PM8038_S4_1 = 97,
+ MSM_RPM_8930_ID_PM8038_S5_0 = 98,
+ MSM_RPM_8930_ID_PM8038_S5_1 = 99,
+ MSM_RPM_8930_ID_PM8038_S6_0 = 100,
+ MSM_RPM_8930_ID_PM8038_S6_1 = 101,
+ MSM_RPM_8930_ID_PM8038_L1_0 = 102,
+ MSM_RPM_8930_ID_PM8038_L1_1 = 103,
+ MSM_RPM_8930_ID_PM8038_L2_0 = 104,
+ MSM_RPM_8930_ID_PM8038_L2_1 = 105,
+ MSM_RPM_8930_ID_PM8038_L3_0 = 106,
+ MSM_RPM_8930_ID_PM8038_L3_1 = 107,
+ MSM_RPM_8930_ID_PM8038_L4_0 = 108,
+ MSM_RPM_8930_ID_PM8038_L4_1 = 109,
+ MSM_RPM_8930_ID_PM8038_L5_0 = 110,
+ MSM_RPM_8930_ID_PM8038_L5_1 = 111,
+ MSM_RPM_8930_ID_PM8038_L6_0 = 112,
+ MSM_RPM_8930_ID_PM8038_L6_1 = 113,
+ MSM_RPM_8930_ID_PM8038_L7_0 = 114,
+ MSM_RPM_8930_ID_PM8038_L7_1 = 115,
+ MSM_RPM_8930_ID_PM8038_L8_0 = 116,
+ MSM_RPM_8930_ID_PM8038_L8_1 = 117,
+ MSM_RPM_8930_ID_PM8038_L9_0 = 118,
+ MSM_RPM_8930_ID_PM8038_L9_1 = 119,
+ MSM_RPM_8930_ID_PM8038_L10_0 = 120,
+ MSM_RPM_8930_ID_PM8038_L10_1 = 121,
+ MSM_RPM_8930_ID_PM8038_L11_0 = 122,
+ MSM_RPM_8930_ID_PM8038_L11_1 = 123,
+ MSM_RPM_8930_ID_PM8038_L12_0 = 124,
+ MSM_RPM_8930_ID_PM8038_L12_1 = 125,
+ MSM_RPM_8930_ID_PM8038_L13_0 = 126,
+ MSM_RPM_8930_ID_PM8038_L13_1 = 127,
+ MSM_RPM_8930_ID_PM8038_L14_0 = 128,
+ MSM_RPM_8930_ID_PM8038_L14_1 = 129,
+ MSM_RPM_8930_ID_PM8038_L15_0 = 130,
+ MSM_RPM_8930_ID_PM8038_L15_1 = 131,
+ MSM_RPM_8930_ID_PM8038_L16_0 = 132,
+ MSM_RPM_8930_ID_PM8038_L16_1 = 133,
+ MSM_RPM_8930_ID_PM8038_L17_0 = 134,
+ MSM_RPM_8930_ID_PM8038_L17_1 = 135,
+ MSM_RPM_8930_ID_PM8038_L18_0 = 136,
+ MSM_RPM_8930_ID_PM8038_L18_1 = 137,
+ MSM_RPM_8930_ID_PM8038_L19_0 = 138,
+ MSM_RPM_8930_ID_PM8038_L19_1 = 139,
+ MSM_RPM_8930_ID_PM8038_L20_0 = 140,
+ MSM_RPM_8930_ID_PM8038_L20_1 = 141,
+ MSM_RPM_8930_ID_PM8038_L21_0 = 142,
+ MSM_RPM_8930_ID_PM8038_L21_1 = 143,
+ MSM_RPM_8930_ID_PM8038_L22_0 = 144,
+ MSM_RPM_8930_ID_PM8038_L22_1 = 145,
+ MSM_RPM_8930_ID_PM8038_L23_0 = 146,
+ MSM_RPM_8930_ID_PM8038_L23_1 = 147,
+ MSM_RPM_8930_ID_PM8038_L24_0 = 148,
+ MSM_RPM_8930_ID_PM8038_L24_1 = 149,
+ MSM_RPM_8930_ID_PM8038_L25_0 = 150,
+ MSM_RPM_8930_ID_PM8038_L25_1 = 151,
+ MSM_RPM_8930_ID_PM8038_L26_0 = 152,
+ MSM_RPM_8930_ID_PM8038_L26_1 = 153,
+ MSM_RPM_8930_ID_PM8038_L27_0 = 154,
+ MSM_RPM_8930_ID_PM8038_L27_1 = 155,
+ MSM_RPM_8930_ID_PM8038_CLK1_0 = 156,
+ MSM_RPM_8930_ID_PM8038_CLK1_1 = 157,
+ MSM_RPM_8930_ID_PM8038_CLK2_0 = 158,
+ MSM_RPM_8930_ID_PM8038_CLK2_1 = 159,
+ MSM_RPM_8930_ID_PM8038_LVS1 = 160,
+ MSM_RPM_8930_ID_PM8038_LVS2 = 161,
+ MSM_RPM_8930_ID_PM8038_NCP_0 = 162,
+ MSM_RPM_8930_ID_PM8038_NCP_1 = 163,
+ MSM_RPM_8930_ID_PM8038_CXO_BUFFERS = 164,
+ MSM_RPM_8930_ID_PM8038_USB_OTG_SWITCH = 165,
+ MSM_RPM_8930_ID_PM8038_HDMI_SWITCH = 166,
+ MSM_RPM_8930_ID_PM8038_QDSS_CLK = 167,
+ MSM_RPM_8930_ID_PM8038_VOLTAGE_CORNER = 168,
+ MSM_RPM_8930_ID_PM8038_LAST = MSM_RPM_8930_ID_PM8038_VOLTAGE_CORNER,
/* PMIC 8917 */
- MSM_RPM_8930_ID_PM8917_S1_0 = 90,
- MSM_RPM_8930_ID_PM8917_S1_1 = 91,
- MSM_RPM_8930_ID_PM8917_S2_0 = 92,
- MSM_RPM_8930_ID_PM8917_S2_1 = 93,
- MSM_RPM_8930_ID_PM8917_S3_0 = 94,
- MSM_RPM_8930_ID_PM8917_S3_1 = 95,
- MSM_RPM_8930_ID_PM8917_S4_0 = 96,
- MSM_RPM_8930_ID_PM8917_S4_1 = 97,
- MSM_RPM_8930_ID_PM8917_S5_0 = 98,
- MSM_RPM_8930_ID_PM8917_S5_1 = 99,
- MSM_RPM_8930_ID_PM8917_S6_0 = 100,
- MSM_RPM_8930_ID_PM8917_S6_1 = 101,
- MSM_RPM_8930_ID_PM8917_S7_0 = 102,
- MSM_RPM_8930_ID_PM8917_S7_1 = 103,
- MSM_RPM_8930_ID_PM8917_S8_0 = 104,
- MSM_RPM_8930_ID_PM8917_S8_1 = 105,
- MSM_RPM_8930_ID_PM8917_L1_0 = 106,
- MSM_RPM_8930_ID_PM8917_L1_1 = 107,
- MSM_RPM_8930_ID_PM8917_L2_0 = 108,
- MSM_RPM_8930_ID_PM8917_L2_1 = 109,
- MSM_RPM_8930_ID_PM8917_L3_0 = 110,
- MSM_RPM_8930_ID_PM8917_L3_1 = 111,
- MSM_RPM_8930_ID_PM8917_L4_0 = 112,
- MSM_RPM_8930_ID_PM8917_L4_1 = 113,
- MSM_RPM_8930_ID_PM8917_L5_0 = 114,
- MSM_RPM_8930_ID_PM8917_L5_1 = 115,
- MSM_RPM_8930_ID_PM8917_L6_0 = 116,
- MSM_RPM_8930_ID_PM8917_L6_1 = 117,
- MSM_RPM_8930_ID_PM8917_L7_0 = 118,
- MSM_RPM_8930_ID_PM8917_L7_1 = 119,
- MSM_RPM_8930_ID_PM8917_L8_0 = 120,
- MSM_RPM_8930_ID_PM8917_L8_1 = 121,
- MSM_RPM_8930_ID_PM8917_L9_0 = 122,
- MSM_RPM_8930_ID_PM8917_L9_1 = 123,
- MSM_RPM_8930_ID_PM8917_L10_0 = 124,
- MSM_RPM_8930_ID_PM8917_L10_1 = 125,
- MSM_RPM_8930_ID_PM8917_L11_0 = 126,
- MSM_RPM_8930_ID_PM8917_L11_1 = 127,
- MSM_RPM_8930_ID_PM8917_L12_0 = 128,
- MSM_RPM_8930_ID_PM8917_L12_1 = 129,
- MSM_RPM_8930_ID_PM8917_L14_0 = 130,
- MSM_RPM_8930_ID_PM8917_L14_1 = 131,
- MSM_RPM_8930_ID_PM8917_L15_0 = 132,
- MSM_RPM_8930_ID_PM8917_L15_1 = 133,
- MSM_RPM_8930_ID_PM8917_L16_0 = 134,
- MSM_RPM_8930_ID_PM8917_L16_1 = 135,
- MSM_RPM_8930_ID_PM8917_L17_0 = 136,
- MSM_RPM_8930_ID_PM8917_L17_1 = 137,
- MSM_RPM_8930_ID_PM8917_L18_0 = 138,
- MSM_RPM_8930_ID_PM8917_L18_1 = 139,
- MSM_RPM_8930_ID_PM8917_L21_0 = 140,
- MSM_RPM_8930_ID_PM8917_L21_1 = 141,
- MSM_RPM_8930_ID_PM8917_L22_0 = 142,
- MSM_RPM_8930_ID_PM8917_L22_1 = 143,
- MSM_RPM_8930_ID_PM8917_L23_0 = 144,
- MSM_RPM_8930_ID_PM8917_L23_1 = 145,
- MSM_RPM_8930_ID_PM8917_L24_0 = 146,
- MSM_RPM_8930_ID_PM8917_L24_1 = 147,
- MSM_RPM_8930_ID_PM8917_L25_0 = 148,
- MSM_RPM_8930_ID_PM8917_L25_1 = 149,
- MSM_RPM_8930_ID_PM8917_L26_0 = 150,
- MSM_RPM_8930_ID_PM8917_L26_1 = 151,
- MSM_RPM_8930_ID_PM8917_L27_0 = 152,
- MSM_RPM_8930_ID_PM8917_L27_1 = 153,
- MSM_RPM_8930_ID_PM8917_L28_0 = 154,
- MSM_RPM_8930_ID_PM8917_L28_1 = 155,
- MSM_RPM_8930_ID_PM8917_L29_0 = 156,
- MSM_RPM_8930_ID_PM8917_L29_1 = 157,
- MSM_RPM_8930_ID_PM8917_L30_0 = 158,
- MSM_RPM_8930_ID_PM8917_L30_1 = 159,
- MSM_RPM_8930_ID_PM8917_L31_0 = 160,
- MSM_RPM_8930_ID_PM8917_L31_1 = 161,
- MSM_RPM_8930_ID_PM8917_L32_0 = 162,
- MSM_RPM_8930_ID_PM8917_L32_1 = 163,
- MSM_RPM_8930_ID_PM8917_L33_0 = 164,
- MSM_RPM_8930_ID_PM8917_L33_1 = 165,
- MSM_RPM_8930_ID_PM8917_L34_0 = 166,
- MSM_RPM_8930_ID_PM8917_L34_1 = 167,
- MSM_RPM_8930_ID_PM8917_L35_0 = 168,
- MSM_RPM_8930_ID_PM8917_L35_1 = 169,
- MSM_RPM_8930_ID_PM8917_L36_0 = 170,
- MSM_RPM_8930_ID_PM8917_L36_1 = 171,
- MSM_RPM_8930_ID_PM8917_CLK1_0 = 172,
- MSM_RPM_8930_ID_PM8917_CLK1_1 = 173,
- MSM_RPM_8930_ID_PM8917_CLK2_0 = 174,
- MSM_RPM_8930_ID_PM8917_CLK2_1 = 175,
- MSM_RPM_8930_ID_PM8917_LVS1 = 176,
- MSM_RPM_8930_ID_PM8917_LVS3 = 177,
- MSM_RPM_8930_ID_PM8917_LVS4 = 178,
- MSM_RPM_8930_ID_PM8917_LVS5 = 179,
- MSM_RPM_8930_ID_PM8917_LVS6 = 180,
- MSM_RPM_8930_ID_PM8917_LVS7 = 181,
+ MSM_RPM_8930_ID_PM8917_S1_0 = 90,
+ MSM_RPM_8930_ID_PM8917_S1_1 = 91,
+ MSM_RPM_8930_ID_PM8917_S2_0 = 92,
+ MSM_RPM_8930_ID_PM8917_S2_1 = 93,
+ MSM_RPM_8930_ID_PM8917_S3_0 = 94,
+ MSM_RPM_8930_ID_PM8917_S3_1 = 95,
+ MSM_RPM_8930_ID_PM8917_S4_0 = 96,
+ MSM_RPM_8930_ID_PM8917_S4_1 = 97,
+ MSM_RPM_8930_ID_PM8917_S5_0 = 98,
+ MSM_RPM_8930_ID_PM8917_S5_1 = 99,
+ MSM_RPM_8930_ID_PM8917_S6_0 = 100,
+ MSM_RPM_8930_ID_PM8917_S6_1 = 101,
+ MSM_RPM_8930_ID_PM8917_S7_0 = 102,
+ MSM_RPM_8930_ID_PM8917_S7_1 = 103,
+ MSM_RPM_8930_ID_PM8917_S8_0 = 104,
+ MSM_RPM_8930_ID_PM8917_S8_1 = 105,
+ MSM_RPM_8930_ID_PM8917_L1_0 = 106,
+ MSM_RPM_8930_ID_PM8917_L1_1 = 107,
+ MSM_RPM_8930_ID_PM8917_L2_0 = 108,
+ MSM_RPM_8930_ID_PM8917_L2_1 = 109,
+ MSM_RPM_8930_ID_PM8917_L3_0 = 110,
+ MSM_RPM_8930_ID_PM8917_L3_1 = 111,
+ MSM_RPM_8930_ID_PM8917_L4_0 = 112,
+ MSM_RPM_8930_ID_PM8917_L4_1 = 113,
+ MSM_RPM_8930_ID_PM8917_L5_0 = 114,
+ MSM_RPM_8930_ID_PM8917_L5_1 = 115,
+ MSM_RPM_8930_ID_PM8917_L6_0 = 116,
+ MSM_RPM_8930_ID_PM8917_L6_1 = 117,
+ MSM_RPM_8930_ID_PM8917_L7_0 = 118,
+ MSM_RPM_8930_ID_PM8917_L7_1 = 119,
+ MSM_RPM_8930_ID_PM8917_L8_0 = 120,
+ MSM_RPM_8930_ID_PM8917_L8_1 = 121,
+ MSM_RPM_8930_ID_PM8917_L9_0 = 122,
+ MSM_RPM_8930_ID_PM8917_L9_1 = 123,
+ MSM_RPM_8930_ID_PM8917_L10_0 = 124,
+ MSM_RPM_8930_ID_PM8917_L10_1 = 125,
+ MSM_RPM_8930_ID_PM8917_L11_0 = 126,
+ MSM_RPM_8930_ID_PM8917_L11_1 = 127,
+ MSM_RPM_8930_ID_PM8917_L12_0 = 128,
+ MSM_RPM_8930_ID_PM8917_L12_1 = 129,
+ MSM_RPM_8930_ID_PM8917_L14_0 = 130,
+ MSM_RPM_8930_ID_PM8917_L14_1 = 131,
+ MSM_RPM_8930_ID_PM8917_L15_0 = 132,
+ MSM_RPM_8930_ID_PM8917_L15_1 = 133,
+ MSM_RPM_8930_ID_PM8917_L16_0 = 134,
+ MSM_RPM_8930_ID_PM8917_L16_1 = 135,
+ MSM_RPM_8930_ID_PM8917_L17_0 = 136,
+ MSM_RPM_8930_ID_PM8917_L17_1 = 137,
+ MSM_RPM_8930_ID_PM8917_L18_0 = 138,
+ MSM_RPM_8930_ID_PM8917_L18_1 = 139,
+ MSM_RPM_8930_ID_PM8917_L21_0 = 140,
+ MSM_RPM_8930_ID_PM8917_L21_1 = 141,
+ MSM_RPM_8930_ID_PM8917_L22_0 = 142,
+ MSM_RPM_8930_ID_PM8917_L22_1 = 143,
+ MSM_RPM_8930_ID_PM8917_L23_0 = 144,
+ MSM_RPM_8930_ID_PM8917_L23_1 = 145,
+ MSM_RPM_8930_ID_PM8917_L24_0 = 146,
+ MSM_RPM_8930_ID_PM8917_L24_1 = 147,
+ MSM_RPM_8930_ID_PM8917_L25_0 = 148,
+ MSM_RPM_8930_ID_PM8917_L25_1 = 149,
+ MSM_RPM_8930_ID_PM8917_L26_0 = 150,
+ MSM_RPM_8930_ID_PM8917_L26_1 = 151,
+ MSM_RPM_8930_ID_PM8917_L27_0 = 152,
+ MSM_RPM_8930_ID_PM8917_L27_1 = 153,
+ MSM_RPM_8930_ID_PM8917_L28_0 = 154,
+ MSM_RPM_8930_ID_PM8917_L28_1 = 155,
+ MSM_RPM_8930_ID_PM8917_L29_0 = 156,
+ MSM_RPM_8930_ID_PM8917_L29_1 = 157,
+ MSM_RPM_8930_ID_PM8917_L30_0 = 158,
+ MSM_RPM_8930_ID_PM8917_L30_1 = 159,
+ MSM_RPM_8930_ID_PM8917_L31_0 = 160,
+ MSM_RPM_8930_ID_PM8917_L31_1 = 161,
+ MSM_RPM_8930_ID_PM8917_L32_0 = 162,
+ MSM_RPM_8930_ID_PM8917_L32_1 = 163,
+ MSM_RPM_8930_ID_PM8917_L33_0 = 164,
+ MSM_RPM_8930_ID_PM8917_L33_1 = 165,
+ MSM_RPM_8930_ID_PM8917_L34_0 = 166,
+ MSM_RPM_8930_ID_PM8917_L34_1 = 167,
+ MSM_RPM_8930_ID_PM8917_L35_0 = 168,
+ MSM_RPM_8930_ID_PM8917_L35_1 = 169,
+ MSM_RPM_8930_ID_PM8917_L36_0 = 170,
+ MSM_RPM_8930_ID_PM8917_L36_1 = 171,
+ MSM_RPM_8930_ID_PM8917_CLK1_0 = 172,
+ MSM_RPM_8930_ID_PM8917_CLK1_1 = 173,
+ MSM_RPM_8930_ID_PM8917_CLK2_0 = 174,
+ MSM_RPM_8930_ID_PM8917_CLK2_1 = 175,
+ MSM_RPM_8930_ID_PM8917_LVS1 = 176,
+ MSM_RPM_8930_ID_PM8917_LVS3 = 177,
+ MSM_RPM_8930_ID_PM8917_LVS4 = 178,
+ MSM_RPM_8930_ID_PM8917_LVS5 = 179,
+ MSM_RPM_8930_ID_PM8917_LVS6 = 180,
+ MSM_RPM_8930_ID_PM8917_LVS7 = 181,
+ MSM_RPM_8930_ID_PM8917_NCP_0 = 182,
+ MSM_RPM_8930_ID_PM8917_NCP_1 = 183,
+ MSM_RPM_8930_ID_PM8917_CXO_BUFFERS = 184,
+ MSM_RPM_8930_ID_PM8917_USB_OTG_SWITCH = 185,
+ MSM_RPM_8930_ID_PM8917_HDMI_SWITCH = 186,
+ MSM_RPM_8930_ID_PM8917_QDSS_CLK = 187,
+ MSM_RPM_8930_ID_PM8917_VOLTAGE_CORNER = 188,
- MSM_RPM_8930_ID_NCP_0 = 182,
- MSM_RPM_8930_ID_NCP_1 = 183,
- MSM_RPM_8930_ID_CXO_BUFFERS = 184,
- MSM_RPM_8930_ID_USB_OTG_SWITCH = 185,
- MSM_RPM_8930_ID_HDMI_SWITCH = 186,
- MSM_RPM_8930_ID_QDSS_CLK = 187,
- MSM_RPM_8930_ID_VOLTAGE_CORNER = 188,
-
- MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_VOLTAGE_CORNER,
+ MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_PM8917_VOLTAGE_CORNER,
+ MSM_RPM_8930_ID_PM8917_LAST = MSM_RPM_8930_ID_LAST,
};
/* RPM status ID enum */
diff --git a/arch/arm/mach-msm/include/mach/rpm.h b/arch/arm/mach-msm/include/mach/rpm.h
index 4ee1997..200a8cf 100644
--- a/arch/arm/mach-msm/include/mach/rpm.h
+++ b/arch/arm/mach-msm/include/mach/rpm.h
@@ -1086,6 +1086,14 @@
.count = c, \
}
+#define MSM_RPM_MAP_PMIC(_target, _pmic, _id, _select, _count) \
+ [MSM_RPM_ID_##_id] = \
+ {\
+ .id = MSM_RPM_##_target##_ID_PM##_pmic##_##_id, \
+ .sel = MSM_RPM_##_target##_SEL_##_select, \
+ .count = _count, \
+ }
+
#define MSM_RPM_STATUS_ID_VALID BIT(31)
#define MSM_RPM_STATUS_ID_MAP(t, i) \
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index bad2d52..56b16ee 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -90,6 +90,7 @@
MSM_CPU_7X25AB,
MSM_CPU_8064,
MSM_CPU_8064AB,
+ MSM_CPU_8064AA,
MSM_CPU_8930,
MSM_CPU_8930AA,
MSM_CPU_8930AB,
@@ -315,6 +316,15 @@
#endif
}
+static inline int cpu_is_apq8064aa(void)
+{
+#ifdef CONFIG_ARCH_APQ8064
+ return read_msm_cpu_type() == MSM_CPU_8064AA;
+#else
+ return 0;
+#endif
+}
+
static inline int cpu_is_msm8930(void)
{
#ifdef CONFIG_ARCH_MSM8930
@@ -432,7 +442,7 @@
static inline int soc_class_is_apq8064(void)
{
- return cpu_is_apq8064() || cpu_is_apq8064ab();
+ return cpu_is_apq8064() || cpu_is_apq8064ab() || cpu_is_apq8064aa();
}
static inline int soc_class_is_msm8930(void)
diff --git a/arch/arm/mach-msm/include/mach/usbdiag.h b/arch/arm/mach-msm/include/mach/usbdiag.h
index d1e3605..d9320c3 100644
--- a/arch/arm/mach-msm/include/mach/usbdiag.h
+++ b/arch/arm/mach-msm/include/mach/usbdiag.h
@@ -1,6 +1,6 @@
/* include/asm-arm/arch-msm/usbdiag.h
*
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2010, 2012, The Linux Foundation. All rights reserved.
*
* All source code in this file is licensed under the following license except
* where indicated.
@@ -21,8 +21,11 @@
#ifndef _DRIVERS_USB_DIAG_H_
#define _DRIVERS_USB_DIAG_H_
+#include <linux/err.h>
+
#define DIAG_LEGACY "diag"
#define DIAG_MDM "diag_mdm"
+#define DIAG_QSC "diag_qsc"
#define USB_DIAG_CONNECT 0
#define USB_DIAG_DISCONNECT 1
@@ -45,6 +48,7 @@
void *priv_usb;
};
+#ifdef CONFIG_USB_G_ANDROID
struct usb_diag_ch *usb_diag_open(const char *name, void *priv,
void (*notify)(void *, unsigned, struct diag_request *));
void usb_diag_close(struct usb_diag_ch *ch);
@@ -52,7 +56,32 @@
void usb_diag_free_req(struct usb_diag_ch *ch);
int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req);
int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req);
-
-int diag_read_from_cb(unsigned char * , int);
-
+#else
+static inline struct usb_diag_ch *usb_diag_open(const char *name, void *priv,
+ void (*notify)(void *, unsigned, struct diag_request *))
+{
+ return ERR_PTR(-ENODEV);
+}
+static inline void usb_diag_close(struct usb_diag_ch *ch)
+{
+}
+static inline
+int usb_diag_alloc_req(struct usb_diag_ch *ch, int n_write, int n_read)
+{
+ return -ENODEV;
+}
+static inline void usb_diag_free_req(struct usb_diag_ch *ch)
+{
+}
+static inline
+int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req)
+{
+ return -ENODEV;
+}
+static inline
+int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_USB_G_ANDROID */
#endif /* _DRIVERS_USB_DIAG_H_ */
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index 83b3bc4..c7cbac1 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -258,7 +258,7 @@
{
int ret;
- if (cpu_is_apq8064() || cpu_is_apq8064ab())
+ if (soc_class_is_apq8064())
return -ENODEV;
ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 0c75f66..b555271 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -19,10 +19,10 @@
obj-$(CONFIG_MSM_QDSP6_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
obj-$(CONFIG_MSM_QDSP6_CODECS) += rtac.o q6audio_v1.o q6audio_v1_aio.o
-obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_amrwbplus.o audio_evrc.o audio_qcelp.o amrwb_in.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += rtac_v2.o q6audio_v2.o q6audio_v2_aio.o
-obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o
obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
new file mode 100644
index 0000000..13f5e78
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
@@ -0,0 +1,234 @@
+/* amr-wbplus audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2010-2013, 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.
+ *
+ */
+#include <linux/msm_audio_amrwbplus.h>
+#include "audio_utils_aio.h"
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_amrwbplus_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+static void config_debug_fs(struct q6audio_aio *audio)
+{
+ if (audio != NULL) {
+ char name[sizeof("msm_amrwbplus_") + 5];
+ snprintf(name, sizeof(name), "msm_amrwbplus_%04x",
+ audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, (void *)audio,
+ &audio_amrwbplus_debug_fops);
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+ }
+}
+#else
+static void config_debug_fs(struct q6audio_aio *)
+{
+}
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct asm_amrwbplus_cfg q6_amrwbplus_cfg;
+ struct msm_audio_amrwbplus_config_v2 *amrwbplus_drv_config;
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_err("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+ amrwbplus_drv_config =
+ (struct msm_audio_amrwbplus_config_v2 *)audio->codec_cfg;
+
+ q6_amrwbplus_cfg.size_bytes =
+ amrwbplus_drv_config->size_bytes;
+ q6_amrwbplus_cfg.version =
+ amrwbplus_drv_config->version;
+ q6_amrwbplus_cfg.num_channels =
+ amrwbplus_drv_config->num_channels;
+ q6_amrwbplus_cfg.amr_band_mode =
+ amrwbplus_drv_config->amr_band_mode;
+ q6_amrwbplus_cfg.amr_dtx_mode =
+ amrwbplus_drv_config->amr_dtx_mode;
+ q6_amrwbplus_cfg.amr_frame_fmt =
+ amrwbplus_drv_config->amr_frame_fmt;
+ q6_amrwbplus_cfg.amr_lsf_idx =
+ amrwbplus_drv_config->amr_lsf_idx;
+
+ rc = q6asm_media_format_block_amrwbplus(audio->ac,
+ &q6_amrwbplus_cfg);
+ if (rc < 0) {
+ pr_err("q6asm_media_format_block_amrwb+ failed...\n");
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("%s:AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ case AUDIO_GET_AMRWBPLUS_CONFIG_V2: {
+ if ((audio) && (arg) && (audio->codec_cfg)) {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_amrwbplus_config_v2))) {
+ rc = -EFAULT;
+ pr_err("wb+ config get copy_to_user failed");
+ break;
+ }
+ } else {
+ pr_err("wb+ config v2 invalid parameters..");
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_AMRWBPLUS_CONFIG_V2: {
+ if ((audio) && (arg) && (audio->codec_cfg)) {
+ if (copy_from_user(audio->codec_cfg, (void *)arg,
+ sizeof(struct msm_audio_amrwbplus_config_v2))) {
+ rc = -EFAULT;
+ pr_err("wb+ config set copy_to_user_failed");
+ break;
+ }
+ } else {
+ pr_err("wb+ config invalid parameters..");
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ default:
+ pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL) {
+ pr_err("kzalloc failed for amrwb+ decode driver\n");
+ return -ENOMEM;
+ }
+ audio->codec_cfg =
+ kzalloc(sizeof(struct msm_audio_amrwbplus_config_v2), GFP_KERNEL);
+ if (audio->codec_cfg == NULL) {
+ pr_err("%s:failed kzalloc for amrwb+ config structure",
+ __func__);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+ audio->ac =
+ q6asm_audio_client_alloc((app_cb) q6_audio_cb, (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_AMR_WB_PLUS);
+ if (rc < 0) {
+ pr_err("amrwbplus NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_AMR_WB_PLUS);
+ if (rc < 0) {
+ pr_err("wb+ T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("audio_amrwbplus Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+ rc = audio_aio_open(audio, file);
+
+ config_debug_fs(audio);
+ pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_amrwbplus_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_amrwbplus_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_amrwbplus",
+ .fops = &audio_amrwbplus_fops,
+};
+
+static int __init audio_amrwbplus_init(void)
+{
+ return misc_register(&audio_amrwbplus_misc);
+}
+
+device_initcall(audio_amrwbplus_init);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 5a71b1d..166c496 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -3191,6 +3191,7 @@
flags, "smd_dev", 0);
if (r < 0)
return r;
+ interrupt_stats[SMD_MODEM].smd_interrupt_id = INT_A9_M2A_0;
r = enable_irq_wake(INT_A9_M2A_0);
if (r < 0)
pr_err("smd_core_init: "
@@ -3202,6 +3203,7 @@
free_irq(INT_A9_M2A_0, 0);
return r;
}
+ interrupt_stats[SMD_MODEM].smsm_interrupt_id = INT_A9_M2A_5;
r = enable_irq_wake(INT_A9_M2A_5);
if (r < 0)
pr_err("smd_core_init: "
@@ -3219,6 +3221,7 @@
return r;
}
+ interrupt_stats[SMD_Q6].smd_interrupt_id = INT_ADSP_A11;
r = request_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler,
flags, "smsm_dev", smsm_dsp_irq_handler);
if (r < 0) {
@@ -3228,6 +3231,7 @@
return r;
}
+ interrupt_stats[SMD_Q6].smsm_interrupt_id = INT_ADSP_A11_SMSM;
r = enable_irq_wake(INT_ADSP_A11);
if (r < 0)
pr_err("smd_core_init: "
@@ -3253,6 +3257,7 @@
return r;
}
+ interrupt_stats[SMD_DSPS].smd_interrupt_id = INT_DSPS_A11;
r = enable_irq_wake(INT_DSPS_A11);
if (r < 0)
pr_err("smd_core_init: "
@@ -3271,6 +3276,7 @@
return r;
}
+ interrupt_stats[SMD_WCNSS].smd_interrupt_id = INT_WCNSS_A11;
r = enable_irq_wake(INT_WCNSS_A11);
if (r < 0)
pr_err("smd_core_init: "
@@ -3288,6 +3294,7 @@
return r;
}
+ interrupt_stats[SMD_WCNSS].smsm_interrupt_id = INT_WCNSS_A11_SMSM;
r = enable_irq_wake(INT_WCNSS_A11_SMSM);
if (r < 0)
pr_err("smd_core_init: "
@@ -3308,6 +3315,7 @@
return r;
}
+ interrupt_stats[SMD_DSPS].smsm_interrupt_id = INT_DSPS_A11_SMSM;
r = enable_irq_wake(INT_DSPS_A11_SMSM);
if (r < 0)
pr_err("smd_core_init: "
@@ -3437,6 +3445,8 @@
goto intr_failed;
}
+ interrupt_stats[cfg->irq_config_id].smd_interrupt_id
+ = cfg->smd_int.irq_id;
/* only init smsm structs if this edge supports smsm */
if (cfg->smsm_int.irq_id)
ret = intr_init(
@@ -3452,6 +3462,9 @@
goto intr_failed;
}
+ if (cfg->smsm_int.irq_id)
+ interrupt_stats[cfg->irq_config_id].smsm_interrupt_id
+ = cfg->smsm_int.irq_id;
if (cfg->subsys_name)
strlcpy(edge_to_pids[cfg->edge].subsys_name,
cfg->subsys_name, SMD_MAX_CH_NAME_LEN);
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index d64bcf2..cc82a01 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -103,22 +103,24 @@
const char *subsys_name;
i += scnprintf(buf + i, max - i,
- " Subsystem | In | Out (Hardcoded) |"
+ " Subsystem | Interrupt ID | In | Out (Hardcoded) |"
" Out (Configured) |\n");
for (subsys = 0; subsys < NUM_SMD_SUBSYSTEMS; ++subsys) {
subsys_name = smd_pid_to_subsystem(subsys);
if (subsys_name) {
i += scnprintf(buf + i, max - i,
- "%-10s %4s | %9u | %9u | %9u |\n",
+ "%-10s %4s | %9d | %9u | %9u | %9u |\n",
smd_pid_to_subsystem(subsys), "smd",
+ stats->smd_interrupt_id,
stats->smd_in_count,
stats->smd_out_hardcode_count,
stats->smd_out_config_count);
i += scnprintf(buf + i, max - i,
- "%-10s %4s | %9u | %9u | %9u |\n",
+ "%-10s %4s | %9d | %9u | %9u | %9u |\n",
smd_pid_to_subsystem(subsys), "smsm",
+ stats->smsm_interrupt_id,
stats->smsm_in_count,
stats->smsm_out_hardcode_count,
stats->smsm_out_config_count);
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 5962d71..19be521 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -35,12 +35,13 @@
#include <mach/msm_smd.h>
#include <mach/peripheral-loader.h>
+#include <mach/msm_ipc_logging.h>
#include "smd_private.h"
#ifdef CONFIG_ARCH_FSM9XXX
#define NUM_SMD_PKT_PORTS 4
#else
-#define NUM_SMD_PKT_PORTS 15
+#define NUM_SMD_PKT_PORTS 24
#endif
#define PDRIVER_NAME_MAX_SIZE 32
@@ -65,6 +66,7 @@
wait_queue_head_t ch_opened_wait_queue;
int i;
+ int ref_cnt;
int blocking_write;
int is_open;
@@ -88,6 +90,9 @@
static void check_and_wakeup_writer(struct smd_pkt_dev *smd_pkt_devp);
static uint32_t is_modem_smsm_inited(void);
+#define SMD_PKT_IPC_LOG_PAGE_CNT 2
+static void *smd_pkt_ilctxt;
+
static int msm_smd_pkt_debug_mask;
module_param_named(debug_mask, msm_smd_pkt_debug_mask,
int, S_IRUGO | S_IWUSR | S_IWGRP);
@@ -104,22 +109,44 @@
#define DEBUG
#ifdef DEBUG
+
+#define SMD_PKT_LOG_STRING(x...) \
+do { \
+ if (smd_pkt_ilctxt) \
+ ipc_log_string(smd_pkt_ilctxt, "<SMD_PKT>: "x); \
+} while (0)
+
+#define SMD_PKT_LOG_BUF(buf, cnt) \
+do { \
+ char log_buf[128]; \
+ int i; \
+ if (smd_pkt_ilctxt) { \
+ i = cnt < 16 ? cnt : 16; \
+ hex_dump_to_buffer(buf, i, 16, 1, log_buf, \
+ sizeof(log_buf), false); \
+ ipc_log_string(smd_pkt_ilctxt, "<SMD_PKT>: %s", log_buf); \
+ } \
+} while (0)
+
#define D_STATUS(x...) \
do { \
if (msm_smd_pkt_debug_mask & SMD_PKT_STATUS) \
pr_info("Status: "x); \
+ SMD_PKT_LOG_STRING(x); \
} while (0)
#define D_READ(x...) \
do { \
if (msm_smd_pkt_debug_mask & SMD_PKT_READ) \
pr_info("Read: "x); \
+ SMD_PKT_LOG_STRING(x); \
} while (0)
#define D_WRITE(x...) \
do { \
if (msm_smd_pkt_debug_mask & SMD_PKT_WRITE) \
pr_info("Write: "x); \
+ SMD_PKT_LOG_STRING(x); \
} while (0)
#define D_READ_DUMP_BUFFER(prestr, cnt, buf) \
@@ -128,6 +155,7 @@
print_hex_dump(KERN_INFO, prestr, \
DUMP_PREFIX_NONE, 16, 1, \
buf, cnt, 1); \
+ SMD_PKT_LOG_BUF(buf, cnt); \
} while (0)
#define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) \
@@ -136,12 +164,14 @@
print_hex_dump(KERN_INFO, prestr, \
DUMP_PREFIX_NONE, 16, 1, \
buf, cnt, 1); \
+ SMD_PKT_LOG_BUF(buf, cnt); \
} while (0)
#define D_POLL(x...) \
do { \
if (msm_smd_pkt_debug_mask & SMD_PKT_POLL) \
pr_info("Poll: "x); \
+ SMD_PKT_LOG_STRING(x); \
} while (0)
#define E_SMD_PKT_SSR(x) \
@@ -270,6 +300,7 @@
if (!smd_pkt_devp)
return -EINVAL;
+ mutex_lock(&smd_pkt_devp->ch_lock);
switch (cmd) {
case TIOCMGET:
D_STATUS("%s TIOCMGET command on smd_pkt_dev id:%d\n",
@@ -288,6 +319,7 @@
pr_err("%s: Unrecognized ioctl command %d\n", __func__, cmd);
ret = -1;
}
+ mutex_unlock(&smd_pkt_devp->ch_lock);
return ret;
}
@@ -679,6 +711,15 @@
"smdcntl6",
"smdcntl7",
"smd22",
+ "smdcnt_rev0",
+ "smdcnt_rev1",
+ "smdcnt_rev2",
+ "smdcnt_rev3",
+ "smdcnt_rev4",
+ "smdcnt_rev5",
+ "smdcnt_rev6",
+ "smdcnt_rev7",
+ "smdcnt_rev8",
"smd_sns_dsps",
"apr_apps2",
"smdcntl8",
@@ -697,6 +738,15 @@
"DATA13_CNTL",
"DATA14_CNTL",
"DATA22",
+ "DATA23_CNTL",
+ "DATA24_CNTL",
+ "DATA25_CNTL",
+ "DATA26_CNTL",
+ "DATA27_CNTL",
+ "DATA28_CNTL",
+ "DATA29_CNTL",
+ "DATA30_CNTL",
+ "DATA31_CNTL",
"SENSOR",
"apr_apps2",
"DATA40_CNTL",
@@ -715,6 +765,15 @@
SMD_APPS_MODEM,
SMD_APPS_MODEM,
SMD_APPS_MODEM,
+ SMD_APPS_MODEM,
+ SMD_APPS_MODEM,
+ SMD_APPS_MODEM,
+ SMD_APPS_MODEM,
+ SMD_APPS_MODEM,
+ SMD_APPS_MODEM,
+ SMD_APPS_MODEM,
+ SMD_APPS_MODEM,
+ SMD_APPS_MODEM,
SMD_APPS_DSPS,
SMD_APPS_QDSP,
SMD_APPS_MODEM,
@@ -867,9 +926,12 @@
smd_pkt_devp->ch_size =
smd_write_avail(smd_pkt_devp->ch);
r = 0;
+ smd_pkt_devp->ref_cnt++;
D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
__func__, smd_pkt_devp->i);
}
+ } else {
+ smd_pkt_devp->ref_cnt++;
}
release_pil:
if (peripheral && (r < 0))
@@ -902,12 +964,14 @@
D_STATUS("Begin %s on smd_pkt_dev id:%d\n",
__func__, smd_pkt_devp->i);
- clean_and_signal(smd_pkt_devp);
-
mutex_lock(&smd_pkt_devp->ch_lock);
mutex_lock(&smd_pkt_devp->rx_lock);
mutex_lock(&smd_pkt_devp->tx_lock);
- if (smd_pkt_devp->ch != 0) {
+ if (smd_pkt_devp->ref_cnt > 0)
+ smd_pkt_devp->ref_cnt--;
+
+ if (smd_pkt_devp->ch != 0 && smd_pkt_devp->ref_cnt == 0) {
+ clean_and_signal(smd_pkt_devp);
r = smd_close(smd_pkt_devp->ch);
smd_pkt_devp->ch = 0;
smd_pkt_devp->blocking_write = 0;
@@ -916,15 +980,15 @@
smd_pkt_devp->driver.probe = NULL;
if (smd_pkt_devp->pil)
pil_put(smd_pkt_devp->pil);
+ smd_pkt_devp->has_reset = 0;
+ smd_pkt_devp->do_reset_notification = 0;
+ smd_pkt_devp->wakelock_locked = 0;
+ wake_lock_destroy(&smd_pkt_devp->pa_wake_lock);
}
mutex_unlock(&smd_pkt_devp->tx_lock);
mutex_unlock(&smd_pkt_devp->rx_lock);
mutex_unlock(&smd_pkt_devp->ch_lock);
- smd_pkt_devp->has_reset = 0;
- smd_pkt_devp->do_reset_notification = 0;
- smd_pkt_devp->wakelock_locked = 0;
- wake_lock_destroy(&smd_pkt_devp->pa_wake_lock);
D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
__func__, smd_pkt_devp->i);
@@ -1024,6 +1088,9 @@
INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
+ smd_pkt_ilctxt = ipc_log_context_create(SMD_PKT_IPC_LOG_PAGE_CNT,
+ "smd_pkt");
+
D_STATUS("SMD Packet Port Driver Initialized.\n");
return 0;
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 9117280..7f39a24 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -255,10 +255,12 @@
uint32_t smd_in_count;
uint32_t smd_out_hardcode_count;
uint32_t smd_out_config_count;
+ uint32_t smd_interrupt_id;
uint32_t smsm_in_count;
uint32_t smsm_out_hardcode_count;
uint32_t smsm_out_config_count;
+ uint32_t smsm_interrupt_id;
};
extern struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index eb2b64b..4d0e060 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -293,7 +293,10 @@
[154] = MSM_CPU_8930AB,
[155] = MSM_CPU_8930AB,
[156] = MSM_CPU_8930AB,
- [157] = MSM_CPU_8930AB
+ [157] = MSM_CPU_8930AB,
+
+ /* 8064AA IDs */
+ [172] = MSM_CPU_8064AA,
/* Uninitialized IDs are not known to run Linux.
MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
diff --git a/drivers/char/diag/Kconfig b/drivers/char/diag/Kconfig
index 8f8707f..91fcdfc 100644
--- a/drivers/char/diag/Kconfig
+++ b/drivers/char/diag/Kconfig
@@ -30,9 +30,9 @@
SDIO Transport Layer for DIAG Router
endmenu
-menu "HSIC support for DIAG"
+menu "HSIC/SMUX support for DIAG"
-config DIAG_BRIDGE_CODE
+config DIAGFWD_BRIDGE_CODE
depends on USB_QCOM_DIAG_BRIDGE
default y
bool "Enable QSC/9K DIAG traffic over SMUX/HSIC"
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index 6ecc970..c9204ea 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_DIAG_CHAR) := diagchar.o
obj-$(CONFIG_DIAG_SDIO_PIPE) += diagfwd_sdio.o
-obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_hsic.o
-obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_smux.o
+obj-$(CONFIG_DIAGFWD_BRIDGE_CODE) += diagfwd_bridge.o
+obj-$(CONFIG_DIAGFWD_BRIDGE_CODE) += diagfwd_hsic.o
+obj-$(CONFIG_DIAGFWD_BRIDGE_CODE) += diagfwd_smux.o
diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagmem.o diagfwd_cntl.o diag_dci.o diag_masks.o diag_debugfs.o
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 24fc99a..d4b1856 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -38,73 +38,48 @@
struct mutex dci_log_mask_mutex;
struct mutex dci_event_mask_mutex;
-smd_channel_t *ch_dci_temp;
-
#define DCI_CHK_CAPACITY(entry, new_data_len) \
((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0) \
-static void diag_smd_dci_send_req(int proc_num)
+/* Process the data read from the smd dci channel */
+int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf,
+ int recd_bytes)
{
- void *buf = NULL;
- smd_channel_t *smd_ch = NULL;
- int recd_bytes, read_bytes, dci_pkt_len, i;
+ int read_bytes, dci_pkt_len, i;
uint8_t recv_pkt_cmd_code;
- if (driver->in_busy_dci)
- return;
-
- if (proc_num == MODEM_PROC) {
- buf = driver->buf_in_dci;
- smd_ch = driver->ch_dci;
+ /* Each SMD read can have multiple DCI packets */
+ read_bytes = 0;
+ while (read_bytes < recd_bytes) {
+ /* read actual length of dci pkt */
+ dci_pkt_len = *(uint16_t *)(buf+2);
+ /* process one dci packet */
+ pr_debug("diag: bytes read = %d, single dci pkt len = %d\n",
+ read_bytes, dci_pkt_len);
+ /* print_hex_dump(KERN_DEBUG, "Single DCI packet :",
+ DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1);*/
+ recv_pkt_cmd_code = *(uint8_t *)(buf+4);
+ if (recv_pkt_cmd_code == LOG_CMD_CODE)
+ extract_dci_log(buf+4);
+ else if (recv_pkt_cmd_code == EVENT_CMD_CODE)
+ extract_dci_events(buf+4);
+ else
+ extract_dci_pkt_rsp(buf); /* pkt response */
+ read_bytes += 5 + dci_pkt_len;
+ buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
}
-
- if (!smd_ch || !buf)
- return;
-
- recd_bytes = smd_read_avail(smd_ch);
- if (recd_bytes > IN_BUF_SIZE) {
- if (recd_bytes < MAX_IN_BUF_SIZE) {
- pr_err("diag: SMD DCI sending pkt upto %d bytes",
- recd_bytes);
- buf = krealloc(buf, recd_bytes, GFP_KERNEL);
- } else {
- pr_err("diag: DCI pkt > %d bytes", MAX_IN_BUF_SIZE);
- return;
+ /* wake up all sleeping DCI clients which have some data */
+ for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ if (driver->dci_client_tbl[i].client &&
+ driver->dci_client_tbl[i].data_len) {
+ smd_info->in_busy_1 = 1;
+ diag_update_sleeping_process(
+ driver->dci_client_tbl[i].client->tgid,
+ DCI_DATA_TYPE);
}
}
- if (buf && recd_bytes > 0) {
- smd_read(smd_ch, buf, recd_bytes);
- pr_debug("diag: data received %d bytes\n", recd_bytes);
- /* Each SMD read can have multiple DCI packets */
- read_bytes = 0;
- while (read_bytes < recd_bytes) {
- /* read actual length of dci pkt */
- dci_pkt_len = *(uint16_t *)(buf+2);
- /* process one dci packet */
- pr_debug("diag: bytes read = %d, single dci pkt len = %d\n",
- read_bytes, dci_pkt_len);
- /* print_hex_dump(KERN_DEBUG, "Single DCI packet :",
- DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1);*/
- recv_pkt_cmd_code = *(uint8_t *)(buf+4);
- if (recv_pkt_cmd_code == LOG_CMD_CODE)
- extract_dci_log(buf+4);
- else if (recv_pkt_cmd_code == EVENT_CMD_CODE)
- extract_dci_events(buf+4);
- else
- extract_dci_pkt_rsp(buf); /* pkt response */
- read_bytes += 5 + dci_pkt_len;
- buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
- }
- /* wake up all sleeping DCI clients which have some data */
- for (i = 0; i < MAX_DCI_CLIENTS; i++)
- if (driver->dci_client_tbl[i].client &&
- driver->dci_client_tbl[i].data_len) {
- driver->in_busy_dci = 1;
- diag_update_sleeping_process(
- driver->dci_client_tbl[i].client->tgid,
- DCI_DATA_TYPE);
- }
- }
+
+ return 0;
}
void extract_dci_pkt_rsp(unsigned char *buf)
@@ -163,7 +138,8 @@
buf+4+cmd_code_len, write_len);
entry->data_len += write_len;
/* delete immediate response entry */
- if (driver->buf_in_dci[8+cmd_code_len] != 0x80)
+ if (driver->smd_dci[MODEM_DATA].
+ buf_in_1[8+cmd_code_len] != 0x80)
driver->req_tracking_tbl[index].pid = 0;
break;
}
@@ -303,23 +279,22 @@
}
}
-void diag_read_smd_dci_work_fn(struct work_struct *work)
-{
- diag_smd_dci_send_req(MODEM_PROC);
-}
-
void diag_update_smd_dci_work_fn(struct work_struct *work)
{
+ struct diag_smd_info *smd_info = container_of(work,
+ struct diag_smd_info,
+ diag_notify_update_smd_work);
int i, j;
char dirty_bits[16];
uint8_t *client_log_mask_ptr;
uint8_t *log_mask_ptr;
int ret;
+ int index = smd_info->peripheral;
/* Update the peripheral(s) with the dci log and event masks */
/* If the cntl channel is not up, we can't update logs and events */
- if (!driver->ch_cntl)
+ if (!driver->smd_cntl[index].ch)
return;
memset(dirty_bits, 0, 16 * sizeof(uint8_t));
@@ -352,9 +327,11 @@
}
mutex_unlock(&dci_log_mask_mutex);
- ret = diag_send_dci_log_mask(driver->ch_cntl);
+ ret = diag_send_dci_log_mask(driver->smd_cntl[index].ch);
- ret = diag_send_dci_event_mask(driver->ch_cntl);
+ ret = diag_send_dci_event_mask(driver->smd_cntl[index].ch);
+
+ smd_info->notify_context = 0;
}
void diag_dci_notify_client(int peripheral_mask, int data)
@@ -380,41 +357,23 @@
} /* end of loop for all DCI clients */
}
-static void diag_smd_dci_notify(void *ctxt, unsigned event)
-{
- if (event == SMD_EVENT_CLOSE) {
- driver->ch_dci = 0;
- /* Notify the clients of the close */
- diag_dci_notify_client(DIAG_CON_MPSS, DIAG_STATUS_CLOSED);
- return;
- } else if (event == SMD_EVENT_OPEN) {
-
- if (ch_dci_temp)
- driver->ch_dci = ch_dci_temp;
-
- queue_work(driver->diag_dci_wq,
- &(driver->diag_update_smd_dci_work));
-
- /* Notify the clients of the open */
- diag_dci_notify_client(DIAG_CON_MPSS, DIAG_STATUS_OPEN);
- }
-
- queue_work(driver->diag_dci_wq, &(driver->diag_read_smd_dci_work));
-}
-
static int diag_dci_probe(struct platform_device *pdev)
{
int err = 0;
+ int index;
if (pdev->id == SMD_APPS_MODEM) {
- err = smd_open("DIAG_2", &driver->ch_dci, driver,
- diag_smd_dci_notify);
+ index = MODEM_DATA;
+ err = smd_open("DIAG_2", &driver->smd_dci[index].ch,
+ &driver->smd_dci[index],
+ diag_smd_notify);
+ driver->smd_dci[index].ch_save =
+ driver->smd_dci[index].ch;
if (err)
- pr_err("diag: cannot open DCI port, Id = %d, err ="
- " %d\n", pdev->id, err);
- else
- ch_dci_temp = driver->ch_dci;
+ pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
+ __func__, pdev->id, err);
}
+
return err;
}
@@ -422,6 +381,7 @@
int len, int index)
{
int i;
+ int status = 0;
/* remove UID from user space pkt before sending to peripheral */
buf = buf + 4;
@@ -439,15 +399,23 @@
driver->apps_dci_buf[9+len] = CONTROL_CHAR; /* end */
- if (entry.client_id == MODEM_PROC && driver->ch_dci) {
- smd_write(driver->ch_dci, driver->apps_dci_buf, len + 10);
- i = DIAG_DCI_NO_ERROR;
- } else {
+ for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
+ if (entry.client_id == driver->smd_dci[i].peripheral) {
+ if (driver->smd_dci[i].ch) {
+ smd_write(driver->smd_dci[i].ch,
+ driver->apps_dci_buf, len + 10);
+ status = DIAG_DCI_NO_ERROR;
+ }
+ break;
+ }
+ }
+
+ if (status != DIAG_DCI_NO_ERROR) {
pr_alert("diag: check DCI channel\n");
- i = DIAG_DCI_SEND_DATA_FAIL;
+ status = DIAG_DCI_SEND_DATA_FAIL;
}
mutex_unlock(&driver->dci_mutex);
- return i;
+ return status;
}
int diag_register_dci_transaction(int uid)
@@ -487,8 +455,9 @@
uint8_t *event_mask_ptr;
int offset = 0;
- if (!driver->ch_dci) {
- pr_err("diag: ch_dci not valid for dci updates\n");
+ if (!driver->smd_dci[MODEM_DATA].ch) {
+ pr_err("diag: DCI smd channel for peripheral %d not valid for dci updates\n",
+ driver->smd_dci[MODEM_DATA].peripheral);
return DIAG_DCI_SEND_DATA_FAIL;
}
@@ -613,7 +582,7 @@
ret = DIAG_DCI_NO_ERROR;
}
/* send updated mask to peripherals */
- ret = diag_send_dci_log_mask(driver->ch_cntl);
+ ret = diag_send_dci_log_mask(driver->smd_cntl[MODEM_DATA].ch);
} else if (*(int *)temp == DCI_EVENT_TYPE) {
/* find client id and table */
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
@@ -659,7 +628,7 @@
ret = DIAG_DCI_NO_ERROR;
}
/* send updated mask to peripherals */
- ret = diag_send_dci_event_mask(driver->ch_cntl);
+ ret = diag_send_dci_event_mask(driver->smd_cntl[MODEM_DATA].ch);
} else {
pr_alert("diag: Incorrect DCI transaction\n");
}
@@ -872,27 +841,19 @@
int diag_dci_init(void)
{
int success = 0;
-
- ch_dci_temp = NULL;
+ int i;
driver->dci_tag = 0;
driver->dci_client_id = 0;
driver->num_dci_client = 0;
- driver->in_busy_dci = 0;
mutex_init(&driver->dci_mutex);
mutex_init(&dci_log_mask_mutex);
mutex_init(&dci_event_mask_mutex);
- if (driver->buf_in_dci == NULL) {
- driver->buf_in_dci = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_dci == NULL)
- goto err;
- }
- if (driver->write_ptr_dci == NULL) {
- driver->write_ptr_dci = kzalloc(
- sizeof(struct diag_write_device), GFP_KERNEL);
- if (driver->write_ptr_dci == NULL)
- goto err;
- }
+ success = diag_smd_constructor(&driver->smd_dci[MODEM_DATA],
+ MODEM_DATA, SMD_DCI_TYPE);
+ if (!success)
+ goto err;
+
if (driver->req_tracking_tbl == NULL) {
driver->req_tracking_tbl = kzalloc(dci_max_reg *
sizeof(struct dci_pkt_req_tracking_tbl), GFP_KERNEL);
@@ -922,8 +883,8 @@
kfree(driver->req_tracking_tbl);
kfree(driver->dci_client_tbl);
kfree(driver->apps_dci_buf);
- kfree(driver->buf_in_dci);
- kfree(driver->write_ptr_dci);
+ for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
+ diag_smd_destructor(&driver->smd_dci[i]);
if (driver->diag_dci_wq)
destroy_workqueue(driver->diag_dci_wq);
return DIAG_DCI_NO_REG;
@@ -931,13 +892,14 @@
void diag_dci_exit(void)
{
- smd_close(driver->ch_dci);
- driver->ch_dci = 0;
+ int i;
+
+ for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
+ diag_smd_destructor(&driver->smd_dci[i]);
+
platform_driver_unregister(&msm_diag_dci_driver);
kfree(driver->req_tracking_tbl);
kfree(driver->dci_client_tbl);
kfree(driver->apps_dci_buf);
- kfree(driver->buf_in_dci);
- kfree(driver->write_ptr_dci);
destroy_workqueue(driver->diag_dci_wq);
}
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 3f62e5e..af89ac8 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -78,8 +78,10 @@
int diag_dci_init(void);
void diag_dci_exit(void);
-void diag_read_smd_dci_work_fn(struct work_struct *);
void diag_update_smd_dci_work_fn(struct work_struct *);
+void diag_dci_notify_client(int peripheral_mask, int data);
+int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf,
+ int recd_bytes);
int diag_process_dci_transaction(unsigned char *buf, int len);
int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
int len, int index);
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 0048007..d852d75 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -16,6 +16,7 @@
#include <linux/debugfs.h>
#include "diagchar.h"
#include "diagfwd.h"
+#include "diagfwd_bridge.h"
#define DEBUG_BUF_SIZE 4096
static struct dentry *diag_dbgfs_dent;
@@ -47,34 +48,34 @@
"Check Polling Response: %d\n"
"polling_reg_flag: %d\n"
"uses device tree: %d\n"
- "in_busy_1: %d\n"
- "in_busy_2: %d\n"
- "in_busy_lpass_1: %d\n"
- "in_busy_lpass_2: %d\n"
- "in_busy_wcnss_1: %d\n"
- "in_busy_wcnss_2: %d\n"
- "in_busy_dci: %d\n"
+ "Modem in_busy_1: %d\n"
+ "Modem in_busy_2: %d\n"
+ "LPASS in_busy_1: %d\n"
+ "LPASS in_busy_2: %d\n"
+ "RIVA in_busy_1: %d\n"
+ "RIVA in_busy_2: %d\n"
+ "DCI Modem in_busy_1: %d\n"
"logging_mode: %d\n",
- (unsigned int)driver->ch,
- (unsigned int)driver->chlpass,
- (unsigned int)driver->ch_wcnss,
- (unsigned int)driver->ch_dci,
- (unsigned int)driver->ch_cntl,
- (unsigned int)driver->chlpass_cntl,
- (unsigned int)driver->ch_wcnss_cntl,
+ (unsigned int)driver->smd_data[MODEM_DATA].ch,
+ (unsigned int)driver->smd_data[LPASS_DATA].ch,
+ (unsigned int)driver->smd_data[WCNSS_DATA].ch,
+ (unsigned int)driver->smd_dci[MODEM_DATA].ch,
+ (unsigned int)driver->smd_cntl[MODEM_DATA].ch,
+ (unsigned int)driver->smd_cntl[LPASS_DATA].ch,
+ (unsigned int)driver->smd_cntl[WCNSS_DATA].ch,
chk_config_get_id(),
chk_apps_only(),
chk_apps_master(),
chk_polling_response(),
driver->polling_reg_flag,
driver->use_device_tree,
- driver->in_busy_1,
- driver->in_busy_2,
- driver->in_busy_lpass_1,
- driver->in_busy_lpass_2,
- driver->in_busy_wcnss_1,
- driver->in_busy_wcnss_2,
- driver->in_busy_dci,
+ driver->smd_data[MODEM_DATA].in_busy_1,
+ driver->smd_data[MODEM_DATA].in_busy_2,
+ driver->smd_data[LPASS_DATA].in_busy_1,
+ driver->smd_data[LPASS_DATA].in_busy_2,
+ driver->smd_data[WCNSS_DATA].in_busy_1,
+ driver->smd_data[WCNSS_DATA].in_busy_2,
+ driver->smd_dci[MODEM_DATA].in_busy_1,
driver->logging_mode);
#ifdef CONFIG_DIAG_OVER_USB
@@ -103,29 +104,49 @@
ret = scnprintf(buf, DEBUG_BUF_SIZE,
"Pending status for work_stucts:\n"
"diag_drain_work: %d\n"
- "diag_read_smd_work: %d\n"
- "diag_read_smd_cntl_work: %d\n"
- "diag_read_smd_lpass_work: %d\n"
- "diag_read_smd_lpass_cntl_work: %d\n"
- "diag_read_smd_wcnss_work: %d\n"
- "diag_read_smd_wcnss_cntl_work: %d\n"
- "diag_modem_mask_update_work: %d\n"
- "diag_lpass_mask_update_work: %d\n"
- "diag_wcnss_mask_update_work: %d\n"
- "diag_read_smd_dci_work: %d\n"
- "diag_update_smd_dci_work: %d\n",
+ "Modem data diag_read_smd_work: %d\n"
+ "LPASS data diag_read_smd_work: %d\n"
+ "RIVA data diag_read_smd_work: %d\n"
+ "Modem cntl diag_read_smd_work: %d\n"
+ "LPASS cntl diag_read_smd_work: %d\n"
+ "RIVA cntl diag_read_smd_work: %d\n"
+ "Modem dci diag_read_smd_work: %d\n"
+ "Modem data diag_notify_update_smd_work: %d\n"
+ "LPASS data diag_notify_update_smd_work: %d\n"
+ "RIVA data diag_notify_update_smd_work: %d\n"
+ "Modem cntl diag_notify_update_smd_work: %d\n"
+ "LPASS cntl diag_notify_update_smd_work: %d\n"
+ "RIVA cntl diag_notify_update_smd_work: %d\n"
+ "Modem dci diag_notify_update_smd_work: %d\n",
work_pending(&(driver->diag_drain_work)),
- work_pending(&(driver->diag_read_smd_work)),
- work_pending(&(driver->diag_read_smd_cntl_work)),
- work_pending(&(driver->diag_read_smd_lpass_work)),
- work_pending(&(driver->diag_read_smd_lpass_cntl_work)),
- work_pending(&(driver->diag_read_smd_wcnss_work)),
- work_pending(&(driver->diag_read_smd_wcnss_cntl_work)),
- work_pending(&(driver->diag_modem_mask_update_work)),
- work_pending(&(driver->diag_lpass_mask_update_work)),
- work_pending(&(driver->diag_wcnss_mask_update_work)),
- work_pending(&(driver->diag_read_smd_dci_work)),
- work_pending(&(driver->diag_update_smd_dci_work)));
+ work_pending(&(driver->smd_data[MODEM_DATA].
+ diag_read_smd_work)),
+ work_pending(&(driver->smd_data[LPASS_DATA].
+ diag_read_smd_work)),
+ work_pending(&(driver->smd_data[WCNSS_DATA].
+ diag_read_smd_work)),
+ work_pending(&(driver->smd_cntl[MODEM_DATA].
+ diag_read_smd_work)),
+ work_pending(&(driver->smd_cntl[LPASS_DATA].
+ diag_read_smd_work)),
+ work_pending(&(driver->smd_cntl[WCNSS_DATA].
+ diag_read_smd_work)),
+ work_pending(&(driver->smd_dci[MODEM_DATA].
+ diag_read_smd_work)),
+ work_pending(&(driver->smd_data[MODEM_DATA].
+ diag_notify_update_smd_work)),
+ work_pending(&(driver->smd_data[LPASS_DATA].
+ diag_notify_update_smd_work)),
+ work_pending(&(driver->smd_data[WCNSS_DATA].
+ diag_notify_update_smd_work)),
+ work_pending(&(driver->smd_cntl[MODEM_DATA].
+ diag_notify_update_smd_work)),
+ work_pending(&(driver->smd_cntl[LPASS_DATA].
+ diag_notify_update_smd_work)),
+ work_pending(&(driver->smd_cntl[WCNSS_DATA].
+ diag_notify_update_smd_work)),
+ work_pending(&(driver->smd_dci[MODEM_DATA].
+ diag_notify_update_smd_work)));
#ifdef CONFIG_DIAG_OVER_USB
ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
@@ -164,6 +185,15 @@
}
bytes_remaining = buf_size;
+
+ if (diag_dbgfs_table_index == 0) {
+ bytes_written = scnprintf(buf+bytes_in_buffer, bytes_remaining,
+ "Client ids: Modem: %d, LPASS: %d, "
+ "WCNSS: %d, APPS: %d\n",
+ MODEM_DATA, LPASS_DATA, WCNSS_DATA, APPS_DATA);
+ bytes_in_buffer += bytes_written;
+ }
+
for (i = diag_dbgfs_table_index; i < diag_max_reg; i++) {
/* Do not process empty entries in the table */
if (driver->table[i].process_id == 0)
@@ -188,7 +218,7 @@
if (bytes_remaining < bytes_written)
break;
}
- diag_dbgfs_table_index = i;
+ diag_dbgfs_table_index = i+1;
*ppos = 0;
ret = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buffer);
@@ -197,8 +227,8 @@
return ret;
}
-#ifdef CONFIG_DIAG_BRIDGE_CODE
-static ssize_t diag_dbgfs_read_hsic(struct file *file, char __user *ubuf,
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+static ssize_t diag_dbgfs_read_bridge(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
char *buf;
@@ -222,13 +252,17 @@
"count_hsic_write_pool: %d\n"
"diag_hsic_pool: %x\n"
"diag_hsic_write_pool: %x\n"
- "write_len_mdm: %d\n"
+ "HSIC write_len: %d\n"
"num_hsic_buf_tbl_entries: %d\n"
- "usb_mdm_connected: %d\n"
- "diag_read_mdm_work: %d\n"
+ "HSIC usb_connected: %d\n"
+ "HSIC diag_read_work: %d\n"
"diag_read_hsic_work: %d\n"
"diag_disconnect_work: %d\n"
- "diag_usb_read_complete_work: %d\n",
+ "diag_usb_read_complete_work: %d\n"
+ "smux ch: %d\n"
+ "smux enabled %d\n"
+ "smux in busy %d\n"
+ "smux connected %d\n",
driver->hsic_ch,
driver->hsic_inited,
driver->hsic_device_enabled,
@@ -240,13 +274,17 @@
driver->count_hsic_write_pool,
(unsigned int)driver->diag_hsic_pool,
(unsigned int)driver->diag_hsic_write_pool,
- driver->write_len_mdm,
+ diag_bridge[HSIC].write_len,
driver->num_hsic_buf_tbl_entries,
- driver->usb_mdm_connected,
- work_pending(&(driver->diag_read_mdm_work)),
+ diag_bridge[HSIC].usb_connected,
+ work_pending(&(diag_bridge[HSIC].diag_read_work)),
work_pending(&(driver->diag_read_hsic_work)),
work_pending(&(driver->diag_disconnect_work)),
- work_pending(&(driver->diag_usb_read_complete_work)));
+ work_pending(&(diag_bridge[HSIC].usb_read_complete_work)),
+ driver->lcid,
+ driver->diag_smux_enabled,
+ driver->in_busy_smux,
+ driver->smux_connected);
ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
@@ -254,8 +292,8 @@
return ret;
}
-const struct file_operations diag_dbgfs_hsic_ops = {
- .read = diag_dbgfs_read_hsic,
+const struct file_operations diag_dbgfs_bridge_ops = {
+ .read = diag_dbgfs_read_bridge,
};
#endif
@@ -286,9 +324,9 @@
debugfs_create_file("work_pending", 0444, diag_dbgfs_dent, 0,
&diag_dbgfs_workpending_ops);
-#ifdef CONFIG_DIAG_BRIDGE_CODE
- debugfs_create_file("hsic", 0444, diag_dbgfs_dent, 0,
- &diag_dbgfs_hsic_ops);
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+ debugfs_create_file("bridge", 0444, diag_dbgfs_dent, 0,
+ &diag_dbgfs_bridge_ops);
#endif
diag_dbgfs_table_index = 0;
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 5316548..e8567db 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -26,6 +26,9 @@
#define ALL_SSID -1
#define MAX_SSID_PER_RANGE 100
+#define FEATURE_MASK_LEN_BYTES 1
+#define APPS_RESPOND_LOG_ON_DEMAND 0x04
+
struct mask_info {
int equip_id;
int num_items;
@@ -294,29 +297,24 @@
mutex_unlock(&driver->diagchar_mutex);
}
-void diag_modem_mask_update_fn(struct work_struct *work)
+void diag_mask_update_fn(struct work_struct *work)
{
- diag_send_msg_mask_update(driver->ch_cntl, ALL_SSID,
- ALL_SSID, MODEM_PROC);
- diag_send_log_mask_update(driver->ch_cntl, ALL_EQUIP_ID);
- diag_send_event_mask_update(driver->ch_cntl, diag_event_num_bytes);
-}
+ struct diag_smd_info *smd_info = container_of(work,
+ struct diag_smd_info,
+ diag_notify_update_smd_work);
+ if (!smd_info) {
+ pr_err("diag: In %s, smd info is null, cannot update masks for the peripheral\n",
+ __func__);
+ return;
+ }
-void diag_lpass_mask_update_fn(struct work_struct *work)
-{
- diag_send_msg_mask_update(driver->chlpass_cntl, ALL_SSID,
- ALL_SSID, LPASS_PROC);
- diag_send_log_mask_update(driver->chlpass_cntl, ALL_EQUIP_ID);
- diag_send_event_mask_update(driver->chlpass_cntl, diag_event_num_bytes);
-}
+ diag_send_msg_mask_update(smd_info->ch, ALL_SSID, ALL_SSID,
+ smd_info->peripheral);
+ diag_send_log_mask_update(smd_info->ch, ALL_EQUIP_ID);
+ diag_send_event_mask_update(smd_info->ch, diag_event_num_bytes);
+ diag_send_feature_mask_update(smd_info->ch, smd_info->peripheral);
-void diag_wcnss_mask_update_fn(struct work_struct *work)
-{
- diag_send_msg_mask_update(driver->ch_wcnss_cntl, ALL_SSID,
- ALL_SSID, WCNSS_PROC);
- diag_send_log_mask_update(driver->ch_wcnss_cntl, ALL_EQUIP_ID);
- diag_send_event_mask_update(driver->ch_wcnss_cntl,
- diag_event_num_bytes);
+ smd_info->notify_context = 0;
}
void diag_send_log_mask_update(smd_channel_t *ch, int equip_id)
@@ -467,6 +465,42 @@
mutex_unlock(&driver->diag_cntl_mutex);
}
+void diag_send_feature_mask_update(smd_channel_t *ch, int proc)
+{
+ void *buf = driver->buf_feature_mask_update;
+ int header_size = sizeof(struct diag_ctrl_feature_mask);
+ int wr_size = -ENOMEM, retry_count = 0, timer;
+ uint8_t feature_byte = 0;
+
+ mutex_lock(&driver->diag_cntl_mutex);
+ /* send feature mask update */
+ driver->feature_mask->ctrl_pkt_id = DIAG_CTRL_MSG_FEATURE;
+ driver->feature_mask->ctrl_pkt_data_len = 4 + FEATURE_MASK_LEN_BYTES;
+ driver->feature_mask->feature_mask_len = FEATURE_MASK_LEN_BYTES;
+ memcpy(buf, driver->feature_mask, header_size);
+ feature_byte |= APPS_RESPOND_LOG_ON_DEMAND;
+ memcpy(buf+header_size, &feature_byte, FEATURE_MASK_LEN_BYTES);
+
+ if (ch) {
+ while (retry_count < 3) {
+ wr_size = smd_write(ch, buf, header_size +
+ FEATURE_MASK_LEN_BYTES);
+ if (wr_size == -ENOMEM) {
+ retry_count++;
+ for (timer = 0; timer < 5; timer++)
+ udelay(2000);
+ } else
+ break;
+ }
+ if (wr_size != header_size + FEATURE_MASK_LEN_BYTES)
+ pr_err("diag: proc %d fail feature update %d, tried %d",
+ proc, wr_size, header_size + FEATURE_MASK_LEN_BYTES);
+ } else
+ pr_err("diag: ch invalid, feature update on proc %d\n", proc);
+ mutex_unlock(&driver->diag_cntl_mutex);
+
+}
+
int diag_process_apps_masks(unsigned char *buf, int len)
{
int packet_type = 1;
@@ -493,15 +527,13 @@
payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
for (i = 0; i < payload_length; i++)
*(int *)(driver->apps_rsp_buf+12+i) = *(buf+i);
- if (driver->ch_cntl)
- diag_send_log_mask_update(driver->ch_cntl,
- *(int *)buf);
- if (driver->chlpass_cntl)
- diag_send_log_mask_update(driver->chlpass_cntl,
- *(int *)buf);
- if (driver->ch_wcnss_cntl)
- diag_send_log_mask_update(driver->ch_wcnss_cntl,
- *(int *)buf);
+
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+ if (driver->smd_cntl[i].ch)
+ diag_send_log_mask_update(
+ driver->smd_cntl[i].ch,
+ *(int *)buf);
+ }
encode_rsp_and_send(12 + payload_length - 1);
return 0;
}
@@ -509,7 +541,8 @@
} /* Get log masks */
else if (*buf == 0x73 && *(int *)(buf+4) == 4) {
#if defined(CONFIG_DIAG_OVER_USB)
- if (!(driver->ch) && chk_apps_only()) {
+ if (!(driver->smd_data[MODEM_DATA].ch) &&
+ chk_apps_only()) {
equip_id = *(int *)(buf + 8);
num_items = *(int *)(buf + 12);
driver->apps_rsp_buf[0] = 0x73;
@@ -541,15 +574,13 @@
driver->apps_rsp_buf[3] = 0x0;
*(int *)(driver->apps_rsp_buf + 4) = 0x0;
*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* status */
- if (driver->ch_cntl)
- diag_send_log_mask_update(driver->ch_cntl,
- ALL_EQUIP_ID);
- if (driver->chlpass_cntl)
- diag_send_log_mask_update(driver->chlpass_cntl,
- ALL_EQUIP_ID);
- if (driver->ch_wcnss_cntl)
- diag_send_log_mask_update(driver->ch_wcnss_cntl,
- ALL_EQUIP_ID);
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+ if (driver->smd_cntl[i].ch)
+ diag_send_log_mask_update(
+ driver->smd_cntl[i].ch,
+ ALL_EQUIP_ID);
+
+ }
encode_rsp_and_send(11);
return 0;
}
@@ -559,7 +590,8 @@
ssid_first = *(uint16_t *)(buf + 2);
ssid_last = *(uint16_t *)(buf + 4);
#if defined(CONFIG_DIAG_OVER_USB)
- if (!(driver->ch) && chk_apps_only()) {
+ if (!(driver->smd_data[MODEM_DATA].ch) &&
+ chk_apps_only()) {
driver->apps_rsp_buf[0] = 0x7d;
driver->apps_rsp_buf[1] = 0x3;
*(uint16_t *)(driver->apps_rsp_buf+2) = ssid_first;
@@ -599,15 +631,14 @@
for (i = 0; i < 8 + ssid_range; i++)
*(driver->apps_rsp_buf + i) = *(buf+i);
*(driver->apps_rsp_buf + 6) = 0x1;
- if (driver->ch_cntl)
- diag_send_msg_mask_update(driver->ch_cntl,
- ssid_first, ssid_last, MODEM_PROC);
- if (driver->chlpass_cntl)
- diag_send_msg_mask_update(driver->chlpass_cntl,
- ssid_first, ssid_last, LPASS_PROC);
- if (driver->ch_wcnss_cntl)
- diag_send_msg_mask_update(driver->ch_wcnss_cntl,
- ssid_first, ssid_last, WCNSS_PROC);
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+ if (driver->smd_cntl[i].ch)
+ diag_send_msg_mask_update(
+ driver->smd_cntl[i].ch,
+ ssid_first, ssid_last,
+ driver->smd_cntl[i].peripheral);
+
+ }
encode_rsp_and_send(8 + ssid_range - 1);
return 0;
}
@@ -625,15 +656,14 @@
driver->apps_rsp_buf[3] = 0; /* rsvd */
*(int *)(driver->apps_rsp_buf + 4) = rt_mask;
/* send msg mask update to peripheral */
- if (driver->ch_cntl)
- diag_send_msg_mask_update(driver->ch_cntl,
- ALL_SSID, ALL_SSID, MODEM_PROC);
- if (driver->chlpass_cntl)
- diag_send_msg_mask_update(driver->chlpass_cntl,
- ALL_SSID, ALL_SSID, LPASS_PROC);
- if (driver->ch_wcnss_cntl)
- diag_send_msg_mask_update(driver->ch_wcnss_cntl,
- ALL_SSID, ALL_SSID, WCNSS_PROC);
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+ if (driver->smd_cntl[i].ch)
+ diag_send_msg_mask_update(
+ driver->smd_cntl[i].ch,
+ ALL_SSID, ALL_SSID,
+ driver->smd_cntl[i].peripheral);
+
+ }
encode_rsp_and_send(7);
return 0;
}
@@ -652,16 +682,12 @@
EVENT_LAST_ID + 1;
memcpy(driver->apps_rsp_buf+6, driver->event_masks,
EVENT_LAST_ID/8+1);
- if (driver->ch_cntl)
- diag_send_event_mask_update(driver->ch_cntl,
- diag_event_num_bytes);
- if (driver->chlpass_cntl)
- diag_send_event_mask_update(
- driver->chlpass_cntl,
- diag_event_num_bytes);
- if (driver->ch_wcnss_cntl)
- diag_send_event_mask_update(
- driver->ch_wcnss_cntl, diag_event_num_bytes);
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+ if (driver->smd_cntl[i].ch)
+ diag_send_event_mask_update(
+ driver->smd_cntl[i].ch,
+ diag_event_num_bytes);
+ }
encode_rsp_and_send(6 + EVENT_LAST_ID/8);
return 0;
}
@@ -675,20 +701,26 @@
driver->apps_rsp_buf[0] = 0x60;
driver->apps_rsp_buf[1] = 0x0;
driver->apps_rsp_buf[2] = 0x0;
- if (driver->ch_cntl)
- diag_send_event_mask_update(driver->ch_cntl,
- diag_event_num_bytes);
- if (driver->chlpass_cntl)
- diag_send_event_mask_update(
- driver->chlpass_cntl,
- diag_event_num_bytes);
- if (driver->ch_wcnss_cntl)
- diag_send_event_mask_update(
- driver->ch_wcnss_cntl, diag_event_num_bytes);
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+ if (driver->smd_cntl[i].ch)
+ diag_send_event_mask_update(
+ driver->smd_cntl[i].ch,
+ diag_event_num_bytes);
+ }
encode_rsp_and_send(2);
return 0;
}
#endif
+ } else if (*buf == 0x78) {
+ if (!(driver->smd_cntl[MODEM_DATA].ch) ||
+ (driver->log_on_demand_support)) {
+ driver->apps_rsp_buf[0] = 0x78;
+ /* Copy log code received */
+ *(uint16_t *)(driver->apps_rsp_buf+1) =
+ *(uint16_t *)buf;
+ driver->apps_rsp_buf[3] = 0x1;/* Unknown */
+ encode_rsp_and_send(3);
+ }
}
return packet_type;
@@ -745,6 +777,21 @@
goto err;
kmemleak_not_leak(driver->msg_masks);
}
+ if (driver->buf_feature_mask_update == NULL) {
+ driver->buf_feature_mask_update = kzalloc(sizeof(
+ struct diag_ctrl_feature_mask) +
+ FEATURE_MASK_LEN_BYTES, GFP_KERNEL);
+ if (driver->buf_feature_mask_update == NULL)
+ goto err;
+ kmemleak_not_leak(driver->buf_feature_mask_update);
+ }
+ if (driver->feature_mask == NULL) {
+ driver->feature_mask = kzalloc(sizeof(
+ struct diag_ctrl_feature_mask), GFP_KERNEL);
+ if (driver->feature_mask == NULL)
+ goto err;
+ kmemleak_not_leak(driver->feature_mask);
+ }
diag_create_msg_mask_table();
diag_event_num_bytes = 0;
if (driver->log_masks == NULL) {
@@ -760,14 +807,6 @@
goto err;
kmemleak_not_leak(driver->event_masks);
}
-#ifdef CONFIG_DIAG_OVER_USB
- INIT_WORK(&(driver->diag_modem_mask_update_work),
- diag_modem_mask_update_fn);
- INIT_WORK(&(driver->diag_lpass_mask_update_work),
- diag_lpass_mask_update_fn);
- INIT_WORK(&(driver->diag_wcnss_mask_update_work),
- diag_wcnss_mask_update_fn);
-#endif
return;
err:
pr_err("diag: Could not initialize diag mask buffers");
@@ -777,6 +816,8 @@
kfree(driver->msg_masks);
kfree(driver->log_masks);
kfree(driver->event_masks);
+ kfree(driver->feature_mask);
+ kfree(driver->buf_feature_mask_update);
}
void diag_masks_exit(void)
@@ -787,4 +828,6 @@
kfree(driver->msg_masks);
kfree(driver->log_masks);
kfree(driver->event_masks);
+ kfree(driver->feature_mask);
+ kfree(driver->buf_feature_mask_update);
}
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
index bcf5bc2..53f72e8 100644
--- a/drivers/char/diag/diag_masks.h
+++ b/drivers/char/diag/diag_masks.h
@@ -20,6 +20,8 @@
void diag_send_msg_mask_update(smd_channel_t *, int ssid_first,
int ssid_last, int proc);
void diag_send_log_mask_update(smd_channel_t *, int);
+void diag_mask_update_fn(struct work_struct *work);
+void diag_send_feature_mask_update(smd_channel_t *ch, int proc);
int diag_process_apps_masks(unsigned char *buf, int len);
void diag_masks_init(void);
void diag_masks_exit(void);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index cb895d8..0d5ad6a 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -23,12 +23,14 @@
#include <mach/msm_smd.h>
#include <asm/atomic.h>
#include <asm/mach-types.h>
+
/* Size of the USB buffers used for read and write*/
#define USB_MAX_OUT_BUF 4096
#define APPS_BUF_SIZE 2000
#define IN_BUF_SIZE 16384
#define MAX_IN_BUF_SIZE 32768
#define MAX_SYNC_OBJ_NAME_SIZE 32
+#define UINT32_MAX UINT_MAX
/* Size of the buffer used for deframing a packet
reveived from the PC tool*/
#define HDLC_MAX 4096
@@ -39,17 +41,14 @@
#define POOL_TYPE_HSIC 8
#define POOL_TYPE_HSIC_WRITE 16
#define POOL_TYPE_ALL 7
-#define MODEM_DATA 1
-#define LPASS_DATA 2
+#define MODEM_DATA 0
+#define LPASS_DATA 1
+#define WCNSS_DATA 2
#define APPS_DATA 3
#define SDIO_DATA 4
-#define WCNSS_DATA 5
-#define HSIC_DATA 6
-#define SMUX_DATA 7
-#define MODEM_PROC 0
+#define HSIC_DATA 5
+#define SMUX_DATA 6
#define APPS_PROC 1
-#define LPASS_PROC 2
-#define WCNSS_PROC 3
#define MSG_MASK_SIZE 10000
#define LOG_MASK_SIZE 8000
#define EVENT_MASK_SIZE 1000
@@ -75,6 +74,14 @@
#define DIAG_STATUS_OPEN (0x00010000) /* DCI channel open status mask */
#define DIAG_STATUS_CLOSED (0x00020000) /* DCI channel closed status mask */
+#define NUM_SMD_DATA_CHANNELS 3
+#define NUM_SMD_CONTROL_CHANNELS 3
+#define NUM_SMD_DCI_CHANNELS 1
+
+#define SMD_DATA_TYPE 0
+#define SMD_CNTL_TYPE 1
+#define SMD_DCI_TYPE 2
+
/* Maximum number of pkt reg supported at initialization*/
extern unsigned int diag_max_reg;
extern unsigned int diag_threshold_reg;
@@ -86,6 +93,12 @@
(diag_debug_buf_idx++) : (diag_debug_buf_idx = 0); \
} while (0)
+/* List of remote processor supported */
+enum remote_procs {
+ MDM = 1,
+ QSC = 2,
+};
+
struct diag_master_table {
uint16_t cmd_code;
uint16_t subsys_id;
@@ -136,6 +149,35 @@
};
#endif
+struct diag_smd_info {
+ int peripheral; /* The peripheral this smd channel communicates with */
+ int type; /* The type of smd channel (data, control, dci) */
+ uint16_t peripheral_mask;
+
+ smd_channel_t *ch;
+ smd_channel_t *ch_save;
+
+ int in_busy_1;
+ int in_busy_2;
+
+ unsigned char *buf_in_1;
+ unsigned char *buf_in_2;
+
+ struct diag_request *write_ptr_1;
+ struct diag_request *write_ptr_2;
+
+ struct work_struct diag_read_smd_work;
+ struct work_struct diag_notify_update_smd_work;
+ int notify_context;
+
+ /*
+ * Function ptr for function to call to process the data that
+ * was just read from the smd channel
+ */
+ int (*process_smd_read_data)(struct diag_smd_info *smd_info,
+ void *buf, int num_bytes);
+};
+
struct diagchar_dev {
/* State for the char driver */
@@ -149,6 +191,7 @@
int ref_count;
struct mutex diagchar_mutex;
wait_queue_head_t wait_q;
+ wait_queue_head_t smd_wait_q;
struct diag_client_map *client_map;
int *data_ready;
int num_clients;
@@ -187,17 +230,11 @@
struct diag_ctrl_event_mask *event_mask;
struct diag_ctrl_log_mask *log_mask;
struct diag_ctrl_msg_mask *msg_mask;
+ struct diag_ctrl_feature_mask *feature_mask;
/* State for diag forwarding */
- unsigned char *buf_in_1;
- unsigned char *buf_in_2;
- unsigned char *buf_in_cntl;
- unsigned char *buf_in_lpass_1;
- unsigned char *buf_in_lpass_2;
- unsigned char *buf_in_lpass_cntl;
- unsigned char *buf_in_wcnss_1;
- unsigned char *buf_in_wcnss_2;
- unsigned char *buf_in_wcnss_cntl;
- unsigned char *buf_in_dci;
+ struct diag_smd_info smd_data[NUM_SMD_DATA_CHANNELS];
+ struct diag_smd_info smd_cntl[NUM_SMD_CONTROL_CHANNELS];
+ struct diag_smd_info smd_dci[NUM_SMD_DCI_CHANNELS];
unsigned char *usb_buf_out;
unsigned char *apps_rsp_buf;
unsigned char *user_space_data;
@@ -205,20 +242,7 @@
unsigned char *buf_msg_mask_update;
unsigned char *buf_log_mask_update;
unsigned char *buf_event_mask_update;
- smd_channel_t *ch;
- smd_channel_t *ch_cntl;
- smd_channel_t *ch_dci;
- smd_channel_t *chlpass;
- smd_channel_t *chlpass_cntl;
- smd_channel_t *ch_wcnss;
- smd_channel_t *ch_wcnss_cntl;
- int in_busy_1;
- int in_busy_2;
- int in_busy_lpass_1;
- int in_busy_lpass_2;
- int in_busy_wcnss_1;
- int in_busy_wcnss_2;
- int in_busy_dci;
+ unsigned char *buf_feature_mask_update;
int read_len_legacy;
unsigned char *hdlc_buf;
unsigned hdlc_count;
@@ -231,41 +255,22 @@
#endif
struct workqueue_struct *diag_wq;
struct work_struct diag_drain_work;
- struct work_struct diag_read_smd_work;
- struct work_struct diag_read_smd_cntl_work;
- struct work_struct diag_read_smd_lpass_work;
- struct work_struct diag_read_smd_lpass_cntl_work;
- struct work_struct diag_read_smd_wcnss_work;
- struct work_struct diag_read_smd_wcnss_cntl_work;
struct workqueue_struct *diag_cntl_wq;
- struct work_struct diag_modem_mask_update_work;
- struct work_struct diag_lpass_mask_update_work;
- struct work_struct diag_wcnss_mask_update_work;
- struct work_struct diag_read_smd_dci_work;
- struct work_struct diag_update_smd_dci_work;
- struct work_struct diag_clean_modem_reg_work;
- struct work_struct diag_clean_lpass_reg_work;
- struct work_struct diag_clean_wcnss_reg_work;
uint8_t *msg_masks;
uint8_t *log_masks;
int log_masks_length;
uint8_t *event_masks;
+ uint8_t log_on_demand_support;
struct diag_master_table *table;
uint8_t *pkt_buf;
int pkt_length;
- struct diag_request *write_ptr_1;
- struct diag_request *write_ptr_2;
struct diag_request *usb_read_ptr;
struct diag_request *write_ptr_svc;
- struct diag_request *write_ptr_lpass_1;
- struct diag_request *write_ptr_lpass_2;
- struct diag_request *write_ptr_wcnss_1;
- struct diag_request *write_ptr_wcnss_2;
- struct diag_write_device *write_ptr_dci;
int logging_mode;
int mask_check;
int logging_process_id;
struct task_struct *socket_process;
+ struct task_struct *callback_process;
#ifdef CONFIG_DIAG_SDIO_PIPE
unsigned char *buf_in_sdio;
unsigned char *usb_buf_mdm_out;
@@ -280,7 +285,9 @@
struct diag_request *usb_read_mdm_ptr;
struct diag_request *write_ptr_mdm;
#endif
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+ /* common for all bridges */
+ struct work_struct diag_disconnect_work;
/* SGLTE variables */
int lcid;
unsigned char *buf_in_smux;
@@ -297,18 +304,6 @@
int in_busy_hsic_read_on_device;
int in_busy_hsic_write;
struct work_struct diag_read_hsic_work;
- struct mutex bridge_mutex;
- /* USB MDM channel variables */
- int usb_mdm_connected;
- int read_len_mdm;
- int write_len_mdm;
- unsigned char *usb_buf_mdm_out;
- struct usb_diag_ch *mdm_ch;
- struct workqueue_struct *diag_bridge_wq;
- struct work_struct diag_read_mdm_work;
- struct work_struct diag_disconnect_work;
- struct work_struct diag_usb_read_complete_work;
- struct diag_request *usb_read_mdm_ptr;
int count_hsic_pool;
int count_hsic_write_pool;
unsigned int poolsize_hsic;
@@ -323,5 +318,10 @@
#endif
};
+extern struct diag_bridge_dev *diag_bridge;
extern struct diagchar_dev *driver;
+
+extern int wrap_enabled;
+extern uint16_t wrap_count;
+
#endif
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 6c9e5ab..d2454f4 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2013, The Linux Foundation. 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
@@ -32,13 +32,14 @@
#ifdef CONFIG_DIAG_SDIO_PIPE
#include "diagfwd_sdio.h"
#endif
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
#include "diagfwd_hsic.h"
#include "diagfwd_smux.h"
#endif
#include <linux/timer.h>
#include "diag_debugfs.h"
#include "diag_masks.h"
+#include "diagfwd_bridge.h"
MODULE_DESCRIPTION("Diag Char Driver");
MODULE_LICENSE("GPL v2");
@@ -78,12 +79,25 @@
/* delayed_rsp_id 0 represents no delay in the response. Any other number
means that the diag packet has a delayed response. */
static uint16_t delayed_rsp_id = 1;
-#define DIAGPKT_MAX_DELAYED_RSP 0xFFFF
-/* This macro gets the next delayed respose id. Once it reaches
- DIAGPKT_MAX_DELAYED_RSP, it stays at DIAGPKT_MAX_DELAYED_RSP */
-#define DIAGPKT_NEXT_DELAYED_RSP_ID(x) \
-((x < DIAGPKT_MAX_DELAYED_RSP) ? x++ : DIAGPKT_MAX_DELAYED_RSP)
+#define DIAGPKT_MAX_DELAYED_RSP 0xFFFF
+
+/* returns the next delayed rsp id - rollsover the id if wrapping is
+ enabled. */
+uint16_t diagpkt_next_delayed_rsp_id(uint16_t rspid)
+{
+ if (rspid < DIAGPKT_MAX_DELAYED_RSP)
+ rspid++;
+ else {
+ if (wrap_enabled) {
+ rspid = 1;
+ wrap_count++;
+ } else
+ rspid = DIAGPKT_MAX_DELAYED_RSP;
+ }
+ delayed_rsp_id = rspid;
+ return delayed_rsp_id;
+}
#define COPY_USER_SPACE_OR_EXIT(buf, data, length) \
do { \
@@ -124,7 +138,7 @@
mutex_unlock(&driver->diagchar_mutex);
}
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
void diag_clear_hsic_tbl(void)
{
int i;
@@ -145,21 +159,6 @@
void diag_clear_hsic_tbl(void) { }
#endif
-void diag_read_smd_work_fn(struct work_struct *work)
-{
- __diag_smd_send_req();
-}
-
-void diag_read_smd_lpass_work_fn(struct work_struct *work)
-{
- __diag_smd_lpass_send_req();
-}
-
-void diag_read_smd_wcnss_work_fn(struct work_struct *work)
-{
- __diag_smd_wcnss_send_req();
-}
-
void diag_add_client(int i, struct file *file)
{
struct diagchar_priv *diagpriv_data;
@@ -248,6 +247,10 @@
pr_alert("diag: Invalid file pointer");
return -ENOMEM;
}
+
+ if (!driver)
+ return -ENOMEM;
+
/* clean up any DCI registrations, if this is a DCI client
* This will specially help in case of ungraceful exit of any DCI client
* This call will remove any pending registrations of such client
@@ -265,13 +268,17 @@
(driver->socket_process->tgid == current->tgid)) {
driver->socket_process = NULL;
}
+ if (driver->callback_process &&
+ (driver->callback_process->tgid == current->tgid)) {
+ driver->callback_process = NULL;
+ }
#ifdef CONFIG_DIAG_OVER_USB
/* If the SD logging process exits, change logging to USB mode */
if (driver->logging_process_id == current->tgid) {
driver->logging_mode = USB_MODE;
diagfwd_connect();
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
diag_clear_hsic_tbl();
diagfwd_cancel_hsic();
diagfwd_connect_bridge(0);
@@ -283,26 +290,23 @@
if (driver->table[i].process_id == current->tgid)
driver->table[i].process_id = 0;
- if (driver) {
- mutex_lock(&driver->diagchar_mutex);
- driver->ref_count--;
- /* On Client exit, try to destroy all 3 pools */
- diagmem_exit(driver, POOL_TYPE_COPY);
- diagmem_exit(driver, POOL_TYPE_HDLC);
- diagmem_exit(driver, POOL_TYPE_WRITE_STRUCT);
- for (i = 0; i < driver->num_clients; i++) {
- if (NULL != diagpriv_data && diagpriv_data->pid ==
- driver->client_map[i].pid) {
- driver->client_map[i].pid = 0;
- kfree(diagpriv_data);
- diagpriv_data = NULL;
- break;
- }
+ mutex_lock(&driver->diagchar_mutex);
+ driver->ref_count--;
+ /* On Client exit, try to destroy all 3 pools */
+ diagmem_exit(driver, POOL_TYPE_COPY);
+ diagmem_exit(driver, POOL_TYPE_HDLC);
+ diagmem_exit(driver, POOL_TYPE_WRITE_STRUCT);
+ for (i = 0; i < driver->num_clients; i++) {
+ if (NULL != diagpriv_data && diagpriv_data->pid ==
+ driver->client_map[i].pid) {
+ driver->client_map[i].pid = 0;
+ kfree(diagpriv_data);
+ diagpriv_data = NULL;
+ break;
}
- mutex_unlock(&driver->diagchar_mutex);
- return 0;
}
- return -ENOMEM;
+ mutex_unlock(&driver->diagchar_mutex);
+ return 0;
}
int diag_find_polling_reg(int i)
@@ -328,7 +332,7 @@
return 0;
}
-void diag_clear_reg(int proc_num)
+void diag_clear_reg(int peripheral)
{
int i;
@@ -336,9 +340,8 @@
/* reset polling flag */
driver->polling_reg_flag = 0;
for (i = 0; i < diag_max_reg; i++) {
- if (driver->table[i].client_id == proc_num) {
+ if (driver->table[i].client_id == peripheral)
driver->table[i].process_id = 0;
- }
}
/* re-scan the registration table */
for (i = 0; i < diag_max_reg; i++) {
@@ -351,7 +354,7 @@
}
void diag_add_reg(int j, struct bindpkt_params *params,
- int *success, int *count_entries)
+ int *success, unsigned int *count_entries)
{
*success = 1;
driver->table[j].cmd_code = params->cmd_code;
@@ -365,7 +368,7 @@
driver->polling_reg_flag = 1;
if (params->proc_id == APPS_PROC) {
driver->table[j].process_id = current->tgid;
- driver->table[j].client_id = APPS_PROC;
+ driver->table[j].client_id = APPS_DATA;
} else {
driver->table[j].process_id = NON_APPS_PROC;
driver->table[j].client_id = params->client_id;
@@ -373,82 +376,193 @@
(*count_entries)++;
}
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+uint16_t diag_get_remote_device_mask(void)
+{
+ uint16_t remote_dev = 0;
+
+ /* Check for MDM processor */
+ if (driver->hsic_inited)
+ remote_dev |= 1 << 0;
+
+ /* Check for QSC processor */
+ if (driver->diag_smux_enabled)
+ remote_dev |= 1 << 1;
+
+ return remote_dev;
+}
+#else
+inline uint16_t diag_get_remote_device_mask(void) { return 0; }
+#endif
+
+static int diag_get_remote(int remote_info)
+{
+ int val = (remote_info < 0) ? -remote_info : remote_info;
+ int remote_val;
+
+ switch (val) {
+ case MDM:
+ case QSC:
+ remote_val = -remote_info;
+ break;
+ default:
+ remote_val = 0;
+ break;
+ }
+
+ return remote_val;
+}
+
long diagchar_ioctl(struct file *filp,
unsigned int iocmd, unsigned long ioarg)
{
- int i, j, count_entries = 0, temp;
- int success = -1;
+ int i, j, temp, success = -1, status;
+ unsigned int count_entries = 0, interim_count = 0;
void *temp_buf;
uint16_t support_list = 0;
- struct diag_dci_client_tbl *params =
- kzalloc(sizeof(struct diag_dci_client_tbl), GFP_KERNEL);
+ struct diag_dci_client_tbl *dci_params;
struct diag_dci_health_stats stats;
- int status;
if (iocmd == DIAG_IOCTL_COMMAND_REG) {
- struct bindpkt_params_per_process *pkt_params =
- (struct bindpkt_params_per_process *) ioarg;
+ struct bindpkt_params_per_process pkt_params;
+ struct bindpkt_params *params;
+ struct bindpkt_params *head_params;
+ if (copy_from_user(&pkt_params, (void *)ioarg,
+ sizeof(struct bindpkt_params_per_process))) {
+ return -EFAULT;
+ }
+ if ((UINT32_MAX/sizeof(struct bindpkt_params)) <
+ pkt_params.count) {
+ pr_warning("diag: integer overflow while multiply\n");
+ return -EFAULT;
+ }
+ params = kzalloc(pkt_params.count*sizeof(
+ struct bindpkt_params), GFP_KERNEL);
+ if (!params) {
+ pr_err("diag: unable to alloc memory\n");
+ return -ENOMEM;
+ } else
+ head_params = params;
+
+ if (copy_from_user(params, pkt_params.params,
+ pkt_params.count*sizeof(struct bindpkt_params))) {
+ kfree(head_params);
+ return -EFAULT;
+ }
mutex_lock(&driver->diagchar_mutex);
for (i = 0; i < diag_max_reg; i++) {
if (driver->table[i].process_id == 0) {
- diag_add_reg(i, pkt_params->params,
- &success, &count_entries);
- if (pkt_params->count > count_entries) {
- pkt_params->params++;
+ diag_add_reg(i, params, &success,
+ &count_entries);
+ if (pkt_params.count > count_entries) {
+ params++;
} else {
mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
return success;
}
}
}
if (i < diag_threshold_reg) {
/* Increase table size by amount required */
- diag_max_reg += pkt_params->count -
+ if (pkt_params.count >= count_entries) {
+ interim_count = pkt_params.count -
count_entries;
+ } else {
+ pr_warning("diag: error in params count\n");
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return -EFAULT;
+ }
+ if (UINT32_MAX - diag_max_reg >=
+ interim_count) {
+ diag_max_reg += interim_count;
+ } else {
+ pr_warning("diag: Integer overflow\n");
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return -EFAULT;
+ }
/* Make sure size doesnt go beyond threshold */
if (diag_max_reg > diag_threshold_reg) {
diag_max_reg = diag_threshold_reg;
pr_info("diag: best case memory allocation\n");
}
+ if (UINT32_MAX/sizeof(struct diag_master_table) <
+ diag_max_reg) {
+ pr_warning("diag: integer overflow\n");
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return -EFAULT;
+ }
temp_buf = krealloc(driver->table,
diag_max_reg*sizeof(struct
diag_master_table), GFP_KERNEL);
if (!temp_buf) {
- diag_max_reg -= pkt_params->count -
- count_entries;
- pr_alert("diag: Insufficient memory for reg.");
+ pr_alert("diag: Insufficient memory for reg.\n");
mutex_unlock(&driver->diagchar_mutex);
+
+ if (pkt_params.count >= count_entries) {
+ interim_count = pkt_params.count -
+ count_entries;
+ } else {
+ pr_warning("diag: params count error\n");
+ mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
+ return -EFAULT;
+ }
+ if (diag_max_reg >= interim_count) {
+ diag_max_reg -= interim_count;
+ } else {
+ pr_warning("diag: Integer underflow\n");
+ mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
+ return -EFAULT;
+ }
+ kfree(head_params);
return 0;
} else {
driver->table = temp_buf;
}
for (j = i; j < diag_max_reg; j++) {
- diag_add_reg(j, pkt_params->params,
- &success, &count_entries);
- if (pkt_params->count > count_entries) {
- pkt_params->params++;
+ diag_add_reg(j, params, &success,
+ &count_entries);
+ if (pkt_params.count > count_entries) {
+ params++;
} else {
mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
return success;
}
}
+ kfree(head_params);
mutex_unlock(&driver->diagchar_mutex);
} else {
mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
pr_err("Max size reached, Pkt Registration failed for"
" Process %d", current->tgid);
}
success = 0;
} else if (iocmd == DIAG_IOCTL_GET_DELAYED_RSP_ID) {
- struct diagpkt_delay_params *delay_params =
- (struct diagpkt_delay_params *) ioarg;
-
- if ((delay_params->rsp_ptr) &&
- (delay_params->size == sizeof(delayed_rsp_id)) &&
- (delay_params->num_bytes_ptr)) {
- *((uint16_t *)delay_params->rsp_ptr) =
- DIAGPKT_NEXT_DELAYED_RSP_ID(delayed_rsp_id);
- *(delay_params->num_bytes_ptr) = sizeof(delayed_rsp_id);
+ struct diagpkt_delay_params delay_params;
+ uint16_t interim_rsp_id;
+ int interim_size;
+ if (copy_from_user(&delay_params, (void *)ioarg,
+ sizeof(struct diagpkt_delay_params)))
+ return -EFAULT;
+ if ((delay_params.rsp_ptr) &&
+ (delay_params.size == sizeof(delayed_rsp_id)) &&
+ (delay_params.num_bytes_ptr)) {
+ interim_rsp_id = diagpkt_next_delayed_rsp_id(
+ delayed_rsp_id);
+ if (copy_to_user((void *)delay_params.rsp_ptr,
+ &interim_rsp_id, sizeof(uint16_t)))
+ return -EFAULT;
+ interim_size = sizeof(delayed_rsp_id);
+ if (copy_to_user((void *)delay_params.num_bytes_ptr,
+ &interim_size, sizeof(int)))
+ return -EFAULT;
success = 0;
}
} else if (iocmd == DIAG_IOCTL_DCI_REG) {
@@ -456,22 +570,30 @@
return DIAG_DCI_NO_REG;
if (driver->num_dci_client >= MAX_DCI_CLIENTS)
return DIAG_DCI_NO_REG;
- if (copy_from_user(params, (void *)ioarg,
+ dci_params = kzalloc(sizeof(struct diag_dci_client_tbl),
+ GFP_KERNEL);
+ if (dci_params == NULL) {
+ pr_err("diag: unable to alloc memory\n");
+ return -ENOMEM;
+ }
+ if (copy_from_user(dci_params, (void *)ioarg,
sizeof(struct diag_dci_client_tbl)))
return -EFAULT;
mutex_lock(&driver->dci_mutex);
if (!(driver->num_dci_client))
- driver->in_busy_dci = 0;
+ for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
+ driver->smd_dci[i].in_busy_1 = 0;
driver->num_dci_client++;
- pr_debug("diag: id = %d\n", driver->dci_client_id);
+ pr_debug("diag: In %s, id = %d\n",
+ __func__, driver->dci_client_id);
driver->dci_client_id++;
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
if (driver->dci_client_tbl[i].client == NULL) {
driver->dci_client_tbl[i].client = current;
driver->dci_client_tbl[i].list =
- params->list;
+ dci_params->list;
driver->dci_client_tbl[i].signal_type =
- params->signal_type;
+ dci_params->signal_type;
create_dci_log_mask_tbl(driver->
dci_client_tbl[i].dci_log_mask);
create_dci_event_mask_tbl(driver->
@@ -489,6 +611,7 @@
}
}
mutex_unlock(&driver->dci_mutex);
+ kfree(dci_params);
return driver->dci_client_id;
} else if (iocmd == DIAG_IOCTL_DCI_DEINIT) {
success = -1;
@@ -511,27 +634,34 @@
mutex_unlock(&driver->dci_mutex);
return success;
} else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) {
- if (driver->ch_dci)
- support_list = support_list | DIAG_CON_MPSS;
- *(uint16_t *)ioarg = support_list;
+ for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
+ if (driver->smd_dci[i].ch)
+ support_list |=
+ driver->smd_dci[i].peripheral_mask;
+ }
+ if (copy_to_user((void *)ioarg, &support_list,
+ sizeof(uint16_t)))
+ return -EFAULT;
return DIAG_DCI_NO_ERROR;
} else if (iocmd == DIAG_IOCTL_DCI_HEALTH_STATS) {
if (copy_from_user(&stats, (void *)ioarg,
sizeof(struct diag_dci_health_stats)))
return -EFAULT;
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- params = &(driver->dci_client_tbl[i]);
- if (params->client &&
- params->client->tgid == current->tgid) {
- stats.dropped_logs = params->dropped_logs;
- stats.dropped_events = params->dropped_events;
- stats.received_logs = params->received_logs;
- stats.received_events = params->received_events;
+ dci_params = &(driver->dci_client_tbl[i]);
+ if (dci_params->client &&
+ dci_params->client->tgid == current->tgid) {
+ stats.dropped_logs = dci_params->dropped_logs;
+ stats.dropped_events =
+ dci_params->dropped_events;
+ stats.received_logs = dci_params->received_logs;
+ stats.received_events =
+ dci_params->received_events;
if (stats.reset_status) {
- params->dropped_logs = 0;
- params->dropped_events = 0;
- params->received_logs = 0;
- params->received_events = 0;
+ dci_params->dropped_logs = 0;
+ dci_params->dropped_events = 0;
+ dci_params->received_logs = 0;
+ dci_params->received_events = 0;
}
break;
}
@@ -544,7 +674,7 @@
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
break;
- if (i == -1)
+ if (i == driver->num_clients)
return -EINVAL;
driver->data_ready[i] |= DEINIT_TYPE;
wake_up_interruptible(&driver->wait_q);
@@ -553,6 +683,11 @@
mutex_lock(&driver->diagchar_mutex);
temp = driver->logging_mode;
driver->logging_mode = (int)ioarg;
+ if (temp == driver->logging_mode) {
+ mutex_unlock(&driver->diagchar_mutex);
+ pr_alert("diag: forbidden logging change requested\n");
+ return 0;
+ }
if (driver->logging_mode == MEMORY_DEVICE_MODE) {
diag_clear_hsic_tbl();
driver->mask_check = 1;
@@ -571,14 +706,14 @@
}
}
}
- if (driver->logging_mode == UART_MODE) {
- diag_clear_hsic_tbl();
- driver->mask_check = 0;
- driver->logging_mode = MEMORY_DEVICE_MODE;
- }
- if (driver->logging_mode == SOCKET_MODE) {
- diag_clear_hsic_tbl();
+ if (driver->logging_mode == SOCKET_MODE)
driver->socket_process = current;
+ if (driver->logging_mode == CALLBACK_MODE)
+ driver->callback_process = current;
+ if (driver->logging_mode == UART_MODE ||
+ driver->logging_mode == SOCKET_MODE ||
+ driver->logging_mode == CALLBACK_MODE) {
+ diag_clear_hsic_tbl();
driver->mask_check = 0;
driver->logging_mode = MEMORY_DEVICE_MODE;
}
@@ -586,37 +721,28 @@
mutex_unlock(&driver->diagchar_mutex);
if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
== NO_LOGGING_MODE) {
- driver->in_busy_1 = 1;
- driver->in_busy_2 = 1;
- driver->in_busy_lpass_1 = 1;
- driver->in_busy_lpass_2 = 1;
- driver->in_busy_wcnss_1 = 1;
- driver->in_busy_wcnss_2 = 1;
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ driver->smd_data[i].in_busy_1 = 0;
+ driver->smd_data[i].in_busy_2 = 0;
+ }
#ifdef CONFIG_DIAG_SDIO_PIPE
driver->in_busy_sdio = 1;
#endif
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
diagfwd_disconnect_bridge(0);
diag_clear_hsic_tbl();
#endif
} else if (temp == NO_LOGGING_MODE && driver->logging_mode
== MEMORY_DEVICE_MODE) {
- driver->in_busy_1 = 0;
- driver->in_busy_2 = 0;
- driver->in_busy_lpass_1 = 0;
- driver->in_busy_lpass_2 = 0;
- driver->in_busy_wcnss_1 = 0;
- driver->in_busy_wcnss_2 = 0;
- /* Poll SMD channels to check for data*/
- if (driver->ch)
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_work));
- if (driver->chlpass)
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_lpass_work));
- if (driver->ch_wcnss)
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_wcnss_work));
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ driver->smd_data[i].in_busy_1 = 0;
+ driver->smd_data[i].in_busy_2 = 0;
+ /* Poll SMD channels to check for data*/
+ if (driver->smd_data[i].ch)
+ queue_work(driver->diag_wq,
+ &(driver->smd_data[i].
+ diag_read_smd_work));
+ }
#ifdef CONFIG_DIAG_SDIO_PIPE
driver->in_busy_sdio = 0;
/* Poll SDIO channel to check for data */
@@ -624,7 +750,7 @@
queue_work(driver->diag_sdio_wq,
&(driver->diag_read_sdio_work));
#endif
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
diagfwd_connect_bridge(0);
#endif
}
@@ -632,35 +758,27 @@
else if (temp == USB_MODE && driver->logging_mode
== NO_LOGGING_MODE) {
diagfwd_disconnect();
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
diagfwd_disconnect_bridge(0);
#endif
} else if (temp == NO_LOGGING_MODE && driver->logging_mode
== USB_MODE) {
diagfwd_connect();
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
diagfwd_connect_bridge(0);
#endif
} else if (temp == USB_MODE && driver->logging_mode
== MEMORY_DEVICE_MODE) {
diagfwd_disconnect();
- driver->in_busy_1 = 0;
- driver->in_busy_2 = 0;
- driver->in_busy_lpass_1 = 0;
- driver->in_busy_lpass_2 = 0;
- driver->in_busy_wcnss_1 = 0;
- driver->in_busy_wcnss_2 = 0;
-
- /* Poll SMD channels to check for data*/
- if (driver->ch)
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_work));
- if (driver->chlpass)
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_lpass_work));
- if (driver->ch_wcnss)
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_wcnss_work));
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ driver->smd_data[i].in_busy_1 = 0;
+ driver->smd_data[i].in_busy_2 = 0;
+ /* Poll SMD channels to check for data*/
+ if (driver->smd_data[i].ch)
+ queue_work(driver->diag_wq,
+ &(driver->smd_data[i].
+ diag_read_smd_work));
+ }
#ifdef CONFIG_DIAG_SDIO_PIPE
driver->in_busy_sdio = 0;
/* Poll SDIO channel to check for data */
@@ -668,14 +786,14 @@
queue_work(driver->diag_sdio_wq,
&(driver->diag_read_sdio_work));
#endif
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
diagfwd_cancel_hsic();
diagfwd_connect_bridge(0);
#endif
} else if (temp == MEMORY_DEVICE_MODE &&
driver->logging_mode == USB_MODE) {
diagfwd_connect();
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
diag_clear_hsic_tbl();
diagfwd_cancel_hsic();
diagfwd_connect_bridge(0);
@@ -683,6 +801,12 @@
}
#endif /* DIAG over USB */
success = 1;
+ } else if (iocmd == DIAG_IOCTL_REMOTE_DEV) {
+ uint16_t remote_dev = diag_get_remote_device_mask();
+ if (copy_to_user((void *)ioarg, &remote_dev, sizeof(uint16_t)))
+ success = -EFAULT;
+ else
+ success = 1;
}
return success;
@@ -694,6 +818,8 @@
struct diag_dci_client_tbl *entry;
int index = -1, i = 0, ret = 0;
int num_data = 0, data_type;
+ int remote_token;
+
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
index = i;
@@ -707,16 +833,16 @@
driver->data_ready[index]);
mutex_lock(&driver->diagchar_mutex);
- if ((driver->data_ready[index] & USER_SPACE_LOG_TYPE) && (driver->
+ if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) && (driver->
logging_mode == MEMORY_DEVICE_MODE)) {
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
unsigned long spin_lock_flags;
struct diag_write_device hsic_buf_tbl[NUM_HSIC_BUF_TBL_ENTRIES];
#endif
-
+ remote_token = 0;
pr_debug("diag: process woken up\n");
/*Copy the type of data being passed*/
- data_type = driver->data_ready[index] & USER_SPACE_LOG_TYPE;
+ data_type = driver->data_ready[index] & USER_SPACE_DATA_TYPE;
COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
/* place holder for number of data field */
ret += 4;
@@ -761,78 +887,40 @@
}
/* copy modem data */
- if (driver->in_busy_1 == 1) {
- num_data++;
- /*Copy the length of data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret,
- (driver->write_ptr_1->length), 4);
- /*Copy the actual data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret,
- *(driver->buf_in_1),
- driver->write_ptr_1->length);
- driver->in_busy_1 = 0;
- }
- if (driver->in_busy_2 == 1) {
- num_data++;
- /*Copy the length of data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret,
- (driver->write_ptr_2->length), 4);
- /*Copy the actual data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret,
- *(driver->buf_in_2),
- driver->write_ptr_2->length);
- driver->in_busy_2 = 0;
- }
- /* copy lpass data */
- if (driver->in_busy_lpass_1 == 1) {
- num_data++;
- /*Copy the length of data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret,
- (driver->write_ptr_lpass_1->length), 4);
- /*Copy the actual data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
- buf_in_lpass_1),
- driver->write_ptr_lpass_1->length);
- driver->in_busy_lpass_1 = 0;
- }
- if (driver->in_busy_lpass_2 == 1) {
- num_data++;
- /*Copy the length of data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret,
- (driver->write_ptr_lpass_2->length), 4);
- /*Copy the actual data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
- buf_in_lpass_2), driver->
- write_ptr_lpass_2->length);
- driver->in_busy_lpass_2 = 0;
- }
- /* copy wncss data */
- if (driver->in_busy_wcnss_1 == 1) {
- num_data++;
- /*Copy the length of data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret,
- (driver->write_ptr_wcnss_1->length), 4);
- /*Copy the actual data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
- buf_in_wcnss_1),
- driver->write_ptr_wcnss_1->length);
- driver->in_busy_wcnss_1 = 0;
- }
- if (driver->in_busy_wcnss_2 == 1) {
- num_data++;
- /*Copy the length of data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret,
- (driver->write_ptr_wcnss_2->length), 4);
- /*Copy the actual data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
- buf_in_wcnss_2),
- driver->write_ptr_wcnss_2->length);
- driver->in_busy_wcnss_2 = 0;
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ struct diag_smd_info *data = &driver->smd_data[i];
+ if (data->in_busy_1 == 1) {
+ num_data++;
+ /*Copy the length of data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ (data->write_ptr_1->length), 4);
+ /*Copy the actual data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ *(data->buf_in_1),
+ data->write_ptr_1->length);
+ data->in_busy_1 = 0;
+ }
+ if (data->in_busy_2 == 1) {
+ num_data++;
+ /*Copy the length of data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ (data->write_ptr_2->length), 4);
+ /*Copy the actual data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ *(data->buf_in_2),
+ data->write_ptr_2->length);
+ data->in_busy_2 = 0;
+ }
}
#ifdef CONFIG_DIAG_SDIO_PIPE
/* copy 9K data over SDIO */
if (driver->in_busy_sdio == 1) {
+ remote_token = diag_get_remote(MDM);
num_data++;
+
+ /*Copy the negative token of data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ remote_token, 4);
/*Copy the length of data being passed*/
COPY_USER_SPACE_OR_EXIT(buf+ret,
(driver->write_ptr_mdm->length), 4);
@@ -843,7 +931,7 @@
driver->in_busy_sdio = 0;
}
#endif
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
spin_lock_irqsave(&driver->hsic_spinlock, spin_lock_flags);
for (i = 0; i < driver->poolsize_hsic_write; i++) {
hsic_buf_tbl[i].buf = driver->hsic_buf_tbl[i].buf;
@@ -856,12 +944,22 @@
spin_unlock_irqrestore(&driver->hsic_spinlock,
spin_lock_flags);
+ remote_token = diag_get_remote(MDM);
for (i = 0; i < driver->poolsize_hsic_write; i++) {
if (hsic_buf_tbl[i].length > 0) {
pr_debug("diag: HSIC copy to user, i: %d, buf: %x, len: %d\n",
i, (unsigned int)hsic_buf_tbl[i].buf,
hsic_buf_tbl[i].length);
num_data++;
+
+ /* Copy the negative token */
+ if (copy_to_user(buf+ret,
+ &remote_token, 4)) {
+ num_data--;
+ goto drop_hsic;
+ }
+ ret += 4;
+
/* Copy the length of data being passed */
if (copy_to_user(buf+ret,
(void *)&(hsic_buf_tbl[i].length),
@@ -890,20 +988,33 @@
diagfwd_write_complete_hsic(NULL);
}
}
+ if (driver->in_busy_smux == 1) {
+ remote_token = diag_get_remote(QSC);
+ num_data++;
+
+ /* Copy the negative token of data being passed */
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ remote_token, 4);
+ /* Copy the length of data being passed */
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ (driver->write_ptr_mdm->length), 4);
+ /* Copy the actual data being passed */
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ *(driver->buf_in_smux),
+ driver->write_ptr_mdm->length);
+ pr_debug("diag: SMUX data copied\n");
+ driver->in_busy_smux = 0;
+ }
#endif
/* copy number of data fields */
COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
ret -= 4;
- driver->data_ready[index] ^= USER_SPACE_LOG_TYPE;
- if (driver->ch)
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_work));
- if (driver->chlpass)
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_lpass_work));
- if (driver->ch_wcnss)
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_wcnss_work));
+ driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ if (driver->smd_data[i].ch)
+ queue_work(driver->diag_wq,
+ &(driver->smd_data[i].diag_read_smd_work));
+ }
#ifdef CONFIG_DIAG_SDIO_PIPE
if (driver->sdio_ch)
queue_work(driver->diag_sdio_wq,
@@ -911,10 +1022,10 @@
#endif
APPEND_DEBUG('n');
goto exit;
- } else if (driver->data_ready[index] & USER_SPACE_LOG_TYPE) {
+ } else if (driver->data_ready[index] & USER_SPACE_DATA_TYPE) {
/* In case, the thread wakes up and the logging mode is
not memory device any more, the condition needs to be cleared */
- driver->data_ready[index] ^= USER_SPACE_LOG_TYPE;
+ driver->data_ready[index] ^= USER_SPACE_DATA_TYPE;
}
if (driver->data_ready[index] & DEINIT_TYPE) {
@@ -971,10 +1082,9 @@
COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
/* check the current client and copy its data */
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- if (driver->dci_client_tbl[i].client != NULL) {
- entry = &(driver->dci_client_tbl[i]);
- if (entry && (current->tgid ==
- entry->client->tgid)) {
+ entry = &(driver->dci_client_tbl[i]);
+ if (entry && entry->client) {
+ if (current->tgid == entry->client->tgid) {
COPY_USER_SPACE_OR_EXIT(buf+4,
entry->data_len, 4);
COPY_USER_SPACE_OR_EXIT(buf+8,
@@ -985,10 +1095,12 @@
}
}
driver->data_ready[index] ^= DCI_DATA_TYPE;
- driver->in_busy_dci = 0;
- if (driver->ch_dci)
- queue_work(driver->diag_dci_wq,
- &(driver->diag_read_smd_dci_work));
+ for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
+ driver->smd_dci[i].in_busy_1 = 0;
+ if (driver->smd_dci[i].ch)
+ queue_work(driver->diag_dci_wq,
+ &(driver->smd_dci[i].diag_read_smd_work));
+ }
goto exit;
}
exit:
@@ -999,14 +1111,15 @@
static int diagchar_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- int err, ret = 0, pkt_type;
+ int err, ret = 0, pkt_type, token_offset = 0;
+ int remote_proc = 0;
#ifdef DIAG_DEBUG
int length = 0, i;
#endif
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
void *buf_copy = NULL;
- int payload_size;
+ unsigned int payload_size;
#ifdef CONFIG_DIAG_OVER_USB
if (((driver->logging_mode == USB_MODE) && (!driver->usb_connected)) ||
(driver->logging_mode == NO_LOGGING_MODE)) {
@@ -1017,8 +1130,17 @@
/* Get the packet type F3/log/event/Pkt response */
err = copy_from_user((&pkt_type), buf, 4);
/* First 4 bytes indicate the type of payload - ignore these */
+ if (count < 4) {
+ pr_err("diag: Client sending short data\n");
+ return -EBADMSG;
+ }
payload_size = count - 4;
-
+ if (payload_size > USER_SPACE_DATA) {
+ pr_err("diag: Dropping packet, packet payload size crosses 8KB limit. Current payload size %d\n",
+ payload_size);
+ driver->dropped_count++;
+ return -EBADMSG;
+ }
if (pkt_type == DCI_DATA_TYPE) {
err = copy_from_user(driver->user_space_data, buf + 4,
payload_size);
@@ -1030,12 +1152,22 @@
payload_size);
return err;
}
- if (pkt_type == USER_SPACE_LOG_TYPE) {
+ if (pkt_type == USER_SPACE_DATA_TYPE) {
err = copy_from_user(driver->user_space_data, buf + 4,
payload_size);
+ /* Check for proc_type */
+ remote_proc = diag_get_remote(*(int *)driver->user_space_data);
+
+ if (remote_proc) {
+ token_offset = 4;
+ payload_size -= 4;
+ buf += 4;
+ }
+
/* Check masks for On-Device logging */
if (driver->mask_check) {
- if (!mask_request_validate(driver->user_space_data)) {
+ if (!mask_request_validate(driver->user_space_data +
+ token_offset)) {
pr_alert("diag: mask request Invalid\n");
return -EFAULT;
}
@@ -1044,31 +1176,35 @@
#ifdef DIAG_DEBUG
pr_debug("diag: user space data %d\n", payload_size);
for (i = 0; i < payload_size; i++)
- pr_debug("\t %x", *((driver->user_space_data)+i));
+ pr_debug("\t %x", *((driver->user_space_data
+ + token_offset)+i));
#endif
#ifdef CONFIG_DIAG_SDIO_PIPE
/* send masks to 9k too */
- if (driver->sdio_ch) {
+ if (driver->sdio_ch && (remote_proc == MDM)) {
wait_event_interruptible(driver->wait_q,
(sdio_write_avail(driver->sdio_ch) >=
payload_size));
if (driver->sdio_ch && (payload_size > 0)) {
sdio_write(driver->sdio_ch, (void *)
- (driver->user_space_data), payload_size);
+ (driver->user_space_data + token_offset),
+ payload_size);
}
}
#endif
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
/* send masks to 9k too */
- if (driver->hsic_ch && (payload_size > 0)) {
+ if (driver->hsic_ch && (payload_size > 0) &&
+ (remote_proc == MDM)) {
/* wait sending mask updates if HSIC ch not ready */
if (driver->in_busy_hsic_write)
wait_event_interruptible(driver->wait_q,
(driver->in_busy_hsic_write != 1));
driver->in_busy_hsic_write = 1;
driver->in_busy_hsic_read_on_device = 0;
- err = diag_bridge_write(driver->user_space_data,
- payload_size);
+ err = diag_bridge_write(
+ driver->user_space_data + token_offset,
+ payload_size);
if (err) {
pr_err("diag: err sending mask to MDM: %d\n",
err);
@@ -1082,10 +1218,25 @@
driver->in_busy_hsic_write = 0;
}
}
+ if (driver->diag_smux_enabled && (remote_proc == QSC)
+ && driver->lcid) {
+ if (payload_size > 0) {
+ err = msm_smux_write(driver->lcid, NULL,
+ driver->user_space_data + token_offset,
+ payload_size);
+ if (err) {
+ pr_err("diag:send mask to MDM err %d",
+ err);
+ return err;
+ }
+ }
+ }
#endif
/* send masks to 8k now */
- diag_process_hdlc((void *)(driver->user_space_data),
- payload_size);
+ if (!remote_proc)
+ diag_process_hdlc((void *)
+ (driver->user_space_data + token_offset),
+ payload_size);
return 0;
}
@@ -1136,13 +1287,21 @@
ret = -ENOMEM;
goto fail_free_hdlc;
}
+ if (HDLC_OUT_BUF_SIZE < (2*payload_size) + 3) {
+ pr_err("diag: Dropping packet, HDLC encoded packet payload size crosses buffer limit. Current payload size %d\n",
+ ((2*payload_size) + 3));
+ driver->dropped_count++;
+ ret = -EBADMSG;
+ goto fail_free_hdlc;
+ }
if (HDLC_OUT_BUF_SIZE - driver->used <= (2*payload_size) + 3) {
err = diag_device_write(buf_hdlc, APPS_DATA, NULL);
if (err) {
/*Free the buffer right away if write failed */
diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
- diagmem_free(driver, (unsigned char *)driver->
- write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
+ if (driver->logging_mode == USB_MODE)
+ diagmem_free(driver, (unsigned char *)driver->
+ write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
ret = -EIO;
goto fail_free_hdlc;
}
@@ -1169,8 +1328,9 @@
if (err) {
/*Free the buffer right away if write failed */
diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
- diagmem_free(driver, (unsigned char *)driver->
- write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
+ if (driver->logging_mode == USB_MODE)
+ diagmem_free(driver, (unsigned char *)driver->
+ write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
ret = -EIO;
goto fail_free_hdlc;
}
@@ -1194,8 +1354,9 @@
if (err) {
/*Free the buffer right away if write failed */
diagmem_free(driver, buf_hdlc, POOL_TYPE_HDLC);
- diagmem_free(driver, (unsigned char *)driver->
- write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
+ if (driver->logging_mode == USB_MODE)
+ diagmem_free(driver, (unsigned char *)driver->
+ write_ptr_svc, POOL_TYPE_WRITE_STRUCT);
ret = -EIO;
goto fail_free_hdlc;
}
@@ -1203,8 +1364,8 @@
driver->used = 0;
}
- mutex_unlock(&driver->diagchar_mutex);
diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+ mutex_unlock(&driver->diagchar_mutex);
if (!timer_in_progress) {
timer_in_progress = 1;
ret = mod_timer(&drain_timer, jiffies + msecs_to_jiffies(500));
@@ -1345,6 +1506,13 @@
return 0;
}
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+static void diag_disconnect_work_fn(struct work_struct *w)
+{
+ diagfwd_disconnect_bridge(1);
+}
+#endif
+
#ifdef CONFIG_DIAG_SDIO_PIPE
void diag_sdio_fn(int type)
{
@@ -1359,16 +1527,14 @@
inline void diag_sdio_fn(int type) {}
#endif
-#ifdef CONFIG_DIAG_BRIDGE_CODE
-void diag_bridge_fn(int type)
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+void diagfwd_bridge_fn(int type)
{
- if (type == INIT)
- diagfwd_bridge_init();
- else if (type == EXIT)
+ if (type == EXIT)
diagfwd_bridge_exit();
}
#else
-inline void diag_bridge_fn(int type) {}
+inline void diagfwd_bridge_fn(int type) { }
#endif
static int __init diagchar_init(void)
@@ -1378,6 +1544,12 @@
pr_debug("diagfwd initializing ..\n");
driver = kzalloc(sizeof(struct diagchar_dev) + 5, GFP_KERNEL);
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+ diag_bridge = kzalloc(MAX_BRIDGES * sizeof(struct diag_bridge_dev),
+ GFP_KERNEL);
+ if (!diag_bridge)
+ pr_warning("diag: could not allocate memory for bridge\n");
+#endif
if (driver) {
driver->used = 0;
@@ -1394,38 +1566,25 @@
driver->num_clients = max_clients;
driver->logging_mode = USB_MODE;
driver->socket_process = NULL;
+ driver->callback_process = NULL;
driver->mask_check = 0;
mutex_init(&driver->diagchar_mutex);
init_waitqueue_head(&driver->wait_q);
+ init_waitqueue_head(&driver->smd_wait_q);
INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn);
- INIT_WORK(&(driver->diag_read_smd_work), diag_read_smd_work_fn);
- INIT_WORK(&(driver->diag_read_smd_cntl_work),
- diag_read_smd_cntl_work_fn);
- INIT_WORK(&(driver->diag_read_smd_lpass_work),
- diag_read_smd_lpass_work_fn);
- INIT_WORK(&(driver->diag_read_smd_lpass_cntl_work),
- diag_read_smd_lpass_cntl_work_fn);
- INIT_WORK(&(driver->diag_read_smd_wcnss_work),
- diag_read_smd_wcnss_work_fn);
- INIT_WORK(&(driver->diag_read_smd_wcnss_cntl_work),
- diag_read_smd_wcnss_cntl_work_fn);
- INIT_WORK(&(driver->diag_read_smd_dci_work),
- diag_read_smd_dci_work_fn);
- INIT_WORK(&(driver->diag_update_smd_dci_work),
- diag_update_smd_dci_work_fn);
- INIT_WORK(&(driver->diag_clean_modem_reg_work),
- diag_clean_modem_reg_fn);
- INIT_WORK(&(driver->diag_clean_lpass_reg_work),
- diag_clean_lpass_reg_fn);
- INIT_WORK(&(driver->diag_clean_wcnss_reg_work),
- diag_clean_wcnss_reg_fn);
diag_debugfs_init();
- diagfwd_init();
- diagfwd_cntl_init();
diag_masks_init();
+ diagfwd_init();
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+ diagfwd_bridge_init(HSIC);
+ diagfwd_bridge_init(SMUX);
+ INIT_WORK(&(driver->diag_disconnect_work),
+ diag_disconnect_work_fn);
+#endif
+ diagfwd_cntl_init();
driver->dci_state = diag_dci_init();
diag_sdio_fn(INIT);
- diag_bridge_fn(INIT);
+
pr_debug("diagchar initializing ..\n");
driver->num = 1;
driver->name = ((void *)driver) + sizeof(struct diagchar_dev);
@@ -1460,7 +1619,7 @@
diagfwd_cntl_exit();
diag_masks_exit();
diag_sdio_fn(EXIT);
- diag_bridge_fn(EXIT);
+ diagfwd_bridge_fn(EXIT);
return -1;
}
@@ -1474,7 +1633,7 @@
diagfwd_cntl_exit();
diag_masks_exit();
diag_sdio_fn(EXIT);
- diag_bridge_fn(EXIT);
+ diagfwd_bridge_fn(EXIT);
diag_debugfs_cleanup();
diagchar_cleanup();
printk(KERN_INFO "done diagchar exit\n");
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 602ca67..0bd26cf 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -40,6 +40,7 @@
#endif
#include "diag_dci.h"
#include "diag_masks.h"
+#include "diagfwd_bridge.h"
#define MODE_CMD 41
#define RESET_ID 2
@@ -48,26 +49,28 @@
unsigned char diag_debug_buf[1024];
static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
struct diag_master_table entry;
-smd_channel_t *ch_temp = NULL, *chlpass_temp = NULL, *ch_wcnss_temp = NULL;
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
+int wrap_enabled;
+uint16_t wrap_count;
void encode_rsp_and_send(int buf_length)
{
+ struct diag_smd_info *data = &(driver->smd_data[MODEM_DATA]);
send.state = DIAG_STATE_START;
send.pkt = driver->apps_rsp_buf;
send.last = (void *)(driver->apps_rsp_buf + buf_length);
send.terminate = 1;
- if (!driver->in_busy_1) {
- enc.dest = driver->buf_in_1;
- enc.dest_last = (void *)(driver->buf_in_1 + APPS_BUF_SIZE - 1);
+ if (!data->in_busy_1) {
+ enc.dest = data->buf_in_1;
+ enc.dest_last = (void *)(data->buf_in_1 + APPS_BUF_SIZE - 1);
diag_hdlc_encode(&send, &enc);
- driver->write_ptr_1->buf = driver->buf_in_1;
- driver->write_ptr_1->length = (int)(enc.dest -
- (void *)(driver->buf_in_1));
- driver->in_busy_1 = 1;
- diag_device_write(driver->buf_in_1, MODEM_DATA,
- driver->write_ptr_1);
+ data->write_ptr_1->buf = data->buf_in_1;
+ data->write_ptr_1->length = (int)(enc.dest -
+ (void *)(data->buf_in_1));
+ data->in_busy_1 = 1;
+ diag_device_write(data->buf_in_1, data->peripheral,
+ data->write_ptr_1);
memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
}
}
@@ -177,7 +180,8 @@
* has registered to respond for polling
*/
return 1;
- else if (!(driver->ch) && !(chk_apps_master()))
+ else if (!(driver->smd_data[MODEM_DATA].ch) &&
+ !(chk_apps_master()))
/*
* If the apps processor is not the master and the modem
* is not up
@@ -212,69 +216,144 @@
* have their data read/logged. Detect and remedy this
* situation.
*/
- if ((driver->data_ready[i] & USER_SPACE_LOG_TYPE) == 0) {
- driver->data_ready[i] |= USER_SPACE_LOG_TYPE;
+ if ((driver->data_ready[i] & USER_SPACE_DATA_TYPE) == 0) {
+ driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
pr_debug("diag: Force wakeup of logging process\n");
wake_up_interruptible(&driver->wait_q);
}
}
}
-void __diag_smd_send_req(void)
+/* Process the data read from the smd data channel */
+int diag_process_smd_read_data(struct diag_smd_info *smd_info, void *buf,
+ int total_recd)
{
- void *buf = NULL;
- int *in_busy_ptr = NULL;
struct diag_request *write_ptr_modem = NULL;
+ int *in_busy_ptr = 0;
- if (!driver->in_busy_1) {
- buf = driver->buf_in_1;
- write_ptr_modem = driver->write_ptr_1;
- in_busy_ptr = &(driver->in_busy_1);
- } else if (!driver->in_busy_2) {
- buf = driver->buf_in_2;
- write_ptr_modem = driver->write_ptr_2;
- in_busy_ptr = &(driver->in_busy_2);
+ if (smd_info->buf_in_1 == buf) {
+ write_ptr_modem = smd_info->write_ptr_1;
+ in_busy_ptr = &smd_info->in_busy_1;
+ } else if (smd_info->buf_in_2 == buf) {
+ write_ptr_modem = smd_info->write_ptr_2;
+ in_busy_ptr = &smd_info->in_busy_2;
+ } else {
+ pr_err("diag: In %s, no match for in_busy_1\n", __func__);
}
- if (driver->ch && buf) {
- int r = smd_read_avail(driver->ch);
+ if (write_ptr_modem) {
+ write_ptr_modem->length = total_recd;
+ *in_busy_ptr = 1;
+ diag_device_write(buf, smd_info->peripheral, write_ptr_modem);
+ }
- if (r > IN_BUF_SIZE) {
- if (r < MAX_IN_BUF_SIZE) {
- pr_err("diag: SMD sending in "
- "packets upto %d bytes", r);
- buf = krealloc(buf, r, GFP_KERNEL);
- } else {
- pr_err("diag: SMD sending in "
- "packets more than %d bytes", MAX_IN_BUF_SIZE);
+ return 0;
+}
+
+void diag_smd_send_req(struct diag_smd_info *smd_info)
+{
+ void *buf = NULL, *temp_buf = NULL;
+ int total_recd = 0, r = 0, pkt_len;
+ int loop_count = 0;
+ int notify = 0;
+
+ if (!smd_info) {
+ pr_err("diag: In %s, no smd info. Not able to read.\n",
+ __func__);
+ return;
+ }
+
+ if (!smd_info->in_busy_1)
+ buf = smd_info->buf_in_1;
+ else if ((smd_info->type == SMD_DATA_TYPE) && !smd_info->in_busy_2)
+ buf = smd_info->buf_in_2;
+
+ if (smd_info->ch && buf) {
+ temp_buf = buf;
+ pkt_len = smd_cur_packet_size(smd_info->ch);
+
+ while (pkt_len && (pkt_len != total_recd)) {
+ loop_count++;
+ r = smd_read_avail(smd_info->ch);
+ pr_debug("diag: In %s, received pkt %d %d\n",
+ __func__, r, total_recd);
+ if (!r) {
+ /* Nothing to read from SMD */
+ wait_event(driver->smd_wait_q,
+ ((smd_info->ch == 0) ||
+ smd_read_avail(smd_info->ch)));
+ /* If the smd channel is open */
+ if (smd_info->ch) {
+ pr_debug("diag: In %s, return from wait_event\n",
+ __func__);
+ continue;
+ } else {
+ pr_debug("diag: In %s, return from wait_event ch closed\n",
+ __func__);
+ return;
+ }
+ }
+ total_recd += r;
+ if (total_recd > IN_BUF_SIZE) {
+ if (total_recd < MAX_IN_BUF_SIZE) {
+ pr_err("diag: In %s, SMD sending in packets up to %d bytes\n",
+ __func__, total_recd);
+ buf = krealloc(buf, total_recd,
+ GFP_KERNEL);
+ } else {
+ pr_err("diag: In %s, SMD sending in packets more than %d bytes\n",
+ __func__, MAX_IN_BUF_SIZE);
+ return;
+ }
+ }
+ if (pkt_len < r) {
+ pr_err("diag: In %s, SMD sending incorrect pkt\n",
+ __func__);
return;
}
+ if (pkt_len > r) {
+ pr_err("diag: In %s, SMD sending partial pkt %d %d %d %d %d %d\n",
+ __func__, pkt_len, r, total_recd, loop_count,
+ smd_info->peripheral, smd_info->type);
+ }
+
+ /* keep reading for complete packet */
+ smd_read(smd_info->ch, temp_buf, r);
+ temp_buf += r;
}
- if (r > 0) {
- if (!buf)
- pr_info("Out of diagmem for Modem\n");
- else {
- APPEND_DEBUG('i');
- smd_read(driver->ch, buf, r);
- APPEND_DEBUG('j');
- write_ptr_modem->length = r;
- *in_busy_ptr = 1;
- diag_device_write(buf, MODEM_DATA,
- write_ptr_modem);
+
+ if (total_recd > 0) {
+ if (!buf) {
+ pr_err("diag: Out of diagmem for Modem\n");
+ } else if (smd_info->process_smd_read_data) {
+ notify = smd_info->process_smd_read_data(
+ smd_info, buf, total_recd);
+ /* Poll SMD channels to check for data */
+ if (notify)
+ diag_smd_notify(smd_info,
+ SMD_EVENT_DATA);
}
}
- } else if (driver->ch && !buf &&
+ } else if (smd_info->ch && !buf &&
(driver->logging_mode == MEMORY_DEVICE_MODE)) {
- chk_logging_wakeup();
+ chk_logging_wakeup();
}
}
-int diag_device_write(void *buf, int proc_num, struct diag_request *write_ptr)
+void diag_read_smd_work_fn(struct work_struct *work)
+{
+ struct diag_smd_info *smd_info = container_of(work,
+ struct diag_smd_info,
+ diag_read_smd_work);
+ diag_smd_send_req(smd_info);
+}
+
+int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
{
int i, err = 0;
if (driver->logging_mode == MEMORY_DEVICE_MODE) {
- if (proc_num == APPS_DATA) {
+ if (data_type == APPS_DATA) {
for (i = 0; i < driver->poolsize_write_struct; i++)
if (driver->buf_tbl[i].length == 0) {
driver->buf_tbl[i].buf = buf;
@@ -290,8 +369,8 @@
}
}
-#ifdef CONFIG_DIAG_BRIDGE_CODE
- else if (proc_num == HSIC_DATA) {
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+ else if (data_type == HSIC_DATA) {
unsigned long flags;
int foundIndex = -1;
@@ -300,7 +379,7 @@
if (driver->hsic_buf_tbl[i].length == 0) {
driver->hsic_buf_tbl[i].buf = buf;
driver->hsic_buf_tbl[i].length =
- driver->write_len_mdm;
+ diag_bridge[HSIC].write_len;
driver->num_hsic_buf_tbl_entries++;
foundIndex = i;
break;
@@ -312,7 +391,7 @@
else
pr_debug("diag: ENQUEUE HSIC buf ptr and length is %x , %d\n",
(unsigned int)buf,
- driver->write_len_mdm);
+ diag_bridge[HSIC].write_len);
}
#endif
for (i = 0; i < driver->num_clients; i++)
@@ -320,39 +399,30 @@
driver->logging_process_id)
break;
if (i < driver->num_clients) {
- driver->data_ready[i] |= USER_SPACE_LOG_TYPE;
+ driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
pr_debug("diag: wake up logging process\n");
wake_up_interruptible(&driver->wait_q);
} else
return -EINVAL;
} else if (driver->logging_mode == NO_LOGGING_MODE) {
- if (proc_num == MODEM_DATA) {
- driver->in_busy_1 = 0;
- driver->in_busy_2 = 0;
- queue_work(driver->diag_wq, &(driver->
+ if ((data_type >= 0) && (data_type < NUM_SMD_DATA_CHANNELS)) {
+ driver->smd_data[data_type].in_busy_1 = 0;
+ driver->smd_data[data_type].in_busy_2 = 0;
+ queue_work(driver->diag_wq,
+ &(driver->smd_data[data_type].
diag_read_smd_work));
- } else if (proc_num == LPASS_DATA) {
- driver->in_busy_lpass_1 = 0;
- driver->in_busy_lpass_2 = 0;
- queue_work(driver->diag_wq, &(driver->
- diag_read_smd_lpass_work));
- } else if (proc_num == WCNSS_DATA) {
- driver->in_busy_wcnss_1 = 0;
- driver->in_busy_wcnss_2 = 0;
- queue_work(driver->diag_wq, &(driver->
- diag_read_smd_wcnss_work));
}
#ifdef CONFIG_DIAG_SDIO_PIPE
- else if (proc_num == SDIO_DATA) {
+ else if (data_type == SDIO_DATA) {
driver->in_busy_sdio = 0;
queue_work(driver->diag_sdio_wq,
&(driver->diag_read_sdio_work));
}
#endif
-#ifdef CONFIG_DIAG_BRIDGE_CODE
- else if (proc_num == HSIC_DATA) {
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+ else if (data_type == HSIC_DATA) {
if (driver->hsic_ch)
- queue_work(driver->diag_bridge_wq,
+ queue_work(diag_bridge[HSIC].wq,
&(driver->diag_read_hsic_work));
}
#endif
@@ -360,7 +430,7 @@
}
#ifdef CONFIG_DIAG_OVER_USB
else if (driver->logging_mode == USB_MODE) {
- if (proc_num == APPS_DATA) {
+ if (data_type == APPS_DATA) {
driver->write_ptr_svc = (struct diag_request *)
(diagmem_alloc(driver, sizeof(struct diag_request),
POOL_TYPE_WRITE_STRUCT));
@@ -371,7 +441,8 @@
driver->write_ptr_svc);
} else
err = -1;
- } else if (proc_num == MODEM_DATA) {
+ } else if ((data_type >= 0) &&
+ (data_type < NUM_SMD_DATA_CHANNELS)) {
write_ptr->buf = buf;
#ifdef DIAG_DEBUG
printk(KERN_INFO "writing data to USB,"
@@ -381,15 +452,9 @@
buf, write_ptr->length, 1);
#endif /* DIAG DEBUG */
err = usb_diag_write(driver->legacy_ch, write_ptr);
- } else if (proc_num == LPASS_DATA) {
- write_ptr->buf = buf;
- err = usb_diag_write(driver->legacy_ch, write_ptr);
- } else if (proc_num == WCNSS_DATA) {
- write_ptr->buf = buf;
- err = usb_diag_write(driver->legacy_ch, write_ptr);
}
#ifdef CONFIG_DIAG_SDIO_PIPE
- else if (proc_num == SDIO_DATA) {
+ else if (data_type == SDIO_DATA) {
if (machine_is_msm8x60_fusion() ||
machine_is_msm8x60_fusn_ffa()) {
write_ptr->buf = buf;
@@ -399,8 +464,8 @@
"while USB write\n");
}
#endif
-#ifdef CONFIG_DIAG_BRIDGE_CODE
- else if (proc_num == HSIC_DATA) {
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
+ else if (data_type == HSIC_DATA) {
if (driver->hsic_device_enabled) {
struct diag_request *write_ptr_mdm;
write_ptr_mdm = (struct diag_request *)
@@ -410,9 +475,10 @@
if (write_ptr_mdm) {
write_ptr_mdm->buf = buf;
write_ptr_mdm->length =
- driver->write_len_mdm;
- err = usb_diag_write(driver->mdm_ch,
- write_ptr_mdm);
+ diag_bridge[HSIC].write_len;
+ write_ptr_mdm->context = (void *)HSIC;
+ err = usb_diag_write(
+ diag_bridge[HSIC].ch, write_ptr_mdm);
/* Return to the pool immediately */
if (err) {
diagmem_free(driver,
@@ -426,14 +492,16 @@
err = -1;
}
} else {
- pr_err("diag: Incorrect hsic data "
+ pr_err("diag: Incorrect HSIC data "
"while USB write\n");
err = -1;
}
- } else if (proc_num == SMUX_DATA) {
+ } else if (data_type == SMUX_DATA) {
write_ptr->buf = buf;
+ write_ptr->context = (void *)SMUX;
pr_debug("diag: writing SMUX data\n");
- err = usb_diag_write(driver->mdm_ch, write_ptr);
+ err = usb_diag_write(diag_bridge[SMUX].ch,
+ write_ptr);
}
#endif
APPEND_DEBUG('d');
@@ -442,101 +510,6 @@
return err;
}
-void __diag_smd_wcnss_send_req(void)
-{
- void *buf = NULL;
- int *in_busy_wcnss_ptr = NULL;
- struct diag_request *write_ptr_wcnss = NULL;
-
- if (!driver->in_busy_wcnss_1) {
- buf = driver->buf_in_wcnss_1;
- write_ptr_wcnss = driver->write_ptr_wcnss_1;
- in_busy_wcnss_ptr = &(driver->in_busy_wcnss_1);
- } else if (!driver->in_busy_wcnss_2) {
- buf = driver->buf_in_wcnss_2;
- write_ptr_wcnss = driver->write_ptr_wcnss_2;
- in_busy_wcnss_ptr = &(driver->in_busy_wcnss_2);
- }
-
- if (driver->ch_wcnss && buf) {
- int r = smd_read_avail(driver->ch_wcnss);
- if (r > IN_BUF_SIZE) {
- if (r < MAX_IN_BUF_SIZE) {
- pr_err("diag: wcnss packets > %d bytes", r);
- buf = krealloc(buf, r, GFP_KERNEL);
- } else {
- pr_err("diag: wcnss pkt > %d", MAX_IN_BUF_SIZE);
- return;
- }
- }
- if (r > 0) {
- if (!buf) {
- pr_err("Out of diagmem for wcnss\n");
- } else {
- APPEND_DEBUG('i');
- smd_read(driver->ch_wcnss, buf, r);
- APPEND_DEBUG('j');
- write_ptr_wcnss->length = r;
- *in_busy_wcnss_ptr = 1;
- diag_device_write(buf, WCNSS_DATA,
- write_ptr_wcnss);
- }
- }
- } else if (driver->ch_wcnss && !buf &&
- (driver->logging_mode == MEMORY_DEVICE_MODE)) {
- chk_logging_wakeup();
- }
-}
-
-void __diag_smd_lpass_send_req(void)
-{
- void *buf = NULL;
- int *in_busy_lpass_ptr = NULL;
- struct diag_request *write_ptr_lpass = NULL;
-
- if (!driver->in_busy_lpass_1) {
- buf = driver->buf_in_lpass_1;
- write_ptr_lpass = driver->write_ptr_lpass_1;
- in_busy_lpass_ptr = &(driver->in_busy_lpass_1);
- } else if (!driver->in_busy_lpass_2) {
- buf = driver->buf_in_lpass_2;
- write_ptr_lpass = driver->write_ptr_lpass_2;
- in_busy_lpass_ptr = &(driver->in_busy_lpass_2);
- }
-
- if (driver->chlpass && buf) {
- int r = smd_read_avail(driver->chlpass);
-
- if (r > IN_BUF_SIZE) {
- if (r < MAX_IN_BUF_SIZE) {
- pr_err("diag: SMD sending in "
- "packets upto %d bytes", r);
- buf = krealloc(buf, r, GFP_KERNEL);
- } else {
- pr_err("diag: SMD sending in "
- "packets more than %d bytes", MAX_IN_BUF_SIZE);
- return;
- }
- }
- if (r > 0) {
- if (!buf)
- printk(KERN_INFO "Out of diagmem for LPASS\n");
- else {
- APPEND_DEBUG('i');
- smd_read(driver->chlpass, buf, r);
- APPEND_DEBUG('j');
- write_ptr_lpass->length = r;
- *in_busy_lpass_ptr = 1;
- diag_device_write(buf, LPASS_DATA,
- write_ptr_lpass);
- }
- }
- } else if (driver->chlpass && !buf &&
- (driver->logging_mode == MEMORY_DEVICE_MODE)) {
- chk_logging_wakeup();
- }
-}
-
static void diag_update_pkt_buffer(unsigned char *buf)
{
unsigned char *ptr = driver->pkt_buf;
@@ -576,6 +549,15 @@
mutex_unlock(&driver->diagchar_mutex);
}
+static int diag_check_mode_reset(unsigned char *buf)
+{
+ int is_mode_reset = 0;
+ if (chk_apps_master() && (int)(*(char *)buf) == MODE_CMD)
+ if ((int)(*(char *)(buf+1)) == RESET_ID)
+ is_mode_reset = 1;
+ return is_mode_reset;
+}
+
void diag_send_data(struct diag_master_table entry, unsigned char *buf,
int len, int type)
{
@@ -585,21 +567,23 @@
diag_update_sleeping_process(entry.process_id, PKT_TYPE);
} else {
if (len > 0) {
- if (entry.client_id == MODEM_PROC && driver->ch) {
- if (chk_apps_master() &&
- (int)(*(char *)buf) == MODE_CMD)
- if ((int)(*(char *)(buf+1)) ==
- RESET_ID)
+ if ((entry.client_id >= 0) &&
+ (entry.client_id < NUM_SMD_DATA_CHANNELS)) {
+ int index = entry.client_id;
+ if (driver->smd_data[index].ch) {
+ if ((index == MODEM_DATA) &&
+ diag_check_mode_reset(buf)) {
return;
- smd_write(driver->ch, buf, len);
- } else if (entry.client_id == LPASS_PROC &&
- driver->chlpass) {
- smd_write(driver->chlpass, buf, len);
- } else if (entry.client_id == WCNSS_PROC &&
- driver->ch_wcnss) {
- smd_write(driver->ch_wcnss, buf, len);
+ }
+ smd_write(driver->smd_data[index].ch,
+ buf, len);
+ } else {
+ pr_err("diag: In %s, smd channel %d not open\n",
+ __func__, index);
+ }
} else {
- pr_alert("diag: incorrect channel");
+ pr_alert("diag: In %s, incorrect channel: %d",
+ __func__, entry.client_id);
}
}
}
@@ -680,7 +664,8 @@
return 0;
}
/* Check for Apps Only & get event mask request */
- else if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
+ else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only() &&
+ *buf == 0x81) {
driver->apps_rsp_buf[0] = 0x81;
driver->apps_rsp_buf[1] = 0x0;
*(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
@@ -691,7 +676,7 @@
return 0;
}
/* Get log ID range & Check for Apps Only */
- else if (!(driver->ch) && chk_apps_only()
+ else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
&& (*buf == 0x73) && *(int *)(buf+4) == 1) {
driver->apps_rsp_buf[0] = 0x73;
*(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
@@ -716,7 +701,7 @@
return 0;
}
/* Respond to Get SSID Range request message */
- else if (!(driver->ch) && chk_apps_only()
+ else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
&& (*buf == 0x7d) && (*(buf+1) == 0x1)) {
driver->apps_rsp_buf[0] = 0x7d;
driver->apps_rsp_buf[1] = 0x1;
@@ -774,7 +759,7 @@
return 0;
}
/* Check for Apps Only Respond to Get Subsys Build mask */
- else if (!(driver->ch) && chk_apps_only()
+ else if (!(driver->smd_data[MODEM_DATA].ch) && chk_apps_only()
&& (*buf == 0x7d) && (*(buf+1) == 0x2)) {
ssid_first = *(uint16_t *)(buf + 2);
ssid_last = *(uint16_t *)(buf + 4);
@@ -913,6 +898,23 @@
return 0;
}
}
+ /* Return the Delayed Response Wrap Status */
+ else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
+ (*(buf+2) == 0x04) && (*(buf+3) == 0x0)) {
+ memcpy(driver->apps_rsp_buf, buf, 4);
+ driver->apps_rsp_buf[4] = wrap_enabled;
+ encode_rsp_and_send(4);
+ return 0;
+ }
+ /* Wrap the Delayed Rsp ID */
+ else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
+ (*(buf+2) == 0x05) && (*(buf+3) == 0x0)) {
+ wrap_enabled = true;
+ memcpy(driver->apps_rsp_buf, buf, 4);
+ driver->apps_rsp_buf[4] = wrap_count;
+ encode_rsp_and_send(5);
+ return 0;
+ }
/* Check for ID for NO MODEM present */
else if (chk_polling_response()) {
/* respond to 0x0 command */
@@ -991,13 +993,14 @@
type = 0;
}
/* implies this packet is NOT meant for apps */
- if (!(driver->ch) && type == 1) {
+ if (!(driver->smd_data[MODEM_DATA].ch) && type == 1) {
if (chk_apps_only()) {
diag_send_error_rsp(hdlc.dest_idx);
} else { /* APQ 8060, Let Q6 respond */
- if (driver->chlpass)
- smd_write(driver->chlpass, driver->hdlc_buf,
- hdlc.dest_idx - 3);
+ if (driver->smd_data[LPASS_DATA].ch)
+ smd_write(driver->smd_data[LPASS_DATA].ch,
+ driver->hdlc_buf,
+ hdlc.dest_idx - 3);
}
type = 0;
}
@@ -1009,9 +1012,11 @@
driver->hdlc_buf)+i));
#endif /* DIAG DEBUG */
/* ignore 2 bytes for CRC, one for 7E and send */
- if ((driver->ch) && (ret) && (type) && (hdlc.dest_idx > 3)) {
+ if ((driver->smd_data[MODEM_DATA].ch) && (ret) && (type) &&
+ (hdlc.dest_idx > 3)) {
APPEND_DEBUG('g');
- smd_write(driver->ch, driver->hdlc_buf, hdlc.dest_idx - 3);
+ smd_write(driver->smd_data[MODEM_DATA].ch,
+ driver->hdlc_buf, hdlc.dest_idx - 3);
APPEND_DEBUG('h');
#ifdef DIAG_DEBUG
printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
@@ -1029,6 +1034,7 @@
int diagfwd_connect(void)
{
int err;
+ int i;
printk(KERN_DEBUG "diag: USB connected\n");
err = usb_diag_alloc_req(driver->legacy_ch, N_LEGACY_WRITE,
@@ -1037,21 +1043,16 @@
printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
driver->usb_connected = 1;
- driver->in_busy_1 = 0;
- driver->in_busy_2 = 0;
- driver->in_busy_lpass_1 = 0;
- driver->in_busy_lpass_2 = 0;
- driver->in_busy_wcnss_1 = 0;
- driver->in_busy_wcnss_2 = 0;
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ driver->smd_data[i].in_busy_1 = 0;
+ driver->smd_data[i].in_busy_2 = 0;
+ /* Poll SMD data channels to check for data */
+ queue_work(driver->diag_wq,
+ &(driver->smd_data[i].diag_read_smd_work));
+ /* Poll SMD CNTL channels to check for data */
+ diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
+ }
- /* Poll SMD channels to check for data*/
- queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
- queue_work(driver->diag_wq, &(driver->diag_read_smd_lpass_work));
- queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
- /* Poll SMD CNTL channels to check for data */
- diag_smd_cntl_notify(NULL, SMD_EVENT_DATA);
- diag_smd_lpass_cntl_notify(NULL, SMD_EVENT_DATA);
- diag_smd_wcnss_cntl_notify(NULL, SMD_EVENT_DATA);
/* Poll USB channel to check for data*/
queue_work(driver->diag_wq, &(driver->diag_read_work));
#ifdef CONFIG_DIAG_SDIO_PIPE
@@ -1067,17 +1068,17 @@
int diagfwd_disconnect(void)
{
+ int i;
+
printk(KERN_DEBUG "diag: USB disconnected\n");
driver->usb_connected = 0;
driver->debug_flag = 1;
usb_diag_free_req(driver->legacy_ch);
if (driver->logging_mode == USB_MODE) {
- driver->in_busy_1 = 1;
- driver->in_busy_2 = 1;
- driver->in_busy_lpass_1 = 1;
- driver->in_busy_lpass_2 = 1;
- driver->in_busy_wcnss_1 = 1;
- driver->in_busy_wcnss_2 = 1;
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ driver->smd_data[i].in_busy_1 = 1;
+ driver->smd_data[i].in_busy_2 = 1;
+ }
}
#ifdef CONFIG_DIAG_SDIO_PIPE
if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
@@ -1091,50 +1092,44 @@
int diagfwd_write_complete(struct diag_request *diag_write_ptr)
{
unsigned char *buf = diag_write_ptr->buf;
- /*Determine if the write complete is for data from modem/apps/q6 */
+ int found_it = 0;
+ int i;
+
+ /* Determine if the write complete is for data from modem/apps/q6 */
/* Need a context variable here instead */
- if (buf == (void *)driver->buf_in_1) {
- driver->in_busy_1 = 0;
- APPEND_DEBUG('o');
- queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
- } else if (buf == (void *)driver->buf_in_2) {
- driver->in_busy_2 = 0;
- APPEND_DEBUG('O');
- queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
- } else if (buf == (void *)driver->buf_in_lpass_1) {
- driver->in_busy_lpass_1 = 0;
- APPEND_DEBUG('p');
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_lpass_work));
- } else if (buf == (void *)driver->buf_in_lpass_2) {
- driver->in_busy_lpass_2 = 0;
- APPEND_DEBUG('P');
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_lpass_work));
- } else if (buf == driver->buf_in_wcnss_1) {
- driver->in_busy_wcnss_1 = 0;
- APPEND_DEBUG('r');
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_wcnss_work));
- } else if (buf == driver->buf_in_wcnss_2) {
- driver->in_busy_wcnss_2 = 0;
- APPEND_DEBUG('R');
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_wcnss_work));
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ struct diag_smd_info *data = &(driver->smd_data[i]);
+ if (buf == (void *)data->buf_in_1) {
+ data->in_busy_1 = 0;
+ queue_work(driver->diag_wq,
+ &(data->diag_read_smd_work));
+ found_it = 1;
+ break;
+ } else if (buf == (void *)data->buf_in_2) {
+ data->in_busy_2 = 0;
+ queue_work(driver->diag_wq,
+ &(data->diag_read_smd_work));
+ found_it = 1;
+ break;
+ }
}
#ifdef CONFIG_DIAG_SDIO_PIPE
- else if (buf == (void *)driver->buf_in_sdio)
- if (machine_is_msm8x60_fusion() ||
- machine_is_msm8x60_fusn_ffa())
- diagfwd_write_complete_sdio();
- else
- pr_err("diag: Incorrect buffer pointer while WRITE");
+ if (!found_it) {
+ if (buf == (void *)driver->buf_in_sdio) {
+ if (machine_is_msm8x60_fusion() ||
+ machine_is_msm8x60_fusn_ffa())
+ diagfwd_write_complete_sdio();
+ else
+ pr_err("diag: Incorrect buffer pointer while WRITE");
+ found_it = 1;
+ }
+ }
#endif
- else {
- diagmem_free(driver, (unsigned char *)buf, POOL_TYPE_HDLC);
+ if (!found_it) {
+ diagmem_free(driver, (unsigned char *)buf,
+ POOL_TYPE_HDLC);
diagmem_free(driver, (unsigned char *)diag_write_ptr,
- POOL_TYPE_WRITE_STRUCT);
- APPEND_DEBUG('q');
+ POOL_TYPE_WRITE_STRUCT);
}
return 0;
}
@@ -1221,70 +1216,87 @@
#endif /* DIAG OVER USB */
-static void diag_smd_notify(void *ctxt, unsigned event)
+void diag_smd_notify(void *ctxt, unsigned event)
{
- if (event == SMD_EVENT_CLOSE) {
- queue_work(driver->diag_cntl_wq,
- &(driver->diag_clean_modem_reg_work));
- driver->ch = 0;
+ struct diag_smd_info *smd_info = (struct diag_smd_info *)ctxt;
+ if (!smd_info)
return;
- } else if (event == SMD_EVENT_OPEN) {
- if (ch_temp)
- driver->ch = ch_temp;
- }
- queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
-}
-#if defined(CONFIG_MSM_N_WAY_SMD)
-static void diag_smd_lpass_notify(void *ctxt, unsigned event)
-{
if (event == SMD_EVENT_CLOSE) {
- queue_work(driver->diag_cntl_wq,
- &(driver->diag_clean_lpass_reg_work));
- driver->chlpass = 0;
+ smd_info->ch = 0;
+ wake_up(&driver->smd_wait_q);
+ if (smd_info->type == SMD_DATA_TYPE) {
+ smd_info->notify_context = event;
+ queue_work(driver->diag_cntl_wq,
+ &(smd_info->diag_notify_update_smd_work));
+ } else if (smd_info->type == SMD_DCI_TYPE) {
+ /* Notify the clients of the close */
+ diag_dci_notify_client(smd_info->peripheral_mask,
+ DIAG_STATUS_CLOSED);
+ }
return;
} else if (event == SMD_EVENT_OPEN) {
- if (chlpass_temp)
- driver->chlpass = chlpass_temp;
- }
- queue_work(driver->diag_wq, &(driver->diag_read_smd_lpass_work));
-}
-#endif
+ if (smd_info->ch_save)
+ smd_info->ch = smd_info->ch_save;
-static void diag_smd_wcnss_notify(void *ctxt, unsigned event)
-{
- if (event == SMD_EVENT_CLOSE) {
- queue_work(driver->diag_cntl_wq,
- &(driver->diag_clean_wcnss_reg_work));
- driver->ch_wcnss = 0;
- return;
- } else if (event == SMD_EVENT_OPEN) {
- if (ch_wcnss_temp)
- driver->ch_wcnss = ch_wcnss_temp;
+ if (smd_info->type == SMD_CNTL_TYPE) {
+ smd_info->notify_context = event;
+ queue_work(driver->diag_cntl_wq,
+ &(smd_info->diag_notify_update_smd_work));
+ } else if (smd_info->type == SMD_DCI_TYPE) {
+ smd_info->notify_context = event;
+ queue_work(driver->diag_dci_wq,
+ &(smd_info->diag_notify_update_smd_work));
+ /* Notify the clients of the open */
+ diag_dci_notify_client(smd_info->peripheral_mask,
+ DIAG_STATUS_OPEN);
+ }
}
- queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
+
+ wake_up(&driver->smd_wait_q);
+
+ if (smd_info->type == SMD_DCI_TYPE)
+ queue_work(driver->diag_dci_wq,
+ &(smd_info->diag_read_smd_work));
+ else
+ queue_work(driver->diag_wq, &(smd_info->diag_read_smd_work));
}
static int diag_smd_probe(struct platform_device *pdev)
{
int r = 0;
+ int index = -1;
if (pdev->id == SMD_APPS_MODEM) {
- r = smd_open("DIAG", &driver->ch, driver, diag_smd_notify);
- ch_temp = driver->ch;
+ index = MODEM_DATA;
+ r = smd_open("DIAG", &driver->smd_data[index].ch,
+ &driver->smd_data[index],
+ diag_smd_notify);
+ driver->smd_data[index].ch_save =
+ driver->smd_data[index].ch;
}
#if defined(CONFIG_MSM_N_WAY_SMD)
if (pdev->id == SMD_APPS_QDSP) {
+ index = LPASS_DATA;
r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP,
- &driver->chlpass, driver, diag_smd_lpass_notify);
- chlpass_temp = driver->chlpass;
+ &driver->smd_data[index].ch,
+ &driver->smd_data[index],
+ diag_smd_notify);
+ driver->smd_data[index].ch_save =
+ driver->smd_data[index].ch;
}
#endif
if (pdev->id == SMD_APPS_WCNSS) {
- r = smd_named_open_on_edge("APPS_RIVA_DATA", SMD_APPS_WCNSS
- , &driver->ch_wcnss, driver, diag_smd_wcnss_notify);
- ch_wcnss_temp = driver->ch_wcnss;
+ index = WCNSS_DATA;
+ r = smd_named_open_on_edge("APPS_RIVA_DATA",
+ SMD_APPS_WCNSS,
+ &driver->smd_data[index].ch,
+ &driver->smd_data[index],
+ diag_smd_notify);
+ driver->smd_data[index].ch_save =
+ driver->smd_data[index].ch;
}
+
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pr_debug("diag: open SMD port, Id = %d, r = %d\n", pdev->id, r);
@@ -1292,86 +1304,192 @@
return 0;
}
-static int diagfwd_runtime_suspend(struct device *dev)
+static int diag_smd_runtime_suspend(struct device *dev)
{
dev_dbg(dev, "pm_runtime: suspending...\n");
return 0;
}
-static int diagfwd_runtime_resume(struct device *dev)
+static int diag_smd_runtime_resume(struct device *dev)
{
dev_dbg(dev, "pm_runtime: resuming...\n");
return 0;
}
-static const struct dev_pm_ops diagfwd_dev_pm_ops = {
- .runtime_suspend = diagfwd_runtime_suspend,
- .runtime_resume = diagfwd_runtime_resume,
+static const struct dev_pm_ops diag_smd_dev_pm_ops = {
+ .runtime_suspend = diag_smd_runtime_suspend,
+ .runtime_resume = diag_smd_runtime_resume,
};
static struct platform_driver msm_smd_ch1_driver = {
.probe = diag_smd_probe,
.driver = {
- .name = "DIAG",
- .owner = THIS_MODULE,
- .pm = &diagfwd_dev_pm_ops,
- },
+ .name = "DIAG",
+ .owner = THIS_MODULE,
+ .pm = &diag_smd_dev_pm_ops,
+ },
};
static struct platform_driver diag_smd_lite_driver = {
.probe = diag_smd_probe,
.driver = {
- .name = "APPS_RIVA_DATA",
- .owner = THIS_MODULE,
- .pm = &diagfwd_dev_pm_ops,
- },
+ .name = "APPS_RIVA_DATA",
+ .owner = THIS_MODULE,
+ .pm = &diag_smd_dev_pm_ops,
+ },
};
+void diag_smd_destructor(struct diag_smd_info *smd_info)
+{
+ if (smd_info->ch)
+ smd_close(smd_info->ch);
+
+ smd_info->ch = 0;
+ smd_info->ch_save = 0;
+ kfree(smd_info->buf_in_1);
+ kfree(smd_info->buf_in_2);
+ kfree(smd_info->write_ptr_1);
+ kfree(smd_info->write_ptr_2);
+}
+
+int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
+ int type)
+{
+ smd_info->peripheral = peripheral;
+ smd_info->type = type;
+
+ switch (peripheral) {
+ case MODEM_DATA:
+ smd_info->peripheral_mask = DIAG_CON_MPSS;
+ break;
+ case LPASS_DATA:
+ smd_info->peripheral_mask = DIAG_CON_LPASS;
+ break;
+ case WCNSS_DATA:
+ smd_info->peripheral_mask = DIAG_CON_WCNSS;
+ break;
+ default:
+ pr_err("diag: In %s, unknown peripheral, peripheral: %d\n",
+ __func__, peripheral);
+ goto err;
+ }
+
+ smd_info->ch = 0;
+ smd_info->ch_save = 0;
+
+ if (smd_info->buf_in_1 == NULL) {
+ smd_info->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+ if (smd_info->buf_in_1 == NULL)
+ goto err;
+ kmemleak_not_leak(smd_info->buf_in_1);
+ }
+
+ if (smd_info->write_ptr_1 == NULL) {
+ smd_info->write_ptr_1 = kzalloc(sizeof(struct diag_request),
+ GFP_KERNEL);
+ if (smd_info->write_ptr_1 == NULL)
+ goto err;
+ kmemleak_not_leak(smd_info->write_ptr_1);
+ }
+
+ /* The smd data type needs two buffers */
+ if (smd_info->type == SMD_DATA_TYPE) {
+ if (smd_info->buf_in_2 == NULL) {
+ smd_info->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+ if (smd_info->buf_in_2 == NULL)
+ goto err;
+ kmemleak_not_leak(smd_info->buf_in_2);
+ }
+ if (smd_info->write_ptr_2 == NULL) {
+ smd_info->write_ptr_2 =
+ kzalloc(sizeof(struct diag_request),
+ GFP_KERNEL);
+ if (smd_info->write_ptr_2 == NULL)
+ goto err;
+ kmemleak_not_leak(smd_info->write_ptr_2);
+ }
+ }
+
+ INIT_WORK(&(smd_info->diag_read_smd_work), diag_read_smd_work_fn);
+
+ /*
+ * The update function assigned to the diag_notify_update_smd_work
+ * work_struct is meant to be used for updating that is not to
+ * be done in the context of the smd notify function. The
+ * notify_context variable can be used for passing additional
+ * information to the update function.
+ */
+ smd_info->notify_context = 0;
+ if (type == SMD_DATA_TYPE)
+ INIT_WORK(&(smd_info->diag_notify_update_smd_work),
+ diag_clean_reg_fn);
+ else if (type == SMD_CNTL_TYPE)
+ INIT_WORK(&(smd_info->diag_notify_update_smd_work),
+ diag_mask_update_fn);
+ else if (type == SMD_DCI_TYPE)
+ INIT_WORK(&(smd_info->diag_notify_update_smd_work),
+ diag_update_smd_dci_work_fn);
+ else {
+ pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
+ goto err;
+ }
+
+ /*
+ * Set function ptr for function to call to process the data that
+ * was just read from the smd channel
+ */
+ if (type == SMD_DATA_TYPE)
+ smd_info->process_smd_read_data = diag_process_smd_read_data;
+ else if (type == SMD_CNTL_TYPE)
+ smd_info->process_smd_read_data =
+ diag_process_smd_cntl_read_data;
+ else if (type == SMD_DCI_TYPE)
+ smd_info->process_smd_read_data =
+ diag_process_smd_dci_read_data;
+ else {
+ pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
+ goto err;
+ }
+
+ return 1;
+err:
+ kfree(smd_info->buf_in_1);
+ kfree(smd_info->buf_in_2);
+ kfree(smd_info->write_ptr_1);
+ kfree(smd_info->write_ptr_2);
+
+ return 0;
+}
+
void diagfwd_init(void)
{
+ int success;
+ int i;
+
+ wrap_enabled = 0;
+ wrap_count = 0;
diag_debug_buf_idx = 0;
driver->read_len_legacy = 0;
driver->use_device_tree = has_device_tree();
mutex_init(&driver->diag_cntl_mutex);
- if (driver->buf_in_1 == NULL) {
- driver->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_1 == NULL)
- goto err;
- kmemleak_not_leak(driver->buf_in_1);
- }
- if (driver->buf_in_2 == NULL) {
- driver->buf_in_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_2 == NULL)
- goto err;
- kmemleak_not_leak(driver->buf_in_2);
- }
- if (driver->buf_in_lpass_1 == NULL) {
- driver->buf_in_lpass_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_lpass_1 == NULL)
- goto err;
- kmemleak_not_leak(driver->buf_in_lpass_1);
- }
- if (driver->buf_in_lpass_2 == NULL) {
- driver->buf_in_lpass_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_lpass_2 == NULL)
- goto err;
- kmemleak_not_leak(driver->buf_in_lpass_2);
- }
- if (driver->buf_in_wcnss_1 == NULL) {
- driver->buf_in_wcnss_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_wcnss_1 == NULL)
- goto err;
- kmemleak_not_leak(driver->buf_in_wcnss_1);
- }
- if (driver->buf_in_wcnss_2 == NULL) {
- driver->buf_in_wcnss_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_wcnss_2 == NULL)
- goto err;
- kmemleak_not_leak(driver->buf_in_wcnss_2);
- }
+ success = diag_smd_constructor(&driver->smd_data[MODEM_DATA],
+ MODEM_DATA, SMD_DATA_TYPE);
+ if (!success)
+ goto err;
+
+ success = diag_smd_constructor(&driver->smd_data[LPASS_DATA],
+ LPASS_DATA, SMD_DATA_TYPE);
+ if (!success)
+ goto err;
+
+ success = diag_smd_constructor(&driver->smd_data[WCNSS_DATA],
+ WCNSS_DATA, SMD_DATA_TYPE);
+ if (!success)
+ goto err;
+
if (driver->usb_buf_out == NULL &&
(driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
GFP_KERNEL)) == NULL)
@@ -1409,48 +1527,6 @@
GFP_KERNEL)) == NULL)
goto err;
kmemleak_not_leak(driver->table);
- if (driver->write_ptr_1 == NULL) {
- driver->write_ptr_1 = kzalloc(
- sizeof(struct diag_request), GFP_KERNEL);
- if (driver->write_ptr_1 == NULL)
- goto err;
- kmemleak_not_leak(driver->write_ptr_1);
- }
- if (driver->write_ptr_2 == NULL) {
- driver->write_ptr_2 = kzalloc(
- sizeof(struct diag_request), GFP_KERNEL);
- if (driver->write_ptr_2 == NULL)
- goto err;
- kmemleak_not_leak(driver->write_ptr_2);
- }
- if (driver->write_ptr_lpass_1 == NULL) {
- driver->write_ptr_lpass_1 = kzalloc(
- sizeof(struct diag_request), GFP_KERNEL);
- if (driver->write_ptr_lpass_1 == NULL)
- goto err;
- kmemleak_not_leak(driver->write_ptr_lpass_1);
- }
- if (driver->write_ptr_lpass_2 == NULL) {
- driver->write_ptr_lpass_2 = kzalloc(
- sizeof(struct diag_request), GFP_KERNEL);
- if (driver->write_ptr_lpass_2 == NULL)
- goto err;
- kmemleak_not_leak(driver->write_ptr_lpass_2);
- }
- if (driver->write_ptr_wcnss_1 == NULL) {
- driver->write_ptr_wcnss_1 = kzalloc(
- sizeof(struct diag_request), GFP_KERNEL);
- if (driver->write_ptr_wcnss_1 == NULL)
- goto err;
- kmemleak_not_leak(driver->write_ptr_wcnss_1);
- }
- if (driver->write_ptr_wcnss_2 == NULL) {
- driver->write_ptr_wcnss_2 = kzalloc(
- sizeof(struct diag_request), GFP_KERNEL);
- if (driver->write_ptr_wcnss_2 == NULL)
- goto err;
- kmemleak_not_leak(driver->write_ptr_wcnss_2);
- }
if (driver->usb_read_ptr == NULL) {
driver->usb_read_ptr = kzalloc(
@@ -1483,16 +1559,13 @@
#endif
platform_driver_register(&msm_smd_ch1_driver);
platform_driver_register(&diag_smd_lite_driver);
-
return;
err:
pr_err("diag: Could not initialize diag buffers");
- kfree(driver->buf_in_1);
- kfree(driver->buf_in_2);
- kfree(driver->buf_in_lpass_1);
- kfree(driver->buf_in_lpass_2);
- kfree(driver->buf_in_wcnss_1);
- kfree(driver->buf_in_wcnss_2);
+
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
+ diag_smd_destructor(&driver->smd_data[i]);
+
kfree(driver->buf_msg_mask_update);
kfree(driver->buf_log_mask_update);
kfree(driver->buf_event_mask_update);
@@ -1503,12 +1576,6 @@
kfree(driver->data_ready);
kfree(driver->table);
kfree(driver->pkt_buf);
- kfree(driver->write_ptr_1);
- kfree(driver->write_ptr_2);
- kfree(driver->write_ptr_lpass_1);
- kfree(driver->write_ptr_lpass_2);
- kfree(driver->write_ptr_wcnss_1);
- kfree(driver->write_ptr_wcnss_2);
kfree(driver->usb_read_ptr);
kfree(driver->apps_rsp_buf);
kfree(driver->user_space_data);
@@ -1518,12 +1585,11 @@
void diagfwd_exit(void)
{
- smd_close(driver->ch);
- smd_close(driver->chlpass);
- smd_close(driver->ch_wcnss);
- driver->ch = 0; /* SMD can make this NULL */
- driver->chlpass = 0;
- driver->ch_wcnss = 0;
+ int i;
+
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
+ diag_smd_destructor(&driver->smd_data[i]);
+
#ifdef CONFIG_DIAG_OVER_USB
if (driver->usb_connected)
usb_diag_free_req(driver->legacy_ch);
@@ -1532,12 +1598,7 @@
platform_driver_unregister(&msm_smd_ch1_driver);
platform_driver_unregister(&msm_diag_dci_driver);
platform_driver_unregister(&diag_smd_lite_driver);
- kfree(driver->buf_in_1);
- kfree(driver->buf_in_2);
- kfree(driver->buf_in_lpass_1);
- kfree(driver->buf_in_lpass_2);
- kfree(driver->buf_in_wcnss_1);
- kfree(driver->buf_in_wcnss_2);
+
kfree(driver->buf_msg_mask_update);
kfree(driver->buf_log_mask_update);
kfree(driver->buf_event_mask_update);
@@ -1548,12 +1609,6 @@
kfree(driver->data_ready);
kfree(driver->table);
kfree(driver->pkt_buf);
- kfree(driver->write_ptr_1);
- kfree(driver->write_ptr_2);
- kfree(driver->write_ptr_lpass_1);
- kfree(driver->write_ptr_lpass_2);
- kfree(driver->write_ptr_wcnss_1);
- kfree(driver->write_ptr_wcnss_2);
kfree(driver->usb_read_ptr);
kfree(driver->apps_rsp_buf);
kfree(driver->user_space_data);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index a0631d6..14e2dd5 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -22,9 +22,7 @@
void diagfwd_init(void);
void diagfwd_exit(void);
void diag_process_hdlc(void *data, unsigned len);
-void __diag_smd_send_req(void);
-void __diag_smd_lpass_send_req(void);
-void __diag_smd_wcnss_send_req(void);
+void diag_smd_send_req(struct diag_smd_info *smd_info);
void diag_usb_legacy_notifier(void *, unsigned, struct diag_request *);
long diagchar_ioctl(struct file *, unsigned int, unsigned long);
int diag_device_write(void *, int, struct diag_request *);
@@ -37,6 +35,10 @@
void diag_update_userspace_clients(unsigned int type);
void diag_update_sleeping_process(int process_id, int data_type);
void encode_rsp_and_send(int buf_length);
+void diag_smd_notify(void *ctxt, unsigned event);
+int diag_smd_constructor(struct diag_smd_info *smd_info, int peripheral,
+ int type);
+void diag_smd_destructor(struct diag_smd_info *smd_info);
/* State for diag forwarding */
#ifdef CONFIG_DIAG_OVER_USB
int diagfwd_connect(void);
diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c
new file mode 100644
index 0000000..75fdeb4
--- /dev/null
+++ b/drivers/char/diag/diagfwd_bridge.c
@@ -0,0 +1,355 @@
+/* Copyright (c) 2012, The Linux Foundation. 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.
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/diagchar.h>
+#include <linux/kmemleak.h>
+#include <linux/err.h>
+#include <linux/workqueue.h>
+#include <linux/ratelimit.h>
+#include <linux/platform_device.h>
+#include <linux/smux.h>
+#ifdef CONFIG_DIAG_OVER_USB
+#include <mach/usbdiag.h>
+#endif
+#include "diagchar.h"
+#include "diagmem.h"
+#include "diagfwd_cntl.h"
+#include "diagfwd_smux.h"
+#include "diagfwd_hsic.h"
+#include "diag_masks.h"
+#include "diagfwd_bridge.h"
+
+struct diag_bridge_dev *diag_bridge;
+
+/* diagfwd_connect_bridge is called when the USB mdm channel is connected */
+int diagfwd_connect_bridge(int process_cable)
+{
+ int i;
+
+ pr_debug("diag: in %s\n", __func__);
+
+ for (i = 0; i < MAX_BRIDGES; i++)
+ if (diag_bridge[i].enabled)
+ connect_bridge(process_cable, i);
+ return 0;
+}
+
+void connect_bridge(int process_cable, int index)
+{
+ int err;
+
+ mutex_lock(&diag_bridge[index].bridge_mutex);
+ /* If the usb cable is being connected */
+ if (process_cable) {
+ err = usb_diag_alloc_req(diag_bridge[index].ch, N_MDM_WRITE,
+ N_MDM_READ);
+ if (err)
+ pr_err("diag: unable to alloc USB req on mdm ch err:%d\n",
+ err);
+
+ diag_bridge[index].usb_connected = 1;
+ }
+
+ if (index == SMUX && driver->diag_smux_enabled) {
+ driver->in_busy_smux = 0;
+ diagfwd_connect_smux();
+ } else if (index == HSIC && driver->hsic_device_enabled) {
+ driver->in_busy_hsic_read_on_device = 0;
+ driver->in_busy_hsic_write = 0;
+ /* If the HSIC (diag_bridge) platform device is not open */
+ if (!driver->hsic_device_opened) {
+ err = diag_bridge_open(&hsic_diag_bridge_ops);
+ if (err) {
+ pr_err("diag: HSIC channel open error: %d\n",
+ err);
+ } else {
+ pr_debug("diag: opened HSIC channel\n");
+ driver->hsic_device_opened = 1;
+ }
+ } else {
+ pr_debug("diag: HSIC channel already open\n");
+ }
+ /*
+ * Turn on communication over usb mdm and HSIC, if the HSIC
+ * device driver is enabled and opened
+ */
+ if (driver->hsic_device_opened) {
+ driver->hsic_ch = 1;
+ /* Poll USB mdm channel to check for data */
+ if (driver->logging_mode == USB_MODE)
+ queue_work(diag_bridge[HSIC].wq,
+ &diag_bridge[HSIC].diag_read_work);
+ /* Poll HSIC channel to check for data */
+ queue_work(diag_bridge[HSIC].wq,
+ &driver->diag_read_hsic_work);
+ }
+ }
+ mutex_unlock(&diag_bridge[index].bridge_mutex);
+}
+
+/*
+ * diagfwd_disconnect_bridge is called when the USB mdm channel
+ * is disconnected. So disconnect should happen for all bridges
+ */
+int diagfwd_disconnect_bridge(int process_cable)
+{
+ int i;
+ pr_debug("diag: In %s, process_cable: %d\n", __func__, process_cable);
+
+ for (i = 0; i < MAX_BRIDGES; i++) {
+ if (diag_bridge[i].enabled) {
+ mutex_lock(&diag_bridge[i].bridge_mutex);
+ /* If the usb cable is being disconnected */
+ if (process_cable) {
+ diag_bridge[i].usb_connected = 0;
+ usb_diag_free_req(diag_bridge[i].ch);
+ }
+
+ if (i == HSIC && driver->hsic_device_enabled &&
+ driver->logging_mode != MEMORY_DEVICE_MODE) {
+ driver->in_busy_hsic_read_on_device = 1;
+ driver->in_busy_hsic_write = 1;
+ /* Turn off communication over usb and HSIC */
+ diag_hsic_close();
+ } else if (i == SMUX && driver->diag_smux_enabled &&
+ driver->logging_mode == USB_MODE) {
+ driver->in_busy_smux = 1;
+ driver->lcid = LCID_INVALID;
+ driver->smux_connected = 0;
+ /* Turn off communication over usb and smux */
+ msm_smux_close(LCID_VALID);
+ }
+ mutex_unlock(&diag_bridge[i].bridge_mutex);
+ }
+ }
+ return 0;
+}
+
+/* Called after the asychronous usb_diag_read() on mdm channel is complete */
+int diagfwd_read_complete_bridge(struct diag_request *diag_read_ptr)
+{
+ int index = (int)(diag_read_ptr->context);
+
+ /* The read of the usb on the mdm (not HSIC/SMUX) has completed */
+ diag_bridge[index].read_len = diag_read_ptr->actual;
+
+ if (index == SMUX) {
+ if (driver->diag_smux_enabled) {
+ diagfwd_read_complete_smux();
+ return 0;
+ } else {
+ pr_warning("diag: incorrect callback for smux\n");
+ }
+ }
+
+ /* If SMUX not enabled, check for HSIC */
+ driver->in_busy_hsic_read_on_device = 0;
+ if (!driver->hsic_ch) {
+ pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+ return 0;
+ }
+
+ /*
+ * The read of the usb driver on the mdm channel has completed.
+ * If there is no write on the HSIC in progress, check if the
+ * read has data to pass on to the HSIC. If so, pass the usb
+ * mdm data on to the HSIC.
+ */
+ if (!driver->in_busy_hsic_write && diag_bridge[HSIC].usb_buf_out &&
+ (diag_bridge[HSIC].read_len > 0)) {
+
+ /*
+ * Initiate the HSIC write. The HSIC write is
+ * asynchronous. When complete the write
+ * complete callback function will be called
+ */
+ int err;
+ driver->in_busy_hsic_write = 1;
+ err = diag_bridge_write(diag_bridge[HSIC].usb_buf_out,
+ diag_bridge[HSIC].read_len);
+ if (err) {
+ pr_err_ratelimited("diag: mdm data on HSIC write err: %d\n",
+ err);
+ /*
+ * If the error is recoverable, then clear
+ * the write flag, so we will resubmit a
+ * write on the next frame. Otherwise, don't
+ * resubmit a write on the next frame.
+ */
+ if ((-ENODEV) != err)
+ driver->in_busy_hsic_write = 0;
+ }
+ }
+
+ /*
+ * If there is no write of the usb mdm data on the
+ * HSIC channel
+ */
+ if (!driver->in_busy_hsic_write)
+ queue_work(diag_bridge[HSIC].wq,
+ &diag_bridge[HSIC].diag_read_work);
+
+ return 0;
+}
+
+static void diagfwd_bridge_notifier(void *priv, unsigned event,
+ struct diag_request *d_req)
+{
+ int index;
+
+ switch (event) {
+ case USB_DIAG_CONNECT:
+ diagfwd_connect_bridge(1);
+ break;
+ case USB_DIAG_DISCONNECT:
+ queue_work(driver->diag_wq,
+ &driver->diag_disconnect_work);
+ break;
+ case USB_DIAG_READ_DONE:
+ index = (int)(d_req->context);
+ queue_work(diag_bridge[index].wq,
+ &diag_bridge[index].usb_read_complete_work);
+ break;
+ case USB_DIAG_WRITE_DONE:
+ index = (int)(d_req->context);
+ if (index == HSIC && driver->hsic_device_enabled)
+ diagfwd_write_complete_hsic(d_req);
+ else if (index == SMUX && driver->diag_smux_enabled)
+ diagfwd_write_complete_smux();
+ break;
+ default:
+ pr_err("diag: in %s: Unknown event from USB diag:%u\n",
+ __func__, event);
+ break;
+ }
+}
+
+void diagfwd_bridge_init(int index)
+{
+ int ret;
+ unsigned char name[20];
+
+ if (index == HSIC)
+ strlcpy(name, "hsic", sizeof(name));
+ else
+ strlcpy(name, "smux", sizeof(name));
+
+ strlcpy(diag_bridge[index].name, name, sizeof(diag_bridge[index].name));
+ strlcat(name, "_diag_wq", sizeof(diag_bridge[index].name));
+ diag_bridge[index].enabled = 1;
+ diag_bridge[index].wq = create_singlethread_workqueue(name);
+ diag_bridge[index].read_len = 0;
+ diag_bridge[index].write_len = 0;
+ if (diag_bridge[index].usb_buf_out == NULL)
+ diag_bridge[index].usb_buf_out =
+ kzalloc(USB_MAX_OUT_BUF, GFP_KERNEL);
+ if (diag_bridge[index].usb_buf_out == NULL)
+ goto err;
+ if (diag_bridge[index].usb_read_ptr == NULL)
+ diag_bridge[index].usb_read_ptr =
+ kzalloc(sizeof(struct diag_request), GFP_KERNEL);
+ if (diag_bridge[index].usb_read_ptr == NULL)
+ goto err;
+ if (diag_bridge[index].usb_read_ptr->context == NULL)
+ diag_bridge[index].usb_read_ptr->context =
+ kzalloc(sizeof(int), GFP_KERNEL);
+ if (diag_bridge[index].usb_read_ptr->context == NULL)
+ goto err;
+ mutex_init(&diag_bridge[index].bridge_mutex);
+
+ if (index == HSIC) {
+ INIT_WORK(&(diag_bridge[index].usb_read_complete_work),
+ diag_usb_read_complete_hsic_fn);
+#ifdef CONFIG_DIAG_OVER_USB
+ INIT_WORK(&(diag_bridge[index].diag_read_work),
+ diag_read_usb_hsic_work_fn);
+ diag_bridge[index].ch = usb_diag_open(DIAG_MDM, (void *)index,
+ diagfwd_bridge_notifier);
+ if (IS_ERR(diag_bridge[index].ch)) {
+ pr_err("diag: Unable to open USB diag MDM channel\n");
+ goto err;
+ }
+#endif
+ /* register HSIC device */
+ ret = platform_driver_register(&msm_hsic_ch_driver);
+ if (ret)
+ pr_err("diag: could not register HSIC device, ret: %d\n",
+ ret);
+ } else if (index == SMUX) {
+ INIT_WORK(&(diag_bridge[index].usb_read_complete_work),
+ diag_usb_read_complete_smux_fn);
+#ifdef CONFIG_DIAG_OVER_USB
+ INIT_WORK(&(diag_bridge[index].diag_read_work),
+ diag_read_usb_smux_work_fn);
+ diag_bridge[index].ch = usb_diag_open(DIAG_QSC, (void *)index,
+ diagfwd_bridge_notifier);
+ if (IS_ERR(diag_bridge[index].ch)) {
+ pr_err("diag: Unable to open USB diag QSC channel\n");
+ goto err;
+ }
+#endif
+ ret = platform_driver_register(&msm_diagfwd_smux_driver);
+ if (ret)
+ pr_err("diag: could not register SMUX device, ret: %d\n",
+ ret);
+ }
+ return;
+err:
+ pr_err("diag: Could not initialize for bridge forwarding\n");
+ kfree(diag_bridge[index].usb_buf_out);
+ kfree(driver->hsic_buf_tbl);
+ kfree(driver->write_ptr_mdm);
+ kfree(diag_bridge[index].usb_read_ptr);
+ if (diag_bridge[index].wq)
+ destroy_workqueue(diag_bridge[index].wq);
+ return;
+}
+
+void diagfwd_bridge_exit(void)
+{
+ int i;
+ pr_debug("diag: in %s\n", __func__);
+
+ if (driver->hsic_device_enabled) {
+ diag_hsic_close();
+ driver->hsic_device_enabled = 0;
+ diag_bridge[HSIC].enabled = 0;
+ }
+ driver->hsic_inited = 0;
+ diagmem_exit(driver, POOL_TYPE_ALL);
+ if (driver->diag_smux_enabled) {
+ driver->lcid = LCID_INVALID;
+ kfree(driver->buf_in_smux);
+ driver->diag_smux_enabled = 0;
+ diag_bridge[SMUX].enabled = 0;
+ }
+ platform_driver_unregister(&msm_hsic_ch_driver);
+ platform_driver_unregister(&msm_diagfwd_smux_driver);
+ /* destroy USB MDM specific variables */
+ for (i = 0; i < MAX_BRIDGES; i++) {
+ if (diag_bridge[i].enabled) {
+#ifdef CONFIG_DIAG_OVER_USB
+ if (diag_bridge[i].usb_connected)
+ usb_diag_free_req(diag_bridge[i].ch);
+ usb_diag_close(diag_bridge[i].ch);
+#endif
+ kfree(diag_bridge[i].usb_buf_out);
+ kfree(diag_bridge[i].usb_read_ptr);
+ destroy_workqueue(diag_bridge[i].wq);
+ diag_bridge[i].enabled = 0;
+ }
+ }
+ kfree(driver->hsic_buf_tbl);
+ kfree(driver->write_ptr_mdm);
+}
diff --git a/drivers/char/diag/diagfwd_bridge.h b/drivers/char/diag/diagfwd_bridge.h
new file mode 100644
index 0000000..06e6a96
--- /dev/null
+++ b/drivers/char/diag/diagfwd_bridge.h
@@ -0,0 +1,47 @@
+/* Copyright (c) 2012, The Linux Foundation. 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 DIAGFWD_BRIDGE_H
+#define DIAGFWD_BRIDGE_H
+
+#include "diagfwd.h"
+
+#define MAX_BRIDGES 5
+#define HSIC 0
+#define SMUX 1
+
+int diagfwd_connect_bridge(int);
+void connect_bridge(int, int);
+int diagfwd_disconnect_bridge(int);
+void diagfwd_bridge_init(int index);
+void diagfwd_bridge_exit(void);
+int diagfwd_read_complete_bridge(struct diag_request *diag_read_ptr);
+
+/* Diag-Bridge structure, n bridges can be used at same time
+ * for instance SMUX, HSIC working at same time
+ */
+struct diag_bridge_dev {
+ char name[20];
+ int enabled;
+ struct mutex bridge_mutex;
+ int usb_connected;
+ int read_len;
+ int write_len;
+ unsigned char *usb_buf_out;
+ struct usb_diag_ch *ch;
+ struct workqueue_struct *wq;
+ struct work_struct diag_read_work;
+ struct diag_request *usb_read_ptr;
+ struct work_struct usb_read_complete_work;
+};
+
+#endif
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 9e5a8d0..acac2fb 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -21,251 +21,151 @@
static uint16_t reg_dirty;
#define HDR_SIZ 8
-void diag_clean_modem_reg_fn(struct work_struct *work)
+void diag_clean_reg_fn(struct work_struct *work)
{
- pr_debug("diag: clean modem registration\n");
- reg_dirty |= DIAG_CON_MPSS;
- diag_clear_reg(MODEM_PROC);
- reg_dirty ^= DIAG_CON_MPSS;
-}
-
-void diag_clean_lpass_reg_fn(struct work_struct *work)
-{
- pr_debug("diag: clean lpass registration\n");
- reg_dirty |= DIAG_CON_LPASS;
- diag_clear_reg(LPASS_PROC);
- reg_dirty ^= DIAG_CON_LPASS;
-}
-
-void diag_clean_wcnss_reg_fn(struct work_struct *work)
-{
- pr_debug("diag: clean wcnss registration\n");
- reg_dirty |= DIAG_CON_WCNSS;
- diag_clear_reg(WCNSS_PROC);
- reg_dirty ^= DIAG_CON_WCNSS;
-}
-
-void diag_smd_cntl_notify(void *ctxt, unsigned event)
-{
- int r1, r2;
-
- if (!(driver->ch_cntl))
+ struct diag_smd_info *smd_info = container_of(work,
+ struct diag_smd_info,
+ diag_notify_update_smd_work);
+ if (!smd_info)
return;
- switch (event) {
- case SMD_EVENT_DATA:
- r1 = smd_read_avail(driver->ch_cntl);
- r2 = smd_cur_packet_size(driver->ch_cntl);
- if (r1 > 0 && r1 == r2)
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_cntl_work));
- else
- pr_debug("diag: incomplete pkt on Modem CNTL ch\n");
- break;
- case SMD_EVENT_OPEN:
- queue_work(driver->diag_cntl_wq,
- &(driver->diag_modem_mask_update_work));
- break;
- }
+ pr_debug("diag: clean registration for peripheral: %d\n",
+ smd_info->peripheral);
+
+ reg_dirty |= smd_info->peripheral_mask;
+ diag_clear_reg(smd_info->peripheral);
+ reg_dirty ^= smd_info->peripheral_mask;
+
+ smd_info->notify_context = 0;
}
-void diag_smd_lpass_cntl_notify(void *ctxt, unsigned event)
+/* Process the data read from the smd control channel */
+int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf,
+ int total_recd)
{
- int r1, r2;
-
- if (!(driver->chlpass_cntl))
- return;
-
- switch (event) {
- case SMD_EVENT_DATA:
- r1 = smd_read_avail(driver->chlpass_cntl);
- r2 = smd_cur_packet_size(driver->chlpass_cntl);
- if (r1 > 0 && r1 == r2)
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_lpass_cntl_work));
- else
- pr_debug("diag: incomplete pkt on LPASS CNTL ch\n");
- break;
- case SMD_EVENT_OPEN:
- queue_work(driver->diag_cntl_wq,
- &(driver->diag_lpass_mask_update_work));
- break;
- }
-}
-
-void diag_smd_wcnss_cntl_notify(void *ctxt, unsigned event)
-{
- int r1, r2;
-
- if (!(driver->ch_wcnss_cntl))
- return;
-
- switch (event) {
- case SMD_EVENT_DATA:
- r1 = smd_read_avail(driver->ch_wcnss_cntl);
- r2 = smd_cur_packet_size(driver->ch_wcnss_cntl);
- if (r1 > 0 && r1 == r2)
- queue_work(driver->diag_wq,
- &(driver->diag_read_smd_wcnss_cntl_work));
- else
- pr_debug("diag: incomplete pkt on WCNSS CNTL ch\n");
- break;
- case SMD_EVENT_OPEN:
- queue_work(driver->diag_cntl_wq,
- &(driver->diag_wcnss_mask_update_work));
- break;
- }
-}
-
-static void diag_smd_cntl_send_req(int proc_num)
-{
- int data_len = 0, type = -1, count_bytes = 0, j, r, flag = 0;
+ int data_len = 0, type = -1, count_bytes = 0, j, flag = 0;
+ int feature_mask_len;
struct bindpkt_params_per_process *pkt_params =
- kzalloc(sizeof(struct bindpkt_params_per_process), GFP_KERNEL);
+ kzalloc(sizeof(struct bindpkt_params_per_process), GFP_KERNEL);
struct diag_ctrl_msg *msg;
struct cmd_code_range *range;
struct bindpkt_params *temp;
- void *buf = NULL;
- smd_channel_t *smd_ch = NULL;
- /* tracks which peripheral is sending registration */
- uint16_t reg_mask = 0;
if (pkt_params == NULL) {
- pr_alert("diag: Memory allocation failure\n");
- return;
+ pr_alert("diag: In %s, Memory allocation failure\n",
+ __func__);
+ return 0;
}
- if (proc_num == MODEM_PROC) {
- buf = driver->buf_in_cntl;
- smd_ch = driver->ch_cntl;
- reg_mask = DIAG_CON_MPSS;
- } else if (proc_num == LPASS_PROC) {
- buf = driver->buf_in_lpass_cntl;
- smd_ch = driver->chlpass_cntl;
- reg_mask = DIAG_CON_LPASS;
- } else if (proc_num == WCNSS_PROC) {
- buf = driver->buf_in_wcnss_cntl;
- smd_ch = driver->ch_wcnss_cntl;
- reg_mask = DIAG_CON_WCNSS;
- }
-
- if (!smd_ch || !buf) {
+ if (!smd_info) {
+ pr_err("diag: In %s, No smd info. Not able to read.\n",
+ __func__);
kfree(pkt_params);
- return;
+ return 0;
}
- r = smd_read_avail(smd_ch);
- if (r > IN_BUF_SIZE) {
- if (r < MAX_IN_BUF_SIZE) {
- pr_err("diag: SMD CNTL sending pkt upto %d bytes", r);
- buf = krealloc(buf, r, GFP_KERNEL);
- } else {
- pr_err("diag: CNTL pkt > %d bytes", MAX_IN_BUF_SIZE);
- kfree(pkt_params);
- return;
+ while (count_bytes + HDR_SIZ <= total_recd) {
+ type = *(uint32_t *)(buf);
+ data_len = *(uint32_t *)(buf + 4);
+ if (type < DIAG_CTRL_MSG_REG ||
+ type > DIAG_CTRL_MSG_F3_MASK_V2) {
+ pr_alert("diag: In %s, Invalid Msg type %d proc %d",
+ __func__, type, smd_info->peripheral);
+ break;
}
- }
- if (buf && r > 0) {
- smd_read(smd_ch, buf, r);
- while (count_bytes + HDR_SIZ <= r) {
- type = *(uint32_t *)(buf);
- data_len = *(uint32_t *)(buf + 4);
- if (type < DIAG_CTRL_MSG_REG ||
- type > DIAG_CTRL_MSG_F3_MASK_V2) {
- pr_alert("diag: Invalid Msg type %d proc %d",
- type, proc_num);
- break;
- }
- if (data_len < 0 || data_len > r) {
- pr_alert("diag: Invalid data len %d proc %d",
- data_len, proc_num);
- break;
- }
- count_bytes = count_bytes+HDR_SIZ+data_len;
- if (type == DIAG_CTRL_MSG_REG && r >= count_bytes) {
- msg = buf+HDR_SIZ;
- range = buf+HDR_SIZ+
- sizeof(struct diag_ctrl_msg);
- pkt_params->count = msg->count_entries;
- temp = kzalloc(pkt_params->count * sizeof(struct
- bindpkt_params), GFP_KERNEL);
- if (temp == NULL) {
- pr_alert("diag: Memory alloc fail\n");
- kfree(pkt_params);
- return;
- }
- for (j = 0; j < pkt_params->count; j++) {
- temp->cmd_code = msg->cmd_code;
- temp->subsys_id = msg->subsysid;
- temp->client_id = proc_num;
- temp->proc_id = proc_num;
- temp->cmd_code_lo = range->cmd_code_lo;
- temp->cmd_code_hi = range->cmd_code_hi;
- range++;
- temp++;
- }
- temp -= pkt_params->count;
- pkt_params->params = temp;
- flag = 1;
- /* peripheral undergoing SSR should not
- * record new registration
- */
- if (!(reg_dirty & reg_mask))
- diagchar_ioctl(NULL,
- DIAG_IOCTL_COMMAND_REG, (unsigned long)
- pkt_params);
- else
- pr_err("diag: drop reg proc %d\n",
- proc_num);
- kfree(temp);
- }
- buf = buf + HDR_SIZ + data_len;
+ if (data_len < 0 || data_len > total_recd) {
+ pr_alert("diag: In %s, Invalid data len %d, total_recd: %d, proc %d",
+ __func__, data_len, total_recd,
+ smd_info->peripheral);
+ break;
}
+ count_bytes = count_bytes+HDR_SIZ+data_len;
+ if (type == DIAG_CTRL_MSG_REG && total_recd >= count_bytes) {
+ msg = buf+HDR_SIZ;
+ range = buf+HDR_SIZ+
+ sizeof(struct diag_ctrl_msg);
+ pkt_params->count = msg->count_entries;
+ temp = kzalloc(pkt_params->count * sizeof(struct
+ bindpkt_params), GFP_KERNEL);
+ if (temp == NULL) {
+ pr_alert("diag: In %s, Memory alloc fail\n",
+ __func__);
+ kfree(pkt_params);
+ return flag;
+ }
+ for (j = 0; j < pkt_params->count; j++) {
+ temp->cmd_code = msg->cmd_code;
+ temp->subsys_id = msg->subsysid;
+ temp->client_id = smd_info->peripheral;
+ temp->proc_id = NON_APPS_PROC;
+ temp->cmd_code_lo = range->cmd_code_lo;
+ temp->cmd_code_hi = range->cmd_code_hi;
+ range++;
+ temp++;
+ }
+ temp -= pkt_params->count;
+ pkt_params->params = temp;
+ flag = 1;
+ /* peripheral undergoing SSR should not
+ * record new registration
+ */
+ if (!(reg_dirty & smd_info->peripheral_mask))
+ diagchar_ioctl(NULL, DIAG_IOCTL_COMMAND_REG,
+ (unsigned long)pkt_params);
+ else
+ pr_err("diag: drop reg proc %d\n",
+ smd_info->peripheral);
+ kfree(temp);
+ } else if ((type == DIAG_CTRL_MSG_FEATURE) &&
+ (smd_info->peripheral == MODEM_DATA)) {
+ feature_mask_len = *(int *)(buf + 8);
+ driver->log_on_demand_support = (*(uint8_t *)
+ (buf + 12)) & 0x04;
+ } else if (type != DIAG_CTRL_MSG_REG) {
+ flag = 1;
+ }
+ buf = buf + HDR_SIZ + data_len;
}
kfree(pkt_params);
- if (flag) {
- /* Poll SMD CNTL channels to check for data */
- if (proc_num == MODEM_PROC)
- diag_smd_cntl_notify(NULL, SMD_EVENT_DATA);
- else if (proc_num == LPASS_PROC)
- diag_smd_lpass_cntl_notify(NULL, SMD_EVENT_DATA);
- else if (proc_num == WCNSS_PROC)
- diag_smd_wcnss_cntl_notify(NULL, SMD_EVENT_DATA);
- }
-}
-void diag_read_smd_cntl_work_fn(struct work_struct *work)
-{
- diag_smd_cntl_send_req(MODEM_PROC);
-}
-
-void diag_read_smd_lpass_cntl_work_fn(struct work_struct *work)
-{
- diag_smd_cntl_send_req(LPASS_PROC);
-}
-
-void diag_read_smd_wcnss_cntl_work_fn(struct work_struct *work)
-{
- diag_smd_cntl_send_req(WCNSS_PROC);
+ return flag;
}
static int diag_smd_cntl_probe(struct platform_device *pdev)
{
int r = 0;
+ int index = -1;
/* open control ports only on 8960 & newer targets */
if (chk_apps_only()) {
- if (pdev->id == SMD_APPS_MODEM)
- r = smd_open("DIAG_CNTL", &driver->ch_cntl, driver,
- diag_smd_cntl_notify);
- if (pdev->id == SMD_APPS_QDSP)
- r = smd_named_open_on_edge("DIAG_CNTL", SMD_APPS_QDSP
- , &driver->chlpass_cntl, driver,
- diag_smd_lpass_cntl_notify);
- if (pdev->id == SMD_APPS_WCNSS)
+ if (pdev->id == SMD_APPS_MODEM) {
+ index = MODEM_DATA;
+ r = smd_open("DIAG_CNTL",
+ &driver->smd_cntl[index].ch,
+ &driver->smd_cntl[index],
+ diag_smd_notify);
+ driver->smd_cntl[index].ch_save =
+ driver->smd_cntl[index].ch;
+ } else if (pdev->id == SMD_APPS_QDSP) {
+ index = LPASS_DATA;
+ r = smd_named_open_on_edge("DIAG_CNTL",
+ SMD_APPS_QDSP,
+ &driver->smd_cntl[index].ch,
+ &driver->smd_cntl[index],
+ diag_smd_notify);
+ driver->smd_cntl[index].ch_save =
+ driver->smd_cntl[index].ch;
+ } else if (pdev->id == SMD_APPS_WCNSS) {
+ index = WCNSS_DATA;
r = smd_named_open_on_edge("APPS_RIVA_CTRL",
- SMD_APPS_WCNSS, &driver->ch_wcnss_cntl,
- driver, diag_smd_wcnss_cntl_notify);
+ SMD_APPS_WCNSS,
+ &driver->smd_cntl[index].ch,
+ &driver->smd_cntl[index],
+ diag_smd_notify);
+ driver->smd_cntl[index].ch_save =
+ driver->smd_cntl[index].ch;
+ }
+
pr_debug("diag: open CNTL port, ID = %d,r = %d\n", pdev->id, r);
}
return 0;
@@ -310,53 +210,52 @@
void diagfwd_cntl_init(void)
{
+ int success;
+ int i;
+
reg_dirty = 0;
driver->polling_reg_flag = 0;
+ driver->log_on_demand_support = 1;
driver->diag_cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
- if (driver->buf_in_cntl == NULL) {
- driver->buf_in_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_cntl == NULL)
- goto err;
- kmemleak_not_leak(driver->buf_in_cntl);
- }
- if (driver->buf_in_lpass_cntl == NULL) {
- driver->buf_in_lpass_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_lpass_cntl == NULL)
- goto err;
- kmemleak_not_leak(driver->buf_in_lpass_cntl);
- }
- if (driver->buf_in_wcnss_cntl == NULL) {
- driver->buf_in_wcnss_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_wcnss_cntl == NULL)
- goto err;
- kmemleak_not_leak(driver->buf_in_wcnss_cntl);
- }
+
+ success = diag_smd_constructor(&driver->smd_cntl[MODEM_DATA],
+ MODEM_DATA, SMD_CNTL_TYPE);
+ if (!success)
+ goto err;
+
+ success = diag_smd_constructor(&driver->smd_cntl[LPASS_DATA],
+ LPASS_DATA, SMD_CNTL_TYPE);
+ if (!success)
+ goto err;
+
+ success = diag_smd_constructor(&driver->smd_cntl[WCNSS_DATA],
+ WCNSS_DATA, SMD_CNTL_TYPE);
+ if (!success)
+ goto err;
+
platform_driver_register(&msm_smd_ch1_cntl_driver);
platform_driver_register(&diag_smd_lite_cntl_driver);
return;
err:
- pr_err("diag: Could not initialize diag buffers");
- kfree(driver->buf_in_cntl);
- kfree(driver->buf_in_lpass_cntl);
- kfree(driver->buf_in_wcnss_cntl);
- if (driver->diag_cntl_wq)
- destroy_workqueue(driver->diag_cntl_wq);
+ pr_err("diag: Could not initialize diag buffers");
+
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+ diag_smd_destructor(&driver->smd_cntl[i]);
+
+ if (driver->diag_cntl_wq)
+ destroy_workqueue(driver->diag_cntl_wq);
}
void diagfwd_cntl_exit(void)
{
- smd_close(driver->ch_cntl);
- smd_close(driver->chlpass_cntl);
- smd_close(driver->ch_wcnss_cntl);
- driver->ch_cntl = 0;
- driver->chlpass_cntl = 0;
- driver->ch_wcnss_cntl = 0;
+ int i;
+
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+ diag_smd_destructor(&driver->smd_cntl[i]);
+
destroy_workqueue(driver->diag_cntl_wq);
+
platform_driver_unregister(&msm_smd_ch1_cntl_driver);
platform_driver_unregister(&diag_smd_lite_cntl_driver);
-
- kfree(driver->buf_in_cntl);
- kfree(driver->buf_in_lpass_cntl);
- kfree(driver->buf_in_wcnss_cntl);
}
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index 8a0ec3f..8d262c4 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -77,16 +77,18 @@
/* Copy msg mask here */
} __packed;
+struct diag_ctrl_feature_mask {
+ uint32_t ctrl_pkt_id;
+ uint32_t ctrl_pkt_data_len;
+ uint32_t feature_mask_len;
+ /* Copy feature mask here */
+} __packed;
+
void diagfwd_cntl_init(void);
void diagfwd_cntl_exit(void);
void diag_read_smd_cntl_work_fn(struct work_struct *);
-void diag_read_smd_lpass_cntl_work_fn(struct work_struct *);
-void diag_read_smd_wcnss_cntl_work_fn(struct work_struct *);
-void diag_smd_cntl_notify(void *ctxt, unsigned event);
-void diag_smd_lpass_cntl_notify(void *ctxt, unsigned event);
-void diag_smd_wcnss_cntl_notify(void *ctxt, unsigned event);
-void diag_clean_modem_reg_fn(struct work_struct *);
-void diag_clean_lpass_reg_fn(struct work_struct *);
-void diag_clean_wcnss_reg_fn(struct work_struct *);
+void diag_clean_reg_fn(struct work_struct *work);
+int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf,
+ int total_recd);
#endif
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index 56f2fae..3d5eea5 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -31,6 +31,7 @@
#include "diagfwd.h"
#include "diagfwd_hsic.h"
#include "diagfwd_smux.h"
+#include "diagfwd_bridge.h"
#define READ_HSIC_BUF_SIZE 2048
@@ -72,7 +73,7 @@
write_ptrs_available--;
/*
- * No sense queuing a read if the hsic bridge was
+ * No sense queuing a read if the HSIC bridge was
* closed in another thread
*/
if (!driver->hsic_ch)
@@ -82,7 +83,7 @@
POOL_TYPE_HSIC);
if (buf_in_hsic) {
/*
- * Initiate the read from the hsic. The hsic read is
+ * Initiate the read from the HSIC. The HSIC read is
* asynchronous. Once the read is complete the read
* callback function will be called.
*/
@@ -116,7 +117,7 @@
if ((driver->count_hsic_pool < driver->poolsize_hsic) &&
(num_reads_submitted == 0) && (err != -ENODEV) &&
(driver->hsic_ch != 0))
- queue_work(driver->diag_bridge_wq,
+ queue_work(diag_bridge[HSIC].wq,
&driver->diag_read_hsic_work);
}
@@ -127,7 +128,7 @@
if (!driver->hsic_ch) {
/*
- * The hsic channel is closed. Return the buffer to
+ * The HSIC channel is closed. Return the buffer to
* the pool. Do not send it on.
*/
diagmem_free(driver, buf, POOL_TYPE_HSIC);
@@ -149,7 +150,7 @@
* Send data in buf to be written on the
* appropriate device, e.g. USB MDM channel
*/
- driver->write_len_mdm = actual_size;
+ diag_bridge[HSIC].write_len = actual_size;
err = diag_device_write((void *)buf, HSIC_DATA, NULL);
/* If an error, return buffer to the pool */
if (err) {
@@ -170,13 +171,13 @@
}
/*
- * If for some reason there was no hsic data to write to the
+ * If for some reason there was no HSIC data to write to the
* mdm channel, set up another read
*/
if (err &&
((driver->logging_mode == MEMORY_DEVICE_MODE) ||
- (driver->usb_mdm_connected && !driver->hsic_suspend))) {
- queue_work(driver->diag_bridge_wq,
+ (diag_bridge[HSIC].usb_connected && !driver->hsic_suspend))) {
+ queue_work(diag_bridge[HSIC].wq,
&driver->diag_read_hsic_work);
}
}
@@ -195,8 +196,10 @@
if (actual_size < 0)
pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
- if (driver->usb_mdm_connected)
- queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
+ if (diag_bridge[HSIC].usb_connected &&
+ (driver->logging_mode == USB_MODE))
+ queue_work(diag_bridge[HSIC].wq,
+ &diag_bridge[HSIC].diag_read_work);
}
static int diag_hsic_suspend(void *ctxt)
@@ -223,12 +226,12 @@
if ((driver->count_hsic_pool < driver->poolsize_hsic) &&
((driver->logging_mode == MEMORY_DEVICE_MODE) ||
- (driver->usb_mdm_connected)))
- queue_work(driver->diag_bridge_wq,
+ (diag_bridge[HSIC].usb_connected)))
+ queue_work(diag_bridge[HSIC].wq,
&driver->diag_read_hsic_work);
}
-static struct diag_bridge_ops hsic_diag_bridge_ops = {
+struct diag_bridge_ops hsic_diag_bridge_ops = {
.ctxt = NULL,
.read_complete_cb = diag_hsic_read_complete_callback,
.write_complete_cb = diag_hsic_write_complete_callback,
@@ -236,7 +239,7 @@
.resume = diag_hsic_resume,
};
-static void diag_hsic_close(void)
+void diag_hsic_close(void)
{
if (driver->hsic_device_enabled) {
driver->hsic_ch = 0;
@@ -257,7 +260,7 @@
{
int err;
- mutex_lock(&driver->bridge_mutex);
+ mutex_lock(&diag_bridge[HSIC].bridge_mutex);
if (driver->hsic_device_enabled) {
if (driver->hsic_device_opened) {
driver->hsic_ch = 0;
@@ -274,112 +277,7 @@
}
}
}
-
- mutex_unlock(&driver->bridge_mutex);
- return 0;
-}
-
-/* diagfwd_connect_bridge is called when the USB mdm channel is connected */
-int diagfwd_connect_bridge(int process_cable)
-{
- int err;
-
- pr_debug("diag: in %s\n", __func__);
-
- mutex_lock(&driver->bridge_mutex);
- /* If the usb cable is being connected */
- if (process_cable) {
- err = usb_diag_alloc_req(driver->mdm_ch, N_MDM_WRITE,
- N_MDM_READ);
- if (err)
- pr_err("diag: unable to alloc USB req on mdm"
- " ch err:%d\n", err);
-
- driver->usb_mdm_connected = 1;
- }
-
- if (driver->hsic_device_enabled) {
- driver->in_busy_hsic_read_on_device = 0;
- driver->in_busy_hsic_write = 0;
- } else if (driver->diag_smux_enabled) {
- driver->in_busy_smux = 0;
- diagfwd_connect_smux();
- mutex_unlock(&driver->bridge_mutex);
- return 0;
- }
-
- /* If the hsic (diag_bridge) platform device is not open */
- if (driver->hsic_device_enabled) {
- if (!driver->hsic_device_opened) {
- err = diag_bridge_open(&hsic_diag_bridge_ops);
- if (err) {
- pr_err("diag: HSIC channel open error: %d\n",
- err);
- } else {
- pr_debug("diag: opened HSIC channel\n");
- driver->hsic_device_opened = 1;
- }
- } else {
- pr_debug("diag: HSIC channel already open\n");
- }
-
- /*
- * Turn on communication over usb mdm and hsic, if the hsic
- * device driver is enabled and opened
- */
- if (driver->hsic_device_opened) {
- driver->hsic_ch = 1;
-
- /* Poll USB mdm channel to check for data */
- if (driver->logging_mode == USB_MODE)
- queue_work(driver->diag_bridge_wq,
- &driver->diag_read_mdm_work);
-
- /* Poll HSIC channel to check for data */
- queue_work(driver->diag_bridge_wq,
- &driver->diag_read_hsic_work);
- }
- } else {
- /* The hsic device driver has not yet been enabled */
- pr_info("diag: HSIC channel not yet enabled\n");
- }
-
- mutex_unlock(&driver->bridge_mutex);
- return 0;
-}
-
-/*
- * diagfwd_disconnect_bridge is called when the USB mdm channel
- * is disconnected
- */
-int diagfwd_disconnect_bridge(int process_cable)
-{
- pr_debug("diag: In %s, process_cable: %d\n", __func__, process_cable);
-
- mutex_lock(&driver->bridge_mutex);
-
- /* If the usb cable is being disconnected */
- if (process_cable) {
- driver->usb_mdm_connected = 0;
- usb_diag_free_req(driver->mdm_ch);
- }
-
- if (driver->hsic_device_enabled &&
- driver->logging_mode != MEMORY_DEVICE_MODE) {
- driver->in_busy_hsic_read_on_device = 1;
- driver->in_busy_hsic_write = 1;
- /* Turn off communication over usb mdm and hsic */
- diag_hsic_close();
- } else if (driver->diag_smux_enabled &&
- driver->logging_mode == USB_MODE) {
- driver->in_busy_smux = 1;
- driver->lcid = LCID_INVALID;
- driver->smux_connected = 0;
- /* Turn off communication over usb mdm and smux */
- msm_smux_close(LCID_VALID);
- }
-
- mutex_unlock(&driver->bridge_mutex);
+ mutex_unlock(&diag_bridge[HSIC].bridge_mutex);
return 0;
}
@@ -403,225 +301,128 @@
return 0;
}
- /* Read data from the hsic */
- queue_work(driver->diag_bridge_wq, &driver->diag_read_hsic_work);
+ /* Read data from the HSIC */
+ queue_work(diag_bridge[HSIC].wq, &driver->diag_read_hsic_work);
return 0;
}
-/* Called after the asychronous usb_diag_read() on mdm channel is complete */
-static int diagfwd_read_complete_bridge(struct diag_request *diag_read_ptr)
+void diag_usb_read_complete_hsic_fn(struct work_struct *w)
{
- /* The read of the usb driver on the mdm (not hsic) has completed */
- driver->in_busy_hsic_read_on_device = 0;
- driver->read_len_mdm = diag_read_ptr->actual;
+ diagfwd_read_complete_bridge(diag_bridge[HSIC].usb_read_ptr);
+}
- if (driver->diag_smux_enabled) {
- diagfwd_read_complete_smux();
- return 0;
- }
- /* If SMUX not enabled, check for HSIC */
+
+void diag_read_usb_hsic_work_fn(struct work_struct *work)
+{
if (!driver->hsic_ch) {
- pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
- return 0;
- }
-
- /*
- * The read of the usb driver on the mdm channel has completed.
- * If there is no write on the hsic in progress, check if the
- * read has data to pass on to the hsic. If so, pass the usb
- * mdm data on to the hsic.
- */
- if (!driver->in_busy_hsic_write && driver->usb_buf_mdm_out &&
- (driver->read_len_mdm > 0)) {
-
- /*
- * Initiate the hsic write. The hsic write is
- * asynchronous. When complete the write
- * complete callback function will be called
- */
- int err;
- driver->in_busy_hsic_write = 1;
- err = diag_bridge_write(driver->usb_buf_mdm_out,
- driver->read_len_mdm);
- if (err) {
- pr_err_ratelimited("diag: mdm data on hsic write err: %d\n",
- err);
- /*
- * If the error is recoverable, then clear
- * the write flag, so we will resubmit a
- * write on the next frame. Otherwise, don't
- * resubmit a write on the next frame.
- */
- if ((-ENODEV) != err)
- driver->in_busy_hsic_write = 0;
- }
- }
-
- /*
- * If there is no write of the usb mdm data on the
- * hsic channel
- */
- if (!driver->in_busy_hsic_write)
- queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
-
- return 0;
-}
-
-static void diagfwd_bridge_notifier(void *priv, unsigned event,
- struct diag_request *d_req)
-{
- switch (event) {
- case USB_DIAG_CONNECT:
- diagfwd_connect_bridge(1);
- break;
- case USB_DIAG_DISCONNECT:
- queue_work(driver->diag_bridge_wq,
- &driver->diag_disconnect_work);
- break;
- case USB_DIAG_READ_DONE:
- queue_work(driver->diag_bridge_wq,
- &driver->diag_usb_read_complete_work);
- break;
- case USB_DIAG_WRITE_DONE:
- if (driver->hsic_device_enabled)
- diagfwd_write_complete_hsic(d_req);
- else if (driver->diag_smux_enabled)
- diagfwd_write_complete_smux();
- break;
- default:
- pr_err("diag: in %s: Unknown event from USB diag:%u\n",
- __func__, event);
- break;
- }
-}
-
-static void diag_usb_read_complete_fn(struct work_struct *w)
-{
- diagfwd_read_complete_bridge(driver->usb_read_mdm_ptr);
-}
-
-static void diag_disconnect_work_fn(struct work_struct *w)
-{
- diagfwd_disconnect_bridge(1);
-}
-
-static void diag_read_mdm_work_fn(struct work_struct *work)
-{
- int ret;
- if (driver->diag_smux_enabled) {
- if (driver->lcid && driver->usb_buf_mdm_out &&
- (driver->read_len_mdm > 0) &&
- driver->smux_connected) {
- ret = msm_smux_write(driver->lcid, NULL,
- driver->usb_buf_mdm_out, driver->read_len_mdm);
- if (ret)
- pr_err("diag: writing to SMUX ch, r = %d,"
- "lcid = %d\n", ret, driver->lcid);
- }
- driver->usb_read_mdm_ptr->buf = driver->usb_buf_mdm_out;
- driver->usb_read_mdm_ptr->length = USB_MAX_OUT_BUF;
- usb_diag_read(driver->mdm_ch, driver->usb_read_mdm_ptr);
+ pr_err("diag: in %s: driver->hsic_ch == 0\n", __func__);
return;
}
-
- /* if SMUX not enabled, check for HSIC */
- if (!driver->hsic_ch) {
- pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
- return;
- }
-
/*
* If there is no data being read from the usb mdm channel
* and there is no mdm channel data currently being written
- * to the hsic
+ * to the HSIC
*/
if (!driver->in_busy_hsic_read_on_device &&
- !driver->in_busy_hsic_write) {
+ !driver->in_busy_hsic_write) {
APPEND_DEBUG('x');
-
/* Setup the next read from usb mdm channel */
driver->in_busy_hsic_read_on_device = 1;
- driver->usb_read_mdm_ptr->buf = driver->usb_buf_mdm_out;
- driver->usb_read_mdm_ptr->length = USB_MAX_OUT_BUF;
- usb_diag_read(driver->mdm_ch, driver->usb_read_mdm_ptr);
+ diag_bridge[HSIC].usb_read_ptr->buf =
+ diag_bridge[HSIC].usb_buf_out;
+ diag_bridge[HSIC].usb_read_ptr->length = USB_MAX_OUT_BUF;
+ diag_bridge[HSIC].usb_read_ptr->context = (void *)HSIC;
+ usb_diag_read(diag_bridge[HSIC].ch,
+ diag_bridge[HSIC].usb_read_ptr);
APPEND_DEBUG('y');
}
-
- /*
- * If for some reason there was no mdm channel read initiated,
+ /* If for some reason there was no mdm channel read initiated,
* queue up the reading of data from the mdm channel
*/
- if (!driver->in_busy_hsic_read_on_device)
- queue_work(driver->diag_bridge_wq,
- &driver->diag_read_mdm_work);
+
+ if (!driver->in_busy_hsic_read_on_device &&
+ (driver->logging_mode == USB_MODE))
+ queue_work(diag_bridge[HSIC].wq,
+ &(diag_bridge[HSIC].diag_read_work));
}
static int diag_hsic_probe(struct platform_device *pdev)
{
int err = 0;
+
pr_debug("diag: in %s\n", __func__);
+ mutex_lock(&diag_bridge[HSIC].bridge_mutex);
if (!driver->hsic_inited) {
+ spin_lock_init(&driver->hsic_spinlock);
+ driver->num_hsic_buf_tbl_entries = 0;
+ if (driver->hsic_buf_tbl == NULL)
+ driver->hsic_buf_tbl = kzalloc(NUM_HSIC_BUF_TBL_ENTRIES
+ * sizeof(struct diag_write_device), GFP_KERNEL);
+ if (driver->hsic_buf_tbl == NULL) {
+ mutex_unlock(&diag_bridge[HSIC].bridge_mutex);
+ return -ENOMEM;
+ }
+ driver->count_hsic_pool = 0;
+ driver->count_hsic_write_pool = 0;
+ driver->itemsize_hsic = READ_HSIC_BUF_SIZE;
+ driver->poolsize_hsic = N_MDM_WRITE;
+ driver->itemsize_hsic_write = sizeof(struct diag_request);
+ driver->poolsize_hsic_write = N_MDM_WRITE;
diagmem_hsic_init(driver);
INIT_WORK(&(driver->diag_read_hsic_work),
- diag_read_hsic_work_fn);
+ diag_read_hsic_work_fn);
driver->hsic_inited = 1;
}
-
- mutex_lock(&driver->bridge_mutex);
-
/*
* The probe function was called after the usb was connected
* on the legacy channel OR ODL is turned on. Communication over usb
- * mdm and hsic needs to be turned on.
+ * mdm and HSIC needs to be turned on.
*/
- if (driver->usb_mdm_connected || (driver->logging_mode ==
- MEMORY_DEVICE_MODE)) {
+ if (diag_bridge[HSIC].usb_connected || (driver->logging_mode ==
+ MEMORY_DEVICE_MODE)) {
if (driver->hsic_device_opened) {
/* should not happen. close it before re-opening */
pr_warn("diag: HSIC channel already opened in probe\n");
diag_bridge_close();
}
-
err = diag_bridge_open(&hsic_diag_bridge_ops);
if (err) {
pr_err("diag: could not open HSIC, err: %d\n", err);
driver->hsic_device_opened = 0;
- mutex_unlock(&driver->bridge_mutex);
+ mutex_unlock(&diag_bridge[HSIC].bridge_mutex);
return err;
}
pr_info("diag: opened HSIC channel\n");
driver->hsic_device_opened = 1;
driver->hsic_ch = 1;
-
driver->in_busy_hsic_read_on_device = 0;
driver->in_busy_hsic_write = 0;
- if (driver->usb_mdm_connected) {
+ if (diag_bridge[HSIC].usb_connected) {
/* Poll USB mdm channel to check for data */
- queue_work(driver->diag_bridge_wq,
- &driver->diag_read_mdm_work);
+ queue_work(diag_bridge[HSIC].wq,
+ &diag_bridge[HSIC].diag_read_work);
}
-
/* Poll HSIC channel to check for data */
- queue_work(driver->diag_bridge_wq,
- &driver->diag_read_hsic_work);
+ queue_work(diag_bridge[HSIC].wq,
+ &driver->diag_read_hsic_work);
}
-
- /* The hsic (diag_bridge) platform device driver is enabled */
+ /* The HSIC (diag_bridge) platform device driver is enabled */
driver->hsic_device_enabled = 1;
- mutex_unlock(&driver->bridge_mutex);
+ mutex_unlock(&diag_bridge[HSIC].bridge_mutex);
return err;
}
static int diag_hsic_remove(struct platform_device *pdev)
{
pr_debug("diag: %s called\n", __func__);
- mutex_lock(&driver->bridge_mutex);
+ mutex_lock(&diag_bridge[HSIC].bridge_mutex);
diag_hsic_close();
driver->hsic_device_enabled = 0;
- mutex_unlock(&driver->bridge_mutex);
+ mutex_unlock(&diag_bridge[HSIC].bridge_mutex);
+
return 0;
}
@@ -642,7 +443,7 @@
.runtime_resume = diagfwd_hsic_runtime_resume,
};
-static struct platform_driver msm_hsic_ch_driver = {
+struct platform_driver msm_hsic_ch_driver = {
.probe = diag_hsic_probe,
.remove = diag_hsic_remove,
.driver = {
@@ -651,112 +452,3 @@
.pm = &diagfwd_hsic_dev_pm_ops,
},
};
-
-void diagfwd_bridge_init(void)
-{
- int ret;
-
- pr_debug("diag: in %s\n", __func__);
- driver->diag_bridge_wq = create_singlethread_workqueue(
- "diag_bridge_wq");
- driver->read_len_mdm = 0;
- driver->write_len_mdm = 0;
- driver->num_hsic_buf_tbl_entries = 0;
- spin_lock_init(&driver->hsic_spinlock);
- if (driver->usb_buf_mdm_out == NULL)
- driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF,
- GFP_KERNEL);
- if (driver->usb_buf_mdm_out == NULL)
- goto err;
- /* Only used by smux move to smux probe function */
- if (driver->write_ptr_mdm == NULL)
- driver->write_ptr_mdm = kzalloc(
- sizeof(struct diag_request), GFP_KERNEL);
- if (driver->write_ptr_mdm == NULL)
- goto err;
- if (driver->usb_read_mdm_ptr == NULL)
- driver->usb_read_mdm_ptr = kzalloc(
- sizeof(struct diag_request), GFP_KERNEL);
- if (driver->usb_read_mdm_ptr == NULL)
- goto err;
-
- if (driver->hsic_buf_tbl == NULL)
- driver->hsic_buf_tbl = kzalloc(NUM_HSIC_BUF_TBL_ENTRIES *
- sizeof(struct diag_write_device), GFP_KERNEL);
- if (driver->hsic_buf_tbl == NULL)
- goto err;
-
- driver->count_hsic_pool = 0;
- driver->count_hsic_write_pool = 0;
-
- driver->itemsize_hsic = READ_HSIC_BUF_SIZE;
- driver->poolsize_hsic = N_MDM_WRITE;
- driver->itemsize_hsic_write = sizeof(struct diag_request);
- driver->poolsize_hsic_write = N_MDM_WRITE;
-
- mutex_init(&driver->bridge_mutex);
-#ifdef CONFIG_DIAG_OVER_USB
- INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
-#endif
- INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
- INIT_WORK(&(driver->diag_usb_read_complete_work),
- diag_usb_read_complete_fn);
-#ifdef CONFIG_DIAG_OVER_USB
- driver->mdm_ch = usb_diag_open(DIAG_MDM, driver,
- diagfwd_bridge_notifier);
- if (IS_ERR(driver->mdm_ch)) {
- pr_err("diag: Unable to open USB diag MDM channel\n");
- goto err;
- }
-#endif
- /* register HSIC device */
- ret = platform_driver_register(&msm_hsic_ch_driver);
- if (ret)
- pr_err("diag: could not register HSIC device, ret: %d\n", ret);
- /* register SMUX device */
- ret = platform_driver_register(&msm_diagfwd_smux_driver);
- if (ret)
- pr_err("diag: could not register SMUX device, ret: %d\n", ret);
-
- return;
-err:
- pr_err("diag: Could not initialize for bridge forwarding\n");
- kfree(driver->usb_buf_mdm_out);
- kfree(driver->hsic_buf_tbl);
- kfree(driver->write_ptr_mdm);
- kfree(driver->usb_read_mdm_ptr);
- if (driver->diag_bridge_wq)
- destroy_workqueue(driver->diag_bridge_wq);
-
- return;
-}
-
-void diagfwd_bridge_exit(void)
-{
- pr_debug("diag: in %s\n", __func__);
-
- if (driver->hsic_device_enabled) {
- diag_hsic_close();
- driver->hsic_device_enabled = 0;
- }
- driver->hsic_inited = 0;
- diagmem_exit(driver, POOL_TYPE_ALL);
- if (driver->diag_smux_enabled) {
- driver->lcid = LCID_INVALID;
- kfree(driver->buf_in_smux);
- driver->diag_smux_enabled = 0;
- }
- platform_driver_unregister(&msm_hsic_ch_driver);
- platform_driver_unregister(&msm_diagfwd_smux_driver);
- /* destroy USB MDM specific variables */
-#ifdef CONFIG_DIAG_OVER_USB
- if (driver->usb_mdm_connected)
- usb_diag_free_req(driver->mdm_ch);
- usb_diag_close(driver->mdm_ch);
-#endif
- kfree(driver->usb_buf_mdm_out);
- kfree(driver->hsic_buf_tbl);
- kfree(driver->write_ptr_mdm);
- kfree(driver->usb_read_mdm_ptr);
- destroy_workqueue(driver->diag_bridge_wq);
-}
diff --git a/drivers/char/diag/diagfwd_hsic.h b/drivers/char/diag/diagfwd_hsic.h
index 19ed3c7..2190fff 100644
--- a/drivers/char/diag/diagfwd_hsic.h
+++ b/drivers/char/diag/diagfwd_hsic.h
@@ -17,14 +17,14 @@
#define N_MDM_WRITE 8
#define N_MDM_READ 1
-
#define NUM_HSIC_BUF_TBL_ENTRIES N_MDM_WRITE
-int diagfwd_connect_bridge(int);
-int diagfwd_disconnect_bridge(int);
int diagfwd_write_complete_hsic(struct diag_request *);
int diagfwd_cancel_hsic(void);
-void diagfwd_bridge_init(void);
-void diagfwd_bridge_exit(void);
+void diag_read_usb_hsic_work_fn(struct work_struct *work);
+void diag_usb_read_complete_hsic_fn(struct work_struct *w);
+extern struct diag_bridge_ops hsic_diag_bridge_ops;
+extern struct platform_driver msm_hsic_ch_driver;
+void diag_hsic_close(void);
#endif
diff --git a/drivers/char/diag/diagfwd_smux.c b/drivers/char/diag/diagfwd_smux.c
index ae90686..0a97baf 100644
--- a/drivers/char/diag/diagfwd_smux.c
+++ b/drivers/char/diag/diagfwd_smux.c
@@ -18,6 +18,8 @@
#include "diagchar.h"
#include "diagfwd.h"
#include "diagfwd_smux.h"
+#include "diagfwd_hsic.h"
+#include "diagfwd_bridge.h"
void diag_smux_event(void *priv, int event_type, const void *metadata)
{
@@ -30,8 +32,8 @@
driver->smux_connected = 1;
driver->in_busy_smux = 0;
/* read data from USB MDM channel & Initiate first write */
- queue_work(driver->diag_bridge_wq,
- &(driver->diag_read_mdm_work));
+ queue_work(diag_bridge[SMUX].wq,
+ &diag_bridge[SMUX].diag_read_work);
break;
case SMUX_DISCONNECTED:
driver->smux_connected = 0;
@@ -67,7 +69,7 @@
int diagfwd_read_complete_smux(void)
{
- queue_work(driver->diag_bridge_wq, &(driver->diag_read_mdm_work));
+ queue_work(diag_bridge[SMUX].wq, &diag_bridge[SMUX].diag_read_work);
return 0;
}
@@ -85,6 +87,36 @@
return 0;
}
+void diag_usb_read_complete_smux_fn(struct work_struct *w)
+{
+ diagfwd_read_complete_bridge(diag_bridge[SMUX].usb_read_ptr);
+}
+
+void diag_read_usb_smux_work_fn(struct work_struct *work)
+{
+ int ret;
+
+ if (driver->diag_smux_enabled) {
+ if (driver->lcid && diag_bridge[SMUX].usb_buf_out &&
+ (diag_bridge[SMUX].read_len > 0) &&
+ driver->smux_connected) {
+ ret = msm_smux_write(driver->lcid, NULL,
+ diag_bridge[SMUX].usb_buf_out,
+ diag_bridge[SMUX].read_len);
+ if (ret)
+ pr_err("diag: writing to SMUX ch, r = %d, lcid = %d\n",
+ ret, driver->lcid);
+ }
+ diag_bridge[SMUX].usb_read_ptr->buf =
+ diag_bridge[SMUX].usb_buf_out;
+ diag_bridge[SMUX].usb_read_ptr->length = USB_MAX_OUT_BUF;
+ diag_bridge[SMUX].usb_read_ptr->context = (void *)SMUX;
+ usb_diag_read(diag_bridge[SMUX].ch,
+ diag_bridge[SMUX].usb_read_ptr);
+ return;
+ }
+}
+
static int diagfwd_smux_runtime_suspend(struct device *dev)
{
dev_dbg(dev, "pm_runtime: suspending...\n");
@@ -120,7 +152,7 @@
}
}
/* Poll USB channel to check for data*/
- queue_work(driver->diag_bridge_wq, &(driver->diag_read_mdm_work));
+ queue_work(diag_bridge[SMUX].wq, &(diag_bridge[SMUX].diag_read_work));
return ret;
}
@@ -142,6 +174,11 @@
* if (ret)
* pr_err("diag: error setting SMUX ch option, r = %d\n", ret);
*/
+ if (driver->write_ptr_mdm == NULL)
+ driver->write_ptr_mdm = kzalloc(sizeof(struct diag_request),
+ GFP_KERNEL);
+ if (driver->write_ptr_mdm == NULL)
+ goto err;
ret = diagfwd_connect_smux();
return ret;
diff --git a/drivers/char/diag/diagfwd_smux.h b/drivers/char/diag/diagfwd_smux.h
index e78b7ed..b45fd5d 100644
--- a/drivers/char/diag/diagfwd_smux.h
+++ b/drivers/char/diag/diagfwd_smux.h
@@ -20,6 +20,8 @@
int diagfwd_read_complete_smux(void);
int diagfwd_write_complete_smux(void);
int diagfwd_connect_smux(void);
+void diag_usb_read_complete_smux_fn(struct work_struct *w);
+void diag_read_usb_smux_work_fn(struct work_struct *work);
extern struct platform_driver msm_diagfwd_smux_driver;
#endif
diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c
index 1a522d5..ab1aa75 100644
--- a/drivers/char/diag/diagmem.c
+++ b/drivers/char/diag/diagmem.c
@@ -51,7 +51,7 @@
driver->diag_write_struct_pool, GFP_ATOMIC);
}
}
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
} else if (pool_type == POOL_TYPE_HSIC) {
if (driver->diag_hsic_pool) {
if (driver->count_hsic_pool < driver->poolsize_hsic) {
@@ -105,7 +105,7 @@
} else if (driver->ref_count == 0 && pool_type == POOL_TYPE_ALL)
printk(KERN_ALERT "Unable to destroy STRUCT mempool");
}
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
if (driver->diag_hsic_pool && (driver->hsic_inited == 0)) {
if (driver->count_hsic_pool == 0) {
mempool_destroy(driver->diag_hdlc_pool);
@@ -156,7 +156,7 @@
pr_err("diag: Attempt to free up DIAG driver "
"USB structure mempool which is already free %d ",
driver->count_write_struct_pool);
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
} else if (pool_type == POOL_TYPE_HSIC) {
if (driver->diag_hsic_pool != NULL &&
driver->count_hsic_pool > 0) {
@@ -210,7 +210,7 @@
printk(KERN_INFO "Cannot allocate diag USB struct mempool\n");
}
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
void diagmem_hsic_init(struct diagchar_dev *driver)
{
if (driver->count_hsic_pool == 0)
diff --git a/drivers/char/diag/diagmem.h b/drivers/char/diag/diagmem.h
index 8665c75..36def72 100644
--- a/drivers/char/diag/diagmem.h
+++ b/drivers/char/diag/diagmem.h
@@ -18,7 +18,7 @@
void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type);
void diagmem_init(struct diagchar_dev *driver);
void diagmem_exit(struct diagchar_dev *driver, int pool_type);
-#ifdef CONFIG_DIAG_BRIDGE_CODE
+#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
void diagmem_hsic_init(struct diagchar_dev *driver);
#endif
#endif
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 5243689..017b756 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -2,7 +2,7 @@
* drivers/gpu/ion/ion_cp_heap.c
*
* Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, 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
@@ -309,6 +309,7 @@
{
unsigned long offset;
unsigned long secure_allocation = flags & ION_SECURE;
+ unsigned long force_contig = flags & ION_FORCE_CONTIGUOUS;
struct ion_cp_heap *cp_heap =
container_of(heap, struct ion_cp_heap, heap);
@@ -321,7 +322,8 @@
return ION_CP_ALLOCATE_FAIL;
}
- if (!secure_allocation && cp_heap->disallow_non_secure_allocation) {
+ if (!force_contig && !secure_allocation &&
+ cp_heap->disallow_non_secure_allocation) {
mutex_unlock(&cp_heap->lock);
pr_debug("%s: non-secure allocation disallowed from this heap\n",
__func__);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 8ebca50..8b43024 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -475,7 +475,7 @@
device->state == KGSL_STATE_ACTIVE &&
device->requested_state == KGSL_STATE_NONE) {
kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
- kgsl_pwrscale_idle(device, 1);
+ kgsl_pwrscale_idle(device);
if (kgsl_pwrctrl_sleep(device) != 0)
mod_timer(&device->idle_timer,
jiffies +
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 54eae2b..1eb12a0 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1008,7 +1008,7 @@
mutex_lock(&device->mutex);
if (device->state & (KGSL_STATE_ACTIVE | KGSL_STATE_NAP)) {
- kgsl_pwrscale_idle(device, 0);
+ kgsl_pwrscale_idle(device);
if (kgsl_pwrctrl_sleep(device) != 0) {
mod_timer(&device->idle_timer,
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index aad1a8d..d46f552 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -242,13 +242,13 @@
&device->pwrscale);
}
-void kgsl_pwrscale_idle(struct kgsl_device *device, unsigned int ignore_idle)
+void kgsl_pwrscale_idle(struct kgsl_device *device)
{
if (PWRSCALE_ACTIVE(device) && device->pwrscale.policy->idle)
if (device->requested_state != KGSL_STATE_SLUMBER &&
device->requested_state != KGSL_STATE_SLEEP)
device->pwrscale.policy->idle(device,
- &device->pwrscale, ignore_idle);
+ &device->pwrscale);
}
EXPORT_SYMBOL(kgsl_pwrscale_idle);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index ba9b1af..85d5b82 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.h
@@ -23,8 +23,7 @@
void (*close)(struct kgsl_device *device,
struct kgsl_pwrscale *pwrscale);
void (*idle)(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale,
- unsigned int ignore_idle);
+ struct kgsl_pwrscale *pwrscale);
void (*busy)(struct kgsl_device *device,
struct kgsl_pwrscale *pwrscale);
void (*sleep)(struct kgsl_device *device,
@@ -64,8 +63,7 @@
struct kgsl_pwrscale_policy *policy);
void kgsl_pwrscale_detach_policy(struct kgsl_device *device);
-void kgsl_pwrscale_idle(struct kgsl_device *device,
- unsigned int ignore_idle);
+void kgsl_pwrscale_idle(struct kgsl_device *device);
void kgsl_pwrscale_busy(struct kgsl_device *device);
void kgsl_pwrscale_sleep(struct kgsl_device *device);
void kgsl_pwrscale_wake(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
index fc58dd1..cd432c6 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
@@ -131,7 +131,7 @@
}
static void idlestats_idle(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale, unsigned int ignore_idle)
+ struct kgsl_pwrscale *pwrscale)
{
int i, nr_cpu;
struct idlestats_priv *priv = pwrscale->priv;
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
index c680d57..073e474 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_msm.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c
@@ -132,7 +132,7 @@
}
static void msm_idle(struct kgsl_device *device,
- struct kgsl_pwrscale *pwrscale, unsigned int ignore_idle)
+ struct kgsl_pwrscale *pwrscale)
{
struct msm_priv *priv = pwrscale->priv;
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index e01932b..3e81e56 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -30,9 +30,14 @@
int governor;
unsigned int no_switch_cnt;
unsigned int skip_cnt;
+ struct kgsl_power_stats bin;
};
spinlock_t tz_lock;
+/* FLOOR is 5msec to capture up to 3 re-draws
+ * per frame for 60fps content.
+ */
+#define FLOOR 5000
#define SWITCH_OFF 200
#define SWITCH_OFF_RESET_TH 40
#define SKIP_COUNTER 500
@@ -119,24 +124,27 @@
device->pwrctrl.default_pwrlevel);
}
-static void tz_idle(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale,
- unsigned int ignore_idle)
+static void tz_idle(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct tz_priv *priv = pwrscale->priv;
struct kgsl_power_stats stats;
int val, idle;
- if (ignore_idle)
- return;
-
/* In "performance" mode the clock speed always stays
the same */
if (priv->governor == TZ_GOVERNOR_PERFORMANCE)
return;
device->ftbl->power_stats(device, &stats);
- if (stats.total_time == 0)
+ priv->bin.total_time += stats.total_time;
+ priv->bin.busy_time += stats.busy_time;
+ /* Do not waste CPU cycles running this algorithm if
+ * the GPU just started, or if less than FLOOR time
+ * has passed since the last run.
+ */
+ if ((stats.total_time == 0) ||
+ (priv->bin.total_time < FLOOR))
return;
/* If the GPU has stayed in turbo mode for a while, *
@@ -155,7 +163,9 @@
priv->no_switch_cnt = 0;
}
- idle = stats.total_time - stats.busy_time;
+ idle = priv->bin.total_time - priv->bin.busy_time;
+ priv->bin.total_time = 0;
+ priv->bin.busy_time = 0;
idle = (idle > 0) ? idle : 0;
val = __secure_tz_entry(TZ_UPDATE_ID, idle, device->id);
if (val)
@@ -176,6 +186,8 @@
__secure_tz_entry(TZ_RESET_ID, 0, device->id);
priv->no_switch_cnt = 0;
+ priv->bin.total_time = 0;
+ priv->bin.busy_time = 0;
}
#ifdef CONFIG_MSM_SCM
diff --git a/drivers/input/misc/lis3dh_acc.c b/drivers/input/misc/lis3dh_acc.c
index cc4ee9f..ea1b079 100644
--- a/drivers/input/misc/lis3dh_acc.c
+++ b/drivers/input/misc/lis3dh_acc.c
@@ -274,6 +274,7 @@
rc = PTR_ERR(lis3dh_acc_vreg[i].vreg);
pr_err("%s:regulator get failed rc=%d\n",
__func__, rc);
+ lis3dh_acc_vreg[i].vreg = NULL;
goto error_vdd;
}
@@ -287,6 +288,7 @@
pr_err("%s: set voltage failed rc=%d\n",
__func__, rc);
regulator_put(lis3dh_acc_vreg[i].vreg);
+ lis3dh_acc_vreg[i].vreg = NULL;
goto error_vdd;
}
}
@@ -302,6 +304,7 @@
lis3dh_acc_vreg[i].max_uV);
}
regulator_put(lis3dh_acc_vreg[i].vreg);
+ lis3dh_acc_vreg[i].vreg = NULL;
goto error_vdd;
}
}
@@ -312,12 +315,16 @@
error_vdd:
while (--i >= 0) {
- if (regulator_count_voltages(lis3dh_acc_vreg[i].vreg) > 0) {
- regulator_set_voltage(lis3dh_acc_vreg[i].vreg, 0,
- lis3dh_acc_vreg[i].max_uV);
+ if (!IS_ERR_OR_NULL(lis3dh_acc_vreg[i].vreg)) {
+ if (regulator_count_voltages(
+ lis3dh_acc_vreg[i].vreg) > 0) {
+ regulator_set_voltage(lis3dh_acc_vreg[i].vreg,
+ 0, lis3dh_acc_vreg[i].max_uV);
+ }
+ regulator_disable(lis3dh_acc_vreg[i].vreg);
+ regulator_put(lis3dh_acc_vreg[i].vreg);
+ lis3dh_acc_vreg[i].vreg = NULL;
}
- regulator_disable(lis3dh_acc_vreg[i].vreg);
- regulator_put(lis3dh_acc_vreg[i].vreg);
}
return rc;
}
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index db6f93c..6c64a57 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -184,6 +184,7 @@
rc = PTR_ERR(mpu_vreg[i].vreg);
pr_err("%s:regulator get failed rc=%d\n",
__func__, rc);
+ mpu_vreg[i].vreg = NULL;
goto error_vdd;
}
@@ -194,6 +195,7 @@
pr_err("%s:set_voltage failed rc=%d\n",
__func__, rc);
regulator_put(mpu_vreg[i].vreg);
+ mpu_vreg[i].vreg = NULL;
goto error_vdd;
}
}
@@ -210,6 +212,7 @@
0, mpu_vreg[i].max_uV);
}
regulator_put(mpu_vreg[i].vreg);
+ mpu_vreg[i].vreg = NULL;
goto error_vdd;
}
}
@@ -219,12 +222,16 @@
}
error_vdd:
while (--i >= 0) {
- if (regulator_count_voltages(mpu_vreg[i].vreg) > 0) {
- regulator_set_voltage(mpu_vreg[i].vreg, 0,
+ if (!IS_ERR_OR_NULL(mpu_vreg[i].vreg)) {
+ if (regulator_count_voltages(
+ mpu_vreg[i].vreg) > 0) {
+ regulator_set_voltage(mpu_vreg[i].vreg, 0,
mpu_vreg[i].max_uV);
+ }
+ regulator_disable(mpu_vreg[i].vreg);
+ regulator_put(mpu_vreg[i].vreg);
+ mpu_vreg[i].vreg = NULL;
}
- regulator_disable(mpu_vreg[i].vreg);
- regulator_put(mpu_vreg[i].vreg);
}
return rc;
}
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index 7155d4c..73e9ea2 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -107,6 +107,9 @@
if (p_mctl->pp_info.pp_ctrl.pp_msg_type & OUTPUT_TYPE_R)
*pp_type = OUTPUT_TYPE_R;
break;
+ case MSM_V4L2_EXT_CAPTURE_MODE_RDI2:
+ *pp_divert_type = OUTPUT_TYPE_R2;
+ break;
default:
break;
}
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index ddadf0b..dcefaac 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -49,6 +49,9 @@
uint16_t cur_line = 0;
uint16_t exp_fl_lines = 0;
uint8_t int_time[3];
+ uint32_t fll = (s_ctrl->msm_sensor_reg->
+ output_settings[s_ctrl->curr_res].frame_length_lines *
+ s_ctrl->fps_divider) / Q10;
if (s_ctrl->sensor_exp_gain_info) {
msm_camera_i2c_read_seq(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_exp_gain_info->coarse_int_time_addr-1,
@@ -58,8 +61,7 @@
cur_line |= int_time[2] >> 4;
exp_fl_lines = cur_line +
s_ctrl->sensor_exp_gain_info->vert_offset;
- if (exp_fl_lines > s_ctrl->msm_sensor_reg->
- output_settings[s_ctrl->curr_res].frame_length_lines)
+ if (exp_fl_lines > fll)
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_output_reg_addr->
frame_length_lines,
@@ -132,6 +134,9 @@
uint16_t res)
{
int32_t rc = -EFAULT;
+ uint32_t fll = (s_ctrl->msm_sensor_reg->
+ output_settings[res].frame_length_lines *
+ s_ctrl->fps_divider) / Q10;
struct msm_camera_i2c_reg_conf dim_settings[] = {
{s_ctrl->sensor_output_reg_addr->x_output,
s_ctrl->msm_sensor_reg->
@@ -143,8 +148,7 @@
s_ctrl->msm_sensor_reg->
output_settings[res].line_length_pclk},
{s_ctrl->sensor_output_reg_addr->frame_length_lines,
- s_ctrl->msm_sensor_reg->
- output_settings[res].frame_length_lines},
+ fll},
};
rc = msm_camera_i2c_write_tbl(s_ctrl->sensor_i2c_client, dim_settings,
@@ -157,7 +161,8 @@
if (s_ctrl->curr_res >= s_ctrl->msm_sensor_reg->num_conf)
return;
- if (s_ctrl->func_tbl->sensor_adjust_frame_lines)
+ if (s_ctrl->func_tbl->sensor_adjust_frame_lines &&
+ s_ctrl->vision_mode_flag == 0)
s_ctrl->func_tbl->sensor_adjust_frame_lines(s_ctrl);
msm_camera_i2c_write_tbl(
@@ -439,6 +444,9 @@
break;
case CFG_SET_EXP_GAIN:
+ if(s_ctrl->vision_mode_flag) {
+ break;
+ }
if (s_ctrl->func_tbl->
sensor_write_exp_gain == NULL) {
rc = -EFAULT;
@@ -453,6 +461,9 @@
break;
case CFG_SET_PICT_EXP_GAIN:
+ if(s_ctrl->vision_mode_flag) {
+ break;
+ }
if (s_ctrl->func_tbl->
sensor_write_snapshot_exp_gain == NULL) {
rc = -EFAULT;
@@ -558,7 +569,21 @@
else
rc = -EFAULT;
break;
-
+ case CFG_SET_VISION_MODE:
+ if (s_ctrl->func_tbl->sensor_set_vision_mode)
+ rc = s_ctrl->func_tbl->sensor_set_vision_mode(
+ s_ctrl, cdata.cfg.vision_mode_enable);
+ else
+ rc = -EFAULT;
+ break;
+ case CFG_SET_VISION_AE:
+ if (s_ctrl->func_tbl->sensor_set_vision_ae_control)
+ rc = s_ctrl->func_tbl->
+ sensor_set_vision_ae_control(
+ s_ctrl, cdata.cfg.vision_ae);
+ else
+ rc = -EFAULT;
+ break;
default:
rc = -EFAULT;
break;
diff --git a/drivers/media/video/msm/sensors/msm_sensor_common.h b/drivers/media/video/msm/sensors/msm_sensor_common.h
index 79fe52e..e2ae18e 100644
--- a/drivers/media/video/msm/sensors/msm_sensor_common.h
+++ b/drivers/media/video/msm/sensors/msm_sensor_common.h
@@ -156,6 +156,10 @@
void (*sensor_adjust_frame_lines) (struct msm_sensor_ctrl_t *s_ctrl);
int32_t (*sensor_get_csi_params)(struct msm_sensor_ctrl_t *,
struct csi_lane_params_t *);
+ int (*sensor_set_vision_mode)(struct msm_sensor_ctrl_t *s_ctrl,
+ int32_t vision_mode_enable);
+ int (*sensor_set_vision_ae_control)(
+ struct msm_sensor_ctrl_t *s_ctrl, int ae_mode);
};
struct msm_sensor_csi_info {
@@ -192,6 +196,7 @@
struct msm_sensor_v4l2_ctrl_info_t *msm_sensor_v4l2_ctrl_info;
uint16_t num_v4l2_ctrl;
uint8_t is_csic;
+ int8_t vision_mode_flag;
uint16_t curr_line_length_pclk;
uint16_t curr_frame_length_lines;
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index bc38f62..d21e1fe 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -846,6 +846,7 @@
.sensor_v4l2_subdev_ops = &ov2720_subdev_ops,
.func_tbl = &ov2720_func_tbl,
.clk_rate = MSM_SENSOR_MCLK_24HZ,
+ .fps_divider = Q10,
};
module_init(msm_sensor_init_module);
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 05070a3..afc3b63 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -474,16 +474,15 @@
kfree(ctrlcmd);
free_qcmd(rcmd);
D("%s: rc %d\n", __func__, rc);
- /* rc is the time elapsed. */
- if (rc >= 0) {
- /* TODO: Refactor msm_ctrl_cmd::status field */
- if (out->status == 0)
- rc = -1;
- else if (out->status == 1 || out->status == 4)
- rc = 0;
- else
- rc = -EINVAL;
- }
+ /* rc is the time elapsed.
+ * This means that the communication with the daemon itself was
+ * successful(irrespective of the handling of the ctrlcmd).
+ * So, just reset the rc to 0 to indicate success.
+ * Its upto the caller to parse the ctrlcmd to check the status. We
+ * dont need to parse it here. */
+ if (rc >= 0)
+ rc = 0;
+
return rc;
ctrlcmd_alloc_fail:
@@ -846,9 +845,9 @@
rc = -EINVAL;
goto end;
}
-
+ tmp_cmd.status = cmd_ptr->status = ctrlcmd.status;
if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
- (void *)&tmp_cmd, cmd_len)) {
+ (void *)cmd_ptr, cmd_len)) {
pr_err("%s: copy_to_user failed in cpy, size=%d\n",
__func__, cmd_len);
rc = -EINVAL;
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c
old mode 100755
new mode 100644
index 94463fa..50ad80e
--- a/drivers/media/video/msm/vfe/msm_vfe32.c
+++ b/drivers/media/video/msm/vfe/msm_vfe32.c
@@ -5913,6 +5913,8 @@
axi_ctrl->share_ctrl->lp_mode = lp_mode;
if (lp_mode)
axi_ctrl->share_ctrl->dual_enabled = 0;
+ else
+ axi_ctrl->share_ctrl->dual_enabled = 1;
return rc;
}
diff --git a/drivers/media/video/msm_wfd/enc-mfc-subdev.c b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
index 21fc719..78678eb 100644
--- a/drivers/media/video/msm_wfd/enc-mfc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Linux Foundation. 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
@@ -2431,7 +2431,7 @@
long venc_mmap(struct v4l2_subdev *sd, void *arg)
{
- struct venc_inst *inst = sd->dev_priv;
+ struct venc_inst *inst = NULL;
struct mem_region_map *mmap = arg;
struct mem_region *mregion = NULL;
unsigned long rc = 0, size = 0;
@@ -2445,6 +2445,7 @@
return -EINVAL;
}
+ inst = sd->dev_priv;
mregion = mmap->mregion;
if (mregion->size % SZ_4K != 0) {
WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
@@ -2476,17 +2477,18 @@
long venc_munmap(struct v4l2_subdev *sd, void *arg)
{
- struct venc_inst *inst = sd->dev_priv;
+ struct venc_inst *inst = NULL;
struct mem_region_map *mmap = arg;
struct mem_region *mregion = NULL;
if (!sd) {
WFD_MSG_ERR("Subdevice required for %s\n", __func__);
return -EINVAL;
- } else if (!mregion) {
+ } else if (!mmap || !mmap->mregion) {
WFD_MSG_ERR("Memregion required for %s\n", __func__);
return -EINVAL;
}
+ inst = sd->dev_priv;
mregion = mmap->mregion;
if (!inst->secure) {
ion_unmap_iommu(mmap->ion_client, mregion->ion_handle,
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index b8f51495..cb58f8c 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -142,7 +142,6 @@
static DEFINE_MUTEX(pil_access_lock);
static DEFINE_MUTEX(qsee_bw_mutex);
-static DEFINE_MUTEX(qsee_sfpb_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
static int qsee_bw_count;
@@ -1196,28 +1195,41 @@
case CLK_DFAB:
mutex_lock(&qsee_bw_mutex);
if (!qsee_bw_count) {
- ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 1);
+ if (qsee_sfpb_bw_count > 0)
+ ret = msm_bus_scale_client_update_request(
+ qsee_perf_client, 3);
+ else
+ ret = msm_bus_scale_client_update_request(
+ qsee_perf_client, 1);
if (ret)
pr_err("DFAB Bandwidth req failed (%d)\n",
ret);
else
qsee_bw_count++;
+ } else {
+ qsee_bw_count++;
}
mutex_unlock(&qsee_bw_mutex);
break;
case CLK_SFPB:
- mutex_lock(&qsee_sfpb_bw_mutex);
+ mutex_lock(&qsee_bw_mutex);
if (!qsee_sfpb_bw_count) {
- ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 2);
+ if (qsee_bw_count > 0)
+ ret = msm_bus_scale_client_update_request(
+ qsee_perf_client, 3);
+ else
+ ret = msm_bus_scale_client_update_request(
+ qsee_perf_client, 2);
+
if (ret)
pr_err("SFPB Bandwidth req failed (%d)\n",
ret);
else
qsee_sfpb_bw_count++;
+ } else {
+ qsee_sfpb_bw_count++;
}
- mutex_unlock(&qsee_sfpb_bw_mutex);
+ mutex_unlock(&qsee_bw_mutex);
break;
default:
pr_err("Clock type not defined\n");
@@ -1236,29 +1248,44 @@
switch (clk_type) {
case CLK_DFAB:
mutex_lock(&qsee_bw_mutex);
- if (qsee_bw_count > 0) {
- if (qsee_bw_count-- == 1) {
+ if (qsee_bw_count == 0) {
+ pr_err("Client error.Extra call to disable DFAB clk\n");
+ mutex_unlock(&qsee_bw_mutex);
+ return;
+ }
+
+ if ((qsee_bw_count > 0) && (qsee_bw_count-- == 1)) {
+ if (qsee_sfpb_bw_count > 0)
+ ret = msm_bus_scale_client_update_request(
+ qsee_perf_client, 2);
+ else
ret = msm_bus_scale_client_update_request(
qsee_perf_client, 0);
- if (ret)
- pr_err("SFPB Bandwidth req fail (%d)\n",
+ if (ret)
+ pr_err("SFPB Bandwidth req fail (%d)\n",
ret);
- }
}
mutex_unlock(&qsee_bw_mutex);
break;
case CLK_SFPB:
- mutex_lock(&qsee_sfpb_bw_mutex);
- if (qsee_sfpb_bw_count > 0) {
- if (qsee_sfpb_bw_count-- == 1) {
+ mutex_lock(&qsee_bw_mutex);
+ if (qsee_sfpb_bw_count == 0) {
+ pr_err("Client error.Extra call to disable SFPB clk\n");
+ mutex_unlock(&qsee_bw_mutex);
+ return;
+ }
+ if ((qsee_sfpb_bw_count > 0) && (qsee_sfpb_bw_count-- == 1)) {
+ if (qsee_bw_count > 0)
+ ret = msm_bus_scale_client_update_request(
+ qsee_perf_client, 1);
+ else
ret = msm_bus_scale_client_update_request(
qsee_perf_client, 0);
- if (ret)
- pr_err("SFPB Bandwidth req fail (%d)\n",
+ if (ret)
+ pr_err("SFPB Bandwidth req fail (%d)\n",
ret);
- }
}
- mutex_unlock(&qsee_sfpb_bw_mutex);
+ mutex_unlock(&qsee_bw_mutex);
break;
default:
pr_err("Clock type not defined\n");
@@ -1580,12 +1607,16 @@
ret = qsee_vote_for_clock(CLK_DFAB);
if (ret)
pr_err("Failed to vote for DFAB clock%d\n", ret);
+ ret = qsee_vote_for_clock(CLK_SFPB);
+ if (ret)
+ pr_err("Failed to vote for SFPB clock%d\n", ret);
atomic_dec(&data->ioctl_count);
break;
}
case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
atomic_inc(&data->ioctl_count);
qsee_disable_clock_vote(CLK_DFAB);
+ qsee_disable_clock_vote(CLK_SFPB);
atomic_dec(&data->ioctl_count);
break;
}
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 295c55c..83f486c 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. 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
@@ -746,6 +746,112 @@
return 0;
}
+/* support for 9 new rmnet ports */
+#define RMNET_REV_DEVICE_COUNT (9)
+static struct net_device *netdevs_rev[RMNET_REV_DEVICE_COUNT];
+static struct platform_driver bam_rmnet_rev_drivers[RMNET_REV_DEVICE_COUNT];
+
+static int bam_rmnet_rev_probe(struct platform_device *pdev)
+{
+ int i;
+ char name[BAM_DMUX_CH_NAME_MAX_LEN];
+ struct rmnet_private *p;
+
+ for (i = 0; i < RMNET_REV_DEVICE_COUNT; ++i) {
+ scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+ (i+BAM_DMUX_DATA_REV_RMNET_0));
+ if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
+ break;
+ }
+
+ if (i >= RMNET_REV_DEVICE_COUNT) {
+ pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
+ return 0;
+ }
+
+ p = netdev_priv(netdevs_rev[i]);
+ if (p->in_reset) {
+ p->in_reset = 0;
+ msm_bam_dmux_open(p->ch_id, netdevs_rev[i], bam_notify);
+ netif_carrier_on(netdevs_rev[i]);
+ netif_start_queue(netdevs_rev[i]);
+ }
+
+ return 0;
+}
+
+static int bam_rmnet_rev_remove(struct platform_device *pdev)
+{
+ int i;
+ char name[BAM_DMUX_CH_NAME_MAX_LEN];
+ struct rmnet_private *p;
+
+ for (i = 0; i < RMNET_REV_DEVICE_COUNT; ++i) {
+ scnprintf(name, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+ (i+BAM_DMUX_DATA_REV_RMNET_0));
+ if (!strncmp(pdev->name, name, BAM_DMUX_CH_NAME_MAX_LEN))
+ break;
+ }
+
+ if (i >= RMNET_REV_DEVICE_COUNT) {
+ pr_err("%s: wrong netdev %s\n", __func__, pdev->name);
+ return 0;
+ }
+
+ p = netdev_priv(netdevs_rev[i]);
+ p->in_reset = 1;
+ if (p->waiting_for_ul_skb != NULL) {
+ dev_kfree_skb_any(p->waiting_for_ul_skb);
+ p->waiting_for_ul_skb = NULL;
+ }
+ msm_bam_dmux_close(p->ch_id);
+ netif_carrier_off(netdevs_rev[i]);
+ netif_stop_queue(netdevs_rev[i]);
+ return 0;
+}
+
+#ifdef CONFIG_MSM_RMNET_DEBUG
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static int rmnet_debug_init_timeout_suspend(struct net_device *dev)
+{
+ struct device *d;
+ d = &(dev->dev);
+ return device_create_file(d, &dev_attr_timeout_suspend);
+}
+#else
+static int rmnet_debug_init_timeout_suspend(struct net_device *dev)
+{
+ return 0;
+}
+#endif
+static int rmnet_debug_init(struct net_device *dev)
+{
+
+ struct device *d;
+ struct rmnet_private *p;
+ int err = 0;
+ d = &(dev->dev);
+ p = netdev_priv(dev);
+ p->timeout_us = 0;
+ p->wakeups_xmit = p->wakeups_rcv = 0;
+ err = device_create_file(d, &dev_attr_timeout);
+ if (err)
+ return err;
+ err = device_create_file(d, &dev_attr_wakeups_xmit);
+ if (err)
+ return err;
+ err = device_create_file(d, &dev_attr_wakeups_rcv);
+ if (err)
+ return err;
+ err = rmnet_debug_init_timeout_suspend(dev);
+ return err;
+}
+#else
+static int rmnet_debug_init(struct net_device *dev)
+{
+ return 0;
+}
+#endif
static int __init rmnet_init(void)
{
int ret;
@@ -828,6 +934,53 @@
return ret;
}
}
+ /*Support for new rmnet ports */
+ for (n = 0; n < RMNET_REV_DEVICE_COUNT; n++) {
+ dev = alloc_netdev(sizeof(struct rmnet_private),
+ "rev_rmnet%d", rmnet_setup);
+
+ if (!dev) {
+ pr_err("%s: no memory for rev netdev %d\n",
+ __func__, n);
+ return -ENOMEM;
+ }
+
+ netdevs_rev[n] = dev;
+ d = &(dev->dev);
+ p = netdev_priv(dev);
+ /* Initial config uses Ethernet */
+ p->operation_mode = RMNET_MODE_LLP_ETH;
+ p->ch_id = n+BAM_DMUX_DATA_REV_RMNET_0;
+ p->waiting_for_ul_skb = NULL;
+ p->in_reset = 0;
+ spin_lock_init(&p->lock);
+ spin_lock_init(&p->tx_queue_lock);
+
+ ret = register_netdev(dev);
+ if (ret) {
+ pr_err("%s: unable to register rev netdev %d rc=%d\n",
+ __func__, n, ret);
+ free_netdev(dev);
+ return ret;
+ }
+ if (rmnet_debug_init(dev))
+ continue;
+ bam_rmnet_rev_drivers[n].probe = bam_rmnet_rev_probe;
+ bam_rmnet_rev_drivers[n].remove = bam_rmnet_rev_remove;
+ tempname = kmalloc(BAM_DMUX_CH_NAME_MAX_LEN, GFP_KERNEL);
+ if (tempname == NULL)
+ return -ENOMEM;
+ scnprintf(tempname, BAM_DMUX_CH_NAME_MAX_LEN, "bam_dmux_ch_%d",
+ (n+BAM_DMUX_DATA_REV_RMNET_0));
+ bam_rmnet_rev_drivers[n].driver.name = tempname;
+ bam_rmnet_rev_drivers[n].driver.owner = THIS_MODULE;
+ ret = platform_driver_register(&bam_rmnet_rev_drivers[n]);
+ if (ret) {
+ pr_err("%s: new rev driver registration failed n=%d rc=%d\n",
+ __func__, n, ret);
+ return ret;
+ }
+ }
return 0;
}
diff --git a/drivers/net/ethernet/msm/msm_rmnet_smux.c b/drivers/net/ethernet/msm/msm_rmnet_smux.c
index bf06406..e56a64e 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_smux.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_smux.c
@@ -620,7 +620,7 @@
spin_lock_irqsave(&p->tx_queue_lock, flags);
ret = _rmnet_xmit(skb, dev);
- if (msm_smux_is_ch_full(p->ch_id) || (ret == -EAGAIN)) {
+ if (ret == -EAGAIN) {
/*
* EAGAIN means we attempted to overflow the high watermark
* Clearly the queue is not stopped like it should be, so
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index 9ebb54a..71f6a99 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -6,7 +6,7 @@
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_N_GSM) += n_gsm.o
-obj-$(CONFIG_N_SMUX) += n_smux.o
+obj-$(CONFIG_N_SMUX) += n_smux.o smux_debug.o
obj-$(CONFIG_N_SMUX_LOOPBACK) += smux_test.o smux_loopback.o
obj-$(CONFIG_SMUX_CTL) += smux_ctl.o
obj-$(CONFIG_TRACE_ROUTER) += n_tracerouter.o
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 706ea04..14b8ca2 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -28,6 +28,7 @@
#include <mach/subsystem_notif.h>
#include <mach/subsystem_restart.h>
#include <mach/msm_serial_hs.h>
+#include <mach/msm_ipc_logging.h>
#include "smux_private.h"
#include "smux_loopback.h"
@@ -59,10 +60,12 @@
MSM_SMUX_PKT = 1U << 3,
};
-static int smux_debug_mask;
+static int smux_debug_mask = MSM_SMUX_DEBUG | MSM_SMUX_POWER_INFO;
module_param_named(debug_mask, smux_debug_mask,
int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int disable_ipc_logging;
+
/* Simulated wakeup used for testing */
int smux_byte_loopback;
module_param_named(byte_loopback, smux_byte_loopback,
@@ -71,14 +74,24 @@
module_param_named(simulate_wakeup_delay, smux_simulate_wakeup_delay,
int, S_IRUGO | S_IWUSR | S_IWGRP);
+#define IPC_LOG_STR(x...) do { \
+ if (!disable_ipc_logging && log_ctx) \
+ ipc_log_string(log_ctx, x); \
+} while (0)
+
#define SMUX_DBG(x...) do { \
if (smux_debug_mask & MSM_SMUX_DEBUG) \
- pr_info(x); \
+ IPC_LOG_STR(x); \
+} while (0)
+
+#define SMUX_ERR(x...) do { \
+ pr_err(x); \
+ IPC_LOG_STR(x); \
} while (0)
#define SMUX_PWR(x...) do { \
if (smux_debug_mask & MSM_SMUX_POWER_INFO) \
- pr_info(x); \
+ IPC_LOG_STR(x); \
} while (0)
#define SMUX_PWR_PKT_RX(pkt) do { \
@@ -90,10 +103,10 @@
if (smux_debug_mask & MSM_SMUX_POWER_INFO) { \
if (pkt->hdr.cmd == SMUX_CMD_BYTE && \
pkt->hdr.flags == SMUX_WAKEUP_ACK) \
- pr_info("smux: TX Wakeup ACK\n"); \
+ IPC_LOG_STR("smux: TX Wakeup ACK\n"); \
else if (pkt->hdr.cmd == SMUX_CMD_BYTE && \
pkt->hdr.flags == SMUX_WAKEUP_REQ) \
- pr_info("smux: TX Wakeup REQ\n"); \
+ IPC_LOG_STR("smux: TX Wakeup REQ\n"); \
else \
smux_log_pkt(pkt, 0); \
} \
@@ -170,59 +183,6 @@
SMUX_PWR_OFF_FLUSH,
};
-/**
- * Logical Channel Structure. One instance per channel.
- *
- * Locking Hierarchy
- * Each lock has a postfix that describes the locking level. If multiple locks
- * are required, only increasing lock hierarchy numbers may be locked which
- * ensures avoiding a deadlock.
- *
- * Locking Example
- * If state_lock_lhb1 is currently held and the TX list needs to be
- * manipulated, then tx_lock_lhb2 may be locked since it's locking hierarchy
- * is greater. However, if tx_lock_lhb2 is held, then state_lock_lhb1 may
- * not be acquired since it would result in a deadlock.
- *
- * Note that the Line Discipline locks (*_lha) should always be acquired
- * before the logical channel locks.
- */
-struct smux_lch_t {
- /* channel state */
- spinlock_t state_lock_lhb1;
- uint8_t lcid;
- unsigned local_state;
- unsigned local_mode;
- uint8_t local_tiocm;
- unsigned options;
-
- unsigned remote_state;
- unsigned remote_mode;
- uint8_t remote_tiocm;
-
- int tx_flow_control;
- int rx_flow_control_auto;
- int rx_flow_control_client;
-
- /* client callbacks and private data */
- void *priv;
- void (*notify)(void *priv, int event_type, const void *metadata);
- int (*get_rx_buffer)(void *priv, void **pkt_priv, void **buffer,
- int size);
-
- /* RX Info */
- struct list_head rx_retry_queue;
- unsigned rx_retry_queue_cnt;
- struct delayed_work rx_retry_work;
-
- /* TX Info */
- spinlock_t tx_lock_lhb2;
- struct list_head tx_queue;
- struct list_head tx_ready_list;
- unsigned tx_pending_data_cnt;
- unsigned notify_lwm;
-};
-
union notifier_metadata {
struct smux_meta_disconnected disconnected;
struct smux_meta_read read;
@@ -276,6 +236,7 @@
int is_initialized;
int platform_devs_registered;
int in_reset;
+ int remote_is_alive;
int ld_open_count;
struct tty_struct *tty;
@@ -302,7 +263,7 @@
/* data structures */
-static struct smux_lch_t smux_lch[SMUX_NUM_LOGICAL_CHANNELS];
+struct smux_lch_t smux_lch[SMUX_NUM_LOGICAL_CHANNELS];
static struct smux_ldisc_t smux;
static const char *tty_error_type[] = {
[TTY_NORMAL] = "normal",
@@ -312,7 +273,7 @@
[TTY_FRAME] = "framing",
};
-static const char *smux_cmds[] = {
+static const char * const smux_cmds[] = {
[SMUX_CMD_DATA] = "DATA",
[SMUX_CMD_OPEN_LCH] = "OPEN",
[SMUX_CMD_CLOSE_LCH] = "CLOSE",
@@ -321,6 +282,44 @@
[SMUX_CMD_BYTE] = "Raw Byte",
};
+static const char * const smux_events[] = {
+ [SMUX_CONNECTED] = "CONNECTED" ,
+ [SMUX_DISCONNECTED] = "DISCONNECTED",
+ [SMUX_READ_DONE] = "READ_DONE",
+ [SMUX_READ_FAIL] = "READ_FAIL",
+ [SMUX_WRITE_DONE] = "WRITE_DONE",
+ [SMUX_WRITE_FAIL] = "WRITE_FAIL",
+ [SMUX_TIOCM_UPDATE] = "TIOCM_UPDATE",
+ [SMUX_LOW_WM_HIT] = "LOW_WM_HIT",
+ [SMUX_HIGH_WM_HIT] = "HIGH_WM_HIT",
+ [SMUX_RX_RETRY_HIGH_WM_HIT] = "RX_RETRY_HIGH_WM_HIT",
+ [SMUX_RX_RETRY_LOW_WM_HIT] = "RX_RETRY_LOW_WM_HIT",
+};
+
+static const char * const smux_local_state[] = {
+ [SMUX_LCH_LOCAL_CLOSED] = "CLOSED",
+ [SMUX_LCH_LOCAL_OPENING] = "OPENING",
+ [SMUX_LCH_LOCAL_OPENED] = "OPENED",
+ [SMUX_LCH_LOCAL_CLOSING] = "CLOSING",
+};
+
+static const char * const smux_remote_state[] = {
+ [SMUX_LCH_REMOTE_CLOSED] = "CLOSED",
+ [SMUX_LCH_REMOTE_OPENED] = "OPENED",
+};
+
+static const char * const smux_mode[] = {
+ [SMUX_LCH_MODE_NORMAL] = "N",
+ [SMUX_LCH_MODE_LOCAL_LOOPBACK] = "L",
+ [SMUX_LCH_MODE_REMOTE_LOOPBACK] = "R",
+};
+
+static const char * const smux_undef[] = {
+ [SMUX_UNDEF_LONG] = "UNDEF",
+ [SMUX_UNDEF_SHORT] = "U",
+};
+
+static void *log_ctx;
static void smux_notify_local_fn(struct work_struct *work);
static DECLARE_WORK(smux_notify_local, smux_notify_local_fn);
@@ -346,7 +345,6 @@
static DECLARE_DELAYED_WORK(smux_delayed_inactivity_work,
smux_inactivity_worker);
-static long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch);
static void list_channel(struct smux_lch_t *ch);
static int smux_send_status_cmd(struct smux_lch_t *ch);
static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt);
@@ -363,6 +361,45 @@
static void smux_pdev_release(struct device *dev);
/**
+ * local_lch_state() - Return human readable form of local logical state.
+ * @state: Local logical channel state enum.
+ *
+ */
+const char *local_lch_state(unsigned state)
+{
+ if (state < ARRAY_SIZE(smux_local_state))
+ return smux_local_state[state];
+ else
+ return smux_undef[SMUX_UNDEF_LONG];
+}
+
+/**
+ * remote_lch_state() - Return human readable for of remote logical state.
+ * @state: Remote logical channel state enum.
+ *
+ */
+const char *remote_lch_state(unsigned state)
+{
+ if (state < ARRAY_SIZE(smux_remote_state))
+ return smux_remote_state[state];
+ else
+ return smux_undef[SMUX_UNDEF_LONG];
+}
+
+/**
+ * lch_mode() - Return human readable form of mode.
+ * @mode: Mode of the logical channel.
+ *
+ */
+const char *lch_mode(unsigned mode)
+{
+ if (mode < ARRAY_SIZE(smux_mode))
+ return smux_mode[mode];
+ else
+ return smux_undef[SMUX_UNDEF_SHORT];
+}
+
+/**
* Convert TTY Error Flags to string for logging purposes.
*
* @flag TTY_* flag
@@ -389,14 +426,31 @@
}
/**
+ * Convert SMUX event to string for logging purposes.
+ *
+ * @event SMUX event
+ * @returns String description or NULL if unknown
+ */
+static const char *event_to_str(unsigned cmd)
+{
+ if (cmd < ARRAY_SIZE(smux_events))
+ return smux_events[cmd];
+ return NULL;
+}
+
+/**
* Set the reset state due to an unrecoverable failure.
*/
static void smux_enter_reset(void)
{
- pr_err("%s: unrecoverable failure, waiting for ssr\n", __func__);
+ SMUX_ERR("%s: unrecoverable failure, waiting for ssr\n", __func__);
smux.in_reset = 1;
+ smux.remote_is_alive = 0;
}
+/**
+ * Initialize the lch_structs.
+ */
static int lch_init(void)
{
unsigned int id;
@@ -410,7 +464,7 @@
smux_rx_wq = create_singlethread_workqueue("smux_rx_wq");
if (IS_ERR(smux_notify_wq) || IS_ERR(smux_tx_wq)) {
- SMUX_DBG("%s: create_singlethread_workqueue ENOMEM\n",
+ SMUX_DBG("smux: %s: create_singlethread_workqueue ENOMEM\n",
__func__);
return -ENOMEM;
}
@@ -421,7 +475,7 @@
i |= smux_loopback_init();
if (i) {
- pr_err("%s: out of memory error\n", __func__);
+ SMUX_ERR("%s: out of memory error\n", __func__);
return -ENOMEM;
}
@@ -471,7 +525,7 @@
/* Empty TX ready list */
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
while (!list_empty(&smux.lch_tx_ready_list)) {
- SMUX_DBG("%s: emptying ready list %p\n",
+ SMUX_DBG("smux: %s: emptying ready list %p\n",
__func__, smux.lch_tx_ready_list.next);
ch = list_first_entry(&smux.lch_tx_ready_list,
struct smux_lch_t,
@@ -488,7 +542,7 @@
struct smux_pkt_t,
list);
list_del(&pkt->list);
- SMUX_DBG("%s: emptying power queue pkt=%p\n",
+ SMUX_DBG("smux: %s: emptying power queue pkt=%p\n",
__func__, pkt);
smux_free_pkt(pkt);
}
@@ -497,7 +551,7 @@
/* Close all ports */
for (i = 0 ; i < SMUX_NUM_LOGICAL_CHANNELS; i++) {
ch = &smux_lch[i];
- SMUX_DBG("%s: cleaning up lcid %d\n", __func__, i);
+ SMUX_DBG("smux: %s: cleaning up lcid %d\n", __func__, i);
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
@@ -670,7 +724,7 @@
i += snprintf(logbuf + i, SMUX_PKT_LOG_SIZE - i,
"%02x ", (unsigned)data[count]);
- pr_info("%s\n", logbuf);
+ IPC_LOG_STR(logbuf);
}
static void smux_notify_local_fn(struct work_struct *work)
@@ -688,8 +742,9 @@
¬ify_handle,
handle_size);
if (i != handle_size) {
- pr_err("%s: unable to retrieve handle %d expected %d\n",
- __func__, i, handle_size);
+ SMUX_ERR(
+ "%s: unable to retrieve handle %d expected %d\n",
+ __func__, i, handle_size);
spin_unlock_irqrestore(¬ify_lock_lhc1, flags);
break;
}
@@ -735,7 +790,7 @@
/* Consider a free list implementation instead of kmalloc */
pkt = kmalloc(sizeof(struct smux_pkt_t), GFP_ATOMIC);
if (!pkt) {
- pr_err("%s: out of memory\n", __func__);
+ SMUX_ERR("%s: out of memory\n", __func__);
return NULL;
}
smux_init_pkt(pkt);
@@ -779,7 +834,7 @@
pkt->payload = kmalloc(pkt->hdr.payload_len, GFP_ATOMIC);
pkt->free_payload = 1;
if (!pkt->payload) {
- pr_err("%s: unable to malloc %d bytes for payload\n",
+ SMUX_ERR("%s: unable to malloc %d bytes for payload\n",
__func__, pkt->hdr.payload_len);
return -ENOMEM;
}
@@ -797,11 +852,12 @@
unsigned long flags;
int ret = 0;
+ IPC_LOG_STR("smux: %s ch:%d\n", event_to_str(event), lcid);
ch = &smux_lch[lcid];
notify_handle = kzalloc(sizeof(struct smux_notify_handle),
GFP_ATOMIC);
if (!notify_handle) {
- pr_err("%s: out of memory\n", __func__);
+ SMUX_ERR("%s: out of memory\n", __func__);
ret = -ENOMEM;
goto free_out;
}
@@ -813,7 +869,7 @@
meta_copy = kzalloc(sizeof(union notifier_metadata),
GFP_ATOMIC);
if (!meta_copy) {
- pr_err("%s: out of memory\n", __func__);
+ SMUX_ERR("%s: out of memory\n", __func__);
ret = -ENOMEM;
goto free_out;
}
@@ -826,7 +882,7 @@
spin_lock_irqsave(¬ify_lock_lhc1, flags);
i = kfifo_avail(&smux_notify_fifo);
if (i < handle_size) {
- pr_err("%s: fifo full error %d expected %d\n",
+ SMUX_ERR("%s: fifo full error %d expected %d\n",
__func__, i, handle_size);
ret = -ENOMEM;
goto unlock_out;
@@ -834,7 +890,7 @@
i = kfifo_in(&smux_notify_fifo, ¬ify_handle, handle_size);
if (i < 0 || i != handle_size) {
- pr_err("%s: fifo not available error %d (expected %d)\n",
+ SMUX_ERR("%s: fifo not available error %d (expected %d)\n",
__func__, i, handle_size);
ret = -ENOSPC;
goto unlock_out;
@@ -886,7 +942,7 @@
char *data_start = out;
if (smux_serialize_size(pkt) > SMUX_MAX_PKT_SIZE) {
- pr_err("%s: packet size %d too big\n",
+ SMUX_ERR("%s: packet size %d too big\n",
__func__, smux_serialize_size(pkt));
return -E2BIG;
}
@@ -971,7 +1027,7 @@
len -= data_written;
data += data_written;
} else {
- pr_err("%s: TTY write returned error %d\n",
+ SMUX_ERR("%s: TTY write returned error %d\n",
__func__, data_written);
return data_written;
}
@@ -997,12 +1053,12 @@
int ret;
if (!smux.tty) {
- pr_err("%s: TTY not initialized", __func__);
+ SMUX_ERR("%s: TTY not initialized", __func__);
return -ENOTTY;
}
if (pkt->hdr.cmd == SMUX_CMD_BYTE) {
- SMUX_DBG("%s: tty send single byte\n", __func__);
+ SMUX_DBG("smux: %s: tty send single byte\n", __func__);
ret = write_to_tty(&pkt->hdr.flags, 1);
return ret;
}
@@ -1010,7 +1066,7 @@
smux_serialize_hdr(pkt, &data, &len);
ret = write_to_tty(data, len);
if (ret) {
- pr_err("%s: failed %d to write header %d\n",
+ SMUX_ERR("%s: failed %d to write header %d\n",
__func__, ret, len);
return ret;
}
@@ -1018,7 +1074,7 @@
smux_serialize_payload(pkt, &data, &len);
ret = write_to_tty(data, len);
if (ret) {
- pr_err("%s: failed %d to write payload %d\n",
+ SMUX_ERR("%s: failed %d to write payload %d\n",
__func__, ret, len);
return ret;
}
@@ -1028,7 +1084,7 @@
char zero = 0x0;
ret = write_to_tty(&zero, 1);
if (ret) {
- pr_err("%s: failed %d to write padding %d\n",
+ SMUX_ERR("%s: failed %d to write padding %d\n",
__func__, ret, len);
return ret;
}
@@ -1048,7 +1104,7 @@
pkt = smux_alloc_pkt();
if (!pkt) {
- pr_err("%s: alloc failure for byte %x\n", __func__, ch);
+ SMUX_ERR("%s: alloc failure for byte %x\n", __func__, ch);
return;
}
pkt->hdr.cmd = SMUX_CMD_BYTE;
@@ -1091,7 +1147,7 @@
{
unsigned long flags;
- SMUX_DBG("%s: queuing pkt %p\n", __func__, pkt_ptr);
+ SMUX_DBG("smux: %s: queuing pkt %p\n", __func__, pkt_ptr);
spin_lock_irqsave(&ch->tx_lock_lhb2, flags);
list_add_tail(&pkt_ptr->list, &ch->tx_queue);
@@ -1120,7 +1176,7 @@
spin_lock(&ch->state_lock_lhb1);
if (ch->local_state == SMUX_LCH_LOCAL_OPENING) {
- SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+ SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
ch->local_state,
SMUX_LCH_LOCAL_OPENED);
@@ -1132,10 +1188,10 @@
schedule_notify(lcid, SMUX_CONNECTED, NULL);
ret = 0;
} else if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
- SMUX_DBG("Remote loopback OPEN ACK received\n");
+ SMUX_DBG("smux: Remote loopback OPEN ACK received\n");
ret = 0;
} else {
- pr_err("%s: lcid %d state 0x%x open ack invalid\n",
+ SMUX_ERR("%s: lcid %d state 0x%x open ack invalid\n",
__func__, lcid, ch->local_state);
ret = -EINVAL;
}
@@ -1145,7 +1201,7 @@
spin_lock(&smux.tx_lock_lha2);
if (!smux.powerdown_enabled) {
smux.powerdown_enabled = 1;
- SMUX_DBG("%s: enabling power-collapse support\n",
+ SMUX_DBG("smux: %s: enabling power-collapse support\n",
__func__);
}
spin_unlock(&smux.tx_lock_lha2);
@@ -1169,7 +1225,7 @@
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
if (ch->local_state == SMUX_LCH_LOCAL_CLOSING) {
- SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+ SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
SMUX_LCH_LOCAL_CLOSING,
SMUX_LCH_LOCAL_CLOSED);
ch->local_state = SMUX_LCH_LOCAL_CLOSED;
@@ -1178,10 +1234,10 @@
&meta_disconnected);
ret = 0;
} else if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
- SMUX_DBG("Remote loopback CLOSE ACK received\n");
+ SMUX_DBG("smux: Remote loopback CLOSE ACK received\n");
ret = 0;
} else {
- pr_err("%s: lcid %d state 0x%x close ack invalid\n",
+ SMUX_ERR("%s: lcid %d state 0x%x close ack invalid\n",
__func__, lcid, ch->local_state);
ret = -EINVAL;
}
@@ -1215,7 +1271,7 @@
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
if (ch->remote_state == SMUX_LCH_REMOTE_CLOSED) {
- SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
+ SMUX_DBG("smux: lcid %d remote state 0x%x -> 0x%x\n", lcid,
SMUX_LCH_REMOTE_CLOSED,
SMUX_LCH_REMOTE_OPENED);
@@ -1259,15 +1315,16 @@
smux_tx_queue(ack_pkt, ch, 0);
tx_ready = 1;
} else {
- pr_err("%s: Remote loopack allocation failure\n",
- __func__);
+ SMUX_ERR(
+ "%s: Remote loopack allocation failure\n",
+ __func__);
}
} else if (ch->local_state == SMUX_LCH_LOCAL_OPENED) {
schedule_notify(lcid, SMUX_CONNECTED, NULL);
}
ret = 0;
} else {
- pr_err("%s: lcid %d remote state 0x%x open invalid\n",
+ SMUX_ERR("%s: lcid %d remote state 0x%x open invalid\n",
__func__, lcid, ch->remote_state);
ret = -EINVAL;
}
@@ -1279,7 +1336,7 @@
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (!smux.powerdown_enabled) {
smux.powerdown_enabled = 1;
- SMUX_DBG("%s: enabling power-collapse support\n",
+ SMUX_DBG("smux: %s: enabling power-collapse support\n",
__func__);
}
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -1317,7 +1374,7 @@
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
if (ch->remote_state == SMUX_LCH_REMOTE_OPENED) {
- SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
+ SMUX_DBG("smux: lcid %d remote state 0x%x -> 0x%x\n", lcid,
SMUX_LCH_REMOTE_OPENED,
SMUX_LCH_REMOTE_CLOSED);
@@ -1351,8 +1408,9 @@
smux_tx_queue(ack_pkt, ch, 0);
tx_ready = 1;
} else {
- pr_err("%s: Remote loopack allocation failure\n",
- __func__);
+ SMUX_ERR(
+ "%s: Remote loopack allocation failure\n",
+ __func__);
}
}
@@ -1361,7 +1419,7 @@
&meta_disconnected);
ret = 0;
} else {
- pr_err("%s: lcid %d remote state 0x%x close invalid\n",
+ SMUX_ERR("%s: lcid %d remote state 0x%x close invalid\n",
__func__, lcid, ch->remote_state);
ret = -EINVAL;
}
@@ -1412,7 +1470,7 @@
if (ch->local_state != SMUX_LCH_LOCAL_OPENED
&& !remote_loopback) {
- pr_err("smux: ch %d error data on local state 0x%x",
+ SMUX_ERR("smux: ch %d error data on local state 0x%x",
lcid, ch->local_state);
ret = -EIO;
spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -1420,7 +1478,7 @@
}
if (ch->remote_state != SMUX_LCH_REMOTE_OPENED) {
- pr_err("smux: ch %d error data on remote state 0x%x",
+ SMUX_ERR("smux: ch %d error data on remote state 0x%x",
lcid, ch->remote_state);
ret = -EIO;
spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -1441,8 +1499,9 @@
}
if ((ch->rx_retry_queue_cnt + 1) > SMUX_RX_RETRY_MAX_PKTS) {
/* retry queue full */
- pr_err("%s: ch %d RX retry queue full\n",
- __func__, lcid);
+ SMUX_ERR(
+ "%s: ch %d RX retry queue full; rx flow=%d\n",
+ __func__, lcid, ch->rx_flow_control_auto);
schedule_notify(lcid, SMUX_READ_FAIL, NULL);
ret = -ENOMEM;
spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -1468,7 +1527,7 @@
smux_tx_queue(ack_pkt, ch, 0);
tx_ready = 1;
} else {
- pr_err("%s: Remote loopack allocation failure\n",
+ SMUX_ERR("%s: Remote loopack allocation failure\n",
__func__);
}
} else if (!do_retry) {
@@ -1492,7 +1551,7 @@
/* buffer allocation failed - add to retry queue */
do_retry = 1;
} else if (tmp < 0) {
- pr_err("%s: ch %d Client RX buffer alloc failed %d\n",
+ SMUX_ERR("%s: ch %d Client RX buffer alloc failed %d\n",
__func__, lcid, tmp);
schedule_notify(lcid, SMUX_READ_FAIL, NULL);
ret = -ENOMEM;
@@ -1504,7 +1563,7 @@
retry = kmalloc(sizeof(struct smux_rx_pkt_retry), GFP_KERNEL);
if (!retry) {
- pr_err("%s: retry alloc failure\n", __func__);
+ SMUX_ERR("%s: retry alloc failure\n", __func__);
ret = -ENOMEM;
schedule_notify(lcid, SMUX_READ_FAIL, NULL);
goto out;
@@ -1516,7 +1575,7 @@
retry->pkt = smux_alloc_pkt();
if (!retry->pkt) {
kfree(retry);
- pr_err("%s: pkt alloc failure\n", __func__);
+ SMUX_ERR("%s: pkt alloc failure\n", __func__);
ret = -ENOMEM;
schedule_notify(lcid, SMUX_READ_FAIL, NULL);
goto out;
@@ -1562,7 +1621,7 @@
unsigned long flags;
if (!pkt || smux_assert_lch_id(pkt->hdr.lcid)) {
- pr_err("%s: invalid packet or channel id\n", __func__);
+ SMUX_ERR("%s: invalid packet or channel id\n", __func__);
return -ENXIO;
}
@@ -1571,14 +1630,14 @@
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
if (ch->local_state != SMUX_LCH_LOCAL_OPENED) {
- pr_err("smux: ch %d error data on local state 0x%x",
+ SMUX_ERR("smux: ch %d error data on local state 0x%x",
lcid, ch->local_state);
ret = -EIO;
goto out;
}
if (ch->remote_state != SMUX_LCH_REMOTE_OPENED) {
- pr_err("smux: ch %d error data on remote state 0x%x",
+ SMUX_ERR("smux: ch %d error data on remote state 0x%x",
lcid, ch->remote_state);
ret = -EIO;
goto out;
@@ -1623,11 +1682,11 @@
/* logical channel flow control changed */
if (pkt->hdr.flags & SMUX_CMD_STATUS_FLOW_CNTL) {
/* disabled TX */
- SMUX_DBG("TX Flow control enabled\n");
+ SMUX_DBG("smux: TX Flow control enabled\n");
ch->tx_flow_control = 1;
} else {
/* re-enable channel */
- SMUX_DBG("TX Flow control disabled\n");
+ SMUX_DBG("smux: TX Flow control disabled\n");
ch->tx_flow_control = 0;
tx_ready = 1;
}
@@ -1671,7 +1730,7 @@
/* Power-down complete, turn off UART */
power_down = 1;
else
- pr_err("%s: sleep request ack invalid in state %d\n",
+ SMUX_ERR("%s: sleep request ack invalid in state %d\n",
__func__, smux.power_state);
} else {
/*
@@ -1690,7 +1749,7 @@
if (smux.power_state == SMUX_PWR_ON) {
ack_pkt = smux_alloc_pkt();
if (ack_pkt) {
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_OFF_FLUSH);
@@ -1706,7 +1765,7 @@
}
} else if (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH) {
/* Local power-down request still in TX queue */
- SMUX_PWR("%s: Power-down shortcut - no ack\n",
+ SMUX_PWR("smux: %s: Power-down shortcut - no ack\n",
__func__);
smux.power_ctl_remote_req_received = 1;
} else if (smux.power_state == SMUX_PWR_TURNING_OFF) {
@@ -1714,17 +1773,17 @@
* Local power-down request already sent to remote
* side, so this request gets treated as an ACK.
*/
- SMUX_PWR("%s: Power-down shortcut - no ack\n",
+ SMUX_PWR("smux: %s: Power-down shortcut - no ack\n",
__func__);
power_down = 1;
} else {
- pr_err("%s: sleep request invalid in state %d\n",
+ SMUX_ERR("%s: sleep request invalid in state %d\n",
__func__, smux.power_state);
}
}
if (power_down) {
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_OFF_FLUSH);
smux.power_state = SMUX_PWR_OFF_FLUSH;
queue_work(smux_tx_wq, &smux_inactivity_work);
@@ -1749,7 +1808,7 @@
case SMUX_CMD_OPEN_LCH:
SMUX_LOG_PKT_RX(pkt);
if (smux_assert_lch_id(pkt->hdr.lcid)) {
- pr_err("%s: invalid channel id %d\n",
+ SMUX_ERR("%s: invalid channel id %d\n",
__func__, pkt->hdr.lcid);
break;
}
@@ -1759,7 +1818,7 @@
case SMUX_CMD_DATA:
SMUX_LOG_PKT_RX(pkt);
if (smux_assert_lch_id(pkt->hdr.lcid)) {
- pr_err("%s: invalid channel id %d\n",
+ SMUX_ERR("%s: invalid channel id %d\n",
__func__, pkt->hdr.lcid);
break;
}
@@ -1769,7 +1828,7 @@
case SMUX_CMD_CLOSE_LCH:
SMUX_LOG_PKT_RX(pkt);
if (smux_assert_lch_id(pkt->hdr.lcid)) {
- pr_err("%s: invalid channel id %d\n",
+ SMUX_ERR("%s: invalid channel id %d\n",
__func__, pkt->hdr.lcid);
break;
}
@@ -1779,7 +1838,7 @@
case SMUX_CMD_STATUS:
SMUX_LOG_PKT_RX(pkt);
if (smux_assert_lch_id(pkt->hdr.lcid)) {
- pr_err("%s: invalid channel id %d\n",
+ SMUX_ERR("%s: invalid channel id %d\n",
__func__, pkt->hdr.lcid);
break;
}
@@ -1797,7 +1856,7 @@
default:
SMUX_LOG_PKT_RX(pkt);
- pr_err("%s: command %d unknown\n", __func__, pkt->hdr.cmd);
+ SMUX_ERR("%s: command %d unknown\n", __func__, pkt->hdr.cmd);
ret = -EINVAL;
}
return ret;
@@ -1824,7 +1883,7 @@
memcpy(&recv.hdr, data, sizeof(struct smux_hdr_t));
if (recv.hdr.magic != SMUX_MAGIC) {
- pr_err("%s: invalid header magic\n", __func__);
+ SMUX_ERR("%s: invalid header magic\n", __func__);
return -EINVAL;
}
@@ -1845,7 +1904,7 @@
if (smux.power_state == SMUX_PWR_OFF
|| smux.power_state == SMUX_PWR_TURNING_ON) {
/* wakeup system */
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_ON);
smux.power_state = SMUX_PWR_ON;
queue_work(smux_tx_wq, &smux_wakeup_work);
@@ -1857,7 +1916,7 @@
smux_send_byte(SMUX_WAKEUP_ACK);
} else {
/* stale wakeup request from previous wakeup */
- SMUX_PWR("%s: stale Wakeup REQ in state %d\n",
+ SMUX_PWR("smux: %s: stale Wakeup REQ in state %d\n",
__func__, smux.power_state);
}
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -1873,7 +1932,7 @@
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_TURNING_ON) {
/* received response to wakeup request */
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_ON);
smux.power_state = SMUX_PWR_ON;
queue_work(smux_tx_wq, &smux_tx_work);
@@ -1882,7 +1941,7 @@
} else if (smux.power_state != SMUX_PWR_ON) {
/* invalid message */
- SMUX_PWR("%s: stale Wakeup REQ ACK in state %d\n",
+ SMUX_PWR("smux: %s: stale Wakeup REQ ACK in state %d\n",
__func__, smux.power_state);
}
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -1905,7 +1964,7 @@
if (smux_byte_loopback)
smux_receive_byte(SMUX_UT_ECHO_ACK_FAIL,
smux_byte_loopback);
- pr_err("%s: TTY error 0x%x - ignoring\n", __func__, flag);
+ SMUX_ERR("%s: TTY error 0x%x - ignoring\n", __func__, flag);
++*used;
return;
}
@@ -1916,11 +1975,21 @@
smux.rx_state = SMUX_RX_MAGIC;
break;
case SMUX_WAKEUP_REQ:
- SMUX_PWR("smux: RX Wakeup REQ\n");
+ SMUX_PWR("smux: smux: RX Wakeup REQ\n");
+ if (unlikely(!smux.remote_is_alive)) {
+ mutex_lock(&smux.mutex_lha0);
+ smux.remote_is_alive = 1;
+ mutex_unlock(&smux.mutex_lha0);
+ }
smux_handle_wakeup_req();
break;
case SMUX_WAKEUP_ACK:
- SMUX_PWR("smux: RX Wakeup ACK\n");
+ SMUX_PWR("smux: smux: RX Wakeup ACK\n");
+ if (unlikely(!smux.remote_is_alive)) {
+ mutex_lock(&smux.mutex_lha0);
+ smux.remote_is_alive = 1;
+ mutex_unlock(&smux.mutex_lha0);
+ }
smux_handle_wakeup_ack();
break;
default:
@@ -1928,8 +1997,8 @@
if (smux_byte_loopback && data[i] == SMUX_UT_ECHO_REQ)
smux_receive_byte(SMUX_UT_ECHO_ACK_OK,
smux_byte_loopback);
- pr_err("%s: parse error 0x%02x - ignoring\n", __func__,
- (unsigned)data[i]);
+ SMUX_ERR("%s: parse error 0x%02x - ignoring\n",
+ __func__, (unsigned)data[i]);
break;
}
}
@@ -1951,7 +2020,7 @@
int i;
if (flag) {
- pr_err("%s: TTY RX error %d\n", __func__, flag);
+ SMUX_ERR("%s: TTY RX error %d\n", __func__, flag);
smux_enter_reset();
smux.rx_state = SMUX_RX_FAILURE;
++*used;
@@ -1967,8 +2036,9 @@
smux.rx_state = SMUX_RX_HDR;
} else {
/* unexpected / trash character */
- pr_err("%s: rx parse error for char %c; *used=%d, len=%d\n",
- __func__, data[i], *used, len);
+ SMUX_ERR(
+ "%s: rx parse error for char %c; *used=%d, len=%d\n",
+ __func__, data[i], *used, len);
smux.rx_state = SMUX_RX_IDLE;
}
}
@@ -1991,7 +2061,7 @@
struct smux_hdr_t *hdr;
if (flag) {
- pr_err("%s: TTY RX error %d\n", __func__, flag);
+ SMUX_ERR("%s: TTY RX error %d\n", __func__, flag);
smux_enter_reset();
smux.rx_state = SMUX_RX_FAILURE;
++*used;
@@ -2025,7 +2095,7 @@
int remaining;
if (flag) {
- pr_err("%s: TTY RX error %d\n", __func__, flag);
+ SMUX_ERR("%s: TTY RX error %d\n", __func__, flag);
smux_enter_reset();
smux.rx_state = SMUX_RX_FAILURE;
++*used;
@@ -2073,6 +2143,24 @@
}
/**
+ * Returns true if the remote side has acknowledged a wakeup
+ * request previously, so we know that the link is alive and active.
+ *
+ * @returns true for is alive, false for not alive
+ */
+bool smux_remote_is_active(void)
+{
+ bool is_active = false;
+
+ mutex_lock(&smux.mutex_lha0);
+ if (smux.remote_is_alive)
+ is_active = true;
+ mutex_unlock(&smux.mutex_lha0);
+
+ return is_active;
+}
+
+/**
* Add channel to transmit-ready list and trigger transmit worker.
*
* @ch Channel to add
@@ -2081,7 +2169,7 @@
{
unsigned long flags;
- SMUX_DBG("%s: listing channel %d\n",
+ SMUX_DBG("smux: %s: listing channel %d\n",
__func__, ch->lcid);
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
@@ -2120,11 +2208,11 @@
meta_write.write.buffer = pkt->payload;
meta_write.write.len = pkt->hdr.payload_len;
if (ret >= 0) {
- SMUX_DBG("%s: PKT write done", __func__);
+ SMUX_DBG("smux: %s: PKT write done", __func__);
schedule_notify(ch->lcid, SMUX_WRITE_DONE,
&meta_write);
} else {
- pr_err("%s: failed to write pkt %d\n",
+ SMUX_ERR("%s: failed to write pkt %d\n",
__func__, ret);
schedule_notify(ch->lcid, SMUX_WRITE_FAIL,
&meta_write);
@@ -2140,7 +2228,7 @@
{
mutex_lock(&smux.mutex_lha0);
if (!smux.tty) {
- pr_err("%s: ldisc not loaded\n", __func__);
+ SMUX_ERR("%s: ldisc not loaded\n", __func__);
mutex_unlock(&smux.mutex_lha0);
return;
}
@@ -2149,7 +2237,7 @@
msecs_to_jiffies(TTY_BUFFER_FULL_WAIT_MS));
if (tty_chars_in_buffer(smux.tty) > 0)
- pr_err("%s: unable to flush UART queue\n", __func__);
+ SMUX_ERR("%s: unable to flush UART queue\n", __func__);
mutex_unlock(&smux.mutex_lha0);
}
@@ -2222,7 +2310,7 @@
struct uart_state *state;
if (!smux.tty || !smux.tty->driver_data) {
- pr_err("%s: unable to find UART port for tty %p\n",
+ SMUX_ERR("%s: unable to find UART port for tty %p\n",
__func__, smux.tty);
return;
}
@@ -2250,7 +2338,7 @@
struct uart_state *state;
if (!smux.tty || !smux.tty->driver_data) {
- pr_err("%s: unable to find UART port for tty %p\n",
+ SMUX_ERR("%s: unable to find UART port for tty %p\n",
__func__, smux.tty);
mutex_unlock(&smux.mutex_lha0);
return;
@@ -2290,7 +2378,7 @@
/* wakeup complete */
smux.pwr_wakeup_delay_us = 1;
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
- SMUX_DBG("%s: wakeup complete\n", __func__);
+ SMUX_DBG("smux: %s: wakeup complete\n", __func__);
/*
* Cancel any pending retry. This avoids a race condition with
@@ -2310,17 +2398,18 @@
SMUX_WAKEUP_DELAY_MAX;
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
- SMUX_PWR("%s: triggering wakeup\n", __func__);
+ SMUX_PWR("smux: %s: triggering wakeup\n", __func__);
smux_send_byte(SMUX_WAKEUP_REQ);
if (wakeup_delay < SMUX_WAKEUP_DELAY_MIN) {
- SMUX_DBG("%s: sleeping for %u us\n", __func__,
+ SMUX_DBG("smux: %s: sleeping for %u us\n", __func__,
wakeup_delay);
usleep_range(wakeup_delay, 2*wakeup_delay);
queue_work(smux_tx_wq, &smux_wakeup_work);
} else {
/* schedule delayed work */
- SMUX_DBG("%s: scheduling delayed wakeup in %u ms\n",
+ SMUX_DBG(
+ "smux: %s: scheduling delayed wakeup in %u ms\n",
__func__, wakeup_delay / 1000);
queue_delayed_work(smux_tx_wq,
&smux_wakeup_delayed_work,
@@ -2330,7 +2419,7 @@
/* wakeup aborted */
smux.pwr_wakeup_delay_us = 1;
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
- SMUX_PWR("%s: wakeup aborted\n", __func__);
+ SMUX_PWR("smux: %s: wakeup aborted\n", __func__);
cancel_delayed_work(&smux_wakeup_delayed_work);
}
}
@@ -2360,7 +2449,8 @@
/* start power-down sequence */
pkt = smux_alloc_pkt();
if (pkt) {
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR(
+ "smux: %s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_OFF_FLUSH);
smux.power_state =
@@ -2374,7 +2464,7 @@
&smux.power_queue);
queue_work(smux_tx_wq, &smux_tx_work);
} else {
- pr_err("%s: packet alloc failed\n",
+ SMUX_ERR("%s: packet alloc failed\n",
__func__);
}
}
@@ -2385,7 +2475,7 @@
if (smux.power_state == SMUX_PWR_OFF_FLUSH) {
/* ready to power-down the UART */
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_OFF);
smux.power_state = SMUX_PWR_OFF;
@@ -2466,16 +2556,16 @@
smux.rx_activity_flag = 1;
spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
- SMUX_DBG("%s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
+ SMUX_DBG("smux: %s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
used = 0;
do {
if (smux.in_reset) {
- SMUX_DBG("%s: abort RX due to reset\n", __func__);
+ SMUX_DBG("smux: %s: abort RX due to reset\n", __func__);
smux.rx_state = SMUX_RX_IDLE;
break;
}
- SMUX_DBG("%s: state %d; %d of %d\n",
+ SMUX_DBG("smux: %s: state %d; %d of %d\n",
__func__, smux.rx_state, used, len);
initial_rx_state = smux.rx_state;
@@ -2493,7 +2583,7 @@
smux_rx_handle_pkt_payload(data, len, &used, flag);
break;
default:
- SMUX_DBG("%s: invalid state %d\n",
+ SMUX_DBG("smux: %s: invalid state %d\n",
__func__, smux.rx_state);
smux.rx_state = SMUX_RX_IDLE;
break;
@@ -2534,7 +2624,7 @@
}
if (list_empty(&ch->rx_retry_queue)) {
- SMUX_DBG("%s: retry list empty for channel %d\n",
+ SMUX_DBG("smux: %s: retry list empty for channel %d\n",
__func__, ch->lcid);
spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
return;
@@ -2544,7 +2634,7 @@
rx_retry_list);
spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
- SMUX_DBG("%s: ch %d retrying rx pkt %p\n",
+ SMUX_DBG("smux: %s: ch %d retrying rx pkt %p\n",
__func__, ch->lcid, retry);
metadata.read.pkt_priv = 0;
metadata.read.buffer = 0;
@@ -2573,7 +2663,7 @@
retry->timeout_in_ms <<= 1;
if (retry->timeout_in_ms > SMUX_RX_RETRY_MAX_MS) {
/* timed out */
- pr_err("%s: ch %d RX retry client timeout\n",
+ SMUX_ERR("%s: ch %d RX retry client timeout\n",
__func__, ch->lcid);
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
tx_ready = smux_remove_rx_retry(ch, retry);
@@ -2584,7 +2674,7 @@
}
} else {
/* client error - drop packet */
- pr_err("%s: ch %d RX retry client failed (%d)\n",
+ SMUX_ERR("%s: ch %d RX retry client failed (%d)\n",
__func__, ch->lcid, tmp);
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
tx_ready = smux_remove_rx_retry(ch, retry);
@@ -2649,7 +2739,7 @@
if (!list_empty(&smux.lch_tx_ready_list) ||
!list_empty(&smux.power_queue)) {
/* data to transmit, do wakeup */
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_ON);
smux.power_state = SMUX_PWR_TURNING_ON;
@@ -2683,7 +2773,8 @@
* and we already received a remote
* power-down request.
*/
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR(
+ "smux: %s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_OFF_FLUSH);
smux.power_state = SMUX_PWR_OFF_FLUSH;
@@ -2692,7 +2783,8 @@
&smux_inactivity_work);
} else {
/* sending local power-down request */
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR(
+ "smux: %s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_OFF);
smux.power_state = SMUX_PWR_TURNING_OFF;
@@ -2718,7 +2810,7 @@
/* get the next ready channel */
if (list_empty(&smux.lch_tx_ready_list)) {
/* no ready channels */
- SMUX_DBG("%s: no more ready channels, exiting\n",
+ SMUX_DBG("smux: %s: no more ready channels, exiting\n",
__func__);
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
break;
@@ -2727,7 +2819,7 @@
if (smux.power_state != SMUX_PWR_ON) {
/* channel not ready to transmit */
- SMUX_DBG("%s: waiting for link up (state %d)\n",
+ SMUX_DBG("smux: %s: waiting for link up (state %d)\n",
__func__,
smux.power_state);
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -2838,11 +2930,11 @@
{
smux.in_reset = 1;
- SMUX_DBG("%s: flushing tx wq\n", __func__);
+ SMUX_DBG("smux: %s: flushing tx wq\n", __func__);
flush_workqueue(smux_tx_wq);
- SMUX_DBG("%s: flushing rx wq\n", __func__);
+ SMUX_DBG("smux: %s: flushing rx wq\n", __func__);
flush_workqueue(smux_rx_wq);
- SMUX_DBG("%s: flushing notify wq\n", __func__);
+ SMUX_DBG("smux: %s: flushing notify wq\n", __func__);
flush_workqueue(smux_notify_wq);
}
@@ -2900,13 +2992,13 @@
/* Auto RX Flow Control */
if (set & SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP) {
- SMUX_DBG("%s: auto rx flow control option enabled\n",
+ SMUX_DBG("smux: %s: auto rx flow control option enabled\n",
__func__);
ch->options |= SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP;
}
if (clear & SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP) {
- SMUX_DBG("%s: auto rx flow control option disabled\n",
+ SMUX_DBG("smux: %s: auto rx flow control option disabled\n",
__func__);
ch->options &= ~SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP;
ch->rx_flow_control_auto = 0;
@@ -2961,13 +3053,13 @@
}
if (ch->local_state != SMUX_LCH_LOCAL_CLOSED) {
- pr_err("%s: open lcid %d local state %x invalid\n",
+ SMUX_ERR("%s: open lcid %d local state %x invalid\n",
__func__, lcid, ch->local_state);
ret = -EINVAL;
goto out;
}
- SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+ SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
ch->local_state,
SMUX_LCH_LOCAL_OPENING);
@@ -3031,6 +3123,7 @@
ch->remote_tiocm = 0x0;
ch->tx_pending_data_cnt = 0;
ch->notify_lwm = 0;
+ ch->tx_flow_control = 0;
/* Purge TX queue */
spin_lock(&ch->tx_lock_lhb2);
@@ -3040,7 +3133,7 @@
/* Send Close Command */
if (ch->local_state == SMUX_LCH_LOCAL_OPENED ||
ch->local_state == SMUX_LCH_LOCAL_OPENING) {
- SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+ SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
ch->local_state,
SMUX_LCH_LOCAL_CLOSING);
@@ -3055,7 +3148,7 @@
smux_tx_queue(pkt, ch, 0);
tx_ready = 1;
} else {
- pr_err("%s: pkt allocation failed\n", __func__);
+ SMUX_ERR("%s: pkt allocation failed\n", __func__);
ret = -ENOMEM;
}
@@ -3105,14 +3198,14 @@
if (ch->local_state != SMUX_LCH_LOCAL_OPENED &&
ch->local_state != SMUX_LCH_LOCAL_OPENING) {
- pr_err("%s: hdr.invalid local state %d channel %d\n",
+ SMUX_ERR("%s: hdr.invalid local state %d channel %d\n",
__func__, ch->local_state, lcid);
ret = -EINVAL;
goto out;
}
if (len > SMUX_MAX_PKT_SIZE - sizeof(struct smux_hdr_t)) {
- pr_err("%s: payload %d too large\n",
+ SMUX_ERR("%s: payload %d too large\n",
__func__, len);
ret = -E2BIG;
goto out;
@@ -3134,10 +3227,10 @@
spin_lock(&ch->tx_lock_lhb2);
/* verify high watermark */
- SMUX_DBG("%s: pending %d", __func__, ch->tx_pending_data_cnt);
+ SMUX_DBG("smux: %s: pending %d", __func__, ch->tx_pending_data_cnt);
if (ch->tx_pending_data_cnt >= SMUX_TX_WM_HIGH) {
- pr_err("%s: ch %d high watermark %d exceeded %d\n",
+ SMUX_ERR("%s: ch %d high watermark %d exceeded %d\n",
__func__, lcid, SMUX_TX_WM_HIGH,
ch->tx_pending_data_cnt);
ret = -EAGAIN;
@@ -3147,7 +3240,7 @@
/* queue packet for transmit */
if (++ch->tx_pending_data_cnt == SMUX_TX_WM_HIGH) {
ch->notify_lwm = 1;
- pr_err("%s: high watermark hit\n", __func__);
+ SMUX_ERR("%s: high watermark hit\n", __func__);
schedule_notify(lcid, SMUX_HIGH_WM_HIT, NULL);
}
list_add_tail(&pkt->list, &ch->tx_queue);
@@ -3265,7 +3358,7 @@
*
* @returns TIOCM status
*/
-static long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch)
+long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch)
{
long status = 0x0;
@@ -3383,24 +3476,26 @@
int power_off_uart = 0;
if (code == SUBSYS_BEFORE_SHUTDOWN) {
- SMUX_DBG("%s: ssr - before shutdown\n", __func__);
+ SMUX_DBG("smux: %s: ssr - before shutdown\n", __func__);
mutex_lock(&smux.mutex_lha0);
smux.in_reset = 1;
+ smux.remote_is_alive = 0;
mutex_unlock(&smux.mutex_lha0);
return NOTIFY_DONE;
} else if (code == SUBSYS_AFTER_POWERUP) {
/* re-register platform devices */
- SMUX_DBG("%s: ssr - after power-up\n", __func__);
+ SMUX_DBG("smux: %s: ssr - after power-up\n", __func__);
mutex_lock(&smux.mutex_lha0);
if (smux.ld_open_count > 0
&& !smux.platform_devs_registered) {
for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
- SMUX_DBG("%s: register pdev '%s'\n",
+ SMUX_DBG("smux: %s: register pdev '%s'\n",
__func__, smux_devs[i].name);
smux_devs[i].dev.release = smux_pdev_release;
tmp = platform_device_register(&smux_devs[i]);
if (tmp)
- pr_err("%s: error %d registering device %s\n",
+ SMUX_ERR(
+ "%s: error %d registering device %s\n",
__func__, tmp, smux_devs[i].name);
}
smux.platform_devs_registered = 1;
@@ -3410,7 +3505,7 @@
} else if (code != SUBSYS_AFTER_SHUTDOWN) {
return NOTIFY_DONE;
}
- SMUX_DBG("%s: ssr - after shutdown\n", __func__);
+ SMUX_DBG("smux: %s: ssr - after shutdown\n", __func__);
/* Cleanup channels */
smux_flush_workqueues();
@@ -3423,7 +3518,7 @@
/* Unregister platform devices */
if (smux.platform_devs_registered) {
for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
- SMUX_DBG("%s: unregister pdev '%s'\n",
+ SMUX_DBG("smux: %s: unregister pdev '%s'\n",
__func__, smux_devs[i].name);
platform_device_unregister(&smux_devs[i]);
}
@@ -3433,7 +3528,8 @@
/* Power-down UART */
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state != SMUX_PWR_OFF) {
- SMUX_PWR("%s: SSR - turning off UART\n", __func__);
+ SMUX_PWR("smux: %s: SSR - turning off UART\n",
+ __func__);
smux.power_state = SMUX_PWR_OFF;
power_off_uart = 1;
}
@@ -3447,6 +3543,7 @@
smux.rx_activity_flag = 0;
smux.rx_state = SMUX_RX_IDLE;
smux.in_reset = 0;
+ smux.remote_is_alive = 0;
mutex_unlock(&smux.mutex_lha0);
return NOTIFY_DONE;
@@ -3460,7 +3557,8 @@
struct platform_device *pdev;
pdev = container_of(dev, struct platform_device, dev);
- SMUX_DBG("%s: releasing pdev %p '%s'\n", __func__, pdev, pdev->name);
+ SMUX_DBG("smux: %s: releasing pdev %p '%s'\n",
+ __func__, pdev, pdev->name);
memset(&pdev->dev, 0x0, sizeof(pdev->dev));
}
@@ -3475,14 +3573,14 @@
mutex_lock(&smux.mutex_lha0);
if (smux.ld_open_count) {
- pr_err("%s: %p multiple instances not supported\n",
+ SMUX_ERR("%s: %p multiple instances not supported\n",
__func__, tty);
mutex_unlock(&smux.mutex_lha0);
return -EEXIST;
}
if (tty->ops->write == NULL) {
- pr_err("%s: tty->ops->write already NULL\n", __func__);
+ SMUX_ERR("%s: tty->ops->write already NULL\n", __func__);
mutex_unlock(&smux.mutex_lha0);
return -EINVAL;
}
@@ -3498,7 +3596,7 @@
/* power-down the UART if we are idle */
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_OFF) {
- SMUX_PWR("%s: powering off uart\n", __func__);
+ SMUX_PWR("smux: %s: powering off uart\n", __func__);
smux.power_state = SMUX_PWR_OFF_FLUSH;
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
queue_work(smux_tx_wq, &smux_inactivity_work);
@@ -3508,12 +3606,12 @@
/* register platform devices */
for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
- SMUX_DBG("%s: register pdev '%s'\n",
+ SMUX_DBG("smux: %s: register pdev '%s'\n",
__func__, smux_devs[i].name);
smux_devs[i].dev.release = smux_pdev_release;
tmp = platform_device_register(&smux_devs[i]);
if (tmp)
- pr_err("%s: error %d registering device %s\n",
+ SMUX_ERR("%s: error %d registering device %s\n",
__func__, tmp, smux_devs[i].name);
}
smux.platform_devs_registered = 1;
@@ -3527,12 +3625,12 @@
int power_up_uart = 0;
int i;
- SMUX_DBG("%s: ldisc unload\n", __func__);
+ SMUX_DBG("smux: %s: ldisc unload\n", __func__);
smux_flush_workqueues();
mutex_lock(&smux.mutex_lha0);
if (smux.ld_open_count <= 0) {
- pr_err("%s: invalid ld count %d\n", __func__,
+ SMUX_ERR("%s: invalid ld count %d\n", __func__,
smux.ld_open_count);
mutex_unlock(&smux.mutex_lha0);
return;
@@ -3545,7 +3643,7 @@
/* Unregister platform devices */
if (smux.platform_devs_registered) {
for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
- SMUX_DBG("%s: unregister pdev '%s'\n",
+ SMUX_DBG("smux: %s: unregister pdev '%s'\n",
__func__, smux_devs[i].name);
platform_device_unregister(&smux_devs[i]);
}
@@ -3569,8 +3667,9 @@
/* Disconnect from TTY */
smux.tty = NULL;
+ smux.remote_is_alive = 0;
mutex_unlock(&smux.mutex_lha0);
- SMUX_DBG("%s: ldisc complete\n", __func__);
+ SMUX_DBG("smux: %s: ldisc complete\n", __func__);
}
/**
@@ -3589,16 +3688,12 @@
const char *tty_name = NULL;
char *f;
- if (smux_debug_mask & MSM_SMUX_DEBUG)
- print_hex_dump(KERN_INFO, "smux tty rx: ", DUMP_PREFIX_OFFSET,
- 16, 1, cp, count, true);
-
/* verify error flags */
for (i = 0, f = fp; i < count; ++i, ++f) {
if (*f != TTY_NORMAL) {
if (tty)
tty_name = tty->name;
- pr_err("%s: TTY %s Error %d (%s)\n", __func__,
+ SMUX_ERR("%s: TTY %s Error %d (%s)\n", __func__,
tty_name, *f, tty_flag_to_str(*f));
/* feed all previous valid data to the parser */
@@ -3617,46 +3712,46 @@
static void smuxld_flush_buffer(struct tty_struct *tty)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
}
static ssize_t smuxld_chars_in_buffer(struct tty_struct *tty)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
return -ENODEV;
}
static ssize_t smuxld_read(struct tty_struct *tty, struct file *file,
unsigned char __user *buf, size_t nr)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
return -ENODEV;
}
static ssize_t smuxld_write(struct tty_struct *tty, struct file *file,
const unsigned char *buf, size_t nr)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
return -ENODEV;
}
static int smuxld_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
return -ENODEV;
}
static unsigned int smuxld_poll(struct tty_struct *tty, struct file *file,
struct poll_table_struct *tbl)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
return -ENODEV;
}
static void smuxld_write_wakeup(struct tty_struct *tty)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
}
static struct tty_ldisc_ops smux_ldisc_ops = {
@@ -3694,6 +3789,7 @@
smux.tty = NULL;
smux.ld_open_count = 0;
smux.in_reset = 0;
+ smux.remote_is_alive = 0;
smux.is_initialized = 1;
smux.platform_devs_registered = 0;
smux_byte_loopback = 0;
@@ -3703,7 +3799,7 @@
ret = tty_register_ldisc(N_SMUX, &smux_ldisc_ops);
if (ret != 0) {
- pr_err("%s: error %d registering line discipline\n",
+ SMUX_ERR("%s: error %d registering line discipline\n",
__func__, ret);
return ret;
}
@@ -3712,10 +3808,16 @@
ret = lch_init();
if (ret != 0) {
- pr_err("%s: lch_init failed\n", __func__);
+ SMUX_ERR("%s: lch_init failed\n", __func__);
return ret;
}
+ log_ctx = ipc_log_context_create(1, "smux");
+ if (!log_ctx) {
+ SMUX_ERR("%s: unable to create log context\n", __func__);
+ disable_ipc_logging = 1;
+ }
+
return 0;
}
@@ -3725,7 +3827,7 @@
ret = tty_unregister_ldisc(N_SMUX);
if (ret != 0) {
- pr_err("%s error %d unregistering line discipline\n",
+ SMUX_ERR("%s error %d unregistering line discipline\n",
__func__, ret);
return;
}
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 1acec4d..2d73af6 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -3,7 +3,7 @@
* MSM 7k High speed uart driver
*
* Copyright (c) 2008 Google Inc.
- * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
* Modified: Nick Pelly <npelly@google.com>
*
* All source code in this file is licensed under the following license
@@ -168,6 +168,7 @@
struct work_struct clock_off_w; /* work for actual clock off */
struct workqueue_struct *hsuart_wq; /* hsuart workqueue */
struct mutex clk_mutex; /* mutex to guard against clock off/clock on */
+ bool tty_flush_receive;
};
#define MSM_UARTDM_BURST_SIZE 16 /* DM burst size (in bytes) */
@@ -753,6 +754,8 @@
uport->ignore_status_mask = termios->c_iflag & INPCK;
uport->ignore_status_mask |= termios->c_iflag & IGNPAR;
+ uport->ignore_status_mask |= termios->c_iflag & IGNBRK;
+
uport->read_status_mask = (termios->c_cflag & CREAD);
msm_hs_write(uport, UARTDM_IMR_ADDR, 0);
@@ -1030,15 +1033,29 @@
if (unlikely(status & UARTDM_SR_PAR_FRAME_BMSK)) {
/* Can not tell difference between parity & frame error */
+ if (hs_serial_debug_mask)
+ printk(KERN_WARNING "msm_serial_hs: parity error\n");
uport->icount.parity++;
error_f = 1;
- if (uport->ignore_status_mask & IGNPAR) {
+ if (!(uport->ignore_status_mask & IGNPAR)) {
retval = tty_insert_flip_char(tty, 0, TTY_PARITY);
if (!retval)
msm_uport->rx.buffer_pending |= TTY_PARITY;
}
}
+ if (unlikely(status & UARTDM_SR_RX_BREAK_BMSK)) {
+ if (hs_serial_debug_mask)
+ printk(KERN_WARNING "msm_serial_hs: Rx break\n");
+ uport->icount.brk++;
+ error_f = 1;
+ if (!(uport->ignore_status_mask & IGNBRK)) {
+ retval = tty_insert_flip_char(tty, 0, TTY_BREAK);
+ if (!retval)
+ msm_uport->rx.buffer_pending |= TTY_BREAK;
+ }
+ }
+
if (error_f)
msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS);
@@ -1244,6 +1261,13 @@
}
+static void msm_hs_flush_buffer(struct uart_port *uport)
+{
+ struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+ msm_uport->tty_flush_receive = true;
+}
+
/*
* Standard API, Break Signal
*
@@ -1459,7 +1483,14 @@
*/
mb();
/* Complete DMA TX transactions and submit new transactions */
- tx_buf->tail = (tx_buf->tail + tx->tx_count) & ~UART_XMIT_SIZE;
+
+ /* Do not update tx_buf.tail if uart_flush_buffer already
+ called in serial core */
+ if (!msm_uport->tty_flush_receive)
+ tx_buf->tail = (tx_buf->tail +
+ tx->tx_count) & ~UART_XMIT_SIZE;
+ else
+ msm_uport->tty_flush_receive = false;
tx->dma_in_flight = 0;
@@ -2213,6 +2244,7 @@
.config_port = msm_hs_config_port,
.release_port = msm_hs_release_port,
.request_port = msm_hs_request_port,
+ .flush_buffer = msm_hs_flush_buffer,
};
module_init(msm_serial_hs_init);
diff --git a/drivers/tty/smux_debug.c b/drivers/tty/smux_debug.c
new file mode 100644
index 0000000..86377d6
--- /dev/null
+++ b/drivers/tty/smux_debug.c
@@ -0,0 +1,170 @@
+/* drivers/tty/smux_debug.c
+ *
+ * Copyright (c) 2012, Code Aurora Forum. 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.
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/termios.h>
+#include <linux/smux.h>
+#include "smux_private.h"
+
+#define DEBUG_BUFMAX 4096
+
+
+
+/**
+ * smux_dump_ch() - Dumps the information of a channel to the screen.
+ * @buf: Buffer for status message.
+ * @max: Size of status queue.
+ * @lch_number: Number of the logical channel.
+ * @lch: Pointer to the lch_number'th instance of struct smux_lch_t.
+ *
+ */
+static int smux_dump_ch(char *buf, int max, struct smux_lch_t *lch)
+{
+ int bytes_written;
+ long tiocm_bits;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lch->state_lock_lhb1, flags);
+ spin_lock(&lch->tx_lock_lhb2);
+
+ tiocm_bits = msm_smux_tiocm_get_atomic(lch);
+
+ bytes_written = scnprintf(
+ buf, max,
+ "ch%02d: "
+ "%s(%s) "
+ "%c%c%c%c%c "
+ "%d "
+ "%s(%s) "
+ "%c%c\n",
+ lch->lcid,
+ local_lch_state(lch->local_state), lch_mode(lch->local_mode),
+ (tiocm_bits & TIOCM_DSR) ? 'D' : 'd',
+ (tiocm_bits & TIOCM_CTS) ? 'T' : 't',
+ (tiocm_bits & TIOCM_RI) ? 'I' : 'i',
+ (tiocm_bits & TIOCM_CD) ? 'C' : 'c',
+ lch->tx_flow_control ? 'F' : 'f',
+ lch->tx_pending_data_cnt,
+ remote_lch_state(lch->remote_state), lch_mode(lch->remote_mode),
+ (tiocm_bits & TIOCM_DTR) ? 'R' : 'r',
+ (tiocm_bits & TIOCM_RTS) ? 'S' : 's'
+ );
+
+ spin_unlock(&lch->tx_lock_lhb2);
+ spin_unlock_irqrestore(&lch->state_lock_lhb1, flags);
+
+ return bytes_written;
+}
+
+/**
+ * smux_dump_format_ch() - Informs user of format for channel dump
+ * @buf: Buffer for status message.
+ * @max: Size of status queue.
+ *
+ */
+static int smux_dump_format_ch(char *buf, int max)
+{
+ return scnprintf(
+ buf, max,
+ "ch_id "
+ "local state(mode) tiocm "
+ "tx_queue "
+ "remote state(mode) tiocm\n"
+ "local tiocm: DSR(D) CTS(T) RI(I) DCD(C) FLOW_CONTROL(F)\n"
+ "remote tiocm: DTR(R) RTS(S)\n"
+ "A capital letter indicates set, otherwise, it is not set.\n\n"
+ );
+}
+
+/**
+ * smux_debug_ch() - Log following information about each channel
+ * local open, local mode, remote open, remote mode,
+ * tiocm bits, flow control state and transmit queue size.
+ * Returns the number of bytes written to buf.
+ * @buf Buffer for status message
+ * @max Size of status queue
+ *
+ */
+static int smux_debug_ch(char *buf, int max)
+{
+ int ch_id;
+
+ int bytes_written = smux_dump_format_ch(buf, max);
+
+ for (ch_id = 0; ch_id < SMUX_NUM_LOGICAL_CHANNELS; ch_id++) {
+ bytes_written += smux_dump_ch(buf + bytes_written,
+ max - bytes_written,
+ &smux_lch[ch_id]);
+ }
+
+ return bytes_written;
+
+}
+
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int (*fill)(char *buf, int max) = file->private_data;
+ int bsize;
+
+ if (*ppos != 0)
+ return 0;
+
+ bsize = fill(debug_buffer, DEBUG_BUFMAX);
+ return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static const struct file_operations debug_ops = {
+ .read = debug_read,
+ .open = debug_open,
+};
+
+
+static void debug_create(const char *name, mode_t mode,
+ struct dentry *dent,
+ int (*fill)(char *buf, int max))
+{
+ debugfs_create_file(name, mode, dent, fill, &debug_ops);
+}
+
+
+static int __init smux_debugfs_init(void)
+{
+ struct dentry *dent;
+
+ dent = debugfs_create_dir("n_smux", 0);
+ if (IS_ERR(dent))
+ return PTR_ERR(dent);
+
+ debug_create("ch", 0444, dent, smux_debug_ch);
+
+
+ return 0;
+}
+
+late_initcall(smux_debugfs_init);
diff --git a/drivers/tty/smux_private.h b/drivers/tty/smux_private.h
index 4c901c0..195ee0f 100644
--- a/drivers/tty/smux_private.h
+++ b/drivers/tty/smux_private.h
@@ -39,6 +39,62 @@
struct tty_struct;
+/**
+ * Logical Channel Structure. One instance per channel.
+ *
+ * Locking Hierarchy
+ * Each lock has a postfix that describes the locking level. If multiple locks
+ * are required, only increasing lock hierarchy numbers may be locked which
+ * ensures avoiding a deadlock.
+ *
+ * Locking Example
+ * If state_lock_lhb1 is currently held and the TX list needs to be
+ * manipulated, then tx_lock_lhb2 may be locked since it's locking hierarchy
+ * is greater. However, if tx_lock_lhb2 is held, then state_lock_lhb1 may
+ * not be acquired since it would result in a deadlock.
+ *
+ * Note that the Line Discipline locks (*_lha) should always be acquired
+ * before the logical channel locks.
+ */
+struct smux_lch_t {
+ /* channel state */
+ spinlock_t state_lock_lhb1;
+ uint8_t lcid;
+ unsigned local_state;
+ unsigned local_mode;
+ uint8_t local_tiocm;
+ unsigned options;
+
+ unsigned remote_state;
+ unsigned remote_mode;
+ uint8_t remote_tiocm;
+
+ int tx_flow_control;
+ int rx_flow_control_auto;
+ int rx_flow_control_client;
+
+ /* client callbacks and private data */
+ void *priv;
+ void (*notify)(void *priv, int event_type, const void *metadata);
+ int (*get_rx_buffer)(void *priv, void **pkt_priv, void **buffer,
+ int size);
+
+ /* RX Info */
+ struct list_head rx_retry_queue;
+ unsigned rx_retry_queue_cnt;
+ struct delayed_work rx_retry_work;
+
+ /* TX Info */
+ spinlock_t tx_lock_lhb2;
+ struct list_head tx_queue;
+ struct list_head tx_ready_list;
+ unsigned tx_pending_data_cnt;
+ unsigned notify_lwm;
+};
+
+/* Each instance of smux_lch_t */
+extern struct smux_lch_t smux_lch[SMUX_NUM_LOGICAL_CHANNELS];
+
/* Packet header. */
struct smux_hdr_t {
uint16_t magic;
@@ -102,6 +158,16 @@
SMUX_LCH_REMOTE_OPENED,
};
+/* Enum used to report various undefined actions */
+enum {
+ SMUX_UNDEF_LONG,
+ SMUX_UNDEF_SHORT,
+};
+
+long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch);
+const char *local_lch_state(unsigned state);
+const char *remote_lch_state(unsigned state);
+const char *lch_mode(unsigned mode);
int smux_assert_lch_id(uint32_t lcid);
void smux_init_pkt(struct smux_pkt_t *pkt);
@@ -114,6 +180,7 @@
void smux_rx_state_machine(const unsigned char *data, int len, int flag);
void smuxld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count);
+bool smux_remote_is_active(void);
/* testing parameters */
extern int smux_byte_loopback;
diff --git a/drivers/tty/smux_test.c b/drivers/tty/smux_test.c
index 4c255a4..81ac04b 100644
--- a/drivers/tty/smux_test.c
+++ b/drivers/tty/smux_test.c
@@ -690,6 +690,7 @@
};
int i = 0;
int failed = 0;
+ int retry_count = 0;
int ret;
i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
@@ -701,7 +702,13 @@
i += smux_ut_basic_core(buf + i, max - i, test_data, __func__);
subsystem_restart("external_modem");
- msleep(5000);
+
+ do {
+ msleep(500);
+ ++retry_count;
+ UT_ASSERT_INT(retry_count, <, 20);
+ } while (!smux_remote_is_active() && !failed);
+
i += smux_ut_basic_core(buf + i, max - i, test_data, __func__);
break;
}
@@ -721,6 +728,7 @@
static struct smux_mock_callback cb_data;
static int cb_initialized;
int ret;
+ int retry_count;
int i = 0;
int failed = 0;
@@ -763,6 +771,14 @@
/* close port */
ret = msm_smux_close(SMUX_TEST_LCID);
UT_ASSERT_INT(ret, ==, 0);
+
+ /* wait for remote side to finish booting */
+ retry_count = 0;
+ do {
+ msleep(500);
+ ++retry_count;
+ UT_ASSERT_INT(retry_count, <, 20);
+ } while (!smux_remote_is_active() && !failed);
break;
}
@@ -795,6 +811,7 @@
static int cb_initialized;
int i = 0;
int failed = 0;
+ int retry_count;
int ret;
i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
@@ -841,12 +858,16 @@
subsystem_restart("external_modem");
/* verify SSR completed */
- UT_ASSERT_INT(ret, ==, 0);
- UT_ASSERT_INT(
- (int)wait_for_completion_timeout(
- &cb_data.cb_completion, 5*HZ),
- >, 0);
- UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ retry_count = 0;
+ while (cb_data.event_disconnected_ssr == 0) {
+ (void)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ);
+ INIT_COMPLETION(cb_data.cb_completion);
+ ++retry_count;
+ UT_ASSERT_INT(retry_count, <, 10);
+ }
+ if (failed)
+ break;
UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 1);
mock_cb_data_reset(&cb_data);
@@ -854,6 +875,14 @@
/* close port */
ret = msm_smux_close(SMUX_TEST_LCID);
UT_ASSERT_INT(ret, ==, 0);
+
+ /* wait for remote side to finish booting */
+ retry_count = 0;
+ do {
+ msleep(500);
+ ++retry_count;
+ UT_ASSERT_INT(retry_count, <, 20);
+ } while (!smux_remote_is_active() && !failed);
break;
}
@@ -1924,6 +1953,136 @@
return i;
}
+/**
+ * Verify remote flow control (remote TX stop).
+ *
+ * @buf Buffer for status message
+ * @max Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ */
+static int smux_ut_remote_tx_stop(char *buf, int max)
+{
+ static struct smux_mock_callback cb_data;
+ static int cb_initialized;
+ int i = 0;
+ int failed = 0;
+ int ret;
+
+ i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+ pr_err("%s", buf);
+
+ if (!cb_initialized)
+ mock_cb_data_init(&cb_data);
+
+ mock_cb_data_reset(&cb_data);
+ while (!failed) {
+ /* open port for remote loopback */
+ ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+ SMUX_CH_OPTION_REMOTE_LOOPBACK, 0);
+ UT_ASSERT_INT(ret, ==, 0);
+
+ ret = msm_smux_open(SMUX_TEST_LCID, &cb_data, smux_mock_cb,
+ get_rx_buffer);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ), >, 0);
+ UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+ mock_cb_data_reset(&cb_data);
+
+ /* send 1 packet and verify response */
+ ret = msm_smux_write(SMUX_TEST_LCID, (void *)1,
+ test_array, sizeof(test_array));
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ UT_ASSERT_INT(cb_data.event_write_done, ==, 1);
+
+ INIT_COMPLETION(cb_data.cb_completion);
+ if (!cb_data.event_read_done) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ }
+ UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+ mock_cb_data_reset(&cb_data);
+
+ /* enable flow control */
+ UT_ASSERT_INT(smux_lch[SMUX_TEST_LCID].tx_flow_control, ==, 0);
+ ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+ SMUX_CH_OPTION_REMOTE_TX_STOP, 0);
+ UT_ASSERT_INT(ret, ==, 0);
+
+ /* wait for remote echo and clear our tx_flow control */
+ msleep(500);
+ UT_ASSERT_INT(smux_lch[SMUX_TEST_LCID].tx_flow_control, ==, 1);
+ smux_lch[SMUX_TEST_LCID].tx_flow_control = 0;
+
+ /* Send 1 packet and verify no response */
+ ret = msm_smux_write(SMUX_TEST_LCID, (void *)2,
+ test_array, sizeof(test_array));
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ UT_ASSERT_INT(cb_data.event_write_done, ==, 1);
+ UT_ASSERT_INT(cb_data.event_read_done, ==, 0);
+ UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, 1*HZ),
+ ==, 0);
+ UT_ASSERT_INT(cb_data.event_read_done, ==, 0);
+ mock_cb_data_reset(&cb_data);
+
+ /* disable flow control and verify response is received */
+ UT_ASSERT_INT(cb_data.event_read_done, ==, 0);
+ ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+ 0, SMUX_CH_OPTION_REMOTE_TX_STOP);
+ UT_ASSERT_INT(ret, ==, 0);
+
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+ mock_cb_data_reset(&cb_data);
+
+ /* close port */
+ ret = msm_smux_close(SMUX_TEST_LCID);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
+ UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+ break;
+ }
+
+ if (!failed) {
+ i += scnprintf(buf + i, max - i, "\tOK\n");
+ } else {
+ pr_err("%s: Failed\n", __func__);
+ i += scnprintf(buf + i, max - i, "\tFailed\n");
+ i += mock_cb_data_print(&cb_data, buf + i, max - i);
+ msm_smux_set_ch_option(SMUX_TEST_LCID,
+ 0, SMUX_CH_OPTION_REMOTE_TX_STOP);
+ msm_smux_close(SMUX_TEST_LCID);
+ }
+ mock_cb_data_reset(&cb_data);
+ return i;
+}
+
static char debug_buffer[DEBUG_BUFMAX];
static ssize_t debug_read(struct file *file, char __user *buf,
@@ -1961,7 +2120,7 @@
{
struct dentry *dent;
- dent = debugfs_create_dir("n_smux", 0);
+ dent = debugfs_create_dir("n_smux_test", 0);
if (IS_ERR(dent))
return PTR_ERR(dent);
@@ -1995,6 +2154,8 @@
smux_ut_remote_ssr_open);
debug_create("ut_remote_ssr_rx_buff_retry", 0444, dent,
smux_ut_remote_ssr_rx_buff_retry);
+ debug_create("ut_remote_tx_stop", 0444, dent,
+ smux_ut_remote_tx_stop);
return 0;
}
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 15eed46..f67c8c8 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -75,7 +75,7 @@
*****************************************************************************/
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-#define ATDTW_SET_DELAY 100 /* 100msec delay */
+#define USB_MAX_TIMEOUT 100 /* 100msec timeout */
#define EP_PRIME_CHECK_DELAY (jiffies + msecs_to_jiffies(1000))
#define MAX_PRIME_CHECK_RETRY 3 /*Wait for 3sec for EP prime failure */
@@ -177,7 +177,8 @@
/* maximum number of enpoints: valid only after hw_device_reset() */
static unsigned hw_ep_max;
-
+static void dbg_usb_op_fail(u8 addr, const char *name,
+ const struct ci13xxx_ep *mep);
/**
* hw_ep_bit: calculates the bit number
* @num: endpoint number
@@ -381,6 +382,27 @@
return 0;
}
+static void debug_ept_flush_info(int ep_num, int dir)
+{
+ struct ci13xxx *udc = _udc;
+ struct ci13xxx_ep *mep;
+
+ if (dir)
+ mep = &udc->ci13xxx_ep[ep_num + hw_ep_max/2];
+ else
+ mep = &udc->ci13xxx_ep[ep_num];
+
+ pr_err_ratelimited("USB Registers\n");
+ pr_err_ratelimited("USBCMD:%x\n", hw_cread(CAP_USBCMD, ~0));
+ pr_err_ratelimited("USBSTS:%x\n", hw_cread(CAP_USBSTS, ~0));
+ pr_err_ratelimited("ENDPTLISTADDR:%x\n",
+ hw_cread(CAP_ENDPTLISTADDR, ~0));
+ pr_err_ratelimited("PORTSC:%x\n", hw_cread(CAP_PORTSC, ~0));
+ pr_err_ratelimited("USBMODE:%x\n", hw_cread(CAP_USBMODE, ~0));
+ pr_err_ratelimited("ENDPTSTAT:%x\n", hw_cread(CAP_ENDPTSTAT, ~0));
+
+ dbg_usb_op_fail(0xFF, "FLUSHF", mep);
+}
/**
* hw_ep_flush: flush endpoint fifo (execute without interruption)
* @num: endpoint number
@@ -390,13 +412,25 @@
*/
static int hw_ep_flush(int num, int dir)
{
+ ktime_t start, diff;
int n = hw_ep_bit(num, dir);
+ start = ktime_get();
do {
/* flush any pending transfer */
hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n));
- while (hw_cread(CAP_ENDPTFLUSH, BIT(n)))
+ while (hw_cread(CAP_ENDPTFLUSH, BIT(n))) {
cpu_relax();
+ diff = ktime_sub(ktime_get(), start);
+ if (ktime_to_ms(diff) > USB_MAX_TIMEOUT) {
+ printk_ratelimited(KERN_ERR
+ "%s: Failed to flush ep#%d %s\n",
+ __func__, num,
+ dir ? "IN" : "OUT");
+ debug_ept_flush_info(num, dir);
+ return 0;
+ }
+ }
} while (hw_cread(CAP_ENDPTSTAT, BIT(n)));
return 0;
@@ -1006,29 +1040,30 @@
}
/**
- * dbg_prime_fail: prints a PRIME FAIL event
+ * dbg_usb_op_fail: prints USB Operation FAIL event
* @addr: endpoint address
* @mEp: endpoint structure
*/
-static void dbg_prime_fail(u8 addr, const char *name,
- const struct ci13xxx_ep *mEp)
+static void dbg_usb_op_fail(u8 addr, const char *name,
+ const struct ci13xxx_ep *mep)
{
char msg[DBG_DATA_MSG];
struct ci13xxx_req *req;
struct list_head *ptr = NULL;
- if (mEp != NULL) {
+ if (mep != NULL) {
scnprintf(msg, sizeof(msg),
- "PRIME fail EP%d%s QH:%08X",
- mEp->num, mEp->dir ? "IN" : "OUT", mEp->qh.ptr->cap);
+ "%s Fail EP%d%s QH:%08X",
+ name, mep->num,
+ mep->dir ? "IN" : "OUT", mep->qh.ptr->cap);
dbg_print(addr, name, 0, msg);
scnprintf(msg, sizeof(msg),
"cap:%08X %08X %08X\n",
- mEp->qh.ptr->curr, mEp->qh.ptr->td.next,
- mEp->qh.ptr->td.token);
+ mep->qh.ptr->curr, mep->qh.ptr->td.next,
+ mep->qh.ptr->td.token);
dbg_print(addr, "QHEAD", 0, msg);
- list_for_each(ptr, &mEp->qh.queue) {
+ list_for_each(ptr, &mep->qh.queue) {
req = list_entry(ptr, struct ci13xxx_req, queue);
scnprintf(msg, sizeof(msg),
"%08X:%08X:%08X\n",
@@ -1703,52 +1738,52 @@
static void ep_prime_timer_func(unsigned long data)
{
- struct ci13xxx_ep *mEp = (struct ci13xxx_ep *)data;
+ struct ci13xxx_ep *mep = (struct ci13xxx_ep *)data;
struct ci13xxx_req *req;
struct list_head *ptr = NULL;
- int n = hw_ep_bit(mEp->num, mEp->dir);
+ int n = hw_ep_bit(mep->num, mep->dir);
unsigned long flags;
- spin_lock_irqsave(mEp->lock, flags);
+ spin_lock_irqsave(mep->lock, flags);
if (!hw_cread(CAP_ENDPTPRIME, BIT(n)))
goto out;
- if (list_empty(&mEp->qh.queue))
+ if (list_empty(&mep->qh.queue))
goto out;
- req = list_entry(mEp->qh.queue.next, struct ci13xxx_req, queue);
+ req = list_entry(mep->qh.queue.next, struct ci13xxx_req, queue);
mb();
if (!(TD_STATUS_ACTIVE & req->ptr->token))
goto out;
- mEp->prime_timer_count++;
- if (mEp->prime_timer_count == MAX_PRIME_CHECK_RETRY) {
- mEp->prime_timer_count = 0;
+ mep->prime_timer_count++;
+ if (mep->prime_timer_count == MAX_PRIME_CHECK_RETRY) {
+ mep->prime_timer_count = 0;
pr_info("ep%d dir:%s QH:cap:%08x cur:%08x next:%08x tkn:%08x\n",
- mEp->num, mEp->dir ? "IN" : "OUT",
- mEp->qh.ptr->cap, mEp->qh.ptr->curr,
- mEp->qh.ptr->td.next, mEp->qh.ptr->td.token);
- list_for_each(ptr, &mEp->qh.queue) {
+ mep->num, mep->dir ? "IN" : "OUT",
+ mep->qh.ptr->cap, mep->qh.ptr->curr,
+ mep->qh.ptr->td.next, mep->qh.ptr->td.token);
+ list_for_each(ptr, &mep->qh.queue) {
req = list_entry(ptr, struct ci13xxx_req, queue);
pr_info("\treq:%08xnext:%08xtkn:%08xpage0:%08xsts:%d\n",
req->dma, req->ptr->next,
req->ptr->token, req->ptr->page[0],
req->req.status);
}
- dbg_prime_fail(0xFF, "PRIMEF", mEp);
- mEp->prime_fail_count++;
+ dbg_usb_op_fail(0xFF, "PRIMEF", mep);
+ mep->prime_fail_count++;
} else {
- mod_timer(&mEp->prime_timer, EP_PRIME_CHECK_DELAY);
+ mod_timer(&mep->prime_timer, EP_PRIME_CHECK_DELAY);
}
- spin_unlock_irqrestore(mEp->lock, flags);
+ spin_unlock_irqrestore(mep->lock, flags);
return;
out:
- mEp->prime_timer_count = 0;
- spin_unlock_irqrestore(mEp->lock, flags);
+ mep->prime_timer_count = 0;
+ spin_unlock_irqrestore(mep->lock, flags);
}
@@ -1874,7 +1909,7 @@
tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n));
diff = ktime_sub(ktime_get(), start);
/* poll for max. 100ms */
- if (ktime_to_ms(diff) > ATDTW_SET_DELAY) {
+ if (ktime_to_ms(diff) > USB_MAX_TIMEOUT) {
if (hw_cread(CAP_USBCMD, USBCMD_ATDTW))
break;
printk_ratelimited(KERN_ERR
@@ -2080,7 +2115,6 @@
*/
static int _gadget_stop_activity(struct usb_gadget *gadget)
{
- struct usb_ep *ep;
struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
unsigned long flags;
@@ -2101,20 +2135,10 @@
gadget->host_request = 0;
gadget->otg_srp_reqd = 0;
- /* flush all endpoints */
- gadget_for_each_ep(ep, gadget) {
- usb_ep_fifo_flush(ep);
- }
+ udc->driver->disconnect(gadget);
usb_ep_fifo_flush(&udc->ep0out.ep);
usb_ep_fifo_flush(&udc->ep0in.ep);
- udc->driver->disconnect(gadget);
-
- /* make sure to disable all endpoints */
- gadget_for_each_ep(ep, gadget) {
- usb_ep_disable(ep);
- }
-
if (udc->status != NULL) {
usb_ep_free_request(&udc->ep0in.ep, udc->status);
udc->status = NULL;
@@ -3462,8 +3486,7 @@
void __iomem *regs)
{
struct ci13xxx *udc;
- struct ci13xxx_platform_data *pdata =
- (struct ci13xxx_platform_data *)(dev->platform_data);
+ struct ci13xxx_platform_data *pdata;
int retval = 0, i;
trace("%p, %p, %p", dev, regs, driver->name);
@@ -3492,6 +3515,7 @@
INIT_LIST_HEAD(&udc->gadget.ep_list);
udc->gadget.ep0 = NULL;
+ pdata = dev->platform_data;
if (pdata)
udc->gadget.usb_core_id = pdata->usb_core_id;
diff --git a/drivers/usb/gadget/u_data_hsic.c b/drivers/usb/gadget/u_data_hsic.c
index 89d2887..44c36db 100644
--- a/drivers/usb/gadget/u_data_hsic.c
+++ b/drivers/usb/gadget/u_data_hsic.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, Linux Foundation. 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
@@ -633,10 +633,10 @@
ghsic_data_free_buffers(port);
- data_bridge_close(port->brdg.ch_id);
-
+ cancel_work_sync(&port->connect_w);
+ if (test_and_clear_bit(CH_OPENED, &port->bridge_sts))
+ data_bridge_close(port->brdg.ch_id);
clear_bit(CH_READY, &port->bridge_sts);
- clear_bit(CH_OPENED, &port->bridge_sts);
return 0;
}
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index 0b35f0d..ce50a99 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, Linux Foundation. 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
@@ -284,6 +284,10 @@
unsigned long flags;
struct ks_bridge *ksb = fp->private_data;
+
+ if (count > MAX_DATA_PKT_SIZE)
+ count = MAX_DATA_PKT_SIZE;
+
pkt = ksb_alloc_data_pkt(count, GFP_KERNEL, ksb);
if (IS_ERR(pkt)) {
pr_err("unable to allocate data packet");
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index 92524fd..d473275 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, Linux Foundation. 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
@@ -362,6 +362,9 @@
dev_dbg(&dev->intf->dev, "%s:\n", __func__);
+ cancel_work_sync(&dev->kevent);
+ cancel_work_sync(&dev->process_rx_w);
+
usb_unlink_anchored_urbs(&dev->tx_active);
usb_unlink_anchored_urbs(&dev->rx_active);
usb_unlink_anchored_urbs(&dev->delayed);
@@ -1025,9 +1028,6 @@
usb_set_intfdata(intf, NULL);
__dev[chid] = NULL;
- cancel_work_sync(&dev->process_rx_w);
- cancel_work_sync(&dev->kevent);
-
/*free rx urbs*/
head = &dev->rx_idle;
spin_lock_irqsave(&dev->rx_done.lock, flags);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 7271083..d4ad8ae 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -2366,6 +2366,7 @@
break;
} else {
pr_debug("chg_work cancel");
+ clear_bit(A_BUS_REQ, &motg->inputs);
cancel_delayed_work_sync(&motg->chg_work);
cancel_delayed_work_sync(&motg->check_ta_work);
motg->chg_state = USB_CHG_STATE_UNDEFINED;
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 7b8493d..31f98be 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -2,7 +2,7 @@
*
* MSM MDP Interface (used by framebuffer core)
*
- * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
* Copyright (C) 2007 Google Incorporated
*
* This software is licensed under the terms of the GNU General Public
@@ -951,12 +951,10 @@
int ret = 0;
mutex_lock(&mgmt->mdp_hist_mutex);
- if (mgmt->mdp_is_hist_start == TRUE) {
- if (en)
- ret = mdp_histogram_enable(mgmt);
- else
- ret = mdp_histogram_disable(mgmt);
- }
+ if (mgmt->mdp_is_hist_start && !mgmt->mdp_is_hist_data && en)
+ ret = mdp_histogram_enable(mgmt);
+ else if (mgmt->mdp_is_hist_data && !en)
+ ret = mdp_histogram_disable(mgmt);
mutex_unlock(&mgmt->mdp_hist_mutex);
if (en == false)
@@ -1054,7 +1052,6 @@
mgmt->mdp_is_hist_start = FALSE;
if (!mfd->panel_power_on) {
- mgmt->mdp_is_hist_data = FALSE;
if (mgmt->hist != NULL) {
mgmt->hist = NULL;
complete(&mgmt->mdp_hist_comp);
@@ -1419,32 +1416,47 @@
u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd)
{
- u32 frame_rate = 0, total_pixel;
+ u32 frame_rate = 0, pixel_rate = 0, total_pixel;
struct msm_panel_info *panel_info = &mfd->panel_info;
+
+ pixel_rate =
+ (panel_info->type == MIPI_CMD_PANEL ||
+ panel_info->type == MIPI_VIDEO_PANEL) ?
+ panel_info->mipi.dsi_pclk_rate :
+ panel_info->clk_rate;
+
+ if (!pixel_rate)
+ pr_warn("%s pixel rate is zero\n", __func__);
+
+ total_pixel =
+ (panel_info->lcdc.h_back_porch +
+ panel_info->lcdc.h_front_porch +
+ panel_info->lcdc.h_pulse_width +
+ panel_info->xres) *
+ (panel_info->lcdc.v_back_porch +
+ panel_info->lcdc.v_front_porch +
+ panel_info->lcdc.v_pulse_width +
+ panel_info->yres);
+
+ if (total_pixel)
+ frame_rate = pixel_rate / total_pixel;
+ else
+ pr_warn("%s total pixels are zero\n", __func__);
+
if (mfd->dest == DISPLAY_LCD) {
if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1)
frame_rate = panel_info->lcd.refx100 / (100 * 2);
- else
+ else if (panel_info->type != MIPI_CMD_PANEL)
frame_rate = panel_info->lcd.refx100 / 100;
- } else {
- if (panel_info->type == MIPI_VIDEO_PANEL) {
- frame_rate = panel_info->mipi.frame_rate;
- } else {
- total_pixel = (panel_info->lcdc.h_back_porch +
- panel_info->lcdc.h_front_porch +
- panel_info->lcdc.h_pulse_width +
- panel_info->xres) *
- (panel_info->lcdc.v_back_porch +
- panel_info->lcdc.v_front_porch +
- panel_info->lcdc.v_pulse_width +
- panel_info->yres);
- if (total_pixel)
- frame_rate = panel_info->clk_rate /
- total_pixel;
- }
}
- if (frame_rate == 0)
+
+ if (frame_rate == 0) {
frame_rate = DEFAULT_FRAME_RATE;
+ pr_warn("%s frame rate=%d is default\n", __func__, frame_rate);
+ }
+ pr_debug("%s frame rate=%d total_pixel=%d, pixel_rate=%d\n", __func__,
+ frame_rate, total_pixel, pixel_rate);
+
return frame_rate;
}
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 7bb027c..9b05d2a 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+/*
+ * Copyright (c) 2009-2013, The Linux Foundation. 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
@@ -1932,6 +1933,7 @@
alpha_drop = 0; /* per stage */
/* alpha channel is lost on VG pipe when using QSEED or M/N */
if (s_pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
+ s_pipe->alpha_enable &&
((s_pipe->op_mode & MDP4_OP_SCALEY_EN) ||
(s_pipe->op_mode & MDP4_OP_SCALEX_EN)) &&
!(s_pipe->op_mode & MDP4_OP_SCALEY_PIXEL_RPT))
@@ -3346,9 +3348,6 @@
if (mfd == NULL)
return -ENODEV;
- if (!mfd->panel_power_on) /* suspended */
- return -EPERM;
-
pipe = mdp4_overlay_ndx2pipe(req->id);
if (pipe == NULL) {
mdp4_stat.err_play++;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 8a5ae18..23e6d1d 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. 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
@@ -251,6 +251,7 @@
}
static void mdp4_dsi_cmd_blt_ov_update(struct mdp4_overlay_pipe *pipe);
+static int mdp4_dsi_cmd_clk_check(struct vsycn_ctrl *vctrl);
int mdp4_dsi_cmd_pipe_commit(int cndx, int wait)
{
@@ -275,10 +276,11 @@
mdp_update_pm(vctrl->mfd, vctrl->vsync_time);
- if (vp->update_cnt == 0) {
- mutex_unlock(&vctrl->update_lock);
- return cnt;
- }
+ /*
+ * allow stage_commit without pipes queued
+ * (vp->update_cnt == 0) to unstage pipes after
+ * overlay_unset
+ */
vctrl->update_ndx++;
vctrl->update_ndx &= 0x01;
@@ -290,6 +292,9 @@
}
mutex_unlock(&vctrl->update_lock);
+ if (mdp4_dsi_cmd_clk_check(vctrl) < 0)
+ return 0;
+
/* free previous committed iommu back to pool */
mdp4_overlay_iommu_unmap_freelist(mixer);
@@ -861,6 +866,9 @@
pipe = vctrl->base_pipe;
}
+ /* TE enabled */
+ mdp4_mipi_vsync_enable(mfd, pipe, 0);
+
MDP_OUTP(MDP_BASE + 0x021c, 10); /* read pointer */
/*
@@ -1131,35 +1139,16 @@
}
}
-void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd)
+static int mdp4_dsi_cmd_clk_check(struct vsycn_ctrl *vctrl)
{
- int cndx = 0;
- struct vsycn_ctrl *vctrl;
- struct mdp4_overlay_pipe *pipe;
- unsigned long flags;
int clk_set_on = 0;
-
- mutex_lock(&mfd->dma->ov_mutex);
- vctrl = &vsync_ctrl_db[cndx];
-
- if (!mfd->panel_power_on) {
- mutex_unlock(&mfd->dma->ov_mutex);
- return;
- }
-
- pipe = vctrl->base_pipe;
- if (pipe == NULL) {
- pr_err("%s: NO base pipe\n", __func__);
- mutex_unlock(&mfd->dma->ov_mutex);
- return;
- }
+ unsigned long flags;
mutex_lock(&vctrl->update_lock);
if (atomic_read(&vctrl->suspend)) {
mutex_unlock(&vctrl->update_lock);
- mutex_unlock(&mfd->dma->ov_mutex);
pr_err("%s: suspended, no more pan display\n", __func__);
- return;
+ return -EPERM;
}
spin_lock_irqsave(&vctrl->spin_lock, flags);
@@ -1181,6 +1170,35 @@
mutex_unlock(&vctrl->update_lock);
+ return 0;
+}
+
+void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd)
+{
+ int cndx = 0;
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+
+ mutex_lock(&mfd->dma->ov_mutex);
+ vctrl = &vsync_ctrl_db[cndx];
+
+ if (!mfd->panel_power_on) {
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
+
+ pipe = vctrl->base_pipe;
+ if (pipe == NULL) {
+ pr_err("%s: NO base pipe\n", __func__);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
+
+ if (mdp4_dsi_cmd_clk_check(vctrl) < 0) {
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
+
if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE) {
mdp4_mipi_vsync_enable(mfd, pipe, 0);
mdp4_overlay_setup_pipe_addr(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index f31dd98..6239cce 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -170,10 +170,11 @@
mdp_update_pm(vctrl->mfd, vctrl->vsync_time);
- if (vp->update_cnt == 0) {
- mutex_unlock(&vctrl->update_lock);
- return cnt;
- }
+ /*
+ * allow stage_commit without pipes queued
+ * (vp->update_cnt == 0) to unstage pipes after
+ * overlay_unset
+ */
vctrl->update_ndx++;
vctrl->update_ndx &= 0x01;
@@ -1137,7 +1138,7 @@
mdp4_overlay_mdp_perf_upd(mfd, 1);
cnt = mdp4_dsi_video_pipe_commit(cndx, 0);
- if (cnt) {
+ if (cnt >= 0) {
if (pipe->ov_blt_addr)
mdp4_dsi_video_wait4ov(cndx);
else
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 7f3e287..34983a4 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -188,10 +188,11 @@
mdp_update_pm(vctrl->mfd, vctrl->vsync_time);
- if (vp->update_cnt == 0) {
- mutex_unlock(&vctrl->update_lock);
- return 0;
- }
+ /*
+ * allow stage_commit without pipes queued
+ * (vp->update_cnt == 0) to unstage pipes after
+ * overlay_unset
+ */
vctrl->update_ndx++;
vctrl->update_ndx &= 0x01;
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 7a32001..9feaaca 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -174,10 +174,11 @@
mdp_update_pm(vctrl->mfd, vctrl->vsync_time);
- if (vp->update_cnt == 0) {
- mutex_unlock(&vctrl->update_lock);
- return 0;
- }
+ /*
+ * allow stage_commit without pipes queued
+ * (vp->update_cnt == 0) to unstage pipes after
+ * overlay_unset
+ */
vctrl->update_ndx++;
vctrl->update_ndx &= 0x01;
@@ -977,7 +978,7 @@
mdp4_overlay_mdp_perf_upd(mfd, 1);
cnt = mdp4_lcdc_pipe_commit(cndx, 0);
- if (cnt) {
+ if (cnt >= 0) {
if (pipe->ov_blt_addr)
mdp4_lcdc_wait4ov(cndx);
else
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 42b748c..8e0c3d8 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -343,10 +343,11 @@
pipe = vctrl->base_pipe;
mixer = pipe->mixer_num;
- if (vp->update_cnt == 0) {
- mutex_unlock(&vctrl->update_lock);
- return cnt;
- }
+ /*
+ * allow stage_commit without pipes queued
+ * (vp->update_cnt == 0) to unstage pipes after
+ * overlay_unset
+ */
vctrl->update_ndx++;
vctrl->update_ndx &= 0x01;
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index cfbff9a..89657d9 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/*
+ * Copyright (c) 2011-2013, The Linux Foundation. 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
@@ -241,7 +242,7 @@
/*Turning on DMA_P block*/
mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
}
-
+ mdp_histogram_ctrl_all(TRUE);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -251,6 +252,7 @@
int mdp_dsi_video_off(struct platform_device *pdev)
{
int ret = 0;
+ mdp_histogram_ctrl_all(FALSE);
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c
index c51a99a..668ce53 100644
--- a/drivers/video/msm/mdp_dma_lcdc.c
+++ b/drivers/video/msm/mdp_dma_lcdc.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2008-2009, 2012 Code Aurora Forum. All rights reserved.
+/*
+ * Copyright (c) 2008-2009, 2012-2013 The Linux Foundation. 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
@@ -308,9 +309,11 @@
MDP_OUTP(MDP_BASE + timer_base, 1);
mdp_pipe_ctrl(block, MDP_BLOCK_POWER_ON, FALSE);
}
+ mdp_histogram_ctrl_all(TRUE);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
return ret;
}
@@ -329,6 +332,7 @@
timer_base = DTV_BASE;
}
#endif
+ mdp_histogram_ctrl_all(FALSE);
down(&mfd->dma->mutex);
/* MDP cmd block enable */
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index ccc0e73..f071d7b 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1,9 +1,10 @@
-/* drivers/video/msm/msm_fb.c
+/*
+ * drivers/video/msm/msm_fb.c
*
* Core MSM framebuffer driver.
*
* Copyright (C) 2007 Google Incorporated
- * Copyright (c) 2008-2013, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2013, 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
@@ -545,10 +546,6 @@
if ((!mfd) || (mfd->key != MFD_KEY))
return 0;
- if (mfd->msmfb_no_update_notify_timer.function)
- del_timer(&mfd->msmfb_no_update_notify_timer);
- complete(&mfd->msmfb_no_update_notify);
-
/*
* suspend this channel
*/
@@ -942,6 +939,11 @@
mfd->op_enable = FALSE;
curr_pwr_state = mfd->panel_power_on;
mfd->panel_power_on = FALSE;
+
+ if (mfd->msmfb_no_update_notify_timer.function)
+ del_timer(&mfd->msmfb_no_update_notify_timer);
+ complete(&mfd->msmfb_no_update_notify);
+
bl_updated = 0;
/* clean fb to prevent displaying old fb */
@@ -1368,27 +1370,7 @@
var->yres_virtual = panel_info->yres * mfd->fb_page +
((PAGE_SIZE - remainder)/fix->line_length) * mfd->fb_page;
var->bits_per_pixel = bpp * 8; /* FrameBuffer color depth */
- if (mfd->dest == DISPLAY_LCD) {
- if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1)
- var->reserved[3] = panel_info->lcd.refx100 / (100 * 2);
- else
- var->reserved[3] = panel_info->lcd.refx100 / 100;
- } else {
- if (panel_info->type == MIPI_VIDEO_PANEL) {
- var->reserved[3] = panel_info->mipi.frame_rate;
- } else {
- var->reserved[3] = panel_info->clk_rate /
- ((panel_info->lcdc.h_back_porch +
- panel_info->lcdc.h_front_porch +
- panel_info->lcdc.h_pulse_width +
- panel_info->xres) *
- (panel_info->lcdc.v_back_porch +
- panel_info->lcdc.v_front_porch +
- panel_info->lcdc.v_pulse_width +
- panel_info->yres));
- }
- }
- pr_debug("reserved[3] %u\n", var->reserved[3]);
+ var->reserved[3] = mdp_get_panel_framerate(mfd);
/*
* id field for fb app
@@ -1904,6 +1886,7 @@
{
struct mdp_display_commit disp_commit;
memset(&disp_commit, 0, sizeof(disp_commit));
+ disp_commit.var = *var;
disp_commit.wait_for_finish = TRUE;
return msm_fb_pan_display_ex(info, &disp_commit);
}
@@ -1998,7 +1981,7 @@
}
mdp_set_dma_pan_info(info, dirtyPtr,
- (var->activate == FB_ACTIVATE_VBL));
+ (var->activate & FB_ACTIVATE_VBL));
/* async call */
mdp_dma_pan_update(info);
@@ -3184,6 +3167,9 @@
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
struct msm_fb_panel_data *pdata;
+ if (!mfd->panel_power_on) /* suspended */
+ return -EPERM;
+
if (mfd->overlay_play_enable == 0) /* nothing to do */
return 0;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
index a82feb9..4909725 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. 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
@@ -198,8 +198,7 @@
ddl->client_state = DDL_CLIENT_OPEN;
ddl->codec_data.hdr.decoding = decoding;
ddl->decoding = decoding;
- if (!res_trk_check_for_sec_session())
- ddl_set_default_meta_data_hdr(ddl);
+ ddl_set_default_meta_data_hdr(ddl);
ddl_set_initial_default_values(ddl);
*ddl_handle = (u32 *) ddl;
} else {
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc_pix_cache.c b/drivers/video/msm/vidc/1080p/ddl/vidc_pix_cache.c
index 6870525..5206182 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc_pix_cache.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc_pix_cache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, Linux Foundation. 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
@@ -214,7 +214,7 @@
VIDC_HWIO_IN(REG_261029, &dmi_cfg_reg);
dmi_cfg_reg &= (~HWIO_REG_261029_DMI_RAM_SEL_BMSK);
dmi_cfg_reg |= VIDC_SETFIELD(ram_select,
- HWIO_REG_261029_AUTO_INC_EN_SHFT,
+ HWIO_REG_261029_DMI_RAM_SEL_SHFT,
HWIO_REG_261029_DMI_RAM_SEL_BMSK);
VIDC_HWIO_OUT(REG_261029, dmi_cfg_reg);
}
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index a337d7b..a6af235 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, Linux Foundation. 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
@@ -2011,8 +2011,11 @@
return VCD_ERR_FAIL;
}
- if (orig_frame != transc->ip_buf_entry)
+ if (orig_frame != transc->ip_buf_entry) {
+ VCD_MSG_HIGH("%s: free duplicate buffer", __func__);
kfree(transc->ip_buf_entry);
+ transc->ip_buf_entry = NULL;
+ }
transc->ip_buf_entry = NULL;
transc->input_done = true;
@@ -2781,6 +2784,7 @@
struct vcd_frame_data *frm_entry;
u32 rc = VCD_S_SUCCESS;
u32 eos_handled = false;
+ u32 duplicate_buffer = false;
VCD_MSG_LOW("vcd_handle_input_frame:");
@@ -2864,6 +2868,8 @@
buf_entry->allocated = orig_frame->allocated;
buf_entry->in_use = 1; /* meaningless for the dupe buffers */
buf_entry->frame = orig_frame->frame;
+ duplicate_buffer = true;
+ VCD_MSG_HIGH("%s: duplicate buffer", __func__);
} else
buf_entry = orig_frame;
@@ -2887,6 +2893,10 @@
if (VCD_FAILED(rc) || eos_handled) {
VCD_MSG_HIGH("rc = 0x%x, eos_handled = %d", rc,
eos_handled);
+ if ((duplicate_buffer) && (buf_entry)) {
+ kfree(buf_entry);
+ buf_entry = NULL;
+ }
return rc;
}
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 3ef736f..28c80ad 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -445,3 +445,4 @@
header-y += idle_stats_device.h
header-y += genlock.h
header-y += msm_audio_amrwb.h
+header-y += msm_audio_amrwbplus.h
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 03c69d0..4bd8885 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2013, The Linux Foundation. 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
@@ -18,14 +18,14 @@
#define EVENT_MASKS_TYPE 4
#define PKT_TYPE 8
#define DEINIT_TYPE 16
-#define USER_SPACE_LOG_TYPE 32
+#define USER_SPACE_DATA_TYPE 32
#define DCI_DATA_TYPE 64
#define USB_MODE 1
#define MEMORY_DEVICE_MODE 2
#define NO_LOGGING_MODE 3
#define UART_MODE 4
#define SOCKET_MODE 5
-
+#define CALLBACK_MODE 6
/* different values that go in for diag_data_type */
#define DATA_TYPE_EVENT 0
#define DATA_TYPE_F3 1
@@ -43,6 +43,7 @@
#define DIAG_IOCTL_DCI_REG 23
#define DIAG_IOCTL_DCI_STREAM_INIT 24
#define DIAG_IOCTL_DCI_HEALTH_STATS 25
+#define DIAG_IOCTL_REMOTE_DEV 32
/* PC Tools IDs */
#define APQ8060_TOOLS_ID 4062
@@ -111,7 +112,7 @@
/* This needs to be modified manually now, when we add
a new RANGE of SSIDs to the msg_mask_tbl */
#define MSG_MASK_TBL_CNT 24
-#define EVENT_LAST_ID 0x08AD
+#define EVENT_LAST_ID 0x099F
#define MSG_SSID_0 0
#define MSG_SSID_0_LAST 93
@@ -674,24 +675,24 @@
};
static const uint32_t msg_bld_masks_22[] = {
- MSG_LVL_HIGH,
- MSG_LVL_HIGH,
- MSG_LVL_HIGH,
- MSG_LVL_HIGH,
- MSG_LVL_HIGH,
- MSG_LVL_HIGH,
- MSG_LVL_HIGH,
- MSG_LVL_HIGH,
- MSG_LVL_HIGH,
- MSG_LVL_HIGH,
- MSG_LVL_HIGH,
- MSG_LVL_HIGH
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW
};
/* LOG CODES */
#define LOG_0 0x0
-#define LOG_1 0x15A7
+#define LOG_1 0x1750
#define LOG_2 0x0
#define LOG_3 0x0
#define LOG_4 0x4910
diff --git a/include/linux/msm_audio_amrwbplus.h b/include/linux/msm_audio_amrwbplus.h
new file mode 100644
index 0000000..aa17117
--- /dev/null
+++ b/include/linux/msm_audio_amrwbplus.h
@@ -0,0 +1,18 @@
+#ifndef __MSM_AUDIO_AMR_WB_PLUS_H
+#define __MSM_AUDIO_AMR_WB_PLUS_H
+
+#define AUDIO_GET_AMRWBPLUS_CONFIG_V2 _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+2), struct msm_audio_amrwbplus_config_v2)
+#define AUDIO_SET_AMRWBPLUS_CONFIG_V2 _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+3), struct msm_audio_amrwbplus_config_v2)
+
+struct msm_audio_amrwbplus_config_v2 {
+ unsigned int size_bytes;
+ unsigned int version;
+ unsigned int num_channels;
+ unsigned int amr_band_mode;
+ unsigned int amr_dtx_mode;
+ unsigned int amr_frame_fmt;
+ unsigned int amr_lsf_idx;
+};
+#endif /* __MSM_AUDIO_AMR_WB_PLUS_H */
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index 09c584b..d51acf7 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, Code Aurora Forum. 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
@@ -73,6 +73,13 @@
#define ION_SECURE (1 << ION_HEAP_ID_RESERVED)
/**
+ * Flag for clients to force contiguous memort allocation
+ *
+ * Use of this flag is carefully monitored!
+ */
+#define ION_FORCE_CONTIGUOUS (1 << 30)
+
+/**
* Macro should be used with ion_heap_ids defined above.
*/
#define ION_HEAP(bit) (1 << (bit))
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 7241e90..90d01da 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1014,7 +1014,9 @@
#define CFG_CONFIG_VREG_ARRAY 52
#define CFG_CONFIG_CLK_ARRAY 53
#define CFG_GPIO_OP 54
-#define CFG_MAX 55
+#define CFG_SET_VISION_MODE 55
+#define CFG_SET_VISION_AE 56
+#define CFG_MAX 57
#define MOVE_NEAR 0
@@ -1672,6 +1674,8 @@
int is_autoflash;
struct mirror_flip mirror_flip;
void *setting;
+ int32_t vision_mode_enable;
+ int32_t vision_ae;
} cfg;
};
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 7dc95af..73ac1b0 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -913,14 +913,12 @@
* This array describes the order lists are fallen back to when
* the free lists for the desirable migrate type are depleted
*/
-static int fallbacks[MIGRATE_TYPES][4] = {
+static int fallbacks[MIGRATE_TYPES][3] = {
[MIGRATE_UNMOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_MOVABLE, MIGRATE_RESERVE },
[MIGRATE_RECLAIMABLE] = { MIGRATE_UNMOVABLE, MIGRATE_MOVABLE, MIGRATE_RESERVE },
-#ifdef CONFIG_CMA
- [MIGRATE_MOVABLE] = { MIGRATE_CMA, MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_RESERVE },
- [MIGRATE_CMA] = { MIGRATE_RESERVE }, /* Never used */
-#else
[MIGRATE_MOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_RESERVE },
+#ifdef CONFIG_CMA
+ [MIGRATE_CMA] = { MIGRATE_RESERVE }, /* Never used */
#endif
[MIGRATE_RESERVE] = { MIGRATE_RESERVE }, /* Never used */
[MIGRATE_ISOLATE] = { MIGRATE_RESERVE }, /* Never used */
@@ -1043,17 +1041,10 @@
* pages to the preferred allocation list. If falling
* back for a reclaimable kernel allocation, be more
* aggressive about taking ownership of free pages
- *
- * On the other hand, never change migration
- * type of MIGRATE_CMA pageblocks nor move CMA
- * pages on different free lists. We don't
- * want unmovable pages to be allocated from
- * MIGRATE_CMA areas.
*/
- if (!is_migrate_cma(migratetype) &&
- (unlikely(current_order >= pageblock_order / 2) ||
- start_migratetype == MIGRATE_RECLAIMABLE ||
- page_group_by_mobility_disabled)) {
+ if (unlikely(current_order >= pageblock_order / 2) ||
+ start_migratetype == MIGRATE_RECLAIMABLE ||
+ page_group_by_mobility_disabled) {
int pages;
pages = move_freepages_block(zone, page,
start_migratetype);
@@ -1072,14 +1063,12 @@
rmv_page_order(page);
/* Take ownership for orders >= pageblock_order */
- if (current_order >= pageblock_order &&
- !is_migrate_cma(migratetype))
+ if (current_order >= pageblock_order)
change_pageblock_range(page, current_order,
start_migratetype);
expand(zone, page, order, current_order, area,
- is_migrate_cma(migratetype)
- ? migratetype : start_migratetype);
+ start_migratetype);
trace_mm_page_alloc_extfrag(page, order, current_order,
start_migratetype, migratetype);
@@ -1100,21 +1089,27 @@
{
struct page *page;
-retry_reserve:
- page = __rmqueue_smallest(zone, order, migratetype);
+#ifdef CONFIG_CMA
+ if (migratetype == MIGRATE_MOVABLE)
+ migratetype = MIGRATE_CMA;
+#endif
- if (unlikely(!page) && migratetype != MIGRATE_RESERVE) {
- page = __rmqueue_fallback(zone, order, migratetype);
+ for(;;) {
+ page = __rmqueue_smallest(zone, order, migratetype);
+ if (likely(page) || migratetype == MIGRATE_RESERVE)
+ break;
- /*
- * Use MIGRATE_RESERVE rather than fail an allocation. goto
- * is used because __rmqueue_smallest is an inline function
- * and we want just one call site
- */
- if (!page) {
- migratetype = MIGRATE_RESERVE;
- goto retry_reserve;
+ if (is_migrate_cma(migratetype)) {
+ migratetype = MIGRATE_MOVABLE;
+ continue;
}
+
+ page = __rmqueue_fallback(zone, order, migratetype);
+ if (page)
+ break;
+
+ /* Use MIGRATE_RESERVE rather than fail an allocation. */
+ migratetype = MIGRATE_RESERVE;
}
trace_mm_page_alloc_zone_locked(page, order, migratetype);
@@ -2791,6 +2786,31 @@
#define K(x) ((x) << (PAGE_SHIFT-10))
+static void show_migration_types(unsigned char type)
+{
+ static const char types[MIGRATE_TYPES] = {
+ [MIGRATE_UNMOVABLE] = 'U',
+ [MIGRATE_RECLAIMABLE] = 'E',
+ [MIGRATE_MOVABLE] = 'M',
+ [MIGRATE_RESERVE] = 'R',
+#ifdef CONFIG_CMA
+ [MIGRATE_CMA] = 'C',
+#endif
+ [MIGRATE_ISOLATE] = 'I',
+ };
+ char tmp[MIGRATE_TYPES + 1];
+ char *p = tmp;
+ int i;
+
+ for (i = 0; i < MIGRATE_TYPES; i++) {
+ if (type & (1 << i))
+ *p++ = types[i];
+ }
+
+ *p = '\0';
+ printk("(%s) ", tmp);
+}
+
/*
* Show free area list (used inside shift_scroll-lock stuff)
* We also calculate the percentage fragmentation. We do this by counting the
@@ -2919,6 +2939,7 @@
for_each_populated_zone(zone) {
unsigned long nr[MAX_ORDER], flags, order, total = 0;
+ unsigned char types[MAX_ORDER];
if (skip_free_areas_node(filter, zone_to_nid(zone)))
continue;
@@ -2927,12 +2948,24 @@
spin_lock_irqsave(&zone->lock, flags);
for (order = 0; order < MAX_ORDER; order++) {
- nr[order] = zone->free_area[order].nr_free;
+ struct free_area *area = &zone->free_area[order];
+ int type;
+
+ nr[order] = area->nr_free;
total += nr[order] << order;
+
+ types[order] = 0;
+ for (type = 0; type < MIGRATE_TYPES; type++) {
+ if (!list_empty(&area->free_list[type]))
+ types[order] |= 1 << type;
+ }
}
spin_unlock_irqrestore(&zone->lock, flags);
- for (order = 0; order < MAX_ORDER; order++)
+ for (order = 0; order < MAX_ORDER; order++) {
printk("%lu*%lukB ", nr[order], K(1UL) << order);
+ if (nr[order])
+ show_migration_types(types[order]);
+ }
printk("= %lukB\n", K(total));
}
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 68c6cc2..e819c9f 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1807,7 +1807,7 @@
int mask)
{
/* XXX: wake_lock_timeout()? */
- snd_soc_jack_report(jack, status, mask);
+ snd_soc_jack_report_no_dapm(jack, status, mask);
}
static void hphocp_off_report(struct sitar_priv *sitar,
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 6bef9ba..0575f6e 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1626,6 +1626,9 @@
case FORMAT_AMRWB:
open.write_format = AMRWB_FS;
break;
+ case FORMAT_AMR_WB_PLUS:
+ open.write_format = AMR_WB_PLUS;
+ break;
case FORMAT_V13K:
open.write_format = V13K_FS;
break;