Netdev List
 help / color / mirror / Atom feed
* [PATCH net 4/6] bnxt_en: Fix VF resource checking.
From: Michael Chan @ 2017-10-14  1:09 UTC (permalink / raw)
  To: davem; +Cc: netdev
In-Reply-To: <1507943374-13308-1-git-send-email-michael.chan@broadcom.com>

In bnxt_sriov_enable(), we calculate to see if we have enough hardware
resources to enable the requested number of VFs.  The logic to check
for minimum completion rings and statistics contexts is missing.  Add
the required checks so that VF configuration won't fail.

Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
index d37925a..5ee1866 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
@@ -502,6 +502,7 @@ static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs)
 	int rc = 0, vfs_supported;
 	int min_rx_rings, min_tx_rings, min_rss_ctxs;
 	int tx_ok = 0, rx_ok = 0, rss_ok = 0;
+	int avail_cp, avail_stat;
 
 	/* Check if we can enable requested num of vf's. At a mininum
 	 * we require 1 RX 1 TX rings for each VF. In this minimum conf
@@ -509,6 +510,10 @@ static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs)
 	 */
 	vfs_supported = *num_vfs;
 
+	avail_cp = bp->pf.max_cp_rings - bp->cp_nr_rings;
+	avail_stat = bp->pf.max_stat_ctxs - bp->num_stat_ctxs;
+	avail_cp = min_t(int, avail_cp, avail_stat);
+
 	while (vfs_supported) {
 		min_rx_rings = vfs_supported;
 		min_tx_rings = vfs_supported;
@@ -523,10 +528,12 @@ static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs)
 			    min_rx_rings)
 				rx_ok = 1;
 		}
-		if (bp->pf.max_vnics - bp->nr_vnics < min_rx_rings)
+		if (bp->pf.max_vnics - bp->nr_vnics < min_rx_rings ||
+		    avail_cp < min_rx_rings)
 			rx_ok = 0;
 
-		if (bp->pf.max_tx_rings - bp->tx_nr_rings >= min_tx_rings)
+		if (bp->pf.max_tx_rings - bp->tx_nr_rings >= min_tx_rings &&
+		    avail_cp >= min_tx_rings)
 			tx_ok = 1;
 
 		if (bp->pf.max_rsscos_ctxs - bp->rsscos_nr_ctxs >= min_rss_ctxs)
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH net 5/6] bnxt_en: Fix possible corrupted NVRAM parameters from firmware response.
From: Michael Chan @ 2017-10-14  1:09 UTC (permalink / raw)
  To: davem; +Cc: netdev
In-Reply-To: <1507943374-13308-1-git-send-email-michael.chan@broadcom.com>

In bnxt_find_nvram_item(), it is copying firmware response data after
releasing the mutex.  This can cause the firmware response data
to be corrupted if the next firmware response overwrites the response
buffer.  The rare problem shows up when running ethtool -i repeatedly.

Fix it by calling the new variant _hwrm_send_message_silent() that requires
the caller to take the mutex and to release it after the response data has
been copied.

Fixes: 3ebf6f0a09a2 ("bnxt_en: Add installed-package version reporting via Ethtool GDRVINFO")
Reported-by: Sarveswara Rao Mygapula <sarveswararao.mygapula@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c         | 6 ++++++
 drivers/net/ethernet/broadcom/bnxt/bnxt.h         | 1 +
 drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 4 +++-
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 4ffa0b1..dc5de27 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -3466,6 +3466,12 @@ int _hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
 	return bnxt_hwrm_do_send_msg(bp, msg, msg_len, timeout, false);
 }
 
+int _hwrm_send_message_silent(struct bnxt *bp, void *msg, u32 msg_len,
+			      int timeout)
+{
+	return bnxt_hwrm_do_send_msg(bp, msg, msg_len, timeout, true);
+}
+
 int hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
 {
 	int rc;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index d2925c0..c911e69 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -1362,6 +1362,7 @@ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
 int bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode);
 void bnxt_hwrm_cmd_hdr_init(struct bnxt *, void *, u16, u16, u16);
 int _hwrm_send_message(struct bnxt *, void *, u32, int);
+int _hwrm_send_message_silent(struct bnxt *bp, void *msg, u32 len, int timeout);
 int hwrm_send_message(struct bnxt *, void *, u32, int);
 int hwrm_send_message_silent(struct bnxt *, void *, u32, int);
 int bnxt_hwrm_func_rgtr_async_events(struct bnxt *bp, unsigned long *bmap,
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index b2cbc97..3cbe771 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -1809,7 +1809,8 @@ static int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal,
 	req.dir_ordinal = cpu_to_le16(ordinal);
 	req.dir_ext = cpu_to_le16(ext);
 	req.opt_ordinal = NVM_FIND_DIR_ENTRY_REQ_OPT_ORDINAL_EQ;
-	rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+	mutex_lock(&bp->hwrm_cmd_lock);
+	rc = _hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
 	if (rc == 0) {
 		if (index)
 			*index = le16_to_cpu(output->dir_idx);
@@ -1818,6 +1819,7 @@ static int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal,
 		if (data_length)
 			*data_length = le32_to_cpu(output->dir_data_length);
 	}
+	mutex_unlock(&bp->hwrm_cmd_lock);
 	return rc;
 }
 
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH net 6/6] bnxt_en: Fix possible corruption in DCB parameters from firmware.
From: Michael Chan @ 2017-10-14  1:09 UTC (permalink / raw)
  To: davem; +Cc: netdev, Sankar Patchineelam
In-Reply-To: <1507943374-13308-1-git-send-email-michael.chan@broadcom.com>

From: Sankar Patchineelam <sankar.patchineelam@broadcom.com>

hwrm_send_message() is replaced with _hwrm_send_message(), and
hwrm_cmd_lock mutex lock is grabbed for the whole period of
firmware call until the firmware DCB parameters have been copied.
This will prevent possible corruption of the firmware data.

Fixes: 7df4ae9fe855 ("bnxt_en: Implement DCBNL to support host-based DCBX.")
Signed-off-by: Sankar Patchineelam <sankar.patchineelam@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
index aa1f3a2..fed37cd 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
@@ -50,7 +50,9 @@ static int bnxt_hwrm_queue_pri2cos_qcfg(struct bnxt *bp, struct ieee_ets *ets)
 
 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PRI2COS_QCFG, -1, -1);
 	req.flags = cpu_to_le32(QUEUE_PRI2COS_QCFG_REQ_FLAGS_IVLAN);
-	rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+
+	mutex_lock(&bp->hwrm_cmd_lock);
+	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
 	if (!rc) {
 		u8 *pri2cos = &resp->pri0_cos_queue_id;
 		int i, j;
@@ -66,6 +68,7 @@ static int bnxt_hwrm_queue_pri2cos_qcfg(struct bnxt *bp, struct ieee_ets *ets)
 			}
 		}
 	}
+	mutex_unlock(&bp->hwrm_cmd_lock);
 	return rc;
 }
 
@@ -119,9 +122,13 @@ static int bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt *bp, struct ieee_ets *ets)
 	int rc, i;
 
 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_COS2BW_QCFG, -1, -1);
-	rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
-	if (rc)
+
+	mutex_lock(&bp->hwrm_cmd_lock);
+	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+	if (rc) {
+		mutex_unlock(&bp->hwrm_cmd_lock);
 		return rc;
+	}
 
 	data = &resp->queue_id0 + offsetof(struct bnxt_cos2bw_cfg, queue_id);
 	for (i = 0; i < bp->max_tc; i++, data += sizeof(cos2bw) - 4) {
@@ -143,6 +150,7 @@ static int bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt *bp, struct ieee_ets *ets)
 			}
 		}
 	}
+	mutex_unlock(&bp->hwrm_cmd_lock);
 	return 0;
 }
 
@@ -240,12 +248,17 @@ static int bnxt_hwrm_queue_pfc_qcfg(struct bnxt *bp, struct ieee_pfc *pfc)
 	int rc;
 
 	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PFCENABLE_QCFG, -1, -1);
-	rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
-	if (rc)
+
+	mutex_lock(&bp->hwrm_cmd_lock);
+	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+	if (rc) {
+		mutex_unlock(&bp->hwrm_cmd_lock);
 		return rc;
+	}
 
 	pri_mask = le32_to_cpu(resp->flags);
 	pfc->pfc_en = pri_mask;
+	mutex_unlock(&bp->hwrm_cmd_lock);
 	return 0;
 }
 
-- 
1.8.3.1

^ permalink raw reply related

* RE: [Intel-wired-lan] [PATCH][V3] e1000: avoid null pointer dereference    on invalid stat type
From: Brown, Aaron F @ 2017-10-14  1:44 UTC (permalink / raw)
  To: Colin King, Kirsher, Jeffrey T, intel-wired-lan@lists.osuosl.org,
	netdev@vger.kernel.org
  Cc: kernel-janitors@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <20170922171348.17630-1-colin.king@canonical.com>

> From: Intel-wired-lan [mailto:intel-wired-lan-bounces@osuosl.org] On Behalf
> Of Colin King
> Sent: Friday, September 22, 2017 10:14 AM
> To: Kirsher, Jeffrey T <jeffrey.t.kirsher@intel.com>; intel-wired-
> lan@lists.osuosl.org; netdev@vger.kernel.org
> Cc: kernel-janitors@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: [Intel-wired-lan] [PATCH][V3] e1000: avoid null pointer dereference
> on invalid stat type
> 
> From: Colin Ian King <colin.king@canonical.com>
> 
> Currently if the stat type is invalid then data[i] is being set
> either by dereferencing a null pointer p, or it is reading from
> an incorrect previous location if we had a valid stat type
> previously.  Fix this by skipping over the read of p on an invalid
> stat type.
> 
> Detected by CoverityScan, CID#113385 ("Explicit null dereferenced")
> 
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
>  drivers/net/ethernet/intel/e1000/e1000_ethtool.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)

Tested-by: Aaron Brown <aaron.f.brown@intel.com>

^ permalink raw reply

* [PATCH net v2 1/2] ARM: dts: imx: name the interrupts for the fec ethernet driver
From: Troy Kisky @ 2017-10-14  2:09 UTC (permalink / raw)
  To: shawn.guo, fugang.duan, netdev, davem
  Cc: fabio.estevam, lznuaa, andrew, Troy Kisky

imx7s/imx7d has the ptp interrupt newly added as well.

