aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2021-08-29 10:44:31 +0100
committerDavid S. Miller <davem@davemloft.net>2021-08-29 10:44:31 +0100
commitd65a606b90ee2d4abd9961aadc9c3c69b9691e04 (patch)
treeeff27d1e59adec5251429b38a6a7eea96e97b1f0
parentc77225119daa0ca0a9c6c007945c0a87b3e4a2e8 (diff)
parent1ab011b0bf073ef02abf15344bb59e383aa15457 (diff)
downloadlinux-d65a606b90ee2d4abd9961aadc9c3c69b9691e04.tar.gz
Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-
queue Tony Nguyen says: ==================== 1GbE Intel Wired LAN Driver Updates 2021-08-27 ravindhan Gunasekaran says: This adds support for Credit-based shaper qdisc offload from Traffic Control system. It enables traffic prioritization and bandwidth reservation via the Credit-Based Shaper which is implemented in hardware by i225 controller. Patch 1/3 adds a default cycle-time for TSN mode to be configured. Patch 2/3 helps to separate TSN mode programming on the fly and during reset sequence. It also simplifies handling features flags for various TSN modes supported by i225 in the driver. Patch 3/3 adds support for IEEE802.1Qav(CBS) standard implemented in i225 HW. Two sets of CBS HW shapers are present in i225 and driver enables them in the two high priority queues. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/intel/igc/igc.h11
-rw-r--r--drivers/net/ethernet/intel/igc/igc_defines.h8
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c110
-rw-r--r--drivers/net/ethernet/intel/igc/igc_regs.h3
-rw-r--r--drivers/net/ethernet/intel/igc/igc_tsn.c174
-rw-r--r--drivers/net/ethernet/intel/igc/igc_tsn.h1
6 files changed, 258 insertions, 49 deletions
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index 2d17a6da63cf0..3e386c38d016c 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -98,6 +98,13 @@ struct igc_ring {
u32 start_time;
u32 end_time;
+ /* CBS parameters */
+ bool cbs_enable; /* indicates if CBS is enabled */
+ s32 idleslope; /* idleSlope in kbps */
+ s32 sendslope; /* sendSlope in kbps */
+ s32 hicredit; /* hiCredit in bytes */
+ s32 locredit; /* loCredit in bytes */
+
/* everything past this point are written often */
u16 next_to_clean;
u16 next_to_use;
@@ -290,6 +297,10 @@ extern char igc_driver_name[];
#define IGC_FLAG_VLAN_PROMISC BIT(15)
#define IGC_FLAG_RX_LEGACY BIT(16)
#define IGC_FLAG_TSN_QBV_ENABLED BIT(17)
+#define IGC_FLAG_TSN_QAV_ENABLED BIT(18)
+
+#define IGC_FLAG_TSN_ANY_ENABLED \
+ (IGC_FLAG_TSN_QBV_ENABLED | IGC_FLAG_TSN_QAV_ENABLED)
#define IGC_FLAG_RSS_FIELD_IPV4_UDP BIT(6)
#define IGC_FLAG_RSS_FIELD_IPV6_UDP BIT(7)
diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h
index c40563350a5ea..a4bbee7487984 100644
--- a/drivers/net/ethernet/intel/igc/igc_defines.h
+++ b/drivers/net/ethernet/intel/igc/igc_defines.h
@@ -518,6 +518,14 @@
#define IGC_TXQCTL_QUEUE_MODE_LAUNCHT 0x00000001
#define IGC_TXQCTL_STRICT_CYCLE 0x00000002
#define IGC_TXQCTL_STRICT_END 0x00000004
+#define IGC_TXQCTL_QAV_SEL_MASK 0x000000C0
+#define IGC_TXQCTL_QAV_SEL_CBS0 0x00000080
+#define IGC_TXQCTL_QAV_SEL_CBS1 0x000000C0
+
+#define IGC_TQAVCC_IDLESLOPE_MASK 0xFFFF
+#define IGC_TQAVCC_KEEP_CREDITS BIT(30)
+
+#define IGC_MAX_SR_QUEUES 2
/* Receive Checksum Control */
#define IGC_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index c6c075a637ea8..b877efae61dfa 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -120,7 +120,7 @@ void igc_reset(struct igc_adapter *adapter)
igc_ptp_reset(adapter);
/* Re-enable TSN offloading, where applicable. */
- igc_tsn_offload_apply(adapter);
+ igc_tsn_reset(adapter);
igc_get_phy_info(hw);
}
@@ -5749,7 +5749,6 @@ static int igc_save_launchtime_params(struct igc_adapter *adapter, int queue,
bool enable)
{
struct igc_ring *ring;
- int i;
if (queue < 0 || queue >= adapter->num_tx_queues)
return -EINVAL;
@@ -5757,17 +5756,6 @@ static int igc_save_launchtime_params(struct igc_adapter *adapter, int queue,
ring = adapter->tx_ring[queue];
ring->launchtime_enable = enable;
- if (adapter->base_time)
- return 0;
-
- adapter->cycle_time = NSEC_PER_SEC;
-
- for (i = 0; i < adapter->num_tx_queues; i++) {
- ring = adapter->tx_ring[i];
- ring->start_time = 0;
- ring->end_time = NSEC_PER_SEC;
- }
-
return 0;
}
@@ -5840,16 +5828,31 @@ static int igc_tsn_enable_launchtime(struct igc_adapter *adapter,
return igc_tsn_offload_apply(adapter);
}
+static int igc_tsn_clear_schedule(struct igc_adapter *adapter)
+{
+ int i;
+
+ adapter->base_time = 0;
+ adapter->cycle_time = NSEC_PER_SEC;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct igc_ring *ring = adapter->tx_ring[i];
+
+ ring->start_time = 0;
+ ring->end_time = NSEC_PER_SEC;
+ }
+
+ return 0;
+}
+
static int igc_save_qbv_schedule(struct igc_adapter *adapter,
struct tc_taprio_qopt_offload *qopt)
{
u32 start_time = 0, end_time = 0;
size_t n;
- if (!qopt->enable) {
- adapter->base_time = 0;
- return 0;
- }
+ if (!qopt->enable)
+ return igc_tsn_clear_schedule(adapter);
if (adapter->base_time)
return -EALREADY;
@@ -5901,6 +5904,74 @@ static int igc_tsn_enable_qbv_scheduling(struct igc_adapter *adapter,
return igc_tsn_offload_apply(adapter);
}
+static int igc_save_cbs_params(struct igc_adapter *adapter, int queue,
+ bool enable, int idleslope, int sendslope,
+ int hicredit, int locredit)
+{
+ bool cbs_status[IGC_MAX_SR_QUEUES] = { false };
+ struct net_device *netdev = adapter->netdev;
+ struct igc_ring *ring;
+ int i;
+
+ /* i225 has two sets of credit-based shaper logic.
+ * Supporting it only on the top two priority queues
+ */
+ if (queue < 0 || queue > 1)
+ return -EINVAL;
+
+ ring = adapter->tx_ring[queue];
+
+ for (i = 0; i < IGC_MAX_SR_QUEUES; i++)
+ if (adapter->tx_ring[i])
+ cbs_status[i] = adapter->tx_ring[i]->cbs_enable;
+
+ /* CBS should be enabled on the highest priority queue first in order
+ * for the CBS algorithm to operate as intended.
+ */
+ if (enable) {
+ if (queue == 1 && !cbs_status[0]) {
+ netdev_err(netdev,
+ "Enabling CBS on queue1 before queue0\n");
+ return -EINVAL;
+ }
+ } else {
+ if (queue == 0 && cbs_status[1]) {
+ netdev_err(netdev,
+ "Disabling CBS on queue0 before queue1\n");
+ return -EINVAL;
+ }
+ }
+
+ ring->cbs_enable = enable;
+ ring->idleslope = idleslope;
+ ring->sendslope = sendslope;
+ ring->hicredit = hicredit;
+ ring->locredit = locredit;
+
+ return 0;
+}
+
+static int igc_tsn_enable_cbs(struct igc_adapter *adapter,
+ struct tc_cbs_qopt_offload *qopt)
+{
+ struct igc_hw *hw = &adapter->hw;
+ int err;
+
+ if (hw->mac.type != igc_i225)
+ return -EOPNOTSUPP;
+
+ if (qopt->queue < 0 || qopt->queue > 1)
+ return -EINVAL;
+
+ err = igc_save_cbs_params(adapter, qopt->queue, qopt->enable,
+ qopt->idleslope, qopt->sendslope,
+ qopt->hicredit, qopt->locredit);
+ if (err)
+ return err;
+
+ return igc_tsn_offload_apply(adapter);
+}
+
static int igc_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
@@ -5913,6 +5984,9 @@ static int igc_setup_tc(struct net_device *dev, enum tc_setup_type type,
case TC_SETUP_QDISC_ETF:
return igc_tsn_enable_launchtime(adapter, type_data);
+ case TC_SETUP_QDISC_CBS:
+ return igc_tsn_enable_cbs(adapter, type_data);
+
default:
return -EOPNOTSUPP;
}
@@ -6339,6 +6413,8 @@ static int igc_probe(struct pci_dev *pdev,
igc_ptp_init(adapter);
+ igc_tsn_clear_schedule(adapter);
+
/* reset the hardware with the new settings */
igc_reset(adapter);
diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h
index dbba2eb2a2479..e197a33d93a03 100644
--- a/drivers/net/ethernet/intel/igc/igc_regs.h
+++ b/drivers/net/ethernet/intel/igc/igc_regs.h
@@ -236,6 +236,9 @@
#define IGC_ENDQT(_n) (0x3334 + 0x4 * (_n))
#define IGC_DTXMXPKTSZ 0x355C
+#define IGC_TQAVCC(_n) (0x3004 + ((_n) * 0x40))
+#define IGC_TQAVHC(_n) (0x300C + ((_n) * 0x40))
+
/* System Time Registers */
#define IGC_SYSTIML 0x0B600 /* System time register Low - RO */
#define IGC_SYSTIMH 0x0B604 /* System time register High - RO */
diff --git a/drivers/net/ethernet/intel/igc/igc_tsn.c b/drivers/net/ethernet/intel/igc/igc_tsn.c
index 4dbbb8a32ce91..0fce22de2ab85 100644
--- a/drivers/net/ethernet/intel/igc/igc_tsn.c
+++ b/drivers/net/ethernet/intel/igc/igc_tsn.c
@@ -18,8 +18,38 @@ static bool is_any_launchtime(struct igc_adapter *adapter)
return false;
}
+static bool is_cbs_enabled(struct igc_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct igc_ring *ring = adapter->tx_ring[i];
+
+ if (ring->cbs_enable)
+ return true;
+ }
+
+ return false;
+}
+
+static unsigned int igc_tsn_new_flags(struct igc_adapter *adapter)
+{
+ unsigned int new_flags = adapter->flags & ~IGC_FLAG_TSN_ANY_ENABLED;
+
+ if (adapter->base_time)
+ new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
+
+ if (is_any_launchtime(adapter))
+ new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
+
+ if (is_cbs_enabled(adapter))
+ new_flags |= IGC_FLAG_TSN_QAV_ENABLED;
+
+ return new_flags;
+}
+
/* Returns the TSN specific registers to their default values after
- * TSN offloading is disabled.
+ * the adapter is reset.
*/
static int igc_tsn_disable_offload(struct igc_adapter *adapter)
{
@@ -27,11 +57,6 @@ static int igc_tsn_disable_offload(struct igc_adapter *adapter)
u32 tqavctrl;
int i;
- if (!(adapter->flags & IGC_FLAG_TSN_QBV_ENABLED))
- return 0;
-
- adapter->cycle_time = 0;
-
wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT);
wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT);
@@ -41,12 +66,6 @@ static int igc_tsn_disable_offload(struct igc_adapter *adapter)
wr32(IGC_TQAVCTRL, tqavctrl);
for (i = 0; i < adapter->num_tx_queues; i++) {
- struct igc_ring *ring = adapter->tx_ring[i];
-
- ring->start_time = 0;
- ring->end_time = 0;
- ring->launchtime_enable = false;
-
wr32(IGC_TXQCTL(i), 0);
wr32(IGC_STQT(i), 0);
wr32(IGC_ENDQT(i), NSEC_PER_SEC);
@@ -68,9 +87,6 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter)
ktime_t base_time, systim;
int i;
- if (adapter->flags & IGC_FLAG_TSN_QBV_ENABLED)
- return 0;
-
cycle = adapter->cycle_time;
base_time = adapter->base_time;
@@ -88,6 +104,8 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter)
for (i = 0; i < adapter->num_tx_queues; i++) {
struct igc_ring *ring = adapter->tx_ring[i];
u32 txqctl = 0;
+ u16 cbs_value;
+ u32 tqavcc;
wr32(IGC_STQT(i), ring->start_time);
wr32(IGC_ENDQT(i), ring->end_time);
@@ -105,6 +123,90 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter)
if (ring->launchtime_enable)
txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT;
+ /* Skip configuring CBS for Q2 and Q3 */
+ if (i > 1)
+ goto skip_cbs;
+
+ if (ring->cbs_enable) {
+ if (i == 0)
+ txqctl |= IGC_TXQCTL_QAV_SEL_CBS0;
+ else
+ txqctl |= IGC_TXQCTL_QAV_SEL_CBS1;
+
+ /* According to i225 datasheet section 7.5.2.7, we
+ * should set the 'idleSlope' field from TQAVCC
+ * register following the equation:
+ *
+ * value = link-speed 0x7736 * BW * 0.2
+ * ---------- * ----------------- (E1)
+ * 100Mbps 2.5
+ *
+ * Note that 'link-speed' is in Mbps.
+ *
+ * 'BW' is the percentage bandwidth out of full
+ * link speed which can be found with the
+ * following equation. Note that idleSlope here
+ * is the parameter from this function
+ * which is in kbps.
+ *
+ * BW = idleSlope
+ * ----------------- (E2)
+ * link-speed * 1000
+ *
+ * That said, we can come up with a generic
+ * equation to calculate the value we should set
+ * it TQAVCC register by replacing 'BW' in E1 by E2.
+ * The resulting equation is:
+ *
+ * value = link-speed * 0x7736 * idleSlope * 0.2
+ * ------------------------------------- (E3)
+ * 100 * 2.5 * link-speed * 1000
+ *
+ * 'link-speed' is present in both sides of the
+ * fraction so it is canceled out. The final
+ * equation is the following:
+ *
+ * value = idleSlope * 61036
+ * ----------------- (E4)
+ * 2500000
+ *
+ * NOTE: For i225, given the above, we can see
+ * that idleslope is represented in
+ * 40.959433 kbps units by the value at
+ * the TQAVCC register (2.5Gbps / 61036),
+ * which reduces the granularity for
+ * idleslope increments.
+ *
+ * In i225 controller, the sendSlope and loCredit
+ * parameters from CBS are not configurable
+ * by software so we don't do any
+ * 'controller configuration' in respect to
+ * these parameters.
+ */
+ cbs_value = DIV_ROUND_UP_ULL(ring->idleslope
+ * 61036ULL, 2500000);
+
+ tqavcc = rd32(IGC_TQAVCC(i));
+ tqavcc &= ~IGC_TQAVCC_IDLESLOPE_MASK;
+ tqavcc |= cbs_value | IGC_TQAVCC_KEEP_CREDITS;
+ wr32(IGC_TQAVCC(i), tqavcc);
+
+ wr32(IGC_TQAVHC(i),
+ 0x80000000 + ring->hicredit * 0x7735);
+ } else {
+ /* Disable any CBS for the queue */
+ txqctl &= ~(IGC_TXQCTL_QAV_SEL_MASK);
+
+ /* Set idleSlope to zero. */
+ tqavcc = rd32(IGC_TQAVCC(i));
+ tqavcc &= ~(IGC_TQAVCC_IDLESLOPE_MASK |
+ IGC_TQAVCC_KEEP_CREDITS);
+ wr32(IGC_TQAVCC(i), tqavcc);
+
+ /* Set hiCredit to zero. */
+ wr32(IGC_TQAVHC(i), 0);
+ }
+skip_cbs:
wr32(IGC_TXQCTL(i), txqctl);
}
@@ -125,33 +227,41 @@ static int igc_tsn_enable_offload(struct igc_adapter *adapter)
wr32(IGC_BASET_H, baset_h);
wr32(IGC_BASET_L, baset_l);
- adapter->flags |= IGC_FLAG_TSN_QBV_ENABLED;
-
return 0;
}
-int igc_tsn_offload_apply(struct igc_adapter *adapter)
+int igc_tsn_reset(struct igc_adapter *adapter)
{
- bool is_any_enabled = adapter->base_time || is_any_launchtime(adapter);
+ unsigned int new_flags;
+ int err = 0;
- if (!(adapter->flags & IGC_FLAG_TSN_QBV_ENABLED) && !is_any_enabled)
- return 0;
+ new_flags = igc_tsn_new_flags(adapter);
- if (!is_any_enabled) {
- int err = igc_tsn_disable_offload(adapter);
+ if (!(new_flags & IGC_FLAG_TSN_ANY_ENABLED))
+ return igc_tsn_disable_offload(adapter);
- if (err < 0)
- return err;
+ err = igc_tsn_enable_offload(adapter);
+ if (err < 0)
+ return err;
- /* The BASET registers aren't cleared when writing
- * into them, force a reset if the interface is
- * running.
- */
- if (netif_running(adapter->netdev))
- schedule_work(&adapter->reset_task);
+ adapter->flags = new_flags;
+ return err;
+}
+
+int igc_tsn_offload_apply(struct igc_adapter *adapter)
+{
+ int err;
+
+ if (netif_running(adapter->netdev)) {
+ schedule_work(&adapter->reset_task);
return 0;
}
- return igc_tsn_enable_offload(adapter);
+ err = igc_tsn_enable_offload(adapter);
+ if (err < 0)
+ return err;
+
+ adapter->flags = igc_tsn_new_flags(adapter);
+ return 0;
}
diff --git a/drivers/net/ethernet/intel/igc/igc_tsn.h b/drivers/net/ethernet/intel/igc/igc_tsn.h
index f76bc86ddccd9..1512307f5a528 100644
--- a/drivers/net/ethernet/intel/igc/igc_tsn.h
+++ b/drivers/net/ethernet/intel/igc/igc_tsn.h
@@ -5,5 +5,6 @@
#define _IGC_TSN_H_
int igc_tsn_offload_apply(struct igc_adapter *adapter);
+int igc_tsn_reset(struct igc_adapter *adapter);
#endif /* _IGC_BASE_H */