Merge "msm: mdss: enable overlay handoff for secondary ctl on split display"
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 5e890d3..78e1a63 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -78,7 +78,7 @@
vdd-apc-supply = <&pm8226_s2>;
vdd-mx-supply = <&pm8226_l3_ao>;
- qcom,vdd-mx-vmax = <1350000>;
+ qcom,vdd-mx-vmax = <1337500>;
qcom,vdd-mx-vmin-method = <1>;
qcom,cpr-ref-clk = <19200>;
@@ -109,7 +109,7 @@
qcom,cpr-fuse-uplift-sel = <22 53 1 0 0>;
qcom,cpr-uplift-voltage = <50000>;
qcom,cpr-uplift-quotient = <0 0 120>;
- qcom,cpr-uplift-max-volt = <1350000>;
+ qcom,cpr-uplift-max-volt = <1330000>;
qcom,cpr-uplift-speed-bin = <1>;
qcom,speed-bin-fuse-sel = <22 0 3 0>;
};
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index 813ecaa..ae0547f 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -1657,6 +1657,7 @@
};
&mdss_mdp {
+ qcom,max-bandwidth-low-kbps = <2750000>;
qcom,vbif-settings = <0x0004 0x00000001>;
qcom,mdss-wb-off = <0x00011100 0x00011500
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index fe7de31..08566bb 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -57,6 +57,42 @@
};
#endif
+static struct gpiomux_setting smsc_hub_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting smsc_hub_susp_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config smsc_hub_configs[] = {
+ {
+ .gpio = 114, /* reset_n */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &smsc_hub_act_cfg,
+ [GPIOMUX_SUSPENDED] = &smsc_hub_susp_cfg,
+ },
+ },
+ {
+ .gpio = 8, /* clk_en */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &smsc_hub_act_cfg,
+ [GPIOMUX_SUSPENDED] = &smsc_hub_susp_cfg,
+ },
+ },
+ {
+ .gpio = 9, /* int_n */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &smsc_hub_act_cfg,
+ [GPIOMUX_SUSPENDED] = &smsc_hub_susp_cfg,
+ },
+ },
+};
+
#define KS8851_IRQ_GPIO 115
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
@@ -940,6 +976,9 @@
}
msm_gpiomux_install(msm_hsic_configs, ARRAY_SIZE(msm_hsic_configs));
#endif
+ if (machine_is_msm8926() && of_board_is_mtp())
+ msm_gpiomux_install(smsc_hub_configs,
+ ARRAY_SIZE(smsc_hub_configs));
}
static void wcnss_switch_to_gpio(void)
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 9857162..bd28131 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -82,6 +82,7 @@
static struct lpm_system_state sys_state;
static bool suspend_in_progress;
+static int64_t suspend_time;
struct lpm_lookup_table {
uint32_t modes;
@@ -545,11 +546,11 @@
if (!dev->cpu && msm_rpm_waiting_for_ack())
break;
- if ((next_wakeup_us >> 10) > pwr->latency_us) {
+ if ((next_wakeup_us >> 10) > pwr->time_overhead_us) {
power = pwr->ss_power;
} else {
power = pwr->ss_power;
- power -= (pwr->latency_us * pwr->ss_power)
+ power -= (pwr->time_overhead_us * pwr->ss_power)
/ next_wakeup_us;
power += pwr->energy_overhead / next_wakeup_us;
}
@@ -779,6 +780,11 @@
static int lpm_suspend_prepare(void)
{
+ struct timespec ts;
+
+ getnstimeofday(&ts);
+ suspend_time = timespec_to_ns(&ts);
+
suspend_in_progress = true;
msm_mpm_suspend_prepare();
return 0;
@@ -786,6 +792,12 @@
static void lpm_suspend_wake(void)
{
+ struct timespec ts;
+
+ getnstimeofday(&ts);
+ suspend_time = timespec_to_ns(&ts) - suspend_time;
+ msm_pm_add_stat(MSM_PM_STAT_SUSPEND, suspend_time);
+
msm_mpm_suspend_wake();
suspend_in_progress = false;
}
diff --git a/arch/arm/mach-msm/msm-pm.c b/arch/arm/mach-msm/msm-pm.c
index 080bab3..cb65a70 100644
--- a/arch/arm/mach-msm/msm-pm.c
+++ b/arch/arm/mach-msm/msm-pm.c
@@ -799,17 +799,19 @@
pr_info("CPU%u: %s mode:%d\n",
smp_processor_id(), __func__, mode);
- time = sched_clock();
+ if (from_idle)
+ time = sched_clock();
+
if (execute[mode])
exit_stat = execute[mode](from_idle);
- time = sched_clock() - time;
- if (from_idle)
+
+ if (from_idle) {
+ time = sched_clock() - time;
msm_pm_ftrace_lpm_exit(smp_processor_id(), mode, collapsed);
- else
- exit_stat = MSM_PM_STAT_SUSPEND;
- if (exit_stat >= 0)
- msm_pm_add_stat(exit_stat, time);
- do_div(time, 1000);
+ if (exit_stat >= 0)
+ msm_pm_add_stat(exit_stat, time);
+ }
+
return collapsed;
}
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index e87c670..69b953f 100755
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -641,16 +641,18 @@
phys_addr_t pt_base)
{
struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
- phys_addr_t domain_ptbase = iommu_pt ?
- iommu_get_pt_base_addr(iommu_pt->domain) : 0;
+ phys_addr_t domain_ptbase;
- /* Only compare the valid address bits of the pt_base */
- domain_ptbase &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
+ if (iommu_pt == NULL)
+ return 0;
+
+ domain_ptbase = iommu_get_pt_base_addr(iommu_pt->domain)
+ & KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
pt_base &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
- return domain_ptbase && pt_base &&
- (domain_ptbase == pt_base);
+ return (domain_ptbase == pt_base);
+
}
/*
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 067a887..44da261 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -1014,7 +1014,7 @@
int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *iadc, int32_t *rsense)
{
- uint8_t rslt_rsense;
+ uint8_t rslt_rsense = 0;
int32_t rc = 0, sign_bit = 0;
if (qpnp_iadc_is_valid(iadc) < 0)
@@ -1022,36 +1022,37 @@
if (iadc->external_rsense) {
*rsense = iadc->rsense;
- return rc;
- }
-
- if (iadc->default_internal_rsense) {
+ } else if (iadc->default_internal_rsense) {
*rsense = iadc->rsense_workaround_value;
- return rc;
- }
+ } else {
- rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
- if (rc < 0) {
- pr_err("qpnp adc rsense read failed with %d\n", rc);
- return rc;
- }
+ rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE,
+ &rslt_rsense);
+ if (rc < 0) {
+ pr_err("qpnp adc rsense read failed with %d\n", rc);
+ return rc;
+ }
- pr_debug("rsense:0%x\n", rslt_rsense);
+ pr_debug("rsense:0%x\n", rslt_rsense);
- if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
- sign_bit = 1;
+ if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
+ sign_bit = 1;
- rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
+ rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
- if (sign_bit)
- *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
+ if (sign_bit)
+ *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
(rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
- else
- *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
+ else
+ *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
(rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
-
+ }
pr_debug("rsense value is %d\n", *rsense);
+ if (*rsense == 0)
+ pr_err("incorrect rsens value:%d rslt_rsense:%d\n",
+ *rsense, rslt_rsense);
+
return rc;
}
EXPORT_SYMBOL(qpnp_iadc_get_rsense);
@@ -1215,6 +1216,11 @@
if (qpnp_iadc_is_valid(iadc) < 0)
return -EPROBE_DEFER;
+ if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
+ pr_err("raw offset errors! run iadc calibration again\n");
+ return -EINVAL;
+ }
+
mutex_lock(&iadc->adc->adc_lock);
if (iadc->iadc_poll_eoc) {
@@ -1251,6 +1257,11 @@
result_current = i_result->result_uv;
result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
/* Intentional fall through. Process the result w/o comp */
+ if (!rsense_u_ohms) {
+ pr_err("rsense error=%d\n", rsense_u_ohms);
+ goto fail_release_vadc;
+ }
+
do_div(result_current, rsense_u_ohms);
if (sign) {
diff --git a/drivers/spmi/qpnp-int.c b/drivers/spmi/qpnp-int.c
index 3e14333..9fc7299 100644
--- a/drivers/spmi/qpnp-int.c
+++ b/drivers/spmi/qpnp-int.c
@@ -184,6 +184,22 @@
return 0;
}
+static void qpnpint_irq_ack(struct irq_data *d)
+{
+ struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
+ int rc;
+
+ pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
+
+ rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR,
+ &irq_d->mask_shift, 1);
+ if (rc) {
+ pr_err_ratelimited("spmi write failure on irq %d, rc=%d\n",
+ d->irq, rc);
+ return;
+ }
+}
+
static void qpnpint_irq_mask(struct irq_data *d)
{
struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
@@ -223,44 +239,10 @@
static void qpnpint_irq_mask_ack(struct irq_data *d)
{
- struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
- struct q_chip_data *chip_d = irq_d->chip_d;
- struct q_perip_data *per_d = irq_d->per_d;
- int rc;
- uint8_t prev_int_en = per_d->int_en;
-
pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
- if (!chip_d->cb) {
- pr_warn_ratelimited("No arbiter on bus=%u slave=%u offset=%u\n",
- chip_d->bus_nr, irq_d->spmi_slave,
- irq_d->spmi_offset);
- return;
- }
-
- per_d->int_en &= ~irq_d->mask_shift;
-
- if (prev_int_en && !(per_d->int_en)) {
- /*
- * no interrupt on this peripheral is enabled
- * ask the arbiter to ignore this peripheral
- */
- qpnpint_arbiter_op(d, irq_d, chip_d->cb->mask);
- }
-
- rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
- &irq_d->mask_shift, 1);
- if (rc) {
- pr_err("spmi failure on irq %d\n", d->irq);
- return;
- }
-
- rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR,
- &irq_d->mask_shift, 1);
- if (rc) {
- pr_err("spmi failure on irq %d\n", d->irq);
- return;
- }
+ qpnpint_irq_mask(d);
+ qpnpint_irq_ack(d);
}
static void qpnpint_irq_unmask(struct irq_data *d)
@@ -269,6 +251,7 @@
struct q_chip_data *chip_d = irq_d->chip_d;
struct q_perip_data *per_d = irq_d->per_d;
int rc;
+ uint8_t buf[2];
uint8_t prev_int_en = per_d->int_en;
pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
@@ -289,12 +272,29 @@
*/
qpnpint_arbiter_op(d, irq_d, chip_d->cb->unmask);
}
- rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_SET,
- &irq_d->mask_shift, 1);
+
+ /* Check the current state of the interrupt enable bit. */
+ rc = qpnpint_spmi_read(irq_d, QPNPINT_REG_EN_SET, buf, 1);
if (rc) {
- pr_err("spmi failure on irq %d\n", d->irq);
+ pr_err("SPMI read failure for IRQ %d, rc=%d\n", d->irq, rc);
return;
}
+
+ if (!(buf[0] & irq_d->mask_shift)) {
+ /*
+ * Since the interrupt is currently disabled, write to both the
+ * LATCHED_CLR and EN_SET registers so that a spurious interrupt
+ * cannot be triggered when the interrupt is enabled.
+ */
+ buf[0] = irq_d->mask_shift;
+ buf[1] = irq_d->mask_shift;
+ rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR, buf, 2);
+ if (rc) {
+ pr_err("SPMI write failure for IRQ %d, rc=%d\n", d->irq,
+ rc);
+ return;
+ }
+ }
}
static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
@@ -336,6 +336,11 @@
return rc;
}
+ if (flow_type & IRQ_TYPE_EDGE_BOTH)
+ __irq_set_handler_locked(d->irq, handle_edge_irq);
+ else
+ __irq_set_handler_locked(d->irq, handle_level_irq);
+
return 0;
}
@@ -363,6 +368,7 @@
static struct irq_chip qpnpint_chip = {
.name = "qpnp-int",
+ .irq_ack = qpnpint_irq_ack,
.irq_mask = qpnpint_irq_mask,
.irq_mask_ack = qpnpint_irq_mask_ack,
.irq_unmask = qpnpint_irq_unmask,
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 1111aeb..da714ad 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -897,9 +897,7 @@
dma->source_config.stride = stride;
dma->output_config.pack_pattern =
mdp3_ctrl_get_pack_pattern(req->src.format);
- mdp3_clk_enable(1, 0);
- mdp3_session->dma->dma_config_source(dma);
- mdp3_clk_enable(0, 0);
+ dma->update_src_cfg = true;
}
mdp3_session->overlay.id = 1;
req->id = 1;
@@ -923,14 +921,6 @@
mutex_lock(&mdp3_session->lock);
if (mdp3_session->overlay.id == ndx && ndx == 1) {
- struct mdp3_dma *dma = mdp3_session->dma;
- dma->source_config.format = format;
- dma->source_config.stride = fix->line_length;
- dma->output_config.pack_pattern =
- mdp3_ctrl_get_pack_pattern(mfd->fb_imgType);
- mdp3_clk_enable(1, 0);
- mdp3_session->dma->dma_config_source(dma);
- mdp3_clk_enable(0, 0);
mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
mdp3_bufq_deinit(&mdp3_session->bufq_in);
} else {
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 993a36f..8a13de2 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -605,6 +605,13 @@
}
}
}
+ if (dma->update_src_cfg) {
+ if (dma->output_config.out_sel ==
+ MDP3_DMA_OUTPUT_SEL_DSI_VIDEO && intf->active)
+ pr_err("configuring dma source while dma is active\n");
+ dma->dma_config_source(dma);
+ dma->update_src_cfg = false;
+ }
spin_lock_irqsave(&dma->dma_lock, flag);
MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, (u32)buf);
dma->source_config.buf = buf;
@@ -961,6 +968,7 @@
dma->vsync_client.handler = NULL;
dma->vsync_client.arg = NULL;
dma->histo_state = MDP3_DMA_HISTO_STATE_IDLE;
+ dma->update_src_cfg = false;
memset(&dma->cursor, 0, sizeof(dma->cursor));
memset(&dma->ccs_config, 0, sizeof(dma->ccs_config));
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 207168f..80ebb9b 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -259,6 +259,7 @@
int histo_state;
struct mdp3_dma_histogram_data histo_data;
unsigned int vsync_status;
+ bool update_src_cfg;
int (*dma_config)(struct mdp3_dma *dma,
struct mdp3_dma_source *source_config,
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index c2fbc1a..f342c56 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -90,6 +90,8 @@
ctrl->ndx = DSI_CTRL_1;
}
+ ctrl->panel_mode = ctrl->panel_data.panel_info.mipi.mode;
+
ctrl_list[ctrl->ndx] = ctrl; /* keep it */
if (ctrl->shared_pdata.broadcast_enable)
@@ -269,8 +271,6 @@
pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
- ctrl_pdata->panel_mode = pinfo->mode;
-
if (pinfo->mode == DSI_VIDEO_MODE) {
data = 0;
if (pinfo->pulse_mode_hsa_he)
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index cdf9d73..2b409f5 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2014, 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
@@ -1127,6 +1127,17 @@
DEV_DBG("%s: Got HPD interrupt\n", __func__);
if (hdmi_ctrl->hpd_state) {
+ /*
+ * If a down stream device or bridge chip is attached to hdmi
+ * Tx core output, it is likely that it might be powering the
+ * hpd module ON/OFF on cable connect/disconnect as it would
+ * have its own mechanism of detecting cable. Flush power off
+ * work is needed in case there is any race condidtion between
+ * power off and on during fast cable plug in/out.
+ */
+ if (hdmi_ctrl->ds_registered)
+ flush_work(&hdmi_ctrl->power_off_work);
+
if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, true)) {
DEV_ERR("%s: Failed to enable ddc power\n", __func__);
return;
@@ -2351,6 +2362,8 @@
ops->set_mhl_max_pclk = hdmi_tx_set_mhl_max_pclk;
ops->set_upstream_hpd = hdmi_tx_set_mhl_hpd;
+ hdmi_ctrl->ds_registered = true;
+
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 8233ba8..54d80dc 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -83,6 +83,7 @@
struct work_struct cable_notify_work;
bool hdcp_feature_on;
+ bool ds_registered;
u32 present_hdcp;
u8 spd_vendor_name[9];
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index b6d4982..34cfe23 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -974,6 +974,11 @@
int ret = 0;
int sd_in_pipe = 0;
+ if (!ctl) {
+ pr_warn("kickoff on fb=%d without a ctl attched\n", mfd->index);
+ return ret;
+ }
+
if (ctl->shared_lock)
mutex_lock(ctl->shared_lock);
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 50660b3..dce56a6 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -131,6 +131,8 @@
* most likely due to retrans in 3WHS.
*/
+#define TCP_DELACK_SEG 1 /*Number of full MSS to receive before Acking RFC2581*/
+
#define TCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ/2U)) /* Maximal interval between probes
* for local resources.
*/
@@ -253,6 +255,10 @@
extern int sysctl_tcp_thin_linear_timeouts;
extern int sysctl_tcp_thin_dupack;
+/* sysctl variables for controlling various tcp parameters */
+extern int sysctl_tcp_delack_seg;
+extern int sysctl_tcp_use_userconfig;
+
extern atomic_long_t tcp_memory_allocated;
extern struct percpu_counter tcp_sockets_allocated;
extern int tcp_memory_pressure;
@@ -346,6 +352,10 @@
struct pipe_inode_info *pipe, size_t len,
unsigned int flags);
+extern int tcp_use_userconfig_sysctl_handler(struct ctl_table *, int,
+ void __user *, size_t *, loff_t *);
+extern int tcp_proc_delayed_ack_control(struct ctl_table *, int,
+ void __user *, size_t *, loff_t *);
static inline void tcp_dec_quickack_mode(struct sock *sk,
const unsigned int pkts)
{
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 7f38d35..a8d7ed0 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -896,13 +896,13 @@
sin6->sin6_port = 0;
sin6->sin6_addr = ip6->saddr;
+ sin6->sin6_flowinfo = 0;
if (np->sndflow)
sin6->sin6_flowinfo =
*(__be32 *)ip6 & IPV6_FLOWINFO_MASK;
- if (__ipv6_addr_needs_scope_id(
- ipv6_addr_type(&sin6->sin6_addr)))
- sin6->sin6_scope_id = IP6CB(skb)->iif;
+ sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
+ IP6CB(skb)->iif);
if (inet6_sk(sk)->rxopt.all)
pingv6_ops.datagram_recv_ctl(sk, msg, skb);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 7a7724d..6bd622f 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -36,6 +36,10 @@
static int ip_ttl_max = 255;
static int ip_ping_group_range_min[] = { 0, 0 };
static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
+static int tcp_delack_seg_min = TCP_DELACK_MIN;
+static int tcp_delack_seg_max = 60;
+static int tcp_use_userconfig_min;
+static int tcp_use_userconfig_max = 1;
/* Update system visible IP port range */
static void set_local_port_range(int range[2])
@@ -699,6 +703,25 @@
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero
},
+ {
+ .procname = "tcp_delack_seg",
+ .data = &sysctl_tcp_delack_seg,
+ .maxlen = sizeof(sysctl_tcp_delack_seg),
+ .mode = 0644,
+ .proc_handler = tcp_proc_delayed_ack_control,
+ .extra1 = &tcp_delack_seg_min,
+ .extra2 = &tcp_delack_seg_max,
+ },
+ {
+ .procname = "tcp_use_userconfig",
+ .data = &sysctl_tcp_use_userconfig,
+ .maxlen = sizeof(sysctl_tcp_use_userconfig),
+ .mode = 0644,
+ .proc_handler = tcp_use_userconfig_sysctl_handler,
+ .extra1 = &tcp_use_userconfig_min,
+ .extra2 = &tcp_use_userconfig_max,
+ },
+
{ }
};
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 74a286c..706899e 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -294,6 +294,12 @@
EXPORT_SYMBOL(sysctl_tcp_rmem);
EXPORT_SYMBOL(sysctl_tcp_wmem);
+int sysctl_tcp_delack_seg __read_mostly = TCP_DELACK_SEG;
+EXPORT_SYMBOL(sysctl_tcp_delack_seg);
+
+int sysctl_tcp_use_userconfig __read_mostly;
+EXPORT_SYMBOL(sysctl_tcp_use_userconfig);
+
atomic_long_t tcp_memory_allocated; /* Current allocated memory. */
EXPORT_SYMBOL(tcp_memory_allocated);
@@ -1213,8 +1219,11 @@
/* Delayed ACKs frequently hit locked sockets during bulk
* receive. */
if (icsk->icsk_ack.blocked ||
- /* Once-per-two-segments ACK was not sent by tcp_input.c */
- tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss ||
+ /* Once-per-sysctl_tcp_delack_seg segments
+ * ACK was not sent by tcp_input.c
+ */
+ tp->rcv_nxt - tp->rcv_wup > (icsk->icsk_ack.rcv_mss) *
+ sysctl_tcp_delack_seg ||
/*
* If this read emptied read buffer, we send ACK, if
* connection is not bidirectional, user drained
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 257b617..7c3612b 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5047,7 +5047,8 @@
struct tcp_sock *tp = tcp_sk(sk);
/* More than one full frame received... */
- if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss &&
+ if (((tp->rcv_nxt - tp->rcv_wup) > (inet_csk(sk)->icsk_ack.rcv_mss) *
+ sysctl_tcp_delack_seg &&
/* ... and right edge of window advances far enough.
* (tcp_recvmsg() will send ACK otherwise). Or...
*/
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 34d4a02..d1b4792 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -34,7 +34,39 @@
static void tcp_write_timer(unsigned long);
static void tcp_delack_timer(unsigned long);
-static void tcp_keepalive_timer (unsigned long data);
+static void tcp_keepalive_timer(unsigned long data);
+
+/*Function to reset tcp_ack related sysctl on resetting master control */
+void set_tcp_default(void)
+{
+ sysctl_tcp_delack_seg = TCP_DELACK_SEG;
+}
+
+/*sysctl handler for tcp_ack realted master control */
+int tcp_proc_delayed_ack_control(ctl_table *table, int write,
+ void __user *buffer, size_t *length, loff_t *ppos)
+{
+ int ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
+
+ /* The ret value will be 0 if the input validation is successful
+ * and the values are written to sysctl table. If not, the stack
+ * will continue to work with currently configured values
+ */
+ return ret;
+}
+
+/*sysctl handler for tcp_ack realted master control */
+int tcp_use_userconfig_sysctl_handler(ctl_table *table, int write,
+ void __user *buffer, size_t *length, loff_t *ppos)
+{
+ int ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
+
+ if (write && ret == 0) {
+ if (!sysctl_tcp_use_userconfig)
+ set_tcp_default();
+ }
+ return ret;
+}
void tcp_init_xmit_timers(struct sock *sk)
{