For imx7, "int0" is the interrupt for queue 0 and ENET_MII
"int1" is for queue 1
"int2" is for queue 2

For imx6sx, "int0" handles all 3 queues and ENET_MII

And of course, the "ptp" interrupt is for the PTP_CLOCK_PPS interrupts
This will help document what each interrupt does.

Signed-off-by: Troy Kisky <troy.kisky@boundarydevices.com>

---
v2: replaced empty names with "int0","int1", or "int2"

reordered imx7 interrupts so that "int0", for queue 0, is first.
---
 arch/arm/boot/dts/imx6qdl.dtsi | 1 +
 arch/arm/boot/dts/imx6sx.dtsi  | 2 ++
 arch/arm/boot/dts/imx6ul.dtsi  | 2 ++
 arch/arm/boot/dts/imx7d.dtsi   | 6 ++++--
 arch/arm/boot/dts/imx7s.dtsi   | 6 ++++--
 5 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 8884b4a3cafb..b78f7e7a0869 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1017,6 +1017,7 @@
 			fec: ethernet@02188000 {
 				compatible = "fsl,imx6q-fec";
 				reg = <0x02188000 0x4000>;
+				interrupt-names = "int0","ptp";
 				interrupts-extended =
 					<&intc 0 118 IRQ_TYPE_LEVEL_HIGH>,
 					<&intc 0 119 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index 6c7eb54be9e2..ed148775f991 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -861,6 +861,7 @@
 			fec1: ethernet@02188000 {
 				compatible = "fsl,imx6sx-fec", "fsl,imx6q-fec";
 				reg = <0x02188000 0x4000>;
+				interrupt-names = "int0","ptp";
 				interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
 					     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6SX_CLK_ENET>,
@@ -970,6 +971,7 @@
 			fec2: ethernet@021b4000 {
 				compatible = "fsl,imx6sx-fec", "fsl,imx6q-fec";
 				reg = <0x021b4000 0x4000>;
+				interrupt-names = "int0","ptp";
 				interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
 					     <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6SX_CLK_ENET>,
diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi
index f11a241a340d..b624b5fc2d99 100644
--- a/arch/arm/boot/dts/imx6ul.dtsi
+++ b/arch/arm/boot/dts/imx6ul.dtsi
@@ -476,6 +476,7 @@
 			fec2: ethernet@020b4000 {
 				compatible = "fsl,imx6ul-fec", "fsl,imx6q-fec";
 				reg = <0x020b4000 0x4000>;
+				interrupt-names = "int0","ptp";
 				interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
 					     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6UL_CLK_ENET>,
@@ -775,6 +776,7 @@
 			fec1: ethernet@02188000 {
 				compatible = "fsl,imx6ul-fec", "fsl,imx6q-fec";
 				reg = <0x02188000 0x4000>;
+				interrupt-names = "int0","ptp";
 				interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
 					     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX6UL_CLK_ENET>,
diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi
index f46814a7ea44..312d24ff106e 100644
--- a/arch/arm/boot/dts/imx7d.dtsi
+++ b/arch/arm/boot/dts/imx7d.dtsi
@@ -114,9 +114,11 @@
 	fec2: ethernet@30bf0000 {
 		compatible = "fsl,imx7d-fec", "fsl,imx6sx-fec";
 		reg = <0x30bf0000 0x10000>;
-		interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+		interrupt-names = "int0","int1","int2","ptp";
+		interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+			<GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
 			<GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
-			<GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+			<GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&clks IMX7D_ENET_AXI_ROOT_CLK>,
 			<&clks IMX7D_ENET_AXI_ROOT_CLK>,
 			<&clks IMX7D_ENET2_TIME_ROOT_CLK>,
diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index 82ad26e766eb..b00a31a50771 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -1007,9 +1007,11 @@
 			fec1: ethernet@30be0000 {
 				compatible = "fsl,imx7d-fec", "fsl,imx6sx-fec";
 				reg = <0x30be0000 0x10000>;
-				interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+				interrupt-names = "int0","int1","int2","ptp";
+				interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
 					<GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
-					<GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+					<GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&clks IMX7D_ENET_AXI_ROOT_CLK>,
 					<&clks IMX7D_ENET_AXI_ROOT_CLK>,
 					<&clks IMX7D_ENET1_TIME_ROOT_CLK>,
-- 
2.11.0

^ permalink raw reply related

* [PATCH net v2 2/2] net: fec: Let fec_ptp have its own interrupt routine
From: Troy Kisky @ 2017-10-14  2:09 UTC (permalink / raw)
  To: shawn.guo, fugang.duan, netdev, davem
  Cc: fabio.estevam, lznuaa, andrew, Troy Kisky
In-Reply-To: <20171014020940.32736-1-troy.kisky@boundarydevices.com>

This is better for code locality and should slightly
speed up normal interrupts.

This also allows PPS clock output to start working for
i.mx7. This is because i.mx7 was already using the limit
of 3 interrupts, and needed another.

Signed-off-by: Troy Kisky <troy.kisky@boundarydevices.com>

---

v2: made this change independent of any devicetree change
so that old dtbs continue to work.

Continue to register ptp clock if interrupt is not found.
---
 drivers/net/ethernet/freescale/fec.h      |  3 +-
 drivers/net/ethernet/freescale/fec_main.c | 25 ++++++----
 drivers/net/ethernet/freescale/fec_ptp.c  | 82 ++++++++++++++++++-------------
 3 files changed, 65 insertions(+), 45 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index ede1876a9a19..be56ac1f1ac4 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -582,12 +582,11 @@ struct fec_enet_private {
 	u64 ethtool_stats[0];
 };
 
-void fec_ptp_init(struct platform_device *pdev);
+void fec_ptp_init(struct platform_device *pdev, int irq_index);
 void fec_ptp_stop(struct platform_device *pdev);
 void fec_ptp_start_cyclecounter(struct net_device *ndev);
 int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
 int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);
-uint fec_ptp_check_pps_event(struct fec_enet_private *fep);
 
 /****************************************************************************/
 #endif /* FEC_H */
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 3dc2d771a222..21afabbc560f 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1602,10 +1602,6 @@ fec_enet_interrupt(int irq, void *dev_id)
 		ret = IRQ_HANDLED;
 		complete(&fep->mdio_done);
 	}
-
-	if (fep->ptp_clock)
-		if (fec_ptp_check_pps_event(fep))
-			ret = IRQ_HANDLED;
 	return ret;
 }
 
@@ -3325,6 +3321,8 @@ fec_probe(struct platform_device *pdev)
 	struct device_node *np = pdev->dev.of_node, *phy_node;
 	int num_tx_qs;
 	int num_rx_qs;
+	char irq_name[8];
+	int irq_cnt;
 
 	fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
 
@@ -3465,18 +3463,27 @@ fec_probe(struct platform_device *pdev)
 	if (ret)
 		goto failed_reset;
 
+	irq_cnt = platform_irq_count(pdev);
+	if (irq_cnt > FEC_IRQ_NUM)
+		irq_cnt = FEC_IRQ_NUM;	/* last for ptp */
+	else if (irq_cnt == 2)
+		irq_cnt = 1;	/* last for ptp */
+	else if (irq_cnt <= 0)
+		irq_cnt = 1;	/* Let the for loop fail */
+
 	if (fep->bufdesc_ex)
-		fec_ptp_init(pdev);
+		fec_ptp_init(pdev, irq_cnt);
 
 	ret = fec_enet_init(ndev);
 	if (ret)
 		goto failed_init;
 
-	for (i = 0; i < FEC_IRQ_NUM; i++) {
-		irq = platform_get_irq(pdev, i);
+	for (i = 0; i < irq_cnt; i++) {
+		sprintf(irq_name, "int%d", i);
+		irq = platform_get_irq_byname(pdev, irq_name);
+		if (irq < 0)
+			irq = platform_get_irq(pdev, i);
 		if (irq < 0) {
-			if (i)
-				break;
 			ret = irq;
 			goto failed_irq;
 		}
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index 6ebad3fac81d..3abeee0d16dd 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -549,6 +549,37 @@ static void fec_time_keep(struct work_struct *work)
 	schedule_delayed_work(&fep->time_keep, HZ);
 }
 
+/* This function checks the pps event and reloads the timer compare counter. */
+static irqreturn_t fec_ptp_interrupt(int irq, void *dev_id)
+{
+	struct net_device *ndev = dev_id;
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	u32 val;
+	u8 channel = fep->pps_channel;
+	struct ptp_clock_event event;
+
+	val = readl(fep->hwp + FEC_TCSR(channel));
+	if (val & FEC_T_TF_MASK) {
+		/* Write the next next compare(not the next according the spec)
+		 * value to the register
+		 */
+		writel(fep->next_counter, fep->hwp + FEC_TCCR(channel));
+		do {
+			writel(val, fep->hwp + FEC_TCSR(channel));
+		} while (readl(fep->hwp + FEC_TCSR(channel)) & FEC_T_TF_MASK);
+
+		/* Update the counter; */
+		fep->next_counter = (fep->next_counter + fep->reload_period) &
+				fep->cc.mask;
+
+		event.type = PTP_CLOCK_PPS;
+		ptp_clock_event(fep->ptp_clock, &event);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
 /**
  * fec_ptp_init
  * @ndev: The FEC network adapter
@@ -558,10 +589,12 @@ static void fec_time_keep(struct work_struct *work)
  * cyclecounter init routine and exits.
  */
 
-void fec_ptp_init(struct platform_device *pdev)
+void fec_ptp_init(struct platform_device *pdev, int irq_index)
 {
 	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct fec_enet_private *fep = netdev_priv(ndev);
+	int irq;
+	int ret;
 
 	fep->ptp_caps.owner = THIS_MODULE;
 	snprintf(fep->ptp_caps.name, 16, "fec ptp");
@@ -587,6 +620,20 @@ void fec_ptp_init(struct platform_device *pdev)
 
 	INIT_DELAYED_WORK(&fep->time_keep, fec_time_keep);
 
+	irq = platform_get_irq_byname(pdev, "ptp");
+	if (irq < 0)
+		irq = platform_get_irq(pdev, irq_index);
+	/* Failure to get an irq is not fatal,
+	 * only the PTP_CLOCK_PPS clock events should stop
+	 */
+	if (irq >= 0) {
+		ret = devm_request_irq(&pdev->dev, irq, fec_ptp_interrupt,
+				       0, pdev->name, ndev);
+		if (ret < 0)
+			dev_warn(&pdev->dev, "request for ptp irq failed(%d)\n",
+				 ret);
+	}
+
 	fep->ptp_clock = ptp_clock_register(&fep->ptp_caps, &pdev->dev);
 	if (IS_ERR(fep->ptp_clock)) {
 		fep->ptp_clock = NULL;
@@ -605,36 +652,3 @@ void fec_ptp_stop(struct platform_device *pdev)
 	if (fep->ptp_clock)
 		ptp_clock_unregister(fep->ptp_clock);
 }
-
-/**
- * fec_ptp_check_pps_event
- * @fep: the fec_enet_private structure handle
- *
- * This function check the pps event and reload the timer compare counter.
- */
-uint fec_ptp_check_pps_event(struct fec_enet_private *fep)
-{
-	u32 val;
-	u8 channel = fep->pps_channel;
-	struct ptp_clock_event event;
-
-	val = readl(fep->hwp + FEC_TCSR(channel));
-	if (val & FEC_T_TF_MASK) {
-		/* Write the next next compare(not the next according the spec)
-		 * value to the register
-		 */
-		writel(fep->next_counter, fep->hwp + FEC_TCCR(channel));
-		do {
-			writel(val, fep->hwp + FEC_TCSR(channel));
-		} while (readl(fep->hwp + FEC_TCSR(channel)) & FEC_T_TF_MASK);
-
-		/* Update the counter; */
-		fep->next_counter = (fep->next_counter + fep->reload_period) & fep->cc.mask;
-
-		event.type = PTP_CLOCK_PPS;
-		ptp_clock_event(fep->ptp_clock, &event);
-		return 1;
-	}
-
-	return 0;
-}
-- 
2.11.0

^ permalink raw reply related

* [PATCH net-next 0/2] net: add skb_memcpy_to[from]_msg()
From: yuan linyu @ 2017-10-14  2:25 UTC (permalink / raw)
  To: netdev; +Cc: David S . Miller, yuan linyu

From: yuan linyu <Linyu.Yuan@alcatel-sbell.com.cn>



yuan linyu (2):
  net: move memcpy_to[from]_msg() from skbuff.h to socket.h
  net: add skb_memcpy_to[from]_msg() to optimize skb code

 drivers/isdn/mISDN/socket.c        |  2 +-
 drivers/staging/irda/net/af_irda.c |  2 +-
 include/linux/skbuff.h             |  8 ++++----
 include/linux/socket.h             | 12 +++++++++++-
 net/appletalk/ddp.c                |  2 +-
 net/ax25/af_ax25.c                 |  2 +-
 net/bluetooth/hci_sock.c           |  4 ++--
 net/bluetooth/rfcomm/sock.c        |  2 +-
 net/bluetooth/sco.c                |  2 +-
 net/caif/caif_socket.c             |  6 +++---
 net/can/bcm.c                      |  4 ++--
 net/can/raw.c                      |  4 ++--
 net/dccp/proto.c                   |  2 +-
 net/decnet/af_decnet.c             |  4 ++--
 net/ieee802154/socket.c            |  4 ++--
 net/ipx/ipx_route.c                |  2 +-
 net/key/af_key.c                   |  2 +-
 net/l2tp/l2tp_ip.c                 |  2 +-
 net/l2tp/l2tp_ppp.c                |  2 +-
 net/llc/af_llc.c                   |  2 +-
 net/netlink/af_netlink.c           |  2 +-
 net/nfc/rawsock.c                  |  2 +-
 net/packet/af_packet.c             |  2 +-
 net/phonet/datagram.c              |  2 +-
 net/phonet/pep.c                   |  2 +-
 25 files changed, 45 insertions(+), 35 deletions(-)

-- 
2.7.4

^ permalink raw reply

* [PATCH net-next 2/2] net: add skb_memcpy_to[from]_msg() to optimize skb code
From: yuan linyu @ 2017-10-14  2:27 UTC (permalink / raw)
  To: netdev; +Cc: David S . Miller, yuan linyu

From: yuan linyu <Linyu.Yuan@alcatel-sbell.com.cn>

add these two wrappers in skbuff.h which is better named
than previous and only used for skb.

Signed-off-by: yuan linyu <Linyu.Yuan@alcatel-sbell.com.cn>
---
 drivers/isdn/mISDN/socket.c        |  2 +-
 drivers/staging/irda/net/af_irda.c |  2 +-
 include/linux/skbuff.h             | 10 ++++++++++
 net/appletalk/ddp.c                |  2 +-
 net/ax25/af_ax25.c                 |  2 +-
 net/bluetooth/hci_sock.c           |  4 ++--
 net/bluetooth/rfcomm/sock.c        |  2 +-
 net/bluetooth/sco.c                |  2 +-
 net/caif/caif_socket.c             |  6 +++---
 net/can/bcm.c                      |  4 ++--
 net/can/raw.c                      |  4 ++--
 net/dccp/proto.c                   |  2 +-
 net/decnet/af_decnet.c             |  4 ++--
 net/ieee802154/socket.c            |  4 ++--
 net/ipx/ipx_route.c                |  2 +-
 net/key/af_key.c                   |  2 +-
 net/l2tp/l2tp_ip.c                 |  2 +-
 net/l2tp/l2tp_ppp.c                |  2 +-
 net/llc/af_llc.c                   |  2 +-
 net/netlink/af_netlink.c           |  2 +-
 net/nfc/rawsock.c                  |  2 +-
 net/packet/af_packet.c             |  2 +-
 net/phonet/datagram.c              |  2 +-
 net/phonet/pep.c                   |  2 +-
 24 files changed, 40 insertions(+), 30 deletions(-)

diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index c5603d1..19ecf62 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -202,7 +202,7 @@ mISDN_sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 	if (!skb)
 		goto done;
 
-	if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
+	if (skb_memcpy_from_msg(skb, msg, len)) {
 		err = -EFAULT;
 		goto done;
 	}
diff --git a/drivers/staging/irda/net/af_irda.c b/drivers/staging/irda/net/af_irda.c
index 23fa7c8..159fc1a 100644
--- a/drivers/staging/irda/net/af_irda.c
+++ b/drivers/staging/irda/net/af_irda.c
@@ -1469,7 +1469,7 @@ static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg,
 		}
 
 		chunk = min_t(unsigned int, skb->len, size);
-		if (memcpy_to_msg(msg, skb->data, chunk)) {
+		if (skb_memcpy_to_msg(msg, skb, chunk)) {
 			skb_queue_head(&sk->sk_receive_queue, skb);
 			if (copied == 0)
 				copied = -EFAULT;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 90868d1..901fa60 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3294,6 +3294,16 @@ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci);
 struct sk_buff *pskb_extract(struct sk_buff *skb, int off, int to_copy,
 			     gfp_t gfp);
 
+static inline int skb_memcpy_from_msg(struct sk_buff *skb, struct msghdr *msg, int len)
+{
+	return memcpy_from_msg(skb_put(skb, len), msg, len);
+}
+
+static inline int skb_memcpy_to_msg(struct msghdr *msg, struct sk_buff *skb, int len)
+{
+	return memcpy_to_msg(msg, skb->data, len);
+}
+
 struct skb_checksum_ops {
 	__wsum (*update)(const void *mem, int len, __wsum wsum);
 	__wsum (*combine)(__wsum csum, __wsum csum2, int offset, int len);
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 5d035c1..c7846c3 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1658,7 +1658,7 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 
 	SOCK_DEBUG(sk, "SK %p: Copy user data (%zd bytes).\n", sk, len);
 
-	err = memcpy_from_msg(skb_put(skb, len), msg, len);
+	err = skb_memcpy_from_msg(skb, msg, len);
 	if (err) {
 		kfree_skb(skb);
 		err = -EFAULT;
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index f3f9d18..442763e 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1552,7 +1552,7 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 	skb_reserve(skb, size - len);
 
 	/* User data follows immediately after the AX.25 data */
-	if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
+	if (skb_memcpy_from_msg(skb, msg, len)) {
 		err = -EFAULT;
 		kfree_skb(skb);
 		goto out;
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 65d734c..349c79a 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -1601,7 +1601,7 @@ static int hci_logging_frame(struct sock *sk, struct msghdr *msg, int len)
 	if (!skb)
 		return err;
 
-	if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
+	if (skb_memcpy_from_msg(skb, msg, len)) {
 		err = -EFAULT;
 		goto drop;
 	}
@@ -1726,7 +1726,7 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
 	if (!skb)
 		goto done;
 
-	if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
+	if (skb_memcpy_from_msg(skb, msg, len)) {
 		err = -EFAULT;
 		goto drop;
 	}
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 1aaccf6..41d19dc 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -594,7 +594,7 @@ static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg,
 		}
 		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
 
-		err = memcpy_from_msg(skb_put(skb, size), msg, size);
+		err = skb_memcpy_from_msg(skb, msg, size);
 		if (err) {
 			kfree_skb(skb);
 			if (sent == 0)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 795e920..01958d2 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -288,7 +288,7 @@ static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
 	if (!skb)
 		return err;
 
-	if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
+	if (skb_memcpy_from_msg(skb, msg, len)) {
 		kfree_skb(skb);
 		return -EFAULT;
 	}
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 632d5a4..6b49e5a 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -422,7 +422,7 @@ static int caif_stream_recvmsg(struct socket *sock, struct msghdr *msg,
 		}
 		release_sock(sk);
 		chunk = min_t(unsigned int, skb->len, size);
-		if (memcpy_to_msg(msg, skb->data, chunk)) {
+		if (skb_memcpy_to_msg(msg, skb, chunk)) {
 			skb_queue_head(&sk->sk_receive_queue, skb);
 			if (copied == 0)
 				copied = -EFAULT;
@@ -570,7 +570,7 @@ static int caif_seqpkt_sendmsg(struct socket *sock, struct msghdr *msg,
 
 	skb_reserve(skb, cf_sk->headroom);
 
-	ret = memcpy_from_msg(skb_put(skb, len), msg, len);
+	ret = skb_memcpy_from_msg(skb, msg, len);
 
 	if (ret)
 		goto err;
@@ -645,7 +645,7 @@ static int caif_stream_sendmsg(struct socket *sock, struct msghdr *msg,
 		 */
 		size = min_t(int, size, skb_tailroom(skb));
 
-		err = memcpy_from_msg(skb_put(skb, size), msg, size);
+		err = skb_memcpy_from_msg(skb, msg, size);
 		if (err) {
 			kfree_skb(skb);
 			goto out_err;
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 47a8748d..6fb4670 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1269,7 +1269,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk,
 
 	can_skb_reserve(skb);
 
-	err = memcpy_from_msg(skb_put(skb, cfsiz), msg, cfsiz);
+	err = skb_memcpy_from_msg(skb, msg, cfsiz);
 	if (err < 0) {
 		kfree_skb(skb);
 		return err;
@@ -1642,7 +1642,7 @@ static int bcm_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
 	if (skb->len < size)
 		size = skb->len;
 
-	err = memcpy_to_msg(msg, skb->data, size);
+	err = skb_memcpy_to_msg(msg, skb, size);
 	if (err < 0) {
 		skb_free_datagram(sk, skb);
 		return err;
diff --git a/net/can/raw.c b/net/can/raw.c
index 864c80d..b52d1db 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -766,7 +766,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 	can_skb_prv(skb)->ifindex = dev->ifindex;
 	can_skb_prv(skb)->skbcnt = 0;
 
-	err = memcpy_from_msg(skb_put(skb, size), msg, size);
+	err = skb_memcpy_from_msg(skb, msg, size);
 	if (err < 0)
 		goto free_skb;
 
@@ -813,7 +813,7 @@ static int raw_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
 	else
 		size = skb->len;
 
-	err = memcpy_to_msg(msg, skb->data, size);
+	err = skb_memcpy_to_msg(msg, skb, size);
 	if (err < 0) {
 		skb_free_datagram(sk, skb);
 		return err;
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index b68168f..affe21a 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -785,7 +785,7 @@ int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 		goto out_release;
 
 	skb_reserve(skb, sk->sk_prot->max_header);
-	rc = memcpy_from_msg(skb_put(skb, len), msg, len);
+	rc = skb_memcpy_from_msg(skb, msg, len);
 	if (rc != 0)
 		goto out_discard;
 
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 73a0399..6fa54fd 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1765,7 +1765,7 @@ static int dn_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
 		if ((chunk + copied) > size)
 			chunk = size - copied;
 
-		if (memcpy_to_msg(msg, skb->data, chunk)) {
+		if (skb_memcpy_to_msg(msg, skb, chunk)) {
 			rv = -EFAULT;
 			break;
 		}
@@ -2036,7 +2036,7 @@ static int dn_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 
 		skb_reserve(skb, 64 + DN_MAX_NSP_DATA_HEADER);
 
-		if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
+		if (skb_memcpy_from_msg(skb, msg, len)) {
 			err = -EFAULT;
 			goto out;
 		}
diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c
index a60658c..c4072a4 100644
--- a/net/ieee802154/socket.c
+++ b/net/ieee802154/socket.c
@@ -296,7 +296,7 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
 	skb_reset_mac_header(skb);
 	skb_reset_network_header(skb);
 
-	err = memcpy_from_msg(skb_put(skb, size), msg, size);
+	err = skb_memcpy_from_msg(skb, msg, size);
 	if (err < 0)
 		goto out_skb;
 
@@ -684,7 +684,7 @@ static int dgram_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
 	if (err < 0)
 		goto out_skb;
 
-	err = memcpy_from_msg(skb_put(skb, size), msg, size);
+	err = skb_memcpy_from_msg(skb, msg, size);
 	if (err < 0)
 		goto out_skb;
 
diff --git a/net/ipx/ipx_route.c b/net/ipx/ipx_route.c
index b5d9144..72c8403 100644
--- a/net/ipx/ipx_route.c
+++ b/net/ipx/ipx_route.c
@@ -229,7 +229,7 @@ int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
 	memcpy(ipx->ipx_dest.node, usipx->sipx_node, IPX_NODE_LEN);
 	ipx->ipx_dest.sock		= usipx->sipx_port;
 
-	rc = memcpy_from_msg(skb_put(skb, len), msg, len);
+	rc = skb_memcpy_from_msg(skb, msg, len);
 	if (rc) {
 		kfree_skb(skb);
 		goto out_put;
diff --git a/net/key/af_key.c b/net/key/af_key.c
index a00d607..af9b4b9 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3637,7 +3637,7 @@ static int pfkey_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 		goto out;
 
 	err = -EFAULT;
-	if (memcpy_from_msg(skb_put(skb,len), msg, len))
+	if (skb_memcpy_from_msg(skb, msg, len))
 		goto out;
 
 	hdr = pfkey_get_base_msg(skb, &err);
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index 4d322c1..3640f92 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -458,7 +458,7 @@ static int l2tp_ip_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	*((__be32 *) skb_put(skb, 4)) = 0;
 
 	/* Copy user data into skb */
-	rc = memcpy_from_msg(skb_put(skb, len), msg, len);
+	rc = skb_memcpy_from_msg(skb, msg, len);
 	if (rc < 0) {
 		kfree_skb(skb);
 		goto error;
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index bc6e8bf..c54ebaf 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -329,7 +329,7 @@ static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m,
 	skb_put(skb, 2);
 
 	/* Copy user data into skb */
-	error = memcpy_from_msg(skb_put(skb, total_len), m, total_len);
+	error = skb_memcpy_from_msg(skb, m, total_len);
 	if (error < 0) {
 		kfree_skb(skb);
 		goto error_put_sess_tun;
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index c38d16f..aed88a1 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -928,7 +928,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 	skb->dev      = llc->dev;
 	skb->protocol = llc_proto_type(addr->sllc_arphrd);
 	skb_reserve(skb, hdrlen);
-	rc = memcpy_from_msg(skb_put(skb, copied), msg, copied);
+	rc = skb_memcpy_from_msg(skb, msg, copied);
 	if (rc)
 		goto out;
 	if (sk->sk_type == SOCK_DGRAM || addr->sllc_ua) {
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index f347506..5ce9ac2 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1844,7 +1844,7 @@ static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 	NETLINK_CB(skb).flags	= netlink_skb_flags;
 
 	err = -EFAULT;
-	if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
+	if (skb_memcpy_from_msg(skb, msg, len)) {
 		kfree_skb(skb);
 		goto out;
 	}
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
index e2188de..a7bf4d4 100644
--- a/net/nfc/rawsock.c
+++ b/net/nfc/rawsock.c
@@ -230,7 +230,7 @@ static int rawsock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 	if (skb == NULL)
 		return rc;
 
-	rc = memcpy_from_msg(skb_put(skb, len), msg, len);
+	rc = skb_memcpy_from_msg(skb, msg, len);
 	if (rc < 0) {
 		kfree_skb(skb);
 		return rc;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 3f5caa3..162460b 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1972,7 +1972,7 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
 			if (len < hhlen)
 				skb_reset_network_header(skb);
 		}
-		err = memcpy_from_msg(skb_put(skb, len), msg, len);
+		err = skb_memcpy_from_msg(skb, msg, len);
 		if (err)
 			goto out_free;
 		goto retry;
diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c
index b44fb90..1ea1105 100644
--- a/net/phonet/datagram.c
+++ b/net/phonet/datagram.c
@@ -108,7 +108,7 @@ static int pn_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 		return err;
 	skb_reserve(skb, MAX_PHONET_HEADER);
 
-	err = memcpy_from_msg((void *)skb_put(skb, len), msg, len);
+	err = skb_memcpy_from_msg(skb, msg, len);
 	if (err < 0) {
 		kfree_skb(skb);
 		return err;
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 9fc76b1..84870b6 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -1143,7 +1143,7 @@ static int pep_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 		return err;
 
 	skb_reserve(skb, MAX_PHONET_HEADER + 3 + pn->aligned);
-	err = memcpy_from_msg(skb_put(skb, len), msg, len);
+	err = skb_memcpy_from_msg(skb, msg, len);
 	if (err < 0)
 		goto outfree;
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH net-next 1/2] net: move memcpy_to[from]_msg() from skbuff.h to socket.h
From: yuan linyu @ 2017-10-14  2:26 UTC (permalink / raw)
  To: netdev; +Cc: David S . Miller, yuan linyu

From: yuan linyu <Linyu.Yuan@alcatel-sbell.com.cn>

these two functions used by skb and other places,
move to socket.h where struct msghdr defined.

Signed-off-by: yuan linyu <Linyu.Yuan@alcatel-sbell.com.cn>
---
 include/linux/skbuff.h | 10 ----------
 include/linux/socket.h | 12 +++++++++++-
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 03634ec2..90868d1 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3294,16 +3294,6 @@ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci);
 struct sk_buff *pskb_extract(struct sk_buff *skb, int off, int to_copy,
 			     gfp_t gfp);
 
-static inline int memcpy_from_msg(void *data, struct msghdr *msg, int len)
-{
-	return copy_from_iter_full(data, len, &msg->msg_iter) ? 0 : -EFAULT;
-}
-
-static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len)
-{
-	return copy_to_iter(data, len, &msg->msg_iter) == len ? 0 : -EFAULT;
-}
-
 struct skb_checksum_ops {
 	__wsum (*update)(const void *mem, int len, __wsum wsum);
 	__wsum (*combine)(__wsum csum, __wsum csum2, int offset, int len);
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 8ad963c..c414f1f 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -53,7 +53,17 @@ struct msghdr {
 	unsigned int	msg_flags;	/* flags on received message */
 	struct kiocb	*msg_iocb;	/* ptr to iocb for async requests */
 };
- 
+
+static inline int memcpy_from_msg(void *data, struct msghdr *msg, int len)
+{
+	return copy_from_iter_full(data, len, &msg->msg_iter) ? 0 : -EFAULT;
+}
+
+static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len)
+{
+	return copy_to_iter(data, len, &msg->msg_iter) == len ? 0 : -EFAULT;
+}
+
 struct user_msghdr {
 	void		__user *msg_name;	/* ptr to socket address structure */
 	int		msg_namelen;		/* size of socket address structure */
-- 
2.7.4

^ permalink raw reply related

* Re: [RFC 0/3] Adding config get/set to devlink
From: Roopa Prabhu @ 2017-10-14  4:21 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: Florian Fainelli, David Miller, Steve Lin, netdev@vger.kernel.org,
	Jiri Pirko, Michael Chan, linux-pci, John W. Linville,
	Andy Gospodarek
In-Reply-To: <20171013071121.GF1952@nanopsycho.orion>

On Fri, Oct 13, 2017 at 12:11 AM, Jiri Pirko <jiri@resnulli.us> wrote:
> Thu, Oct 12, 2017 at 11:53:56PM CEST, roopa@cumulusnetworks.com wrote:
>>On Thu, Oct 12, 2017 at 12:20 PM, Florian Fainelli <f.fainelli@gmail.com> wrote:
>>> On 10/12/2017 12:06 PM, David Miller wrote:
>>>> From: Florian Fainelli <f.fainelli@gmail.com>
>>>> Date: Thu, 12 Oct 2017 08:43:59 -0700
>>>>
>>>>> Once we move ethtool (or however we name its successor) over to
>>>>> netlink there is an opportunity for accessing objects that do and do
>>>>> not have a netdevice representor today (e.g: management ports on
>>>>> switches) with the same interface, and devlink could be used for
>>>>> that.
>>>>
>>>> That is an interesting angle for including this in devlink.
>>>>
>>>> I'm not so sure what to do about this.
>>>>
>>>> One suggestion is that devlink is used for getting ethtool stats for
>>>> objects lacking netdev representor's, and a new genetlink family is
>>>> used for netdev based ethtool.
>>>
>>> Right, I was also thinking along those lines that we we would have a new
>>> generic netlink family for ethtool to support ethtool over netlink.
>>
>>new api is fine by me. The reason for suggesting devlink was because
>>some of the devlink
>>port_* ops are close to ethtool ops that can operate on a port/netdev.
>>eg split_port could be a netdev operation
>>unless you want to split before the netdev is created.
>
> Let me correct you. The split is always devlink_port operation. In some
> cases however when there is a mapping between devlink_port and netdev,
> userspace part could translate netdev->devlink_port.

yes, thats what i was trying to hint..that in some cases devlink_port
can already be mapped to a netdev.

>
>
>>
>>There are some ops in devlink which are global hw parameters and not
>>specific to a port, those fit perfectly with
>>devlinks original goal.
>
> There are 2 handles from the very beginning:
> 1) devlink - asic-wide handle
> 2) devlink_port - port handle

yep, i know that...and i was not trying to say that is a bad thing.

I think we will end up with devlink_port operations that could also be
done on a netdev down the lane. And, we may have to then argue where
an attribute will go. Hence my suggestion on classifying the api by
the target (driver in this case vs kernel networking for rtnetlink).
If you take netdev out of the picture, the port attributes that
devlink tries to set are similar to the ethtool port attributes today.
Also, it seemed like the new port attributes set api (proposed in this
thread) was close to the ethtool attributes set. Having all link hw
attributes in the same tool/api has  advantages. I have no plans to
move anything yet...so if the general preference is to keep devlink
netdev free for now, thats fine.

^ permalink raw reply

* [net-next 0/3] optimisations and reorganisations of tcp_collapse
From: Koichiro Den @ 2017-10-14  7:27 UTC (permalink / raw)
  To: netdev; +Cc: davem, kuznet, yoshfuji

This patch series removes possible useless copying and collapsing while
not missing the chance when it is worth the effort. Also reorganizes it
and do some cleanups.

Koichiro Den (3):
  tcp: avoid useless copying and collapsing of just one skb
  tcp: do not tcp_collapse once SYN or FIN found
  tcp: keep tcp_collapse controllable even after processing starts

 net/ipv4/tcp_input.c | 193 ++++++++++++++++++++++++---------------------------
 1 file changed, 90 insertions(+), 103 deletions(-)

-- 
2.9.4

^ permalink raw reply

* [net-next 2/3] tcp: do not tcp_collapse once SYN or FIN found
From: Koichiro Den @ 2017-10-14  7:27 UTC (permalink / raw)
  To: netdev; +Cc: davem, kuznet, yoshfuji
In-Reply-To: <20171014072745.23462-1-den@klaipeden.com>

Since 9f5afeae5152 ("tcp: use an RB tree for ooo receive queue")
applied, we no longer need to continue to search for the starting
point once we encounter FIN packet. Same reasoning for SYN packet
since commit 9d691539eea2d ("tcp: do not enqueue skb with SYN flag"),
that would help us with error message when actual receiving.

Signed-off-by: Koichiro Den <den@klaipeden.com>
---
 net/ipv4/tcp_input.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 1d785b5bf62d..1a74457db0f3 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4775,6 +4775,14 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
 	 */
 restart:
 	for (end_of_skbs = true; skb != NULL && skb != tail; skb = n) {
+		/* If list is ooo queue, it will get purged when
+		 * this FIN will get moved to sk_receive_queue.
+		 * SYN packet is not expected here. We will get
+		 * error message when actual receiving.
+		 */
+		if (TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_FIN | TCPHDR_SYN))
+			return;
+
 		n = tcp_skb_next(skb, list);
 
 		/* No new bits? It is possible on ofo queue. */
@@ -4786,13 +4794,11 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
 		}
 
 		/* The first skb to collapse is:
-		 * - not SYN/FIN and
 		 * - bloated or contains data before "start" or
 		 *   overlaps to the next one.
 		 */
-		if (!(TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN)) &&
-		    (tcp_win_from_space(skb->truesize) > skb->len ||
-		     before(TCP_SKB_CB(skb)->seq, start))) {
+		if (tcp_win_from_space(skb->truesize) > skb->len ||
+		    before(TCP_SKB_CB(skb)->seq, start)) {
 			end_of_skbs = false;
 			break;
 		}
@@ -4807,7 +4813,6 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
 		start = TCP_SKB_CB(skb)->end_seq;
 	}
 	if (end_of_skbs ||
-	    (TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN)) ||
 	    (TCP_SKB_CB(skb)->seq == start && TCP_SKB_CB(skb)->end_seq == end))
 		return;
 
@@ -4845,9 +4850,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
 			}
 			if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
 				skb = tcp_collapse_one(sk, skb, list, root);
-				if (!skb ||
-				    skb == tail ||
-				    (TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN)))
+				if (!skb || skb == tail)
 					goto end;
 			}
 		}
-- 
2.9.4

^ permalink raw reply related

* [net-next 1/3] tcp: avoid useless copying and collapsing of just one skb
From: Koichiro Den @ 2017-10-14  7:27 UTC (permalink / raw)
  To: netdev; +Cc: davem, kuznet, yoshfuji
In-Reply-To: <20171014072745.23462-1-den@klaipeden.com>

On the starting point chosen, it could be possible that just one skb
remains in between the range provided, leading to copying and re-insertion
of rb node, which is useless with respect to the rcv buf measurement.
This is rather probable in ooo queue case, in which non-contiguous bloated
packets have been queued up.

Signed-off-by: Koichiro Den <den@klaipeden.com>
---
 net/ipv4/tcp_input.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index d0682ce2a5d6..1d785b5bf62d 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4807,7 +4807,8 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
 		start = TCP_SKB_CB(skb)->end_seq;
 	}
 	if (end_of_skbs ||
-	    (TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN)))
+	    (TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN)) ||
+	    (TCP_SKB_CB(skb)->seq == start && TCP_SKB_CB(skb)->end_seq == end))
 		return;
 
 	__skb_queue_head_init(&tmp);
-- 
2.9.4

^ permalink raw reply related

* [net-next 3/3] tcp: keep tcp_collapse controllable even after processing starts
From: Koichiro Den @ 2017-10-14  7:27 UTC (permalink / raw)
  To: netdev; +Cc: davem, kuznet, yoshfuji
In-Reply-To: <20171014072745.23462-1-den@klaipeden.com>

Combining actual collapsing with reasoning for deciding the starting
point, we can apply its logic in a consistent manner such that we can
avoid costly yet not much useful collapsing. When collapsing to be
triggered, it's not rare that most of the skbs in the receive or ooo
queue are large ones without much metadata overhead. This also
simplifies code and makes it easier to apply logic in a fair manner.

Subtle subsidiary changes included:
- When the end_seq of the skb we are trying to collapse was larger than
  the 'end' argument provided, we would end up copying to the 'end'
  even though we couldn't collapse the original one. Current users of
  tcp_collapse does not require such reserves so redefines it as the
  point over which skbs whose seq passes guranteed not to be collapsed.
- Naturally tcp_collapse_ofo_queue shapes up and we no longer need
  'tail' argument.

Signed-off-by: Koichiro Den <den@klaipeden.com>
---
 net/ipv4/tcp_input.c | 197 +++++++++++++++++++++++----------------------------
 1 file changed, 90 insertions(+), 107 deletions(-)

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 1a74457db0f3..5fb90cc0ae95 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4756,108 +4756,117 @@ void tcp_rbtree_insert(struct rb_root *root, struct sk_buff *skb)
 
 /* Collapse contiguous sequence of skbs head..tail with
  * sequence numbers start..end.
- *
- * If tail is NULL, this means until the end of the queue.
- *
- * Segments with FIN/SYN are not collapsed (only because this
- * simplifies code)
  */
 static void
 tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
-	     struct sk_buff *head, struct sk_buff *tail, u32 start, u32 end)
+	     struct sk_buff *head, u32 start, u32 *end)
 {
-	struct sk_buff *skb = head, *n;
+	struct sk_buff *skb = head, *n, *nskb = NULL;
+	int copy = 0, offset, size;
 	struct sk_buff_head tmp;
-	bool end_of_skbs;
 
-	/* First, check that queue is collapsible and find
-	 * the point where collapsing can be useful.
-	 */
-restart:
-	for (end_of_skbs = true; skb != NULL && skb != tail; skb = n) {
-		/* If list is ooo queue, it will get purged when
-		 * this FIN will get moved to sk_receive_queue.
-		 * SYN packet is not expected here. We will get
-		 * error message when actual receiving.
-		 */
-		if (TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_FIN | TCPHDR_SYN))
-			return;
+	if (!list)
+		__skb_queue_head_init(&tmp); /* To defer rb tree insertion */
 
-		n = tcp_skb_next(skb, list);
-
-		/* No new bits? It is possible on ofo queue. */
+	while (skb) {
 		if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
 			skb = tcp_collapse_one(sk, skb, list, root);
-			if (!skb)
-				break;
-			goto restart;
+			continue;
 		}
+		n = tcp_skb_next(skb, list);
 
-		/* The first skb to collapse is:
-		 * - bloated or contains data before "start" or
-		 *   overlaps to the next one.
-		 */
-		if (tcp_win_from_space(skb->truesize) > skb->len ||
-		    before(TCP_SKB_CB(skb)->seq, start)) {
-			end_of_skbs = false;
+examine:
+		/* Nothing beneficial to expect any more if SYN/FIN or last. */
+		if (!n ||
+		    TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_FIN | TCPHDR_SYN))
 			break;
+
+		/* If hole found, skip to the next. */
+		if (after(TCP_SKB_CB(n)->seq, TCP_SKB_CB(skb)->end_seq)) {
+			skb = n;
+			continue;
 		}
 
-		if (n && n != tail &&
-		    TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(n)->seq) {
-			end_of_skbs = false;
-			break;
+		/* If the 2nd skb has no newer bits than the current one,
+		 * just collapse and advance it to re-examine.
+		 */
+		if (!after(TCP_SKB_CB(n)->end_seq, TCP_SKB_CB(skb)->end_seq)) {
+			n = tcp_collapse_one(sk, skb, list, root);
+			if (!n)
+				break;
+			goto examine;
 		}
 
-		/* Decided to skip this, advance start seq. */
-		start = TCP_SKB_CB(skb)->end_seq;
-	}
-	if (end_of_skbs ||
-	    (TCP_SKB_CB(skb)->seq == start && TCP_SKB_CB(skb)->end_seq == end))
-		return;
+		/* If the next skb passes the end hint, finish. */
+		if (end && !before(TCP_SKB_CB(n)->seq, *end))
+			break;
 
-	__skb_queue_head_init(&tmp);
+		/* If we can put more into the new skb created before, do so.
+		 * Otherwise we conclude the processing is worth the effort
+		 * only if the two skbs overlaps or either one is bloated.
+		 */
+		if ((!nskb || !after(TCP_SKB_CB(skb)->seq,
+		     TCP_SKB_CB(nskb)->end_seq)) &&
+		    TCP_SKB_CB(n)->seq == TCP_SKB_CB(skb)->end_seq &&
+		    tcp_win_from_space(skb->truesize) <= skb->len &&
+		    tcp_win_from_space(n->truesize) <= n->len) {
+			skb = n;
+			continue;
+		}
 
-	while (before(start, end)) {
-		int copy = min_t(int, SKB_MAX_ORDER(0, 0), end - start);
-		struct sk_buff *nskb;
+		/* Now we decide to take some action for the two.
+		 * Note: at this point, the followings hold true:
+		 * - start < TCP_SKB_CB(skb)->end_seq < TCP_SKB_CB(n)->end_seq
+		 * - TCP_SKB_CB(skb)->seq < TCP_SKB_CB(n)->seq < end
+		 *
+		 * TODO: (split +) shift + collapse if it deserves. */
+		while (after(TCP_SKB_CB(n)->end_seq, start)) {
+			if (!copy) {
+				copy = !end ? SKB_MAX_ORDER(0, 0) :
+				       min_t(int, SKB_MAX_ORDER(0, 0),
+					     *end - start);
+				nskb = alloc_skb(copy, GFP_ATOMIC);
+				if (!nskb)
+					/* Trying to trim the last nskb does not
+					 * help much, lets just abort.
+					 */
+					goto end;
 
-		nskb = alloc_skb(copy, GFP_ATOMIC);
-		if (!nskb)
-			break;
+				memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
+				TCP_SKB_CB(nskb)->seq =
+				TCP_SKB_CB(nskb)->end_seq = start;
 
-		memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
-		TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(nskb)->end_seq = start;
-		if (list)
-			__skb_queue_before(list, skb, nskb);
-		else
-			__skb_queue_tail(&tmp, nskb); /* defer rbtree insertion */
-		skb_set_owner_r(nskb, sk);
+				if (list)
+					__skb_queue_before(list, skb, nskb);
+				else
+					__skb_queue_tail(&tmp, nskb);
+				skb_set_owner_r(nskb, sk);
+			}
 
-		/* Copy data, releasing collapsed skbs. */
-		while (copy > 0) {
-			int offset = start - TCP_SKB_CB(skb)->seq;
-			int size = TCP_SKB_CB(skb)->end_seq - start;
+			/* Copy data, releasing collapsed skbs. */
+			offset = start - TCP_SKB_CB(skb)->seq;
+			size = TCP_SKB_CB(skb)->end_seq - start;
 
 			BUG_ON(offset < 0);
-			if (size > 0) {
-				size = min(copy, size);
-				if (skb_copy_bits(skb, offset, skb_put(nskb, size), size))
-					BUG();
-				TCP_SKB_CB(nskb)->end_seq += size;
-				copy -= size;
-				start += size;
-			}
-			if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
+			BUG_ON(size <= 0);
+
+			size = min(copy, size);
+			if (skb_copy_bits(skb, offset, skb_put(nskb, size),
+					  size))
+				BUG();
+
+			TCP_SKB_CB(nskb)->end_seq += size;
+			copy -= size;
+			start += size;
+
+			if (!before(start, TCP_SKB_CB(skb)->seq))
 				skb = tcp_collapse_one(sk, skb, list, root);
-				if (!skb || skb == tail)
-					goto end;
-			}
 		}
 	}
 end:
-	skb_queue_walk_safe(&tmp, skb, n)
-		tcp_rbtree_insert(root, skb);
+	if (!list)
+		skb_queue_walk_safe(&tmp, skb, n)
+			tcp_rbtree_insert(root, skb);
 }
 
 /* Collapse ofo queue. Algorithm: select contiguous sequence of skbs
@@ -4866,37 +4875,12 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
 static void tcp_collapse_ofo_queue(struct sock *sk)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
-	struct sk_buff *skb, *head;
-	u32 start, end;
-
-	skb = skb_rb_first(&tp->out_of_order_queue);
-new_range:
-	if (!skb) {
-		tp->ooo_last_skb = skb_rb_last(&tp->out_of_order_queue);
-		return;
-	}
-	start = TCP_SKB_CB(skb)->seq;
-	end = TCP_SKB_CB(skb)->end_seq;
+	struct sk_buff *head;
 
-	for (head = skb;;) {
-		skb = skb_rb_next(skb);
-
-		/* Range is terminated when we see a gap or when
-		 * we are at the queue end.
-		 */
-		if (!skb ||
-		    after(TCP_SKB_CB(skb)->seq, end) ||
-		    before(TCP_SKB_CB(skb)->end_seq, start)) {
-			tcp_collapse(sk, NULL, &tp->out_of_order_queue,
-				     head, skb, start, end);
-			goto new_range;
-		}
-
-		if (unlikely(before(TCP_SKB_CB(skb)->seq, start)))
-			start = TCP_SKB_CB(skb)->seq;
-		if (after(TCP_SKB_CB(skb)->end_seq, end))
-			end = TCP_SKB_CB(skb)->end_seq;
-	}
+	head = skb_rb_first(&tp->out_of_order_queue);
+	tcp_collapse(sk, NULL, &tp->out_of_order_queue,
+		     head, TCP_SKB_CB(head)->seq, NULL);
+	tp->ooo_last_skb = skb_rb_last(&tp->out_of_order_queue);
 }
 
 /*
@@ -4965,8 +4949,7 @@ static int tcp_prune_queue(struct sock *sk)
 	if (!skb_queue_empty(&sk->sk_receive_queue))
 		tcp_collapse(sk, &sk->sk_receive_queue, NULL,
 			     skb_peek(&sk->sk_receive_queue),
-			     NULL,
-			     tp->copied_seq, tp->rcv_nxt);
+			     tp->copied_seq, &tp->rcv_nxt);
 	sk_mem_reclaim(sk);
 
 	if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf)
-- 
2.9.4

^ permalink raw reply related

* Re: [PATCH] ath10k: spectral: Simplify error checking
From: Christos Gkekas @ 2017-10-14  8:12 UTC (permalink / raw)
  To: Kalle Valo
  Cc: ath10k@lists.infradead.org, linux-wireless@vger.kernel.org,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <87fuannse6.fsf@kamboji.qca.qualcomm.com>

On 13/10/17 12:28:50 +0000, Kalle Valo wrote:
> Christos Gkekas <chris.gekas@gmail.com> writes:
> 
> > Variable val is unsigned so checking whether it is less than zero is
> > redundant.
> >
> > Signed-off-by: Christos Gkekas <chris.gekas@gmail.com>
> > ---
> >  drivers/net/wireless/ath/ath10k/spectral.c | 5 +----
> >  1 file changed, 1 insertion(+), 4 deletions(-)
> >
> > diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c
> > index dd9cc09..1867937 100644
> > --- a/drivers/net/wireless/ath/ath10k/spectral.c
> > +++ b/drivers/net/wireless/ath/ath10k/spectral.c
> > @@ -403,10 +403,7 @@ static ssize_t write_file_spectral_count(struct file *file,
> >  		return -EFAULT;
> >  
> >  	buf[len] = '\0';
> > -	if (kstrtoul(buf, 0, &val))
> > -		return -EINVAL;
> > -
> > -	if (val < 0 || val > 255)
> > +	if (kstrtoul(buf, 0, &val) || val > 255)
> >  		return -EINVAL;
> 
> Removing the check for negative is correct but I don't think you are
> simplifying anything, on the contrary it's harder to read. Please keep
> the two if statements separate.
> 
> -- 
> Kalle Valo

You are right, will make the change and send a new patch.
Thanks for your time.

Christos Gkekas

^ permalink raw reply

* Re: [PATCH] ath9k: debug: Simplify error checking
From: Christos Gkekas @ 2017-10-14  8:16 UTC (permalink / raw)
  To: Kalle Valo; +Cc: QCA ath9k Development, linux-wireless, netdev, linux-kernel
In-Reply-To: <87infjw6us.fsf@purkki.adurom.net>

On 13/10/17 15:49:15 +0300, Kalle Valo wrote:
> Christos Gkekas <chris.gekas@gmail.com> writes:
> 
> > Variable val is unsigned so checking whether it is less than zero is
> > redundant.
> >
> > Signed-off-by: Christos Gkekas <chris.gekas@gmail.com>
> > ---
> >  drivers/net/wireless/ath/ath9k/debug.c | 5 +----
> >  1 file changed, 1 insertion(+), 4 deletions(-)
> >
> > diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
> > index 01fa301..3b93c23 100644
> > --- a/drivers/net/wireless/ath/ath9k/debug.c
> > +++ b/drivers/net/wireless/ath/ath9k/debug.c
> > @@ -1164,10 +1164,7 @@ static ssize_t write_file_tpc(struct file *file, const char __user *user_buf,
> >  		return -EFAULT;
> >  
> >  	buf[len] = '\0';
> > -	if (kstrtoul(buf, 0, &val))
> > -		return -EINVAL;
> > -
> > -	if (val < 0 || val > 1)
> > +	if (kstrtoul(buf, 0, &val) || val > 1)
> >  		return -EINVAL;
> 
> Same as with the ath10k patch, please keep the two if statements
> separate.
> 
> -- 
> Kalle Valo

Thanks, will submit an new, updated patch.

Christos Gkekas

^ permalink raw reply

* Re: [PATCH v3 0/6] staging: Introduce DPAA2 Ethernet Switch driver
From: Linus Walleij @ 2017-10-14  9:35 UTC (permalink / raw)
  To: Razvan Stefanescu, linux-netdev, OpenWrt Development List
  Cc: Greg KH, devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org,
	Alexander Graf, Arnd Bergmann, alexandru.marginean,
	bogdan.purcareata, ruxandra.radulescu, laurentiu.tudor, stuyoder
In-Reply-To: <1507194974-12050-1-git-send-email-razvan.stefanescu@nxp.com>

On Thu, Oct 5, 2017 at 11:16 AM, Razvan Stefanescu
<razvan.stefanescu@nxp.com> wrote:

> This patchset introduces the Ethernet Switch Driver for Freescale/NXP SoCs
> with DPAA2 (DataPath Acceleration Architecture v2). The driver manages
> switch objects discovered on the fsl-mc bus. A description of the driver
> can be found in the associated README file.
>
> The patchset consists of:
> * A set of libraries containing APIs for configuring and controlling
>   Management Complex (MC) switch objects
> * The DPAA2 Ethernet Switch driver
> * Patch adding ethtool support

So it appears that ethernet switches is a class of device that need their own
subsystem in Linux, before this driver can move out of staging.

I ran into the problem in OpenWRT that has these out-of-tree patches for
off-chip ethernet switches, conveniently placed under net/phy:
https://github.com/openwrt/openwrt/tree/master/target/linux/generic/files/drivers/net/phy

These are some 12 different ethernet switches. It is used in more or
less every home router out there.

It's not really working to have all of this out-of-tree, there must have been
discussions about the requirements for a proper ethernet switch subsystem.

I'm not a good net developers, just a grumpy user having to deal with all
of this out-of-tree code that's not helpful with changing interfaces like
device tree and so on.

Can you people who worked on this over the years pit in with your
requirements for an ethernet switch subsystem so we can house these
drivers in a proper way?

What we need AFAICT:

- Consensus on userspace ABI
- Consensus on ethtool extenstions
- Consensus on where in drivers/net this goes

You can kick me for not knowing what I'm talking about and how complex the
problem is now.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH] ath10k: spectral: Remove redundant check
From: Christos Gkekas @ 2017-10-14  9:41 UTC (permalink / raw)
  To: Kalle Valo, ath10k, linux-wireless, netdev, linux-kernel; +Cc: Christos Gkekas

Variable val is unsigned, so checking whether it is less than zero is
redundant.

Signed-off-by: Christos Gkekas <chris.gekas@gmail.com>
---
 drivers/net/wireless/ath/ath10k/spectral.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c
index dd9cc09..2048b1e 100644
--- a/drivers/net/wireless/ath/ath10k/spectral.c
+++ b/drivers/net/wireless/ath/ath10k/spectral.c
@@ -406,7 +406,7 @@ static ssize_t write_file_spectral_count(struct file *file,
 	if (kstrtoul(buf, 0, &val))
 		return -EINVAL;
 
-	if (val < 0 || val > 255)
+	if (val > 255)
 		return -EINVAL;
 
 	mutex_lock(&ar->conf_mutex);
-- 
2.7.4

^ permalink raw reply related

* [PATCH] ath9k: debug: Remove redundant check
From: Christos Gkekas @ 2017-10-14  9:46 UTC (permalink / raw)
  To: QCA ath9k Development, Kalle Valo, linux-wireless, netdev,
	linux-kernel
  Cc: Christos Gkekas

Variable val is unsigned, so checking whether it is less than zero is
redundant.

Signed-off-by: Christos Gkekas <chris.gekas@gmail.com>
---
 drivers/net/wireless/ath/ath9k/debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 01fa301..4f5f141 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -1167,7 +1167,7 @@ static ssize_t write_file_tpc(struct file *file, const char __user *user_buf,
 	if (kstrtoul(buf, 0, &val))
 		return -EINVAL;
 
-	if (val < 0 || val > 1)
+	if (val > 1)
 		return -EINVAL;
 
 	tpc_enabled = !!val;
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH net-next v2 1/1] bridge: return error code when deleting Vlan
From: Nikolay Aleksandrov @ 2017-10-14 10:52 UTC (permalink / raw)
  To: Roman Mashak
  Cc: David Ahern, David Miller, Stephen Hemminger,
	Linux Kernel Network Developers, Jamal Hadi Salim
In-Reply-To: <85d15rvxze.fsf@mojatatu.com>

On 13/10/17 19:00, Roman Mashak wrote:
> Nikolay Aleksandrov <nikolay@cumulusnetworks.com> writes:
> 
> 
> [...]
> 
>>>> Why do you want to return the error code here? Walking the code paths
>>>> seems like ENOENT or err from switchdev_port_obj_del are the 2 error
>>>> possibilities.
>>>
>>> For example, if you attempt to delete a non-existing vlan on a port,
>>> the current code succeeds and also sends event :
>>>
>>> rtnetlink_rcv_msg
>>>     rtnl_bridge_dellink
>>>        br_dellink
>>>           br_afspec
>>>              br_vlan_info
>>>
>>> int br_dellink(..)
>>> {
>>>   ...
>>>   err = br_afspec()
>>>   if (err == 0)
>>>       br_ifinfo_notify(RTM_NEWLINK, p);
>>> }
>>>
>>> This is misleading, so a proper errcode has to be produced.
>>>
>>
>> True, but you also change the expected behaviour because now a user can
>> clear all vlans with one request (1 - 4094), and after the change that
>> will fail with a partial delete if some vlan was missing.
> 
> Nikolay, would you like to have a crack at fixing this?
> 

Sure, need to finish something and will cook up a patch next week.

Thanks,
 Nik

^ permalink raw reply

* Re: [PATCH v3 0/6] staging: Introduce DPAA2 Ethernet Switch driver
From: Linus Walleij @ 2017-10-14 11:09 UTC (permalink / raw)
  To: Razvan Stefanescu, OpenWrt Development List,
	netdev@vger.kernel.org
  Cc: devel@driverdev.osuosl.org, Arnd Bergmann, Greg KH,
	alexandru.marginean, linux-kernel@vger.kernel.org, Alexander Graf,
	stuyoder, bogdan.purcareata, laurentiu.tudor
In-Reply-To: <CACRpkdYJCzu9Ph8XMYXt=SSAX+ZaiwXqUGgWX5UvTabmMxmBNQ@mail.gmail.com>

Top posting and resending since netdev@vger.kernel.org
is the right mail address for this. Mea culpa.

Linus Walleij

On Sat, Oct 14, 2017 at 11:35 AM, Linus Walleij
<linus.walleij@linaro.org> wrote:
> On Thu, Oct 5, 2017 at 11:16 AM, Razvan Stefanescu
> <razvan.stefanescu@nxp.com> wrote:
>
>> This patchset introduces the Ethernet Switch Driver for Freescale/NXP SoCs
>> with DPAA2 (DataPath Acceleration Architecture v2). The driver manages
>> switch objects discovered on the fsl-mc bus. A description of the driver
>> can be found in the associated README file.
>>
>> The patchset consists of:
>> * A set of libraries containing APIs for configuring and controlling
>>   Management Complex (MC) switch objects
>> * The DPAA2 Ethernet Switch driver
>> * Patch adding ethtool support
>
> So it appears that ethernet switches is a class of device that need their own
> subsystem in Linux, before this driver can move out of staging.
>
> I ran into the problem in OpenWRT that has these out-of-tree patches for
> off-chip ethernet switches, conveniently placed under net/phy:
> https://github.com/openwrt/openwrt/tree/master/target/linux/generic/files/drivers/net/phy
>
> These are some 12 different ethernet switches. It is used in more or
> less every home router out there.
>
> It's not really working to have all of this out-of-tree, there must have been
> discussions about the requirements for a proper ethernet switch subsystem.
>
> I'm not a good net developers, just a grumpy user having to deal with all
> of this out-of-tree code that's not helpful with changing interfaces like
> device tree and so on.
>
> Can you people who worked on this over the years pit in with your
> requirements for an ethernet switch subsystem so we can house these
> drivers in a proper way?
>
> What we need AFAICT:
>
> - Consensus on userspace ABI
> - Consensus on ethtool extenstions
> - Consensus on where in drivers/net this goes
>
> You can kick me for not knowing what I'm talking about and how complex the
> problem is now.
>
> Yours,
> Linus Walleij

^ permalink raw reply

* [RFC PATCH v2 0/5] TCP Wave
From: Natale Patriciello @ 2017-10-14 11:47 UTC (permalink / raw)
  To: David S . Miller, Eric Dumazet
  Cc: netdev, Ahmed Said, Natale Patriciello, Francesco Zampognaro,
	Cesare Roseti

Hello,

after the round of review on our v1 patch (you can find the relevant
thread here [1]) we have improved our code of TCP Wave, a new congestion
control algorithm.

Context: TCP Wave (TCPW) replaces the window-based transmission paradigm
of the standard TCP with a burst-based transmission, the ACK-clock
scheduling with a self-managed timer and the RTT-based congestion
control loop with an Ack-based Capacity and Congestion Estimation (ACCE)
module. In non-technical words, it sends data down the stack when a
timer expires, and the timing of the received ACKs contribute to
updating this timer regularly. We have left many debug messages to help
people understand what is going on inside the module. We plan to remove
almost all of them in the final submission.

We added this new sender paradigm without deeply touching existing code;
we re-used the existing infrastructure (TCP pacing timer, added with
commit 218af599fa635b107cfe10acf3249c4dfe5e4123), thanks to the
suggestion of Eric Dumazet. In fact, we only added four (optional) new
congestion control functions:

+         /* get the expiration time for the pacing timer (optional) */
+         u64 (*get_pacing_time)(struct sock *sk);
+         /* the pacing timer is expired (optional) */
+         void (*pacing_timer_expired)(struct sock *sk);
+         /* get the # segs to send out when the timer expires (optional) */
+         u32 (*get_segs_per_round)(struct sock *sk);
+         /* the TCP has sent some segments (optional) */
+         void (*segments_sent)(struct sock *sk, u32 sent);

to manage the previously mentioned pacing timer. With these functions, a
congestion control can set the pacing time, be informed when it expires,
indicate how many segments can leave when it expires, and know how many
segments really left the TCP layer after it has expired.

Thanks to the reviewers' suggestions we believe that the code has
improved in clarity and performance. David Laight, Stephen Hemminger,
David Miller, Neal Cardwell, Eric Dumazet, and all others that replied
privately, thank you.

Again, we would greatly appreciate any feedback, comments, suggestions,
corrections and so on. Thank you for your attention.

Cesare, Francesco, Ahmed, Natale

[1] http://lists.openwall.net/netdev/2017/07/28/219

---
Changes in v2:
 - Using TCP pacing timer instead of adding a new one
 - Using ktime_t instead of jiffies to measure the time
 - Avoided the use of custom debug facilities
 - Cleaned the variable declarations

Natale Patriciello (5):
  tcp: Added a function to retrieve pacing timer
  tcp: implemented pacing_expired
  tcp: added get_segs_per_round
  tcp: added segment sent
  wave: Added TCP Wave

 MAINTAINERS                    |    6 +
 include/net/tcp.h              |    8 +
 include/uapi/linux/inet_diag.h |   13 +
 net/ipv4/Kconfig               |   16 +
 net/ipv4/Makefile              |    1 +
 net/ipv4/tcp_output.c          |   61 ++-
 net/ipv4/tcp_wave.c            | 1035 ++++++++++++++++++++++++++++++++++++++++
 7 files changed, 1127 insertions(+), 13 deletions(-)
 create mode 100644 net/ipv4/tcp_wave.c

-- 
2.14.2

^ permalink raw reply

* [RFC PATCH v2 1/5] tcp: Added a function to retrieve pacing timer
From: Natale Patriciello @ 2017-10-14 11:47 UTC (permalink / raw)
  To: David S . Miller, Eric Dumazet
  Cc: netdev, Ahmed Said, Natale Patriciello, Francesco Zampognaro,
	Cesare Roseti
In-Reply-To: <20171014114714.3694-1-natale.patriciello@gmail.com>

Allow congestion control modules to set a custom pacing time between
the transmission of segments.
Moreover, it is assumed that the time returned by the congestion module
in the past is firm, until the timer expires; therefore, do not re-start
the timer if it is already active.

Signed-off-by: Natale Patriciello <natale.patriciello@gmail.com>
---
 include/net/tcp.h     |  2 ++
 net/ipv4/tcp_output.c | 36 +++++++++++++++++++++++++-----------
 2 files changed, 27 insertions(+), 11 deletions(-)

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 89974c5286d8..42c7aa96c4cf 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1015,6 +1015,8 @@ struct tcp_congestion_ops {
 	/* get info for inet_diag (optional) */
 	size_t (*get_info)(struct sock *sk, u32 ext, int *attr,
 			   union tcp_cc_info *info);
+	/* get the expiration time for the pacing timer (optional) */
+	u64 (*get_pacing_time)(struct sock *sk);
 
 	char 		name[TCP_CA_NAME_MAX];
 	struct module 	*owner;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 0bc9e46a5369..ec5977156c26 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -950,22 +950,36 @@ static bool tcp_needs_internal_pacing(const struct sock *sk)
 	return smp_load_acquire(&sk->sk_pacing_status) == SK_PACING_NEEDED;
 }
 
+static bool tcp_pacing_timer_check(const struct sock *sk)
+{
+	return hrtimer_active(&tcp_sk(sk)->pacing_timer);
+}
+
 static void tcp_internal_pacing(struct sock *sk, const struct sk_buff *skb)
 {
+	const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops;
 	u64 len_ns;
-	u32 rate;
 
 	if (!tcp_needs_internal_pacing(sk))
 		return;
-	rate = sk->sk_pacing_rate;
-	if (!rate || rate == ~0U)
-		return;
-
-	/* Should account for header sizes as sch_fq does,
-	 * but lets make things simple.
-	 */
-	len_ns = (u64)skb->len * NSEC_PER_SEC;
-	do_div(len_ns, rate);
+
+	if (ca_ops && ca_ops->get_pacing_time) {
+		if (tcp_pacing_timer_check(sk))
+			return;
+
+		len_ns = ca_ops->get_pacing_time(sk);
+	} else {
+		u32 rate = sk->sk_pacing_rate;
+
+		if (!rate || rate == ~0U)
+			return;
+
+		/* Should account for header sizes as sch_fq does,
+		 * but lets make things simple.
+		 */
+		len_ns = (u64)skb->len * NSEC_PER_SEC;
+		do_div(len_ns, rate);
+	}
 	hrtimer_start(&tcp_sk(sk)->pacing_timer,
 		      ktime_add_ns(ktime_get(), len_ns),
 		      HRTIMER_MODE_ABS_PINNED);
@@ -2123,7 +2137,7 @@ static int tcp_mtu_probe(struct sock *sk)
 static bool tcp_pacing_check(const struct sock *sk)
 {
 	return tcp_needs_internal_pacing(sk) &&
-	       hrtimer_active(&tcp_sk(sk)->pacing_timer);
+		tcp_pacing_timer_check(sk);
 }
 
 /* TCP Small Queues :
-- 
2.14.2

^ permalink raw reply related

* [RFC PATCH v2 2/5] tcp: implemented pacing_expired
From: Natale Patriciello @ 2017-10-14 11:47 UTC (permalink / raw)
  To: David S . Miller, Eric Dumazet
  Cc: netdev, Ahmed Said, Natale Patriciello, Francesco Zampognaro,
	Cesare Roseti
In-Reply-To: <20171014114714.3694-1-natale.patriciello@gmail.com>

Inform the congestion control that the pacing timer, previously set,
has expired. The commit does not consider situations in which another
kind of timer has expired (e.g., a tail loss probe, a retransmission
timer...)

Signed-off-by: Natale Patriciello <natale.patriciello@gmail.com>
---
 include/net/tcp.h     | 2 ++
 net/ipv4/tcp_output.c | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 42c7aa96c4cf..e817f0669d0e 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1017,6 +1017,8 @@ struct tcp_congestion_ops {
 			   union tcp_cc_info *info);
 	/* get the expiration time for the pacing timer (optional) */
 	u64 (*get_pacing_time)(struct sock *sk);
+	/* the pacing timer is expired (optional) */
+	void (*pacing_timer_expired)(struct sock *sk);
 
 	char 		name[TCP_CA_NAME_MAX];
 	struct module 	*owner;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index ec5977156c26..25b4cf0802f2 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2241,6 +2241,7 @@ void tcp_chrono_stop(struct sock *sk, const enum tcp_chrono type)
 static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
 			   int push_one, gfp_t gfp)
 {
+	const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops;
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
 	unsigned int tso_segs, sent_pkts;
@@ -2263,6 +2264,11 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
 
 	max_segs = tcp_tso_segs(sk, mss_now);
 	tcp_mstamp_refresh(tp);
+
+	if (!tcp_pacing_timer_check(sk) &&
+	    ca_ops && ca_ops->pacing_timer_expired)
+		ca_ops->pacing_timer_expired(sk);
+
 	while ((skb = tcp_send_head(sk))) {
 		unsigned int limit;
 
-- 
2.14.2

^ permalink raw reply related

* [RFC PATCH v2 3/5] tcp: added get_segs_per_round
From: Natale Patriciello @ 2017-10-14 11:47 UTC (permalink / raw)
  To: David S . Miller, Eric Dumazet
  Cc: netdev, Ahmed Said, Natale Patriciello, Francesco Zampognaro,
	Cesare Roseti
In-Reply-To: <20171014114714.3694-1-natale.patriciello@gmail.com>

Usually, the pacing time is provided per-segment. In some occasion, this
time refers to the time between a group of segments. With this commit, add
the possibility for the congestion control module to tell the TCP socket
how many segments can be sent out before pausing and setting a pacing
timer.

Signed-off-by: Natale Patriciello <natale.patriciello@gmail.com>
---
 include/net/tcp.h     |  2 ++
 net/ipv4/tcp_output.c | 13 +++++++++----
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/include/net/tcp.h b/include/net/tcp.h
index e817f0669d0e..3561eca5a61f 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1019,6 +1019,8 @@ struct tcp_congestion_ops {
 	u64 (*get_pacing_time)(struct sock *sk);
 	/* the pacing timer is expired (optional) */
 	void (*pacing_timer_expired)(struct sock *sk);
+	/* get the # segs to send out when the timer expires (optional) */
+	u32 (*get_segs_per_round)(struct sock *sk);
 
 	char 		name[TCP_CA_NAME_MAX];
 	struct module 	*owner;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 25b4cf0802f2..e37941e4328b 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2249,6 +2249,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
 	int result;
 	bool is_cwnd_limited = false, is_rwnd_limited = false;
 	u32 max_segs;
+	u32 pacing_allowed_segs = 0;
 
 	sent_pkts = 0;
 
@@ -2265,14 +2266,18 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
 	max_segs = tcp_tso_segs(sk, mss_now);
 	tcp_mstamp_refresh(tp);
 
-	if (!tcp_pacing_timer_check(sk) &&
-	    ca_ops && ca_ops->pacing_timer_expired)
-		ca_ops->pacing_timer_expired(sk);
+	if (!tcp_pacing_timer_check(sk)) {
+		pacing_allowed_segs = 1;
+		if (ca_ops && ca_ops->pacing_timer_expired)
+			ca_ops->pacing_timer_expired(sk);
+		if (ca_ops && ca_ops->get_segs_per_round)
+			pacing_allowed_segs = ca_ops->get_segs_per_round(sk);
+	}
 
 	while ((skb = tcp_send_head(sk))) {
 		unsigned int limit;
 
-		if (tcp_pacing_check(sk))
+		if (sent_pkts >= pacing_allowed_segs)
 			break;
 
 		tso_segs = tcp_init_tso_segs(skb, mss_now);
-- 
2.14.2

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox