Nothing too exciting, usual stream of fixes.

Including fixes from Netfilter, Bluetooth and WPAN.
 
 Current release - new code bugs:
 
  - Bluetooth: hci_sync: fix not setting CE length properly
 
  - eth: enic: match mailbox replies to request numbers
 
 Previous releases - regressions:
 
  - tunnels: drop stale dst when building an ICMP error for PMTUD
 
  - ipv6: null-check fib6_node before accessing in __ip6_del_rt_siblings()
    (bug in the rtnl_lock -> RCU conversion)
 
  - eth: bnxt_en: fix crashes on Thor2 due to OOB coalescing buffer accesses
 
  - eth: bnxt_en: prevent queue stop with deferred completions
 
 Previous releases - always broken:
 
  - eth: ice: don't dereference pointers from TP_printk()
 
  - eth: fix OOB writes on ethtool flow rule dump in 3 drivers
 
  - eth: mlx5: fix FEC configuration with RS_544_514_INTERLEAVED_QUAD
 
  - dsa: tag_brcm: legacy FCS: request needed tailroom
 
 Misc:
 
  - net: cap tx_queue_len at S16_MAX to prevent oversized ring alloc
 
  - ipv6: flowlabel: cap duplicate leases per socket
 
 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmqi3pQACgkQMUZtbf5S
 IrvUIg//X9nIxY2F5PzJ5jD9p5ccXrQMLe7kT5AW2tP5PDC8d5PIv4Q5XzFKQPU7
 XElAUKvBxmofwU2lqILYGi8AeUpqHZtKPY7XzKeqd6i72KOD6mGzzYNijqttBXcM
 vFVtIeKExXjAwvNc2as1SeXVEAAAkBtrCFuMNHMq0C56yK4md/XVkCDHaJkomNit
 geke1U8gut3rZddWKxp4WDbL8Wmx9yM0uDMBznO/+cwITObA0Hme3IgRndglzz7n
 n4Ih+EG4tRrD3kUf6oePzKQ47cd+qnSVlVTCZUwB5E/HKqWJFXxSN4Sv+mez0sAS
 rrI5hl+luNKUYrZ8/jiNlvajgAL4+AYpCKPDJbXrOW+z+x4BC2VYZBAHLoUr5ZAq
 Z5OYU9SgD1oGntqkI8mAEiRTEu+4gjhIEhjENHEzqdjUogaBIp7MWwCrNBAnFWvs
 2McmNfZZMVhxKpyYnndUStsVQySVPASb0CXeqTIO6PJsAp/HBjoMYKYKPhhwk0Gp
 lE8zHjEnPVofRfXfT+oZnbS8is2nC9FjBy9ksIGcC7vyTOdPsoIBoB8JY0x/INRM
 SOJvyxrdnVkMjiBejkdOa5X9HbD1cA/NVyzT2WEaZBGPmIqfNBgUIOxnXD4CShuy
 9zX8qtHsUmmYxPteF30Uhfe0kyLQ9OnjUz2Bl++EruxpIE3+i48=
 =f9J9
 -----END PGP SIGNATURE-----

Merge tag 'net-7.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Pull networking fixes from Jakub Kicinski:
 "Nothing too exciting, usual stream of fixes. Including fixes from
  Netfilter, Bluetooth and WPAN.

  Current release - new code bugs:

   - Bluetooth: hci_sync: fix not setting CE length properly

   - eth: enic: match mailbox replies to request numbers

  Previous releases - regressions:

   - tunnels: drop stale dst when building an ICMP error for PMTUD

   - ipv6: null-check fib6_node before accessing in __ip6_del_rt_siblings()
     (bug in the rtnl_lock -> RCU conversion)

   - eth: bnxt_en:
       - fix crashes on Thor2 due to OOB coalescing buffer accesses
       - prevent queue stop with deferred completions

  Previous releases - always broken:

   - eth:
       - ice: don't dereference pointers from TP_printk()
       - fix OOB writes on ethtool flow rule dump in 3 drivers
       - mlx5: fix FEC configuration with RS_544_514_INTERLEAVED_QUAD

   - dsa: tag_brcm: legacy FCS: request needed tailroom

  Misc:

   - net: cap tx_queue_len at S16_MAX to prevent oversized ring alloc

   - ipv6: flowlabel: cap duplicate leases per socket"

* tag 'net-7.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (164 commits)
  selftests: tc-testing: test action batch failure cleanup
  net/sched: act_api: release all action references on NEWACTION failure
  openvswitch: fix wrong flag value in get_ipv6_ext_hdrs()
  ipmr: account multicast table and route memory
  net: phy: dp83td510: handle the active-high LED polarity mode
  net: macb: initialize PTP state before registering clock
  net: hsr: enable promiscuous mode on interlink port with fwd offload
  ipv6: fix fib6 walker UAF on seq stop
  net: stmmac: fix TX descriptor availability check for TSO traffic
  net/rds: fix tcp stream corruption with large pages
  net: mana: restore the XDP program pointer when pre-allocation fails
  net: phy: dp83867: handle the active-high LED polarity mode
  octeontx2-af: fix PF/CGX debugfs PCI bus lookup
  net: net_failover: Fix the deadlock in net_failover_slave_name_change()
  net: phy: mediatek-ge: disable EEE on the MT7530 PHY
  tcp: reject non zerocopy devmem tx
  net: ethernet: mtk_eth_soc: populate lpi_interfaces to fix EEE support
  net: dsa: mt7530: populate lpi_interfaces to fix EEE support
  net: hinic: fix mailbox segment buffer overflow
  net: sun4i-emac: fix missing of_node_put() for phy_node
  ...
This commit is contained in:
Linus Torvalds 2026-09-10 14:07:48 -07:00
commit 7844502343
165 changed files with 2378 additions and 1232 deletions

View File

@ -551,6 +551,9 @@ Li Yang <leoyang.li@nxp.com> <leo@zh-kernel.org>
Lior David <quic_liord@quicinc.com> <liord@codeaurora.org>
Loic Poulain <loic.poulain@oss.qualcomm.com> <loic.poulain@linaro.org>
Loic Poulain <loic.poulain@oss.qualcomm.com> <loic.poulain@intel.com>
Lorenzo Bianconi <lorenzo@kernel.org> <lorenzo.bianconi@redhat.com>
Lorenzo Bianconi <lorenzo@kernel.org> <lorenzo.bianconi@st.com>
Lorenzo Bianconi <lorenzo@kernel.org> <lorenzo.bianconi83@gmail.com>
Lorenzo Pieralisi <lpieralisi@kernel.org> <lorenzo.pieralisi@arm.com>
Lorenzo Stoakes <ljs@kernel.org> <lstoakes@gmail.com>
Lorenzo Stoakes <ljs@kernel.org> <lorenzo.stoakes@oracle.com>

View File

@ -898,6 +898,8 @@ attribute-sets:
-
name: txqlen
type: u32
checks:
max: 32767
-
name: map
type: binary

View File

@ -25336,8 +25336,8 @@ F: Documentation/networking/timestamping.rst
F: include/linux/net_tstamp.h
F: include/uapi/linux/net_tstamp.h
F: tools/testing/selftests/bpf/*/net_timestamping*
F: tools/testing/selftests/drivers/net/so_txtime.*
F: tools/testing/selftests/net/*timestamp*
F: tools/testing/selftests/net/so_txtime.c
SOEKRIS NET48XX LED SUPPORT
M: Chris Boot <bootc@bootc.net>

View File

@ -1099,7 +1099,7 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data)
urbd0 = &txq->urbd0s[cr_tia];
if (urbd0->tfd_index > txq->count)
if (urbd0->tfd_index >= txq->count)
return;
cr_tia = (cr_tia + 1) % txq->count;
@ -1599,7 +1599,9 @@ static int btintel_pcie_submit_rx_work(struct btintel_pcie_data *data, u8 status
rfh_hdr = buf;
len = rfh_hdr->packet_len;
if (len <= 0) {
if (len == 0 || len > BTINTEL_PCIE_BUFFER_SIZE - sizeof(*rfh_hdr)) {
bt_dev_err(data->hdev, "Invalid packet_len %d (max %zu)", len,
BTINTEL_PCIE_BUFFER_SIZE - sizeof(*rfh_hdr));
ret = -EINVAL;
goto resubmit;
}

View File

@ -1374,16 +1374,6 @@ int btmtk_usb_setup(struct hci_dev *hdev)
break;
case 0x7922:
case 0x7925:
/*
* A remote wakeup could cause the device completely unresponsive, and
* recovering from such a state needs a power cycle.
*
* Since the remote wakeup capability is super broken, just disable it
* to get rid of the troubles. The device can still be autosuspended
* when the bluetooth interface is closed.
*/
device_set_wakeup_capable(&btmtk_data->udev->dev, false);
fallthrough;
case 0x7961:
case 0x7902:
case 0x6639:
@ -1587,5 +1577,6 @@ MODULE_FIRMWARE(FIRMWARE_MT7663);
MODULE_FIRMWARE(FIRMWARE_MT7668);
MODULE_FIRMWARE(FIRMWARE_MT7922);
MODULE_FIRMWARE(FIRMWARE_MT7961);
MODULE_FIRMWARE(FIRMWARE_MT7920);
MODULE_FIRMWARE(FIRMWARE_MT7925);
MODULE_FIRMWARE(FIRMWARE_MT7927);

View File

@ -7,6 +7,7 @@
#define FIRMWARE_MT7922 "mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin"
#define FIRMWARE_MT7902 "mediatek/BT_RAM_CODE_MT7902_1_1_hdr.bin"
#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
#define FIRMWARE_MT7920 "mediatek/BT_RAM_CODE_MT7961_1a_2_hdr.bin"
#define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"
#define FIRMWARE_MT7927 "mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin"

View File

@ -188,7 +188,10 @@ static int btqcomsmd_probe(struct platform_device *pdev)
return 0;
hci_free_dev:
rpmsg_destroy_ept(btq->cmd_channel);
rpmsg_destroy_ept(btq->acl_channel);
hci_free_dev(hdev);
return ret;
destroy_cmd_channel:
rpmsg_destroy_ept(btq->cmd_channel);
destroy_acl_channel:
@ -202,10 +205,11 @@ static void btqcomsmd_remove(struct platform_device *pdev)
struct btqcomsmd *btq = platform_get_drvdata(pdev);
hci_unregister_dev(btq->hdev);
hci_free_dev(btq->hdev);
rpmsg_destroy_ept(btq->cmd_channel);
rpmsg_destroy_ept(btq->acl_channel);
hci_free_dev(btq->hdev);
}
static const struct of_device_id btqcomsmd_of_match[] = {

View File

@ -591,7 +591,7 @@ static int rtlbt_parse_firmware_v2(struct hci_dev *hdev,
* headers.
*/
if (!key_id)
break;
continue;
rc = btrtl_parse_section(hdev, btrtl_dev, opcode,
ptr, section_len);
break;
@ -600,8 +600,7 @@ static int rtlbt_parse_firmware_v2(struct hci_dev *hdev,
ptr, section_len);
break;
default:
rc = 0;
break;
continue;
}
if (rc < 0) {
rtl_dev_err(hdev, "RTL: Parse section (%u) err %d",

View File

@ -6,6 +6,7 @@
* Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
*/
#include <linux/cpufeature.h>
#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/usb.h>
@ -980,6 +981,8 @@ struct btqca_data {
#define BTUSB_USE_ALT3_FOR_WBS 15
#define BTUSB_ALT6_CONTINUOUS_TX 16
#define BTUSB_HW_SSR_ACTIVE 17
#define BTUSB_WAKEUP_BROKEN 18
#define BTUSB_RESET 19
struct btusb_data {
struct hci_dev *hdev;
@ -1054,13 +1057,15 @@ static void btusb_reset(struct hci_dev *hdev)
int err;
data = hci_get_drvdata(hdev);
/* This is not an unbalanced PM reference since the device will reset */
err = usb_autopm_get_interface(data->intf);
if (err) {
bt_dev_err(hdev, "Failed usb_autopm_get_interface: %d", err);
return;
}
if (test_and_set_bit(BTUSB_RESET, &data->flags))
usb_autopm_put_interface_no_suspend(data->intf);
bt_dev_err(hdev, "Resetting usb device.");
usb_queue_reset_device(data->intf);
}
@ -2092,18 +2097,24 @@ static int btusb_close(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
cancel_delayed_work(&data->rx_work);
cancel_work_sync(&data->work);
cancel_work_sync(&data->waker);
skb_queue_purge(&data->acl_q);
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
clear_bit(BTUSB_BULK_RUNNING, &data->flags);
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
clear_bit(BTUSB_DIAG_RUNNING, &data->flags);
btusb_stop_traffic(data);
/* rx_work must only be canceled once the URBs that can rearm it are
* gone, and it must be canceled synchronously since btusb_disconnect()
* frees the btusb_data it dereferences right after hci_unregister_dev().
*/
cancel_delayed_work_sync(&data->rx_work);
skb_queue_purge(&data->acl_q);
btusb_free_frags(data);
err = usb_autopm_get_interface(data->intf);
@ -2129,7 +2140,7 @@ static int btusb_flush(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
cancel_delayed_work(&data->rx_work);
cancel_delayed_work_sync(&data->rx_work);
skb_queue_purge(&data->acl_q);
@ -2923,8 +2934,11 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
}
err = usb_autopm_get_interface(data->intf);
if (err < 0)
if (err < 0) {
bt_dev_err(hdev, "Failed usb_autopm_get_interface: %d", err);
clear_bit(BTMTK_HW_RESET_ACTIVE, &btmtk_data->flags);
return err;
}
/* Release MediaTek ISO data interface */
btusb_mtk_release_iso_intf(hdev);
@ -2946,6 +2960,11 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
err = btmtk_usb_subsys_reset(hdev, btmtk_data->dev_id);
if (test_and_set_bit(BTUSB_RESET, &data->flags)) {
bt_dev_err(hdev, "last usb reset failed? Resetting again");
usb_autopm_put_interface_no_suspend(data->intf);
}
usb_queue_reset_device(data->intf);
clear_bit(BTMTK_HW_RESET_ACTIVE, &btmtk_data->flags);
@ -2969,10 +2988,25 @@ static int btusb_send_frame_mtk(struct hci_dev *hdev, struct sk_buff *skb)
}
}
static inline bool platform_is_ryzen(void)
{
#ifdef CONFIG_X86
return boot_cpu_has(X86_FEATURE_ZEN);
#else
return false;
#endif
}
static inline bool is_direct_child_of_root_hub(struct usb_device *udev)
{
return udev->parent == udev->bus->root_hub;
}
static int btusb_mtk_setup(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
int err;
/* MediaTek WMT vendor cmd requiring below USB resources to
* complete the handshake.
@ -2989,7 +3023,40 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
btusb_mtk_claim_iso_intf(data);
}
return btmtk_usb_setup(hdev);
err = btmtk_usb_setup(hdev);
if (err)
return err;
switch (btmtk_data->dev_id) {
case 0x7922:
case 0x7925:
/*
* All reports seen to be relevant to Ryzen-based laptops. These
* NICs are usually used as OEM components thanks to some sort
* of reference designs.
*
* Their popularity on other platforms is unclear. While there
* is still a chance that the quirk may exist on other
* platforms, be cautious and only apply the quirk to direct
* children of Ryzen platforms's root hubs for the time being.
*
* In most cases the root hub is on the SoC or PCH, which needs
* the quirk. Unfortunately, this can't distinguish root hubs on
* PCIe add-in cards. Such roughness should be acceptable, as
* PCIe USB controller add-in cards are less commonly used
* nowadays. On the other hand, applying the quirk doesn't hurt
* any functionalities either, as the device can still be used
* as a wakeup source if desired.
*
* Theoretically, we could retrieve the root hub's PCI vendor ID
* with some hierarchy magic, but that's too intrusive...
*/
if (platform_is_ryzen() && is_direct_child_of_root_hub(data->udev))
set_bit(BTUSB_WAKEUP_BROKEN, &data->flags);
break;
}
return 0;
}
static int btusb_mtk_shutdown(struct hci_dev *hdev)
@ -4540,6 +4607,9 @@ static void btusb_disconnect(struct usb_interface *intf)
if (data->reset_gpio)
gpiod_put(data->reset_gpio);
if (test_and_clear_bit(BTUSB_RESET, &data->flags))
usb_autopm_put_interface_no_suspend(data->intf);
if (intf == data->intf) {
if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc);
@ -4565,11 +4635,26 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
BT_DBG("intf %p", intf);
/* Don't auto-suspend if there are connections or discovery in
* progress; external suspend calls shall never fail.
/*
* It is reported that remote wakeup events could sometimes cause some
* adapters completely unresponsive. Resetting the xHCI root hub doesn't
* help at all, and recovering from such a state needs a power cycle.
* Since disabling remote wakeup simply causes the USB core to gate
* runtime autosuspend as well due to needs_remote_wakeup == 1, let's do
* this ourselves to make our life easier. The interface can be safely
* autosuspended as long as remote wakeup is disabled, i.e., after
* closing the HCI device.
*
* Don't auto-suspend if there are connections or discovery in progress.
*
* External suspend calls shall never fail. Specifically, a device with
* broken remote wakeup may still take the advantage of remote wakeup in
* order to wake up the system from sleep if userspace has enabled it as
* a wakeup source.
*/
if (PMSG_IS_AUTO(message) &&
(hci_conn_count(data->hdev) || hci_discovery_active(data->hdev)))
((test_bit(BTUSB_WAKEUP_BROKEN, &data->flags) && data->intf->needs_remote_wakeup) ||
hci_conn_count(data->hdev) || hci_discovery_active(data->hdev)))
return -EBUSY;
if (data->suspend_count++)

View File

@ -251,13 +251,19 @@ static int __init dibs_init(void)
rc = class_register(&dibs_class);
if (rc)
return rc;
goto err;
rc = dibs_loopback_init();
if (rc)
pr_err("%s fails with %d\n", __func__, rc);
goto err_unregister;
return rc;
err_unregister:
class_unregister(&dibs_class);
err:
pr_err("%s fails with %d\n", __func__, rc);
return rc;
}
static void __exit dibs_exit(void)

View File

@ -678,9 +678,15 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
if (arp->op_code == htons(ARPOP_REPLY)) {
/* the arp must be sent on the selected rx channel */
tx_slave = rlb_choose_channel(skb, bond, arp);
if (tx_slave)
if (tx_slave &&
!ether_addr_equal_64bits(arp->mac_src,
tx_slave->dev->dev_addr)) {
if (unlikely(skb_cow_head(skb, 0)))
return NULL;
arp = (struct arp_pkt *)skb_network_header(skb);
bond_hw_addr_copy(arp->mac_src, tx_slave->dev->dev_addr,
tx_slave->dev->addr_len);
}
netdev_dbg(bond->dev, "(slave %s): Server sent ARP Reply packet\n",
tx_slave ? tx_slave->dev->name : "NULL");
} else if (arp->op_code == htons(ARPOP_REQUEST)) {
@ -1340,7 +1346,6 @@ static netdev_tx_t bond_do_alb_xmit(struct sk_buff *skb, struct bonding *bond,
struct slave *tx_slave)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct ethhdr *eth_data = eth_hdr(skb);
if (!tx_slave) {
/* unbalanced or unassigned, send through primary */
@ -1351,7 +1356,9 @@ static netdev_tx_t bond_do_alb_xmit(struct sk_buff *skb, struct bonding *bond,
if (tx_slave && bond_slave_can_tx(tx_slave)) {
if (tx_slave != rcu_access_pointer(bond->curr_active_slave)) {
ether_addr_copy(eth_data->h_source,
if (unlikely(skb_cow_head(skb, 0)))
return bond_tx_drop(bond->dev, skb);
ether_addr_copy(skb_eth_hdr(skb)->h_source,
tx_slave->dev->dev_addr);
}
@ -1375,8 +1382,7 @@ struct slave *bond_xmit_tlb_slave_get(struct bonding *bond,
struct ethhdr *eth_data;
u32 hash_index;
skb_reset_mac_header(skb);
eth_data = eth_hdr(skb);
eth_data = skb_eth_hdr(skb);
/* Do not TX balance any multicast or broadcast */
if (!is_multicast_ether_addr(eth_data->h_dest)) {
@ -1428,8 +1434,7 @@ struct slave *bond_xmit_alb_slave_get(struct bonding *bond,
u32 hash_index = 0;
int hash_size = 0;
skb_reset_mac_header(skb);
eth_data = eth_hdr(skb);
eth_data = skb_eth_hdr(skb);
switch (ntohs(skb->protocol)) {
case ETH_P_IP: {

View File

@ -1088,6 +1088,8 @@ static int bcm_sf2_cfp_rule_get_all(struct bcm_sf2_priv *priv,
unsigned int index = 1, rules_cnt = 0;
for_each_set_bit_from(index, priv->cfp.unique, priv->num_cfp_rules) {
if (rules_cnt == nfc->rule_cnt)
return -EMSGSIZE;
rule_locs[rules_cnt] = index;
rules_cnt++;
}

View File

@ -42,7 +42,7 @@
#define GSWIP_MDIO_PHY_FDUP_DIS 0x0600
#define GSWIP_MDIO_PHY_FCONTX_MASK 0x0180
#define GSWIP_MDIO_PHY_FCONTX_AUTO 0x0000
#define GSWIP_MDIO_PHY_FCONTX_EN 0x0100
#define GSWIP_MDIO_PHY_FCONTX_EN 0x0080
#define GSWIP_MDIO_PHY_FCONTX_DIS 0x0180
#define GSWIP_MDIO_PHY_FCONRX_MASK 0x0060
#define GSWIP_MDIO_PHY_FCONRX_AUTO 0x0000

View File

@ -3172,23 +3172,31 @@ static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE;
priv->info->mac_port_get_caps(ds, port, config);
/* The EN7528 GPHYs report EEE capability, but negotiating EEE with
* common link partners (e.g. Realtek GbE NICs) results in an unstable
* link with dropped frames. Leave the LPI capabilities empty so that
* phylink disables EEE on these PHYs and refuses to enable it from
* userspace.
*/
if (priv->id != ID_EN7528) {
if (priv->id != ID_EN7528 &&
config->mac_capabilities & (MAC_100FD | MAC_1000FD)) {
u32 eeecr = mt7530_read(priv, MT753X_PMEEECR_P(port));
config->lpi_capabilities = MAC_100FD | MAC_1000FD | MAC_2500FD;
/* LPI above 1 Gbps is not supported */
config->lpi_capabilities = config->mac_capabilities &
(MAC_100FD | MAC_1000FD);
phy_interface_copy(config->lpi_interfaces,
config->supported_interfaces);
__clear_bit(PHY_INTERFACE_MODE_2500BASEX,
config->lpi_interfaces);
/* tx_lpi_timer should be in microseconds. The time units for
* LPI threshold are unspecified.
*/
config->lpi_timer_default = FIELD_GET(LPI_THRESH_MASK, eeecr);
}
priv->info->mac_port_get_caps(ds, port, config);
}
static int mt753x_pcs_validate(struct phylink_pcs *pcs,

View File

@ -2438,6 +2438,7 @@ static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,
struct ethtool_rx_flow_spec *fs = &rxnfc->fs;
struct mv88e6xxx_chip *chip = ds->priv;
struct mv88e6xxx_policy *policy;
u32 cnt = 0;
int err;
int id;
@ -2463,11 +2464,18 @@ static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,
break;
case ETHTOOL_GRXCLSRLALL:
rxnfc->data = 0;
rxnfc->rule_cnt = 0;
idr_for_each_entry(&chip->policies, policy, id)
if (policy->port == port)
rule_locs[rxnfc->rule_cnt++] = id;
err = 0;
idr_for_each_entry(&chip->policies, policy, id) {
if (policy->port != port)
continue;
if (cnt == rxnfc->rule_cnt) {
err = -EMSGSIZE;
break;
}
rule_locs[cnt++] = id;
}
if (!err)
rxnfc->rule_cnt = cnt;
break;
default:
err = -EOPNOTSUPP;

View File

@ -1067,6 +1067,7 @@ static int emac_probe(struct platform_device *pdev)
return 0;
out_release_sram:
of_node_put(db->phy_node);
sunxi_sram_release(&pdev->dev);
out_clk_disable_unprepare:
clk_disable_unprepare(db->clk);
@ -1094,6 +1095,7 @@ static void emac_remove(struct platform_device *pdev)
}
unregister_netdev(ndev);
of_node_put(db->phy_node);
sunxi_sram_release(&pdev->dev);
clk_disable_unprepare(db->clk);
irq_dispose_mapping(ndev->irq);

View File

@ -171,8 +171,10 @@ pdsc_legacy_firmware_update(struct pdsc *pdsc,
dev_info(pdsc->dev, "Installing firmware\n");
if (!pdsc->cmd_regs)
if (!pdsc->cmd_regs) {
NL_SET_ERR_MSG_MOD(extack, "BARs not mapped");
return -ENXIO;
}
dl = priv_to_devlink(pdsc);
devlink_flash_update_status_notify(dl, "Preparing to flash",
@ -198,6 +200,12 @@ pdsc_legacy_firmware_update(struct pdsc *pdsc,
copy_sz = min_t(unsigned int, buf_sz, fw->size - offset);
mutex_lock(&pdsc->devcmd_lock);
if (!pdsc->cmd_regs) {
mutex_unlock(&pdsc->devcmd_lock);
err = -ENXIO;
NL_SET_ERR_MSG_MOD(extack, "Device reset during flash");
goto err_out;
}
memcpy_toio(&pdsc->cmd_regs->data, fw->data + offset, copy_sz);
err = pdsc_devcmd_fw_download_locked(pdsc, data_addr,
offset, copy_sz);

View File

@ -513,8 +513,12 @@ static void pdsc_reset_prepare(struct pci_dev *pdev)
pdsc_auxbus_dev_del(pdsc, pdsc, &pdsc->padev);
}
pdsc_unmap_bars(pdsc);
pci_release_regions(pdev);
if (!pdev->is_virtfn) {
mutex_lock(&pdsc->devcmd_lock);
pdsc_unmap_bars(pdsc);
mutex_unlock(&pdsc->devcmd_lock);
pci_release_regions(pdev);
}
if (pci_is_enabled(pdev))
pci_disable_device(pdev);
pdsc_deferred_dma_free(pdsc);
@ -543,7 +547,9 @@ static void pdsc_reset_done(struct pci_dev *pdev)
return;
}
mutex_lock(&pdsc->devcmd_lock);
err = pdsc_map_bars(pdsc);
mutex_unlock(&pdsc->devcmd_lock);
if (err)
return;
}

View File

@ -148,8 +148,9 @@ static int tx_spb_ring_full(struct bcmasp_intf *intf, int cnt)
int next_index, i;
/* Check if we have enough room for cnt descriptors */
next_index = intf->tx_spb_index;
for (i = 0; i < cnt; i++) {
next_index = incr_ring(intf->tx_spb_index, DESC_RING_COUNT);
next_index = incr_ring(next_index, DESC_RING_COUNT);
if (next_index == intf->tx_spb_clean_index)
return 1;
}
@ -301,6 +302,7 @@ static netdev_tx_t bcmasp_xmit(struct sk_buff *skb, struct net_device *dev)
txcb->bytes_sent = total_bytes;
dma_unmap_addr_set(txcb, dma_addr, mapping);
dma_unmap_len_set(txcb, dma_len, size);
txcb->last = false;
if (!i) {
desc->flags |= DESC_SOF;
if (csum_hw)

View File

@ -462,6 +462,16 @@ u16 bnxt_xmit_get_cfa_action(struct sk_buff *skb)
static void bnxt_txr_db_kick(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
u16 prod)
{
/* If the most recent BD has its completion suppressed, unset the bit
* so that a completion is generated, otherwise nothing is left to
* clean the ring and wake the queue.
*/
if (txr->kick_txbd0) {
txr->kick_txbd0->tx_bd_len_flags_type &=
cpu_to_le32(~TX_BD_FLAGS_NO_CMPL);
txr->kick_txbd0 = NULL;
}
/* Sync BD data before updating doorbell */
wmb();
bnxt_db_write(bp, &txr->tx_db, prod);
@ -485,7 +495,6 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct bnxt_sw_tx_bd *tx_buf;
__le32 lflags = 0;
skb_frag_t *frag;
netdev_tx_t ret;
i = skb_get_queue_mapping(skb);
if (unlikely(i >= bp->tx_nr_rings)) {
@ -509,11 +518,22 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb_is_gso(skb) &&
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) &&
!(bp->flags & BNXT_FLAG_UDP_GSO_CAP)) {
ret = bnxt_sw_udp_gso_xmit(bp, txr, txq, skb);
if (txr->kick_pending)
int rc = bnxt_sw_udp_gso_xmit(bp, txr, txq, skb);
/* if SW USO queued a packet, the doorbell will be written
* below and there is no reason to track the last BD with
* suppressed completions
*/
if (rc > 0)
txr->kick_txbd0 = NULL;
/* if a packet was queued by SW USO or a doorbell was pending
* from a previous xmit that was deferred, write the doorbell.
*/
if (rc > 0 || txr->kick_pending)
bnxt_txr_db_kick(bp, txr, txr->tx_prod);
return ret;
return rc < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK;
}
free_size = bnxt_tx_avail(bp, txr);
@ -751,23 +771,23 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
prod = NEXT_TX(prod);
WRITE_ONCE(txr->tx_prod, prod);
txr->kick_txbd0 = NULL;
if (!netdev_xmit_more() || netif_xmit_stopped(txq)) {
bnxt_txr_db_kick(bp, txr, prod);
} else {
if (free_size >= bp->tx_wake_thresh)
if (free_size >= bp->tx_wake_thresh) {
txbd0->tx_bd_len_flags_type |=
cpu_to_le32(TX_BD_FLAGS_NO_CMPL);
txr->kick_txbd0 = txbd0;
}
txr->kick_pending = 1;
}
tx_done:
if (unlikely(bnxt_tx_avail(bp, txr) <= MAX_SKB_FRAGS + 1)) {
if (netdev_xmit_more() && !tx_buf->is_push) {
txbd0->tx_bd_len_flags_type &=
cpu_to_le32(~TX_BD_FLAGS_NO_CMPL);
if (txr->kick_pending)
bnxt_txr_db_kick(bp, txr, prod);
}
netif_txq_try_stop(txq, bnxt_tx_avail(bp, txr),
bp->tx_wake_thresh);
@ -1514,14 +1534,16 @@ static int bnxt_discard_rx(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
return 0;
}
static u16 bnxt_alloc_agg_idx(struct bnxt_rx_ring_info *rxr, u16 agg_id)
static u16 bnxt_alloc_agg_idx(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
u16 agg_id)
{
struct bnxt_tpa_idx_map *map = rxr->rx_tpa_idx_map;
u16 idx = agg_id & MAX_TPA_P5_MASK;
u16 idx = agg_id & (bp->max_tpa_roundup_size - 1);
if (test_bit(idx, map->agg_idx_bmap)) {
idx = find_first_zero_bit(map->agg_idx_bmap, MAX_TPA_P5);
if (idx >= MAX_TPA_P5)
idx = find_first_zero_bit(map->agg_idx_bmap,
bp->max_tpa_roundup_size);
if (idx >= bp->max_tpa_roundup_size)
return INVALID_HW_RING_ID;
}
__set_bit(idx, map->agg_idx_bmap);
@ -1586,7 +1608,7 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
agg_id = TPA_START_AGG_ID_P5(tpa_start);
agg_id = bnxt_alloc_agg_idx(rxr, agg_id);
agg_id = bnxt_alloc_agg_idx(bp, rxr, agg_id);
if (unlikely(agg_id == INVALID_HW_RING_ID)) {
netdev_warn(bp->dev, "Unable to allocate agg ID for ring %d, agg 0x%x\n",
rxr->bnapi->index,
@ -3584,7 +3606,7 @@ static void bnxt_free_one_tpa_info_data(struct bnxt *bp,
{
int i;
for (i = 0; i < bp->max_tpa; i++) {
for (i = 0; i < bp->max_tpa_roundup_size; i++) {
struct bnxt_tpa_info *tpa_info = &rxr->rx_tpa[i];
u8 *data = tpa_info->data;
@ -3781,7 +3803,7 @@ static void bnxt_free_one_tpa_info(struct bnxt *bp,
kfree(rxr->rx_tpa_idx_map);
rxr->rx_tpa_idx_map = NULL;
if (rxr->rx_tpa) {
for (i = 0; i < bp->max_tpa; i++) {
for (i = 0; i < bp->max_tpa_roundup_size; i++) {
kfree(rxr->rx_tpa[i].agg_arr);
rxr->rx_tpa[i].agg_arr = NULL;
}
@ -3807,13 +3829,14 @@ static int bnxt_alloc_one_tpa_info(struct bnxt *bp,
struct rx_agg_cmp *agg;
int i;
rxr->rx_tpa = kzalloc_objs(struct bnxt_tpa_info, bp->max_tpa);
rxr->rx_tpa = kzalloc_objs(struct bnxt_tpa_info,
bp->max_tpa_roundup_size);
if (!rxr->rx_tpa)
return -ENOMEM;
if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
return 0;
for (i = 0; i < bp->max_tpa; i++) {
for (i = 0; i < bp->max_tpa_roundup_size; i++) {
agg = kzalloc_objs(*agg, MAX_SKB_FRAGS);
if (!agg)
return -ENOMEM;
@ -3832,6 +3855,9 @@ static int bnxt_alloc_tpa_info(struct bnxt *bp)
bp->max_tpa = MAX_TPA;
if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
/* TPA is not supported at all, so there is nothing to
* allocate.
*/
if (!bp->max_tpa_v2)
return 0;
bp->max_tpa = min_t(u16, bp->max_tpa_v2, MAX_TPA_P5);
@ -3839,6 +3865,7 @@ static int bnxt_alloc_tpa_info(struct bnxt *bp)
if (bp->max_tpa <= 32 && BNXT_CHIP_P5(bp) && !BNXT_NPAR(bp))
bp->max_tpa = MAX_TPA_P5;
}
bp->max_tpa_roundup_size = roundup_pow_of_two(bp->max_tpa);
for (i = 0; i < bp->rx_nr_rings; i++) {
struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i];
@ -4551,7 +4578,7 @@ static int bnxt_alloc_one_tpa_info_data(struct bnxt *bp,
u8 *data;
int i;
for (i = 0; i < bp->max_tpa; i++) {
for (i = 0; i < bp->max_tpa_roundup_size; i++) {
data = __bnxt_alloc_rx_frag(bp, &mapping, rxr,
GFP_KERNEL);
if (!data)
@ -5006,7 +5033,8 @@ void bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode)
bnxt_get_max_rings(bp, &rx, &tx, true);
if (rx > 1) {
bp->flags &= ~BNXT_FLAG_NO_AGG_RINGS;
bp->dev->hw_features |= NETIF_F_LRO;
if (BNXT_SUPPORTS_TPA(bp))
bp->dev->hw_features |= NETIF_F_LRO;
}
}
@ -5427,6 +5455,8 @@ static void bnxt_clear_ring_indices(struct bnxt *bp)
txr->tx_prod = 0;
txr->tx_cons = 0;
txr->tx_hw_cons = 0;
txr->kick_pending = 0;
txr->kick_txbd0 = NULL;
}
rxr = bnapi->rx_ring;
@ -11340,8 +11370,13 @@ static int bnxt_shutdown_nic(struct bnxt *bp, bool irq_re_init)
static int bnxt_init_nic(struct bnxt *bp, bool irq_re_init)
{
int rc;
bnxt_init_cp_rings(bp);
bnxt_init_rx_rings(bp);
rc = bnxt_init_rx_rings(bp);
if (rc)
return rc;
bnxt_init_tx_rings(bp);
bnxt_init_ring_grps(bp, irq_re_init);
bnxt_init_vnics(bp);
@ -11772,6 +11807,8 @@ static int bnxt_tx_queue_start(struct bnxt *bp, int idx)
txr->tx_prod = 0;
txr->tx_cons = 0;
txr->tx_hw_cons = 0;
txr->kick_pending = 0;
txr->kick_txbd0 = NULL;
start_tx:
WRITE_ONCE(txr->dev_state, 0);
synchronize_net();
@ -14603,7 +14640,14 @@ static void bnxt_rx_ring_reset(struct bnxt *bp)
rxr->rx_sw_agg_prod = 0;
rxr->rx_next_cons = 0;
rxr->bnapi->in_reset = false;
bnxt_alloc_one_rx_ring(bp, i);
rc = bnxt_alloc_one_rx_ring(bp, i);
if (rc) {
netdev_warn(bp->dev, "RX ring reset failed to allocate buffers, rc = %d, falling back to global reset\n",
rc);
bnxt_reset_task(bp, true);
bnxt_rtnl_unlock_sp(bp);
return;
}
cpr = &rxr->bnapi->cp_ring;
cpr->sw_stats->rx.rx_resets++;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
@ -16332,6 +16376,8 @@ static int bnxt_queue_mem_alloc(struct net_device *dev,
clone->need_head_pool = false;
clone->rx_page_size = qcfg->rx_page_size;
clone->rx_agg_bmap = NULL;
clone->rx_tpa = NULL;
clone->rx_tpa_idx_map = NULL;
rc = bnxt_alloc_rx_page_pool(bp, clone, rxr->page_pool->p.nid);
if (rc)
@ -16375,11 +16421,16 @@ static int bnxt_queue_mem_alloc(struct net_device *dev,
bnxt_alloc_one_rx_ring_skb(bp, clone, idx);
if (bp->flags & BNXT_FLAG_AGG_RINGS)
bnxt_alloc_one_rx_ring_netmem(bp, clone, idx);
if (bp->flags & BNXT_FLAG_TPA)
bnxt_alloc_one_tpa_info_data(bp, clone);
if (bp->flags & BNXT_FLAG_TPA) {
rc = bnxt_alloc_one_tpa_info_data(bp, clone);
if (rc)
goto err_free_rx_ring_skbs;
}
return 0;
err_free_rx_ring_skbs:
bnxt_free_one_rx_ring_skbs(bp, clone);
err_free_tpa_info:
bnxt_free_one_tpa_info(bp, clone);
err_free_rx_agg_ring:

View File

@ -789,7 +789,6 @@ struct nqe_cn {
#define MAX_TPA 64
#define MAX_TPA_P5 256
#define MAX_TPA_P5_MASK (MAX_TPA_P5 - 1)
#define MAX_TPA_SEGS_P5 0x3f
#if (BNXT_PAGE_SHIFT == 16)
@ -993,6 +992,7 @@ struct bnxt_tx_ring_info {
u16 txq_index;
u8 tx_napi_idx;
u8 kick_pending;
struct tx_bd *kick_txbd0;
struct bnxt_db_info tx_db;
struct tx_bd *tx_desc_ring[MAX_TX_PAGES];
@ -2380,6 +2380,7 @@ struct bnxt {
u16 max_tpa_v2;
u16 max_tpa;
u16 max_tpa_roundup_size;
u32 rx_buf_size;
u32 rx_buf_use_size; /* useable size */
u16 rx_offset;

View File

@ -31,10 +31,14 @@ static u32 bnxt_sw_gso_lhint(unsigned int len)
return TX_BD_FLAGS_LHINT_2048_AND_LARGER;
}
netdev_tx_t bnxt_sw_udp_gso_xmit(struct bnxt *bp,
struct bnxt_tx_ring_info *txr,
struct netdev_queue *txq,
struct sk_buff *skb)
/* Transmit an skb requiring software UDP segmentation.
*
* Returns 1 if the skb was queued and new BDs were produced, 0 if the skb
* was dropped, or -1 if the ring is full and the skb should be retried.
* The caller owns the doorbell for all three cases.
*/
int bnxt_sw_udp_gso_xmit(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
struct netdev_queue *txq, struct sk_buff *skb)
{
unsigned int last_unmap_len __maybe_unused = 0;
dma_addr_t last_unmap_addr __maybe_unused = 0;
@ -69,7 +73,7 @@ netdev_tx_t bnxt_sw_udp_gso_xmit(struct bnxt *bp,
if (unlikely(bnxt_tx_avail(bp, txr) < bds_needed)) {
netif_txq_try_stop(txq, bnxt_tx_avail(bp, txr),
bp->tx_wake_thresh);
return NETDEV_TX_BUSY;
return -1;
}
/* BD backpressure alone cannot prevent overwriting in-flight
@ -77,7 +81,7 @@ netdev_tx_t bnxt_sw_udp_gso_xmit(struct bnxt *bp,
*/
if (!netif_txq_maybe_stop(txq, bnxt_inline_avail(txr),
num_segs, num_segs))
return NETDEV_TX_BUSY;
return -1;
if (unlikely(tso_dma_map_init(&map, &pdev->dev, skb, hdr_len)))
goto drop;
@ -223,16 +227,15 @@ netdev_tx_t bnxt_sw_udp_gso_xmit(struct bnxt *bp,
netdev_tx_sent_queue(txq, skb->len);
WRITE_ONCE(txr->tx_prod, prod);
txr->kick_pending = 1;
if (unlikely(bnxt_tx_avail(bp, txr) <= bp->tx_wake_thresh))
netif_txq_try_stop(txq, bnxt_tx_avail(bp, txr),
bp->tx_wake_thresh);
return NETDEV_TX_OK;
return 1;
drop:
dev_kfree_skb_any(skb);
dev_core_stats_tx_dropped_inc(bp->dev);
return NETDEV_TX_OK;
return 0;
}

View File

@ -38,9 +38,7 @@ static inline int bnxt_min_tx_desc_cnt(struct bnxt *bp,
return BNXT_MIN_TX_DESC_CNT;
}
netdev_tx_t bnxt_sw_udp_gso_xmit(struct bnxt *bp,
struct bnxt_tx_ring_info *txr,
struct netdev_queue *txq,
struct sk_buff *skb);
int bnxt_sw_udp_gso_xmit(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
struct netdev_queue *txq, struct sk_buff *skb);
#endif

View File

@ -1164,6 +1164,8 @@ static int macb_mii_init(struct macb *bp)
if (err)
goto err_out_unregister_bus;
of_node_put(mdio_np);
return 0;
err_out_unregister_bus:
@ -4300,9 +4302,9 @@ static int macb_taprio_setup_replace(struct net_device *netdev,
u64 total_on_time = 0, start_time_sec = 0, start_time = conf->base_time;
u32 configured_queues = 0, speed = 0, start_time_nsec;
struct macb_queue_enst_config *enst_queue;
struct tc_taprio_sched_entry *entry;
struct ethtool_link_ksettings kset = {};
struct macb *bp = netdev_priv(netdev);
struct ethtool_link_ksettings kset;
struct tc_taprio_sched_entry *entry;
struct macb_queue *queue;
u32 queue_mask;
u8 queue_id;
@ -4329,8 +4331,8 @@ static int macb_taprio_setup_replace(struct net_device *netdev,
}
speed = kset.base.speed;
if (unlikely(speed <= 0)) {
netdev_err(netdev, "Invalid speed: %d\n", speed);
if (unlikely(speed == SPEED_UNKNOWN || !speed)) {
netdev_err(netdev, "Invalid speed %d, link-down?\n", speed);
return -EINVAL;
}
@ -5881,6 +5883,7 @@ static int macb_probe(struct platform_device *pdev)
}
spin_lock_init(&bp->lock);
spin_lock_init(&bp->stats_lock);
spin_lock_init(&bp->tsu_clk_lock);
/* setup capabilities */
macb_configure_caps(bp, macb_config);
@ -5976,8 +5979,11 @@ static int macb_probe(struct platform_device *pdev)
macb_free_tieoff(bp);
err_out_unregister_mdio:
mdiobus_unregister(bp->mii_bus);
mdiobus_free(bp->mii_bus);
if (bp->mii_bus) {
mdiobus_unregister(bp->mii_bus);
mdiobus_free(bp->mii_bus);
}
phylink_destroy(bp->phylink);
err_out_phy_exit:
phy_exit(bp->phy);
@ -6006,8 +6012,10 @@ static void macb_remove(struct platform_device *pdev)
unregister_netdev(netdev);
macb_free_tieoff(bp);
phy_exit(bp->phy);
mdiobus_unregister(bp->mii_bus);
mdiobus_free(bp->mii_bus);
if (bp->mii_bus) {
mdiobus_unregister(bp->mii_bus);
mdiobus_free(bp->mii_bus);
}
device_set_wakeup_enable(&bp->pdev->dev, 0);
cancel_delayed_work_sync(&bp->tx_lpi_work);

View File

@ -334,6 +334,7 @@ void gem_ptp_init(struct net_device *netdev)
bp->tsu_rate = bp->ptp_info->get_tsu_rate(bp);
bp->ptp_clock_info.max_adj = bp->ptp_info->get_ptp_max_adj();
gem_ptp_init_timer(bp);
gem_ptp_init_tsu(bp);
bp->ptp_clock = ptp_clock_register(&bp->ptp_clock_info, &netdev->dev);
if (IS_ERR(bp->ptp_clock)) {
pr_err("ptp clock register failed: %ld\n",
@ -345,10 +346,6 @@ void gem_ptp_init(struct net_device *netdev)
return;
}
spin_lock_init(&bp->tsu_clk_lock);
gem_ptp_init_tsu(bp);
dev_info(&bp->pdev->dev, "%s ptp clock registered.\n",
GEM_PTP_TIMER_NAME);
}

View File

@ -137,6 +137,12 @@ struct enic_port_profile {
u8 mac_addr[ETH_ALEN];
};
enum enic_vf_link_state {
ENIC_VF_LINK_STATE_UNKNOWN,
ENIC_VF_LINK_STATE_DOWN,
ENIC_VF_LINK_STATE_UP,
};
/* enic_rfs_fltr_node - rfs filter node in hash table
* @@keys: IPv4 5 tuple
* @flow_id: flow_id of clsf filter provided by kernel
@ -312,19 +318,25 @@ struct enic {
unsigned int admin_msg_count; /* current depth of admin_msg_list */
void (*admin_rq_handler)(struct enic *enic, void *buf,
unsigned int len);
/* The PF is authoritative for a V2 VF's carrier. Keep the last
* notification across an ordinary netdev close/open and serialize it
* against the open/stop carrier transition.
*/
spinlock_t vf_link_state_lock;
enum enic_vf_link_state vf_link_state;
bool vf_link_running;
/* MBOX protocol state — mbox_lock serializes admin WQ sends */
struct mutex mbox_lock;
u64 mbox_msg_num;
/* MBOX request-reply state. mbox_expected_reply is written and
* cleared by the process-context request helpers (capability/register/
* unregister) and only read by the admin_msg_work receive handlers, so
* it is annotated with READ_ONCE()/WRITE_ONCE() rather than locked:
* only one request is in flight at a time (requesters run under RTNL or
* single-threaded probe/remove), so each request is serialized and its
* reply completes mbox_comp before the next request is issued.
/* MBOX request-reply state. Existing request callers allow only one
* request in flight. The state lock arbitrates reply acceptance against
* timeout invalidation, while mbox_comp publishes the accepted result to
* the requester.
*/
struct completion mbox_comp;
spinlock_t mbox_state_lock; /* protects expected reply state */
u64 mbox_expected_msg_num;
u8 mbox_expected_reply;
bool mbox_initialized;

View File

@ -1800,6 +1800,8 @@ static int enic_open(struct net_device *netdev)
enic_notify_timer_start(enic);
enic_rfs_timer_start(enic);
if (enic_is_sriov_vf_v2(enic))
enic_mbox_vf_link_state_set_running(enic, true);
return 0;
@ -1853,7 +1855,10 @@ static int enic_stop(struct net_device *netdev)
for (i = 0; i < enic->rq_count; i++)
napi_disable(&enic->napi[i]);
netif_carrier_off(netdev);
if (enic_is_sriov_vf_v2(enic))
enic_mbox_vf_link_state_set_running(enic, false);
else
netif_carrier_off(netdev);
if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX)
for (i = 0; i < enic->wq_count; i++)
napi_disable(&enic->napi[enic_cq_wq(enic, i)]);
@ -2201,9 +2206,10 @@ static void enic_admin_chan_reopen(struct enic *enic)
{
int err;
/* Install the MBOX receive handler and reset the sequence number
* before opening the channel, so the handler is in place before the
* admin interrupt is unmasked and no early completion is dropped.
/* Install the MBOX receive handler and clear pending reply state before
* opening the channel, so the handler is in place before the admin
* interrupt is unmasked and no early completion is dropped. Keep the
* sequence number monotonic across channel generations.
*/
enic_mbox_init(enic);
@ -2215,7 +2221,7 @@ static void enic_admin_chan_reopen(struct enic *enic)
* registration over a dead channel.
*/
if (enic_is_sriov_vf_v2(enic))
enic->vf_registered = false;
WRITE_ONCE(enic->vf_registered, false);
err = enic_admin_channel_open(enic);
if (err) {
@ -2271,6 +2277,8 @@ static void enic_reset(struct work_struct *work)
enic_admin_channel_close(enic);
enic_stop(enic->netdev);
if (enic_is_sriov_vf_v2(enic))
enic_mbox_vf_link_state_reset(enic);
enic_dev_soft_reset(enic);
enic_reset_addr_lists(enic);
@ -2315,6 +2323,8 @@ static void enic_tx_hang_reset(struct work_struct *work)
enic_dev_hang_notify(enic);
enic_stop(enic->netdev);
if (enic_is_sriov_vf_v2(enic))
enic_mbox_vf_link_state_reset(enic);
enic_dev_hang_reset(enic);
enic_reset_addr_lists(enic);
@ -3015,6 +3025,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
enic = netdev_priv(netdev);
enic->netdev = netdev;
enic->pdev = pdev;
spin_lock_init(&enic->vf_link_state_lock);
/* Setup PCI resources
*/
@ -3339,7 +3350,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_out_admin_close:
if (enic_is_sriov_vf_v2(enic)) {
if (enic->vf_registered) {
if (READ_ONCE(enic->vf_registered)) {
int unreg_err = enic_mbox_vf_unregister(enic);
if (unreg_err)
@ -3392,7 +3403,7 @@ static void enic_remove(struct pci_dev *pdev)
* touching a netdev that is being torn down.
*/
if (enic_is_sriov_vf_v2(enic)) {
if (enic->vf_registered) {
if (READ_ONCE(enic->vf_registered)) {
int unreg_err = enic_mbox_vf_unregister(enic);
if (unreg_err)

View File

@ -18,22 +18,25 @@
#define ENIC_MBOX_POLL_TIMEOUT_US 5000000
#define ENIC_MBOX_POLL_INTERVAL_US 100
static void enic_mbox_fill_hdr(struct enic *enic, struct enic_mbox_hdr *hdr,
u8 msg_type, u16 dst_vnic_id, u16 msg_len)
static void enic_mbox_fill_hdr(struct enic_mbox_hdr *hdr, u8 msg_type,
u16 dst_vnic_id, u16 msg_len, u64 msg_num)
{
memset(hdr, 0, sizeof(*hdr));
hdr->dst_vnic_id = cpu_to_le16(dst_vnic_id);
hdr->msg_type = msg_type;
hdr->msg_len = cpu_to_le16(msg_len);
hdr->msg_num = cpu_to_le64(++enic->mbox_msg_num);
hdr->msg_num = cpu_to_le64(msg_num);
}
int enic_mbox_send_msg(struct enic *enic, u8 msg_type, u16 dst_vnic_id,
void *payload, u16 payload_len)
static int enic_mbox_send_msg_id(struct enic *enic, u8 msg_type,
u16 dst_vnic_id, void *payload,
u16 payload_len, u64 msg_num, bool reuse_msg_num,
u8 expected_reply)
{
size_t total_len = sizeof(struct enic_mbox_hdr) + payload_len;
struct vnic_wq *wq = &enic->admin_wq;
struct wq_enet_desc *desc;
bool reply_expected = false;
unsigned long timeout;
dma_addr_t dma_addr;
u16 vlan_tag;
@ -68,7 +71,21 @@ int enic_mbox_send_msg(struct enic *enic, u8 msg_type, u16 dst_vnic_id,
goto unlock;
}
enic_mbox_fill_hdr(enic, buf, msg_type, dst_vnic_id, total_len);
/* Replies reuse the initiating message number. Requests and
* notifications allocate a new one.
*/
if (!reuse_msg_num)
msg_num = ++enic->mbox_msg_num;
if (expected_reply) {
reinit_completion(&enic->mbox_comp);
spin_lock_bh(&enic->mbox_state_lock);
enic->mbox_expected_reply = expected_reply;
enic->mbox_expected_msg_num = msg_num;
spin_unlock_bh(&enic->mbox_state_lock);
reply_expected = true;
}
enic_mbox_fill_hdr(buf, msg_type, dst_vnic_id, total_len, msg_num);
if (payload_len) {
void *dst = buf + sizeof(struct enic_mbox_hdr);
@ -139,18 +156,66 @@ int enic_mbox_send_msg(struct enic *enic, u8 msg_type, u16 dst_vnic_id,
"MBOX send msg_type %u dst %u vlan %u err %d\n",
msg_type, dst_vnic_id, vlan_tag, err);
unlock:
if (err && reply_expected) {
spin_lock_bh(&enic->mbox_state_lock);
if (enic->mbox_expected_reply == expected_reply &&
enic->mbox_expected_msg_num == msg_num) {
enic->mbox_expected_reply = 0;
enic->mbox_expected_msg_num = 0;
}
spin_unlock_bh(&enic->mbox_state_lock);
}
mutex_unlock(&enic->mbox_lock);
return err;
}
int enic_mbox_send_msg(struct enic *enic, u8 msg_type, u16 dst_vnic_id,
void *payload, u16 payload_len)
{
return enic_mbox_send_msg_id(enic, msg_type, dst_vnic_id, payload,
payload_len, 0, false, 0);
}
static int enic_mbox_send_reply(struct enic *enic, u8 msg_type,
u16 dst_vnic_id, void *payload, u16 payload_len,
u64 msg_num)
{
return enic_mbox_send_msg_id(enic, msg_type, dst_vnic_id, payload,
payload_len, msg_num, true, 0);
}
static int enic_mbox_vf_send_request(struct enic *enic, u8 request_type,
u8 expected_reply, void *payload,
u16 payload_len)
{
return enic_mbox_send_msg_id(enic, request_type, ENIC_MBOX_DST_PF,
payload, payload_len, 0, false,
expected_reply);
}
static int enic_mbox_wait_reply(struct enic *enic, unsigned long timeout_ms)
{
unsigned long left;
int err = 0;
left = wait_for_completion_timeout(&enic->mbox_comp,
msecs_to_jiffies(timeout_ms));
if (left)
return 0;
return left ? 0 : -ETIMEDOUT;
/* Invalidate a request that the handler has not already accepted. A
* delayed reply cannot match a later request because message numbers are
* monotonic across channel reopen.
*/
spin_lock_bh(&enic->mbox_state_lock);
if (enic->mbox_expected_reply) {
enic->mbox_expected_reply = 0;
enic->mbox_expected_msg_num = 0;
err = -ETIMEDOUT;
}
spin_unlock_bh(&enic->mbox_state_lock);
return err;
}
int enic_mbox_send_link_state(struct enic *enic, u16 vf_id, u32 link_state)
@ -178,8 +243,8 @@ static int enic_mbox_pf_handle_capability(struct enic *enic, void *msg,
reply.reply.ret_major = cpu_to_le16(0);
reply.version = cpu_to_le32(ENIC_MBOX_CAP_VERSION_1);
return enic_mbox_send_msg(enic, ENIC_MBOX_VF_CAPABILITY_REPLY, vf_id,
&reply, sizeof(reply));
return enic_mbox_send_reply(enic, ENIC_MBOX_VF_CAPABILITY_REPLY, vf_id,
&reply, sizeof(reply), msg_num);
}
static int enic_mbox_pf_handle_register(struct enic *enic, void *msg,
@ -208,8 +273,8 @@ static int enic_mbox_pf_handle_register(struct enic *enic, void *msg,
}
reply.reply.ret_major = cpu_to_le16(0);
err = enic_mbox_send_msg(enic, ENIC_MBOX_VF_REGISTER_REPLY, vf_id,
&reply, sizeof(reply));
err = enic_mbox_send_reply(enic, ENIC_MBOX_VF_REGISTER_REPLY, vf_id,
&reply, sizeof(reply), msg_num);
if (err)
return err;
@ -253,8 +318,8 @@ static int enic_mbox_pf_handle_unregister(struct enic *enic, void *msg,
enic->vf_state[vf_id].registered = false;
reply.reply.ret_major = cpu_to_le16(0);
err = enic_mbox_send_msg(enic, ENIC_MBOX_VF_UNREGISTER_REPLY, vf_id,
&reply, sizeof(reply));
err = enic_mbox_send_reply(enic, ENIC_MBOX_VF_UNREGISTER_REPLY, vf_id,
&reply, sizeof(reply), msg_num);
if (net_ratelimit())
netdev_info(enic->netdev,
@ -324,105 +389,116 @@ static void enic_mbox_pf_process_msg(struct enic *enic,
hdr->msg_type, vf_id, err);
}
static void enic_mbox_vf_handle_capability_reply(struct enic *enic,
void *payload)
static void enic_mbox_vf_handle_reply(struct enic *enic, u8 reply_type,
void *payload, u64 msg_num)
{
struct enic_mbox_vf_capability_reply_msg *reply = payload;
struct enic_mbox_generic_reply *reply = payload;
u16 ret_major = le16_to_cpu(reply->ret_major);
u64 expected_msg_num;
u8 expected_type;
if (READ_ONCE(enic->mbox_expected_reply) != ENIC_MBOX_VF_CAPABILITY_REPLY) {
spin_lock_bh(&enic->mbox_state_lock);
expected_type = enic->mbox_expected_reply;
expected_msg_num = enic->mbox_expected_msg_num;
if (expected_type != reply_type || expected_msg_num != msg_num) {
spin_unlock_bh(&enic->mbox_state_lock);
netdev_warn(enic->netdev,
"MBOX: stale capability reply (expected %u), drop\n",
READ_ONCE(enic->mbox_expected_reply));
"MBOX: stale reply %u/%llu (expected %u/%llu), drop\n",
reply_type, (unsigned long long)msg_num,
expected_type, (unsigned long long)expected_msg_num);
return;
}
if (le16_to_cpu(reply->reply.ret_major) == 0)
enic->pf_cap_version = le32_to_cpu(reply->version);
else
netdev_warn(enic->netdev,
"MBOX: PF rejected capability request: %u/%u\n",
le16_to_cpu(reply->reply.ret_major),
le16_to_cpu(reply->reply.ret_minor));
if (!ret_major) {
switch (reply_type) {
case ENIC_MBOX_VF_CAPABILITY_REPLY: {
struct enic_mbox_vf_capability_reply_msg *cap = payload;
WRITE_ONCE(enic->pf_cap_version,
le32_to_cpu(cap->version));
break;
}
case ENIC_MBOX_VF_REGISTER_REPLY:
WRITE_ONCE(enic->vf_registered, true);
break;
case ENIC_MBOX_VF_UNREGISTER_REPLY:
WRITE_ONCE(enic->vf_registered, false);
break;
}
}
enic->mbox_expected_reply = 0;
enic->mbox_expected_msg_num = 0;
complete(&enic->mbox_comp);
spin_unlock_bh(&enic->mbox_state_lock);
if (ret_major)
netdev_warn(enic->netdev,
"MBOX: PF rejected reply type %u: %u/%u\n",
reply_type, ret_major,
le16_to_cpu(reply->ret_minor));
}
static void enic_mbox_vf_handle_register_reply(struct enic *enic,
void *payload)
{
struct enic_mbox_vf_register_reply_msg *reply = payload;
if (READ_ONCE(enic->mbox_expected_reply) != ENIC_MBOX_VF_REGISTER_REPLY) {
netdev_warn(enic->netdev,
"MBOX: stale register reply (expected %u), drop\n",
READ_ONCE(enic->mbox_expected_reply));
return;
}
if (le16_to_cpu(reply->reply.ret_major)) {
netdev_warn(enic->netdev,
"MBOX: VF register rejected by PF: %u/%u\n",
le16_to_cpu(reply->reply.ret_major),
le16_to_cpu(reply->reply.ret_minor));
} else {
enic->vf_registered = true;
}
complete(&enic->mbox_comp);
}
static void enic_mbox_vf_handle_unregister_reply(struct enic *enic,
void *payload)
{
struct enic_mbox_vf_register_reply_msg *reply = payload;
if (READ_ONCE(enic->mbox_expected_reply) != ENIC_MBOX_VF_UNREGISTER_REPLY) {
netdev_warn(enic->netdev,
"MBOX: stale unregister reply (expected %u), drop\n",
READ_ONCE(enic->mbox_expected_reply));
return;
}
if (le16_to_cpu(reply->reply.ret_major)) {
netdev_warn(enic->netdev,
"MBOX: VF unregister rejected by PF: %u/%u\n",
le16_to_cpu(reply->reply.ret_major),
le16_to_cpu(reply->reply.ret_minor));
} else {
enic->vf_registered = false;
}
complete(&enic->mbox_comp);
}
static void enic_mbox_vf_handle_link_state(struct enic *enic, void *payload)
static void enic_mbox_vf_handle_link_state(struct enic *enic, void *payload,
u64 msg_num)
{
struct enic_mbox_pf_link_state_notif_msg *notif = payload;
struct enic_mbox_pf_link_state_ack_msg ack = {};
u32 link_state = le32_to_cpu(notif->link_state);
int err;
switch (le32_to_cpu(notif->link_state)) {
spin_lock_bh(&enic->vf_link_state_lock);
switch (link_state) {
case ENIC_MBOX_LINK_STATE_ENABLE:
if (!netif_carrier_ok(enic->netdev))
enic->vf_link_state = ENIC_VF_LINK_STATE_UP;
if (enic->vf_link_running &&
!netif_carrier_ok(enic->netdev))
netif_carrier_on(enic->netdev);
netdev_dbg(enic->netdev, "MBOX: link state -> UP\n");
break;
case ENIC_MBOX_LINK_STATE_DISABLE:
if (netif_carrier_ok(enic->netdev))
enic->vf_link_state = ENIC_VF_LINK_STATE_DOWN;
if (enic->vf_link_running &&
netif_carrier_ok(enic->netdev))
netif_carrier_off(enic->netdev);
netdev_dbg(enic->netdev, "MBOX: link state -> DOWN\n");
break;
default:
netdev_warn(enic->netdev, "MBOX: unknown link state %u\n",
le32_to_cpu(notif->link_state));
link_state);
ack.ack.ret_major = cpu_to_le16(ENIC_MBOX_ERR_GENERIC);
break;
}
spin_unlock_bh(&enic->vf_link_state_lock);
err = enic_mbox_send_msg(enic, ENIC_MBOX_PF_LINK_STATE_ACK,
ENIC_MBOX_DST_PF, &ack, sizeof(ack));
err = enic_mbox_send_reply(enic, ENIC_MBOX_PF_LINK_STATE_ACK,
ENIC_MBOX_DST_PF, &ack, sizeof(ack), msg_num);
if (err && net_ratelimit())
netdev_warn(enic->netdev,
"MBOX: failed to send link state ACK: %d\n", err);
}
void enic_mbox_vf_link_state_reset(struct enic *enic)
{
spin_lock_bh(&enic->vf_link_state_lock);
enic->vf_link_state = ENIC_VF_LINK_STATE_UNKNOWN;
if (enic->vf_link_running && netif_carrier_ok(enic->netdev))
netif_carrier_off(enic->netdev);
spin_unlock_bh(&enic->vf_link_state_lock);
}
void enic_mbox_vf_link_state_set_running(struct enic *enic, bool running)
{
spin_lock_bh(&enic->vf_link_state_lock);
enic->vf_link_running = running;
if (running && enic->vf_link_state == ENIC_VF_LINK_STATE_UP) {
if (!netif_carrier_ok(enic->netdev))
netif_carrier_on(enic->netdev);
} else if (netif_carrier_ok(enic->netdev)) {
netif_carrier_off(enic->netdev);
}
spin_unlock_bh(&enic->vf_link_state_lock);
}
static bool enic_mbox_vf_payload_ok(struct enic *enic, u8 msg_type,
u16 payload_len, size_t min_len)
{
@ -439,6 +515,8 @@ static void enic_mbox_vf_process_msg(struct enic *enic,
struct enic_mbox_hdr *hdr, void *payload,
u16 payload_len)
{
u64 msg_num = le64_to_cpu(hdr->msg_num);
switch (hdr->msg_type) {
case ENIC_MBOX_VF_CAPABILITY_REPLY: {
size_t exp = sizeof(struct enic_mbox_vf_capability_reply_msg);
@ -446,7 +524,7 @@ static void enic_mbox_vf_process_msg(struct enic *enic,
if (!enic_mbox_vf_payload_ok(enic, hdr->msg_type,
payload_len, exp))
return;
enic_mbox_vf_handle_capability_reply(enic, payload);
enic_mbox_vf_handle_reply(enic, hdr->msg_type, payload, msg_num);
break;
}
case ENIC_MBOX_VF_REGISTER_REPLY: {
@ -455,7 +533,7 @@ static void enic_mbox_vf_process_msg(struct enic *enic,
if (!enic_mbox_vf_payload_ok(enic, hdr->msg_type,
payload_len, exp))
return;
enic_mbox_vf_handle_register_reply(enic, payload);
enic_mbox_vf_handle_reply(enic, hdr->msg_type, payload, msg_num);
break;
}
case ENIC_MBOX_VF_UNREGISTER_REPLY: {
@ -464,7 +542,7 @@ static void enic_mbox_vf_process_msg(struct enic *enic,
if (!enic_mbox_vf_payload_ok(enic, hdr->msg_type,
payload_len, exp))
return;
enic_mbox_vf_handle_unregister_reply(enic, payload);
enic_mbox_vf_handle_reply(enic, hdr->msg_type, payload, msg_num);
break;
}
case ENIC_MBOX_PF_LINK_STATE_NOTIF: {
@ -473,7 +551,7 @@ static void enic_mbox_vf_process_msg(struct enic *enic,
if (!enic_mbox_vf_payload_ok(enic, hdr->msg_type,
payload_len, exp))
return;
enic_mbox_vf_handle_link_state(enic, payload);
enic_mbox_vf_handle_link_state(enic, payload, msg_num);
break;
}
default:
@ -542,32 +620,31 @@ static void enic_mbox_recv_handler(struct enic *enic, void *buf,
int enic_mbox_vf_capability_check(struct enic *enic)
{
struct enic_mbox_vf_capability_msg req = {};
u32 version;
int err;
enic->pf_cap_version = 0;
reinit_completion(&enic->mbox_comp);
WRITE_ONCE(enic->mbox_expected_reply, ENIC_MBOX_VF_CAPABILITY_REPLY);
WRITE_ONCE(enic->pf_cap_version, 0);
req.version = cpu_to_le32(ENIC_MBOX_CAP_VERSION_1);
err = enic_mbox_send_msg(enic, ENIC_MBOX_VF_CAPABILITY_REQUEST,
ENIC_MBOX_DST_PF, &req, sizeof(req));
if (err) {
WRITE_ONCE(enic->mbox_expected_reply, 0);
err = enic_mbox_vf_send_request(enic,
ENIC_MBOX_VF_CAPABILITY_REQUEST,
ENIC_MBOX_VF_CAPABILITY_REPLY,
&req, sizeof(req));
if (err)
return err;
}
err = enic_mbox_wait_reply(enic, 3000);
WRITE_ONCE(enic->mbox_expected_reply, 0);
version = READ_ONCE(enic->pf_cap_version);
if (err) {
netdev_warn(enic->netdev,
"MBOX: no capability reply from PF\n");
return err;
}
if (enic->pf_cap_version < ENIC_MBOX_CAP_VERSION_1) {
if (version < ENIC_MBOX_CAP_VERSION_1) {
netdev_warn(enic->netdev,
"MBOX: PF rejected capability request or reported unsupported version %u\n",
enic->pf_cap_version);
version);
return -EOPNOTSUPP;
}
@ -576,28 +653,25 @@ int enic_mbox_vf_capability_check(struct enic *enic)
int enic_mbox_vf_register(struct enic *enic)
{
bool registered;
int err;
enic->vf_registered = false;
reinit_completion(&enic->mbox_comp);
WRITE_ONCE(enic->mbox_expected_reply, ENIC_MBOX_VF_REGISTER_REPLY);
WRITE_ONCE(enic->vf_registered, false);
err = enic_mbox_send_msg(enic, ENIC_MBOX_VF_REGISTER_REQUEST,
ENIC_MBOX_DST_PF, NULL, 0);
if (err) {
WRITE_ONCE(enic->mbox_expected_reply, 0);
err = enic_mbox_vf_send_request(enic, ENIC_MBOX_VF_REGISTER_REQUEST,
ENIC_MBOX_VF_REGISTER_REPLY, NULL, 0);
if (err)
return err;
}
err = enic_mbox_wait_reply(enic, 3000);
WRITE_ONCE(enic->mbox_expected_reply, 0);
registered = READ_ONCE(enic->vf_registered);
if (err) {
netdev_warn(enic->netdev,
"MBOX: VF registration with PF timed out\n");
return err;
}
if (!enic->vf_registered)
if (!registered)
return -ENODEV;
return 0;
@ -605,43 +679,48 @@ int enic_mbox_vf_register(struct enic *enic)
int enic_mbox_vf_unregister(struct enic *enic)
{
bool registered;
int err;
if (!enic->vf_registered)
if (!READ_ONCE(enic->vf_registered))
return 0;
reinit_completion(&enic->mbox_comp);
WRITE_ONCE(enic->mbox_expected_reply, ENIC_MBOX_VF_UNREGISTER_REPLY);
err = enic_mbox_send_msg(enic, ENIC_MBOX_VF_UNREGISTER_REQUEST,
ENIC_MBOX_DST_PF, NULL, 0);
if (err) {
WRITE_ONCE(enic->mbox_expected_reply, 0);
return err;
}
err = enic_mbox_wait_reply(enic, 3000);
WRITE_ONCE(enic->mbox_expected_reply, 0);
err = enic_mbox_vf_send_request(enic,
ENIC_MBOX_VF_UNREGISTER_REQUEST,
ENIC_MBOX_VF_UNREGISTER_REPLY,
NULL, 0);
if (err)
return err;
if (enic->vf_registered)
err = enic_mbox_wait_reply(enic, 3000);
registered = READ_ONCE(enic->vf_registered);
if (err)
return err;
if (registered)
return -EACCES;
return 0;
}
void enic_mbox_init(struct enic *enic)
{
/* mbox_lock and mbox_comp must be initialized exactly once per
bool reinit = enic->mbox_initialized;
/* MBOX locks and mbox_comp must be initialized exactly once per
* device lifetime; the PF sriov_configure path can re-enter this
* on each enable cycle where these primitives are already set up.
*/
if (!enic->mbox_initialized) {
if (!reinit) {
mutex_init(&enic->mbox_lock);
init_completion(&enic->mbox_comp);
spin_lock_init(&enic->mbox_state_lock);
enic->mbox_msg_num = 0;
enic->mbox_initialized = true;
} else {
reinit_completion(&enic->mbox_comp);
}
enic->mbox_msg_num = 0;
spin_lock_bh(&enic->mbox_state_lock);
enic->mbox_expected_reply = 0;
enic->mbox_expected_msg_num = 0;
spin_unlock_bh(&enic->mbox_state_lock);
enic->admin_rq_handler = enic_mbox_recv_handler;
}

View File

@ -88,6 +88,8 @@ void enic_mbox_init(struct enic *enic);
int enic_mbox_send_msg(struct enic *enic, u8 msg_type, u16 dst_vnic_id,
void *payload, u16 payload_len);
int enic_mbox_send_link_state(struct enic *enic, u16 vf_id, u32 link_state);
void enic_mbox_vf_link_state_reset(struct enic *enic);
void enic_mbox_vf_link_state_set_running(struct enic *enic, bool running);
int enic_mbox_vf_capability_check(struct enic *enic);
int enic_mbox_vf_register(struct enic *enic);
int enic_mbox_vf_unregister(struct enic *enic);

View File

@ -124,6 +124,7 @@ struct gemini_ethernet_port {
unsigned int rx_coalesce_nsecs;
struct sk_buff *rx_skb;
unsigned int rx_frag_nr;
bool rx_dropping;
unsigned int freeq_refill;
struct gmac_txq txq[TX_QUEUE_NUM];
@ -1439,7 +1440,8 @@ static struct sk_buff *gmac_skb_if_good_frame(struct gemini_ethernet_port *port,
return skb;
}
static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget,
unsigned int *freeq_consumed)
{
struct gemini_ethernet_port *port = netdev_priv(netdev);
unsigned short m = (1 << port->rxq_order) - 1;
@ -1447,9 +1449,12 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
void __iomem *ptr_reg = port->rxq_rwptr;
unsigned int frag_nr = port->rx_frag_nr;
struct sk_buff *skb = port->rx_skb;
unsigned int consumed = 0;
unsigned int frame_len, frag_len;
struct gmac_rxdesc *rx = NULL;
struct gmac_queue_page *gpage;
unsigned int received = 0;
bool dropping = port->rx_dropping;
union gmac_rxdesc_0 word0;
union gmac_rxdesc_1 word1;
union gmac_rxdesc_3 word3;
@ -1471,6 +1476,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
w = rw.bits.wptr;
while (budget && w != r) {
page = NULL;
rx = port->rxq_ring + r;
word0 = rx->word0;
word1 = rx->word1;
@ -1479,11 +1485,22 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
r++;
r &= m;
consumed++;
frag_len = word0.bits.buffer_size;
frame_len = word1.bits.byte_count;
page_offs = mapping & ~PAGE_MASK;
if (word3.bits32 & SOF_BIT) {
if (skb) {
napi_free_frags(&port->napi);
port->stats.rx_dropped++;
skb = NULL;
frag_nr = 0;
}
dropping = false;
}
if (!mapping) {
netdev_err(netdev,
"rxq[%u]: HW BUG: zero DMA desc\n", r);
@ -1494,24 +1511,11 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
gpage = gmac_get_queue_page(geth, port, mapping + PAGE_SIZE);
if (!gpage) {
dev_err(geth->dev, "could not find mapping\n");
port->stats.rx_dropped++;
if (skb) {
napi_free_frags(&port->napi);
skb = NULL;
frag_nr = 0;
}
continue;
goto err_drop;
}
page = gpage->page;
if (word3.bits32 & SOF_BIT) {
if (skb) {
napi_free_frags(&port->napi);
port->stats.rx_dropped++;
skb = NULL;
frag_nr = 0;
}
skb = gmac_skb_if_good_frame(port, word0, frame_len);
if (!skb)
goto err_drop;
@ -1521,8 +1525,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
frag_nr = 0;
} else if (!skb) {
put_page(page);
continue;
goto err_drop;
}
if (word3.bits32 & EOF_BIT)
@ -1545,9 +1548,8 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
napi_gro_frags(&port->napi);
skb = NULL;
frag_nr = 0;
--budget;
}
continue;
goto next_desc;
err_drop:
if (skb) {
@ -1556,16 +1558,29 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
frag_nr = 0;
}
if (mapping)
if (page)
put_page(page);
port->stats.rx_dropped++;
if (!dropping) {
port->stats.rx_dropped++;
dropping = true;
}
next_desc:
/* Final or single-descriptor fragment, advance things */
if (word3.bits32 & EOF_BIT) {
budget--;
received++;
dropping = false;
}
}
port->rx_skb = skb;
port->rx_frag_nr = frag_nr;
port->rx_dropping = dropping;
*freeq_consumed = consumed;
writew(r, ptr_reg);
return budget;
return received;
}
static int gmac_napi_poll(struct napi_struct *napi, int budget)
@ -1573,26 +1588,27 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget)
struct gemini_ethernet_port *port = netdev_priv(napi->dev);
struct gemini_ethernet *geth = port->geth;
unsigned int freeq_threshold;
unsigned int freeq_consumed;
unsigned int received;
freeq_threshold = 1 << (geth->freeq_order - 1);
u64_stats_update_begin(&port->rx_stats_syncp);
received = gmac_rx(napi->dev, budget);
if (received < budget) {
napi_gro_flush(napi, false);
napi_complete_done(napi, received);
gmac_enable_rx_irq(napi->dev, 1);
received = gmac_rx(napi->dev, budget, &freeq_consumed);
if (received < budget)
++port->rx_napi_exits;
}
port->freeq_refill += (budget - received);
u64_stats_update_end(&port->rx_stats_syncp);
port->freeq_refill += freeq_consumed;
if (port->freeq_refill > freeq_threshold) {
port->freeq_refill -= freeq_threshold;
geth_fill_freeq(geth, true);
}
u64_stats_update_end(&port->rx_stats_syncp);
if (received < budget && napi_complete_done(napi, received))
gmac_enable_rx_irq(napi->dev, 1);
return received;
}
@ -1893,6 +1909,7 @@ static int gmac_stop(struct net_device *netdev)
napi_disable(&port->napi);
port->rx_skb = NULL;
port->rx_frag_nr = 0;
port->rx_dropping = false;
gmac_enable_irq(netdev, 0);
gmac_cleanup_rxq(netdev);

View File

@ -128,6 +128,7 @@ enum hinic_mbox_tx_status {
#define SEQ_ID_START_VAL 0
#define SEQ_ID_MAX_VAL 42
#define MBOX_LAST_SEG_MAX_LEN (MBOX_MAX_BUF_SZ - SEQ_ID_MAX_VAL * MBOX_SEG_LEN)
#define NO_DMA_ATTRIBUTE_VAL 0
@ -372,7 +373,8 @@ recv_pf_from_vf_mbox_handler(struct hinic_mbox_func_to_func *func_to_func,
static bool check_mbox_seq_id_and_seg_len(struct hinic_recv_mbox *recv_mbox,
u8 seq_id, u8 seg_len)
{
if (seq_id > SEQ_ID_MAX_VAL || seg_len > MBOX_SEG_LEN)
if (seq_id > SEQ_ID_MAX_VAL || seg_len > MBOX_SEG_LEN ||
(seq_id == SEQ_ID_MAX_VAL && seg_len > MBOX_LAST_SEG_MAX_LEN))
return false;
if (seq_id == 0) {

View File

@ -1051,14 +1051,13 @@ int ice_init_hw(struct ice_hw *hw)
hw->evb_veb = true;
/* init xarray for identifying scheduling nodes uniquely */
xa_init_flags(&hw->port_info->sched_node_ids, XA_FLAGS_ALLOC);
xa_init_flags(&hw->sched_node_ids, XA_FLAGS_ALLOC);
/* Query the allocated resources for Tx scheduler */
status = ice_sched_query_res_alloc(hw);
if (status) {
ice_debug(hw, ICE_DBG_SCHED, "Failed to get scheduler allocated resources\n");
goto err_unroll_alloc;
goto err_unroll_xarray;
}
ice_sched_get_psm_clk_freq(hw);
@ -1146,6 +1145,8 @@ int ice_init_hw(struct ice_hw *hw)
ice_cleanup_fltr_mgmt_struct(hw);
err_unroll_sched:
ice_sched_cleanup_all(hw);
err_unroll_xarray:
xa_destroy(&hw->sched_node_ids);
err_unroll_alloc:
devm_kfree(ice_hw_to_dev(hw), hw->port_info);
err_unroll_cqinit:
@ -1186,6 +1187,8 @@ void ice_deinit_hw(struct ice_hw *hw)
/* Clear VSI contexts if not already cleared */
ice_clear_all_vsi_ctx(hw);
xa_destroy(&hw->sched_node_ids);
}
/**

View File

@ -371,7 +371,7 @@ void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node)
devm_kfree(ice_hw_to_dev(hw), node->children);
kfree(node->name);
xa_erase(&pi->sched_node_ids, node->id);
xa_erase(&hw->sched_node_ids, node->id);
devm_kfree(ice_hw_to_dev(hw), node);
}
@ -977,7 +977,7 @@ ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,
if (!new_node->name)
return -ENOMEM;
status = xa_alloc(&pi->sched_node_ids, &new_node->id, NULL, XA_LIMIT(0, UINT_MAX),
status = xa_alloc(&hw->sched_node_ids, &new_node->id, NULL, XA_LIMIT(0, UINT_MAX),
GFP_KERNEL);
if (status) {
ice_debug(hw, ICE_DBG_SCHED, "xa_alloc failed for sched node status =%d\n",

View File

@ -63,23 +63,33 @@
DECLARE_EVENT_CLASS(ice_rx_dim_template,
TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),
TP_ARGS(q_vector, dim),
TP_STRUCT__entry(__field(struct ice_q_vector *, q_vector)
__field(struct dim *, dim)
TP_STRUCT__entry(__field(u16, q_index)
__field(u8, state)
__field(u8, profile_ix)
__field(u8, tune_state)
__field(u8, steps_right)
__field(u8, steps_left)
__field(u8, tired)
__string(devname, q_vector->rx.rx_ring->netdev->name)),
TP_fast_assign(__entry->q_vector = q_vector;
__entry->dim = dim;
TP_fast_assign(__entry->q_index = q_vector->rx.rx_ring->q_index;
__entry->state = dim->state;
__entry->profile_ix = dim->profile_ix;
__entry->tune_state = dim->tune_state;
__entry->steps_right = dim->steps_right;
__entry->steps_left = dim->steps_left;
__entry->tired = dim->tired;
__assign_str(devname);),
TP_printk("netdev: %s Rx-Q: %d dim-state: %d dim-profile: %d dim-tune: %d dim-st-right: %d dim-st-left: %d dim-tired: %d",
__get_str(devname),
__entry->q_vector->rx.rx_ring->q_index,
__entry->dim->state,
__entry->dim->profile_ix,
__entry->dim->tune_state,
__entry->dim->steps_right,
__entry->dim->steps_left,
__entry->dim->tired)
__entry->q_index,
__entry->state,
__entry->profile_ix,
__entry->tune_state,
__entry->steps_right,
__entry->steps_left,
__entry->tired)
);
DEFINE_EVENT(ice_rx_dim_template, ice_rx_dim_work,
@ -90,23 +100,33 @@ DEFINE_EVENT(ice_rx_dim_template, ice_rx_dim_work,
DECLARE_EVENT_CLASS(ice_tx_dim_template,
TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),
TP_ARGS(q_vector, dim),
TP_STRUCT__entry(__field(struct ice_q_vector *, q_vector)
__field(struct dim *, dim)
TP_STRUCT__entry(__field(u16, q_index)
__field(u8, state)
__field(u8, profile_ix)
__field(u8, tune_state)
__field(u8, steps_right)
__field(u8, steps_left)
__field(u8, tired)
__string(devname, q_vector->tx.tx_ring->netdev->name)),
TP_fast_assign(__entry->q_vector = q_vector;
__entry->dim = dim;
TP_fast_assign(__entry->q_index = q_vector->tx.tx_ring->q_index;
__entry->state = dim->state;
__entry->profile_ix = dim->profile_ix;
__entry->tune_state = dim->tune_state;
__entry->steps_right = dim->steps_right;
__entry->steps_left = dim->steps_left;
__entry->tired = dim->tired;
__assign_str(devname);),
TP_printk("netdev: %s Tx-Q: %d dim-state: %d dim-profile: %d dim-tune: %d dim-st-right: %d dim-st-left: %d dim-tired: %d",
__get_str(devname),
__entry->q_vector->tx.tx_ring->q_index,
__entry->dim->state,
__entry->dim->profile_ix,
__entry->dim->tune_state,
__entry->dim->steps_right,
__entry->dim->steps_left,
__entry->dim->tired)
__entry->q_index,
__entry->state,
__entry->profile_ix,
__entry->tune_state,
__entry->steps_right,
__entry->steps_left,
__entry->tired)
);
DEFINE_EVENT(ice_tx_dim_template, ice_tx_dim_work,

View File

@ -765,7 +765,6 @@ struct ice_port_info {
/* List contain profile ID(s) and other params per layer */
struct list_head rl_prof_list[ICE_AQC_TOPO_MAX_LEVEL_NUM];
struct ice_qos_cfg qos_cfg;
struct xarray sched_node_ids;
u8 is_vf:1;
u8 is_custom_tx_enabled:1;
};
@ -930,6 +929,7 @@ struct ice_hw {
u8 sw_entry_point_layer;
u16 max_children[ICE_AQC_TOPO_MAX_LEVEL_NUM];
struct list_head agg_list; /* lists all aggregator */
struct xarray sched_node_ids;
struct ice_vsi_ctx *vsi_ctx[ICE_MAX_VSI];
u8 evb_veb; /* true for VEB, false for VEPA */

View File

@ -106,6 +106,11 @@ static int idpf_dev_init(struct idpf_adapter *adapter,
*/
static void idpf_decfg_device(struct idpf_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
if (pcie_ptm_enabled(pdev))
pci_disable_ptm(pdev);
libie_pci_unmap_all_mmio_regions(&adapter->ctlq_ctx.mmio_info);
}

View File

@ -3299,6 +3299,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,
struct libeth_rx_pt decoded)
{
u16 rsc_segments, rsc_seg_len;
u16 l3_start = 0;
bool ipv4, ipv6;
int len;
@ -3321,7 +3322,10 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,
NAPI_GRO_CB(skb)->count = rsc_segments;
skb_shinfo(skb)->gso_size = rsc_seg_len;
skb_reset_network_header(skb);
if (unlikely(eth_type_vlan(skb->protocol)))
l3_start = VLAN_HLEN;
skb_set_network_header(skb, l3_start);
if (ipv4) {
struct iphdr *ipv4h = ip_hdr(skb);
@ -3329,7 +3333,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
/* Reset and set transport header offset in skb */
skb_set_transport_header(skb, sizeof(struct iphdr));
skb_set_transport_header(skb, l3_start + sizeof(struct iphdr));
len = skb->len - skb_transport_offset(skb);
/* Compute the TCP pseudo header checksum*/
@ -3339,7 +3343,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
skb_set_transport_header(skb, sizeof(struct ipv6hdr));
skb_set_transport_header(skb, l3_start + sizeof(struct ipv6hdr));
len = skb->len - skb_transport_offset(skb);
tcp_hdr(skb)->check =
~tcp_v6_check(len, &ipv6h->saddr, &ipv6h->daddr, 0);
@ -4145,6 +4149,26 @@ static void idpf_vport_intr_ena_irq_all(struct idpf_vport *vport,
writel(rsrc->noirq_dyn_ctl_ena, rsrc->noirq_dyn_ctl);
}
/**
* idpf_vport_intr_dis_dim_all - Disable DIM work for all q_vectors
* @rsrc: pointer to queue and vector resources
*
* The DIM works are embedded in the q_vector array that
* idpf_vport_intr_rel() frees, and the poll arms them after
* napi_complete_done() has already cleared NAPI_STATE_SCHED. Disable
* rather than just cancel, so that a poll tail still running past
* napi_disable() cannot queue them again behind the drain.
*/
static void idpf_vport_intr_dis_dim_all(struct idpf_q_vec_rsrc *rsrc)
{
for (u16 v_idx = 0; v_idx < rsrc->num_q_vectors; v_idx++) {
struct idpf_q_vector *q_vector = &rsrc->q_vectors[v_idx];
disable_work_sync(&q_vector->tx_dim.work);
disable_work_sync(&q_vector->rx_dim.work);
}
}
/**
* idpf_vport_intr_deinit - Release all vector associations for the vport
* @vport: main vport structure
@ -4155,6 +4179,7 @@ void idpf_vport_intr_deinit(struct idpf_vport *vport,
{
idpf_vport_intr_dis_irq_all(rsrc);
idpf_vport_intr_napi_dis_all(rsrc);
idpf_vport_intr_dis_dim_all(rsrc);
idpf_vport_intr_napi_del_all(rsrc);
idpf_vport_intr_rel_irq(vport, rsrc);
}
@ -4235,7 +4260,6 @@ static void idpf_vport_intr_napi_ena_all(struct idpf_q_vec_rsrc *rsrc)
for (u16 q_idx = 0; q_idx < rsrc->num_q_vectors; q_idx++) {
struct idpf_q_vector *q_vector = &rsrc->q_vectors[q_idx];
idpf_init_dim(q_vector);
napi_enable(&q_vector->napi);
}
}
@ -4578,6 +4602,8 @@ int idpf_vport_intr_alloc(struct idpf_vport *vport,
q_coal = &user_config->q_coalesce[v_idx];
q_vector->vport = vport;
idpf_init_dim(q_vector);
q_vector->tx_itr_value = q_coal->tx_coalesce_usecs;
q_vector->tx_intr_mode = q_coal->tx_intr_mode;
q_vector->tx_itr_idx = VIRTCHNL2_ITR_IDX_1;

View File

@ -1417,6 +1417,16 @@ static int mcs_x2p_calibration(struct mcs *mcs)
int i, err = 0;
u64 val;
/* Clear any stale calibration state left by firmware/bootloader.
* Some firmware versions may leave MCSX_MIL_GLOBAL bit 5 set,
* preventing the hardware from detecting the rising edge needed to
* trigger X2P calibration.
*/
val = mcs_reg_read(mcs, MCSX_MIL_GLOBAL);
val &= ~BIT_ULL(5);
mcs_reg_write(mcs, MCSX_MIL_GLOBAL, val);
usleep_range(100, 200);
/* set X2P calibration */
val = mcs_reg_read(mcs, MCSX_MIL_GLOBAL);
val |= BIT_ULL(5);

View File

@ -829,19 +829,25 @@ static int rvu_dbg_rvu_pf_cgx_map_display(struct seq_file *filp, void *unused)
int pf, domain, blkid;
u8 cgx_id, lmac_id;
u16 pcifunc;
u8 start;
domain = 2;
domain = pci_domain_nr(rvu->pdev->bus);
mac_ops = get_mac_ops(rvu_first_cgx_pdata(rvu));
/* There can be no CGX devices at all */
if (!mac_ops)
return 0;
seq_printf(filp, "PCI dev\t\tRVU PF Func\tNIX block\t%s\tLMAC\tCHAN\n",
mac_ops->name);
/* All the PF devices are on contiguous PCI bus numbers, but the PF0(AF)
* may not start from 1 always. Hence get domain and bus from PCI device.
*/
start = rvu->pdev->bus->number;
for (pf = 0; pf < rvu->hw->total_pfs; pf++) {
if (!is_pf_cgxmapped(rvu, pf))
continue;
pdev = pci_get_domain_bus_and_slot(domain, pf + 1, 0);
pdev = pci_get_domain_bus_and_slot(domain, pf + start, 0);
if (!pdev)
continue;

View File

@ -235,13 +235,63 @@ static int otx2_qos_txschq_set_parent_topology(struct otx2_nic *pfvf,
return rc;
}
static int otx2_qos_reset_schq_topology(struct otx2_nic *pfvf, u16 lvl,
u16 schq)
{
struct mbox *mbox = &pfvf->mbox;
struct nix_txschq_config *cfg;
int rc;
if (lvl < NIX_TXSCH_LVL_TL4 || lvl >= NIX_TXSCH_LVL_TL1)
return 0;
mutex_lock(&mbox->lock);
cfg = otx2_mbox_alloc_msg_nix_txschq_cfg(mbox);
if (!cfg) {
mutex_unlock(&mbox->lock);
return -ENOMEM;
}
cfg->lvl = lvl;
cfg->num_regs = 1;
if (lvl == NIX_TXSCH_LVL_TL4)
cfg->reg[0] = NIX_AF_TL4X_TOPOLOGY(schq);
else if (lvl == NIX_TXSCH_LVL_TL3)
cfg->reg[0] = NIX_AF_TL3X_TOPOLOGY(schq);
else if (lvl == NIX_TXSCH_LVL_TL2)
cfg->reg[0] = NIX_AF_TL2X_TOPOLOGY(schq);
cfg->regval[0] = 0;
rc = otx2_sync_mbox_msg(mbox);
mutex_unlock(&mbox->lock);
return rc;
}
static void otx2_qos_free_hw_schq(struct otx2_nic *pfvf, u16 lvl, u16 schq)
{
int err;
err = otx2_qos_reset_schq_topology(pfvf, lvl, schq);
if (err)
netdev_warn(pfvf->netdev,
"QoS: failed to reset topology for schq %u at level %u: %d\n",
schq, lvl, err);
otx2_txschq_free_one(pfvf, lvl, schq);
}
static void otx2_qos_free_hw_node_schq(struct otx2_nic *pfvf,
struct otx2_qos_node *parent)
{
struct otx2_qos_node *node;
list_for_each_entry_reverse(node, &parent->child_schq_list, list)
otx2_txschq_free_one(pfvf, node->level, node->schq);
otx2_qos_free_hw_schq(pfvf, node->level, node->schq);
}
static void otx2_qos_free_hw_node(struct otx2_nic *pfvf,
@ -252,7 +302,7 @@ static void otx2_qos_free_hw_node(struct otx2_nic *pfvf,
list_for_each_entry_safe(node, tmp, &parent->child_list, list) {
otx2_qos_free_hw_node(pfvf, node);
otx2_qos_free_hw_node_schq(pfvf, node);
otx2_txschq_free_one(pfvf, node->level, node->schq);
otx2_qos_free_hw_schq(pfvf, node->level, node->schq);
}
}
@ -266,7 +316,7 @@ static void otx2_qos_free_hw_cfg(struct otx2_nic *pfvf,
otx2_qos_free_hw_node_schq(pfvf, node);
/* free node hw mappings */
otx2_txschq_free_one(pfvf, node->level, node->schq);
otx2_qos_free_hw_schq(pfvf, node->level, node->schq);
mutex_unlock(&pfvf->qos.qos_lock);
}
@ -913,7 +963,7 @@ static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg)
for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
for (idx = 0; idx < cfg->schq[lvl]; idx++) {
schq = cfg->schq_list[lvl][idx];
otx2_txschq_free_one(pfvf, lvl, schq);
otx2_qos_free_hw_schq(pfvf, lvl, schq);
}
}
@ -921,7 +971,7 @@ static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg)
for (idx = 0; idx < cfg->schq_contig[lvl]; idx++) {
if (cfg->schq_index_used[lvl][idx]) {
schq = cfg->schq_contig_list[lvl][idx];
otx2_txschq_free_one(pfvf, lvl, schq);
otx2_qos_free_hw_schq(pfvf, lvl, schq);
}
}
}

View File

@ -4828,7 +4828,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
phy_interface_t phy_mode;
struct phylink *phylink;
struct mtk_mac *mac;
int id, err;
int id, err, i;
int txqs = 1;
u32 val;
@ -4907,8 +4907,8 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
mac->phylink_config.type = PHYLINK_NETDEV;
mac->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
mac->phylink_config.lpi_capabilities = MAC_100FD | MAC_1000FD |
MAC_2500FD;
/* LPI above 1 Gbps is not supported */
mac->phylink_config.lpi_capabilities = MAC_100FD | MAC_1000FD;
mac->phylink_config.lpi_timer_default = 1000;
/* MT7623 gmac0 is now missing its speed-specific PLL configuration
@ -4966,6 +4966,18 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
__set_bit(PHY_INTERFACE_MODE_INTERNAL,
mac->phylink_config.supported_interfaces);
/* LPI wake-up timing is only verified on MTK_GMAC_EEE SoCs */
if (MTK_HAS_CAPS(eth->soc->caps, MTK_GMAC_EEE)) {
phy_interface_copy(mac->phylink_config.lpi_interfaces,
mac->phylink_config.supported_interfaces);
__clear_bit(PHY_INTERFACE_MODE_2500BASEX,
mac->phylink_config.lpi_interfaces);
for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
if (mtk_interface_mode_is_xgmii(eth, i))
__clear_bit(i,
mac->phylink_config.lpi_interfaces);
}
phylink = phylink_create(&mac->phylink_config,
of_fwnode_handle(mac->of_node),
phy_mode, mac_ops);

View File

@ -994,6 +994,7 @@ enum mkt_eth_capabilities {
MTK_U3_COPHY_V2_BIT,
MTK_SRAM_BIT,
MTK_36BIT_DMA_BIT,
MTK_GMAC_EEE_BIT,
/* MUX BITS*/
MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT,
@ -1034,6 +1035,7 @@ enum mkt_eth_capabilities {
#define MTK_U3_COPHY_V2 BIT_ULL(MTK_U3_COPHY_V2_BIT)
#define MTK_SRAM BIT_ULL(MTK_SRAM_BIT)
#define MTK_36BIT_DMA BIT_ULL(MTK_36BIT_DMA_BIT)
#define MTK_GMAC_EEE BIT_ULL(MTK_GMAC_EEE_BIT)
#define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \
BIT_ULL(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT)
@ -1117,7 +1119,7 @@ enum mkt_eth_capabilities {
#define MT7981_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \
MTK_RSTCTRL_PPE1 | MTK_SRAM)
MTK_RSTCTRL_PPE1 | MTK_SRAM | MTK_GMAC_EEE)
#define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \

View File

@ -557,6 +557,7 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)
u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
int sz = MLX5_ST_SZ_BYTES(pplm_reg);
u16 fec_policy_auto = 0;
bool fec_set = false;
int err;
int i;
@ -569,9 +570,6 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)
if (fec_policy >= (1 << MLX5E_FEC_LLRS_272_257_1) && !fec_50g_per_lane)
return -EOPNOTSUPP;
if (fec_policy && !mlx5e_fec_in_caps(dev, fec_policy))
return -EOPNOTSUPP;
MLX5_SET(pplm_reg, in, local_port, 1);
err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
if (err)
@ -591,12 +589,17 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)
mlx5e_get_fec_cap_field(out, &fec_caps, i);
/* policy supported for link speed */
if (fec_caps & conf_fec)
if (fec_caps & conf_fec) {
mlx5e_fec_admin_field(out, &conf_fec, 1, i);
else
/* set FEC to auto*/
fec_set = true;
} else {
/* set FEC to auto */
mlx5e_fec_admin_field(out, &fec_policy_auto, 1, i);
}
}
if (fec_policy && !fec_set)
return -EOPNOTSUPP;
return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1);
}

View File

@ -66,4 +66,8 @@ enum {
MLX5E_FEC_LLRS_272_257_1 = 9,
};
#define MLX5E_FEC_RS_MASK (BIT(MLX5E_FEC_RS_528_514) | \
BIT(MLX5E_FEC_RS_544_514_INTERLEAVED_QUAD) | \
BIT(MLX5E_FEC_RS_544_514))
#endif

View File

@ -311,12 +311,15 @@ sample_restore_get(struct mlx5e_tc_psample *tc_psample, u32 obj_id,
static void
sample_restore_put(struct mlx5e_tc_psample *tc_psample, struct mlx5e_sample_restore *restore)
{
bool last;
mutex_lock(&tc_psample->restore_lock);
if (--restore->count == 0)
last = --restore->count == 0;
if (last)
hash_del(&restore->hlist);
mutex_unlock(&tc_psample->restore_lock);
if (!restore->count) {
if (last) {
mlx5_del_flow_rules(restore->rule);
mlx5_modify_header_dealloc(tc_psample->esw->dev, restore->modify_hdr);
kfree(restore);

View File

@ -148,7 +148,7 @@ static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev,
if (err)
return err;
if (ets->tc_tx_bw[i] < MLX5E_MAX_BW_ALLOC &&
if (priv->dcbx.tc_tsa[i] == IEEE_8021QAZ_TSA_ETS &&
tc_group[i] == (MLX5E_LOWEST_PRIO_GROUP + 1))
is_zero_bw_ets_tc = true;

View File

@ -1002,9 +1002,9 @@ static u32 pplm2ethtool_fec(u_long fec_mode, unsigned long size)
return 0;
}
#define MLX5E_ADVERTISE_SUPPORTED_FEC(mlx5_fec, ethtool_fec) \
#define MLX5E_ADVERTISE_SUPPORTED_FEC(fec_mask, ethtool_fec) \
do { \
if (mlx5e_fec_in_caps(dev, 1 << (mlx5_fec))) \
if (mlx5e_fec_in_caps(dev, fec_mask)) \
__set_bit(ethtool_fec, \
link_ksettings->link_modes.supported);\
} while (0)
@ -1013,6 +1013,7 @@ static const u32 pplm_fec_2_ethtool_linkmodes[] = {
[MLX5E_FEC_NOFEC] = ETHTOOL_LINK_MODE_FEC_NONE_BIT,
[MLX5E_FEC_FIRECODE] = ETHTOOL_LINK_MODE_FEC_BASER_BIT,
[MLX5E_FEC_RS_528_514] = ETHTOOL_LINK_MODE_FEC_RS_BIT,
[MLX5E_FEC_RS_544_514_INTERLEAVED_QUAD] = ETHTOOL_LINK_MODE_FEC_RS_BIT,
[MLX5E_FEC_RS_544_514] = ETHTOOL_LINK_MODE_FEC_RS_BIT,
[MLX5E_FEC_LLRS_272_257_1] = ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
};
@ -1029,13 +1030,13 @@ static int get_fec_supported_advertised(struct mlx5_core_dev *dev,
if (err)
return (err == -EOPNOTSUPP) ? 0 : err;
MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_NOFEC,
MLX5E_ADVERTISE_SUPPORTED_FEC(BIT(MLX5E_FEC_NOFEC),
ETHTOOL_LINK_MODE_FEC_NONE_BIT);
MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_FIRECODE,
MLX5E_ADVERTISE_SUPPORTED_FEC(BIT(MLX5E_FEC_FIRECODE),
ETHTOOL_LINK_MODE_FEC_BASER_BIT);
MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_RS_528_514,
MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_RS_MASK,
ETHTOOL_LINK_MODE_FEC_RS_BIT);
MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_LLRS_272_257_1,
MLX5E_ADVERTISE_SUPPORTED_FEC(BIT(MLX5E_FEC_LLRS_272_257_1),
ETHTOOL_LINK_MODE_FEC_LLRS_BIT);
active_fec_long = active_fec;

View File

@ -56,7 +56,6 @@
#include "lib/vxlan.h"
#define CREATE_TRACE_POINTS
#include "diag/en_rep_tracepoint.h"
#include "diag/reporter_vnic.h"
#include "en_accel/ipsec.h"
#include "en/tc/int_port.h"
#include "en/ptp.h"
@ -1439,51 +1438,6 @@ static unsigned int mlx5e_ul_rep_stats_grps_num(struct mlx5e_priv *priv)
return ARRAY_SIZE(mlx5e_ul_rep_stats_grps);
}
static int
mlx5e_rep_vnic_reporter_diagnose(struct devlink_health_reporter *reporter,
struct devlink_fmsg *fmsg,
struct netlink_ext_ack *extack)
{
struct mlx5e_rep_priv *rpriv = devlink_health_reporter_priv(reporter);
struct mlx5_eswitch_rep *rep = rpriv->rep;
mlx5_reporter_vnic_diagnose_counters(rep->esw->dev, fmsg, rep->vport,
true);
return 0;
}
static const struct devlink_health_reporter_ops mlx5_rep_vnic_reporter_ops = {
.name = "vnic",
.diagnose = mlx5e_rep_vnic_reporter_diagnose,
};
static void mlx5e_rep_vnic_reporter_create(struct mlx5e_priv *priv,
struct devlink_port *dl_port)
{
struct mlx5e_rep_priv *rpriv = priv->ppriv;
struct devlink_health_reporter *reporter;
reporter = devl_port_health_reporter_create(dl_port,
&mlx5_rep_vnic_reporter_ops,
rpriv);
if (IS_ERR(reporter)) {
mlx5_core_err(priv->mdev,
"Failed to create representor vnic reporter, err = %pe\n",
reporter);
return;
}
rpriv->rep_vnic_reporter = reporter;
}
static void mlx5e_rep_vnic_reporter_destroy(struct mlx5e_priv *priv)
{
struct mlx5e_rep_priv *rpriv = priv->ppriv;
if (!IS_ERR_OR_NULL(rpriv->rep_vnic_reporter))
devl_health_reporter_destroy(rpriv->rep_vnic_reporter);
}
static const struct mlx5e_profile mlx5e_rep_profile = {
.init = mlx5e_init_rep,
.cleanup = mlx5e_cleanup_rep,
@ -1607,10 +1561,8 @@ mlx5e_vport_vf_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
dl_port = mlx5_esw_offloads_devlink_port(dev->priv.eswitch,
rpriv->rep->vport);
if (!IS_ERR(dl_port)) {
if (!IS_ERR(dl_port))
SET_NETDEV_DEVLINK_PORT(netdev, dl_port);
mlx5e_rep_vnic_reporter_create(priv, dl_port);
}
err = register_netdev(netdev);
if (err) {
@ -1623,7 +1575,6 @@ mlx5e_vport_vf_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
return 0;
err_detach_netdev:
mlx5e_rep_vnic_reporter_destroy(priv);
mlx5e_detach_netdev(netdev_priv(netdev));
err_cleanup_profile:
priv->profile->cleanup(priv);
@ -1681,7 +1632,6 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep)
}
unregister_netdev(netdev);
mlx5e_rep_vnic_reporter_destroy(priv);
mlx5e_detach_netdev(priv);
priv->profile->cleanup(priv);
mlx5e_destroy_netdev(netdev);

View File

@ -118,7 +118,6 @@ struct mlx5e_rep_priv {
struct rtnl_link_stats64 prev_vf_vport_stats;
struct mlx5_flow_handle *send_to_vport_meta_rule;
struct rhashtable tc_ht;
struct devlink_health_reporter *rep_vnic_reporter;
};
static inline

View File

@ -1199,50 +1199,39 @@ void mlx5e_stats_rmon_get(struct mlx5e_priv *priv,
void mlx5e_stats_ts_get(struct mlx5e_priv *priv,
struct ethtool_ts_stats *ts_stats)
{
int i, j;
u16 nch = mlx5e_stats_nch_read(priv);
int i, tc;
mutex_lock(&priv->state_lock);
ts_stats->pkts = 0;
for (i = 0; i < nch; i++) {
struct mlx5e_channel_stats *channel_stats =
priv->channel_stats[i];
for (tc = 0; tc < priv->max_opened_tc; tc++)
ts_stats->pkts += channel_stats->sq[tc].timestamps;
}
/* Accumulate DMA and port timestamp counters so values stay monotonic
* across channel teardown and mode switches.
*/
if (priv->tx_ptp_opened) {
struct mlx5e_ptp *ptp = priv->channels.ptp;
ts_stats->pkts = 0;
/* Err and Lost stats are only relevant for port timestamping,
* as the DMA layer will always successfully timestamp packets.
*/
ts_stats->err = 0;
ts_stats->lost = 0;
if (!ptp)
goto out;
/* Aggregate stats across all TCs */
for (i = 0; i < ptp->num_tc; i++) {
for (tc = 0; tc < priv->max_opened_tc; tc++) {
struct mlx5e_ptp_cq_stats *stats =
ptp->ptpsq[i].cq_stats;
&priv->ptp_stats.cq[tc];
ts_stats->pkts += stats->cqe;
ts_stats->err += stats->abort + stats->err_cqe +
stats->late_cqe;
stats->late_cqe;
ts_stats->lost += stats->lost_cqe;
}
} else {
/* DMA layer will always successfully timestamp packets. Other
* counters do not make sense for this layer.
*/
ts_stats->pkts = 0;
/* Aggregate stats across all SQs */
for (j = 0; j < priv->channels.num; j++) {
struct mlx5e_channel *c = priv->channels.c[j];
for (i = 0; i < c->num_tc; i++) {
struct mlx5e_sq_stats *stats = c->sq[i].stats;
ts_stats->pkts += stats->timestamps;
}
}
}
out:
mutex_unlock(&priv->state_lock);
}
#define PPORT_PHY_LAYER_OFF(c) \

View File

@ -4,6 +4,26 @@
#include <linux/mlx5/driver.h>
#include "eswitch.h"
#include "devlink.h"
#include "diag/reporter_vnic.h"
static int
mlx5_esw_rep_vnic_reporter_diagnose(struct devlink_health_reporter *reporter,
struct devlink_fmsg *fmsg,
struct netlink_ext_ack *extack)
{
struct mlx5_vport *vport = devlink_health_reporter_priv(reporter);
mlx5_reporter_vnic_diagnose_counters(vport->dev, fmsg, vport->vport,
true);
return 0;
}
static const
struct devlink_health_reporter_ops mlx5_esw_rep_vnic_reporter_ops = {
.name = "vnic",
.diagnose = mlx5_esw_rep_vnic_reporter_diagnose,
};
static void
mlx5_esw_get_port_parent_id(struct mlx5_core_dev *dev, struct netdev_phys_item_id *ppid)
@ -220,6 +240,7 @@ static void mlx5_esw_devlink_port_res_unregister(struct devlink_port *dl_port)
int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
{
struct devlink_health_reporter *reporter;
struct mlx5_core_dev *dev = esw->dev;
const struct devlink_port_ops *ops;
struct mlx5_devlink_port *dl_port;
@ -255,6 +276,16 @@ int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlx
mlx5_core_dbg(dev, "Failed to register port resources: %d\n",
err);
reporter = devl_port_health_reporter_create(
&dl_port->dl_port, &mlx5_esw_rep_vnic_reporter_ops,
vport);
if (IS_ERR(reporter))
mlx5_core_err(dev,
"Failed to create vnic health reporter for vport %d: %pe\n",
vport_num, reporter);
else
dl_port->vnic_reporter = reporter;
return 0;
rate_err:
@ -269,6 +300,12 @@ void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport *vport)
if (!vport->dl_port)
return;
dl_port = vport->dl_port;
if (dl_port->vnic_reporter) {
devl_health_reporter_destroy(dl_port->vnic_reporter);
dl_port->vnic_reporter = NULL;
}
mlx5_esw_devlink_port_res_unregister(&dl_port->dl_port);
devl_rate_leaf_destroy(&dl_port->dl_port);

View File

@ -1040,13 +1040,19 @@ void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
(vport->info.ipsec_crypto_enabled || vport->info.ipsec_packet_enabled))
esw->enabled_ipsec_vf_count--;
/* Clear rx-mode before esw_vport_change_handle_locked(): on
* MLX5_VPORT_PROMISC_CHANGE it calls esw_update_vport_mc_promisc()
* when vport->allmulti_rule is set, repopulating mc_list with FDB
* rules that dangle once the FDB is destroyed. NULL allmulti_rule
* here skips that path.
*/
esw_apply_vport_rx_mode(esw, vport, false, false);
/* We don't assume VFs will cleanup after themselves.
* Calling vport change handler while vport is disabled will cleanup
* the vport resources.
*/
esw_vport_change_handle_locked(vport);
vport->enabled_events = 0;
esw_apply_vport_rx_mode(esw, vport, false, false);
esw_vport_cleanup(esw, vport);
esw->enabled_vports--;

View File

@ -189,6 +189,7 @@ struct mlx5_vport;
struct mlx5_devlink_port {
struct devlink_port dl_port;
struct mlx5_vport *vport;
struct devlink_health_reporter *vnic_reporter;
};
static inline void mlx5_devlink_port_init(struct mlx5_devlink_port *dl_port,

View File

@ -163,12 +163,15 @@ void
mlx5_eswitch_termtbl_put(struct mlx5_eswitch *esw,
struct mlx5_termtbl_handle *tt)
{
bool last;
mutex_lock(&esw->offloads.termtbl_mutex);
if (--tt->ref_count == 0)
last = (--tt->ref_count == 0);
if (last)
hash_del(&tt->termtbl_hlist);
mutex_unlock(&esw->offloads.termtbl_mutex);
if (!tt->ref_count) {
if (last) {
mlx5_del_flow_rules(tt->rule);
mlx5_destroy_flow_table(tt->termtbl);
kfree(tt);

View File

@ -63,14 +63,15 @@ static int get_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags)
return MLX5_LAG_PORT_SELECT_MODE_QUEUE_AFFINITY;
}
static u8 lag_active_port_bits(struct mlx5_lag *ldev)
static u8 lag_active_port_bits(struct mlx5_lag *ldev,
struct lag_tracker *tracker)
{
u8 enabled_ports[MLX5_MAX_PORTS] = {};
u8 active_port = 0;
int num_enabled;
int idx;
mlx5_infer_tx_enabled(&ldev->tracker, ldev, enabled_ports,
mlx5_infer_tx_enabled(tracker, ldev, enabled_ports,
&num_enabled);
for (idx = 0; idx < num_enabled; idx++)
active_port |= BIT_MASK(enabled_ports[idx]);
@ -79,7 +80,8 @@ static u8 lag_active_port_bits(struct mlx5_lag *ldev)
}
static int mlx5_cmd_create_lag(struct mlx5_core_dev *dev, struct mlx5_lag *ldev,
int mode, unsigned long flags)
struct lag_tracker *tracker, int mode,
unsigned long flags)
{
bool fdb_sel_mode = test_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE,
&flags);
@ -108,7 +110,7 @@ static int mlx5_cmd_create_lag(struct mlx5_core_dev *dev, struct mlx5_lag *ldev,
break;
MLX5_SET(lagc, lag_ctx, active_port,
lag_active_port_bits(mlx5_lag_dev(dev)));
lag_active_port_bits(ldev, tracker));
break;
default:
break;
@ -787,7 +789,8 @@ static int mlx5_cmd_modify_active_port(struct mlx5_core_dev *dev, u8 ports)
return mlx5_cmd_exec_in(dev, modify_lag, in);
}
static int _mlx5_modify_lag(struct mlx5_lag *ldev, u8 *ports)
static int _mlx5_modify_lag(struct mlx5_lag *ldev,
struct lag_tracker *tracker, u8 *ports)
{
int idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
struct mlx5_core_dev *dev0;
@ -804,7 +807,7 @@ static int _mlx5_modify_lag(struct mlx5_lag *ldev, u8 *ports)
!MLX5_CAP_PORT_SELECTION(dev0, port_select_flow_table_bypass))
return ret;
active_ports = lag_active_port_bits(ldev);
active_ports = lag_active_port_bits(ldev, tracker);
return mlx5_cmd_modify_active_port(dev0, active_ports);
}
@ -868,7 +871,7 @@ void mlx5_modify_lag(struct mlx5_lag *ldev,
idx = i * ldev->buckets + j;
if (ports[idx] == ldev->v2p_map[idx])
continue;
err = _mlx5_modify_lag(ldev, ports);
err = _mlx5_modify_lag(ldev, tracker, ports);
if (err) {
mlx5_core_err(dev0,
"Failed to modify LAG (%d)\n",
@ -976,7 +979,7 @@ static int mlx5_create_lag(struct mlx5_lag *ldev,
mlx5_core_info(dev0, "shared_fdb:%d mode:%s\n",
shared_fdb, mlx5_get_str_port_sel_mode(mode, flags));
err = mlx5_cmd_create_lag(dev0, ldev, mode, flags);
err = mlx5_cmd_create_lag(dev0, ldev, tracker, mode, flags);
if (err) {
mlx5_core_err(dev0,
"Failed to create LAG (%d)\n",

View File

@ -572,6 +572,38 @@ mlxsw_sp1_ptp_unmatched_remove(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp1_ptp_unmatched_ht_params);
}
/* mlxsw_sp1_ptp_packet_finish() is reached both from the NAPI poll context
* (mlxsw_sp1_ptp_got_packet(), mlxsw_sp1_ptp_got_piece() and
* mlxsw_sp1_packet_timestamp()) and from process context, by way of the GC
* workqueue (mlxsw_sp1_ptp_ht_gc_collect() ->
* mlxsw_sp1_ptp_unmatched_finish()).
*
* mlxsw_sp_rx_listener_no_mark_func() ends in napi_gro_receive(), using the
* NAPI pointer that was placed in the SKB control block when the trapped
* packet was received in the NAPI context. That pointer may only be used
* from its own poll context, which this call site cannot guarantee.
*
* netif_receive_skb(), unlike napi_gro_receive(), can be called from outside
* of the NAPI instance's poll context. RX stats accounting and the skb->dev
* assignment are still preserved; the only change is the delivery call.
*/
static void mlxsw_sp1_ptp_rx_finish(struct mlxsw_sp_port *mlxsw_sp_port,
struct sk_buff *skb)
{
struct mlxsw_sp_port_pcpu_stats *pcpu_stats;
skb->dev = mlxsw_sp_port->dev;
pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats);
u64_stats_update_begin(&pcpu_stats->syncp);
pcpu_stats->rx_packets++;
pcpu_stats->rx_bytes += skb->len;
u64_stats_update_end(&pcpu_stats->syncp);
skb->protocol = eth_type_trans(skb, skb->dev);
netif_receive_skb(skb);
}
/* This function is called in the following scenarios:
*
* 1) When a packet is matched with its timestamp.
@ -600,7 +632,7 @@ static void mlxsw_sp1_ptp_packet_finish(struct mlxsw_sp *mlxsw_sp,
if (ingress) {
if (hwtstamps)
*skb_hwtstamps(skb) = *hwtstamps;
mlxsw_sp_rx_listener_no_mark_func(skb, local_port, mlxsw_sp);
mlxsw_sp1_ptp_rx_finish(mlxsw_sp_port, skb);
} else {
/* skb_tstamp_tx() allows hwtstamps to be NULL. */
skb_tstamp_tx(skb, hwtstamps);

View File

@ -143,9 +143,6 @@ static int ks8851_write_mac_addr(struct net_device *dev)
ks8851_wrreg16(ks, KS_MAR(i), val);
}
if (!netif_running(dev))
ks8851_set_powermode(ks, PMECR_PM_SOFTDOWN);
ks8851_unlock(ks);
return 0;
@ -478,8 +475,7 @@ static int ks8851_net_open(struct net_device *dev)
* @dev: The device being closed.
*
* Called to close down a network device which has been active. Cancel any
* work, shutdown the RX and TX process and then place the chip into a low
* power state whilst it is not being used.
* work and shutdown the RX and TX process.
*/
static int ks8851_net_stop(struct net_device *dev)
{
@ -506,8 +502,6 @@ static int ks8851_net_stop(struct net_device *dev)
/* shutdown TX process */
ks8851_wrreg16(ks, KS_TXCR, 0x0000);
/* set powermode to soft power down to save power */
ks8851_set_powermode(ks, PMECR_PM_SOFTDOWN);
ks8851_unlock(ks);
/* ensure any queued tx buffers are dumped */

View File

@ -208,6 +208,7 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog,
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"XDP: Insufficient memory for tx/rx re-config");
apc->bpf_prog = old_prog;
return err;
}

View File

@ -2986,6 +2986,10 @@ static int mana_alloc_rx_wqe(struct mana_port_context *apc,
*cq_size += COMP_ENTRY_SIZE;
}
/* Reserve an extra slot for Fence completion
* event (CQE_RX_OBJECT_FENCE) in case RX CQ is full.
*/
*cq_size += COMP_ENTRY_SIZE;
return 0;
}
@ -3080,7 +3084,7 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
goto out;
rq_size = MANA_PAGE_ALIGN(rq_size);
cq_size = MANA_PAGE_ALIGN(cq_size);
cq_size = MANA_PAGE_ALIGN(roundup_pow_of_two(cq_size));
/* Create RQ */
memset(&spec, 0, sizeof(spec));
@ -3983,7 +3987,8 @@ static void mana_rdma_service_handle(struct work_struct *work)
struct device *dev = gd->gdma_context->dev;
int ret;
if (READ_ONCE(gd->rdma_teardown))
/* Pairs with the smp_store_release() in mana_rdma_probe(). */
if (smp_load_acquire(&gd->rdma_teardown))
goto out;
switch (serv_work->event) {
@ -4279,6 +4284,21 @@ int mana_rdma_probe(struct gdma_dev *gd)
if (err)
return err;
/* Clear the state left by a previous mana_rdma_remove() so servicing
* events are handled again after a reset cycle.
*/
gd->is_suspended = false;
/* Publish is_suspended before re-opening the gate, so the handler
* cannot observe an open gate with a stale is_suspended. Pairs
* with the smp_load_acquire() in mana_rdma_service_handle(). This
* matters on the reset path, where mana_rdma_remove() closed the
* gate and drained the workqueue; on the initial probe path the
* gate was never closed and both flags are already clear. It does
* not order gd->adev, which add_adev() publishes below.
*/
smp_store_release(&gd->rdma_teardown, false);
err = add_adev(gd, "rdma");
if (err)
mana_gd_deregister_device(gd);

View File

@ -1421,7 +1421,8 @@ static int nfp_net_get_fs_rule(struct nfp_net *nn, struct ethtool_rxnfc *cmd)
return -ENOENT;
}
static int nfp_net_get_fs_loc(struct nfp_net *nn, u32 *rule_locs)
static int nfp_net_get_fs_loc(struct nfp_net *nn, struct ethtool_rxnfc *cmd,
u32 *rule_locs)
{
struct nfp_fs_entry *entry;
u32 count = 0;
@ -1429,8 +1430,12 @@ static int nfp_net_get_fs_loc(struct nfp_net *nn, u32 *rule_locs)
if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FLOW_STEER))
return -EOPNOTSUPP;
list_for_each_entry(entry, &nn->fs.list, node)
list_for_each_entry(entry, &nn->fs.list, node) {
if (count == cmd->rule_cnt)
return -EMSGSIZE;
rule_locs[count++] = entry->loc;
}
cmd->rule_cnt = count;
return 0;
}
@ -1455,7 +1460,7 @@ static int nfp_net_get_rxnfc(struct net_device *netdev,
return nfp_net_get_fs_rule(nn, cmd);
case ETHTOOL_GRXCLSRLALL:
cmd->data = NFP_FS_MAX_ENTRY;
return nfp_net_get_fs_loc(nn, rule_locs);
return nfp_net_get_fs_loc(nn, cmd, rule_locs);
default:
return -EOPNOTSUPP;
}
@ -1698,8 +1703,14 @@ static int nfp_net_fs_add(struct nfp_net *nn, struct ethtool_rxnfc *cmd)
nn->fs.count--;
err = nfp_net_fs_add_hw(nn, new);
if (err)
if (err) {
/* mbox broken, adding the old rule back will
* likely also fail.
*/
list_del(&entry->node);
kfree(entry);
goto err;
}
nn->fs.count++;
list_replace(&entry->node, &new->node);

View File

@ -1672,15 +1672,22 @@ static int ionic_tx(struct net_device *netdev, struct ionic_queue *q,
stats->pkts++;
stats->bytes += skb->len;
ionic_txq_post(q, false);
if (likely(!ionic_txq_hwstamp_enabled(q))) {
struct netdev_queue *ndq = q_to_ndq(netdev, q);
if (unlikely(!ionic_q_has_space(q, MAX_SKB_FRAGS + 1)))
netif_tx_stop_queue(ndq);
netif_txq_maybe_stop(ndq, ionic_q_space_avail(q),
MAX_SKB_FRAGS + 1, MAX_SKB_FRAGS + 1);
ring_dbell = __netdev_tx_sent_queue(ndq, skb->len,
netdev_xmit_more());
}
ionic_txq_post(q, ring_dbell);
if (ring_dbell) {
ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type,
q->dbval | q->head_idx);
q->dbell_jiffies = jiffies;
}
return 0;
}

View File

@ -4454,6 +4454,26 @@ static bool stmmac_tso_valid_packet(struct sk_buff *skb)
header_len + gso_size < 16383;
}
static int stmmac_tso_get_num_desc(struct stmmac_tx_queue *tx_q,
struct sk_buff *skb, u32 pay_len)
{
int i, ndesc = 1;
/* head payload */
ndesc += DIV_ROUND_UP(pay_len, TSO_MAX_BUFF_SIZE);
/* frag payload */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
ndesc += DIV_ROUND_UP(skb_frag_size(frag),
TSO_MAX_BUFF_SIZE);
}
/* MSS update requires a new descriptor */
ndesc += !!(skb_shinfo(skb)->gso_size != tx_q->mss);
return ndesc;
}
/**
* stmmac_tso_xmit - Tx entry point of the driver for oversized frames (TSO)
* @skb : the socket buffer
@ -4497,10 +4517,10 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
struct stmmac_priv *priv = netdev_priv(dev);
unsigned int first_entry, entry, tx_packets;
struct stmmac_txq_stats *txq_stats;
int i, first_tx, nfrags, ndesc;
struct stmmac_tx_queue *tx_q;
bool set_ic, is_last_segment;
u32 pay_len, mss, queue;
int i, first_tx, nfrags;
u8 proto_hdr_len, hdr;
dma_addr_t des;
@ -4513,14 +4533,15 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
/* Compute header lengths */
proto_hdr_len = stmmac_tso_header_size(skb);
pay_len = skb_headlen(skb) - proto_hdr_len; /* no frags */
if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)
hdr = sizeof(struct udphdr);
else
hdr = tcp_hdrlen(skb);
/* Desc availability based on threshold should be enough safe */
if (unlikely(stmmac_tx_avail(priv, queue) <
(((skb->len - proto_hdr_len) / TSO_MAX_BUFF_SIZE + 1)))) {
ndesc = stmmac_tso_get_num_desc(tx_q, skb, pay_len);
if (unlikely(stmmac_tx_avail(priv, queue) < ndesc)) {
if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, queue))) {
netif_tx_stop_queue(netdev_get_tx_queue(priv->dev,
queue));
@ -4532,8 +4553,6 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY;
}
pay_len = skb_headlen(skb) - proto_hdr_len; /* no frags */
mss = skb_shinfo(skb)->gso_size;
/* set new MSS value if needed */
@ -8025,6 +8044,7 @@ static int __stmmac_dvr_probe(struct device *device,
stmmac_napi_add(ndev);
mutex_init(&priv->lock);
rwlock_init(&priv->ptp_lock);
stmmac_fpe_init(priv);

View File

@ -365,7 +365,6 @@ void stmmac_ptp_register(struct stmmac_priv *priv)
if (priv->plat->crosststamp)
priv->ptp_clock_ops.getcrosststamp = stmmac_getcrosststamp;
rwlock_init(&priv->ptp_lock);
mutex_init(&priv->aux_ts_lock);
priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,

View File

@ -1156,11 +1156,10 @@ static void cc2520_remove(struct spi_device *spi)
{
struct cc2520_private *priv = spi_get_drvdata(spi);
mutex_destroy(&priv->buffer_mutex);
flush_work(&priv->fifop_irqwork);
disable_work_sync(&priv->fifop_irqwork);
ieee802154_unregister_hw(priv->hw);
ieee802154_free_hw(priv->hw);
mutex_destroy(&priv->buffer_mutex);
}
static const struct spi_device_id cc2520_ids[] = {

View File

@ -72,6 +72,8 @@ struct hwsim_phy {
struct ieee802154_hw *hw;
u32 idx;
/* Serializes phy->pib_updates. */
spinlock_t pib_lock;
struct hwsim_pib __rcu *pib;
bool suspended;
@ -102,8 +104,6 @@ static int hwsim_update_pib(struct ieee802154_hw *hw, u8 page, u8 channel,
if (!pib)
return -ENOMEM;
pib_old = rtnl_dereference(phy->pib);
pib->page = page;
pib->channel = channel;
pib->filt.short_addr = filt->short_addr;
@ -112,7 +112,10 @@ static int hwsim_update_pib(struct ieee802154_hw *hw, u8 page, u8 channel,
pib->filt.pan_coord = filt->pan_coord;
pib->filt_level = filt_level;
rcu_assign_pointer(phy->pib, pib);
spin_lock_bh(&phy->pib_lock);
pib_old = rcu_replace_pointer(phy->pib, pib,
lockdep_is_held(&phy->pib_lock));
spin_unlock_bh(&phy->pib_lock);
kfree_rcu(pib_old, rcu);
return 0;
}
@ -952,6 +955,7 @@ static int hwsim_add_one(struct genl_info *info, struct device *dev,
goto err_pib;
}
spin_lock_init(&phy->pib_lock);
pib->channel = 13;
pib->filt.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
pib->filt.pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);

View File

@ -288,6 +288,7 @@ __must_hold(&busdevs_lock)
static int mctp_i3c_probe(struct i3c_device *i3c)
{
struct mctp_i3c_bus *b = NULL, *mbus = NULL;
int rc;
/* Look for a known bus */
mutex_lock(&busdevs_lock);
@ -296,14 +297,16 @@ static int mctp_i3c_probe(struct i3c_device *i3c)
mbus = b;
break;
}
mutex_unlock(&busdevs_lock);
if (!mbus) {
/* probably no "mctp-controller" property on the i3c bus */
return -ENODEV;
rc = -ENODEV;
} else {
rc = mctp_i3c_add_device(mbus, i3c);
}
mutex_unlock(&busdevs_lock);
return mctp_i3c_add_device(mbus, i3c);
return rc;
}
static void mctp_i3c_remove_device(struct mctp_i3c_device *mi)

View File

@ -675,7 +675,7 @@ static int net_failover_slave_name_change(struct net_device *slave_dev,
/* We need to bring up the slave after the rename by udev in case
* open failed with EBUSY when it was registered.
*/
dev_open(slave_dev, NULL);
netif_open(slave_dev, NULL);
return 0;
}

View File

@ -1150,6 +1150,9 @@ static int dp83867_led_polarity_set(struct phy_device *phydev, int index,
case PHY_LED_ACTIVE_LOW:
polarity = 0;
break;
case PHY_LED_ACTIVE_HIGH:
polarity = DP83867_LED_POLARITY(index);
break;
default:
return -EINVAL;
}

View File

@ -439,6 +439,9 @@ static int dp83td510_led_polarity_set(struct phy_device *phydev, int index,
case PHY_LED_ACTIVE_LOW:
polarity = 0;
break;
case PHY_LED_ACTIVE_HIGH:
polarity = DP83TD510E_LED_POLARITY(index);
break;
default:
return -EINVAL;
}

View File

@ -62,10 +62,38 @@ static void mtk_gephy_config_init(struct phy_device *phydev)
FIELD_PREP(MTK_MCC_NEARECHO_OFFSET_MASK, 0x3));
}
static int mt7530_phy_probe(struct phy_device *phydev)
{
/* The MT7530 internal GE PHY has broken EEE: with EEE advertised,
* some link partners fail to establish a stable link (on a 2-pair
* cable, 1000BASE-T training fails and the port loops instead of
* falling back). MediaTek recommends disabling EEE on this PHY.
* Clear the advertisement as early as possible, before anything
* can negotiate EEE with the link partner.
*/
return phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
}
static int mt7530_phy_config_init(struct phy_device *phydev)
{
int ret;
mtk_gephy_config_init(phydev);
/* The probe() clear alone is not durable: phy_init_hw() replays only
* ->config_init after a PHY reset, with the register back at its
* EEE-advertising hardware default, and phy_probe() zeroes
* eee_disabled_modes (of_set_phy_eee_broken()) after ->probe already
* ran. Clear the advertisement again and mark EEE disabled, so that
* neither phylib nor userspace can re-enable it; dp83867 disables
* broken EEE from config_init() the same way.
*/
ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
if (ret)
return ret;
phy_disable_eee(phydev);
/* Increase post_update_timer */
phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3,
MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11, 0x4b);
@ -100,6 +128,7 @@ static struct phy_driver mtk_gephy_driver[] = {
{
PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530),
.name = "MediaTek MT7530 PHY",
.probe = mt7530_phy_probe,
.config_init = mt7530_phy_config_init,
/* Interrupts are handled by the switch, not the PHY
* itself.

View File

@ -1630,8 +1630,10 @@ static void phylink_resolve(struct work_struct *w)
if (pl->phylink_disable_state) {
pl->link_failed = false;
link_state = pl->link_config;
link_state.link = false;
} else if (pl->link_failed) {
link_state = pl->link_config;
link_state.link = false;
retrigger = true;
} else if (pl->act_link_an_mode == MLO_AN_FIXED) {

View File

@ -742,11 +742,8 @@ process_input_packet(struct asyncppp *ap)
err:
/* frame had an error, remember that, reset SC_TOSS & SC_ESCAPE */
ap->state = SC_PREV_ERROR;
if (skb) {
/* make skb appear as freshly allocated */
skb_trim(skb, 0);
skb_reserve(skb, - skb_headroom(skb));
}
kfree_skb(skb);
ap->rpkt = NULL;
}
/* Called when the tty driver has data for us. Runs parallel with the

View File

@ -455,17 +455,9 @@ ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb)
/* prepend address/control fields if necessary */
if ((ap->flags & SC_COMP_AC) == 0 || islcp) {
if (skb_headroom(skb) < 2) {
struct sk_buff *npkt = dev_alloc_skb(skb->len + 2);
if (npkt == NULL) {
kfree_skb(skb);
return NULL;
}
skb_reserve(npkt,2);
skb_copy_from_linear_data(skb,
skb_put(npkt, skb->len), skb->len);
consume_skb(skb);
skb = npkt;
if (skb_cow_head(skb, 2)) {
kfree_skb(skb);
return NULL;
}
skb_push(skb,2);
skb->data[0] = PPP_ALLSTATIONS;

View File

@ -282,6 +282,7 @@ static int cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
if (len == 0xffff) {
netdev_info(dev->net, "router was rebooted, re-enabling ethernet mode");
schedule_work(&priv->reenable_work);
return 0;
} else if (len > CX82310_MTU) {
netdev_err(dev->net, "RX packet too long: %d B\n", len);
return 0;

View File

@ -1547,10 +1547,10 @@ hso_wait_modem_status(struct hso_serial *serial, unsigned long arg)
spin_unlock_irq(&serial->serial_lock);
add_wait_queue(&tiocmget->waitq, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irq(&serial->serial_lock);
memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
spin_unlock_irq(&serial->serial_lock);
set_current_state(TASK_INTERRUPTIBLE);
if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) {

View File

@ -1084,6 +1084,7 @@ static const struct usb_device_id products[] = {
},
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0122)}, /* Quectel RG650V */
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x013d)}, /* Quectel RG660QB */
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)}, /* Quectel EM160R-GL */

View File

@ -996,6 +996,12 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
return -EOPNOTSUPP;
}
if (rcu_access_pointer(f->nh) &&
!(state & (NUD_PERMANENT | NUD_NOARP))) {
NL_SET_ERR_MSG(extack, "Cannot make a nexthop fdb dynamic");
return -EOPNOTSUPP;
}
/* Do not allow an externally learned entry to take over an entry added
* by the user.
*/
@ -1257,6 +1263,11 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
if (err)
return err;
if (nhid && !(ndm->ndm_state & (NUD_PERMANENT | NUD_NOARP))) {
NL_SET_ERR_MSG(extack, "A nexthop fdb cannot be dynamic");
return -EINVAL;
}
if (vxlan->default_dst.remote_ip.sa.sa_family != ip.sa.sa_family)
return -EAFNOSUPPORT;
@ -2362,7 +2373,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
struct ip_tunnel_key key;
struct vxlan_dev *vxlan = netdev_priv(dev);
const struct iphdr *old_iph;
struct vxlan_metadata _md;
struct vxlan_metadata _md = {};
struct vxlan_metadata *md = &_md;
unsigned int pkt_len = skb->len;
__be16 src_port = 0, dst_port;

View File

@ -231,6 +231,7 @@ static void ism_free_dmb(struct ism_dev *ism, struct dibs_dmb *dmb)
dma_unmap_page(&ism->pdev->dev, dmb->dma_addr, dmb->dmb_len,
DMA_FROM_DEVICE);
folio_put(virt_to_folio(dmb->cpu_addr));
dmb->cpu_addr = NULL;
}
static int ism_alloc_dmb(struct ism_dev *ism, struct dibs_dmb *dmb)
@ -274,7 +275,8 @@ static int ism_alloc_dmb(struct ism_dev *ism, struct dibs_dmb *dmb)
return 0;
out_free:
kfree(dmb->cpu_addr);
folio_put(folio);
dmb->cpu_addr = NULL;
out_bit:
clear_bit(dmb->idx, ism->sba_bitmap);
return rc;

View File

@ -13,7 +13,8 @@ extern const struct attribute_group *qeth_l2_attr_groups[];
int qeth_bridgeport_query_ports(struct qeth_card *card,
enum qeth_sbp_roles *role,
enum qeth_sbp_states *state);
enum qeth_sbp_states *state,
bool *os_mismatch);
int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role);
int qeth_bridgeport_an_set(struct qeth_card *card, int enable);

View File

@ -1158,7 +1158,7 @@ static void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card)
qeth_bridgeport_setrole(card, card->options.sbp.role);
/* Let the callback function refresh the stored role value. */
qeth_bridgeport_query_ports(card, &card->options.sbp.role,
NULL);
NULL, NULL);
}
if (card->options.sbp.hostnotification) {
if (qeth_bridgeport_an_set(card, 1))
@ -1545,6 +1545,7 @@ struct _qeth_sbp_cbctl {
struct {
enum qeth_sbp_roles *role;
enum qeth_sbp_states *state;
bool *os_mismatch;
} qports;
} data;
};
@ -1721,10 +1722,19 @@ static int qeth_bridgeport_query_ports_cb(struct qeth_card *card,
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
struct qeth_sbp_port_data *qports;
u16 sbp_rc;
int rc;
QETH_CARD_TEXT(card, 2, "brqprtcb");
rc = qeth_bridgeport_makerc(card, cmd);
sbp_rc = cmd->data.sbp.hdr.return_code;
/* on OS family mismatch, query still returns valid port data;
* treat as success
*/
if (sbp_rc == IPA_RC_SBP_IQD_OS_MISMATCH && !cmd->hdr.return_code)
rc = 0;
else
rc = qeth_bridgeport_makerc(card, cmd);
if (rc)
return rc;
@ -1740,6 +1750,9 @@ static int qeth_bridgeport_query_ports_cb(struct qeth_card *card,
if (cbctl->data.qports.state)
*cbctl->data.qports.state = qports->entry[0].state;
}
if (cbctl->data.qports.os_mismatch)
*cbctl->data.qports.os_mismatch =
(sbp_rc == IPA_RC_SBP_IQD_OS_MISMATCH);
return 0;
}
@ -1748,13 +1761,17 @@ static int qeth_bridgeport_query_ports_cb(struct qeth_card *card,
* @card: qeth_card structure pointer.
* @role: Role of the port: 0-none, 1-primary, 2-secondary.
* @state: State of the port: 0-inactive, 1-standby, 2-active.
* @os_mismatch: if non-NULL, set to true when firmware reports
* OS family mismatch.
*
* Returns negative errno-compatible error indication or 0 on success.
*
* 'role' and 'state' are not updated in case of hardware operation failure.
* 'role', 'state' and 'os_mismatch' are not updated in case of
* hardware operation failure.
*/
int qeth_bridgeport_query_ports(struct qeth_card *card,
enum qeth_sbp_roles *role, enum qeth_sbp_states *state)
enum qeth_sbp_roles *role, enum qeth_sbp_states *state,
bool *os_mismatch)
{
struct qeth_cmd_buffer *iob;
struct _qeth_sbp_cbctl cbctl = {
@ -1762,6 +1779,7 @@ int qeth_bridgeport_query_ports(struct qeth_card *card,
.qports = {
.role = role,
.state = state,
.os_mismatch = os_mismatch,
},
},
};

View File

@ -15,6 +15,7 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
enum qeth_sbp_states state = QETH_SBP_STATE_INACTIVE;
bool os_mismatch = false;
int rc = 0;
char *word;
@ -25,7 +26,7 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
if (qeth_card_hw_is_reachable(card) &&
card->options.sbp.supported_funcs)
rc = qeth_bridgeport_query_ports(card,
&card->options.sbp.role, &state);
&card->options.sbp.role, &state, &os_mismatch);
if (!rc) {
if (show_state)
switch (state) {
@ -52,6 +53,10 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
if (rc)
QETH_CARD_TEXT_(card, 2, "SBP%02x:%02x",
card->options.sbp.role, state);
else if (!show_state &&
card->options.sbp.role == QETH_SBP_ROLE_NONE &&
os_mismatch)
rc = sysfs_emit(buf, "%s (OS family mismatch)\n", word);
else
rc = sysfs_emit(buf, "%s\n", word);
}

View File

@ -1057,6 +1057,12 @@ struct kernel_ethtool_ts_info {
* @get_sset_count: Get number of strings that @get_strings will write.
* @get_rxnfc: Get RX flow classification rules. Returns a negative
* error code or zero.
* Note that for %ETHTOOL_GRXCLSRLALL rule_cnt and size of the arrays
* is user-provided, and not guaranteed to match what driver would
* have reported via %ETHTOOL_GRXCLSRLCNT. Drivers must return -%EMSGSIZE
* when rule_cnt is too small. rule_locs is %NULL when rule_cnt is zero.
* On success drivers must set rule_cnt to the number of locations they
* filled in, the core copies out exactly that many.
* @set_rxnfc: Set RX flow classification rules. Returns a negative
* error code or zero.
* @flash_device: Write a firmware image to device's flash memory.

View File

@ -56,23 +56,4 @@ void arpt_unregister_table(struct net *net, const char *name);
extern unsigned int arpt_do_table(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state);
#ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h>
struct compat_arpt_entry {
struct arpt_arp arp;
__u16 target_offset;
__u16 next_offset;
compat_uint_t comefrom;
struct compat_xt_counters counters;
unsigned char elems[];
};
static inline struct xt_entry_target *
compat_arpt_get_target(struct compat_arpt_entry *e)
{
return (void *)e + e->target_offset;
}
#endif /* CONFIG_COMPAT */
#endif /* _ARPTABLES_H */

View File

@ -376,6 +376,7 @@ struct cfg802154_mac_pkt {
struct list_head node;
struct sk_buff *skb;
struct ieee802154_sub_if_data *sdata;
netdevice_tracker dev_tracker;
u8 page;
u8 channel;
};

View File

@ -384,6 +384,8 @@ static inline unsigned int ip6_dst_mtu_maybe_forward(const struct dst_entry *dst
rcu_read_unlock();
out:
mtu = min_t(unsigned int, mtu, IP6_MAX_MTU);
return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
}

View File

@ -793,7 +793,7 @@ void qdisc_offload_query_caps(struct net_device *dev,
struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
const struct Qdisc_ops *ops,
struct netlink_ext_ack *extack);
void qdisc_free(struct Qdisc *qdisc);
void qdisc_free_rcu(struct Qdisc *qdisc);
struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
const struct Qdisc_ops *ops, u32 parentid,
struct netlink_ext_ack *extack);

View File

@ -15,7 +15,7 @@
* @__nhc: variable name of the lowpan_nhc struct.
* @_name: const char * of common header compression name.
* @_nexthdr: ipv6 nexthdr field for the header compression.
* @_nexthdrlen: ipv6 nexthdr len for the reserved space.
* @_hdrlen: ipv6 nexthdr len for the reserved space.
* @_id: one byte nhc id value.
* @_idmask: one byte nhc id mask value.
* @_uncompress: callback for uncompression call.
@ -102,7 +102,6 @@ int lowpan_nhc_do_compression(struct sk_buff *skb, const struct ipv6hdr *hdr,
/**
* lowpan_nhc_do_uncompression - calling uncompress callback for nhc
*
* @nhc: 6LoWPAN nhc context, get by lowpan_nhc_by_ functions.
* @skb: skb of 6LoWPAN header, skb->data should be pointed to nhc id value.
* @dev: netdevice for print logging information.
* @hdr: ipv6hdr for setting nexthdr value.

View File

@ -4797,6 +4797,24 @@ static int hci_le_set_def_rate_sync(struct hci_dev *hdev)
cp.cont_num = cpu_to_le16(0x0001);
cp.supv_timeout = cpu_to_le16(0x000c); /* 120 ms */
/* The connection event length recommended in requests by a Peripheral
* uses units of 125 us with a valid range of 0x0001 to 0x7CFF
* (0.125 ms to 3.999875 s), so 0x0000 cannot be used. Also note that
* the Controller is not required to use these values:
*
* BLUETOOTH CORE SPECIFICATION Version 6.2 | Vol 4, Part E
* 7.8.158. LE Set Default Rate Parameters command
*
* The Min_CE_Length and Max_CE_Length parameters provide the
* Controller with the expected minimum and maximum length of the
* connection events. The Controller is not required to use these
* values.
*
* So it is safe to just use the minimum.
*/
cp.min_ce_len = cpu_to_le16(0x0001);
cp.max_ce_len = cpu_to_le16(0x0001);
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_DEF_RATE,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}
@ -7466,8 +7484,24 @@ static int hci_le_conn_rate_request_sync(struct hci_dev *hdev, void *data)
cp.max_latency = cpu_to_le16(params->max_latency);
cp.cont_num = cpu_to_le16(params->cont_num);
cp.supv_timeout = cpu_to_le16(params->rate_supv_timeout);
cp.min_ce_len = cpu_to_le16(0x0000);
cp.max_ce_len = cpu_to_le16(0x0000);
/* The connection event length recommended in requests by a Peripheral
* uses units of 125 us with a valid range of 0x0001 to 0x7CFF
* (0.125 ms to 3.999875 s), so 0x0000 cannot be used. Also note that
* the Controller is not required to use these values:
*
* BLUETOOTH CORE SPECIFICATION Version 6.2 | Vol 4, Part E
* 7.8.157. LE Connection Rate Request command
*
* The Min_CE_Length and Max_CE_Length parameters provide the
* Controller with the expected minimum and maximum length of the
* connection events. The Controller is not required to use these
* values.
*
* So it is safe to just use the minimum.
*/
cp.min_ce_len = cpu_to_le16(0x0001);
cp.max_ce_len = cpu_to_le16(0x0001);
hci_dev_unlock(hdev);

View File

@ -13,7 +13,10 @@ static const struct class bt_class = {
static void bt_link_release(struct device *dev)
{
struct hci_conn *conn = to_hci_conn(dev);
struct device *parent = dev->parent;
kfree(conn);
put_device(parent);
}
static const struct device_type bt_link = {
@ -21,6 +24,16 @@ static const struct device_type bt_link = {
.release = bt_link_release,
};
/*
* The rfcomm tty device will possibly retain even when conn
* is down, and sysfs doesn't support move zombie device,
* so we should move the device before conn device is destroyed.
*/
static int __match_tty(struct device *dev, const void *data)
{
return !strncmp(dev_name(dev), "rfcomm", 6);
}
void hci_conn_init_sysfs(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
@ -29,7 +42,7 @@ void hci_conn_init_sysfs(struct hci_conn *conn)
conn->dev.type = &bt_link;
conn->dev.class = &bt_class;
conn->dev.parent = &hdev->dev;
conn->dev.parent = get_device(&hdev->dev);
device_initialize(&conn->dev);
}
@ -69,7 +82,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
while (1) {
struct device *dev;
dev = device_find_any_child(&conn->dev);
dev = device_find_child(&conn->dev, NULL, __match_tty);
if (!dev)
break;
device_move(dev, NULL, DPM_ORDER_DEV_LAST);

View File

@ -367,7 +367,7 @@ static u32 ccm_tlv_extract(struct sk_buff *skb, u32 index,
}
/* note: already called with rcu_read_lock */
static int br_cfm_frame_rx(struct net_bridge_port *port, struct sk_buff *skb)
int br_cfm_frame_rx(struct net_bridge_port *port, struct sk_buff *skb)
{
u32 mdlevel, interval, size, index, max;
const struct br_cfm_common_hdr *hdr;
@ -489,11 +489,6 @@ static int br_cfm_frame_rx(struct net_bridge_port *port, struct sk_buff *skb)
return 1;
}
static struct br_frame_type cfm_frame_type __read_mostly = {
.type = cpu_to_be16(ETH_P_CFM),
.frame_handler = br_cfm_frame_rx,
};
int br_cfm_mep_create(struct net_bridge *br,
const u32 instance,
struct br_cfm_mep_create *const create,
@ -559,7 +554,7 @@ int br_cfm_mep_create(struct net_bridge *br,
INIT_DELAYED_WORK(&mep->ccm_tx_dwork, ccm_tx_work_expired);
if (hlist_empty(&br->mep_list))
br_add_frame(br, &cfm_frame_type);
br_opt_toggle(br, BROPT_CFM_ENABLED, true);
hlist_add_tail_rcu(&mep->head, &br->mep_list);
@ -588,7 +583,7 @@ static void mep_delete_implementation(struct net_bridge *br,
kfree_rcu(mep, rcu);
if (hlist_empty(&br->mep_list))
br_del_frame(br, &cfm_frame_type);
br_opt_toggle(br, BROPT_CFM_ENABLED, false);
}
int br_cfm_mep_delete(struct net_bridge *br,

View File

@ -503,7 +503,6 @@ void br_dev_setup(struct net_device *dev)
spin_lock_init(&br->lock);
INIT_LIST_HEAD(&br->port_list);
INIT_HLIST_HEAD(&br->fdb_list);
INIT_HLIST_HEAD(&br->frame_type_list);
#if IS_ENABLED(CONFIG_BRIDGE_MRP)
INIT_HLIST_HEAD(&br->mrp_list);
#endif

View File

@ -317,17 +317,25 @@ static int nf_hook_bridge_pre(struct sk_buff *skb, struct sk_buff **pskb)
return RX_HANDLER_CONSUMED;
}
#define BR_CFM_MRP_OPTS \
((IS_ENABLED(CONFIG_BRIDGE_CFM) ? BIT(BROPT_CFM_ENABLED) : 0UL) | \
(IS_ENABLED(CONFIG_BRIDGE_MRP) ? BIT(BROPT_MRP_ENABLED) : 0UL))
/* Return 0 if the frame was not processed otherwise 1
* note: already called with rcu_read_lock
*/
static int br_process_frame_type(struct net_bridge_port *p,
struct sk_buff *skb)
{
struct br_frame_type *tmp;
struct net_bridge *br = p->br;
hlist_for_each_entry_rcu(tmp, &p->br->frame_type_list, list)
if (unlikely(tmp->type == skb->protocol))
return tmp->frame_handler(p, skb);
if (skb->protocol == htons(ETH_P_CFM) &&
br_opt_get(br, BROPT_CFM_ENABLED))
return br_cfm_frame_rx(p, skb);
if (skb->protocol == htons(ETH_P_MRP) &&
br_opt_get(br, BROPT_MRP_ENABLED))
return br_mrp_process(p, skb);
return 0;
}
@ -425,7 +433,8 @@ static rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
}
}
if (unlikely(br_process_frame_type(p, skb)))
if (unlikely((READ_ONCE(p->br->options) & BR_CFM_MRP_OPTS) &&
br_process_frame_type(p, skb)))
return RX_HANDLER_PASS;
forward:
@ -467,19 +476,3 @@ rx_handler_func_t *br_get_rx_handler(const struct net_device *dev)
return br_handle_frame;
}
void br_add_frame(struct net_bridge *br, struct br_frame_type *ft)
{
hlist_add_head_rcu(&ft->list, &br->frame_type_list);
}
void br_del_frame(struct net_bridge *br, struct br_frame_type *ft)
{
struct br_frame_type *tmp;
hlist_for_each_entry(tmp, &br->frame_type_list, list)
if (ft == tmp) {
hlist_del_rcu(&ft->list);
return;
}
}

View File

@ -6,13 +6,6 @@
static const u8 mrp_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x1 };
static const u8 mrp_in_test_dmac[ETH_ALEN] = { 0x1, 0x15, 0x4e, 0x0, 0x0, 0x3 };
static int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb);
static struct br_frame_type mrp_frame_type __read_mostly = {
.type = cpu_to_be16(ETH_P_MRP),
.frame_handler = br_mrp_process,
};
static bool br_mrp_is_ring_port(struct net_bridge_port *p_port,
struct net_bridge_port *s_port,
struct net_bridge_port *port)
@ -486,7 +479,7 @@ static void br_mrp_del_impl(struct net_bridge *br, struct br_mrp *mrp)
kfree_rcu(mrp, rcu);
if (hlist_empty(&br->mrp_list))
br_del_frame(br, &mrp_frame_type);
br_opt_toggle(br, BROPT_MRP_ENABLED, false);
}
/* Adds a new MRP instance.
@ -536,7 +529,7 @@ int br_mrp_add(struct net_bridge *br, struct br_mrp_instance *instance)
rcu_assign_pointer(mrp->s_port, p);
if (hlist_empty(&br->mrp_list))
br_add_frame(br, &mrp_frame_type);
br_opt_toggle(br, BROPT_MRP_ENABLED, true);
INIT_DELAYED_WORK(&mrp->test_work, br_mrp_test_work_expired);
INIT_DELAYED_WORK(&mrp->in_test_work, br_mrp_in_test_work_expired);
@ -1241,7 +1234,7 @@ static int br_mrp_rcv(struct net_bridge_port *p,
* normal forwarding.
* note: already called with rcu_read_lock
*/
static int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb)
int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb)
{
/* If there is no MRP instance do normal forwarding */
if (likely(!test_bit(BR_MRP_AWARE_BIT, &p->flags)))

View File

@ -1441,16 +1441,17 @@ struct net_bridge_port_group *br_multicast_new_port_group(
goto free_out;
}
rcu_assign_pointer(p->next, next);
timer_setup(&p->timer, br_multicast_port_group_expired, 0);
timer_setup(&p->rexmit_timer, br_multicast_port_group_rexmit, 0);
hlist_add_head(&p->mglist, &port->mglist);
if (src)
memcpy(p->eth_addr, src, ETH_ALEN);
else
eth_broadcast_addr(p->eth_addr);
RCU_INIT_POINTER(p->next, next);
hlist_add_head_rcu(&p->mglist, &port->mglist);
return p;
free_out:
@ -1465,11 +1466,11 @@ void br_multicast_del_port_group(struct net_bridge_port_group *p)
struct net_bridge_port *port = p->key.port;
__u16 vid = p->key.addr.vid;
hlist_del_init(&p->mglist);
hlist_del_init_rcu(&p->mglist);
if (!br_multicast_is_star_g(&p->key.addr))
rhashtable_remove_fast(&port->br->sg_port_tbl, &p->rhnode,
br_sg_port_rht_params);
kfree(p);
kfree_rcu(p, rcu);
br_multicast_port_ngroups_dec(port, vid);
}

View File

@ -495,12 +495,13 @@ enum net_bridge_opts {
BROPT_MST_ENABLED,
BROPT_MDB_OFFLOAD_FAIL_NOTIFICATION,
BROPT_FDB_LOCAL_VLAN_0,
BROPT_CFM_ENABLED,
BROPT_MRP_ENABLED,
};
struct net_bridge {
spinlock_t lock;
spinlock_t hash_lock;
struct hlist_head frame_type_list;
struct net_device *dev;
unsigned long options;
/* These fields are accessed on each packet */
@ -932,16 +933,6 @@ int nbp_backup_change(struct net_bridge_port *p, struct net_device *backup_dev);
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb);
rx_handler_func_t *br_get_rx_handler(const struct net_device *dev);
struct br_frame_type {
__be16 type;
int (*frame_handler)(struct net_bridge_port *port,
struct sk_buff *skb);
struct hlist_node list;
};
void br_add_frame(struct net_bridge *br, struct br_frame_type *ft);
void br_del_frame(struct net_bridge *br, struct br_frame_type *ft);
static inline bool br_rx_handler_check_rcu(const struct net_device *dev)
{
return rcu_dereference(dev->rx_handler) == br_get_rx_handler(dev);
@ -2080,6 +2071,7 @@ int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
bool br_mrp_enabled(struct net_bridge *br);
void br_mrp_port_del(struct net_bridge *br, struct net_bridge_port *p);
int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br);
int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb);
#else
static inline int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p,
struct nlattr *attr, int cmd,
@ -2103,6 +2095,11 @@ static inline int br_mrp_fill_info(struct sk_buff *skb, struct net_bridge *br)
return 0;
}
static inline int br_mrp_process(struct net_bridge_port *p, struct sk_buff *skb)
{
return 0;
}
#endif
/* br_cfm.c */
@ -2111,6 +2108,7 @@ int br_cfm_parse(struct net_bridge *br, struct net_bridge_port *p,
struct nlattr *attr, int cmd, struct netlink_ext_ack *extack);
bool br_cfm_created(struct net_bridge *br);
void br_cfm_port_del(struct net_bridge *br, struct net_bridge_port *p);
int br_cfm_frame_rx(struct net_bridge_port *port, struct sk_buff *skb);
int br_cfm_config_fill_info(struct sk_buff *skb, struct net_bridge *br);
int br_cfm_status_fill_info(struct sk_buff *skb,
struct net_bridge *br,
@ -2135,6 +2133,12 @@ static inline void br_cfm_port_del(struct net_bridge *br,
{
}
static inline int br_cfm_frame_rx(struct net_bridge_port *port,
struct sk_buff *skb)
{
return 0;
}
static inline int br_cfm_config_fill_info(struct sk_buff *skb, struct net_bridge *br)
{
return -EOPNOTSUPP;

View File

@ -9982,7 +9982,7 @@ int netif_change_tx_queue_len(struct net_device *dev, unsigned long new_len)
unsigned int orig_len = dev->tx_queue_len;
int res;
if (new_len != (unsigned int)new_len)
if (new_len > S16_MAX)
return -ERANGE;
if (new_len != orig_len) {

View File

@ -2287,6 +2287,11 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
return -EMSGSIZE;
}
static const struct netlink_range_validation txqlen_range = {
.min = 0,
.max = S16_MAX,
};
static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_UNSPEC] = { .strict_start_type = IFLA_DPLL_PIN },
[IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 },
@ -2297,7 +2302,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_LINK] = { .type = NLA_U32 },
[IFLA_MASTER] = { .type = NLA_U32 },
[IFLA_CARRIER] = { .type = NLA_U8 },
[IFLA_TXQLEN] = { .type = NLA_U32 },
[IFLA_TXQLEN] = NLA_POLICY_FULL_RANGE(NLA_U32, &txqlen_range),
[IFLA_WEIGHT] = { .type = NLA_U32 },
[IFLA_OPERSTATE] = { .type = NLA_U8 },
[IFLA_LINKMODE] = { .type = NLA_U8 },

View File

@ -6690,6 +6690,13 @@ int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto, int mac_len,
}
skb->protocol = next_proto;
/* The last label is gone, so the inner header recorded by
* skb_mpls_push() no longer describes this packet. Drop it, or a
* later push keeps the stale offset.
*/
if (!eth_p_mpls(next_proto))
skb->inner_protocol = 0;
return 0;
}
EXPORT_SYMBOL_GPL(skb_mpls_pop);

View File

@ -373,6 +373,7 @@ static const struct dsa_device_ops brcm_legacy_fcs_netdev_ops = {
.xmit = brcm_leg_fcs_tag_xmit,
.rcv = brcm_leg_tag_rcv,
.needed_headroom = BRCM_LEG_TAG_LEN,
.needed_tailroom = ETH_FCS_LEN,
};
DSA_TAG_DRIVER(brcm_legacy_fcs_netdev_ops);

View File

@ -149,9 +149,12 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev,
int res;
/* Don't use promiscuous mode for offload since L2 frame forward
* happens at the offloaded hardware.
* happens at the offloaded hardware. The interlink port never
* gets forwarding offload (RedBox forwarding to/from it is done
* by this driver), so it still needs promiscuous mode to receive
* frames addressed to hsr_dev's MAC rather than its own.
*/
if (!port->hsr->fwd_offloaded) {
if (!port->hsr->fwd_offloaded || port->type == HSR_PT_INTERLINK) {
res = dev_set_promiscuity(dev, 1);
if (res)
return res;
@ -176,7 +179,7 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev,
fail_rx_handler:
netdev_upper_dev_unlink(dev, hsr_dev);
fail_upper_dev_link:
if (!port->hsr->fwd_offloaded)
if (!port->hsr->fwd_offloaded || port->type == HSR_PT_INTERLINK)
dev_set_promiscuity(dev, -1);
return res;
@ -240,7 +243,7 @@ void hsr_del_port(struct hsr_port *port)
netdev_update_features(master->dev);
dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
netdev_rx_handler_unregister(port->dev);
if (!port->hsr->fwd_offloaded)
if (!port->hsr->fwd_offloaded || port->type == HSR_PT_INTERLINK)
dev_set_promiscuity(port->dev, -1);
if (port->type == HSR_PT_SLAVE_A || port->type == HSR_PT_SLAVE_B)
vlan_vids_del_by_dev(port->dev, master->dev);

Some files were not shown because too many files have changed in this diff Show More