diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2026-08-18 10:30:20 -0700 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-08-18 10:30:21 -0700 |
| commit | f28ceedbfdf695ff2f0db9d85bb91da2770f2b15 (patch) | |
| tree | 214996c0ccba0f4f7597cdd0146d194e7df94e02 | |
| parent | b4a8e1fae5173cf7a8e81f20027cafef074f3bb1 (diff) | |
| parent | f6a48a7b10be44c470f5ce1037ebaaf343f384f7 (diff) | |
Merge tag 'linux-can-next-for-7.3-20260818' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next
Marc Kleine-Budde says:
====================
pull-request: can-next 2026-08-18
The first patch is by Sean Nyekjaer, targets the tcan4x5x driver and
puts the device into sleep mode before removing the driver.
Pavel Pisa's patch fixes the colors in the documentation of the TX
buffer FSM of CTU CAN FD driver.
2 patches by Cunhao Lu add support for the rockchip 3588 SoC to the
rockchip CAN-FD driver.
Kuniyuki Iwashima contributes per-netns device unregistration for the
vxcan driver.
Eduard Bostina converts the TI HECC DT bindings doc to DT schema.
Harini T contributes 2 patches to the xilinx_can driver to document
phys and update maintainer.
A patch by bui duc phuc converts the m_can driver to use
of_property_present() for wakeup-source.
Fanbo He's patch fixes a typo in the gs_usb driver.
The last patch is by Markus Schneider-Pargmann and removed not needed
driver_data from the m_can PCI driver.
* tag 'linux-can-next-for-7.3-20260818' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next:
can: m_can: pci: Remove driver_data
drivers: gs_usb: gs_usb_probe(): fix typo in error message
can: m_can: Use of_property_present() for wakeup-source
dt-bindings: can: xilinx_can: Document phys property
dt-bindings: net: can: Convert TI HECC to DT schema
MAINTAINERS: Replace maintainer for Xilinx CAN driver
can: vxcan: support per-netns device unregistration.
docs: ctucanfd: fix swapped colors in legend for TX buffer FSM of CTU CAN FD
can: rockchip: add RK3588 CAN support
dt-bindings: can: rockchip: add rk3588 CAN-FD compatible
can: tcan4x5x: put tcan into sleep when removing driver
====================
Link: https://patch.msgid.link/20260817233420.2068204-1-mkl@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | Documentation/devicetree/bindings/net/can/rockchip,rk3568v2-canfd.yaml | 4 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/net/can/ti,am3517-hecc.yaml | 64 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/net/can/ti_hecc.txt | 32 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/net/can/xilinx,can.yaml | 5 | ||||
| -rw-r--r-- | Documentation/networking/device_drivers/can/ctu/fsm_txt_buffer_user.svg | 4 | ||||
| -rw-r--r-- | MAINTAINERS | 2 | ||||
| -rw-r--r-- | drivers/net/can/m_can/m_can.c | 2 | ||||
| -rw-r--r-- | drivers/net/can/m_can/m_can_pci.c | 6 | ||||
| -rw-r--r-- | drivers/net/can/m_can/tcan4x5x-core.c | 31 | ||||
| -rw-r--r-- | drivers/net/can/rockchip/rockchip_canfd-core.c | 17 | ||||
| -rw-r--r-- | drivers/net/can/rockchip/rockchip_canfd-rx.c | 5 | ||||
| -rw-r--r-- | drivers/net/can/rockchip/rockchip_canfd.h | 14 | ||||
| -rw-r--r-- | drivers/net/can/usb/gs_usb.c | 2 | ||||
| -rw-r--r-- | drivers/net/can/vxcan.c | 26 |
14 files changed, 155 insertions, 59 deletions
diff --git a/Documentation/devicetree/bindings/net/can/rockchip,rk3568v2-canfd.yaml b/Documentation/devicetree/bindings/net/can/rockchip,rk3568v2-canfd.yaml index a077c0330013..81e2b6dfeb02 100644 --- a/Documentation/devicetree/bindings/net/can/rockchip,rk3568v2-canfd.yaml +++ b/Documentation/devicetree/bindings/net/can/rockchip,rk3568v2-canfd.yaml @@ -16,7 +16,9 @@ allOf: properties: compatible: oneOf: - - const: rockchip,rk3568v2-canfd + - enum: + - rockchip,rk3568v2-canfd + - rockchip,rk3588-canfd - items: - const: rockchip,rk3568v3-canfd - const: rockchip,rk3568v2-canfd diff --git a/Documentation/devicetree/bindings/net/can/ti,am3517-hecc.yaml b/Documentation/devicetree/bindings/net/can/ti,am3517-hecc.yaml new file mode 100644 index 000000000000..7874e9e49224 --- /dev/null +++ b/Documentation/devicetree/bindings/net/can/ti,am3517-hecc.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/can/ti,am3517-hecc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments High End CAN Controller (HECC) + +maintainers: + - Eduard Bostina <egbostina@gmail.com> + +allOf: + - $ref: can-controller.yaml# + +properties: + compatible: + const: ti,am3517-hecc + + reg: + maxItems: 3 + + reg-names: + items: + - const: hecc + - const: hecc-ram + - const: mbx + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + ti,use-hecc1int: + type: boolean + description: + If provided, configures HECC to produce all interrupts on the + HECC1INT interrupt line. By default, the HECC0INT interrupt line + will be used. + default: false + + xceiver-supply: + description: Regulator that powers the CAN transceiver. + +required: + - compatible + - reg + - reg-names + - interrupts + - clocks + +unevaluatedProperties: false + +examples: + - | + can@5c050000 { + compatible = "ti,am3517-hecc"; + reg = <0x5c050000 0x80>, + <0x5c053000 0x180>, + <0x5c052000 0x200>; + reg-names = "hecc", "hecc-ram", "mbx"; + interrupts = <24>; + clocks = <&hecc_ck>; + }; diff --git a/Documentation/devicetree/bindings/net/can/ti_hecc.txt b/Documentation/devicetree/bindings/net/can/ti_hecc.txt deleted file mode 100644 index e0f0a7cfe329..000000000000 --- a/Documentation/devicetree/bindings/net/can/ti_hecc.txt +++ /dev/null @@ -1,32 +0,0 @@ -Texas Instruments High End CAN Controller (HECC) -================================================ - -This file provides information, what the device node -for the hecc interface contains. - -Required properties: -- compatible: "ti,am3517-hecc" -- reg: addresses and lengths of the register spaces for 'hecc', 'hecc-ram' - and 'mbx' -- reg-names :"hecc", "hecc-ram", "mbx" -- interrupts: interrupt mapping for the hecc interrupts sources -- clocks: clock phandles (see clock bindings for details) - -Optional properties: -- ti,use-hecc1int: if provided configures HECC to produce all interrupts - on HECC1INT interrupt line. By default HECC0INT interrupt - line will be used. -- xceiver-supply: regulator that powers the CAN transceiver - -Example: - -For am3517evm board: - hecc: can@5c050000 { - compatible = "ti,am3517-hecc"; - reg = <0x5c050000 0x80>, - <0x5c053000 0x180>, - <0x5c052000 0x200>; - reg-names = "hecc", "hecc-ram", "mbx"; - interrupts = <24>; - clocks = <&hecc_ck>; - }; diff --git a/Documentation/devicetree/bindings/net/can/xilinx,can.yaml b/Documentation/devicetree/bindings/net/can/xilinx,can.yaml index 40835497050a..18015e60fd6d 100644 --- a/Documentation/devicetree/bindings/net/can/xilinx,can.yaml +++ b/Documentation/devicetree/bindings/net/can/xilinx,can.yaml @@ -8,7 +8,7 @@ title: Xilinx CAN and CANFD controller maintainers: - - Appana Durga Kedareswara rao <appana.durga.rao@xilinx.com> + - Harini T <harini.t@amd.com> properties: compatible: @@ -53,6 +53,9 @@ properties: $ref: /schemas/types.yaml#/definitions/flag description: CAN TX_OL, TX_TL and RX FIFOs have ECC support(AXI CAN) + phys: + maxItems: 1 + required: - compatible - reg diff --git a/Documentation/networking/device_drivers/can/ctu/fsm_txt_buffer_user.svg b/Documentation/networking/device_drivers/can/ctu/fsm_txt_buffer_user.svg index 381323423b4c..c8cf0bc49b69 100644 --- a/Documentation/networking/device_drivers/can/ctu/fsm_txt_buffer_user.svg +++ b/Documentation/networking/device_drivers/can/ctu/fsm_txt_buffer_user.svg @@ -93,9 +93,9 @@ <ellipse cx="144.827" cy="159.143" rx="10.8866" ry="4.39308"/> <ellipse cx="59.4364" cy="142.823" rx="7.36455" ry="4.39308"/> <ellipse cx="144.827" cy="129.196" rx="10.8866" ry="4.39308"/> - <ellipse cx="143.077" cy="180.53" rx="10.8866" ry="4.39308"/> </g> - <ellipse cx="110.386" cy="180.53" rx="10.8866" ry="4.39308" fill="#ffcb35" stroke="#000" stroke-linecap="square" stroke-width=".499999"/> + <ellipse cx="110.386" cy="180.53" rx="10.8866" ry="4.39308" fill="#28a4ff" stroke="#000" stroke-linecap="square" stroke-width=".499999"/> + <ellipse cx="143.077" cy="180.53" rx="10.8866" ry="4.39308" fill="#ffcb35" stroke="#000" stroke-linecap="square" stroke-width=".499999"/> <text x="110.90907" y="179.42688" font-size="3.175px" xml:space="preserve"><tspan x="110.90907" y="179.42688" dy="0.60000002" text-align="center" text-anchor="middle">Accessible</tspan><tspan x="110.90907" y="183.39563"><tspan font-size="3.175px" text-align="center" text-anchor="middle">for S</tspan>W</tspan></text> <text x="143.5869" y="179.52795" xml:space="preserve"><tspan x="143.5869" y="179.52795" dy="1 0 0 0 0 0" font-family="sans-serif" font-size="2.82222px" text-align="center" text-anchor="middle" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal">Inaccessible</tspan><tspan x="143.5869" y="183.36786" font-size="3.175px"><tspan font-size="3.175px" text-align="center" text-anchor="middle">for S</tspan>W</tspan></text> <g font-size="3.175px"> diff --git a/MAINTAINERS b/MAINTAINERS index 906000a4414a..6eee2c2aa6ae 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -29576,7 +29576,7 @@ F: Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml F: drivers/net/ethernet/xilinx/xilinx_axienet* XILINX CAN DRIVER -M: Appana Durga Kedareswara rao <appana.durga.rao@xilinx.com> +M: Harini T <harini.t@amd.com> L: linux-can@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/net/can/xilinx,can.yaml diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index eb856547ae7d..16f80607e150 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -2464,7 +2464,7 @@ struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, return ERR_PTR(ret); } - if (dev->of_node && of_property_read_bool(dev->of_node, "wakeup-source")) + if (dev->of_node && of_property_present(dev->of_node, "wakeup-source")) device_set_wakeup_capable(dev, true); /* Get TX FIFO size diff --git a/drivers/net/can/m_can/m_can_pci.c b/drivers/net/can/m_can/m_can_pci.c index eb31ed1f9644..d11a7c88fc32 100644 --- a/drivers/net/can/m_can/m_can_pci.c +++ b/drivers/net/can/m_can/m_can_pci.c @@ -126,7 +126,7 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) mcan_class->net->irq = pci_irq_vector(pci, 0); mcan_class->pm_clock_support = 1; mcan_class->pm_wake_source = 0; - mcan_class->can.clock.freq = id->driver_data; + mcan_class->can.clock.freq = M_CAN_CLOCK_FREQ_EHL; mcan_class->irq_edge_triggered = true; mcan_class->ops = &m_can_pci_ops; @@ -183,8 +183,8 @@ static SIMPLE_DEV_PM_OPS(m_can_pci_pm_ops, m_can_pci_suspend, m_can_pci_resume); static const struct pci_device_id m_can_pci_id_table[] = { - { PCI_VDEVICE(INTEL, 0x4bc1), M_CAN_CLOCK_FREQ_EHL, }, - { PCI_VDEVICE(INTEL, 0x4bc2), M_CAN_CLOCK_FREQ_EHL, }, + { PCI_VDEVICE(INTEL, 0x4bc1) }, + { PCI_VDEVICE(INTEL, 0x4bc2) }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(pci, m_can_pci_id_table); diff --git a/drivers/net/can/m_can/tcan4x5x-core.c b/drivers/net/can/m_can/tcan4x5x-core.c index 31cc9d0abd45..a5b8829aa519 100644 --- a/drivers/net/can/m_can/tcan4x5x-core.c +++ b/drivers/net/can/m_can/tcan4x5x-core.c @@ -211,8 +211,31 @@ static int tcan4x5x_write_fifo(struct m_can_classdev *cdev, return regmap_bulk_write(priv->regmap, TCAN4X5X_MRAM_START + addr_offset, val, val_count); } -static int tcan4x5x_power_enable(struct regulator *reg, int enable) +static int tcan4x5x_power_enable(struct tcan4x5x_priv *priv, int enable) { + struct regulator *reg = priv->power; + + /* + * Put the device into sleep mode if the RST pin is available, + * since a wake-up event, RST pin toggle, or power cycle are the only + * ways to exit sleep mode. + * Redundant if the regulator is exclusive to this device, but that + * can't be determined here. + * + * Datasheet: TCAN4550, section "8.4.3 Sleep Mode" + * https://www.ti.com/lit/gpn/tcan4550 + */ + if (priv->reset_gpio && !enable) { + int ret; + + ret = regmap_update_bits(priv->regmap, TCAN4X5X_CONFIG, + TCAN4X5X_MODE_SEL_MASK, + TCAN4X5X_MODE_SLEEP); + if (ret) + dev_err(&priv->spi->dev, "Setting sleep mode failed %pe\n", + ERR_PTR(ret)); + } + if (IS_ERR_OR_NULL(reg)) return 0; @@ -476,7 +499,7 @@ static int tcan4x5x_can_probe(struct spi_device *spi) goto out_m_can_class_free_dev; } - ret = tcan4x5x_power_enable(priv->power, 1); + ret = tcan4x5x_power_enable(priv, 1); if (ret) { dev_err(&spi->dev, "Enabling regulator failed %pe\n", ERR_PTR(ret)); @@ -531,7 +554,7 @@ static int tcan4x5x_can_probe(struct spi_device *spi) return 0; out_power: - tcan4x5x_power_enable(priv->power, 0); + tcan4x5x_power_enable(priv, 0); out_m_can_class_free_dev: m_can_class_free_dev(mcan_class->net); return ret; @@ -543,7 +566,7 @@ static void tcan4x5x_can_remove(struct spi_device *spi) m_can_class_unregister(&priv->cdev); - tcan4x5x_power_enable(priv->power, 0); + tcan4x5x_power_enable(priv, 0); m_can_class_free_dev(priv->cdev.net); } diff --git a/drivers/net/can/rockchip/rockchip_canfd-core.c b/drivers/net/can/rockchip/rockchip_canfd-core.c index 29de0c01e4ed..37c1c22c40c9 100644 --- a/drivers/net/can/rockchip/rockchip_canfd-core.c +++ b/drivers/net/can/rockchip/rockchip_canfd-core.c @@ -50,6 +50,12 @@ static const struct rkcanfd_devtype_data rkcanfd_devtype_data_rk3568v3 = { RKCANFD_QUIRK_CANFD_BROKEN, }; +static const struct rkcanfd_devtype_data rkcanfd_devtype_data_rk3588 = { + .model = RKCANFD_MODEL_RK3588, + .quirks = RKCANFD_QUIRK_RK3568_ERRATUM_5 | + RKCANFD_QUIRK_RK3568_ERRATUM_6, +}; + static const char *__rkcanfd_get_model_str(enum rkcanfd_model model) { switch (model) { @@ -57,6 +63,8 @@ static const char *__rkcanfd_get_model_str(enum rkcanfd_model model) return "rk3568v2"; case RKCANFD_MODEL_RK3568V3: return "rk3568v3"; + case RKCANFD_MODEL_RK3588: + return "rk3588"; } return "<unknown>"; @@ -148,6 +156,12 @@ static int rkcanfd_set_bittiming(struct rkcanfd_priv *priv) rkcanfd_write(priv, RKCANFD_REG_FD_DATA_BITTIMING, reg_dbt); + /* RK3588 CAN-FD BRS works with TDC disabled. */ + if (priv->devtype_data.model == RKCANFD_MODEL_RK3588) { + rkcanfd_write(priv, RKCANFD_REG_TRANSMIT_DELAY_COMPENSATION, 0); + return 0; + } + tdco = (priv->can.clock.freq / dbt->bitrate) * 2 / 3; tdco = min(tdco, FIELD_MAX(RKCANFD_REG_TRANSMIT_DELAY_COMPENSATION_TDC_OFFSET)); @@ -847,6 +861,9 @@ static const struct of_device_id rkcanfd_of_match[] = { .compatible = "rockchip,rk3568v3-canfd", .data = &rkcanfd_devtype_data_rk3568v3, }, { + .compatible = "rockchip,rk3588-canfd", + .data = &rkcanfd_devtype_data_rk3588, + }, { /* sentinel */ }, }; diff --git a/drivers/net/can/rockchip/rockchip_canfd-rx.c b/drivers/net/can/rockchip/rockchip_canfd-rx.c index 475c0409e215..24e87daa1df0 100644 --- a/drivers/net/can/rockchip/rockchip_canfd-rx.c +++ b/drivers/net/can/rockchip/rockchip_canfd-rx.c @@ -281,7 +281,10 @@ rkcanfd_rx_fifo_get_len(const struct rkcanfd_priv *priv) { const u32 reg = rkcanfd_read(priv, RKCANFD_REG_RX_FIFO_CTRL); - return FIELD_GET(RKCANFD_REG_RX_FIFO_CTRL_RX_FIFO_CNT, reg); + if (priv->devtype_data.model == RKCANFD_MODEL_RK3588) + return FIELD_GET(RKCANFD_REG_RX_FIFO_CTRL_RX_FIFO_CNT_RK3588, reg); + + return FIELD_GET(RKCANFD_REG_RX_FIFO_CTRL_RX_FIFO_CNT_RK3568, reg); } int rkcanfd_handle_rx_int(struct rkcanfd_priv *priv) diff --git a/drivers/net/can/rockchip/rockchip_canfd.h b/drivers/net/can/rockchip/rockchip_canfd.h index 93131c7d7f54..95bea9bfd8a2 100644 --- a/drivers/net/can/rockchip/rockchip_canfd.h +++ b/drivers/net/can/rockchip/rockchip_canfd.h @@ -214,7 +214,8 @@ #define RKCANFD_REG_TXEVENT_FIFO_CTRL_TXE_FIFO_ENABLE BIT(0) #define RKCANFD_REG_RX_FIFO_CTRL 0x118 -#define RKCANFD_REG_RX_FIFO_CTRL_RX_FIFO_CNT GENMASK(6, 4) +#define RKCANFD_REG_RX_FIFO_CTRL_RX_FIFO_CNT_RK3568 GENMASK(6, 4) +#define RKCANFD_REG_RX_FIFO_CTRL_RX_FIFO_CNT_RK3588 GENMASK(7, 5) #define RKCANFD_REG_RX_FIFO_CTRL_RX_FIFO_FULL_WATERMARK GENMASK(3, 1) #define RKCANFD_REG_RX_FIFO_CTRL_RX_FIFO_ENABLE BIT(0) @@ -331,6 +332,11 @@ * rarely with the standard clock of 300 MHz, but almost immediately * at 80 MHz. * + * Tests on the rk3588 show the same empty FIFO condition. + * In that setup rx_fifo_empty_errors increments when the bus + * transitions from idle to high CAN-FD load and stops growing once + * the bus reaches a steady state. + * * To workaround this problem, check for empty FIFO with * rkcanfd_fifo_header_empty() in rkcanfd_handle_rx_int_one() and exit * early. @@ -344,6 +350,8 @@ /* Erratum 6: The CAN controller's transmission of extended frames may * intermittently change into standard frames * + * Tests on the rk3588 show the same problem. + * * Work around this issue by activating self reception (RXSTX). If we * have pending TX CAN frames, check all RX'ed CAN frames in * rkcanfd_rxstx_filter(). @@ -424,6 +432,9 @@ * cansequence -rv -i 1 * * - TX starvation after repeated Bus-Off + * Tests on the rk3588 show the same problem. In a + * 10-cycle Bus-Off recovery test, 9 cycles failed to send after the + * controller restarted. * To reproduce: * host: * sleep 3 && cangen can0 -I2 -Li -Di -p10 -g 0.0 @@ -434,6 +445,7 @@ enum rkcanfd_model { RKCANFD_MODEL_RK3568V2 = 0x35682, RKCANFD_MODEL_RK3568V3 = 0x35683, + RKCANFD_MODEL_RK3588 = 0x3588, }; struct rkcanfd_devtype_data { diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index 82508a865095..3b9b2f104d86 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -1565,7 +1565,7 @@ static int gs_usb_probe(struct usb_interface *intf, if (icount > type_max(parent->channel_cnt)) { dev_err(&intf->dev, - "Driver cannot handle more that %u CAN interfaces\n", + "Driver cannot handle more than %u CAN interfaces\n", type_max(parent->channel_cnt)); return -EINVAL; } diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index e882250180ef..9e2e25d02471 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -33,6 +33,7 @@ MODULE_ALIAS_RTNL_LINK(DRV_NAME); struct vxcan_priv { struct net_device __rcu *peer; + netdevice_tracker peer_tracker; }; static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev) @@ -268,9 +269,11 @@ static int vxcan_newlink(struct net_device *dev, /* cross link the device pair */ priv = netdev_priv(dev); rcu_assign_pointer(priv->peer, peer); + netdev_hold(peer, &priv->peer_tracker, GFP_KERNEL); priv = netdev_priv(peer); rcu_assign_pointer(priv->peer, dev); + netdev_hold(dev, &priv->peer_tracker, GFP_KERNEL); return 0; @@ -281,24 +284,25 @@ unregister_network_device: static void vxcan_dellink(struct net_device *dev, struct list_head *head) { + netdevice_tracker *peer_tracker; struct vxcan_priv *priv; struct net_device *peer; priv = netdev_priv(dev); - peer = rtnl_dereference(priv->peer); + peer_tracker = &priv->peer_tracker; + peer = unrcu_pointer(xchg(&priv->peer, NULL)); + if (!peer) + return; - /* Note : dellink() is called from default_device_exit_batch(), - * before a rcu_synchronize() point. The devices are guaranteed - * not being freed before one RCU grace period. - */ - RCU_INIT_POINTER(priv->peer, NULL); unregister_netdevice_queue(dev, head); - if (peer) { - priv = netdev_priv(peer); - RCU_INIT_POINTER(priv->peer, NULL); - unregister_netdevice_queue(peer, head); - } + priv = netdev_priv(peer); + dev = unrcu_pointer(xchg(&priv->peer, NULL)); + if (dev) + unregister_netdevice_queue_net(dev_net(dev), peer, head); + + netdev_put(peer, peer_tracker); + netdev_put(dev, &priv->peer_tracker); } static const struct nla_policy vxcan_policy[VXCAN_INFO_MAX + 1] = { |
