Commit b3b71597 authored by Lendacky, Thomas's avatar Lendacky, Thomas Committed by David S. Miller

amd-xgbe: Do traffic class setup when called through dcbnl

Currently the netdev traffic class setup is only performed when invoked
through the ndo_setup_tc interface. However, the same setup should be
performed when the dcbnl interface (ieee_setets) is invoked. Rework the
netdev traffic class setup to be invokable through either interface and
also provide the priority to traffic class mapping if available.
Signed-off-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6a49ee4e
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* License 1: GPLv2 * License 1: GPLv2
* *
* Copyright (c) 2014 Advanced Micro Devices, Inc. * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
* *
* This file is free software; you may copy, redistribute and/or modify * This file is free software; you may copy, redistribute and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
* *
* License 2: Modified BSD * License 2: Modified BSD
* *
* Copyright (c) 2014 Advanced Micro Devices, Inc. * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -146,6 +146,7 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev, ...@@ -146,6 +146,7 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev,
{ {
struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_prv_data *pdata = netdev_priv(netdev);
unsigned int i, tc_ets, tc_ets_weight; unsigned int i, tc_ets, tc_ets_weight;
u8 max_tc = 0;
tc_ets = 0; tc_ets = 0;
tc_ets_weight = 0; tc_ets_weight = 0;
...@@ -157,12 +158,9 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev, ...@@ -157,12 +158,9 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev,
netif_dbg(pdata, drv, netdev, "PRIO%u: TC=%hhu\n", i, netif_dbg(pdata, drv, netdev, "PRIO%u: TC=%hhu\n", i,
ets->prio_tc[i]); ets->prio_tc[i]);
if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]) && max_tc = max_t(u8, max_tc, ets->prio_tc[i]);
(i >= pdata->hw_feat.tc_cnt)) if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]))
return -EINVAL; max_tc = max_t(u8, max_tc, i);
if (ets->prio_tc[i] >= pdata->hw_feat.tc_cnt)
return -EINVAL;
switch (ets->tc_tsa[i]) { switch (ets->tc_tsa[i]) {
case IEEE_8021QAZ_TSA_STRICT: case IEEE_8021QAZ_TSA_STRICT:
...@@ -171,15 +169,28 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev, ...@@ -171,15 +169,28 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev,
tc_ets = 1; tc_ets = 1;
tc_ets_weight += ets->tc_tx_bw[i]; tc_ets_weight += ets->tc_tx_bw[i];
break; break;
default: default:
netif_err(pdata, drv, netdev,
"unsupported TSA algorithm (%hhu)\n",
ets->tc_tsa[i]);
return -EINVAL; return -EINVAL;
} }
} }
/* Check maximum traffic class requested */
if (max_tc >= pdata->hw_feat.tc_cnt) {
netif_err(pdata, drv, netdev,
"exceeded number of supported traffic classes\n");
return -EINVAL;
}
/* Weights must add up to 100% */ /* Weights must add up to 100% */
if (tc_ets && (tc_ets_weight != 100)) if (tc_ets && (tc_ets_weight != 100)) {
netif_err(pdata, drv, netdev,
"sum of ETS algorithm weights is not 100 (%u)\n",
tc_ets_weight);
return -EINVAL; return -EINVAL;
}
if (!pdata->ets) { if (!pdata->ets) {
pdata->ets = devm_kzalloc(pdata->dev, sizeof(*pdata->ets), pdata->ets = devm_kzalloc(pdata->dev, sizeof(*pdata->ets),
...@@ -188,6 +199,7 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev, ...@@ -188,6 +199,7 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev,
return -ENOMEM; return -ENOMEM;
} }
pdata->num_tcs = max_tc + 1;
memcpy(pdata->ets, ets, sizeof(*pdata->ets)); memcpy(pdata->ets, ets, sizeof(*pdata->ets));
pdata->hw_if.config_dcb_tc(pdata); pdata->hw_if.config_dcb_tc(pdata);
...@@ -221,6 +233,13 @@ static int xgbe_dcb_ieee_setpfc(struct net_device *netdev, ...@@ -221,6 +233,13 @@ static int xgbe_dcb_ieee_setpfc(struct net_device *netdev,
"cap=%hhu, en=%#hhx, mbc=%hhu, delay=%hhu\n", "cap=%hhu, en=%#hhx, mbc=%hhu, delay=%hhu\n",
pfc->pfc_cap, pfc->pfc_en, pfc->mbc, pfc->delay); pfc->pfc_cap, pfc->pfc_en, pfc->mbc, pfc->delay);
/* Check PFC for supported number of traffic classes */
if (pfc->pfc_en & ~((1 << pdata->hw_feat.tc_cnt) - 1)) {
netif_err(pdata, drv, netdev,
"PFC requested for unsupported traffic class\n");
return -EINVAL;
}
if (!pdata->pfc) { if (!pdata->pfc) {
pdata->pfc = devm_kzalloc(pdata->dev, sizeof(*pdata->pfc), pdata->pfc = devm_kzalloc(pdata->dev, sizeof(*pdata->pfc),
GFP_KERNEL); GFP_KERNEL);
......
...@@ -1325,6 +1325,36 @@ static int xgbe_config_tstamp(struct xgbe_prv_data *pdata, ...@@ -1325,6 +1325,36 @@ static int xgbe_config_tstamp(struct xgbe_prv_data *pdata,
return 0; return 0;
} }
static void xgbe_config_tc(struct xgbe_prv_data *pdata)
{
unsigned int offset, queue, prio;
u8 i;
netdev_reset_tc(pdata->netdev);
if (!pdata->num_tcs)
return;
netdev_set_num_tc(pdata->netdev, pdata->num_tcs);
for (i = 0, queue = 0, offset = 0; i < pdata->num_tcs; i++) {
while ((queue < pdata->tx_q_count) &&
(pdata->q2tc_map[queue] == i))
queue++;
netif_dbg(pdata, drv, pdata->netdev, "TC%u using TXq%u-%u\n",
i, offset, queue - 1);
netdev_set_tc_queue(pdata->netdev, i, queue - offset, offset);
offset = queue;
}
if (!pdata->ets)
return;
for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
netdev_set_prio_tc_map(pdata->netdev, prio,
pdata->ets->prio_tc[prio]);
}
static void xgbe_config_dcb_tc(struct xgbe_prv_data *pdata) static void xgbe_config_dcb_tc(struct xgbe_prv_data *pdata)
{ {
struct ieee_ets *ets = pdata->ets; struct ieee_ets *ets = pdata->ets;
...@@ -1386,6 +1416,8 @@ static void xgbe_config_dcb_tc(struct xgbe_prv_data *pdata) ...@@ -1386,6 +1416,8 @@ static void xgbe_config_dcb_tc(struct xgbe_prv_data *pdata)
break; break;
} }
} }
xgbe_config_tc(pdata);
} }
static void xgbe_config_dcb_pfc(struct xgbe_prv_data *pdata) static void xgbe_config_dcb_pfc(struct xgbe_prv_data *pdata)
...@@ -2910,6 +2942,7 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) ...@@ -2910,6 +2942,7 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if)
hw_if->get_tx_tstamp = xgbe_get_tx_tstamp; hw_if->get_tx_tstamp = xgbe_get_tx_tstamp;
/* For Data Center Bridging config */ /* For Data Center Bridging config */
hw_if->config_tc = xgbe_config_tc;
hw_if->config_dcb_tc = xgbe_config_dcb_tc; hw_if->config_dcb_tc = xgbe_config_dcb_tc;
hw_if->config_dcb_pfc = xgbe_config_dcb_pfc; hw_if->config_dcb_pfc = xgbe_config_dcb_pfc;
......
...@@ -1630,32 +1630,18 @@ static int xgbe_setup_tc(struct net_device *netdev, u32 handle, __be16 proto, ...@@ -1630,32 +1630,18 @@ static int xgbe_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
struct tc_to_netdev *tc_to_netdev) struct tc_to_netdev *tc_to_netdev)
{ {
struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_prv_data *pdata = netdev_priv(netdev);
unsigned int offset, queue; u8 tc;
u8 i, tc;
if (handle != TC_H_ROOT || tc_to_netdev->type != TC_SETUP_MQPRIO) if (handle != TC_H_ROOT || tc_to_netdev->type != TC_SETUP_MQPRIO)
return -EINVAL; return -EINVAL;
tc = tc_to_netdev->tc; tc = tc_to_netdev->tc;
if (tc && (tc != pdata->hw_feat.tc_cnt)) if (tc > pdata->hw_feat.tc_cnt)
return -EINVAL; return -EINVAL;
if (tc) { pdata->num_tcs = tc;
netdev_set_num_tc(netdev, tc); pdata->hw_if.config_tc(pdata);
for (i = 0, queue = 0, offset = 0; i < tc; i++) {
while ((queue < pdata->tx_q_count) &&
(pdata->q2tc_map[queue] == i))
queue++;
netif_dbg(pdata, drv, netdev, "TC%u using TXq%u-%u\n",
i, offset, queue - 1);
netdev_set_tc_queue(netdev, i, queue - offset, offset);
offset = queue;
}
} else {
netdev_reset_tc(netdev);
}
return 0; return 0;
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* License 1: GPLv2 * License 1: GPLv2
* *
* Copyright (c) 2014 Advanced Micro Devices, Inc. * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
* *
* This file is free software; you may copy, redistribute and/or modify * This file is free software; you may copy, redistribute and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
* *
* License 2: Modified BSD * License 2: Modified BSD
* *
* Copyright (c) 2014 Advanced Micro Devices, Inc. * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -673,6 +673,7 @@ struct xgbe_hw_if { ...@@ -673,6 +673,7 @@ struct xgbe_hw_if {
u64 (*get_tx_tstamp)(struct xgbe_prv_data *); u64 (*get_tx_tstamp)(struct xgbe_prv_data *);
/* For Data Center Bridging config */ /* For Data Center Bridging config */
void (*config_tc)(struct xgbe_prv_data *);
void (*config_dcb_tc)(struct xgbe_prv_data *); void (*config_dcb_tc)(struct xgbe_prv_data *);
void (*config_dcb_pfc)(struct xgbe_prv_data *); void (*config_dcb_pfc)(struct xgbe_prv_data *);
...@@ -880,6 +881,7 @@ struct xgbe_prv_data { ...@@ -880,6 +881,7 @@ struct xgbe_prv_data {
struct ieee_pfc *pfc; struct ieee_pfc *pfc;
unsigned int q2tc_map[XGBE_MAX_QUEUES]; unsigned int q2tc_map[XGBE_MAX_QUEUES];
unsigned int prio2q_map[IEEE_8021QAZ_MAX_TCS]; unsigned int prio2q_map[IEEE_8021QAZ_MAX_TCS];
u8 num_tcs;
/* Hardware features of the device */ /* Hardware features of the device */
struct xgbe_hw_features hw_feat; struct xgbe_hw_features hw_feat;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment