diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igc/igc_main.c')
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_main.c | 110 |
1 files changed, 77 insertions, 33 deletions
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 686793c539f2..458e5eaa92e5 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -683,9 +683,9 @@ static void igc_configure_rx_ring(struct igc_adapter *adapter, wr32(IGC_SRRCTL(reg_idx), srrctl); - rxdctl |= IGC_RX_PTHRESH; - rxdctl |= IGC_RX_HTHRESH << 8; - rxdctl |= IGC_RX_WTHRESH << 16; + rxdctl |= IGC_RXDCTL_PTHRESH; + rxdctl |= IGC_RXDCTL_HTHRESH << 8; + rxdctl |= IGC_RXDCTL_WTHRESH << 16; /* initialize rx_buffer_info */ memset(ring->rx_buffer_info, 0, @@ -749,11 +749,9 @@ static void igc_configure_tx_ring(struct igc_adapter *adapter, wr32(IGC_TDH(reg_idx), 0); writel(0, ring->tail); - txdctl |= IGC_TX_PTHRESH; - txdctl |= IGC_TX_HTHRESH << 8; - txdctl |= IGC_TX_WTHRESH << 16; + txdctl |= IGC_TXDCTL_PTHRESH(8) | IGC_TXDCTL_HTHRESH(1) | + IGC_TXDCTL_WTHRESH(16) | IGC_TXDCTL_QUEUE_ENABLE; - txdctl |= IGC_TXDCTL_QUEUE_ENABLE; wr32(IGC_TXDCTL(reg_idx), txdctl); } @@ -1687,6 +1685,15 @@ done: first->tx_flags = tx_flags; first->protocol = protocol; + /* For preemptible queue, manually pad the skb so that HW includes + * padding bytes in mCRC calculation + */ + if (tx_ring->preemptible && skb->len < ETH_ZLEN) { + if (skb_padto(skb, ETH_ZLEN)) + goto out_drop; + skb_put(skb, ETH_ZLEN - skb->len); + } + tso = igc_tso(tx_ring, first, launch_time, first_flag, &hdr_len); if (tso < 0) goto out_drop; @@ -3867,6 +3874,22 @@ static void igc_del_flex_filter(struct igc_adapter *adapter, wr32(IGC_WUFC, wufc); } +static void igc_set_default_queue_filter(struct igc_adapter *adapter, u32 queue) +{ + struct igc_hw *hw = &adapter->hw; + u32 mrqc = rd32(IGC_MRQC); + + mrqc &= ~IGC_MRQC_DEFAULT_QUEUE_MASK; + mrqc |= FIELD_PREP(IGC_MRQC_DEFAULT_QUEUE_MASK, queue); + wr32(IGC_MRQC, mrqc); +} + +static void igc_reset_default_queue_filter(struct igc_adapter *adapter) +{ + /* Reset the default queue to its default value which is Queue 0 */ + igc_set_default_queue_filter(adapter, 0); +} + static int igc_enable_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule) { @@ -3905,6 +3928,9 @@ static int igc_enable_nfc_rule(struct igc_adapter *adapter, return err; } + if (rule->filter.match_flags & IGC_FILTER_FLAG_DEFAULT_QUEUE) + igc_set_default_queue_filter(adapter, rule->action); + return 0; } @@ -3932,6 +3958,9 @@ static void igc_disable_nfc_rule(struct igc_adapter *adapter, if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST, rule->filter.dst_addr); + + if (rule->filter.match_flags & IGC_FILTER_FLAG_DEFAULT_QUEUE) + igc_reset_default_queue_filter(adapter); } /** @@ -6296,24 +6325,6 @@ int igc_close(struct net_device *netdev) return 0; } -/** - * igc_ioctl - Access the hwtstamp interface - * @netdev: network interface device structure - * @ifr: interface request data - * @cmd: ioctl command - **/ -static int igc_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) -{ - switch (cmd) { - case SIOCGHWTSTAMP: - return igc_ptp_get_ts_config(netdev, ifr); - case SIOCSHWTSTAMP: - return igc_ptp_set_ts_config(netdev, ifr); - default: - return -EOPNOTSUPP; - } -} - static int igc_save_launchtime_params(struct igc_adapter *adapter, int queue, bool enable) { @@ -6423,6 +6434,7 @@ static int igc_qbv_clear_schedule(struct igc_adapter *adapter) ring->start_time = 0; ring->end_time = NSEC_PER_SEC; ring->max_sdu = 0; + ring->preemptible = false; } spin_lock_irqsave(&adapter->qbv_tx_lock, flags); @@ -6488,9 +6500,12 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter, if (!validate_schedule(adapter, qopt)) return -EINVAL; - /* preemptible isn't supported yet */ - if (qopt->mqprio.preemptible_tcs) - return -EOPNOTSUPP; + if (qopt->mqprio.preemptible_tcs && + !(adapter->flags & IGC_FLAG_TSN_REVERSE_TXQ_PRIO)) { + NL_SET_ERR_MSG_MOD(qopt->extack, + "reverse-tsn-txq-prio private flag must be enabled before setting preemptible tc"); + return -ENODEV; + } igc_ptp_read(adapter, &now); @@ -6583,6 +6598,8 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter, ring->max_sdu = 0; } + igc_fpe_save_preempt_queue(adapter, &qopt->mqprio); + return 0; } @@ -6702,7 +6719,8 @@ static int igc_tc_query_caps(struct igc_adapter *adapter, case TC_SETUP_QDISC_TAPRIO: { struct tc_taprio_caps *caps = base->caps; - caps->broken_mqprio = true; + if (!(adapter->flags & IGC_FLAG_TSN_REVERSE_TXQ_PRIO)) + caps->broken_mqprio = true; if (hw->mac.type == igc_i225) { caps->supports_queue_max_sdu = true; @@ -6728,6 +6746,20 @@ static void igc_save_mqprio_params(struct igc_adapter *adapter, u8 num_tc, adapter->queue_per_tc[i] = offset[i]; } +static bool +igc_tsn_is_tc_to_queue_priority_ordered(struct tc_mqprio_qopt_offload *mqprio) +{ + int num_tc = mqprio->qopt.num_tc; + int i; + + for (i = 1; i < num_tc; i++) { + if (mqprio->qopt.offset[i - 1] > mqprio->qopt.offset[i]) + return false; + } + + return true; +} + static int igc_tsn_enable_mqprio(struct igc_adapter *adapter, struct tc_mqprio_qopt_offload *mqprio) { @@ -6739,6 +6771,7 @@ static int igc_tsn_enable_mqprio(struct igc_adapter *adapter, if (!mqprio->qopt.num_tc) { adapter->strict_priority_enable = false; + igc_fpe_clear_preempt_queue(adapter); netdev_reset_tc(adapter->netdev); goto apply; } @@ -6760,10 +6793,9 @@ static int igc_tsn_enable_mqprio(struct igc_adapter *adapter, } } - /* Preemption is not supported yet. */ - if (mqprio->preemptible_tcs) { + if (!igc_tsn_is_tc_to_queue_priority_ordered(mqprio)) { NL_SET_ERR_MSG_MOD(mqprio->extack, - "Preemption is not supported yet"); + "tc to queue mapping must preserve increasing priority (higher tc -> higher queue)"); return -EOPNOTSUPP; } @@ -6786,6 +6818,7 @@ static int igc_tsn_enable_mqprio(struct igc_adapter *adapter, adapter->queue_per_tc[i] = i; mqprio->qopt.hw = TC_MQPRIO_HW_OFFLOAD_TCS; + igc_fpe_save_preempt_queue(adapter, mqprio); apply: return igc_tsn_offload_apply(adapter); @@ -6942,12 +6975,13 @@ static const struct net_device_ops igc_netdev_ops = { .ndo_fix_features = igc_fix_features, .ndo_set_features = igc_set_features, .ndo_features_check = igc_features_check, - .ndo_eth_ioctl = igc_ioctl, .ndo_setup_tc = igc_setup_tc, .ndo_bpf = igc_bpf, .ndo_xdp_xmit = igc_xdp_xmit, .ndo_xsk_wakeup = igc_xsk_wakeup, .ndo_get_tstamp = igc_get_tstamp, + .ndo_hwtstamp_get = igc_ptp_hwtstamp_get, + .ndo_hwtstamp_set = igc_ptp_hwtstamp_set, }; u32 igc_rd32(struct igc_hw *hw, u32 reg) @@ -7115,6 +7149,10 @@ static int igc_probe(struct pci_dev *pdev, adapter->port_num = hw->bus.func; adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); + /* Disable ASPM L1.2 on I226 devices to avoid packet loss */ + if (igc_is_device_id_i226(hw)) + pci_disable_link_state(pdev, PCIE_LINK_STATE_L1_2); + err = pci_save_state(pdev); if (err) goto err_ioremap; @@ -7500,6 +7538,9 @@ static int __igc_resume(struct device *dev, bool rpm) pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); + if (igc_is_device_id_i226(hw)) + pci_disable_link_state(pdev, PCIE_LINK_STATE_L1_2); + if (igc_init_interrupt_scheme(adapter, true)) { netdev_err(netdev, "Unable to allocate memory for queues\n"); return -ENOMEM; @@ -7625,6 +7666,9 @@ static pci_ers_result_t igc_io_slot_reset(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); + if (igc_is_device_id_i226(hw)) + pci_disable_link_state_locked(pdev, PCIE_LINK_STATE_L1_2); + /* In case of PCI error, adapter loses its HW address * so we should re-assign it here. */ |