mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 00:21:59 +00:00
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>
This commit is contained in:
commit
d65a606b90
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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_reset(struct igc_adapter *adapter)
|
||||
{
|
||||
unsigned int new_flags;
|
||||
int err = 0;
|
||||
|
||||
new_flags = igc_tsn_new_flags(adapter);
|
||||
|
||||
if (!(new_flags & IGC_FLAG_TSN_ANY_ENABLED))
|
||||
return igc_tsn_disable_offload(adapter);
|
||||
|
||||
err = igc_tsn_enable_offload(adapter);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
adapter->flags = new_flags;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int igc_tsn_offload_apply(struct igc_adapter *adapter)
|
||||
{
|
||||
bool is_any_enabled = adapter->base_time || is_any_launchtime(adapter);
|
||||
|
||||
if (!(adapter->flags & IGC_FLAG_TSN_QBV_ENABLED) && !is_any_enabled)
|
||||
return 0;
|
||||
|
||||
if (!is_any_enabled) {
|
||||
int err = igc_tsn_disable_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);
|
||||
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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user