* [PATCH V2 net-next 04/10] net: hns3: Rename mac loopback to app loopback
From: Salil Mehta @ 2018-09-29 14:56 UTC (permalink / raw)
To: davem
Cc: salil.mehta, yisen.zhuang, lipeng321, mehta.salil, netdev,
linux-kernel, linuxarm, Fuyun Liang
In-Reply-To: <20180929145622.5448-1-salil.mehta@huawei.com>
From: Fuyun Liang <liangfuyun1@huawei.com>
In fact, our implementation of mac loopback is the implementation of app
loopback now. Current name is wrong. This patch renames mac loopback to
app loopback.
Signed-off-by: Fuyun Liang <liangfuyun1@huawei.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
drivers/net/ethernet/hisilicon/hns3/hnae3.h | 4 ++--
drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 8 ++++----
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 14 +++++++-------
3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
index 03d7878c6168..27155ea76c3a 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -84,7 +84,7 @@ struct hnae3_queue {
/*hnae3 loop mode*/
enum hnae3_loop {
- HNAE3_LOOP_MAC,
+ HNAE3_LOOP_APP,
HNAE3_LOOP_SERDES,
HNAE3_LOOP_PHY,
HNAE3_LOOP_NONE,
@@ -478,7 +478,7 @@ struct hnae3_unic_private_info {
struct hnae3_queue **tqp; /* array base of all TQPs of this instance */
};
-#define HNAE3_SUPPORT_MAC_LOOPBACK BIT(0)
+#define HNAE3_SUPPORT_APP_LOOPBACK BIT(0)
#define HNAE3_SUPPORT_PHY_LOOPBACK BIT(1)
#define HNAE3_SUPPORT_SERDES_LOOPBACK BIT(2)
#define HNAE3_SUPPORT_VF BIT(3)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
index 86587cf2a676..75ebd2e95236 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
@@ -79,7 +79,7 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en)
switch (loop) {
case HNAE3_LOOP_SERDES:
- case HNAE3_LOOP_MAC:
+ case HNAE3_LOOP_APP:
ret = h->ae_algo->ops->set_loopback(h, loop, en);
break;
default:
@@ -286,9 +286,9 @@ static void hns3_self_test(struct net_device *ndev,
if (eth_test->flags != ETH_TEST_FL_OFFLINE)
return;
- st_param[HNAE3_LOOP_MAC][0] = HNAE3_LOOP_MAC;
- st_param[HNAE3_LOOP_MAC][1] =
- h->flags & HNAE3_SUPPORT_MAC_LOOPBACK;
+ st_param[HNAE3_LOOP_APP][0] = HNAE3_LOOP_APP;
+ st_param[HNAE3_LOOP_APP][1] =
+ h->flags & HNAE3_SUPPORT_APP_LOOPBACK;
st_param[HNAE3_LOOP_SERDES][0] = HNAE3_LOOP_SERDES;
st_param[HNAE3_LOOP_SERDES][1] =
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index 33e97fcfe74e..a0f6329020f6 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -49,7 +49,7 @@ static const struct pci_device_id ae_algo_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, ae_algo_pci_tbl);
static const char hns3_nic_test_strs[][ETH_GSTRING_LEN] = {
- "Mac Loopback test",
+ "App Loopback test",
"Serdes Loopback test",
"Phy Loopback test"
};
@@ -493,7 +493,7 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset)
hdev->hw.mac.speed == HCLGE_MAC_SPEED_100M ||
hdev->hw.mac.speed == HCLGE_MAC_SPEED_1G) {
count += 1;
- handle->flags |= HNAE3_SUPPORT_MAC_LOOPBACK;
+ handle->flags |= HNAE3_SUPPORT_APP_LOOPBACK;
}
count++;
@@ -521,9 +521,9 @@ static void hclge_get_strings(struct hnae3_handle *handle,
p);
p = hclge_tqps_get_strings(handle, p);
} else if (stringset == ETH_SS_TEST) {
- if (handle->flags & HNAE3_SUPPORT_MAC_LOOPBACK) {
+ if (handle->flags & HNAE3_SUPPORT_APP_LOOPBACK) {
memcpy(p,
- hns3_nic_test_strs[HNAE3_LOOP_MAC],
+ hns3_nic_test_strs[HNAE3_LOOP_APP],
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
@@ -3345,7 +3345,7 @@ static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable)
"mac enable fail, ret =%d.\n", ret);
}
-static int hclge_set_mac_loopback(struct hclge_dev *hdev, bool en)
+static int hclge_set_app_loopback(struct hclge_dev *hdev, bool en)
{
struct hclge_config_mac_mode_cmd *req;
struct hclge_desc desc;
@@ -3459,8 +3459,8 @@ static int hclge_set_loopback(struct hnae3_handle *handle,
int i, ret;
switch (loop_mode) {
- case HNAE3_LOOP_MAC:
- ret = hclge_set_mac_loopback(hdev, en);
+ case HNAE3_LOOP_APP:
+ ret = hclge_set_app_loopback(hdev, en);
break;
case HNAE3_LOOP_SERDES:
ret = hclge_set_serdes_loopback(hdev, en);
--
2.11.0
^ permalink raw reply related
* [PATCH V2 net-next 03/10] net: hns3: Rename loop mode
From: Salil Mehta @ 2018-09-29 14:56 UTC (permalink / raw)
To: davem
Cc: salil.mehta, yisen.zhuang, lipeng321, mehta.salil, netdev,
linux-kernel, linuxarm, Fuyun Liang
In-Reply-To: <20180929145622.5448-1-salil.mehta@huawei.com>
From: Fuyun Liang <liangfuyun1@huawei.com>
Our loop mode includes mac loop, serdes loop and phy loop. Not all of them
are related with mac. This patch corrects their names.
Signed-off-by: Fuyun Liang <liangfuyun1@huawei.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
drivers/net/ethernet/hisilicon/hns3/hnae3.h | 8 ++++----
drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 12 ++++++------
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 10 +++++-----
3 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
index 564afd4c1323..03d7878c6168 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -84,10 +84,10 @@ struct hnae3_queue {
/*hnae3 loop mode*/
enum hnae3_loop {
- HNAE3_MAC_INTER_LOOP_MAC,
- HNAE3_MAC_INTER_LOOP_SERDES,
- HNAE3_MAC_INTER_LOOP_PHY,
- HNAE3_MAC_LOOP_NONE,
+ HNAE3_LOOP_MAC,
+ HNAE3_LOOP_SERDES,
+ HNAE3_LOOP_PHY,
+ HNAE3_LOOP_NONE,
};
enum hnae3_client_type {
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
index 8803a8721c8e..86587cf2a676 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
@@ -78,8 +78,8 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en)
return -EOPNOTSUPP;
switch (loop) {
- case HNAE3_MAC_INTER_LOOP_SERDES:
- case HNAE3_MAC_INTER_LOOP_MAC:
+ case HNAE3_LOOP_SERDES:
+ case HNAE3_LOOP_MAC:
ret = h->ae_algo->ops->set_loopback(h, loop, en);
break;
default:
@@ -286,12 +286,12 @@ static void hns3_self_test(struct net_device *ndev,
if (eth_test->flags != ETH_TEST_FL_OFFLINE)
return;
- st_param[HNAE3_MAC_INTER_LOOP_MAC][0] = HNAE3_MAC_INTER_LOOP_MAC;
- st_param[HNAE3_MAC_INTER_LOOP_MAC][1] =
+ st_param[HNAE3_LOOP_MAC][0] = HNAE3_LOOP_MAC;
+ st_param[HNAE3_LOOP_MAC][1] =
h->flags & HNAE3_SUPPORT_MAC_LOOPBACK;
- st_param[HNAE3_MAC_INTER_LOOP_SERDES][0] = HNAE3_MAC_INTER_LOOP_SERDES;
- st_param[HNAE3_MAC_INTER_LOOP_SERDES][1] =
+ st_param[HNAE3_LOOP_SERDES][0] = HNAE3_LOOP_SERDES;
+ st_param[HNAE3_LOOP_SERDES][1] =
h->flags & HNAE3_SUPPORT_SERDES_LOOPBACK;
if (if_running)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index 2de5a0061dc9..33e97fcfe74e 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -523,19 +523,19 @@ static void hclge_get_strings(struct hnae3_handle *handle,
} else if (stringset == ETH_SS_TEST) {
if (handle->flags & HNAE3_SUPPORT_MAC_LOOPBACK) {
memcpy(p,
- hns3_nic_test_strs[HNAE3_MAC_INTER_LOOP_MAC],
+ hns3_nic_test_strs[HNAE3_LOOP_MAC],
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
if (handle->flags & HNAE3_SUPPORT_SERDES_LOOPBACK) {
memcpy(p,
- hns3_nic_test_strs[HNAE3_MAC_INTER_LOOP_SERDES],
+ hns3_nic_test_strs[HNAE3_LOOP_SERDES],
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
if (handle->flags & HNAE3_SUPPORT_PHY_LOOPBACK) {
memcpy(p,
- hns3_nic_test_strs[HNAE3_MAC_INTER_LOOP_PHY],
+ hns3_nic_test_strs[HNAE3_LOOP_PHY],
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
@@ -3459,10 +3459,10 @@ static int hclge_set_loopback(struct hnae3_handle *handle,
int i, ret;
switch (loop_mode) {
- case HNAE3_MAC_INTER_LOOP_MAC:
+ case HNAE3_LOOP_MAC:
ret = hclge_set_mac_loopback(hdev, en);
break;
- case HNAE3_MAC_INTER_LOOP_SERDES:
+ case HNAE3_LOOP_SERDES:
ret = hclge_set_serdes_loopback(hdev, en);
break;
default:
--
2.11.0
^ permalink raw reply related
* [PATCH V2 net-next 02/10] net: hns3: Set extra mac address of pause param for HW
From: Salil Mehta @ 2018-09-29 14:56 UTC (permalink / raw)
To: davem
Cc: salil.mehta, yisen.zhuang, lipeng321, mehta.salil, netdev,
linux-kernel, linuxarm, Fuyun Liang
In-Reply-To: <20180929145622.5448-1-salil.mehta@huawei.com>
From: Fuyun Liang <liangfuyun1@huawei.com>
The extra mac address of pause param is used to do double check
for pause frame. This patch set it to HW. If we do not do that,
pfc pause frame will be transferred protocol stack when normal
flow control mode is enabled.
Signed-off-by: Fuyun Liang <liangfuyun1@huawei.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 1 +
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 4 ++++
2 files changed, 5 insertions(+)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
index 00bb39451bc5..ab7280d7f79c 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
@@ -193,6 +193,7 @@ static int hclge_pause_param_cfg(struct hclge_dev *hdev, const u8 *addr,
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_MAC_PARA, false);
ether_addr_copy(pause_param->mac_addr, addr);
+ ether_addr_copy(pause_param->mac_addr_extra, addr);
pause_param->pause_trans_gap = pause_trans_gap;
pause_param->pause_trans_time = cpu_to_le16(pause_trans_time);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
index dd4c194747c1..e1568b826aac 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h
@@ -106,6 +106,10 @@ struct hclge_cfg_pause_param_cmd {
u8 pause_trans_gap;
u8 rsvd;
__le16 pause_trans_time;
+ u8 rsvd1[6];
+ /* extra mac address to do double check for pause frame */
+ u8 mac_addr_extra[ETH_ALEN];
+ u16 rsvd2;
};
struct hclge_pfc_stats_cmd {
--
2.11.0
^ permalink raw reply related
* [PATCH V2 net-next 01/10] net: hns3: Add support for sctp checksum offload
From: Salil Mehta @ 2018-09-29 14:56 UTC (permalink / raw)
To: davem
Cc: salil.mehta, yisen.zhuang, lipeng321, mehta.salil, netdev,
linux-kernel, linuxarm, Fuyun Liang
In-Reply-To: <20180929145622.5448-1-salil.mehta@huawei.com>
From: Peng Li <lipeng321@huawei.com>
This patch adds support for sctp checksum offload.
Signed-off-by: Fuyun Liang <liangfuyun1@huawei.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
---
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index 5a4773a9b4a5..3fc38228f459 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -1740,7 +1740,7 @@ static void hns3_set_default_feature(struct net_device *netdev)
NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
- NETIF_F_GSO_UDP_TUNNEL_CSUM;
+ NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
netdev->hw_enc_features |= NETIF_F_TSO_MANGLEID;
@@ -1752,21 +1752,21 @@ static void hns3_set_default_feature(struct net_device *netdev)
NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
- NETIF_F_GSO_UDP_TUNNEL_CSUM;
+ NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
netdev->vlan_features |=
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO |
NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
- NETIF_F_GSO_UDP_TUNNEL_CSUM;
+ NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
- NETIF_F_GSO_UDP_TUNNEL_CSUM;
+ NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
if (pdev->revision != 0x20)
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
--
2.11.0
^ permalink raw reply related
* [PATCH V2 net-next 00/10] Cleanups, minor additions & fixes for HNS3 driver
From: Salil Mehta @ 2018-09-29 14:56 UTC (permalink / raw)
To: davem
Cc: salil.mehta, yisen.zhuang, lipeng321, mehta.salil, netdev,
linux-kernel, linuxarm
This patch-set contains cleans-ups, minor changes and fixes to the HNS3 driver.
Change Summary:
v1->v2
* Fixed Kbuild error due to missed patch in the current submission.
For now, replaced HNAE3_REVISION_ID_21 macro with 0x21
* Fixed issues identified by Eric Dumazet and spelling mistakes by David Miller
Link: https://lkml.org/lkml/2018/9/28/842
Note:
Hi David,
>From v1->v2 changes only exists in below patch
"net: hns3: Add serdes parallel inner loopback support"
Thanks.
Fuyun Liang (4):
net: hns3: Set extra mac address of pause param for HW
net: hns3: Rename loop mode
net: hns3: Rename mac loopback to app loopback
net: hns3: Add serdes parallel inner loopback support
Huazhong Tan (3):
net: hns3: Change return type of hclge_tm_schd_info_update()
net: hns3: Modify hns3_get_max_available_channels
net: hns3: Fix loss of coal configuration while doing reset
Peng Li (1):
net: hns3: Add support for sctp checksum offload
Yunsheng Lin (2):
net: hns3: Fix for packet buffer setting bug
net: hns3: Fix for netdev not up problem when setting mtu
drivers/net/ethernet/hisilicon/hns3/hnae3.h | 16 ++--
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 101 ++++++++++-----------
drivers/net/ethernet/hisilicon/hns3/hns3_enet.h | 2 +
drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 24 +++--
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 1 +
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c | 8 +-
.../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 94 ++++++++++++-------
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 10 +-
.../net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 6 +-
.../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 4 +-
10 files changed, 157 insertions(+), 109 deletions(-)
--
2.11.0
^ permalink raw reply
* Re: [PATCH net-next v6 04/23] zinc: ChaCha20 x86_64 implementation
From: Borislav Petkov @ 2018-09-29 8:11 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Jason A. Donenfeld, LKML, Netdev, Linux Crypto Mailing List,
David Miller, Greg Kroah-Hartman, Samuel Neves, Andrew Lutomirski,
Jean-Philippe Aumasson, Andy Polyakov, Thomas Gleixner,
Ingo Molnar, X86 ML
In-Reply-To: <CAKv+Gu_jawg7R1n0qz75=H16J+WNx4aRhEsAt2WMNUkPAhD2og@mail.gmail.com>
On Sat, Sep 29, 2018 at 10:00:29AM +0200, Ard Biesheuvel wrote:
> Note that this is the author of the *patch* not necessarily the author
> of the code.
>
> Anyone is free to submit patches adding code authored by others as
> long as the author has made it available under a suitable license, and
> this is actually the whole point of the S-o-B: you are stating to the
> next guy that the code included in your patch was made available to
> you under a compatible license.
... and the actual author could be named with Originally-by or
Co-Developed-by:, and even in free text in the commit message.
But the correct SOB chain denoting who handled the patch on its way up,
is important.
--
Regards/Gruss,
Boris.
Good mailing practices for 400: avoid top-posting and trim the reply.
^ permalink raw reply
* Re: [PATCH net 0/2] s390/qeth: fixes 2019-09-26
From: David Miller @ 2018-09-29 6:08 UTC (permalink / raw)
To: jwi; +Cc: netdev, linux-s390, schwidefsky, heiko.carstens, raspl, ubraun
In-Reply-To: <3d426fbf-9045-7af9-6a06-4c840ec7d690@linux.ibm.com>
From: Julian Wiedmann <jwi@linux.ibm.com>
Date: Fri, 28 Sep 2018 11:05:22 +0200
> On 26.09.2018 19:39, David Miller wrote:
>> From: Julian Wiedmann <jwi@linux.ibm.com>
>> Date: Wed, 26 Sep 2018 18:07:08 +0200
>>
>>> please apply two qeth patches for -net. The first is a trivial cleanup
>>> required for patch #2 by Jean, which fixes a potential endless loop.
>>
>> Series applied, thank you.
>>
>
> Odd, doesn't look like they arrived in -net though. Forgot to push them out?
> Thanks.
They are there.
When I say "applied" that means "in my tree and build testing".
Sometimes I have to run off somewhere while the build is still running
and thus the push doesn't happen until I get back, which can be up to
a day later.
^ permalink raw reply
* [PATCH] gpiolib: Fix incorrect use of find_next_zero_bit()
From: Janusz Krzysztofik @ 2018-09-29 12:20 UTC (permalink / raw)
To: Linus Walleij
Cc: Andrew Lunn, Ulf Hansson, Tony Lindgren, Dominik Brodowski,
Yegor Yefremov, netdev, linux-i2c, Peter Meerwald-Stadler,
Marek Szyprowski, devel, Florian Fainelli, Peter Rosin,
Janusz Krzysztofik, Krzysztof Kozlowski, Kishon Vijay Abraham I,
linux-iio, Peter Korsgaard, Geert Uytterhoeven, linux-serial,
Jiri Slaby, Michael Hennerich, Uwe Kleine-König, linux-gpio
In-Reply-To: <20180923235336.22148-2-jmkrzyszt@gmail.com>
Commit b17566a6b08b ("gpiolib: Implement fast processing path in
get/set array"), already fixed to some extent with commit 5d581d7e8cdc
("gpiolib: Fix missing updates of bitmap index"), introduced a new mode
of processing bitmaps where bits applicable for fast bitmap processing
path are supposed to be skipped while iterating bits which don't apply.
Unfortunately, find_next_zero_bit() function supposed to skip over
those fast bits is always called with a 'start' argument equal to an
index of last zero bit found and returns that index value again an
again, causing an infinite loop.
Fix it by incrementing the index uncoditionally before
find_next_zero_bit() is optionally called.
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Janusz Krzysztofik <jmkrzyszt@gmail.com>
---
Marek,
Could you please test it on top of next-20180920 with "gpiolib: Fix
missing updates of bitmap index" and optionally "mmc: pwrseq_simple:
Fix incorrect handling of GPIO bitmap" also applied?
Thanks,
Janusz
drivers/gpio/gpiolib.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 6ae13e3e05f1..940b543e966d 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2878,12 +2878,11 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
int hwgpio = gpio_chip_hwgpio(desc);
__set_bit(hwgpio, mask);
+ i++;
if (array_info)
i = find_next_zero_bit(array_info->get_mask,
array_size, i);
- else
- i++;
} while ((i < array_size) &&
(desc_array[i]->gdev->chip == chip));
@@ -2903,12 +2902,11 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
value = !value;
__assign_bit(j, value_bitmap, value);
trace_gpio_value(desc_to_gpio(desc), 1, value);
+ j++;
if (array_info)
j = find_next_zero_bit(array_info->get_mask, i,
j);
- else
- j++;
}
if (mask != fastpath)
@@ -3191,12 +3189,11 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
__clear_bit(hwgpio, bits);
count++;
}
+ i++;
if (array_info)
i = find_next_zero_bit(array_info->set_mask,
array_size, i);
- else
- i++;
} while ((i < array_size) &&
(desc_array[i]->gdev->chip == chip));
/* push collected bits to outputs */
--
2.16.4
^ permalink raw reply related
* Re: [PATCH net-next v6 00/23] WireGuard: Secure Network Tunnel
From: Willy Tarreau @ 2018-09-29 5:35 UTC (permalink / raw)
To: Jason A. Donenfeld
Cc: Ard Biesheuvel, Eric Biggers, LKML, Netdev,
Linux Crypto Mailing List, David Miller, Greg Kroah-Hartman
In-Reply-To: <CAHmME9pPTxx5JP+8WQ0jLVBXxJmRKy2=z5YOSx_ar7JZqBQ1CA@mail.gmail.com>
On Sat, Sep 29, 2018 at 04:40:03AM +0200, Jason A. Donenfeld wrote:
> > CRC32 is another case study that I would like to bring up:
> > - the current status is a bit of a mess, where we treat crc32() and
> > crc32c() differently - the latter is exposed by libcrc32.ko as a
> > wrapper around the crypto API, and there is some networking code (SCTP
> > iirc) that puts another kludge on top of that to ensure that the code
> > is not used before the module is loaded
> > - we have C versions, scalar hw instruction based versions and
> > carryless multiplication based versions for various architectures
> > - on ST platforms, we have a synchronous hw accelerator that is 10x
> > faster than C code on the same platform.
> >
> > AFAICT none of its current users rely on the async interface or
> > runtime dispatch of the 'hash'.
>
> I've added Willy to the CC, as we were actually discussing the crc32
> case together two days ago. If my understanding was correct, he seemed
> to think it'd be pretty useful too.
Yep, I've had a hard time finding a suitable implementation when I wrote
libslz (deflate+gzip compression). Some were totally inefficient in C,
spending their time negating the value twice for each byte because they
were using the pre-computed tables found in literature, some were using
optimized SIMD and I didn't understand them at all. Finally I spent some
time studying the principle and implemented mine. Later I discovered
that ARMv8 chips have a crc32 instruction for this which is very fast.
I tried it and it works much faster than my C implementation. For me
it's a perfect example of something that could go into a lib like zinc.
> It seems like unifying the crc32 implementations at some point would
> make sense, and since there's no usage of these as part of the crypto
> api, providing crc32 via a vanilla function call seems reasonable.
> It's not clear that on some strict formal level, crc32 belongs
> anywhere near Zinc, since it's not _exactly_ in the same category...
Well, it's a hash. Not a cryptographically secure one (32 bits only)
but definitely a hash usable (and used) for many cases. Those who need
a hash could start with SHA2 and figure that they don't need something
that secure since they only use 32 output bits and be fine with CRC32
instead. So that would make sense.
> But one could broaden the scope a bit and make the argument that this
> general idea of accepting some bytes, doing some "pure" arithmetic
> operations from a particular discipline on them in slightly different
> ways depending on the architecture, and then returning some other
> bytes, is what in essence is happening with these all of these
> function calls, no matter their security or intended use; so if crc32
> would benefit from being implemented using the exact same design
> patterns, then it might as well be grouped in with the rest of Zinc.
You should avoid suggesting it like this because you may end up
implementing addition :-) You should stick to the initial intent which
is to implement painful and boring stuff like crypto. But when you
see how to implement CRC32, you'll see that it's as painful to
implement as a crypto function. You start with a reference, you're
not satisfied and start to optimize various parts of it until you
break it for some inputs without noticing. I'm pretty sure that it
reminds you your own experience with some crypto functions because
I think we've all been in that situation in this domain.
> On the other hand, this might be a bit of a slippery slope ("are
> compression functions next?"),
I was thinking about it as well. There's a relation between crypto
and compression, all transform intelligible information into hidden
one in a reversable way, so the API is quite similar. One could argue
that compression usually requires memory allocation and huge states,
so that's probably not for the same use cases if the functions have
to deal with memory allocations.
In my opinion currently we have :
- asymmetric crypto whose goal is to reversably encrypt/decrypt
in order to protect confidentiality on small data like keys,
or to sign in order to authenticate small data like hashes
- symmetric crypto whose goal is to protect confidentiality on
data blocks.
- hashes whose goal is to provide integrity of data blocks (crc32
fall into this category by the way)
It's visible that despite using similar APIs, compression doesn't
fit into any of these categories.
> and a libcrc32.ko could just as well
> exist as a standalone thing.
Having it included could simplify exposing it as a static inline
function when it's a single native instruction on the CPU.
Just my two cents,
Willy
^ permalink raw reply
* Re: [Patch net-next v3] net_sched: change tcf_del_walker() to take idrinfo->lock
From: Cong Wang @ 2018-09-29 4:47 UTC (permalink / raw)
To: Ido Schimmel
Cc: Linux Kernel Network Developers, Jiri Pirko, Jamal Hadi Salim,
Vlad Buslov
In-Reply-To: <CAM_iQpXQXwwRvzuCpkrBY6cwgi8vX1mymy_ca3H4rfjrAha58Q@mail.gmail.com>
On Fri, Sep 28, 2018 at 11:29 AM Cong Wang <xiyou.wangcong@gmail.com> wrote:
>
> On Fri, Sep 28, 2018 at 11:11 AM Ido Schimmel <idosch@idosch.org> wrote:
> > I don't think this will work given the reference count already dropped
> > to 0, which is why the template deletion function was invoked. I didn't
> > test the patch, but I don't see what would prevent the chain from being
> > freed.
>
> Good catch! So I should just "move" tcf_chain_destroy() into cls_flower.
>
> A patch is being compiled now.
Just FYI, the crash is fixed, but another RCU warning pops up after
my fix. So I am still debugging it, it is related to the kfree_rcu() in
tcf_chain_destroy().
^ permalink raw reply
* Re: [PATCH net-next v6 00/23] WireGuard: Secure Network Tunnel
From: Jason A. Donenfeld @ 2018-09-29 2:40 UTC (permalink / raw)
To: Ard Biesheuvel, Willy Tarreau
Cc: Eric Biggers, LKML, Netdev, Linux Crypto Mailing List,
David Miller, Greg Kroah-Hartman
In-Reply-To: <CAKv+Gu-8eiMkrJtpnMKzT=m9zGvY5qHVAmLM_rFA3gxk2gV-zw@mail.gmail.com>
[+Willy]
Hi Ard,
On Fri, Sep 28, 2018 at 7:47 PM Ard Biesheuvel
<ard.biesheuvel@linaro.org> wrote:
>
> On 28 September 2018 at 07:46, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> > WireGuard is indeed quite opinionated in its primitive choices, but I
> > don't think it'd be wise to apply the same design to Zinc. There are
> > APIs where the goal is to have a limited set of high-level functions,
> > and have those implemented in only a preferred set of primitives. NaCl
> > is a good example of this -- functions like "crypto_secretbox" that
> > are actually xsalsapoly under the hood. Zinc doesn't intend to become
> > an API like those, but rather to provide the actual primitives for use
> > cases where that specific primitive is used. Sometimes the kernel is
> > in the business of being able to pick its own crypto -- random.c, tcp
> > sequence numbers, big_key.c, etc -- but most of the time the kernel is
> > in the business of implementing other people's crypto, for specific
> > devices/protocols/diskformats. And for those use cases we need not
> > some high-level API like NaCl, but rather direct access to the
> > primitives that are required to implement those drivers. WireGuard is
> > one such example, but so would be Bluetooth, CIFS/SMB, WiFi, and so
> > on. We're in the business of writing drivers, after all. So, no, I
> > don't think I'd knock down the addition of a primitive because of a
> > simple preference for a different primitive, if it was clearly the
> > case that the driver requiring it really benefited from having
> > accessible via the plain Zinc function calls. Sorry if I hadn't made
> > this clear earlier -- I thought Ard had asked more or less the same
> > thing about DES and I answered accordingly, but maybe that wasn't made
> > clear enough there.
> >
>
> CRC32 is another case study that I would like to bring up:
> - the current status is a bit of a mess, where we treat crc32() and
> crc32c() differently - the latter is exposed by libcrc32.ko as a
> wrapper around the crypto API, and there is some networking code (SCTP
> iirc) that puts another kludge on top of that to ensure that the code
> is not used before the module is loaded
> - we have C versions, scalar hw instruction based versions and
> carryless multiplication based versions for various architectures
> - on ST platforms, we have a synchronous hw accelerator that is 10x
> faster than C code on the same platform.
>
> AFAICT none of its current users rely on the async interface or
> runtime dispatch of the 'hash'.
I've added Willy to the CC, as we were actually discussing the crc32
case together two days ago. If my understanding was correct, he seemed
to think it'd be pretty useful too.
It seems like unifying the crc32 implementations at some point would
make sense, and since there's no usage of these as part of the crypto
api, providing crc32 via a vanilla function call seems reasonable.
It's not clear that on some strict formal level, crc32 belongs
anywhere near Zinc, since it's not _exactly_ in the same category...
But one could broaden the scope a bit and make the argument that this
general idea of accepting some bytes, doing some "pure" arithmetic
operations from a particular discipline on them in slightly different
ways depending on the architecture, and then returning some other
bytes, is what in essence is happening with these all of these
function calls, no matter their security or intended use; so if crc32
would benefit from being implemented using the exact same design
patterns, then it might as well be grouped in with the rest of Zinc.
On the other hand, this might be a bit of a slippery slope ("are
compression functions next?"), and a libcrc32.ko could just as well
exist as a standalone thing. I can see it both ways and some other
arguments too, but also this might form a good setting for some much
needed cleanup of the crc32. So that's definitely something we can
consider.
Regarding the synchronous ST driver: I'll give it a thorough read
through, but I do wonder off the bat if actually it'd be possible to
incorporate that into the Zinc paradigm in a fairly non-intrusive way.
I'll give that some thought and play around a bit with it.
Jason
^ permalink raw reply
* Re: [PATCH net-next v6 04/23] zinc: ChaCha20 x86_64 implementation
From: Abel Vesa @ 2018-09-29 8:27 UTC (permalink / raw)
To: Borislav Petkov
Cc: Ard Biesheuvel, Jason A. Donenfeld, LKML, Netdev,
Linux Crypto Mailing List, David Miller, Greg Kroah-Hartman,
Samuel Neves, Andrew Lutomirski, Jean-Philippe Aumasson,
Andy Polyakov, Thomas Gleixner, Ingo Molnar, X86 ML
In-Reply-To: <20180929081118.GB11115@zn.tnic>
On 18-09-29 10:11:18, Borislav Petkov wrote:
> On Sat, Sep 29, 2018 at 10:00:29AM +0200, Ard Biesheuvel wrote:
> > Note that this is the author of the *patch* not necessarily the author
> > of the code.
> >
> > Anyone is free to submit patches adding code authored by others as
> > long as the author has made it available under a suitable license, and
> > this is actually the whole point of the S-o-B: you are stating to the
> > next guy that the code included in your patch was made available to
> > you under a compatible license.
>
> ... and the actual author could be named with Originally-by or
> Co-Developed-by:, and even in free text in the commit message.
Or you could just put the original author as the first S-o-b and then
another (second) S-o-b line where you put yourself as a submitter.
AFAIK, that's how people usually do it.
>
> But the correct SOB chain denoting who handled the patch on its way up,
> is important.
>
> --
> Regards/Gruss,
> Boris.
>
> Good mailing practices for 400: avoid top-posting and trim the reply.
^ permalink raw reply
* Re: [PATCH net-next v6 04/23] zinc: ChaCha20 x86_64 implementation
From: Ard Biesheuvel @ 2018-09-29 8:00 UTC (permalink / raw)
To: Borislav Petkov
Cc: Jason A. Donenfeld, LKML, Netdev, Linux Crypto Mailing List,
David Miller, Greg Kroah-Hartman, Samuel Neves, Andrew Lutomirski,
Jean-Philippe Aumasson, Andy Polyakov, Thomas Gleixner,
Ingo Molnar, X86 ML
In-Reply-To: <20180929075601.GA11115@zn.tnic>
On 29 September 2018 at 09:56, Borislav Petkov <bp@alien8.de> wrote:
> On Sat, Sep 29, 2018 at 04:01:53AM +0200, Jason A. Donenfeld wrote:
>> I was wondering about the ordering of these, actually. I've seen s-o-b
>> on top and s-o-b on bottom of the cc list in lots of commits and
>> haven't yet divined the One True Position.
>
> Documentation/process/submitting-patches.rst
>
> section 12, first sentence.
>
> The SOB chain needs to clearly express the path of the patch from
> author(s) to the upstream kernel.
>
Note that this is the author of the *patch* not necessarily the author
of the code.
Anyone is free to submit patches adding code authored by others as
long as the author has made it available under a suitable license, and
this is actually the whole point of the S-o-B: you are stating to the
next guy that the code included in your patch was made available to
you under a compatible license.
^ permalink raw reply
* Re: [PATCH net-next v6 04/23] zinc: ChaCha20 x86_64 implementation
From: Borislav Petkov @ 2018-09-29 7:56 UTC (permalink / raw)
To: Jason A. Donenfeld
Cc: Ard Biesheuvel, LKML, Netdev, Linux Crypto Mailing List,
David Miller, Greg Kroah-Hartman, Samuel Neves, Andrew Lutomirski,
Jean-Philippe Aumasson, Andy Polyakov, Thomas Gleixner, mingo,
X86 ML
In-Reply-To: <CAHmME9rc5zgN4HhBy0_oq+EbEXdS8nePzA7qW39nocx_y4ay1Q@mail.gmail.com>
On Sat, Sep 29, 2018 at 04:01:53AM +0200, Jason A. Donenfeld wrote:
> I was wondering about the ordering of these, actually. I've seen s-o-b
> on top and s-o-b on bottom of the cc list in lots of commits and
> haven't yet divined the One True Position.
Documentation/process/submitting-patches.rst
section 12, first sentence.
The SOB chain needs to clearly express the path of the patch from
author(s) to the upstream kernel.
--
Regards/Gruss,
Boris.
Good mailing practices for 400: avoid top-posting and trim the reply.
^ permalink raw reply
* Re: [PATCH v2] net/ncsi: Add NCSI OEM command support
From: Vijay Khemka @ 2018-09-29 1:20 UTC (permalink / raw)
To: Justin . Lee1 @ Dell . com, joel @ jms . id . au,
linux-aspeed @ lists . ozlabs . org,
openbmc @ lists . ozlabs . org, Sai Dasari,
netdev @ vger . kernel . org, christian @ cmd . nu,
Samuel Mendoza-Jonas
In-Reply-To: <20180929010602.1025909-1-vijaykhemka@fb.com>
> On 9/28/18, 6:07 PM, "Vijay Khemka" <vijaykhemka@fb.com> wrote:
> This patch adds OEM commands and response handling. It also defines OEM
> command and response structure as per NCSI specification along with its
> handlers.
>
> ncsi_cmd_handler_oem: This is a generic command request handler for OEM
> commands
> ncsi_rsp_handler_oem: This is a generic response handler for OEM commands
This is a generic patch for OEM command handling, There will be another patch
following this to handle specific OEM commands for each vendor. Currently I have
defined 2 vendor/manufacturer id below in internal.h, more can be added here for
other vendors. I have not defined ncsi_rsp_oem_handler in this patch as they are
NULL, but there will be a defined handlers for each vendor in next patch.
Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
---
net/ncsi/internal.h | 4 ++++
net/ncsi/ncsi-cmd.c | 31 ++++++++++++++++++++++++++++---
net/ncsi/ncsi-pkt.h | 16 ++++++++++++++++
net/ncsi/ncsi-rsp.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 91 insertions(+), 4 deletions(-)
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index 8055e3965cef..c16cb7223064 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -68,6 +68,10 @@ enum {
NCSI_MODE_MAX
};
+/* OEM Vendor Manufacture ID */
+#define NCSI_OEM_MFR_MLX_ID 0x8119
+#define NCSI_OEM_MFR_BCM_ID 0x113d
+
struct ncsi_channel_version {
u32 version; /* Supported BCD encoded NCSI version */
u32 alpha2; /* Supported BCD encoded NCSI version */
diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c
index 7567ca63aae2..2f98533eba46 100644
--- a/net/ncsi/ncsi-cmd.c
+++ b/net/ncsi/ncsi-cmd.c
@@ -211,6 +211,26 @@ static int ncsi_cmd_handler_snfc(struct sk_buff *skb,
return 0;
}
+static int ncsi_cmd_handler_oem(struct sk_buff *skb,
+ struct ncsi_cmd_arg *nca)
+{
+ struct ncsi_cmd_oem_pkt *cmd;
+ unsigned int len;
+
+ len = sizeof(struct ncsi_cmd_pkt_hdr) + 4;
+ if (nca->payload < 26)
+ len += 26;
+ else
+ len += nca->payload;
+
+ cmd = skb_put_zero(skb, len);
+ cmd->mfr_id = nca->dwords[0];
+ memcpy(cmd->data, &nca->dwords[1], nca->payload - 4);
+ ncsi_cmd_build_header(&cmd->cmd.common, nca);
+
+ return 0;
+}
+
static struct ncsi_cmd_handler {
unsigned char type;
int payload;
@@ -244,7 +264,7 @@ static struct ncsi_cmd_handler {
{ NCSI_PKT_CMD_GNS, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_GNPTS, 0, ncsi_cmd_handler_default },
{ NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default },
- { NCSI_PKT_CMD_OEM, 0, NULL },
+ { NCSI_PKT_CMD_OEM, -1, ncsi_cmd_handler_oem },
{ NCSI_PKT_CMD_PLDM, 0, NULL },
{ NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default }
};
@@ -316,8 +336,13 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
return -ENOENT;
}
- /* Get packet payload length and allocate the request */
- nca->payload = nch->payload;
+ /* Get packet payload length and allocate the request
+ * It is expected that if length set as negative in
+ * handler structure means caller is initializing it
+ * and setting length in nca before calling xmit function
+ */
+ if (nch->payload >= 0)
+ nca->payload = nch->payload;
nr = ncsi_alloc_command(nca);
if (!nr)
return -ENOMEM;
diff --git a/net/ncsi/ncsi-pkt.h b/net/ncsi/ncsi-pkt.h
index 91b4b66438df..1f338386810d 100644
--- a/net/ncsi/ncsi-pkt.h
+++ b/net/ncsi/ncsi-pkt.h
@@ -151,6 +151,22 @@ struct ncsi_cmd_snfc_pkt {
unsigned char pad[22];
};
+/* OEM Request Command as per NCSI Specification */
+struct ncsi_cmd_oem_pkt {
+ struct ncsi_cmd_pkt_hdr cmd; /* Command header */
+ __be32 mfr_id; /* Manufacture ID */
+ unsigned char data[64]; /* OEM Payload Data */
+ __be32 checksum; /* Checksum */
+};
+
+/* OEM Response Packet as per NCSI Specification */
+struct ncsi_rsp_oem_pkt {
+ struct ncsi_rsp_pkt_hdr rsp; /* Command header */
+ __be32 mfr_id; /* Manufacture ID */
+ unsigned char data[64]; /* Payload data */
+ __be32 checksum; /* Checksum */
+};
+
/* Get Link Status */
struct ncsi_rsp_gls_pkt {
struct ncsi_rsp_pkt_hdr rsp; /* Response header */
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index 930c1d3796f0..22664ebdc93a 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -596,6 +596,48 @@ static int ncsi_rsp_handler_snfc(struct ncsi_request *nr)
return 0;
}
+static struct ncsi_rsp_oem_handler {
+ unsigned int mfr_id;
+ int (*handler)(struct ncsi_request *nr);
+} ncsi_rsp_oem_handlers[] = {
+ { NCSI_OEM_MFR_MLX_ID, NULL },
+ { NCSI_OEM_MFR_BCM_ID, NULL }
+};
+
+
+/* Response handler for OEM command */
+static int ncsi_rsp_handler_oem(struct ncsi_request *nr)
+{
+ struct ncsi_rsp_oem_pkt *rsp;
+ struct ncsi_rsp_oem_handler *nrh = NULL;
+ unsigned int mfr_id, i;
+
+ /* Get the response header */
+ rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
+ mfr_id = ntohl(rsp->mfr_id);
+
+ /* Check for manufacturer id and Find the handler */
+ for (i = 0; i < ARRAY_SIZE(ncsi_rsp_oem_handlers); i++) {
+ if (ncsi_rsp_oem_handlers[i].mfr_id == mfr_id) {
+ if (ncsi_rsp_oem_handlers[i].handler)
+ nrh = &ncsi_rsp_oem_handlers[i];
+ else
+ nrh = NULL;
+
+ break;
+ }
+ }
+
+ if (!nrh) {
+ netdev_err(nr->ndp->ndev.dev, "Received unrecognized OEM packet with MFR-ID (0x%x)\n",
+ mfr_id);
+ return -ENOENT;
+ }
+
+ /* Process the packet */
+ return nrh->handler(nr);
+}
+
static int ncsi_rsp_handler_gvi(struct ncsi_request *nr)
{
struct ncsi_rsp_gvi_pkt *rsp;
@@ -932,7 +974,7 @@ static struct ncsi_rsp_handler {
{ NCSI_PKT_RSP_GNS, 172, ncsi_rsp_handler_gns },
{ NCSI_PKT_RSP_GNPTS, 172, ncsi_rsp_handler_gnpts },
{ NCSI_PKT_RSP_GPS, 8, ncsi_rsp_handler_gps },
- { NCSI_PKT_RSP_OEM, 0, NULL },
+ { NCSI_PKT_RSP_OEM, -1, ncsi_rsp_handler_oem },
{ NCSI_PKT_RSP_PLDM, 0, NULL },
{ NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid }
};
--
2.17.1
^ permalink raw reply
* RE: [PATCH 1/2] net: dpaa2: move DPAA2 PTP driver out of staging/
From: Y.b. Lu @ 2018-09-29 7:43 UTC (permalink / raw)
To: Andrew Lunn
Cc: linux-kernel@vger.kernel.org, devel@driverdev.osuosl.org,
netdev@vger.kernel.org, Richard Cochran, David S . Miller,
Ioana Ciocoi Radulescu, Greg Kroah-Hartman
In-Reply-To: <VI1PR0401MB223737CACE4E4064AE8325A4F8EC0@VI1PR0401MB2237.eurprd04.prod.outlook.com>
Hi all,
Sent out the v2. Please help to review.
Thanks a lot.
Hi Andrew,
> -----Original Message-----
> From: Y.b. Lu
> Sent: Friday, September 28, 2018 4:04 PM
> To: 'Andrew Lunn' <andrew@lunn.ch>
> Cc: linux-kernel@vger.kernel.org; devel@driverdev.osuosl.org;
> netdev@vger.kernel.org; Richard Cochran <richardcochran@gmail.com>;
> David S . Miller <davem@davemloft.net>; Ioana Ciocoi Radulescu
> <ruxandra.radulescu@nxp.com>; Greg Kroah-Hartman
> <gregkh@linuxfoundation.org>
> Subject: RE: [PATCH 1/2] net: dpaa2: move DPAA2 PTP driver out of staging/
>
> Hi Andrew,
>
> Thanks a lot for your comments.
> Please see my comments inline.
>
> Best regards,
> Yangbo Lu
>
> > -----Original Message-----
> > From: Andrew Lunn <andrew@lunn.ch>
> > Sent: Thursday, September 27, 2018 9:25 PM
> > To: Y.b. Lu <yangbo.lu@nxp.com>
> > Cc: linux-kernel@vger.kernel.org; devel@driverdev.osuosl.org;
> > netdev@vger.kernel.org; Richard Cochran <richardcochran@gmail.com>;
> > David S . Miller <davem@davemloft.net>; Ioana Ciocoi Radulescu
> > <ruxandra.radulescu@nxp.com>; Greg Kroah-Hartman
> > <gregkh@linuxfoundation.org>
> > Subject: Re: [PATCH 1/2] net: dpaa2: move DPAA2 PTP driver out of
> > staging/
> >
> > On Thu, Sep 27, 2018 at 07:12:27PM +0800, Yangbo Lu wrote:
> > > This patch is to move DPAA2 PTP driver out of staging/ since the
> > > dpaa2-eth had been moved out.
> > >
> > > Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
> > > ---
[...]
>
> > Can rtc_drv be made const?
>
> [Y.b. Lu] Will use const in next version.
>
[Y.b. Lu] Sorry, just found it couldn't be made const. Warnings showed when built with const.
> > Is rtc.h used by anything other than rtc.c? It seems like it can be removed.
>
> [Y.b. Lu] Let me remove it in next version.
[Y.b. Lu] Sorry, I still kept that header file since dpaa2_phc_index need to be declared.
^ permalink raw reply
* [PATCH iproute2 net-next v1 6/6] taprio: Add manpage for tc-taprio(8)
From: Vinicius Costa Gomes @ 2018-09-29 1:10 UTC (permalink / raw)
To: netdev
Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri,
jesus.sanchez-palencia, ilias.apalodimas, simon.fok
In-Reply-To: <20180929011050.14056-1-vinicius.gomes@intel.com>
This documents the parameters and provides an example of usage.
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
---
man/man8/tc-taprio.8 | 142 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 142 insertions(+)
create mode 100644 man/man8/tc-taprio.8
diff --git a/man/man8/tc-taprio.8 b/man/man8/tc-taprio.8
new file mode 100644
index 00000000..92055b43
--- /dev/null
+++ b/man/man8/tc-taprio.8
@@ -0,0 +1,142 @@
+.TH TAPRIO 8 "25 Sept 2018" "iproute2" "Linux"
+.SH NAME
+TAPRIO \- Time Aware Priority Shaper
+.SH SYNOPSIS
+.B tc qdisc ... dev
+dev
+.B parent
+classid
+.B [ handle
+major:
+.B ] taprio num_tc
+tcs
+.ti +8
+.B map
+P0 P1 P2 ...
+.B queues
+count1@offset1 count2@offset2 ...
+.ti +8
+.B base-time
+base-time
+.B clockid
+clockid
+.ti +8
+.B sched-entry
+<command 1> <gate mask 1> <interval 1>
+.ti +8
+.B sched-entry
+<command 2> <gate mask 2> <interval 2>
+.ti +8
+.B sched-entry
+<command 3> <gate mask 3> <interval 3>
+.ti +8
+.B sched-entry
+<command N> <gate mask N> <interval N>
+
+.SH DESCRIPTION
+The TAPRIO qdisc implements a simplified version of the scheduling
+state machine defined by IEEE 802.1Q-2018 Section 8.6.9, which allows
+configuration of a sequence of gate states, where each gate state
+allows outgoing traffic for a subset (potentially empty) of traffic
+classes.
+
+How traffic is mapped to different hardware queues is similar to
+.BR mqprio(8)
+and so the
+.B map
+and
+.Q queues
+parameters have the same meaning.
+
+The other parameters specify the schedule, and at what point in time
+it should start (it can behave as the schedule started in the past).
+
+.SH PARAMETERS
+.TP
+num_tc
+.BR
+Number of traffic classes to use. Up to 16 classes supported.
+
+.TP
+map
+.br
+The priority to traffic class map. Maps priorities 0..15 to a specified
+traffic class. See
+.BR mqprio(8)
+for more details.
+
+.TP
+queues
+.br
+Provide count and offset of queue range for each traffic class. In the
+format,
+.B count@offset.
+Queue ranges for each traffic classes cannot overlap and must be a
+contiguous range of queues.
+
+.TP
+base-time
+.br
+Specifies the instant in nanoseconds, using the reference of
+.B clockid,
+defining the time when the schedule starts. If 'base-time' is a time
+in the past, the schedule will start at
+
+base-time + (N * cycle-time)
+
+where N is the smallest integer so the resulting time is greater than
+"now", and "cycle-time" is the sum of all the intervals of the entries
+in the schedule;
+
+.TP
+clockid
+.br
+Specifies the clock to be used by qdisc's internal timer for measuring
+time and scheduling events.
+
+.TP
+sched-entry
+.br
+There may multiple
+.B sched-entry
+parameters in a single schedule. Each one has the
+
+sched-entry <command> <gatemask> <interval>
+
+format. The only supported <command> is "S", which
+means "SetGateStates", following the IEEE 802.1Q-2018 definition
+(Table 8-7). <gate mask> is a bitmask where each bit is a associated
+with a traffic class, so bit 0 (the least significant bit) being "on"
+means that traffic class 0 is "active" for that schedule entry.
+<interval> is a time duration, in nanoseconds, that specifies for how
+long that state defined by <command> and <gate mask> should be held
+before moving to the next entry.
+
+.SH EXAMPLES
+
+The following example shows how an traffic schedule with three traffic
+classes ("num_tc 3"), which are separated different traffic classes,
+we are going to call these TC 0, TC 1 and TC 2. We could read the
+"map" parameter below as: traffic with priority 3 is classified as TC
+0, priority 2 is classified as TC 1 and the rest is classified as TC
+2.
+
+The schedule will start at instant 1528743495910289987 using the
+reference CLOCK_TAI. The schedule is composed of three entries each of
+300us duration.
+
+.EX
+# tc qdisc replace dev eth0 parent root handle 100 taprio \\
+ num_tc 3 \\
+ map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \\
+ queues 1@0 1@1 2@2 \\
+ base-time 1528743495910289987 \\
+ sched-entry S 01 300000 \\
+ sched-entry S 02 300000 \\
+ sched-entry S 04 300000 \\
+ clockid CLOCK_TAI
+.EE
+
+
+.SH AUTHORS
+Vinicius Costa Gomes <vinicius.gomes@intel.com>
--
2.19.0
^ permalink raw reply related
* [PATCH iproute2 net-next v1 1/6] utils: Implement get_s64()
From: Vinicius Costa Gomes @ 2018-09-29 1:10 UTC (permalink / raw)
To: netdev
Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri,
jesus.sanchez-palencia, ilias.apalodimas, simon.fok
In-Reply-To: <20180929011050.14056-1-vinicius.gomes@intel.com>
Add this helper to read signed 64-bit integers from a string.
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
---
include/utils.h | 1 +
lib/utils.c | 21 +++++++++++++++++++++
2 files changed, 22 insertions(+)
diff --git a/include/utils.h b/include/utils.h
index 8cb4349e..58574a05 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -139,6 +139,7 @@ int get_time_rtt(unsigned *val, const char *arg, int *raw);
#define get_byte get_u8
#define get_ushort get_u16
#define get_short get_s16
+int get_s64(__s64 *val, const char *arg, int base);
int get_u64(__u64 *val, const char *arg, int base);
int get_u32(__u32 *val, const char *arg, int base);
int get_s32(__s32 *val, const char *arg, int base);
diff --git a/lib/utils.c b/lib/utils.c
index e87ecf31..1b84b801 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -383,6 +383,27 @@ int get_u8(__u8 *val, const char *arg, int base)
return 0;
}
+int get_s64(__s64 *val, const char *arg, int base)
+{
+ long res;
+ char *ptr;
+
+ errno = 0;
+
+ if (!arg || !*arg)
+ return -1;
+ res = strtoll(arg, &ptr, base);
+ if (!ptr || ptr == arg || *ptr)
+ return -1;
+ if ((res == LLONG_MIN || res == LLONG_MAX) && errno == ERANGE)
+ return -1;
+ if (res > INT64_MAX || res < INT64_MIN)
+ return -1;
+
+ *val = res;
+ return 0;
+}
+
int get_s32(__s32 *val, const char *arg, int base)
{
long res;
--
2.19.0
^ permalink raw reply related
* [PATCH iproute2 net-next v1 5/6] tc: Add support for configuring the taprio scheduler
From: Vinicius Costa Gomes @ 2018-09-29 1:10 UTC (permalink / raw)
To: netdev
Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri,
jesus.sanchez-palencia, ilias.apalodimas, simon.fok
In-Reply-To: <20180929011050.14056-1-vinicius.gomes@intel.com>
This traffic scheduler allows traffic classes states (transmission
allowed/not allowed, in the simplest case) to be scheduled, according
to a pre-generated time sequence. This is the basis of the IEEE
802.1Qbv specification.
Example configuration:
tc qdisc replace dev enp3s0 parent root handle 100 taprio \
num_tc 3 \
map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \
queues 1@0 1@1 2@2 \
base-time 1528743495910289987 \
sched-entry S 01 300000 \
sched-entry S 02 300000 \
sched-entry S 04 300000 \
clockid CLOCK_TAI
The configuration format is similar to mqprio. The main difference is
the presence of a schedule, built by multiple "sched-entry"
definitions, each entry has the following format:
sched-entry <CMD> <GATE MASK> <INTERVAL>
The only supported <CMD> is "S", which means "SetGateStates",
following the IEEE 802.1Qbv-2015 definition (Table 8-6). <GATE MASK>
is a bitmask where each bit is a associated with a traffic class, so
bit 0 (the least significant bit) being "on" means that traffic class
0 is "active" for that schedule entry. <INTERVAL> is a time duration
in nanoseconds that specifies for how long that state defined by <CMD>
and <GATE MASK> should be held before moving to the next entry.
This schedule is circular, that is, after the last entry is executed
it starts from the first one, indefinitely.
The other parameters can be defined as follows:
- base-time: specifies the instant when the schedule starts, if
'base-time' is a time in the past, the schedule will start at
base-time + (N * cycle-time)
where N is the smallest integer so the resulting time is greater
than "now", and "cycle-time" is the sum of all the intervals of the
entries in the schedule;
- clockid: specifies the reference clock to be used;
The parameters should be similar to what the IEEE 802.1Q family of
specification defines.
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Signed-off-by: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
---
tc/Makefile | 1 +
tc/q_taprio.c | 410 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 411 insertions(+)
create mode 100644 tc/q_taprio.c
diff --git a/tc/Makefile b/tc/Makefile
index 5a1a7ff9..25a28284 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -74,6 +74,7 @@ TCMODULES += e_bpf.o
TCMODULES += f_matchall.o
TCMODULES += q_cbs.o
TCMODULES += q_etf.o
+TCMODULES += q_taprio.o
TCSO :=
ifeq ($(TC_CONFIG_ATM),y)
diff --git a/tc/q_taprio.c b/tc/q_taprio.c
new file mode 100644
index 00000000..645a7613
--- /dev/null
+++ b/tc/q_taprio.c
@@ -0,0 +1,410 @@
+/*
+ * q_taprio.c Time Aware Priority Scheduler
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Vinicius Costa Gomes <vinicius.gomes@intel.com>
+ * Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+#include "list.h"
+
+struct sched_entry {
+ struct list_head list;
+ uint32_t index;
+ uint32_t interval;
+ uint32_t gatemask;
+ uint8_t cmd;
+};
+
+#define CLOCKID_INVALID (-1)
+static const struct static_clockid {
+ const char *name;
+ clockid_t clockid;
+} clockids_sysv[] = {
+ { "REALTIME", CLOCK_REALTIME },
+ { "TAI", CLOCK_TAI },
+ { "BOOTTIME", CLOCK_BOOTTIME },
+ { "MONOTONIC", CLOCK_MONOTONIC },
+ { NULL }
+};
+
+static void explain(void)
+{
+ fprintf(stderr, "Usage: ... taprio clockid CLOCKID\n");
+ fprintf(stderr, " [num_tc NUMBER] [map P0 P1 ...] ");
+ fprintf(stderr, " [queues COUNT@OFFSET COUNT@OFFSET COUNT@OFFSET ...] ");
+ fprintf(stderr, " [ [sched-entry index cmd gate-mask interval] ... ] ");
+ fprintf(stderr, " [base-time time] ");
+ fprintf(stderr, "\nCLOCKID must be a valid SYS-V id (i.e. CLOCK_TAI)");
+ fprintf(stderr, "\n");
+}
+
+static void explain_clockid(const char *val)
+{
+ fprintf(stderr, "taprio: illegal value for \"clockid\": \"%s\".\n", val);
+ fprintf(stderr, "It must be a valid SYS-V id (i.e. CLOCK_TAI)\n");
+}
+
+static int get_clockid(__s32 *val, const char *arg)
+{
+ const struct static_clockid *c;
+
+ /* Drop the CLOCK_ prefix if that is being used. */
+ if (strcasestr(arg, "CLOCK_") != NULL)
+ arg += sizeof("CLOCK_") - 1;
+
+ for (c = clockids_sysv; c->name; c++) {
+ if (strcasecmp(c->name, arg) == 0) {
+ *val = c->clockid;
+
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static const char* get_clock_name(clockid_t clockid)
+{
+ const struct static_clockid *c;
+
+ for (c = clockids_sysv; c->name; c++) {
+ if (clockid == c->clockid)
+ return c->name;
+ }
+
+ return "invalid";
+}
+
+static int str_to_entry_cmd(const char *str)
+{
+ if (strcmp(str, "S") == 0)
+ return TC_TAPRIO_CMD_SET_GATES;
+
+ if (strcmp(str, "H") == 0)
+ return TC_TAPRIO_CMD_SET_AND_HOLD;
+
+ if (strcmp(str, "R") == 0)
+ return TC_TAPRIO_CMD_SET_AND_RELEASE;
+
+ return -1;
+}
+
+static int add_sched_list(struct list_head *sched_entries, struct nlmsghdr *n)
+{
+ struct sched_entry *e;
+
+ list_for_each_entry(e, sched_entries, list) {
+ struct rtattr *a;
+
+ a = addattr_nest(n, 1024, TCA_TAPRIO_SCHED_ENTRY);
+
+ addattr_l(n, 1024, TCA_TAPRIO_SCHED_ENTRY_CMD, &e->cmd, sizeof(e->cmd));
+ addattr_l(n, 1024, TCA_TAPRIO_SCHED_ENTRY_GATE_MASK, &e->gatemask, sizeof(e->gatemask));
+ addattr_l(n, 1024, TCA_TAPRIO_SCHED_ENTRY_INTERVAL, &e->interval, sizeof(e->interval));
+
+ addattr_nest_end(n, a);
+ }
+
+ return 0;
+}
+
+static void explain_sched_entry(void)
+{
+ fprintf(stderr, "Usage: ... taprio ... sched-entry <cmd> <gate mask> <interval>\n");
+}
+
+static struct sched_entry *create_entry(uint32_t gatemask, uint32_t interval, uint8_t cmd)
+{
+ struct sched_entry *e;
+
+ e = calloc(1, sizeof(*e));
+ if (!e)
+ return NULL;
+
+ e->gatemask = gatemask;
+ e->interval = interval;
+ e->cmd = cmd;
+
+ return e;
+}
+
+static int taprio_parse_opt(struct qdisc_util *qu, int argc,
+ char **argv, struct nlmsghdr *n, const char *dev)
+{
+ __s32 clockid = CLOCKID_INVALID;
+ struct tc_mqprio_qopt opt = { };
+ struct list_head sched_entries;
+ struct rtattr *tail;
+ __s64 base_time = 0;
+ int err, idx;
+
+ INIT_LIST_HEAD(&sched_entries);
+
+ while (argc > 0) {
+ idx = 0;
+ if (strcmp(*argv, "num_tc") == 0) {
+ NEXT_ARG();
+ if (get_u8(&opt.num_tc, *argv, 10)) {
+ fprintf(stderr, "Illegal \"num_tc\"\n");
+ return -1;
+ }
+ } else if (strcmp(*argv, "map") == 0) {
+ while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
+ NEXT_ARG();
+ if (get_u8(&opt.prio_tc_map[idx], *argv, 10)) {
+ PREV_ARG();
+ break;
+ }
+ idx++;
+ }
+ for ( ; idx < TC_QOPT_MAX_QUEUE; idx++)
+ opt.prio_tc_map[idx] = 0;
+ } else if (strcmp(*argv, "queues") == 0) {
+ char *tmp, *tok;
+
+ while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
+ NEXT_ARG();
+
+ tmp = strdup(*argv);
+ if (!tmp)
+ break;
+
+ tok = strtok(tmp, "@");
+ if (get_u16(&opt.count[idx], tok, 10)) {
+ free(tmp);
+ PREV_ARG();
+ break;
+ }
+ tok = strtok(NULL, "@");
+ if (get_u16(&opt.offset[idx], tok, 10)) {
+ free(tmp);
+ PREV_ARG();
+ break;
+ }
+ free(tmp);
+ idx++;
+ }
+ } else if (strcmp(*argv, "sched-entry") == 0) {
+ uint32_t mask, interval;
+ struct sched_entry *e;
+ uint8_t cmd;
+
+ NEXT_ARG();
+ err = str_to_entry_cmd(*argv);
+ if (err < 0) {
+ explain_sched_entry();
+ return -1;
+ }
+ cmd = err;
+
+ NEXT_ARG();
+ if (get_u32(&mask, *argv, 16)) {
+ explain_sched_entry();
+ return -1;
+ }
+
+ NEXT_ARG();
+ if (get_u32(&interval, *argv, 0)) {
+ explain_sched_entry();
+ return -1;
+ }
+
+ e = create_entry(mask, interval, cmd);
+ if (!e) {
+ fprintf(stderr, "taprio: not enough memory for new schedule entry\n");
+ return -1;
+ }
+
+ list_add_tail(&e->list, &sched_entries);
+
+ } else if (strcmp(*argv, "base-time") == 0) {
+ NEXT_ARG();
+ if (get_s64(&base_time, *argv, 10)) {
+ PREV_ARG();
+ break;
+ }
+ } else if (strcmp(*argv, "clockid") == 0) {
+ NEXT_ARG();
+ if (clockid != CLOCKID_INVALID) {
+ fprintf(stderr, "taprio: duplicate \"clockid\" specification\n");
+ return -1;
+ }
+ if (get_clockid(&clockid, *argv)) {
+ explain_clockid(*argv);
+ return -1;
+ }
+ } else if (strcmp(*argv, "help") == 0) {
+ explain();
+ return -1;
+ } else {
+ fprintf(stderr, "Unknown argument\n");
+ return -1;
+ }
+ argc--; argv++;
+ }
+
+ tail = NLMSG_TAIL(n);
+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+
+ if (opt.num_tc > 0)
+ addattr_l(n, 1024, TCA_TAPRIO_ATTR_PRIOMAP, &opt, sizeof(opt));
+
+ if (base_time)
+ addattr_l(n, 1024, TCA_TAPRIO_ATTR_SCHED_BASE_TIME, &base_time, sizeof(base_time));
+
+ addattr_l(n, 1024, TCA_TAPRIO_ATTR_SCHED_CLOCKID, &clockid, sizeof(clockid));
+
+ if (!list_empty(&sched_entries)) {
+ struct rtattr *entry_list;
+ entry_list = addattr_nest(n, 1024, TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST | NLA_F_NESTED);
+
+ err = add_sched_list(&sched_entries, n);
+ if (err < 0) {
+ fprintf(stderr, "Could not add schedule to netlink message\n");
+ return -1;
+ }
+
+ addattr_nest_end(n, entry_list);
+ }
+
+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+
+ return 0;
+}
+
+static const char *command_to_str(__u8 cmd)
+{
+ switch (cmd) {
+ case TC_TAPRIO_CMD_SET_GATES:
+ return "S";
+ case TC_TAPRIO_CMD_SET_AND_HOLD:
+ return "H";
+ case TC_TAPRIO_CMD_SET_AND_RELEASE:
+ return "R";
+ default:
+ return "Invalid";
+ }
+}
+
+static int print_sched_list(FILE *f, struct rtattr *list)
+{
+ struct rtattr *item;
+ int rem;
+
+ if (list == NULL)
+ return 0;
+
+ rem = RTA_PAYLOAD(list);
+
+ open_json_array(PRINT_JSON, "schedule");
+
+ for (item = RTA_DATA(list); RTA_OK(item, rem); item = RTA_NEXT(item, rem)) {
+ struct rtattr *tb[TCA_TAPRIO_SCHED_ENTRY_MAX + 1];
+ __u32 index = 0, gatemask = 0, interval = 0;
+ __u8 command = 0;
+
+ parse_rtattr_nested(tb, TCA_TAPRIO_SCHED_ENTRY_MAX, item);
+
+ if (tb[TCA_TAPRIO_SCHED_ENTRY_INDEX])
+ index = rta_getattr_u32(tb[TCA_TAPRIO_SCHED_ENTRY_INDEX]);
+
+ if (tb[TCA_TAPRIO_SCHED_ENTRY_CMD])
+ command = rta_getattr_u8(tb[TCA_TAPRIO_SCHED_ENTRY_CMD]);
+
+ if (tb[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK])
+ gatemask = rta_getattr_u32(tb[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK]);
+
+ if (tb[TCA_TAPRIO_SCHED_ENTRY_INTERVAL])
+ interval = rta_getattr_u32(tb[TCA_TAPRIO_SCHED_ENTRY_INTERVAL]);
+
+ open_json_object(NULL);
+ print_uint(PRINT_ANY, "index", "\tindex %u", index);
+ print_string(PRINT_ANY, "cmd", " cmd %s", command_to_str(command));
+ print_0xhex(PRINT_ANY, "gatemask", " gatemask %#x", gatemask);
+ print_uint(PRINT_ANY, "interval", " interval %u", interval);
+ close_json_object();
+
+ print_string(PRINT_FP, NULL, "%s", _SL_);
+ }
+
+ close_json_array(PRINT_ANY, "");
+
+ return 0;
+}
+
+static int taprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
+{
+ struct rtattr *tb[TCA_TAPRIO_ATTR_MAX + 1];
+ struct tc_mqprio_qopt *qopt = 0;
+ __s32 clockid = CLOCKID_INVALID;
+ __s64 base_time = 0;
+ int i;
+
+ if (opt == NULL)
+ return 0;
+
+ parse_rtattr_nested(tb, TCA_TAPRIO_ATTR_MAX, opt);
+
+ if (tb[TCA_TAPRIO_ATTR_PRIOMAP] == NULL)
+ return -1;
+
+ qopt = RTA_DATA(tb[TCA_TAPRIO_ATTR_PRIOMAP]);
+
+ print_uint(PRINT_ANY, "tc", "tc %u ", qopt->num_tc);
+
+ open_json_array(PRINT_ANY, "map");
+ for (i = 0; i <= TC_PRIO_MAX; i++)
+ print_uint(PRINT_ANY, NULL, " %u", qopt->prio_tc_map[i]);
+ close_json_array(PRINT_ANY, "");
+
+ print_string(PRINT_FP, NULL, "%s", _SL_);
+
+ open_json_array(PRINT_ANY, "queues");
+ for (i = 0; i < qopt->num_tc; i++) {
+ open_json_object(NULL);
+ print_uint(PRINT_ANY, "offset", " offset %u", qopt->offset[i]);
+ print_uint(PRINT_ANY, "count", " count %u", qopt->count[i]);
+ close_json_object();
+ }
+ close_json_array(PRINT_ANY, "");
+
+ print_string(PRINT_FP, NULL, "%s", _SL_);
+
+ if (tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME])
+ base_time = rta_getattr_s64(tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME]);
+
+ if (tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID])
+ clockid = rta_getattr_s32(tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID]);
+
+ print_string(PRINT_ANY, "clockid", "clockid %s", get_clock_name(clockid));
+
+ print_lluint(PRINT_ANY, "base_time", " base-time %lld", base_time);
+
+ print_string(PRINT_FP, NULL, "%s", _SL_);
+
+ return print_sched_list(f, tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST]);
+}
+
+struct qdisc_util taprio_qdisc_util = {
+ .id = "taprio",
+ .parse_qopt = taprio_parse_opt,
+ .print_qopt = taprio_print_opt,
+};
--
2.19.0
^ permalink raw reply related
* [PATCH iproute2 net-next v1 2/6] include: Add helper to retrieve a __s64 from a netlink msg
From: Vinicius Costa Gomes @ 2018-09-29 1:10 UTC (permalink / raw)
To: netdev
Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri,
jesus.sanchez-palencia, ilias.apalodimas, simon.fok
In-Reply-To: <20180929011050.14056-1-vinicius.gomes@intel.com>
This allows signed 64-bit integers to be retrieved from a netlink
message.
---
include/libnetlink.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/include/libnetlink.h b/include/libnetlink.h
index 9d9249e6..88164975 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -185,6 +185,13 @@ static inline __u64 rta_getattr_u64(const struct rtattr *rta)
memcpy(&tmp, RTA_DATA(rta), sizeof(__u64));
return tmp;
}
+static inline __s64 rta_getattr_s64(const struct rtattr *rta)
+{
+ __s64 tmp;
+
+ memcpy(&tmp, RTA_DATA(rta), sizeof(__s64));
+ return tmp;
+}
static inline const char *rta_getattr_str(const struct rtattr *rta)
{
return (const char *)RTA_DATA(rta);
--
2.19.0
^ permalink raw reply related
* [PATCH iproute2 net-next v1 0/6] introduce the taprio scheduler
From: Vinicius Costa Gomes @ 2018-09-29 1:10 UTC (permalink / raw)
To: netdev
Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri,
jesus.sanchez-palencia, ilias.apalodimas, simon.fok
Hi,
Changes from RFC:
- Removed support for the sched-file parameter, in favor of
supporting the batch mode feature;
This is the iproute2 side of the taprio v1 series.
Please see the kernel side cover letter for more information about how
to test this.
Cheers,
^ permalink raw reply
* [PATCH iproute2 net-next v1 4/6] include: add definitions for taprio [DO NOT COMMIT]
From: Vinicius Costa Gomes @ 2018-09-29 1:10 UTC (permalink / raw)
To: netdev
Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri,
jesus.sanchez-palencia, ilias.apalodimas, simon.fok
In-Reply-To: <20180929011050.14056-1-vinicius.gomes@intel.com>
DO NOT COMMIT
This patch exists only to ease the testing, until this header is
updated with the definitions from the kernel.
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
---
include/uapi/linux/pkt_sched.h | 52 ++++++++++++++++++++++++++++++++--
1 file changed, 49 insertions(+), 3 deletions(-)
diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index 8975fd1a..89ee47c2 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -395,9 +395,9 @@ enum {
struct tc_htb_xstats {
__u32 lends;
__u32 borrows;
- __u32 giants; /* too big packets (rate will not be accurate) */
- __u32 tokens;
- __u32 ctokens;
+ __u32 giants; /* unused since 'Make HTB scheduler work with TSO.' */
+ __s32 tokens;
+ __s32 ctokens;
};
/* HFSC section */
@@ -1084,4 +1084,50 @@ enum {
CAKE_ATM_MAX
};
+
+/* TAPRIO */
+enum {
+ TC_TAPRIO_CMD_SET_GATES = 0x00,
+ TC_TAPRIO_CMD_SET_AND_HOLD = 0x01,
+ TC_TAPRIO_CMD_SET_AND_RELEASE = 0x02,
+};
+
+enum {
+ TCA_TAPRIO_SCHED_ENTRY_UNSPEC,
+ TCA_TAPRIO_SCHED_ENTRY_INDEX, /* u32 */
+ TCA_TAPRIO_SCHED_ENTRY_CMD, /* u8 */
+ TCA_TAPRIO_SCHED_ENTRY_GATE_MASK, /* u32 */
+ TCA_TAPRIO_SCHED_ENTRY_INTERVAL, /* u32 */
+ __TCA_TAPRIO_SCHED_ENTRY_MAX,
+};
+#define TCA_TAPRIO_SCHED_ENTRY_MAX (__TCA_TAPRIO_SCHED_ENTRY_MAX - 1)
+
+/* The format for schedule entry list is:
+ * [TCA_TAPRIO_SCHED_ENTRY_LIST]
+ * [TCA_TAPRIO_SCHED_ENTRY]
+ * [TCA_TAPRIO_SCHED_ENTRY_CMD]
+ * [TCA_TAPRIO_SCHED_ENTRY_GATES]
+ * [TCA_TAPRIO_SCHED_ENTRY_INTERVAL]
+ */
+enum {
+ TCA_TAPRIO_SCHED_UNSPEC,
+ TCA_TAPRIO_SCHED_ENTRY,
+ __TCA_TAPRIO_SCHED_MAX,
+};
+
+#define TCA_TAPRIO_SCHED_MAX (__TCA_TAPRIO_SCHED_MAX - 1)
+
+enum {
+ TCA_TAPRIO_ATTR_UNSPEC,
+ TCA_TAPRIO_ATTR_PRIOMAP, /* struct tc_mqprio_qopt */
+ TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST, /* nested of entry */
+ TCA_TAPRIO_ATTR_SCHED_BASE_TIME, /* s64 */
+ TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY, /* single entry */
+ TCA_TAPRIO_ATTR_SCHED_CLOCKID, /* s32 */
+ TCA_TAPRIO_PAD,
+ __TCA_TAPRIO_ATTR_MAX,
+};
+
+#define TCA_TAPRIO_ATTR_MAX (__TCA_TAPRIO_ATTR_MAX - 1)
+
#endif
--
2.19.0
^ permalink raw reply related
* [PATCH iproute2 net-next v1 3/6] libnetlink: Add helper for getting a __s32 from netlink msgs
From: Vinicius Costa Gomes @ 2018-09-29 1:10 UTC (permalink / raw)
To: netdev
Cc: Jesus Sanchez-Palencia, jhs, xiyou.wangcong, jiri,
ilias.apalodimas, simon.fok
In-Reply-To: <20180929011050.14056-1-vinicius.gomes@intel.com>
From: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
This function retrieves a signed 32-bit integer from a netlink message
and returns it.
Signed-off-by: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
---
include/libnetlink.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/libnetlink.h b/include/libnetlink.h
index 88164975..79ba793e 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -185,6 +185,10 @@ static inline __u64 rta_getattr_u64(const struct rtattr *rta)
memcpy(&tmp, RTA_DATA(rta), sizeof(__u64));
return tmp;
}
+static inline __s32 rta_getattr_s32(const struct rtattr *rta)
+{
+ return *(__s32 *)RTA_DATA(rta);
+}
static inline __s64 rta_getattr_s64(const struct rtattr *rta)
{
__s64 tmp;
--
2.19.0
^ permalink raw reply related
* [PATCH net-next v1 1/1] tc: Add support for configuring the taprio scheduler
From: Vinicius Costa Gomes @ 2018-09-29 0:59 UTC (permalink / raw)
To: netdev
Cc: Vinicius Costa Gomes, jesus.sanchez-palencia, henrik,
richardcochran, jhs, xiyou.wangcong, jiri, ilias.apalodimas,
simon.fok
In-Reply-To: <20180929005943.12928-1-vinicius.gomes@intel.com>
This traffic scheduler allows traffic classes states (transmission
allowed/not allowed, in the simplest case) to be scheduled, according
to a pre-generated time sequence. This is the basis of the IEEE
802.1Qbv specification.
Example configuration:
tc qdisc replace dev enp3s0 parent root handle 100 taprio \
num_tc 3 \
map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \
queues 1@0 1@1 2@2 \
base-time 1528743495910289987 \
sched-entry S 01 300000 \
sched-entry S 02 300000 \
sched-entry S 04 300000 \
clockid CLOCK_TAI
The configuration format is similar to mqprio. The main difference is
the presence of a schedule, built by multiple "sched-entry"
definitions, each entry has the following format:
sched-entry <CMD> <GATE MASK> <INTERVAL>
The only supported <CMD> is "S", which means "SetGateStates",
following the IEEE 802.1Qbv-2015 definition (Table 8-6). <GATE MASK>
is a bitmask where each bit is a associated with a traffic class, so
bit 0 (the least significant bit) being "on" means that traffic class
0 is "active" for that schedule entry. <INTERVAL> is a time duration
in nanoseconds that specifies for how long that state defined by <CMD>
and <GATE MASK> should be held before moving to the next entry.
This schedule is circular, that is, after the last entry is executed
it starts from the first one, indefinitely.
The other parameters can be defined as follows:
- base-time: specifies the instant when the schedule starts, if
'base-time' is a time in the past, the schedule will start at
base-time + (N * cycle-time)
where N is the smallest integer so the resulting time is greater
than "now", and "cycle-time" is the sum of all the intervals of the
entries in the schedule;
- clockid: specifies the reference clock to be used;
The parameters should be similar to what the IEEE 802.1Q family of
specification defines.
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
---
include/uapi/linux/pkt_sched.h | 46 ++
net/sched/Kconfig | 11 +
net/sched/Makefile | 1 +
net/sched/sch_taprio.c | 962 +++++++++++++++++++++++++++++++++
4 files changed, 1020 insertions(+)
create mode 100644 net/sched/sch_taprio.c
diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index e9b7244ac381..89ee47c2f17d 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -1084,4 +1084,50 @@ enum {
CAKE_ATM_MAX
};
+
+/* TAPRIO */
+enum {
+ TC_TAPRIO_CMD_SET_GATES = 0x00,
+ TC_TAPRIO_CMD_SET_AND_HOLD = 0x01,
+ TC_TAPRIO_CMD_SET_AND_RELEASE = 0x02,
+};
+
+enum {
+ TCA_TAPRIO_SCHED_ENTRY_UNSPEC,
+ TCA_TAPRIO_SCHED_ENTRY_INDEX, /* u32 */
+ TCA_TAPRIO_SCHED_ENTRY_CMD, /* u8 */
+ TCA_TAPRIO_SCHED_ENTRY_GATE_MASK, /* u32 */
+ TCA_TAPRIO_SCHED_ENTRY_INTERVAL, /* u32 */
+ __TCA_TAPRIO_SCHED_ENTRY_MAX,
+};
+#define TCA_TAPRIO_SCHED_ENTRY_MAX (__TCA_TAPRIO_SCHED_ENTRY_MAX - 1)
+
+/* The format for schedule entry list is:
+ * [TCA_TAPRIO_SCHED_ENTRY_LIST]
+ * [TCA_TAPRIO_SCHED_ENTRY]
+ * [TCA_TAPRIO_SCHED_ENTRY_CMD]
+ * [TCA_TAPRIO_SCHED_ENTRY_GATES]
+ * [TCA_TAPRIO_SCHED_ENTRY_INTERVAL]
+ */
+enum {
+ TCA_TAPRIO_SCHED_UNSPEC,
+ TCA_TAPRIO_SCHED_ENTRY,
+ __TCA_TAPRIO_SCHED_MAX,
+};
+
+#define TCA_TAPRIO_SCHED_MAX (__TCA_TAPRIO_SCHED_MAX - 1)
+
+enum {
+ TCA_TAPRIO_ATTR_UNSPEC,
+ TCA_TAPRIO_ATTR_PRIOMAP, /* struct tc_mqprio_qopt */
+ TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST, /* nested of entry */
+ TCA_TAPRIO_ATTR_SCHED_BASE_TIME, /* s64 */
+ TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY, /* single entry */
+ TCA_TAPRIO_ATTR_SCHED_CLOCKID, /* s32 */
+ TCA_TAPRIO_PAD,
+ __TCA_TAPRIO_ATTR_MAX,
+};
+
+#define TCA_TAPRIO_ATTR_MAX (__TCA_TAPRIO_ATTR_MAX - 1)
+
#endif
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index e95741388311..1b9afdee5ba9 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -194,6 +194,17 @@ config NET_SCH_ETF
To compile this code as a module, choose M here: the
module will be called sch_etf.
+config NET_SCH_TAPRIO
+ tristate "Time Aware Priority (taprio) Scheduler"
+ help
+ Say Y here if you want to use the Time Aware Priority (taprio) packet
+ scheduling algorithm.
+
+ See the top of <file:net/sched/sch_taprio.c> for more details.
+
+ To compile this code as a module, choose M here: the
+ module will be called sch_taprio.
+
config NET_SCH_GRED
tristate "Generic Random Early Detection (GRED)"
---help---
diff --git a/net/sched/Makefile b/net/sched/Makefile
index f0403f49edcb..8a40431d7b5c 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_NET_SCH_HHF) += sch_hhf.o
obj-$(CONFIG_NET_SCH_PIE) += sch_pie.o
obj-$(CONFIG_NET_SCH_CBS) += sch_cbs.o
obj-$(CONFIG_NET_SCH_ETF) += sch_etf.o
+obj-$(CONFIG_NET_SCH_TAPRIO) += sch_taprio.o
obj-$(CONFIG_NET_CLS_U32) += cls_u32.o
obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o
diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
new file mode 100644
index 000000000000..206e4dbed12f
--- /dev/null
+++ b/net/sched/sch_taprio.c
@@ -0,0 +1,962 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* net/sched/sch_taprio.c Time Aware Priority Scheduler
+ *
+ * Authors: Vinicius Costa Gomes <vinicius.gomes@intel.com>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+#include <net/pkt_cls.h>
+#include <net/sch_generic.h>
+
+#define TAPRIO_ALL_GATES_OPEN -1
+
+struct sched_entry {
+ struct list_head list;
+
+ /* The instant that this entry "closes" and the next one
+ * should open, the qdisc will make some effort so that no
+ * packet leaves after this time.
+ */
+ ktime_t close_time;
+ atomic_t budget;
+ int index;
+ u32 gate_mask;
+ u32 interval;
+ u8 command;
+};
+
+struct taprio_sched {
+ struct Qdisc **qdiscs;
+ struct Qdisc *root;
+ s64 base_time;
+ int clockid;
+ int picos_per_byte; /* Using picoseconds because for 10Gbps+
+ * speeds it's sub-nanoseconds per byte
+ */
+ size_t num_entries;
+
+ /* Protects the update side of the RCU protected current_entry */
+ spinlock_t current_entry_lock;
+ struct sched_entry __rcu *current_entry;
+ struct list_head entries;
+ ktime_t (*get_time)(void);
+ struct hrtimer advance_timer;
+};
+
+static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch,
+ struct sk_buff **to_free)
+{
+ struct taprio_sched *q = qdisc_priv(sch);
+ struct Qdisc *child;
+ int queue;
+
+ queue = skb_get_queue_mapping(skb);
+
+ child = q->qdiscs[queue];
+ if (unlikely(!child))
+ return qdisc_drop(skb, sch, to_free);
+
+ qdisc_qstats_backlog_inc(sch, skb);
+ sch->q.qlen++;
+
+ return qdisc_enqueue(skb, child, to_free);
+}
+
+static struct sk_buff *taprio_peek(struct Qdisc *sch)
+{
+ struct taprio_sched *q = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct sched_entry *entry;
+ struct sk_buff *skb;
+ u32 gate_mask;
+ int i;
+
+ rcu_read_lock();
+ entry = rcu_dereference(q->current_entry);
+ gate_mask = entry ? entry->gate_mask : -1;
+ rcu_read_unlock();
+
+ if (!gate_mask)
+ return NULL;
+
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ struct Qdisc *child = q->qdiscs[i];
+ int prio;
+ u8 tc;
+
+ if (unlikely(!child))
+ continue;
+
+ skb = child->ops->peek(child);
+ if (!skb)
+ continue;
+
+ prio = skb->priority;
+ tc = netdev_get_prio_tc_map(dev, prio);
+
+ if (!(gate_mask & BIT(tc)))
+ return NULL;
+
+ return skb;
+ }
+
+ return NULL;
+}
+
+static inline int length_to_duration(struct taprio_sched *q, int len)
+{
+ return (len * q->picos_per_byte) / 1000;
+}
+
+static struct sk_buff *taprio_dequeue(struct Qdisc *sch)
+{
+ struct taprio_sched *q = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct sched_entry *entry;
+ struct sk_buff *skb;
+ u32 gate_mask;
+ int i;
+
+ rcu_read_lock();
+ entry = rcu_dereference(q->current_entry);
+ /* if there's no entry, it means that the schedule didn't
+ * start yet, so force all gates to be open, this is in
+ * accordance to IEEE 802.1Qbv-2015 Section 8.6.9.4.5
+ * "AdminGateSates"
+ */
+ gate_mask = entry ? entry->gate_mask : TAPRIO_ALL_GATES_OPEN;
+ rcu_read_unlock();
+
+ if (!gate_mask)
+ return NULL;
+
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ struct Qdisc *child = q->qdiscs[i];
+ ktime_t guard;
+ int prio;
+ int len;
+ u8 tc;
+
+ if (unlikely(!child))
+ continue;
+
+ skb = child->ops->peek(child);
+ if (!skb)
+ continue;
+
+ prio = skb->priority;
+ tc = netdev_get_prio_tc_map(dev, prio);
+
+ if (!(gate_mask & BIT(tc)))
+ continue;
+
+ len = qdisc_pkt_len(skb);
+ guard = ktime_add_ns(q->get_time(),
+ length_to_duration(q, len));
+
+ /* In the case that there's no gate entry, there's no
+ * guard band ...
+ */
+ if (gate_mask != TAPRIO_ALL_GATES_OPEN &&
+ ktime_after(guard, entry->close_time))
+ return NULL;
+
+ /* ... and no budget. */
+ if (gate_mask != TAPRIO_ALL_GATES_OPEN &&
+ atomic_sub_return(len, &entry->budget) < 0)
+ return NULL;
+
+ skb = child->ops->dequeue(child);
+ if (unlikely(!skb))
+ return NULL;
+
+ qdisc_bstats_update(sch, skb);
+ qdisc_qstats_backlog_dec(sch, skb);
+ sch->q.qlen--;
+
+ return skb;
+ }
+
+ return NULL;
+}
+
+static bool should_restart_cycle(const struct taprio_sched *q,
+ const struct sched_entry *entry)
+{
+ WARN_ON(!entry);
+
+ return list_is_last(&entry->list, &q->entries);
+}
+
+static enum hrtimer_restart advance_sched(struct hrtimer *timer)
+{
+ struct taprio_sched *q = container_of(timer, struct taprio_sched,
+ advance_timer);
+ struct sched_entry *entry, *next;
+ struct Qdisc *sch = q->root;
+ ktime_t close_time;
+
+ spin_lock(&q->current_entry_lock);
+ entry = rcu_dereference_protected(q->current_entry,
+ lockdep_is_held(&q->current_entry_lock));
+
+ /* This is the case that it's the first time that the schedule
+ * runs, so it only happens once per schedule. The first entry
+ * is pre-calculated during the schedule initialization.
+ */
+ if (unlikely(!entry)) {
+ next = list_first_entry(&q->entries, struct sched_entry,
+ list);
+ close_time = next->close_time;
+ goto first_run;
+ }
+
+ if (should_restart_cycle(q, entry))
+ next = list_first_entry(&q->entries, struct sched_entry,
+ list);
+ else
+ next = list_next_entry(entry, list);
+
+ close_time = ktime_add_ns(entry->close_time, next->interval);
+
+ next->close_time = close_time;
+ atomic_set(&next->budget,
+ (next->interval * 1000) / q->picos_per_byte);
+
+first_run:
+ rcu_assign_pointer(q->current_entry, next);
+ spin_unlock(&q->current_entry_lock);
+
+ hrtimer_set_expires(&q->advance_timer, close_time);
+
+ rcu_read_lock();
+ __netif_schedule(sch);
+ rcu_read_unlock();
+
+ return HRTIMER_RESTART;
+}
+
+static const struct nla_policy entry_policy[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = {
+ [TCA_TAPRIO_SCHED_ENTRY_INDEX] = { .type = NLA_U32 },
+ [TCA_TAPRIO_SCHED_ENTRY_CMD] = { .type = NLA_U8 },
+ [TCA_TAPRIO_SCHED_ENTRY_GATE_MASK] = { .type = NLA_U32 },
+ [TCA_TAPRIO_SCHED_ENTRY_INTERVAL] = { .type = NLA_U32 },
+};
+
+static const struct nla_policy entry_list_policy[TCA_TAPRIO_SCHED_MAX + 1] = {
+ [TCA_TAPRIO_SCHED_ENTRY] = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy taprio_policy[TCA_TAPRIO_ATTR_MAX + 1] = {
+ [TCA_TAPRIO_ATTR_PRIOMAP] = {
+ .len = sizeof(struct tc_mqprio_qopt)
+ },
+ [TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST] = { .type = NLA_NESTED },
+ [TCA_TAPRIO_ATTR_SCHED_BASE_TIME] = { .type = NLA_S64 },
+ [TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY] = { .type = NLA_NESTED },
+ [TCA_TAPRIO_ATTR_SCHED_CLOCKID] = { .type = NLA_S32 },
+};
+
+static int fill_sched_entry(struct nlattr **tb, struct sched_entry *entry,
+ struct netlink_ext_ack *extack)
+{
+ u32 interval = 0;
+
+ if (tb[TCA_TAPRIO_SCHED_ENTRY_CMD])
+ entry->command = nla_get_u8(
+ tb[TCA_TAPRIO_SCHED_ENTRY_CMD]);
+
+ if (tb[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK])
+ entry->gate_mask = nla_get_u32(
+ tb[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK]);
+
+ if (tb[TCA_TAPRIO_SCHED_ENTRY_INTERVAL])
+ interval = nla_get_u32(
+ tb[TCA_TAPRIO_SCHED_ENTRY_INTERVAL]);
+
+ if (interval == 0) {
+ NL_SET_ERR_MSG(extack, "Invalid interval for schedule entry");
+ return -EINVAL;
+ }
+
+ entry->interval = interval;
+
+ return 0;
+}
+
+static int parse_sched_entry(struct nlattr *n, struct sched_entry *entry,
+ int index, struct netlink_ext_ack *extack)
+{
+ struct nlattr *tb[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = { };
+ int err;
+
+ err = nla_parse_nested(tb, TCA_TAPRIO_SCHED_ENTRY_MAX, n,
+ entry_policy, NULL);
+ if (err < 0) {
+ NL_SET_ERR_MSG(extack, "Could not parse nested entry");
+ return -EINVAL;
+ }
+
+ entry->index = index;
+
+ return fill_sched_entry(tb, entry, extack);
+}
+
+/* Returns the number of entries in case of success */
+static int parse_sched_single_entry(struct nlattr *n,
+ struct taprio_sched *q,
+ struct netlink_ext_ack *extack)
+{
+ struct nlattr *tb_entry[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = { };
+ struct nlattr *tb_list[TCA_TAPRIO_SCHED_MAX + 1] = { };
+ struct sched_entry *entry;
+ bool found = false;
+ u32 index;
+ int err;
+
+ err = nla_parse_nested(tb_list, TCA_TAPRIO_SCHED_MAX,
+ n, entry_list_policy, NULL);
+ if (err < 0) {
+ NL_SET_ERR_MSG(extack, "Could not parse nested entry");
+ return -EINVAL;
+ }
+
+ if (!tb_list[TCA_TAPRIO_SCHED_ENTRY]) {
+ NL_SET_ERR_MSG(extack, "Single-entry must include an entry");
+ return -EINVAL;
+ }
+
+ err = nla_parse_nested(tb_entry, TCA_TAPRIO_SCHED_ENTRY_MAX,
+ tb_list[TCA_TAPRIO_SCHED_ENTRY],
+ entry_policy, NULL);
+ if (err < 0) {
+ NL_SET_ERR_MSG(extack, "Could not parse nested entry");
+ return -EINVAL;
+ }
+
+ if (!tb_entry[TCA_TAPRIO_SCHED_ENTRY_INDEX]) {
+ NL_SET_ERR_MSG(extack, "Entry must specify an index\n");
+ return -EINVAL;
+ }
+
+ index = nla_get_u32(tb_entry[TCA_TAPRIO_SCHED_ENTRY_INDEX]);
+ if (index >= q->num_entries) {
+ NL_SET_ERR_MSG(extack, "Index for single entry exceeds number of entries in schedule");
+ return -EINVAL;
+ }
+
+ list_for_each_entry(entry, &q->entries, list) {
+ if (entry->index == index) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ NL_SET_ERR_MSG(extack, "Could not find entry");
+ return -ENOENT;
+ }
+
+ err = fill_sched_entry(tb_entry, entry, extack);
+ if (err < 0)
+ return err;
+
+ return q->num_entries;
+}
+
+static int parse_sched_list(struct nlattr *list,
+ struct taprio_sched *q,
+ struct netlink_ext_ack *extack)
+{
+ struct nlattr *n;
+ int err, rem;
+ int i = 0;
+
+ if (!list)
+ return -EINVAL;
+
+ nla_for_each_nested(n, list, rem) {
+ struct sched_entry *entry;
+
+ if (nla_type(n) != TCA_TAPRIO_SCHED_ENTRY) {
+ NL_SET_ERR_MSG(extack, "Attribute is not of type 'entry'");
+ continue;
+ }
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ NL_SET_ERR_MSG(extack, "Not enough memory for entry");
+ return -ENOMEM;
+ }
+
+ err = parse_sched_entry(n, entry, i, extack);
+ if (err < 0) {
+ kfree(entry);
+ return err;
+ }
+
+ list_add_tail(&entry->list, &q->entries);
+ i++;
+ }
+
+ q->num_entries = i;
+
+ return i;
+}
+
+/* Returns the number of entries in case of success */
+static int parse_taprio_opt(struct nlattr **tb, struct taprio_sched *q,
+ struct netlink_ext_ack *extack)
+{
+ int err = 0;
+ int clockid;
+
+ if (tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST] &&
+ tb[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY])
+ return -EINVAL;
+
+ if (tb[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY] && q->num_entries == 0)
+ return -EINVAL;
+
+ if (q->clockid == -1 && !tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID])
+ return -EINVAL;
+
+ if (tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME])
+ q->base_time = nla_get_s64(
+ tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME]);
+
+ if (tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID]) {
+ clockid = nla_get_s32(tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID]);
+
+ /* We only support static clockids and we don't allow
+ * for it to be modified after the first init.
+ */
+ if (clockid < 0 || (q->clockid != -1 && q->clockid != clockid))
+ return -EINVAL;
+
+ q->clockid = clockid;
+ }
+
+ if (tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST])
+ err = parse_sched_list(
+ tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST], q, extack);
+ else if (tb[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY])
+ err = parse_sched_single_entry(
+ tb[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY], q, extack);
+
+ /* parse_sched_* return the number of entries in the schedule,
+ * a schedule with zero entries is an error.
+ */
+ if (err == 0) {
+ NL_SET_ERR_MSG(extack, "The schedule should contain at least one entry");
+ return -EINVAL;
+ }
+
+ return err;
+}
+
+static int taprio_parse_mqprio_opt(struct net_device *dev,
+ struct tc_mqprio_qopt *qopt,
+ struct netlink_ext_ack *extack)
+{
+ int i, j;
+
+ if (!qopt) {
+ NL_SET_ERR_MSG(extack, "'mqprio' configuration is necessary");
+ return -EINVAL;
+ }
+
+ /* Verify num_tc is not out of max range */
+ if (qopt->num_tc > TC_MAX_QUEUE) {
+ NL_SET_ERR_MSG(extack, "Number of traffic classes is outside valid range");
+ return -EINVAL;
+ }
+
+ /* taprio imposes that traffic classes map 1:n to tx queues */
+ if (qopt->num_tc > dev->num_tx_queues) {
+ NL_SET_ERR_MSG(extack, "Number of traffic classes is greater than number of HW queues");
+ return -EINVAL;
+ }
+
+ /* Verify priority mapping uses valid tcs */
+ for (i = 0; i < TC_BITMASK + 1; i++) {
+ if (qopt->prio_tc_map[i] >= qopt->num_tc) {
+ NL_SET_ERR_MSG(extack, "Invalid traffic class in priority to traffic class mapping");
+ return -EINVAL;
+ }
+ }
+
+ for (i = 0; i < qopt->num_tc; i++) {
+ unsigned int last = qopt->offset[i] + qopt->count[i];
+
+ /* Verify the queue count is in tx range being equal to the
+ * real_num_tx_queues indicates the last queue is in use.
+ */
+ if (qopt->offset[i] >= dev->num_tx_queues ||
+ !qopt->count[i] ||
+ last > dev->real_num_tx_queues) {
+ NL_SET_ERR_MSG(extack, "Invalid queue in traffic class to queue mapping");
+ return -EINVAL;
+ }
+
+ /* Verify that the offset and counts do not overlap */
+ for (j = i + 1; j < qopt->num_tc; j++) {
+ if (last > qopt->offset[j]) {
+ NL_SET_ERR_MSG(extack, "Detected overlap in the traffic class to queue mapping");
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static ktime_t taprio_get_start_time(struct Qdisc *sch)
+{
+ struct taprio_sched *q = qdisc_priv(sch);
+ struct sched_entry *entry;
+ ktime_t now, base, cycle;
+ s64 n;
+
+ base = ns_to_ktime(q->base_time);
+ cycle = 0;
+
+ /* Calculate the cycle_time, by summing all the intervals.
+ */
+ list_for_each_entry(entry, &q->entries, list)
+ cycle = ktime_add_ns(cycle, entry->interval);
+
+ if (!cycle)
+ return base;
+
+ now = q->get_time();
+
+ if (ktime_after(base, now))
+ return base;
+
+ /* Schedule the start time for the beginning of the next
+ * cycle.
+ */
+ n = div64_s64(ktime_sub_ns(now, base), cycle);
+
+ return ktime_add_ns(base, (n + 1) * cycle);
+}
+
+static void taprio_start_sched(struct Qdisc *sch, ktime_t start)
+{
+ struct taprio_sched *q = qdisc_priv(sch);
+ struct sched_entry *first;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->current_entry_lock, flags);
+
+ first = list_first_entry(&q->entries, struct sched_entry,
+ list);
+
+ first->close_time = ktime_add_ns(start, first->interval);
+ atomic_set(&first->budget,
+ (first->interval * 1000) / q->picos_per_byte);
+ rcu_assign_pointer(q->current_entry, NULL);
+
+ spin_unlock_irqrestore(&q->current_entry_lock, flags);
+
+ hrtimer_start(&q->advance_timer, start, HRTIMER_MODE_ABS);
+}
+
+static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
+ struct netlink_ext_ack *extack)
+{
+ struct nlattr *tb[TCA_TAPRIO_ATTR_MAX + 1] = { };
+ struct taprio_sched *q = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct tc_mqprio_qopt *mqprio = NULL;
+ struct ethtool_link_ksettings ecmd;
+ int i, err, size;
+ s64 link_speed;
+ ktime_t start;
+
+ err = nla_parse_nested(tb, TCA_TAPRIO_ATTR_MAX, opt,
+ taprio_policy, extack);
+ if (err < 0)
+ return err;
+
+ err = -EINVAL;
+ if (tb[TCA_TAPRIO_ATTR_PRIOMAP])
+ mqprio = nla_data(tb[TCA_TAPRIO_ATTR_PRIOMAP]);
+
+ err = taprio_parse_mqprio_opt(dev, mqprio, extack);
+ if (err < 0)
+ return err;
+
+ /* A schedule with less than one entry is an error */
+ size = parse_taprio_opt(tb, q, extack);
+ if (size < 0)
+ return size;
+
+ hrtimer_init(&q->advance_timer, q->clockid, HRTIMER_MODE_ABS);
+ q->advance_timer.function = advance_sched;
+
+ switch (q->clockid) {
+ case CLOCK_REALTIME:
+ q->get_time = ktime_get_real;
+ break;
+ case CLOCK_MONOTONIC:
+ q->get_time = ktime_get;
+ break;
+ case CLOCK_BOOTTIME:
+ q->get_time = ktime_get_boottime;
+ break;
+ case CLOCK_TAI:
+ q->get_time = ktime_get_clocktai;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ struct netdev_queue *dev_queue;
+ struct Qdisc *qdisc;
+
+ dev_queue = netdev_get_tx_queue(dev, i);
+ qdisc = qdisc_create_dflt(dev_queue,
+ &pfifo_qdisc_ops,
+ TC_H_MAKE(TC_H_MAJ(sch->handle),
+ TC_H_MIN(i + 1)),
+ extack);
+ if (!qdisc)
+ return -ENOMEM;
+
+ if (i < dev->real_num_tx_queues)
+ qdisc_hash_add(qdisc, false);
+
+ q->qdiscs[i] = qdisc;
+ }
+
+ if (mqprio) {
+ netdev_set_num_tc(dev, mqprio->num_tc);
+ for (i = 0; i < mqprio->num_tc; i++)
+ netdev_set_tc_queue(dev, i,
+ mqprio->count[i],
+ mqprio->offset[i]);
+
+ /* Always use supplied priority mappings */
+ for (i = 0; i < TC_BITMASK + 1; i++)
+ netdev_set_prio_tc_map(dev, i,
+ mqprio->prio_tc_map[i]);
+ }
+
+ if (!__ethtool_get_link_ksettings(dev, &ecmd))
+ link_speed = ecmd.base.speed;
+ else
+ link_speed = SPEED_1000;
+
+ q->picos_per_byte = div64_s64(NSEC_PER_SEC * 1000LL * 8,
+ link_speed * 1000 * 1000);
+
+ start = taprio_get_start_time(sch);
+ if (!start)
+ return 0;
+
+ taprio_start_sched(sch, start);
+
+ return 0;
+}
+
+static void taprio_destroy(struct Qdisc *sch)
+{
+ struct taprio_sched *q = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct sched_entry *entry, *n;
+ unsigned int i;
+
+ hrtimer_cancel(&q->advance_timer);
+
+ if (q->qdiscs) {
+ for (i = 0; i < dev->num_tx_queues && q->qdiscs[i]; i++)
+ qdisc_put(q->qdiscs[i]);
+
+ kfree(q->qdiscs);
+ }
+ q->qdiscs = NULL;
+
+ netdev_set_num_tc(dev, 0);
+
+ list_for_each_entry_safe(entry, n, &q->entries, list) {
+ list_del(&entry->list);
+ kfree(entry);
+ }
+}
+
+static int taprio_init(struct Qdisc *sch, struct nlattr *opt,
+ struct netlink_ext_ack *extack)
+{
+ struct taprio_sched *q = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+
+ INIT_LIST_HEAD(&q->entries);
+ spin_lock_init(&q->current_entry_lock);
+
+ /* We may overwrite the configuration later */
+ hrtimer_init(&q->advance_timer, CLOCK_TAI, HRTIMER_MODE_ABS);
+
+ q->root = sch;
+
+ /* We only support static clockids. Use an invalid value as default
+ * and get the valid one on taprio_change().
+ */
+ q->clockid = -1;
+
+ if (sch->parent != TC_H_ROOT)
+ return -EOPNOTSUPP;
+
+ if (!netif_is_multiqueue(dev))
+ return -EOPNOTSUPP;
+
+ /* pre-allocate qdisc, attachment can't fail */
+ q->qdiscs = kcalloc(dev->num_tx_queues,
+ sizeof(q->qdiscs[0]),
+ GFP_KERNEL);
+
+ if (!q->qdiscs)
+ return -ENOMEM;
+
+ if (!opt)
+ return -EINVAL;
+
+ return taprio_change(sch, opt, extack);
+}
+
+static struct netdev_queue *taprio_queue_get(struct Qdisc *sch,
+ unsigned long cl)
+{
+ struct net_device *dev = qdisc_dev(sch);
+ unsigned long ntx = cl - 1;
+
+ if (ntx >= dev->num_tx_queues)
+ return NULL;
+
+ return netdev_get_tx_queue(dev, ntx);
+}
+
+static int taprio_graft(struct Qdisc *sch, unsigned long cl,
+ struct Qdisc *new, struct Qdisc **old,
+ struct netlink_ext_ack *extack)
+{
+ struct taprio_sched *q = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
+
+ if (!dev_queue)
+ return -EINVAL;
+
+ if (dev->flags & IFF_UP)
+ dev_deactivate(dev);
+
+ *old = q->qdiscs[cl - 1];
+ q->qdiscs[cl - 1] = new;
+
+ if (new)
+ new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
+
+ if (dev->flags & IFF_UP)
+ dev_activate(dev);
+
+ return 0;
+}
+
+static int dump_entry(struct sk_buff *msg,
+ const struct sched_entry *entry)
+{
+ struct nlattr *item;
+
+ item = nla_nest_start(msg, TCA_TAPRIO_SCHED_ENTRY);
+ if (!item)
+ return -ENOSPC;
+
+ if (nla_put_u32(msg, TCA_TAPRIO_SCHED_ENTRY_INDEX, entry->index))
+ goto nla_put_failure;
+
+ if (nla_put_u8(msg, TCA_TAPRIO_SCHED_ENTRY_CMD, entry->command))
+ goto nla_put_failure;
+
+ if (nla_put_u32(msg, TCA_TAPRIO_SCHED_ENTRY_GATE_MASK,
+ entry->gate_mask))
+ goto nla_put_failure;
+
+ if (nla_put_u32(msg, TCA_TAPRIO_SCHED_ENTRY_INTERVAL,
+ entry->interval))
+ goto nla_put_failure;
+
+ return nla_nest_end(msg, item);
+
+nla_put_failure:
+ nla_nest_cancel(msg, item);
+ return -1;
+}
+
+static int taprio_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+ struct taprio_sched *q = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ struct tc_mqprio_qopt opt = { 0 };
+ struct nlattr *nest, *entry_list;
+ struct sched_entry *entry;
+ unsigned int i;
+
+ opt.num_tc = netdev_get_num_tc(dev);
+ memcpy(opt.prio_tc_map, dev->prio_tc_map, sizeof(opt.prio_tc_map));
+
+ for (i = 0; i < netdev_get_num_tc(dev); i++) {
+ opt.count[i] = dev->tc_to_txq[i].count;
+ opt.offset[i] = dev->tc_to_txq[i].offset;
+ }
+
+ nest = nla_nest_start(skb, TCA_OPTIONS);
+ if (!nest)
+ return -ENOSPC;
+
+ if (nla_put(skb, TCA_TAPRIO_ATTR_PRIOMAP, sizeof(opt), &opt))
+ goto options_error;
+
+ if (nla_put_s64(skb, TCA_TAPRIO_ATTR_SCHED_BASE_TIME,
+ q->base_time, TCA_TAPRIO_PAD))
+ goto options_error;
+
+ if (nla_put_s32(skb, TCA_TAPRIO_ATTR_SCHED_CLOCKID, q->clockid))
+ goto options_error;
+
+ entry_list = nla_nest_start(skb, TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST);
+ if (!entry_list)
+ goto options_error;
+
+ list_for_each_entry(entry, &q->entries, list) {
+ if (dump_entry(skb, entry) < 0)
+ goto options_error;
+ }
+
+ nla_nest_end(skb, entry_list);
+
+ return nla_nest_end(skb, nest);
+
+options_error:
+ nla_nest_cancel(skb, nest);
+ return -1;
+}
+
+static struct Qdisc *taprio_leaf(struct Qdisc *sch, unsigned long cl)
+{
+ struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
+
+ if (!dev_queue)
+ return NULL;
+
+ return dev_queue->qdisc_sleeping;
+}
+
+static unsigned long taprio_find(struct Qdisc *sch, u32 classid)
+{
+ unsigned int ntx = TC_H_MIN(classid);
+
+ if (!taprio_queue_get(sch, ntx))
+ return 0;
+ return ntx;
+}
+
+static int taprio_dump_class(struct Qdisc *sch, unsigned long cl,
+ struct sk_buff *skb, struct tcmsg *tcm)
+{
+ struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
+
+ tcm->tcm_parent = TC_H_ROOT;
+ tcm->tcm_handle |= TC_H_MIN(cl);
+ tcm->tcm_info = dev_queue->qdisc_sleeping->handle;
+
+ return 0;
+}
+
+static int taprio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
+ struct gnet_dump *d)
+ __releases(d->lock)
+ __acquires(d->lock)
+{
+ struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
+
+ sch = dev_queue->qdisc_sleeping;
+ if (gnet_stats_copy_basic(&sch->running, d, NULL, &sch->bstats) < 0 ||
+ gnet_stats_copy_queue(d, NULL, &sch->qstats, sch->q.qlen) < 0)
+ return -1;
+ return 0;
+}
+
+static void taprio_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+ struct net_device *dev = qdisc_dev(sch);
+ unsigned long ntx;
+
+ if (arg->stop)
+ return;
+
+ arg->count = arg->skip;
+ for (ntx = arg->skip; ntx < dev->num_tx_queues; ntx++) {
+ if (arg->fn(sch, ntx + 1, arg) < 0) {
+ arg->stop = 1;
+ break;
+ }
+ arg->count++;
+ }
+}
+
+static struct netdev_queue *taprio_select_queue(struct Qdisc *sch,
+ struct tcmsg *tcm)
+{
+ return taprio_queue_get(sch, TC_H_MIN(tcm->tcm_parent));
+}
+
+static const struct Qdisc_class_ops taprio_class_ops = {
+ .graft = taprio_graft,
+ .leaf = taprio_leaf,
+ .find = taprio_find,
+ .walk = taprio_walk,
+ .dump = taprio_dump_class,
+ .dump_stats = taprio_dump_class_stats,
+ .select_queue = taprio_select_queue,
+};
+
+static struct Qdisc_ops taprio_qdisc_ops __read_mostly = {
+ .cl_ops = &taprio_class_ops,
+ .id = "taprio",
+ .priv_size = sizeof(struct taprio_sched),
+ .init = taprio_init,
+ .destroy = taprio_destroy,
+ .peek = taprio_peek,
+ .dequeue = taprio_dequeue,
+ .enqueue = taprio_enqueue,
+ .dump = taprio_dump,
+ .owner = THIS_MODULE,
+};
+
+static int __init taprio_module_init(void)
+{
+ return register_qdisc(&taprio_qdisc_ops);
+}
+
+static void __exit taprio_module_exit(void)
+{
+ unregister_qdisc(&taprio_qdisc_ops);
+}
+
+module_init(taprio_module_init);
+module_exit(taprio_module_exit);
+MODULE_LICENSE("GPL");
--
2.19.0
^ permalink raw reply related
* [PATCH net-next v1 0/1] net/sched: Introduce the taprio scheduler
From: Vinicius Costa Gomes @ 2018-09-29 0:59 UTC (permalink / raw)
To: netdev
Cc: Vinicius Costa Gomes, jesus.sanchez-palencia, henrik,
richardcochran, jhs, xiyou.wangcong, jiri, ilias.apalodimas,
simon.fok
Hi,
Changes from the RFC:
- Moved some fields from the per-qdisc data structure to the per
schedule entry one, mainly "expires" (now called "close_time",
when an entry ends) and "budget" (how many bytes can be sent
during an entry);
- Removed support for the schedule file, in favour of using iproute2
batch mode (only affects the iproute2 patches) (Jiri Pirko,
Stephen Hemminger);
- Removed support for manually setting a cycle-time (it will be
added in a later series);
Original cover letter
=====================
(lightly edited, updated references and usage)
This series provides a set of interfaces that can be used by
applications that require (time-based) Scheduled Transmission of
packets. It is comprised by 3 new components to the kernel:
- etf: the per-queue TxTime-Based scheduling qdisc;
- taprio: the per-port Time-Aware scheduler qdisc;
- SO_TXTIME: a socket option + cmsg APIs.
ETF and SO_TXTIME are already applied[1] into the net-next tree. This
is the remaining piece.
Overview
========
The CBS qdisc proposal RFC [2] included some rough ideas about the
design and API of a "taprio" (Time Aware Priority) qdisc. The idea of
presenting the taprio ideas at that point (almost one year ago!) was
to show our vision of how things would fit together going forward.
>From that concept stage to this (almost) realised stage the main
differences are:
- As of now, taprio is a software only implementation of a schedule
executor;
- Instead of taprio centralising all the time based decisions, taprio
can work together with ETF (the Earliest TxTime First), a qdisc
meant to use the LaunchTime (or similar) feature of various network
controllers;
In a nutshell, taprio is a root qdisc that can execute a pre-defined
schedule, etf is a qdisc that provides time based admission control
and "earliest deadline first" dequeue mode, and SO_TXTIME is a socket
option that is used for enabling a socket to be used for time-based
Tx and configuring its parameters.
taprio
======
This scheduler allows the network administrator to configure schedules
for classes of traffic, the configuration interface is similar to what
IEEE 802.1Q-2018 defines.
Example configuration:
$ tc qdisc add dev enp2s0 parent root handle 100 taprio \
num_tc 3 \
map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \
queues 1@0 1@1 2@2 \
sched-entry S 01 300000 \
sched-entry S 02 300000 \
sched-entry S 04 300000 \
base-time 1528743495910289987 \
clockid CLOCK_TAI
This qdisc borrows a few concepts from mqprio and so, most the
parameters are similar to mqprio. The main difference is the sequence of
'sched-entry' parameters, that constitute one schedule:
sched-entry S 01 300000
sched-entry S 02 300000
sched-entry S 04 300000
The format of each entry is:
sched-entry <CMD> <GATE MASK> <INTERVAL>
The only supported <CMD> is "S", which means "SetGateStates",
following the IEEE 802.1Q-2018 definition (Table 8-7). <GATE MASK>
is a bit-mask where each bit is a associated with a traffic class, so
bit 0 (the least significant bit) being "on" means that traffic class
0 is "active" for that schedule entry. <INTERVAL> is a time duration
in nanoseconds that specifies for how long that state defined by <CMD>
and <GATE MASK> should be held before moving to the next entry.
This schedule is circular, that is, after the last entry is executed
it starts from the first one, indefinitely.
The other parameters can be defined as follows:
- base-time: allows that multiple systems can have synchronised
schedules, it specifies the instant when the schedule starts;
- clockid: specifies the reference clock to be used;
A more complete example can be found here, with instructions of how to
test it:
https://gist.github.com/jeez/bd3afeff081ba64a695008dd8215866f [3]
The basic design of the scheduler is simple, after we calculate the
first expiration of the hrtimer, we set the next expiration to be the
previous plus the current entry's interval. At each time the function
runs, we set the current_entry, which has a gate_mask (that controls
which traffic classes are allowed to "go out" during each interval),
and we reuse this callback to "kick" the qdisc (this is the reason
that the usual qdisc watchdog isn't used).
Future work
===========
- Add support for multiple schedules, so something like the Admin
and Oper schedules from IEEE 802.1Q-2018 can be implemented,
probably "cycle-time" will be re-implemented at this time;
- Add support for HW offloading;
- Add support for Frame Preemption related commands (formerly
802.1Qbu, now part of 802.1Q);
Known Issues
============
- As taprio is a software only implementation, and there's another
layer of queuing in the network controller, packets can still
leave the controller outside their "correct" windows. This happens
mostly for low-priority classes, and only if they are 'starved' by
the higher priority ones;
This series is also hosted on github and can be found at [4].
The companion iproute2 patches can be found at [5].
Cheers,
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox