mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 20:53:03 +02:00
Networking changes for 7.3.
Core & protocols
----------------
- A few steps lowering rtnl_lock dependence:
- per-netns netdev unregistration for select SW drivers
(e.g. veth, ipvlan, tunnels)
- rtnl_lock-less FIB rule changes (RTM_NEWRULE and RTM_DELRULE)
- prepare software drivers and TC qdiscs for rtnl_lock-less GET
- Support BIG TCP (>64kB TSO) in UDP tunnels (vxlan, geneve).
- Support buffers larger than PAGE_SIZE in devmem zero-copy API.
- Improve MPTCP handling of extreme memory pressure handling,
when out-of-order queue had to be pruned.
- Report the per-group user count via RTM_GETMULTICAST.
- Expose the route deletion reason in RTM_DELROUTE.
- Add a SO_RIGHTS_NOTRUNC option to UNIX sockets to enable more useful
handling of LSM denials when receiving SCM_RIGHTS messages: instead
of truncating the message at the first blocked fd, keep every fd slot
and store the LSM errno in the blocked slot.
- IPv6 Segment Routing - support looking up the post-encap SID
(address) in a different/specified routing table.
- Support PRP RedBox (interlink) creation.
- Support per-nexthop UDP dst port in VXLAN.
- Continue converting getsockopt callbacks in a number of protocols
to iov_iter.
Ethernet
--------
- Marge initial CXL support for AMD/Solarflare NICs (shared branch
with the CXL tree).
- New drivers:
- ADIN1140 10BASE-T1S MACPHY
- Initial skeleton of Intel iXD and ZTE Dinghai drivers.
- High-speed NICs:
- AMD/Pensando:
- support firmware flashing
- Cisco (enic):
- SR-IOV V2 admin channel and MBOX protocol
- Huawei (hns3):
- support for ethtool pfc_prevention_tout
- nVidia/Mellanox:
- support sharing bandwidth control across interfaces of
the same device
- Marvell (octeontx2-pf):
- link RQ page pools to netdev for Netlink stats
- Google vNIC:
- XDP metadata support for DQ RDA
- Microsoft vNIC:
- support forcing full-page RX buffers
- Other NICs:
- Synopsys IP:
- eic7700: support for eth1
- Microchip (lan743x):
- support for RMII interface
- Wangxun:
- support for ethtool -G and -C for VFs
- add Tx timeout and PCIe error handling
- Intel (igb/igc):
- RSS key get/set support
- support for forcing link speed without auto-negotiation
- Switches:
- NXP (dpaa2):
- support bonding/LAG offload
- Mediatek:
- mt7530: EN7528 support
- initial support for MT7628
- Micrel (ksz8/9):
- refactoring work to move towards library model
- PTP support for KSZ8463
- nVidia/Mellanox:
- support rtnl-lock-less ethtool callbacks
- Realtek:
- rtl8366rb: use generic RTL83xx code
- support SGMII and HSGMII for RTL8367S
- PHYs:
- Airoha:
- EcoNet EN7528 PHY support
- DAPU Telecom
- DAPU Telecom DAP8211R(I) Gigabit PHY support
- Realtek:
- support RTL8261C_CG
- support RTL8261D
Wireless
--------
- nl80211: per-link statistics support for multi-link operation
- mac80211: AQL/airtime-fairness support for multicast
- Merge Peripheral Authentication Service (PAS) / TEE support
for ath12k (shared branch with the firmware/qcom tree).
- New drivers:
- mm81x for Morse Micro Long-Range S1G devices
- nxpwifi for NXP devices (mostly forked off from mwifiex)
- Driver changes:
- Broadcom (brcmfmac):
- DPP support, some Cypress part update
- MediaTek (mt76):
- mt7928 support
- mt7925 NAN support
- mt7996 AP powersave improvements
- Qualcomm (ath12k):
- much kernel infrastructure integration work
- AHB platform MultiPD support
- Realtek (rt89):
- LED support
- RTL8922DE support
- dual-BT coex for RTL8922D
- Intel:
- new FW version support
Bluetooth
---------
- HCI: add support for Shorter Connection Interval (SCI) feature.
- af_bluetooth: add minimal context analysis annotations.
- Driver changes:
- Intel:
- add Bluetooth SAR revision 2 support
- add vendor_reset PCI sysfs for PLDR
- Mediatek:
- add USB IDs for MT7902 and MT7922 devices
- Realtek:
- add USB IDs for 8761CU and 8852BE devices
- NXP:
- add M.2 Bluetooth device support using pwrseq
Misc
----
- DPLL support for manual/numerical oscillator control (NCO)
(implement in zl3073x).
- MCTP support for MCTP over USB v1.1 (DMTF DSP0283).
- Power-over-Ethernet: support Realtek PSE controllers.
- Remove the IBM EHEA driver.
- Remove tulip/xircom_cb driver.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmqEwJ4ACgkQMUZtbf5S
Irsegw//fmHJae525nxg3DHoXhrUz8EDDOVoLH6oyWyLQnh5bmbReAY/+oWA4m54
3KKKO0b2rtgRvmY/7rnjAt3bjecYgCSjvZT7I+NosB0QbbBYc14PtHfYig9HffYm
uCXfNJOk+aJ2QK4ncEvU2SjgE89Ya7cC+yARFBAwYx4zi/Qx24RB+ziOyvkQ8ksX
atvMOZrnhwqvYUFOwnOLNHTpvdxB/ZsNwWY6iXcx6EYp9xrtPusbh3FlushWkwxH
8cI/dNla44TcIKXAzRn0znRdgiEVmCMyHvOv7LKaOfy8P3I+knmuIf/mScYQqOEF
T143HdXhVSBZFRtLtFKXIja/KsvCjX9lCeMn/2ak0brQDUREcacXxYbuZKDsNAAK
zXt/+5qAcm/mO8W1gKR9Ulfli5bhFN4HKXgXMLjo5ucPtzfPxFN7HGxTiC3Cxv1v
lSXexKaj74pNBVFmADrb5jWbq7oG+GzIdjzx3ycvm2q39Fr4nJ2SzrSPPNwc/ItQ
IHv3tGLQKXlr8dl0+p2mDkRInmHXrawVNsB1UgN8E/jtcwT2QMwyWOV6s5G3uEDl
a+0U/XsrPvDYBTUCRs/KaOJQGB90QkzLe9DATt159mf+rPzAX2/oCDo8xIEe+kWV
aivP+YutFfMH/CSC9PMuvdLE2KmoPY4mibAeE4/4AYLKtJnc/yU=
=zDto
-----END PGP SIGNATURE-----
Merge tag 'net-next-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next
Pull networking updates from Jakub Kicinski:
"One of the 'small improvements all over the place' releases for us.
It's hard to draw any direct comparisons because summer vacations
disrupted our patch processing (and presumably - generation) quite a
bit.
Quick and dirty count suggests we (Paolo and I) merged a very similar
number of net (632) and net-next (648) patches. This is not telling
the full story either because 1/3 to 1/2 of the net-next patches also
*seem* like AI-driven low priority fixes, cleanups and clarifications.
We are completely overwhelmed, of course. The glimmer of hope is that
we secured sufficient LLM budget and access (thank you Meta!) to run
reviews with multiple frontier models on each patch. This eliminates
some hallucinations. That said, in terms of review, the LLMs can only
do so much.
The sad truth is that our APIs (especially for rare events like PCIe
errors, timeouts etc) have always been racy, and now LLMs don't let us
ignore that. I expect our direction for the next release will be to
tweak the reviews a little bit more, but start shifting focus to
letting the LLMs take care of the busy work - managing patchwork,
automating common process complaints, editing commit messages, and
maybe applying patches which already got "reviewed-by" tags from
people we trust...
Core & protocols:
- A few steps lowering rtnl_lock dependence:
- per-netns netdev unregistration for select SW drivers (e.g.
veth, ipvlan, tunnels)
- rtnl_lock-less FIB rule changes (RTM_NEWRULE and RTM_DELRULE)
- prepare software drivers and TC qdiscs for rtnl_lock-less GET
- Support BIG TCP (>64kB TSO) in UDP tunnels (vxlan, geneve)
- Support buffers larger than PAGE_SIZE in devmem zero-copy API
- Improve MPTCP handling of extreme memory pressure handling, when
out-of-order queue had to be pruned
- Report the per-group user count via RTM_GETMULTICAST
- Expose the route deletion reason in RTM_DELROUTE
- Add a SO_RIGHTS_NOTRUNC option to UNIX sockets to enable more
useful handling of LSM denials when receiving SCM_RIGHTS messages:
instead of truncating the message at the first blocked fd, keep
every fd slot and store the LSM errno in the blocked slot
- IPv6 Segment Routing - support looking up the post-encap SID
(address) in a different/specified routing table
- Support PRP RedBox (interlink) creation
- Support per-nexthop UDP dst port in VXLAN
- Continue converting getsockopt callbacks in a number of protocols
to iov_iter
Ethernet:
- Merge initial CXL support for AMD/Solarflare NICs (shared branch
with the CXL tree)
- New drivers:
- ADIN1140 10BASE-T1S MACPHY
- Initial skeleton of Intel iXD and ZTE Dinghai drivers
- High-speed NICs:
- AMD/Pensando:
- support firmware flashing
- Cisco (enic):
- SR-IOV V2 admin channel and MBOX protocol
- Huawei (hns3):
- support for ethtool pfc_prevention_tout
- nVidia/Mellanox:
- support sharing bandwidth control across interfaces
of the same device
- Marvell (octeontx2-pf):
- link RQ page pools to netdev for Netlink stats
- Google vNIC:
- XDP metadata support for DQ RDA
- Microsoft vNIC:
- support forcing full-page RX buffers
- Other NICs:
- Synopsys IP:
- eic7700: support for eth1
- Microchip (lan743x):
- support for RMII interface
- Wangxun:
- support for ethtool -G and -C for VFs
- add Tx timeout and PCIe error handling
- Intel (igb/igc):
- RSS key get/set support
- support for forcing link speed without auto-negotiation
- Switches:
- NXP (dpaa2):
- support bonding/LAG offload
- Mediatek:
- mt7530: EN7528 support
- initial support for MT7628
- Micrel (ksz8/9):
- refactoring work to move towards library model
- PTP support for KSZ8463
- nVidia/Mellanox:
- support rtnl-lock-less ethtool callbacks
- Realtek:
- rtl8366rb: use generic RTL83xx code
- support SGMII and HSGMII for RTL8367S
- PHYs:
- Airoha:
- EcoNet EN7528 PHY support
- DAPU Telecom
- DAPU Telecom DAP8211R(I) Gigabit PHY support
- Realtek:
- support RTL8261C_CG
- support RTL8261D
Wireless:
- nl80211: per-link statistics support for multi-link operation
- mac80211: AQL/airtime-fairness support for multicast
- Merge Peripheral Authentication Service (PAS) / TEE support for
ath12k (shared branch with the firmware/qcom tree)
- New drivers:
- mm81x for Morse Micro Long-Range S1G devices
- nxpwifi for NXP devices (mostly forked off from mwifiex)
- Driver changes:
- Broadcom (brcmfmac):
- DPP support, some Cypress part update
- MediaTek (mt76):
- mt7928 support
- mt7925 NAN support
- mt7996 AP powersave improvements
- Qualcomm (ath12k):
- much kernel infrastructure integration work
- AHB platform MultiPD support
- Realtek (rt89):
- LED support
- RTL8922DE support
- dual-BT coex for RTL8922D
- Intel:
- new FW version support
Bluetooth:
- HCI: add support for Shorter Connection Interval (SCI) feature
- af_bluetooth: add minimal context analysis annotations
- Driver changes:
- Intel:
- add Bluetooth SAR revision 2 support
- add vendor_reset PCI sysfs for PLDR
- Mediatek:
- add USB IDs for MT7902 and MT7922 devices
- Realtek:
- add USB IDs for 8761CU and 8852BE devices
- NXP:
- add M.2 Bluetooth device support using pwrseq
Misc:
- DPLL support for manual/numerical oscillator control (NCO)
(implement in zl3073x)
- MCTP support for MCTP over USB v1.1 (DMTF DSP0283)
- Power-over-Ethernet: support Realtek PSE controllers
- Remove the IBM EHEA driver
- Remove tulip/xircom_cb driver"
* tag 'net-next-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1433 commits)
net/mlx5e: do not HW-GRO coalesce small frames
net: openvswitch: fix nf_connlabels leak in ovs_ct_init
net: add missing ref_tracker_dir_exit() to alloc_netdev_mqs()
net: openvswitch: fix flow mask use-after-free on flow deletion
sctp: stop processing a packet once its association is deleted
dpll: zl3073x: add PTP clock support
dpll: zl3073x: add channel ToD, phase step and TIE operations
dpll: zl3073x: scale poll interval proportionally to timeout
ptp: vmclock: prevent read-only mappings from becoming writable
ipv4: reject undersized MTUs in ip_do_fragment()
bonding: initialize err for empty target lists
net: dsa: initial support for MT7628 embedded switch
net: dsa: initial MT7628 tagging driver
net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet PHYs
dt-bindings: net: dsa: add MT7628 ESW
net: pse-pd: realtek-pse-mcu: add UART transport
net: pse-pd: realtek-pse-mcu: add I2C transport
net: pse-pd: add Realtek PSE MCU core
dt-bindings: net: pse-pd: add bindings for Realtek PSE MCU
vsock: use sock_error() to consume sk_err after a failed connect
...
This commit is contained in:
commit
91ec203513
15
Documentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie
Normal file
15
Documentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
What: /sys/bus/pci/devices/<BDF>/vendor_reset
|
||||
Date: 22-Jul-2026
|
||||
KernelVersion: 6.17
|
||||
Contact: linux-bluetooth@vger.kernel.org
|
||||
Description: This read-write attribute allows userspace to trigger a
|
||||
Product Level Device Reset (PLDR) on Intel PCIe Bluetooth
|
||||
controllers. Reading the attribute displays the supported
|
||||
reset type. Writing integer 0 triggers PLDR. Any other
|
||||
input is rejected with -EINVAL.
|
||||
|
||||
PLDR resets the entire on-chip platform shared between
|
||||
Bluetooth and WiFi. This means any driver attached to
|
||||
the WiFi device that shares hardware with this Bluetooth
|
||||
device will be released, the platform will be reset, and
|
||||
both the Bluetooth and WiFi devices will be re-probed.
|
||||
|
|
@ -14,15 +14,22 @@ description:
|
|||
provides up to 5 independent DPLL channels, up to 10 differential or
|
||||
single-ended inputs and 10 differential or 20 single-ended outputs.
|
||||
These devices support both I2C and SPI interfaces.
|
||||
The ZL3064x line card timing ICs share the ZL3073x register map
|
||||
and are described with a fallback to the register equivalent ZL3073x
|
||||
part.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- microchip,zl30731
|
||||
- microchip,zl30732
|
||||
- microchip,zl30733
|
||||
- microchip,zl30734
|
||||
- microchip,zl30735
|
||||
oneOf:
|
||||
- enum:
|
||||
- microchip,zl30731
|
||||
- microchip,zl30732
|
||||
- microchip,zl30733
|
||||
- microchip,zl30734
|
||||
- microchip,zl30735
|
||||
- items:
|
||||
- const: microchip,zl30643
|
||||
- const: microchip,zl30733
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
71
Documentation/devicetree/bindings/net/adi,ad3306.yaml
Normal file
71
Documentation/devicetree/bindings/net/adi,ad3306.yaml
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/adi,ad3306.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ADI ADIN1140 10BASE-T1S MAC-PHY
|
||||
|
||||
maintainers:
|
||||
- Ciprian Regus <ciprian.regus@analog.com>
|
||||
|
||||
description: |
|
||||
The ADIN1140 (also called AD3306) is a low power single port
|
||||
10BASE-T1S MAC-PHY. It integrates an Ethernet PHY with a MAC
|
||||
and all the associated analog circuitry.
|
||||
The device tries to implement the Open Alliance TC6 10BASE-T1x MAC-PHY
|
||||
Serial Interface specification and is compliant with the
|
||||
IEEE 802.3cg-2019 Ethernet standard for 10 Mbps single pair
|
||||
Ethernet (SPE). The device has a 4-wire SPI interface for
|
||||
communication between the MAC and host processor.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/net/ethernet-controller.yaml#
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: adi,adin1140
|
||||
- const: adi,ad3306
|
||||
- const: adi,ad3306
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 25000000
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
description: Interrupt from the MAC-PHY for receive data available
|
||||
and error conditions
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- spi-max-frequency
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ethernet@0 {
|
||||
compatible = "adi,ad3306";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <23000000>;
|
||||
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <6 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
local-mac-address = [ 00 11 22 33 44 55 ];
|
||||
};
|
||||
};
|
||||
|
|
@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
|||
title: Altera GMII to SGMII Converter
|
||||
|
||||
maintainers:
|
||||
- Matthew Gerlach <matthew.gerlach@altera.com>
|
||||
- Maxime Chevallier <maxime.chevallier@bootlin.com>
|
||||
|
||||
description:
|
||||
This binding describes the Altera GMII to SGMII converter.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
|||
title: Altera SOCFPGA SoC DWMAC controller
|
||||
|
||||
maintainers:
|
||||
- Matthew Gerlach <matthew.gerlach@altera.com>
|
||||
- Maxime Chevallier <maxime.chevallier@bootlin.com>
|
||||
|
||||
description:
|
||||
This binding describes the Altera SOCFPGA SoC implementation of the
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
|
|
@ -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>;
|
||||
};
|
||||
|
|
@ -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
|
||||
|
|
|
|||
62
Documentation/devicetree/bindings/net/dptel,dap8211r.yaml
Normal file
62
Documentation/devicetree/bindings/net/dptel,dap8211r.yaml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/dptel,dap8211r.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: DAPU Telecom DAP8211R(I) Gigabit Ethernet PHY
|
||||
|
||||
maintainers:
|
||||
- Artem Shimko <a.shimko.dev@gmail.com>
|
||||
|
||||
description: |
|
||||
The DAP8211R(I) is a Gigabit Ethernet PHY with RGMII interface,
|
||||
supporting IEEE 802.3az Energy Efficient Ethernet, IEEE 1588 SyncE,
|
||||
and an internal packet generator for diagnostics.
|
||||
|
||||
Specifications:
|
||||
- 10BASE-Te, 100BASE-TX, 1000BASE-T
|
||||
- RGMII with configurable TX/RX clock delays (150 ps steps, 0-2250 ps)
|
||||
- IEEE 802.3az-2010 Energy Efficient Ethernet
|
||||
- IEEE 1588 SyncE support
|
||||
- Internal packet generator and checker for link diagnostics
|
||||
|
||||
allOf:
|
||||
- $ref: ethernet-phy.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: ethernet-phy-id0008.011b
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
rx-internal-delay-ps:
|
||||
description:
|
||||
RGMII RX clock delay in picoseconds (0 to maximum).
|
||||
multipleOf: 150
|
||||
maximum: 2250
|
||||
default: 1950
|
||||
|
||||
tx-internal-delay-ps:
|
||||
description:
|
||||
RGMII TX clock delay in picoseconds (0 to maximum).
|
||||
multipleOf: 150
|
||||
maximum: 2250
|
||||
default: 1950
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ethernet-phy@1 {
|
||||
compatible = "ethernet-phy-id0008.011b";
|
||||
reg = <1>;
|
||||
rx-internal-delay-ps = <1950>;
|
||||
tx-internal-delay-ps = <1950>;
|
||||
};
|
||||
};
|
||||
|
|
@ -100,6 +100,10 @@ properties:
|
|||
Built-in switch of the Airoha AN7583 SoC
|
||||
const: airoha,an7583-switch
|
||||
|
||||
- description:
|
||||
Built-in switch of the EcoNet EN7528 SoC
|
||||
const: econet,en7528-switch
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
|
|
@ -318,6 +322,7 @@ allOf:
|
|||
- mediatek,mt7988-switch
|
||||
- airoha,en7581-switch
|
||||
- airoha,an7583-switch
|
||||
- econet,en7528-switch
|
||||
then:
|
||||
$ref: "#/$defs/builtin-dsa-port"
|
||||
properties:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/dsa/mediatek,mt7628-esw.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mediatek MT7628 Embedded Ethernet Switch
|
||||
|
||||
maintainers:
|
||||
- Joris Vaisvila <joey@tinyisr.com>
|
||||
|
||||
description:
|
||||
The MT7628 SoC's built-in Ethernet Switch has five user ports and one
|
||||
internally connected CPU port. The user ports are all connected to the SoC's
|
||||
integrated Fast Ethernet PHYs. The switch registers are directly mapped in
|
||||
the SoC's memory.
|
||||
|
||||
allOf:
|
||||
- $ref: dsa.yaml#/$defs/ethernet-ports
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mediatek,mt7628-esw
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: internal switch block reset
|
||||
- description: internal phy package reset
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: esw
|
||||
- const: ephy
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- resets
|
||||
- reset-names
|
||||
- ethernet-ports
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
switch@10110000 {
|
||||
compatible = "mediatek,mt7628-esw";
|
||||
reg = <0x10110000 0x8000>;
|
||||
|
||||
resets = <&sysc 23>, <&sysc 24>;
|
||||
reset-names = "esw", "ephy";
|
||||
|
||||
ethernet-ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ethernet-port@0 {
|
||||
reg = <0>;
|
||||
phy-mode = "internal";
|
||||
};
|
||||
|
||||
ethernet-port@1 {
|
||||
reg = <1>;
|
||||
phy-mode = "internal";
|
||||
};
|
||||
|
||||
ethernet-port@2 {
|
||||
reg = <2>;
|
||||
phy-mode = "internal";
|
||||
};
|
||||
|
||||
ethernet-port@3 {
|
||||
reg = <3>;
|
||||
phy-mode = "internal";
|
||||
};
|
||||
|
||||
ethernet-port@4 {
|
||||
reg = <4>;
|
||||
phy-mode = "internal";
|
||||
};
|
||||
|
||||
ethernet-port@6 {
|
||||
reg = <6>;
|
||||
phy-mode = "internal";
|
||||
ethernet = <ðernet>;
|
||||
|
||||
fixed-link {
|
||||
speed = <1000>;
|
||||
full-duplex;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -20,16 +20,37 @@ select:
|
|||
contains:
|
||||
enum:
|
||||
- eswin,eic7700-qos-eth
|
||||
- eswin,eic7700-qos-eth-clk-inversion
|
||||
required:
|
||||
- compatible
|
||||
|
||||
allOf:
|
||||
- $ref: snps,dwmac.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: eswin,eic7700-qos-eth
|
||||
then:
|
||||
properties:
|
||||
tx-internal-delay-ps:
|
||||
maximum: 2540
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: eswin,eic7700-qos-eth-clk-inversion
|
||||
then:
|
||||
properties:
|
||||
tx-internal-delay-ps:
|
||||
minimum: 2000
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: eswin,eic7700-qos-eth
|
||||
- enum:
|
||||
- eswin,eic7700-qos-eth
|
||||
- eswin,eic7700-qos-eth-clk-inversion
|
||||
- const: snps,dwmac-5.20
|
||||
|
||||
reg:
|
||||
|
|
@ -63,10 +84,14 @@ properties:
|
|||
- const: stmmaceth
|
||||
|
||||
rx-internal-delay-ps:
|
||||
enum: [0, 200, 600, 1200, 1600, 1800, 2000, 2200, 2400]
|
||||
minimum: 0
|
||||
maximum: 2540
|
||||
multipleOf: 20
|
||||
|
||||
tx-internal-delay-ps:
|
||||
enum: [0, 200, 600, 1200, 1600, 1800, 2000, 2200, 2400]
|
||||
minimum: 0
|
||||
maximum: 4540
|
||||
multipleOf: 20
|
||||
|
||||
eswin,hsp-sp-csr:
|
||||
description:
|
||||
|
|
@ -105,8 +130,6 @@ required:
|
|||
- phy-mode
|
||||
- resets
|
||||
- reset-names
|
||||
- rx-internal-delay-ps
|
||||
- tx-internal-delay-ps
|
||||
- eswin,hsp-sp-csr
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
|
@ -116,26 +139,51 @@ examples:
|
|||
ethernet@50400000 {
|
||||
compatible = "eswin,eic7700-qos-eth", "snps,dwmac-5.20";
|
||||
reg = <0x50400000 0x10000>;
|
||||
clocks = <&d0_clock 186>, <&d0_clock 171>, <&d0_clock 40>,
|
||||
<&d0_clock 193>;
|
||||
clock-names = "axi", "cfg", "stmmaceth", "tx";
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <61>;
|
||||
interrupt-names = "macirq";
|
||||
phy-mode = "rgmii-id";
|
||||
phy-handle = <&phy0>;
|
||||
clocks = <&d0_clock 186>, <&d0_clock 171>, <&d0_clock 40>,
|
||||
<&d0_clock 193>;
|
||||
clock-names = "axi", "cfg", "stmmaceth", "tx";
|
||||
resets = <&reset 95>;
|
||||
reset-names = "stmmaceth";
|
||||
rx-internal-delay-ps = <200>;
|
||||
tx-internal-delay-ps = <200>;
|
||||
eswin,hsp-sp-csr = <&hsp_sp_csr 0x100 0x108 0x118 0x114 0x11c>;
|
||||
snps,axi-config = <&stmmac_axi_setup>;
|
||||
phy-handle = <&phy0>;
|
||||
phy-mode = "rgmii-id";
|
||||
snps,aal;
|
||||
snps,fixed-burst;
|
||||
snps,tso;
|
||||
snps,axi-config = <&stmmac_axi_setup>;
|
||||
|
||||
stmmac_axi_setup: stmmac-axi-config {
|
||||
snps,blen = <0 0 0 0 16 8 4>;
|
||||
snps,rd_osr_lmt = <2>;
|
||||
snps,wr_osr_lmt = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
ethernet@50410000 {
|
||||
compatible = "eswin,eic7700-qos-eth-clk-inversion", "snps,dwmac-5.20";
|
||||
reg = <0x50410000 0x10000>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <70>;
|
||||
interrupt-names = "macirq";
|
||||
clocks = <&d0_clock 186>, <&d0_clock 171>, <&d0_clock 40>,
|
||||
<&d0_clock 194>;
|
||||
clock-names = "axi", "cfg", "stmmaceth", "tx";
|
||||
resets = <&reset 94>;
|
||||
reset-names = "stmmaceth";
|
||||
eswin,hsp-sp-csr = <&hsp_sp_csr 0x200 0x208 0x218 0x214 0x21c>;
|
||||
phy-handle = <&gmac1_phy0>;
|
||||
phy-mode = "rgmii-id";
|
||||
snps,aal;
|
||||
snps,fixed-burst;
|
||||
snps,tso;
|
||||
snps,axi-config = <&stmmac_axi_setup_gmac1>;
|
||||
|
||||
stmmac_axi_setup_gmac1: stmmac-axi-config {
|
||||
snps,blen = <0 0 0 0 16 8 4>;
|
||||
snps,rd_osr_lmt = <2>;
|
||||
snps,wr_osr_lmt = <2>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ examples:
|
|||
<GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
queue-group@2d14000 {
|
||||
queue-group@2d14000 {
|
||||
reg = <0x0 0x2d14000 0x0 0x1000>;
|
||||
interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
|
||||
|
|
|
|||
89
Documentation/devicetree/bindings/net/microchip,lan7800.yaml
Normal file
89
Documentation/devicetree/bindings/net/microchip,lan7800.yaml
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/microchip,lan7800.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Microchip LAN7800/LAN7801/LAN7850 Gigabit Ethernet controller
|
||||
|
||||
maintainers:
|
||||
- Thangaraj Samynathan <Thangaraj.S@microchip.com>
|
||||
- Rengarajan Sundararajan <Rengarajan.S@microchip.com>
|
||||
|
||||
description:
|
||||
The LAN7800/LAN7801/LAN7850 devices are usually configured by
|
||||
programming their OTP or with an external EEPROM, but some
|
||||
platforms (e.g. Raspberry Pi 3 B+) have neither. The Device Tree
|
||||
properties, if present, override the OTP and EEPROM.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/usb/usb-device.yaml#
|
||||
- $ref: /schemas/net/ethernet-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- usb424,7800
|
||||
- usb424,7801
|
||||
- usb424,7850
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: USB port number
|
||||
|
||||
mdio:
|
||||
$ref: /schemas/net/mdio.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
patternProperties:
|
||||
"^ethernet-phy(@[0-9a-f]+)?$":
|
||||
$ref: /schemas/net/ethernet-phy.yaml#
|
||||
unevaluatedProperties: false
|
||||
type: object
|
||||
|
||||
properties:
|
||||
microchip,led-modes:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
description:
|
||||
Array of LED mode values for each of up to 4 LEDs.
|
||||
Omitted LEDs are turned off. Allowed values are defined
|
||||
in include/dt-bindings/net/microchip-lan78xx.h.
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/net/microchip-lan78xx.h>
|
||||
|
||||
usb {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ethernet@1 {
|
||||
compatible = "usb424,7800";
|
||||
reg = <1>;
|
||||
local-mac-address = [00 11 22 33 44 55];
|
||||
|
||||
mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
ethernet-phy@1 {
|
||||
reg = <1>;
|
||||
microchip,led-modes = <
|
||||
LAN78XX_LINK_1000_ACTIVITY
|
||||
LAN78XX_LINK_10_100_ACTIVITY
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
Microchip LAN78xx Gigabit Ethernet controller
|
||||
|
||||
The LAN78XX devices are usually configured by programming their OTP or with
|
||||
an external EEPROM, but some platforms (e.g. Raspberry Pi 3 B+) have neither.
|
||||
The Device Tree properties, if present, override the OTP and EEPROM.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of "usb424,7800", "usb424,7801" or "usb424,7850".
|
||||
|
||||
The MAC address will be determined using the optional properties
|
||||
defined in ethernet.txt.
|
||||
|
||||
Optional properties of the embedded PHY:
|
||||
- microchip,led-modes: a 0..4 element vector, with each element configuring
|
||||
the operating mode of an LED. Omitted LEDs are turned off. Allowed values
|
||||
are defined in "include/dt-bindings/net/microchip-lan78xx.h".
|
||||
|
||||
Example:
|
||||
|
||||
/* Based on the configuration for a Raspberry Pi 3 B+ */
|
||||
&usb {
|
||||
usb-port@1 {
|
||||
compatible = "usb424,2514";
|
||||
reg = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
usb-port@1 {
|
||||
compatible = "usb424,2514";
|
||||
reg = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ethernet: ethernet@1 {
|
||||
compatible = "usb424,7800";
|
||||
reg = <1>;
|
||||
local-mac-address = [ 00 11 22 33 44 55 ];
|
||||
|
||||
mdio {
|
||||
#address-cells = <0x1>;
|
||||
#size-cells = <0x0>;
|
||||
eth_phy: ethernet-phy@1 {
|
||||
reg = <1>;
|
||||
microchip,led-modes = <
|
||||
LAN78XX_LINK_1000_ACTIVITY
|
||||
LAN78XX_LINK_10_100_ACTIVITY
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -35,7 +35,7 @@ properties:
|
|||
- usb424,9906 # SMSC9505A USB Ethernet Device (HAL)
|
||||
- usb424,9907 # SMSC9500 USB Ethernet Device (Alternate ID)
|
||||
- usb424,9908 # SMSC9500A USB Ethernet Device (Alternate ID)
|
||||
- usb424,9909 # SMSC9512/9514 USB Hub & Ethernet Device ID)
|
||||
- usb424,9909 # SMSC9512/9514 USB Hub & Ethernet Device
|
||||
- usb424,9e00 # SMSC9500A USB Ethernet Device
|
||||
- usb424,9e01 # SMSC9505A USB Ethernet Device
|
||||
- usb424,9e08 # SMSC LAN89530 USB Ethernet Device
|
||||
|
|
|
|||
|
|
@ -140,8 +140,8 @@ examples:
|
|||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
switch: ethernet-switch@e0000000 {
|
||||
compatible = "microchip,lan966x-switch";
|
||||
reg = <0xe0000000 0x0100000>,
|
||||
<0xe2000000 0x0800000>;
|
||||
reg = <0xe0000000 0x0100000>,
|
||||
<0xe2000000 0x0800000>;
|
||||
reg-names = "cpu", "gcb";
|
||||
interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "xtr";
|
||||
|
|
|
|||
|
|
@ -210,9 +210,9 @@ examples:
|
|||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
switch: switch@600000000 {
|
||||
compatible = "microchip,sparx5-switch";
|
||||
reg = <0 0x401000>,
|
||||
<0x10004000 0x7fc000>,
|
||||
<0x11010000 0xaf0000>;
|
||||
reg = <0 0x401000>,
|
||||
<0x10004000 0x7fc000>,
|
||||
<0x11010000 0xaf0000>;
|
||||
reg-names = "cpu", "devices", "gcb";
|
||||
interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "xtr";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,182 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/pse-pd/realtek,pse-mcu-gen1.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Realtek PSE MCU
|
||||
|
||||
maintainers:
|
||||
- Jonas Jelonek <jelonek.jonas@gmail.com>
|
||||
|
||||
description: |
|
||||
A microcontroller (MCU) that manages the PSE (Power Sourcing Equipment)
|
||||
hardware on a range of managed PoE switches. The host CPU talks only to
|
||||
this MCU - over I2C/SMBus or UART - using a small message-based protocol;
|
||||
the PSE silicon it drives sits behind the MCU and is never accessed
|
||||
directly. For example, on the Zyxel GS1900-10HP the SoC reaches the MCU
|
||||
over UART, and the MCU manages the on-board PSE chip.
|
||||
|
||||
This binding describes the MCU together with its Realtek firmware: the
|
||||
firmware and its host protocol, which are stable across boards. The
|
||||
microcontroller silicon is a general-purpose part that varies, and the
|
||||
PSE silicon behind the MCU (Realtek RTL823x/RTL8239* or Broadcom
|
||||
BCM59xxx) is reported by the MCU and detected at runtime - neither is
|
||||
named here.
|
||||
|
||||
Two protocol generations exist, both Realtek's:
|
||||
gen1 older boards, where the MCU fronts Broadcom PSE silicon
|
||||
gen2 the altered protocol used with Realtek's own PSE silicon
|
||||
|
||||
On an I2C attachment the framing the MCU firmware expects is part of the
|
||||
compatible: '-smbus' (reads carry a leading command byte and a repeated
|
||||
start) or '-i2c' (bare block writes and reads). A UART attachment carries
|
||||
no framing suffix; the transport is given by the parent 'serial' node.
|
||||
|
||||
Each board additionally carries a device-specific compatible that falls
|
||||
back to one of the protocol compatibles above. Drivers bind on the
|
||||
protocol compatible; the device-specific string identifies the board and
|
||||
reserves a place for a future per-board quirk without having to retrofit
|
||||
device trees already in the field.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
# UART
|
||||
- items:
|
||||
- enum:
|
||||
- zyxel,gs1900-10hp-a1-pse
|
||||
- const: realtek,pse-mcu-gen1
|
||||
|
||||
# I2C, SMBus framing
|
||||
- items:
|
||||
- enum:
|
||||
- zyxel,gs1920-24hp-v2-pse
|
||||
- const: realtek,pse-mcu-gen1-smbus
|
||||
|
||||
# UART
|
||||
- items:
|
||||
- enum:
|
||||
- zyxel,gs1900-10hp-b1-pse
|
||||
- zyxel,xmg1915-10ep-pse
|
||||
- const: realtek,pse-mcu-gen2
|
||||
|
||||
# I2C, SMBus framing
|
||||
- items:
|
||||
- enum:
|
||||
- zyxel,xs1930-12hp-pse
|
||||
- const: realtek,pse-mcu-gen2-smbus
|
||||
|
||||
# I2C, raw framing
|
||||
- items:
|
||||
- enum:
|
||||
- linksys,lgs328mpc-v2-pse
|
||||
- const: realtek,pse-mcu-gen2-i2c
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
description: Reset line of the MCU.
|
||||
maxItems: 1
|
||||
|
||||
disable-ports-gpios:
|
||||
description:
|
||||
Hardware gate that forces all ports into admin-disabled state while
|
||||
asserted.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
allOf:
|
||||
- $ref: pse-controller.yaml#
|
||||
# A '-smbus'/'-i2c' compatible is an I2C attachment: it has 'reg' and
|
||||
# cannot carry serial bus properties. A bare gen compatible is a UART
|
||||
# attachment: no 'reg', the transport comes from the parent serial node.
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- realtek,pse-mcu-gen1-smbus
|
||||
- realtek,pse-mcu-gen2-smbus
|
||||
- realtek,pse-mcu-gen2-i2c
|
||||
then:
|
||||
required:
|
||||
- reg
|
||||
properties:
|
||||
current-speed: false
|
||||
max-speed: false
|
||||
else:
|
||||
allOf:
|
||||
- $ref: /schemas/serial/serial-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
reg: false
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
# SMBus-framed I2C attachment
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ethernet-pse@20 {
|
||||
compatible = "zyxel,xs1930-12hp-pse", "realtek,pse-mcu-gen2-smbus";
|
||||
reg = <0x20>;
|
||||
|
||||
pse-pis {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pse-pi@0 {
|
||||
reg = <0>;
|
||||
#pse-cells = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Raw-I2C-framed attachment
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ethernet-pse@20 {
|
||||
compatible = "linksys,lgs328mpc-v2-pse", "realtek,pse-mcu-gen2-i2c";
|
||||
reg = <0x20>;
|
||||
|
||||
pse-pis {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pse-pi@0 {
|
||||
reg = <0>;
|
||||
#pse-cells = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# UART attachment
|
||||
- |
|
||||
serial {
|
||||
ethernet-pse {
|
||||
compatible = "zyxel,gs1900-10hp-a1-pse", "realtek,pse-mcu-gen1";
|
||||
current-speed = <19200>;
|
||||
|
||||
pse-pis {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pse-pi@0 {
|
||||
reg = <0>;
|
||||
#pse-cells = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -254,10 +254,10 @@ examples:
|
|||
ethernet@15c30000 {
|
||||
compatible = "renesas,r9a09g057-gbeth", "renesas,rzv2h-gbeth", "snps,dwmac-5.20";
|
||||
reg = <0x15c30000 0x10000>;
|
||||
clocks = <&cpg CPG_MOD 0xbd>, <&cpg CPG_MOD 0xbc>,
|
||||
<&ptp_clock>, <&cpg CPG_MOD 0xb8>,
|
||||
<&cpg CPG_MOD 0xb9>, <&cpg CPG_MOD 0xba>,
|
||||
<&cpg CPG_MOD 0xbb>;
|
||||
clocks = <&cpg CPG_MOD 0xbd>, <&cpg CPG_MOD 0xbc>,
|
||||
<&ptp_clock>, <&cpg CPG_MOD 0xb8>,
|
||||
<&cpg CPG_MOD 0xb9>, <&cpg CPG_MOD 0xba>,
|
||||
<&cpg CPG_MOD 0xbb>;
|
||||
clock-names = "stmmaceth", "pclk", "ptp_ref",
|
||||
"tx", "rx", "tx-180", "rx-180";
|
||||
resets = <&cpg 0xb0>;
|
||||
|
|
|
|||
|
|
@ -461,6 +461,8 @@ patternProperties:
|
|||
description: Dongwoon Anatech
|
||||
"^dptechnics,.*":
|
||||
description: DPTechnics
|
||||
"^dptel,.*":
|
||||
description: Guangdong Dapu Telecom Co., Ltd.
|
||||
"^dragino,.*":
|
||||
description: Dragino Technology Co., Limited
|
||||
"^dream,.*":
|
||||
|
|
|
|||
|
|
@ -91,6 +91,13 @@ following pin states:
|
|||
- ``DPLL_PIN_STATE_DISCONNECTED`` - the pin shall be not considered as
|
||||
a valid input for automatic selection algorithm
|
||||
|
||||
Pins that have the ``DPLL_PIN_CAPABILITIES_STATE_CONNECTED_OVERRIDE``
|
||||
capability can additionally be set to ``DPLL_PIN_STATE_CONNECTED`` in
|
||||
automatic mode, overriding the active input selection. This is useful
|
||||
for automatic-only DPLL devices where mode cannot be switched to manual.
|
||||
When such a pin is disconnected, the device returns to automatic input
|
||||
selection.
|
||||
|
||||
The actual hardware status of a pin is reported via the operational
|
||||
state (``DPLL_A_PIN_OPERSTATE``) attribute nested under the parent
|
||||
device:
|
||||
|
|
@ -109,8 +116,9 @@ Shared pins
|
|||
A single pin object can be attached to multiple dpll devices.
|
||||
Then there are two groups of configuration knobs:
|
||||
|
||||
1) Set on a pin - the configuration affects all dpll devices pin is
|
||||
registered to (i.e., ``DPLL_A_PIN_FREQUENCY``),
|
||||
1) Set on a pin - the configuration is a property of the pin itself and
|
||||
applies to all dpll devices the pin is registered with
|
||||
(i.e., ``DPLL_A_PIN_FREQUENCY``),
|
||||
2) Set on a pin-dpll tuple - the configuration affects only selected
|
||||
dpll device (i.e., ``DPLL_A_PIN_PRIO``, ``DPLL_A_PIN_STATE``,
|
||||
``DPLL_A_PIN_DIRECTION``).
|
||||
|
|
@ -500,9 +508,9 @@ as well as parameter being configured (``DPLL_A_MODE``).
|
|||
``DPLL_CMD_PIN_SET`` - to target a pin user must provide a
|
||||
``DPLL_A_PIN_ID``, which is unique identifier of a pin in the system.
|
||||
Also configured pin parameters must be added.
|
||||
If ``DPLL_A_PIN_FREQUENCY`` is configured, this affects all the dpll
|
||||
devices that are connected with the pin, that is why frequency attribute
|
||||
shall not be enclosed in ``DPLL_A_PIN_PARENT_DEVICE``.
|
||||
If ``DPLL_A_PIN_FREQUENCY`` is configured, it is a property of the pin
|
||||
itself and applies to all dpll devices the pin is registered with, so the
|
||||
frequency attribute shall not be enclosed in ``DPLL_A_PIN_PARENT_DEVICE``.
|
||||
Other attributes: ``DPLL_A_PIN_PRIO``, ``DPLL_A_PIN_STATE`` or
|
||||
``DPLL_A_PIN_DIRECTION`` must be enclosed in
|
||||
``DPLL_A_PIN_PARENT_DEVICE`` as their configuration relates to only one
|
||||
|
|
|
|||
|
|
@ -895,6 +895,16 @@ attribute-sets:
|
|||
resource-dump response. Bit 0 (dev) selects device-level
|
||||
resources; bit 1 (port) selects port-level resources.
|
||||
When absent all classes are returned.
|
||||
-
|
||||
name: parent-dev
|
||||
type: nest
|
||||
nested-attributes: dl-parent-dev
|
||||
doc: |
|
||||
Identifies the devlink instance which owns the parent rate node.
|
||||
Used with rate-set and rate-new to parent a rate object to a node on
|
||||
a different devlink instance, enabling cross-device rate scheduling.
|
||||
When absent, the parent node is resolved on the same instance.
|
||||
|
||||
-
|
||||
name: dl-dev-stats
|
||||
subset-of: devlink
|
||||
|
|
@ -1317,6 +1327,16 @@ attribute-sets:
|
|||
Specifies the bandwidth share assigned to the Traffic Class.
|
||||
The bandwidth for the traffic class is determined
|
||||
in proportion to the sum of the shares of all configured classes.
|
||||
-
|
||||
name: dl-parent-dev
|
||||
subset-of: devlink
|
||||
attributes:
|
||||
-
|
||||
name: bus-name
|
||||
-
|
||||
name: dev-name
|
||||
-
|
||||
name: index
|
||||
|
||||
operations:
|
||||
enum-model: directional
|
||||
|
|
@ -2289,8 +2309,8 @@ operations:
|
|||
dont-validate: [strict]
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
pre: devlink-nl-pre-doit
|
||||
post: devlink-nl-post-doit
|
||||
pre: devlink-nl-pre-doit-parent-dev-optional
|
||||
post: devlink-nl-post-doit-parent-dev-optional
|
||||
request:
|
||||
attributes:
|
||||
- bus-name
|
||||
|
|
@ -2303,6 +2323,7 @@ operations:
|
|||
- rate-tx-weight
|
||||
- rate-parent-node-name
|
||||
- rate-tc-bws
|
||||
- parent-dev
|
||||
|
||||
-
|
||||
name: rate-new
|
||||
|
|
@ -2311,8 +2332,8 @@ operations:
|
|||
dont-validate: [strict]
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
pre: devlink-nl-pre-doit
|
||||
post: devlink-nl-post-doit
|
||||
pre: devlink-nl-pre-doit-parent-dev-optional
|
||||
post: devlink-nl-post-doit-parent-dev-optional
|
||||
request:
|
||||
attributes:
|
||||
- bus-name
|
||||
|
|
@ -2325,6 +2346,7 @@ operations:
|
|||
- rate-tx-weight
|
||||
- rate-parent-node-name
|
||||
- rate-tc-bws
|
||||
- parent-dev
|
||||
|
||||
-
|
||||
name: rate-del
|
||||
|
|
|
|||
|
|
@ -165,6 +165,13 @@ definitions:
|
|||
-
|
||||
name: gnss
|
||||
doc: GNSS recovered clock
|
||||
-
|
||||
name: int-nco
|
||||
doc: |
|
||||
Device internal numerically controlled oscillator.
|
||||
When connected as a DPLL input, the DPLL enters NCO mode
|
||||
where the output frequency is adjusted by the host via
|
||||
the PTP clock interface.
|
||||
render-max: true
|
||||
-
|
||||
type: enum
|
||||
|
|
@ -252,6 +259,12 @@ definitions:
|
|||
-
|
||||
name: state-can-change
|
||||
doc: pin state can be changed
|
||||
-
|
||||
name: state-connected-override
|
||||
doc: |
|
||||
pin state can be set to connected regardless of current
|
||||
DPLL device mode, overriding the active input selection.
|
||||
Requires state-can-change to be set as well.
|
||||
-
|
||||
type: const
|
||||
name: phase-offset-divider
|
||||
|
|
@ -456,6 +469,9 @@ attribute-sets:
|
|||
offset on the media associated with the pin. Inside
|
||||
the pin-parent-device nest it represents the frequency
|
||||
offset between the pin and its parent DPLL device.
|
||||
For pins of type PIN_TYPE_INT_NCO this represents
|
||||
the DPLL's current output frequency offset from its
|
||||
nominal frequency.
|
||||
Value is in PPM (parts per million).
|
||||
This is a lower-precision version of
|
||||
fractional-frequency-offset-ppt.
|
||||
|
|
@ -502,6 +518,9 @@ attribute-sets:
|
|||
offset on the media associated with the pin. Inside
|
||||
the pin-parent-device nest it represents the frequency
|
||||
offset between the pin and its parent DPLL device.
|
||||
For pins of type PIN_TYPE_INT_NCO this represents
|
||||
the DPLL's current output frequency offset from its
|
||||
nominal frequency.
|
||||
Value is in PPT (parts per trillion, 10^-12).
|
||||
This is a higher-precision version of
|
||||
fractional-frequency-offset.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,14 @@ doc: >-
|
|||
netdev configuration over generic netlink.
|
||||
|
||||
definitions:
|
||||
-
|
||||
type: const
|
||||
name: page-size
|
||||
# Dummy value, codegen needs a number. The real value comes from
|
||||
# the PAGE_SIZE macro in the header below.
|
||||
value: 0
|
||||
header: asm/page.h
|
||||
scope: kernel
|
||||
-
|
||||
type: flags
|
||||
name: xdp-act
|
||||
|
|
@ -598,6 +606,16 @@ attribute-sets:
|
|||
type: u32
|
||||
checks:
|
||||
min: 1
|
||||
-
|
||||
name: rx-page-size
|
||||
doc: |
|
||||
Size in bytes of each device page the NIC writes into from the bound
|
||||
dmabuf. Must be a power of two and >= PAGE_SIZE; defaults to
|
||||
PAGE_SIZE.
|
||||
type: u32
|
||||
checks:
|
||||
min: page-size
|
||||
max: u32-max
|
||||
|
||||
operations:
|
||||
list:
|
||||
|
|
@ -812,6 +830,7 @@ operations:
|
|||
- ifindex
|
||||
- fd
|
||||
- queues
|
||||
- rx-page-size
|
||||
reply:
|
||||
attributes:
|
||||
- id
|
||||
|
|
|
|||
|
|
@ -1139,10 +1139,10 @@ attribute-sets:
|
|||
type: binary
|
||||
-
|
||||
name: fils-discovery
|
||||
type: binary # TOOD: nest
|
||||
type: binary # TODO: nest
|
||||
-
|
||||
name: unsol-bcast-probe-resp
|
||||
type: binary # TOOD: nest
|
||||
type: binary # TODO: nest
|
||||
-
|
||||
name: s1g-capability
|
||||
type: binary
|
||||
|
|
|
|||
|
|
@ -123,6 +123,9 @@ attribute-sets:
|
|||
-
|
||||
name: proto
|
||||
type: u8
|
||||
-
|
||||
name: mc-users
|
||||
type: u32
|
||||
|
||||
|
||||
operations:
|
||||
|
|
@ -176,6 +179,7 @@ operations:
|
|||
value: 58
|
||||
attributes: &mcaddr-attrs
|
||||
- multicast
|
||||
- mc-users
|
||||
- cacheinfo
|
||||
dump:
|
||||
request:
|
||||
|
|
|
|||
|
|
@ -928,6 +928,11 @@ attribute-sets:
|
|||
name: vfinfo-list
|
||||
type: nest
|
||||
nested-attributes: vfinfo-list-attrs
|
||||
doc: |
|
||||
Per-VF details. The list holds at most 256 VFs, or 128 when
|
||||
statistics are included, because it is one attribute and has to fit
|
||||
in a u16 length. A device with more VFs than that reports a
|
||||
truncated list; num-vf still carries the real count.
|
||||
-
|
||||
name: stats64
|
||||
type: binary
|
||||
|
|
|
|||
|
|
@ -78,6 +78,27 @@ definitions:
|
|||
-
|
||||
name: rta-used
|
||||
type: u32
|
||||
-
|
||||
name: del-reason
|
||||
type: enum
|
||||
name-prefix: rt-del-reason-
|
||||
enum-name: rt-del-reason
|
||||
doc: |
|
||||
Why the kernel deleted a route. New causes may be appended. The
|
||||
value space is family-agnostic, a value is never reinterpreted
|
||||
per address family.
|
||||
entries:
|
||||
-
|
||||
name: unspec
|
||||
doc: The deletion path does not record a cause.
|
||||
-
|
||||
name: expired
|
||||
doc: The RTF_EXPIRES lifetime ran out and the route was garbage
|
||||
collected.
|
||||
-
|
||||
name: ra-withdrawn
|
||||
doc: A Router Advertisement withdrew the route with a zero
|
||||
lifetime.
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
|
|
@ -185,6 +206,18 @@ attribute-sets:
|
|||
type: u32
|
||||
byte-order: big-endian
|
||||
display-hint: hex
|
||||
-
|
||||
name: del-reason
|
||||
type: u32
|
||||
enum: del-reason
|
||||
doc: |
|
||||
Emitted only on RTM_DELROUTE notifications, and only when the
|
||||
deletion path records a cause. An absent attribute means
|
||||
either an older kernel or a deletion path that does not
|
||||
record its cause, consumers must treat absent and unspec
|
||||
identically. Currently only IPv6 deletion paths record a
|
||||
cause. The attribute is notification-only, the kernel rejects
|
||||
it in requests.
|
||||
-
|
||||
name: metrics
|
||||
name-prefix: rtax-
|
||||
|
|
@ -299,6 +332,7 @@ operations:
|
|||
- dport
|
||||
- nh-id
|
||||
- flowlabel
|
||||
- del-reason
|
||||
dump:
|
||||
request:
|
||||
value: 26
|
||||
|
|
@ -313,7 +347,35 @@ operations:
|
|||
do:
|
||||
request:
|
||||
value: 24
|
||||
attributes: *all-route-attrs
|
||||
attributes: &route-req-attrs
|
||||
- dst
|
||||
- src
|
||||
- iif
|
||||
- oif
|
||||
- gateway
|
||||
- priority
|
||||
- prefsrc
|
||||
- metrics
|
||||
- multipath
|
||||
- flow
|
||||
- cacheinfo
|
||||
- table
|
||||
- mark
|
||||
- mfc-stats
|
||||
- via
|
||||
- newdst
|
||||
- pref
|
||||
- encap-type
|
||||
- encap
|
||||
- expires
|
||||
- pad
|
||||
- uid
|
||||
- ttl-propagate
|
||||
- ip-proto
|
||||
- sport
|
||||
- dport
|
||||
- nh-id
|
||||
- flowlabel
|
||||
-
|
||||
name: delroute
|
||||
doc: Delete an existing route
|
||||
|
|
@ -321,4 +383,23 @@ operations:
|
|||
do:
|
||||
request:
|
||||
value: 25
|
||||
attributes: *all-route-attrs
|
||||
attributes: *route-req-attrs
|
||||
-
|
||||
name: newroute-ntf
|
||||
doc: Notification about a created route.
|
||||
value: 24
|
||||
notify: getroute
|
||||
-
|
||||
name: delroute-ntf
|
||||
doc: Notification about a deleted route.
|
||||
value: 25
|
||||
notify: getroute
|
||||
|
||||
mcast-groups:
|
||||
list:
|
||||
-
|
||||
name: rtnlgrp-ipv4-route
|
||||
value: 7
|
||||
-
|
||||
name: rtnlgrp-ipv6-route
|
||||
value: 11
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -102,6 +102,95 @@ currently in use, and that bank will used for the next boot::
|
|||
# devlink dev flash pci/0000:b5:00.0 \
|
||||
file pensando/dsc_fw_1.63.0-22.tar
|
||||
|
||||
Firmware Management (PLDM)
|
||||
==========================
|
||||
|
||||
Firmware that supports PLDM can be updated using the devlink flash command
|
||||
with a PLDM firmware package. The entire package can be updated at once::
|
||||
|
||||
# devlink dev flash pci/0000:b5:00.0 file firmware.pldmfw
|
||||
|
||||
Individual components can also be updated by specifying the component name::
|
||||
|
||||
# devlink dev flash pci/0000:b5:00.0 \
|
||||
file firmware.pldmfw component fw.cpld
|
||||
|
||||
Per-component update uses driver-defined component names (fw, fw.cpld,
|
||||
etc.). Not all components support per-component update -
|
||||
devlink will reject the request if the specified component cannot
|
||||
be updated.
|
||||
|
||||
Gold (recovery) components can be updated by specifying the base component
|
||||
name (e.g., ``fw`` for ``fw.gold``) with a goldfw package file when the
|
||||
device supports per-component update. The ``.gold`` suffix in devlink info
|
||||
output indicates the gold slot version, not a flash target.
|
||||
|
||||
Info versions (PLDM)
|
||||
====================
|
||||
|
||||
Firmware that supports PLDM reports component versions using driver-defined
|
||||
names. The driver reports the following component versions:
|
||||
|
||||
.. list-table:: devlink info versions for PLDM-capable firmware
|
||||
:widths: 5 5 90
|
||||
|
||||
* - Name
|
||||
- Type
|
||||
- Description
|
||||
* - ``fw``
|
||||
- running, stored
|
||||
- Main firmware
|
||||
* - ``fw.gold``
|
||||
- stored
|
||||
- Gold (recovery) firmware
|
||||
* - ``fw.bootloader``
|
||||
- running, stored
|
||||
- Boot loader
|
||||
* - ``fw.cpld``
|
||||
- running, stored
|
||||
- CPLD
|
||||
* - ``fw.secure``
|
||||
- running, stored
|
||||
- Secure boot firmware
|
||||
* - ``fw.fpga``
|
||||
- running, stored
|
||||
- FPGA configuration
|
||||
* - ``fw.suc``
|
||||
- running, stored
|
||||
- System Unit Controller firmware
|
||||
* - ``fw.suc.bootloader``
|
||||
- running, stored
|
||||
- System Unit Controller bootloader
|
||||
* - ``fw.uboot``
|
||||
- running, stored
|
||||
- U-Boot bootloader
|
||||
* - ``asic.id``
|
||||
- fixed
|
||||
- The ASIC type for this device
|
||||
* - ``asic.rev``
|
||||
- fixed
|
||||
- The revision of the ASIC for this device
|
||||
|
||||
Example output::
|
||||
|
||||
$ devlink dev info pci/0000:00:05.0
|
||||
pci/0000:00:05.0:
|
||||
driver pds_core
|
||||
serial_number FLM18420073
|
||||
versions:
|
||||
fixed:
|
||||
asic.id 0x0
|
||||
asic.rev 0x0
|
||||
running:
|
||||
fw.bootloader 1.2.3
|
||||
fw 1.3.0
|
||||
fw.cpld 3.18
|
||||
stored:
|
||||
fw.bootloader 1.2.3
|
||||
fw.gold 1.2.0
|
||||
fw 1.3.0
|
||||
fw.cpld 3.18
|
||||
|
||||
Health Reporters
|
||||
================
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ Contents:
|
|||
intel/idpf
|
||||
intel/igb
|
||||
intel/igbvf
|
||||
intel/ixd
|
||||
intel/ixgbe
|
||||
intel/ixgbevf
|
||||
intel/i40e
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
==========================================================================
|
||||
iXD Linux* Base Driver for the Intel(R) Control Plane Function
|
||||
==========================================================================
|
||||
|
||||
Intel iXD Linux driver.
|
||||
Copyright(C) 2025 Intel Corporation.
|
||||
|
||||
.. contents::
|
||||
|
||||
For questions related to hardware requirements, refer to the documentation
|
||||
supplied with your Intel adapter. All hardware requirements listed apply to use
|
||||
with Linux.
|
||||
|
||||
|
||||
Identifying Your Adapter
|
||||
========================
|
||||
For information on how to identify your adapter, and for the latest Intel
|
||||
network drivers, refer to the Intel Support website:
|
||||
http://www.intel.com/support
|
||||
|
||||
|
||||
Support
|
||||
=======
|
||||
For general information, go to the Intel support website at:
|
||||
http://www.intel.com/support/
|
||||
|
||||
If an issue is identified with the released source code on a supported kernel
|
||||
with a supported adapter, email the specific information related to the issue
|
||||
to intel-wired-lan@lists.osuosl.org.
|
||||
|
||||
|
||||
Trademarks
|
||||
==========
|
||||
Intel is a trademark or registered trademark of Intel Corporation or its
|
||||
subsidiaries in the United States and/or other countries.
|
||||
|
||||
* Other names and brands may be claimed as the property of others.
|
||||
|
|
@ -165,3 +165,9 @@ own name.
|
|||
- u32
|
||||
- Controls the maximum number of MAC address filters that can be assigned
|
||||
to a Virtual Function (VF).
|
||||
* - ``max_sfs``
|
||||
- u32
|
||||
- The maximum number of subfunctions which can be created on the device.
|
||||
Modifying this parameter may require a device restart and PCI bus
|
||||
rescanning because the BAR layout may change. A value of 0 disables
|
||||
subfunction creation.
|
||||
|
|
|
|||
|
|
@ -107,6 +107,15 @@ doesn't have the eswitch. Local controller (identified by controller number = 0)
|
|||
has the eswitch. The Devlink instance on the local controller has eswitch
|
||||
devlink ports for both the controllers.
|
||||
|
||||
A non-zero controller number may also be used for ports that are not external.
|
||||
For example, a SmartNIC may have additional local PCI physical functions
|
||||
that are managed by the eswitch but are not on an external host. These
|
||||
ports use a non-zero controller number to distinguish them from the eswitch
|
||||
manager's own functions, while the external flag remains unset.
|
||||
|
||||
The ``phys_port_name`` includes the controller prefix (``c<controller_num>``)
|
||||
whenever the controller number is non-zero, regardless of the external flag.
|
||||
|
||||
Function configuration
|
||||
======================
|
||||
|
||||
|
|
@ -420,6 +429,8 @@ API allows to configure following rate object's parameters:
|
|||
Parent node name. Parent node rate limits are considered as additional limits
|
||||
to all node children limits. ``tx_max`` is an upper limit for children.
|
||||
``tx_share`` is a total bandwidth distributed among children.
|
||||
If the device supports cross-function scheduling, the parent can be from a
|
||||
different function of the same underlying device.
|
||||
|
||||
``tc_bw``
|
||||
Allow users to set the bandwidth allocation per traffic class on rate
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@ sure to respect following rules:
|
|||
|
||||
- Lock ordering should be maintained. If driver needs to take instance
|
||||
lock of both nested and parent instances at the same time, devlink
|
||||
instance lock of the parent instance should be taken first, only then
|
||||
instance lock of the nested instance could be taken.
|
||||
- Driver should use object-specific helpers to setup the nested relationship
|
||||
before registering the nested devlink instance:
|
||||
instance lock of the nested instance should be taken first, only then
|
||||
instance lock of the parent instance could be taken.
|
||||
- Driver should use object-specific helpers to setup the
|
||||
nested relationship:
|
||||
|
||||
- ``devl_nested_devlink_set()`` - called to setup devlink -> nested
|
||||
devlink relationship (could be used for multiple nested instances).
|
||||
|
|
@ -87,6 +87,7 @@ parameters, info versions, and other features it supports.
|
|||
ice
|
||||
ionic
|
||||
iosm
|
||||
ixd
|
||||
ixgbe
|
||||
kvaser_pciefd
|
||||
kvaser_usb
|
||||
|
|
|
|||
30
Documentation/networking/devlink/ixd.rst
Normal file
30
Documentation/networking/devlink/ixd.rst
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
===================
|
||||
ixd devlink support
|
||||
===================
|
||||
|
||||
This document describes the devlink features implemented by the ``ixd``
|
||||
device driver.
|
||||
|
||||
Info versions
|
||||
=============
|
||||
|
||||
The ``ixd`` driver reports the following versions
|
||||
|
||||
.. list-table:: devlink info versions implemented
|
||||
:widths: 5 5 5 90
|
||||
|
||||
* - Name
|
||||
- Type
|
||||
- Example
|
||||
- Description
|
||||
* - ``device.type``
|
||||
- fixed
|
||||
- MEV
|
||||
- The hardware type for this device
|
||||
* - ``fw.mgmt.api``
|
||||
- running
|
||||
- 2.0
|
||||
- 2-digit version number (major.minor) of the communication channel
|
||||
(virtchnl) used by the device.
|
||||
|
|
@ -45,8 +45,13 @@ Parameters
|
|||
- The range is between 1 and a device-specific max.
|
||||
- Applies to each physical function (PF) independently, if the device
|
||||
supports it. Otherwise, it applies symmetrically to all PFs.
|
||||
* - ``max_sfs``
|
||||
- permanent
|
||||
- The range is between 0 and a device-specific max.
|
||||
- Applies to each physical function (PF) independently.
|
||||
|
||||
Note: permanent parameters such as ``enable_sriov`` and ``total_vfs`` require FW reset to take effect
|
||||
Note: permanent parameters such as ``enable_sriov``, ``total_vfs`` and ``max_sfs``
|
||||
require FW reset to take effect
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
|
@ -419,3 +424,36 @@ User commands examples:
|
|||
|
||||
.. note::
|
||||
This command can run over all interfaces such as PF/VF and representor ports.
|
||||
|
||||
Rates
|
||||
=====
|
||||
|
||||
mlx5 devices can limit transmission of individual VFs or a group of them via
|
||||
the devlink-rate API in switchdev mode.
|
||||
|
||||
User commands examples:
|
||||
|
||||
- Print the existing rates::
|
||||
|
||||
$ devlink port function rate show
|
||||
|
||||
- Set a max tx limit on traffic from VF0::
|
||||
|
||||
$ devlink port function rate set pci/0000:82:00.0/1 tx_max 10Gbit
|
||||
|
||||
- Create a rate group with a max tx limit and add two VFs to it::
|
||||
|
||||
$ devlink port function rate add pci/0000:82:00.0/group1 tx_max 10Gbit
|
||||
$ devlink port function rate set pci/0000:82:00.0/1 parent group1
|
||||
$ devlink port function rate set pci/0000:82:00.0/2 parent group1
|
||||
|
||||
- Same scenario, with a min guarantee of 20% of the bandwidth for the first VF::
|
||||
|
||||
$ devlink port function rate add pci/0000:82:00.0/group1 tx_max 10Gbit
|
||||
$ devlink port function rate set pci/0000:82:00.0/1 parent group1 tx_share 2Gbit
|
||||
$ devlink port function rate set pci/0000:82:00.0/2 parent group1
|
||||
|
||||
- Cross-device scheduling::
|
||||
|
||||
$ devlink port function rate add pci/0000:82:00.0/group1 tx_max 10Gbit
|
||||
$ devlink port function rate set pci/0000:82:00.1/32769 parent pci/0000:82:00.0/group1
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ struct_mutex ra_mutex
|
|||
struct_fib_rules_ops* rules_ops
|
||||
struct_fib_table fib_main
|
||||
struct_fib_table fib_default
|
||||
spinlock_t fib_table_hash_lock
|
||||
unsigned_int fib_rules_require_fldissect
|
||||
bool fib_has_custom_rules
|
||||
bool fib_has_custom_local_routes
|
||||
|
|
|
|||
|
|
@ -421,10 +421,17 @@ running under the lock:
|
|||
* ``NETDEV_CHANGENAME``
|
||||
* ``NETDEV_REGISTER``
|
||||
* ``NETDEV_UP``
|
||||
* ``NETDEV_DOWN``
|
||||
* ``NETDEV_GOING_DOWN``
|
||||
|
||||
The following notifiers are running without the lock:
|
||||
* ``NETDEV_UNREGISTER``
|
||||
|
||||
Many SW devices (uppers) catch their lower's ``NETDEV_UNREGISTER``
|
||||
events and may interact with them via ``dev_*()`` handlers, which take
|
||||
the instance lock. Until we convert these devices to ``netif_*()`` variants,
|
||||
``NETDEV_UNREGISTER`` stays unlocked.
|
||||
|
||||
There are no clear expectations for the remaining notifiers. Notifiers not on
|
||||
the list may run with or without the instance lock, potentially even invoking
|
||||
the same notifier type with and without the lock from different code paths.
|
||||
|
|
|
|||
|
|
@ -454,7 +454,8 @@ Device drivers API
|
|||
The include/linux/oa_tc6.h defines the following functions:
|
||||
|
||||
.. c:function:: struct oa_tc6 *oa_tc6_init(struct spi_device *spi, \
|
||||
struct net_device *netdev)
|
||||
struct net_device *netdev, \
|
||||
struct oa_tc6_quirks *quirks)
|
||||
|
||||
Initialize OA TC6 lib.
|
||||
|
||||
|
|
|
|||
|
|
@ -206,6 +206,38 @@ enable is true we enable it, otherwise we disable it::
|
|||
return ioctl(fd, TUNSETQUEUE, (void *)&ifr);
|
||||
}
|
||||
|
||||
3.4 qdisc backpressure
|
||||
----------------------
|
||||
|
||||
IFF_BACKPRESSURE can be set to enable qdisc backpressure. Without it, TX
|
||||
drops occur when the internal ring buffer is full, so any attached qdisc
|
||||
is effectively bypassed and applications only learn about congestion
|
||||
through those drops.
|
||||
|
||||
With it, the kernel stops the queue instead, letting the qdisc hold and
|
||||
schedule packets, so its AQM, shaping and fairness actually apply. This
|
||||
helps protocols like TCP, which cut throughput in reaction to packet
|
||||
drops. With IFF_BACKPRESSURE, drops then only occur as a rare race.
|
||||
Backpressure requires a qdisc to be attached and has no effect with
|
||||
noqueue.
|
||||
|
||||
The flag is a property of the TUN/TAP device rather than of the file
|
||||
descriptor it was set on, so it applies to all queues of the device,
|
||||
regardless of which process opened which queue.
|
||||
|
||||
The flag can only be changed while the device has at most one queue. On a
|
||||
multiqueue device that already has a second queue attached or detached, a
|
||||
later TUNSETIFF succeeds but leaves the flag as it is. All the other
|
||||
TUNSETIFF flags behave the same way.
|
||||
|
||||
The txqueuelen can be reduced alongside this flag to further shift
|
||||
buffering into the qdisc and reduce bufferbloat, at a possible
|
||||
performance cost.
|
||||
|
||||
When running multiple network streams in parallel through a single
|
||||
TUN/TAP queue, the flag may reduce performance due to the extra overhead
|
||||
of the backpressure mechanism.
|
||||
|
||||
Universal TUN/TAP device driver Frequently Asked Question
|
||||
=========================================================
|
||||
|
||||
|
|
|
|||
|
|
@ -203,6 +203,22 @@ For RFC postings specifically, if nobody responded in a week - reviewers
|
|||
either missed the posting or have no strong opinions. If the code is ready,
|
||||
repost as a PATCH.
|
||||
|
||||
There are 2 services actively providing LLM-generated review on posted patches:
|
||||
|
||||
- https://sashiko.dev/
|
||||
- https://netdev-ai.bots.linux.dev/sashiko/
|
||||
|
||||
both use the Sashiko infrastructure on top of different models. Reviews are
|
||||
available after 24h. Patch authors are expected to proactively look into the
|
||||
AI-generated reviews and handle such feedback as any other kind of review:
|
||||
either debate it or address it. In both cases a reply on the mailing list is
|
||||
expected.
|
||||
|
||||
Authors are strongly encouraged to run LLM reviews on the posted patches in
|
||||
advance of the actual post. Large series triggering a significant amount of
|
||||
AI-generated feedback will likely get little attention from maintainers and
|
||||
reviewers.
|
||||
|
||||
Emails saying just "ping" or "bump" are considered rude. If you can't figure
|
||||
out the status of the patch from patchwork or where the discussion has
|
||||
landed - describe your best guess and ask if it's correct. For example::
|
||||
|
|
@ -210,6 +226,10 @@ landed - describe your best guess and ask if it's correct. For example::
|
|||
I don't understand what the next steps are. Person X seems to be unhappy
|
||||
with A, should I do B and repost the patches?
|
||||
|
||||
Don't reach out to maintainers or reviewers via private email and/or other
|
||||
communications channels: all the discussion must remain public, and
|
||||
requesting special attention is unfair towards the community, at best.
|
||||
|
||||
.. _Changes requested:
|
||||
|
||||
Changes requested
|
||||
|
|
|
|||
76
MAINTAINERS
76
MAINTAINERS
|
|
@ -1900,6 +1900,21 @@ S: Supported
|
|||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: drivers/dma/dma-axi-dmac.c
|
||||
|
||||
ANALOG DEVICES INC ETHERNET DRIVERS
|
||||
M: Ciprian Regus <ciprian.regus@analog.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/net/adi,ad3306.yaml
|
||||
F: drivers/net/ethernet/adi/adin1140.c
|
||||
|
||||
ANALOG DEVICES INC ETHERNET PHY DRIVERS
|
||||
M: Ciprian Regus <ciprian.regus@analog.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: drivers/net/phy/adin1140-phy.c
|
||||
|
||||
ANALOG DEVICES INC IIO DRIVERS
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
M: Michael Hennerich <Michael.Hennerich@analog.com>
|
||||
|
|
@ -3585,15 +3600,11 @@ M: Dinh Nguyen <dinguyen@kernel.org>
|
|||
S: Maintained
|
||||
F: drivers/clk/socfpga/
|
||||
|
||||
ARM/SOCFPGA DWMAC GLUE LAYER BINDINGS
|
||||
M: Matthew Gerlach <matthew.gerlach@altera.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/altr,gmii-to-sgmii-2.0.yaml
|
||||
F: Documentation/devicetree/bindings/net/altr,socfpga-stmmac.yaml
|
||||
|
||||
ARM/SOCFPGA DWMAC GLUE LAYER
|
||||
M: Maxime Chevallier <maxime.chevallier@bootlin.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/altr,gmii-to-sgmii-2.0.yaml
|
||||
F: Documentation/devicetree/bindings/net/altr,socfpga-stmmac.yaml
|
||||
F: drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
|
||||
|
||||
ARM/SOCFPGA EDAC BINDINGS
|
||||
|
|
@ -4253,7 +4264,6 @@ W: http://linux-atm.sourceforge.net
|
|||
F: drivers/atm/
|
||||
F: drivers/usb/atm/
|
||||
F: include/linux/atm*
|
||||
F: include/linux/sonet.h
|
||||
F: include/uapi/linux/atm*
|
||||
F: include/uapi/linux/sonet.h
|
||||
F: net/atm/
|
||||
|
|
@ -4703,6 +4713,7 @@ S: Supported
|
|||
W: http://www.bluez.org/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
|
||||
F: Documentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie
|
||||
F: Documentation/devicetree/bindings/net/bluetooth/
|
||||
F: drivers/bluetooth/
|
||||
|
||||
|
|
@ -7848,6 +7859,7 @@ DPLL SUBSYSTEM
|
|||
M: Vadim Fedorenko <vadim.fedorenko@linux.dev>
|
||||
M: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
|
||||
M: Jiri Pirko <jiri@resnulli.us>
|
||||
R: Ivan Vecera <ivecera@redhat.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/dpll/dpll-device.yaml
|
||||
|
|
@ -9497,11 +9509,6 @@ L: linux-fbdev@vger.kernel.org
|
|||
S: Maintained
|
||||
F: drivers/video/fbdev/efifb.c
|
||||
|
||||
EHEA (IBM pSeries eHEA 10Gb ethernet adapter) DRIVER
|
||||
L: netdev@vger.kernel.org
|
||||
S: Orphan
|
||||
F: drivers/net/ethernet/ibm/ehea/
|
||||
|
||||
ELM327 CAN NETWORK DRIVER
|
||||
M: Max Staudt <max@enpas.org>
|
||||
L: linux-can@vger.kernel.org
|
||||
|
|
@ -13043,8 +13050,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue.git
|
|||
F: Documentation/networking/device_drivers/ethernet/intel/
|
||||
F: drivers/net/ethernet/intel/
|
||||
F: drivers/net/ethernet/intel/*/
|
||||
F: include/linux/avf/virtchnl.h
|
||||
F: include/linux/net/intel/*/
|
||||
F: include/linux/net/intel/
|
||||
|
||||
INTEL ETHERNET PROTOCOL DRIVER FOR RDMA
|
||||
M: Tatyana Nikolova <tatyana.e.nikolova@intel.com>
|
||||
|
|
@ -18228,6 +18234,14 @@ F: drivers/regulator/mpq7920.c
|
|||
F: drivers/regulator/mpq7920.h
|
||||
F: include/linux/mfd/mp2629.h
|
||||
|
||||
MORSE MICRO MM81X WIRELESS DRIVER
|
||||
M: Lachlan Hodges <lachlan.hodges@morsemicro.com>
|
||||
M: Dan Callaghan <dan.callaghan@morsemicro.com>
|
||||
R: Arien Judge <arien.judge@morsemicro.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/net/wireless/morsemicro/
|
||||
|
||||
MOST(R) TECHNOLOGY DRIVER
|
||||
M: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
|
||||
M: Christian Gromm <christian.gromm@microchip.com>
|
||||
|
|
@ -19139,6 +19153,7 @@ F: include/net/net_failover.h
|
|||
NFC SUBSYSTEM
|
||||
M: David Heidelberg <david@ixit.cz>
|
||||
L: oe-linux-nfc@lists.linux.dev
|
||||
C: https://matrix.to/#/#linux-nfc:ixit.cz
|
||||
S: Maintained
|
||||
T: git https://codeberg.org/linux-nfc/linux.git
|
||||
F: Documentation/devicetree/bindings/net/nfc/
|
||||
|
|
@ -19585,6 +19600,13 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/ptp/nxp,ptp-netc.yaml
|
||||
F: drivers/ptp/ptp_netc.c
|
||||
|
||||
NXP NXPWIFI WIRELESS DRIVER
|
||||
M: Jeff Chen <jeff.chen_1@nxp.com>
|
||||
R: Francesco Dolcini <francesco@dolcini.it>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/nxp/
|
||||
|
||||
NXP PF5300/PF5301/PF5302 PMIC REGULATOR DEVICE DRIVER
|
||||
M: Woodrow Douglass <wdouglass@carnegierobotics.com>
|
||||
S: Maintained
|
||||
|
|
@ -22130,6 +22152,14 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath.git
|
|||
F: Documentation/devicetree/bindings/net/wireless/qca,ath9k.yaml
|
||||
F: drivers/net/wireless/ath/ath9k/
|
||||
|
||||
QUALCOMM ATHEROS QCA8K DSA SWITCH DRIVER
|
||||
M: Christian Marangi <ansuelsmth@gmail.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/dsa/qca8k.yaml
|
||||
F: drivers/net/dsa/qca/qca8k*
|
||||
F: net/dsa/tag_qca.c
|
||||
|
||||
QUALCOMM ATHEROS QCA7K ETHERNET DRIVER
|
||||
M: Stefan Wahren <wahrenst@gmx.net>
|
||||
L: netdev@vger.kernel.org
|
||||
|
|
@ -22782,6 +22812,13 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/watchdog/realtek,otto-wdt.yaml
|
||||
F: drivers/watchdog/realtek_otto_wdt.c
|
||||
|
||||
REALTEK PSE MCU DRIVER
|
||||
M: Jonas Jelonek <jelonek.jonas@gmail.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/pse-pd/realtek,pse-mcu-gen1.yaml
|
||||
F: drivers/net/pse-pd/realtek-pse-mcu*
|
||||
|
||||
REALTEK RTL83xx SMI DSA ROUTER CHIPS
|
||||
M: Linus Walleij <linusw@kernel.org>
|
||||
M: Luiz Angelo Daros de Luca <luizluca@gmail.com>
|
||||
|
|
@ -27302,6 +27339,7 @@ F: tools/testing/selftests/timers/
|
|||
|
||||
TIPC NETWORK LAYER
|
||||
M: Jon Maloy <jmaloy@redhat.com>
|
||||
M: Tung Quang Nguyen <tung.quang.nguyen@est.tech>
|
||||
L: netdev@vger.kernel.org (core kernel code)
|
||||
L: tipc-discussion@lists.sourceforge.net (user apps, general discussion)
|
||||
S: Maintained
|
||||
|
|
@ -28006,7 +28044,7 @@ M: Thangaraj Samynathan <Thangaraj.S@microchip.com>
|
|||
M: UNGLinuxDriver@microchip.com
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/microchip,lan78xx.txt
|
||||
F: Documentation/devicetree/bindings/net/microchip,lan7800.yaml
|
||||
F: drivers/net/usb/lan78xx.*
|
||||
F: include/dt-bindings/net/microchip-lan78xx.h
|
||||
|
||||
|
|
@ -29605,7 +29643,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
|
||||
|
|
@ -29914,6 +29952,12 @@ S: Maintained
|
|||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
|
||||
F: sound/hda/codecs/senarytech.c
|
||||
|
||||
ZTE DINGHAI ETHERNET DRIVER
|
||||
M: Junyang Han <han.junyang@zte.com.cn>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/ethernet/zte/
|
||||
|
||||
THE REST
|
||||
M: Linus Torvalds <torvalds@linux-foundation.org>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
|
|
|
|||
|
|
@ -155,6 +155,8 @@
|
|||
#define SO_INQ 84
|
||||
#define SCM_INQ SO_INQ
|
||||
|
||||
#define SO_RIGHTS_NOTRUNC 85
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
#if __BITS_PER_LONG == 64
|
||||
|
|
|
|||
|
|
@ -234,7 +234,6 @@ CONFIG_TULIP=m
|
|||
CONFIG_WINBOND_840=m
|
||||
CONFIG_DM9102=m
|
||||
CONFIG_ULI526X=m
|
||||
CONFIG_PCMCIA_XIRCOM=m
|
||||
CONFIG_DL2K=m
|
||||
CONFIG_SUNDANCE=m
|
||||
CONFIG_E100=m
|
||||
|
|
|
|||
|
|
@ -166,6 +166,8 @@
|
|||
#define SO_INQ 84
|
||||
#define SCM_INQ SO_INQ
|
||||
|
||||
#define SO_RIGHTS_NOTRUNC 85
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
#if __BITS_PER_LONG == 64
|
||||
|
|
|
|||
|
|
@ -147,6 +147,8 @@
|
|||
#define SO_INQ 0x4052
|
||||
#define SCM_INQ SO_INQ
|
||||
|
||||
#define SO_RIGHTS_NOTRUNC 0x4053
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
#if __BITS_PER_LONG == 64
|
||||
|
|
|
|||
|
|
@ -210,7 +210,6 @@ CONFIG_BNX2X=m
|
|||
CONFIG_CHELSIO_T1=m
|
||||
CONFIG_BE2NET=m
|
||||
CONFIG_IBMVETH=m
|
||||
CONFIG_EHEA=m
|
||||
CONFIG_IBMVNIC=m
|
||||
CONFIG_E100=y
|
||||
CONFIG_E1000=y
|
||||
|
|
|
|||
|
|
@ -412,7 +412,6 @@ CONFIG_TULIP_MMIO=y
|
|||
CONFIG_WINBOND_840=m
|
||||
CONFIG_DM9102=m
|
||||
CONFIG_ULI526X=m
|
||||
CONFIG_PCMCIA_XIRCOM=m
|
||||
CONFIG_DL2K=m
|
||||
CONFIG_SUNDANCE=m
|
||||
CONFIG_FEC_MPC52xx=m
|
||||
|
|
|
|||
|
|
@ -371,12 +371,6 @@ int devmem_is_allowed(unsigned long pfn)
|
|||
}
|
||||
#endif /* CONFIG_STRICT_DEVMEM */
|
||||
|
||||
/*
|
||||
* This is defined in kernel/resource.c but only powerpc needs to export it, for
|
||||
* the EHEA driver. Drop this when drivers/net/ethernet/ibm/ehea is removed.
|
||||
*/
|
||||
EXPORT_SYMBOL_GPL(walk_system_ram_range);
|
||||
|
||||
#ifdef CONFIG_EXECMEM
|
||||
static struct execmem_info execmem_info __ro_after_init;
|
||||
|
||||
|
|
|
|||
|
|
@ -148,6 +148,8 @@
|
|||
#define SO_INQ 0x005d
|
||||
#define SCM_INQ SO_INQ
|
||||
|
||||
#define SO_RIGHTS_NOTRUNC 0x005e
|
||||
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -50,3 +50,5 @@ hci_uart-$(CONFIG_BT_HCIUART_AG6XX) += hci_ag6xx.o
|
|||
hci_uart-$(CONFIG_BT_HCIUART_MRVL) += hci_mrvl.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_AML) += hci_aml.o
|
||||
hci_uart-objs := $(hci_uart-y)
|
||||
|
||||
CONTEXT_ANALYSIS := y
|
||||
|
|
|
|||
|
|
@ -301,6 +301,11 @@ static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned ch
|
|||
return -EILSEQ;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
bt_dev_err(data->hdev, "unknown packet type 0x%02x",
|
||||
pkt_type);
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
|
||||
|
|
@ -319,6 +324,13 @@ static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned ch
|
|||
}
|
||||
}
|
||||
|
||||
if (len > skb_tailroom(data->reassembly)) {
|
||||
bt_dev_err(data->hdev, "block exceeds packet length");
|
||||
kfree_skb(data->reassembly);
|
||||
data->reassembly = NULL;
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
skb_put_data(data->reassembly, buf, len);
|
||||
|
||||
|
|
@ -353,6 +365,13 @@ static void bfusb_rx_complete(struct urb *urb)
|
|||
skb_put(skb, count);
|
||||
|
||||
while (count) {
|
||||
if (count < 2) {
|
||||
bt_dev_err(data->hdev, "short block header");
|
||||
kfree_skb(data->reassembly);
|
||||
data->reassembly = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
hdr = buf[0] | (buf[1] << 8);
|
||||
|
||||
if (hdr & 0x4000) {
|
||||
|
|
@ -360,16 +379,28 @@ static void bfusb_rx_complete(struct urb *urb)
|
|||
count -= 2;
|
||||
buf += 2;
|
||||
} else {
|
||||
if (count < 3) {
|
||||
bt_dev_err(data->hdev, "short block header");
|
||||
kfree_skb(data->reassembly);
|
||||
data->reassembly = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
len = (buf[2] == 0) ? 256 : buf[2];
|
||||
count -= 3;
|
||||
buf += 3;
|
||||
}
|
||||
|
||||
if (count < len)
|
||||
if (count < len) {
|
||||
bt_dev_err(data->hdev, "block extends over URB buffer ranges");
|
||||
kfree_skb(data->reassembly);
|
||||
data->reassembly = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((hdr & 0xe1) == 0xc1)
|
||||
bfusb_recv_block(data, hdr, buf, len);
|
||||
if ((hdr & 0xe1) == 0xc1 &&
|
||||
bfusb_recv_block(data, hdr, buf, len) < 0)
|
||||
data->hdev->stat.err_rx++;
|
||||
|
||||
count -= len;
|
||||
buf += len;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ enum {
|
|||
#define BTINTEL_BT_DOMAIN 0x12
|
||||
#define BTINTEL_SAR_LEGACY 0
|
||||
#define BTINTEL_SAR_INC_PWR 1
|
||||
#define BTINTEL_SAR_REV2 2
|
||||
#define BTINTEL_SAR_INC_PWR_SUPPORTED 0
|
||||
|
||||
#define CMD_WRITE_BOOT_PARAMS 0xfc0e
|
||||
|
|
@ -2745,9 +2746,7 @@ static u8 btintel_classify_pkt_type(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
* based on their connection handle value range.
|
||||
*/
|
||||
if (iso_capable(hdev) && hci_skb_pkt_type(skb) == HCI_ACLDATA_PKT) {
|
||||
__u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle);
|
||||
|
||||
if (hci_handle(handle) >= BTINTEL_ISODATA_HANDLE_BASE)
|
||||
if (hci_acl_handle(skb) >= BTINTEL_ISODATA_HANDLE_BASE)
|
||||
return HCI_ISODATA_PKT;
|
||||
}
|
||||
|
||||
|
|
@ -3104,6 +3103,111 @@ static int btintel_set_mutual_sar(struct hci_dev *hdev, struct btintel_sar_inc_p
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* btintel_send_sar_rev2_band - send DDC command for one Rev2 sub-band
|
||||
*
|
||||
* Each DDC 0x0311-0x0316 carries 2 bytes: [ChainA_value, ChainB_value].
|
||||
* cmd->len = 4 (2 id + 2 data)
|
||||
* HCI total = 5 bytes (1 len + 4)
|
||||
*/
|
||||
static int btintel_send_sar_rev2_band(struct hci_dev *hdev,
|
||||
struct btintel_cp_ddc_write *cmd,
|
||||
u16 id, u8 chain_a, u8 chain_b)
|
||||
{
|
||||
cmd->len = 4;
|
||||
cmd->id = cpu_to_le16(id);
|
||||
cmd->data[0] = chain_a;
|
||||
cmd->data[1] = chain_b;
|
||||
return btintel_send_sar_ddc(hdev, cmd, 5);
|
||||
}
|
||||
|
||||
static int btintel_set_sar_rev2(struct hci_dev *hdev,
|
||||
struct btintel_sar_rev2 *sar)
|
||||
{
|
||||
struct btintel_cp_ddc_write *cmd;
|
||||
struct sk_buff *skb;
|
||||
u8 buffer[64];
|
||||
u8 enable;
|
||||
int ret;
|
||||
|
||||
cmd = (void *)buffer;
|
||||
|
||||
/* DDC 0x019e: enable/disable increased power mode SAR (1 byte) */
|
||||
cmd->len = 3;
|
||||
cmd->id = cpu_to_le16(0x019e);
|
||||
cmd->data[0] = (sar->inc_power_mode == BTINTEL_SAR_INC_PWR_SUPPORTED) ?
|
||||
0x01 : 0x00;
|
||||
ret = btintel_send_sar_ddc(hdev, cmd, 4);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* DDC 0x0311-0x0316: per sub-band ChainA + ChainB limits */
|
||||
ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0311,
|
||||
sar->chain_a.subband_2g4,
|
||||
sar->chain_b.subband_2g4);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0312,
|
||||
sar->chain_a.subband_5g2,
|
||||
sar->chain_b.subband_5g2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* 0x0313 and 0x0314 both carry the 5G8/5G9 value */
|
||||
ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0313,
|
||||
sar->chain_a.subband_5g8_5g9,
|
||||
sar->chain_b.subband_5g8_5g9);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0314,
|
||||
sar->chain_a.subband_5g8_5g9,
|
||||
sar->chain_b.subband_5g8_5g9);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0315,
|
||||
sar->chain_a.subband_6g1,
|
||||
sar->chain_b.subband_6g1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0316,
|
||||
sar->chain_a.subband_6g3,
|
||||
sar->chain_b.subband_6g3);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Notify firmware that SAR initialisation is complete */
|
||||
enable = 0x01;
|
||||
skb = __hci_cmd_sync(hdev, 0xfe25, sizeof(enable), &enable, HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_warn(hdev, "Failed to send Intel SAR Rev2 Enable (%ld)",
|
||||
PTR_ERR(skb));
|
||||
return PTR_ERR(skb);
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btintel_sar_rev2_send_to_device(struct hci_dev *hdev,
|
||||
struct btintel_sar_rev2 *sar,
|
||||
struct intel_version_tlv *ver)
|
||||
{
|
||||
u16 cnvi = ver->cnvi_top & 0xfff;
|
||||
u16 cnvr = ver->cnvr_top & 0xfff;
|
||||
|
||||
if (cnvi < BTINTEL_CNVI_BLAZARI || cnvr != BTINTEL_CNVR_WHP2) {
|
||||
bt_dev_dbg(hdev, "BT SAR Rev2 not supported on this platform (cnvi=0x%x cnvr=0x%x)",
|
||||
cnvi, cnvr);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
bt_dev_info(hdev, "Applying Bluetooth SAR Rev2");
|
||||
return btintel_set_sar_rev2(hdev, sar);
|
||||
}
|
||||
|
||||
static int btintel_sar_send_to_device(struct hci_dev *hdev, struct btintel_sar_inc_pwr *sar,
|
||||
struct intel_version_tlv *ver)
|
||||
{
|
||||
|
|
@ -3130,6 +3234,7 @@ static int btintel_acpi_set_sar(struct hci_dev *hdev, struct intel_version_tlv *
|
|||
{
|
||||
union acpi_object *bt_pkg, *buffer = NULL;
|
||||
struct btintel_sar_inc_pwr sar;
|
||||
struct btintel_sar_rev2 sar_rev2;
|
||||
acpi_status status;
|
||||
u8 revision;
|
||||
int ret;
|
||||
|
|
@ -3150,14 +3255,96 @@ static int btintel_acpi_set_sar(struct hci_dev *hdev, struct intel_version_tlv *
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (buffer->package.elements[0].type != ACPI_TYPE_INTEGER) {
|
||||
bt_dev_warn(hdev, "BT_SAR: unexpected ACPI type for revision field");
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
revision = buffer->package.elements[0].integer.value;
|
||||
|
||||
if (revision > BTINTEL_SAR_INC_PWR) {
|
||||
if (revision > BTINTEL_SAR_REV2) {
|
||||
bt_dev_dbg(hdev, "BT_SAR: revision: 0x%2.2x not supported", revision);
|
||||
ret = -EOPNOTSUPP;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (revision == BTINTEL_SAR_REV2 && bt_pkg->package.count == 13) {
|
||||
/* Element layout: 0 = domain ID (BTINTEL_BT_DOMAIN, 0x12),
|
||||
* 1 = bt_sar_bios (u32), 2 = inc_power_mode (u32),
|
||||
* 3..12 = per-chain sub-band limits (u8 each).
|
||||
*/
|
||||
static const u64 rev2_max[13] = {
|
||||
U8_MAX, /* domain ID */
|
||||
U32_MAX, U32_MAX, /* bt_sar_bios, inc_power_mode */
|
||||
U8_MAX, U8_MAX, U8_MAX, U8_MAX, U8_MAX, /* chain A */
|
||||
U8_MAX, U8_MAX, U8_MAX, U8_MAX, U8_MAX, /* chain B */
|
||||
};
|
||||
union acpi_object *e;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 13; i++) {
|
||||
e = &bt_pkg->package.elements[i];
|
||||
if (e->type != ACPI_TYPE_INTEGER) {
|
||||
bt_dev_warn(hdev, "BT SAR Rev2: unexpected ACPI type at element %d",
|
||||
i);
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
if (e->integer.value > rev2_max[i]) {
|
||||
bt_dev_warn(hdev, "BT SAR Rev2: element %d value 0x%llx out of range",
|
||||
i, e->integer.value);
|
||||
ret = -ERANGE;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&sar_rev2, 0, sizeof(sar_rev2));
|
||||
sar_rev2.revision = revision;
|
||||
sar_rev2.bt_sar_bios = bt_pkg->package.elements[1].integer.value;
|
||||
|
||||
if (sar_rev2.bt_sar_bios != 1) {
|
||||
bt_dev_warn(hdev, "Bluetooth SAR Rev2 is not enabled");
|
||||
ret = -EOPNOTSUPP;
|
||||
goto error;
|
||||
}
|
||||
|
||||
sar_rev2.inc_power_mode = bt_pkg->package.elements[2].integer.value;
|
||||
|
||||
sar_rev2.chain_a.subband_2g4 = bt_pkg->package.elements[3].integer.value;
|
||||
sar_rev2.chain_a.subband_5g2 = bt_pkg->package.elements[4].integer.value;
|
||||
sar_rev2.chain_a.subband_5g8_5g9 = bt_pkg->package.elements[5].integer.value;
|
||||
sar_rev2.chain_a.subband_6g1 = bt_pkg->package.elements[6].integer.value;
|
||||
sar_rev2.chain_a.subband_6g3 = bt_pkg->package.elements[7].integer.value;
|
||||
|
||||
sar_rev2.chain_b.subband_2g4 = bt_pkg->package.elements[8].integer.value;
|
||||
sar_rev2.chain_b.subband_5g2 = bt_pkg->package.elements[9].integer.value;
|
||||
sar_rev2.chain_b.subband_5g8_5g9 = bt_pkg->package.elements[10].integer.value;
|
||||
sar_rev2.chain_b.subband_6g1 = bt_pkg->package.elements[11].integer.value;
|
||||
sar_rev2.chain_b.subband_6g3 = bt_pkg->package.elements[12].integer.value;
|
||||
|
||||
bt_dev_dbg(hdev, "BT SAR Rev2: revision=%u bt_sar_bios=%u inc_power_mode=%u",
|
||||
sar_rev2.revision, sar_rev2.bt_sar_bios, sar_rev2.inc_power_mode);
|
||||
bt_dev_dbg(hdev, "BT SAR Rev2 Chain A: 2g4=%u 5g2=%u 5g8_5g9=%u 6g1=%u 6g3=%u",
|
||||
sar_rev2.chain_a.subband_2g4, sar_rev2.chain_a.subband_5g2,
|
||||
sar_rev2.chain_a.subband_5g8_5g9, sar_rev2.chain_a.subband_6g1,
|
||||
sar_rev2.chain_a.subband_6g3);
|
||||
bt_dev_dbg(hdev, "BT SAR Rev2 Chain B: 2g4=%u 5g2=%u 5g8_5g9=%u 6g1=%u 6g3=%u",
|
||||
sar_rev2.chain_b.subband_2g4, sar_rev2.chain_b.subband_5g2,
|
||||
sar_rev2.chain_b.subband_5g8_5g9, sar_rev2.chain_b.subband_6g1,
|
||||
sar_rev2.chain_b.subband_6g3);
|
||||
|
||||
ret = btintel_sar_rev2_send_to_device(hdev, &sar_rev2, ver);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (revision == BTINTEL_SAR_REV2) {
|
||||
bt_dev_warn(hdev, "BT SAR Rev2: unexpected ACPI package count %d (expected 13)",
|
||||
bt_pkg->package.count);
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
memset(&sar, 0, sizeof(sar));
|
||||
|
||||
if (revision == BTINTEL_SAR_LEGACY && bt_pkg->package.count == 8) {
|
||||
|
|
@ -3804,8 +3991,7 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
struct hci_event_hdr *hdr = (void *)skb->data;
|
||||
const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 };
|
||||
|
||||
if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff &&
|
||||
hdr->plen > 0) {
|
||||
if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff) {
|
||||
const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1;
|
||||
unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1;
|
||||
|
||||
|
|
@ -3834,7 +4020,7 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
/* Handle all diagnostics events separately. May still call
|
||||
* hci_recv_frame.
|
||||
*/
|
||||
if (len >= sizeof(diagnostics_hdr) &&
|
||||
if (len + 1 >= sizeof(diagnostics_hdr) &&
|
||||
memcmp(&skb->data[2], diagnostics_hdr,
|
||||
sizeof(diagnostics_hdr)) == 0) {
|
||||
return btintel_diagnostics(hdev, skb);
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ struct intel_tlv {
|
|||
|
||||
/* CNVR */
|
||||
#define BTINTEL_CNVR_FMP2 0x910
|
||||
#define BTINTEL_CNVR_WHP2 0xA10 /* Whale Peak2 - Panther Lake */
|
||||
|
||||
#define BTINTEL_IMG_BOOTLOADER 0x01 /* Bootloader image */
|
||||
#define BTINTEL_IMG_IML 0x02 /* Intermediate image */
|
||||
|
|
@ -204,6 +205,23 @@ struct btintel_sar_inc_pwr {
|
|||
u8 le_lr;
|
||||
};
|
||||
|
||||
/* Bluetooth SAR feature (BRDS), Revision 2 - per-chain sub-band power limits */
|
||||
struct btintel_sar_band_limits {
|
||||
u8 subband_2g4;
|
||||
u8 subband_5g2;
|
||||
u8 subband_5g8_5g9;
|
||||
u8 subband_6g1;
|
||||
u8 subband_6g3;
|
||||
};
|
||||
|
||||
struct btintel_sar_rev2 {
|
||||
u8 revision;
|
||||
u32 bt_sar_bios; /* 1: BIOS-managed SAR enabled */
|
||||
u32 inc_power_mode; /* 0: supported, 1: disabled */
|
||||
struct btintel_sar_band_limits chain_a;
|
||||
struct btintel_sar_band_limits chain_b;
|
||||
};
|
||||
|
||||
#define INTEL_HW_PLATFORM(cnvx_bt) ((u8)(((cnvx_bt) & 0x0000ff00) >> 8))
|
||||
#define INTEL_HW_VARIANT(cnvx_bt) ((u8)(((cnvx_bt) & 0x003f0000) >> 16))
|
||||
#define INTEL_CNVX_TOP_TYPE(cnvx_top) ((cnvx_top) & 0x00000fff)
|
||||
|
|
|
|||
|
|
@ -1446,72 +1446,134 @@ static int btintel_pcie_dump_fwtrigger_event(struct btintel_pcie_data *data)
|
|||
return err;
|
||||
}
|
||||
|
||||
/* Queue a coredump dump_traces() pass.
|
||||
*
|
||||
* Returns true if a new coredump was queued, false if one was already
|
||||
* in-flight (the BTINTEL_PCIE_COREDUMP_INPROGRESS bit serves as the
|
||||
* single-writer guard for the @coredump_work item) or the workqueue is
|
||||
* disabled (reset / remove in progress).
|
||||
*
|
||||
* Always queue this AFTER any companion event-reader work (hwexp /
|
||||
* fwtrigger) so that, on the ordered @dump_workqueue, the event reader
|
||||
* runs first and populates dmp_hdr.event_type / event_id before
|
||||
* dump_traces consumes them.
|
||||
*/
|
||||
static bool btintel_pcie_queue_coredump(struct btintel_pcie_data *data,
|
||||
u16 trigger_reason)
|
||||
{
|
||||
if (test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
|
||||
return false;
|
||||
|
||||
data->dmp_hdr.trigger_reason = trigger_reason;
|
||||
|
||||
if (queue_work(data->dump_workqueue, &data->coredump_work))
|
||||
return true;
|
||||
|
||||
/* Workqueue is disabled (reset/remove drained it). Release the
|
||||
* guard so a later trigger, after re-probe, can succeed.
|
||||
*/
|
||||
clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void btintel_pcie_msix_fw_trigger_handler(struct btintel_pcie_data *data)
|
||||
{
|
||||
bt_dev_dbg(data->hdev, "Received firmware smart trigger cause");
|
||||
|
||||
if (test_and_set_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags))
|
||||
/* Per-work guard: deduplicate concurrent FW-trigger interrupts.
|
||||
* Cleared at the tail of btintel_pcie_fwtrigger_worker().
|
||||
*/
|
||||
if (test_and_set_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS,
|
||||
&data->flags))
|
||||
return;
|
||||
|
||||
/* Trigger device core dump when there is FW assert */
|
||||
if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
|
||||
data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
|
||||
if (!queue_work(data->dump_workqueue, &data->fwtrigger_work)) {
|
||||
clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags);
|
||||
return;
|
||||
}
|
||||
|
||||
queue_work(data->coredump_workqueue, &data->coredump_work);
|
||||
/* Queue coredump after the fwtrigger event reader so dmp_hdr.event_*
|
||||
* is populated before dump_traces consumes it.
|
||||
*/
|
||||
btintel_pcie_queue_coredump(data, BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT);
|
||||
}
|
||||
|
||||
static void btintel_pcie_msix_hw_exp_handler(struct btintel_pcie_data *data)
|
||||
{
|
||||
bt_dev_err(data->hdev, "Received hw exception interrupt");
|
||||
|
||||
/* CORE_HALTED is the single-writer guard for this handler. It is
|
||||
* set once on first HW exception and cleared only by re-probe
|
||||
* (data is reallocated), so it also serializes hwexp_work
|
||||
* scheduling without needing a separate bit.
|
||||
*/
|
||||
if (test_and_set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags))
|
||||
return;
|
||||
|
||||
if (test_and_set_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags))
|
||||
return;
|
||||
/* Queue companion coredump first so it is appended after hwexp_work
|
||||
* on the ordered @dump_workqueue (preserves the original
|
||||
* coredump-then-hwexp ordering).
|
||||
*/
|
||||
btintel_pcie_queue_coredump(data, BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT);
|
||||
|
||||
/* Trigger device core dump when there is HW exception */
|
||||
if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
|
||||
data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
|
||||
|
||||
queue_work(data->coredump_workqueue, &data->coredump_work);
|
||||
queue_work(data->dump_workqueue, &data->hwexp_work);
|
||||
}
|
||||
|
||||
static void btintel_pcie_coredump_worker(struct work_struct *work)
|
||||
{
|
||||
struct btintel_pcie_data *data = container_of(work,
|
||||
struct btintel_pcie_data, coredump_work);
|
||||
int err;
|
||||
|
||||
/* hdev is NULL until setup_hdev() succeeds, and is cleared on
|
||||
* teardown after disable_work_sync() drains us; bail in that case.
|
||||
*/
|
||||
if (!data->hdev)
|
||||
goto out;
|
||||
|
||||
btintel_pcie_dump_traces(data->hdev);
|
||||
out:
|
||||
/* Release guard last so a new trigger can run only after this
|
||||
* pass has fully completed (including dev_coredumpv()).
|
||||
*/
|
||||
clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
|
||||
}
|
||||
|
||||
static void btintel_pcie_hwexp_worker(struct work_struct *work)
|
||||
{
|
||||
struct btintel_pcie_data *data = container_of(work,
|
||||
struct btintel_pcie_data, hwexp_work);
|
||||
|
||||
if (!data->hdev)
|
||||
return;
|
||||
|
||||
if (test_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags)) {
|
||||
err = btintel_pcie_dump_fwtrigger_event(data);
|
||||
if (err)
|
||||
bt_dev_warn(data->hdev, "failed to log fwtrigger event");
|
||||
clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags);
|
||||
}
|
||||
/* Unlike usb products, controller will not send hardware exception
|
||||
* event on exception. Instead controller writes the hardware event
|
||||
* to device memory along with optional debug events, raises MSIX
|
||||
* and halts. Driver shall read the exception event from device
|
||||
* memory and passes it to the stack for further processing.
|
||||
*
|
||||
* Re-entry is gated by BTINTEL_PCIE_CORE_HALTED in the IRQ
|
||||
* handler, which is only cleared by re-probe; no per-work bit
|
||||
* is needed here.
|
||||
*/
|
||||
btintel_pcie_read_hwexp(data);
|
||||
}
|
||||
|
||||
if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) {
|
||||
btintel_pcie_dump_traces(data->hdev);
|
||||
clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
|
||||
}
|
||||
static void btintel_pcie_fwtrigger_worker(struct work_struct *work)
|
||||
{
|
||||
struct btintel_pcie_data *data = container_of(work,
|
||||
struct btintel_pcie_data, fwtrigger_work);
|
||||
int err;
|
||||
|
||||
if (test_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags)) {
|
||||
/* Unlike usb products, controller will not send hardware
|
||||
* exception event on exception. Instead controller writes the
|
||||
* hardware event to device memory along with optional debug
|
||||
* events, raises MSIX and halts. Driver shall read the
|
||||
* exception event from device memory and passes it stack for
|
||||
* further processing.
|
||||
*/
|
||||
btintel_pcie_read_hwexp(data);
|
||||
clear_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags);
|
||||
}
|
||||
if (!data->hdev)
|
||||
goto out;
|
||||
|
||||
err = btintel_pcie_dump_fwtrigger_event(data);
|
||||
if (err)
|
||||
bt_dev_warn(data->hdev, "failed to log fwtrigger event");
|
||||
out:
|
||||
/* Release guard last; matches set in fw_trigger handler. */
|
||||
clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags);
|
||||
}
|
||||
|
||||
static void btintel_pcie_rx_work(struct work_struct *work)
|
||||
|
|
@ -2363,7 +2425,6 @@ static int btintel_pcie_setup_internal(struct hci_dev *hdev)
|
|||
INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
|
||||
err = -EINVAL;
|
||||
goto exit_error;
|
||||
break;
|
||||
}
|
||||
|
||||
data->dmp_hdr.cnvi_top = ver_tlv.cnvi_top;
|
||||
|
|
@ -2488,8 +2549,6 @@ static void btintel_pcie_inc_recovery_count(struct pci_dev *pdev,
|
|||
}
|
||||
}
|
||||
|
||||
static void btintel_pcie_reset(struct hci_dev *hdev);
|
||||
|
||||
static int btintel_pcie_acpi_reset_method(struct btintel_pcie_data *data)
|
||||
{
|
||||
union acpi_object *obj, argv4;
|
||||
|
|
@ -2650,20 +2709,22 @@ static void btintel_pcie_reset_work(struct work_struct *wk)
|
|||
btintel_pcie_synchronize_irqs(data);
|
||||
|
||||
flush_work(&data->rx_work);
|
||||
/* Drain any in-flight coredump and block new ones across reset.
|
||||
* Safe from self-deadlock: coredump_work runs on a separate wq.
|
||||
/* Drain any in-flight dump workers and block new ones across reset.
|
||||
* Safe from self-deadlock: they all run on a separate wq.
|
||||
*/
|
||||
disable_work_sync(&data->coredump_work);
|
||||
disable_work_sync(&data->hwexp_work);
|
||||
disable_work_sync(&data->fwtrigger_work);
|
||||
|
||||
bt_dev_dbg(data->hdev, "Release bluetooth interface");
|
||||
|
||||
/* Both reset paths follow the same contract: on success they
|
||||
* destroy 'data' via device_reprobe() (a fresh probe re-INIT_WORKs
|
||||
* the coredump_work with disable count 0), so enable_work() must
|
||||
* the dump workers with disable count 0), so enable_work() must
|
||||
* NOT be called on the success path. Only the FLR path can fail
|
||||
* with 'data' still alive, in which case we balance the
|
||||
* disable_work_sync() above so a later successful reset is not
|
||||
* permanently blocked.
|
||||
* disable_work_sync() calls above so a later successful reset is
|
||||
* not permanently blocked.
|
||||
*
|
||||
* pci_lock_rescan_remove() (held above) serializes against PCI
|
||||
* device addition/removal (hotplug), so no device can be added to
|
||||
|
|
@ -2674,64 +2735,134 @@ static void btintel_pcie_reset_work(struct work_struct *wk)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (btintel_pcie_perform_flr(data))
|
||||
if (btintel_pcie_perform_flr(data)) {
|
||||
enable_work(&data->coredump_work);
|
||||
enable_work(&data->hwexp_work);
|
||||
enable_work(&data->fwtrigger_work);
|
||||
}
|
||||
|
||||
out:
|
||||
pci_dev_put(pdev);
|
||||
pci_unlock_rescan_remove();
|
||||
}
|
||||
|
||||
static void btintel_pcie_reset(struct hci_dev *hdev)
|
||||
/* Schedule a device reset of the requested type.
|
||||
*
|
||||
* BTINTEL_PCIE_RECOVERY_IN_PROGRESS serializes all reset requesters
|
||||
* (sysfs reset attribute, hci_cmd_timeout(), hw_error, resume error
|
||||
* path, etc.) so that:
|
||||
*
|
||||
* - dev_data->reset_type is written by exactly one caller (the
|
||||
* thread that wins test_and_set_bit), eliminating the race where
|
||||
* a second hw_error could clobber an already-scheduled reset's
|
||||
* type;
|
||||
* - the write happens AFTER the bit is set, so reset_work observes
|
||||
* it through schedule_work()'s memory ordering;
|
||||
* - losers return without touching reset_type or scheduling the
|
||||
* work, so concurrent triggers are silently coalesced into the
|
||||
* in-flight one (whose recovery will reinitialize the device
|
||||
* regardless of the dropped trigger's variant).
|
||||
*
|
||||
* The bit is cleared only by .remove() / re-probe via fresh devm
|
||||
* allocation, which is the intended one-shot semantics: a reset
|
||||
* tears down and re-probes 'data', so there is no "in-flight"
|
||||
* reset to follow up after device_reprobe() succeeds.
|
||||
*/
|
||||
static void btintel_pcie_request_reset(struct btintel_pcie_data *data,
|
||||
enum btintel_pcie_reset_type type)
|
||||
{
|
||||
struct btintel_pcie_data *data;
|
||||
|
||||
data = hci_get_drvdata(hdev);
|
||||
|
||||
if (!test_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags))
|
||||
return;
|
||||
|
||||
if (test_and_set_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags))
|
||||
return;
|
||||
|
||||
data->reset_type = type;
|
||||
|
||||
pci_dev_get(data->pdev);
|
||||
schedule_work(&data->reset_work);
|
||||
}
|
||||
|
||||
static void btintel_pcie_hci_reset(struct hci_dev *hdev)
|
||||
{
|
||||
struct btintel_pcie_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR);
|
||||
}
|
||||
|
||||
static ssize_t vendor_reset_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int val;
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct btintel_pcie_data *data = pci_get_drvdata(pdev);
|
||||
|
||||
if (!data || !data->hdev)
|
||||
return -ENODEV;
|
||||
|
||||
if (kstrtouint(buf, 10, &val) || val != 0) {
|
||||
bt_dev_warn(data->hdev, "PLDR rejected: invalid input");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bt_dev_info(data->hdev, "PLDR triggered via sysfs");
|
||||
btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_PLDR);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t vendor_reset_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "0 - PLDR\n");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(vendor_reset);
|
||||
|
||||
static struct attribute *btintel_pcie_attrs[] = {
|
||||
&dev_attr_vendor_reset.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(btintel_pcie);
|
||||
|
||||
static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code)
|
||||
{
|
||||
struct btintel_pcie_dev_recovery *data;
|
||||
struct btintel_pcie_dev_recovery *rec;
|
||||
struct btintel_pcie_data *dev_data = hci_get_drvdata(hdev);
|
||||
struct pci_dev *pdev = dev_data->pdev;
|
||||
enum btintel_pcie_reset_type type;
|
||||
time64_t retry_window;
|
||||
|
||||
if (test_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &dev_data->flags))
|
||||
return;
|
||||
|
||||
btintel_pcie_dump_debug_registers(hdev);
|
||||
|
||||
data = btintel_pcie_get_recovery(pdev, &hdev->dev);
|
||||
if (!data)
|
||||
rec = btintel_pcie_get_recovery(pdev, &hdev->dev);
|
||||
if (!rec)
|
||||
return;
|
||||
|
||||
if (code == 0x13)
|
||||
dev_data->reset_type = BTINTEL_PCIE_IOSF_PRR_PLDR;
|
||||
else
|
||||
dev_data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR;
|
||||
type = (code == 0x13) ? BTINTEL_PCIE_IOSF_PRR_PLDR
|
||||
: BTINTEL_PCIE_IOSF_PRR_FLR;
|
||||
|
||||
bt_dev_err(hdev, "Encountered exception err:0x%x triggering: %s", code,
|
||||
dev_data->reset_type == BTINTEL_PCIE_IOSF_PRR_PLDR ? "PLDR" : "FLR");
|
||||
retry_window = ktime_get_boottime_seconds() - data->last_error;
|
||||
type == BTINTEL_PCIE_IOSF_PRR_PLDR ? "PLDR" : "FLR");
|
||||
retry_window = ktime_get_boottime_seconds() - rec->last_error;
|
||||
|
||||
if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS &&
|
||||
data->count >= BTINTEL_PCIE_FLR_MAX_RETRY) {
|
||||
rec->count >= BTINTEL_PCIE_FLR_MAX_RETRY) {
|
||||
bt_dev_err(hdev, "Exhausted maximum: %d recovery attempts: %d",
|
||||
BTINTEL_PCIE_FLR_MAX_RETRY, data->count);
|
||||
BTINTEL_PCIE_FLR_MAX_RETRY, rec->count);
|
||||
bt_dev_dbg(hdev, "Boot time: %lld seconds",
|
||||
ktime_get_boottime_seconds());
|
||||
bt_dev_dbg(hdev, "last error at: %lld seconds",
|
||||
data->last_error);
|
||||
rec->last_error);
|
||||
return;
|
||||
}
|
||||
btintel_pcie_inc_recovery_count(pdev, &hdev->dev);
|
||||
btintel_pcie_reset(hdev);
|
||||
btintel_pcie_request_reset(dev_data, type);
|
||||
}
|
||||
|
||||
static bool btintel_pcie_wakeup(struct hci_dev *hdev)
|
||||
|
|
@ -2821,7 +2952,7 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
|
|||
hdev->hw_error = btintel_pcie_hw_error;
|
||||
hdev->set_diag = btintel_set_diag;
|
||||
hdev->set_bdaddr = btintel_set_bdaddr;
|
||||
hdev->reset = btintel_pcie_reset;
|
||||
hdev->reset = btintel_pcie_hci_reset;
|
||||
hdev->wakeup = btintel_pcie_wakeup;
|
||||
hdev->hci_drv = &btintel_pcie_hci_drv;
|
||||
|
||||
|
|
@ -2869,8 +3000,8 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
|
|||
if (!data->workqueue)
|
||||
return -ENOMEM;
|
||||
|
||||
data->coredump_workqueue = alloc_ordered_workqueue(KBUILD_MODNAME "_cd", 0);
|
||||
if (!data->coredump_workqueue) {
|
||||
data->dump_workqueue = alloc_ordered_workqueue(KBUILD_MODNAME "_cd", 0);
|
||||
if (!data->dump_workqueue) {
|
||||
destroy_workqueue(data->workqueue);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
@ -2879,6 +3010,8 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
|
|||
INIT_WORK(&data->rx_work, btintel_pcie_rx_work);
|
||||
INIT_WORK(&data->reset_work, btintel_pcie_reset_work);
|
||||
INIT_WORK(&data->coredump_work, btintel_pcie_coredump_worker);
|
||||
INIT_WORK(&data->hwexp_work, btintel_pcie_hwexp_worker);
|
||||
INIT_WORK(&data->fwtrigger_work, btintel_pcie_fwtrigger_worker);
|
||||
|
||||
data->boot_stage_cache = 0x00;
|
||||
data->img_resp_cache = 0x00;
|
||||
|
|
@ -2921,7 +3054,7 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
|
|||
/* reset device before exit */
|
||||
btintel_pcie_reset_bt(data);
|
||||
|
||||
destroy_workqueue(data->coredump_workqueue);
|
||||
destroy_workqueue(data->dump_workqueue);
|
||||
|
||||
pci_clear_master(pdev);
|
||||
|
||||
|
|
@ -2940,12 +3073,14 @@ static void btintel_pcie_remove(struct pci_dev *pdev)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Permanently block coredump triggers and drain the worker before
|
||||
* tearing down. Must run before cancel_work_sync(&reset_work) so
|
||||
* the disable counter stays >= 1 even after reset_work()'s
|
||||
/* Permanently block all dump triggers and drain the workers before
|
||||
* tearing down. Must run before disable_work_sync(&reset_work) so
|
||||
* the disable counters stay >= 1 even after reset_work()'s
|
||||
* balanced enable_work() (counter 2 -> 1, never reaching 0).
|
||||
*/
|
||||
disable_work_sync(&data->coredump_work);
|
||||
disable_work_sync(&data->hwexp_work);
|
||||
disable_work_sync(&data->fwtrigger_work);
|
||||
|
||||
/* Cancel pending reset work. Skip only when remove() is called from
|
||||
* within the reset work itself (PLDR device_reprobe path) to avoid
|
||||
|
|
@ -2973,7 +3108,7 @@ static void btintel_pcie_remove(struct pci_dev *pdev)
|
|||
|
||||
btintel_pcie_release_hdev(data);
|
||||
|
||||
destroy_workqueue(data->coredump_workqueue);
|
||||
destroy_workqueue(data->dump_workqueue);
|
||||
destroy_workqueue(data->workqueue);
|
||||
|
||||
btintel_pcie_free(data);
|
||||
|
|
@ -2992,16 +3127,8 @@ static void btintel_pcie_coredump(struct device *dev)
|
|||
if (!data)
|
||||
return;
|
||||
|
||||
if (test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
|
||||
return;
|
||||
|
||||
data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER;
|
||||
/* queue_work() returns false if the work is disabled (reset or
|
||||
* remove in progress); clear the in-progress bit so a later
|
||||
* trigger can succeed once the work is re-enabled.
|
||||
*/
|
||||
if (!queue_work(data->coredump_workqueue, &data->coredump_work))
|
||||
clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
|
||||
btintel_pcie_queue_coredump(data,
|
||||
BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -3113,8 +3240,7 @@ static int btintel_pcie_resume(struct device *dev)
|
|||
if (data->pm_sx_event == PM_EVENT_FREEZE ||
|
||||
data->pm_sx_event == PM_EVENT_HIBERNATE) {
|
||||
set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags);
|
||||
data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR;
|
||||
btintel_pcie_reset(data->hdev);
|
||||
btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3138,14 +3264,10 @@ static int btintel_pcie_resume(struct device *dev)
|
|||
if (btintel_pcie_in_error(data) ||
|
||||
btintel_pcie_in_device_halt(data)) {
|
||||
bt_dev_err(data->hdev, "Controller in error state for D0 entry");
|
||||
if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS,
|
||||
&data->flags)) {
|
||||
data->dmp_hdr.trigger_reason =
|
||||
BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
|
||||
queue_work(data->coredump_workqueue, &data->coredump_work);
|
||||
}
|
||||
btintel_pcie_queue_coredump(data,
|
||||
BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT);
|
||||
set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags);
|
||||
btintel_pcie_reset(data->hdev);
|
||||
btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
|
@ -3165,6 +3287,7 @@ static struct pci_driver btintel_pcie_driver = {
|
|||
.probe = btintel_pcie_probe,
|
||||
.remove = btintel_pcie_remove,
|
||||
.driver.pm = pm_sleep_ptr(&btintel_pcie_pm_ops),
|
||||
.dev_groups = btintel_pcie_groups,
|
||||
#ifdef CONFIG_DEV_COREDUMP
|
||||
.driver.coredump = btintel_pcie_coredump
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -118,7 +118,6 @@ enum {
|
|||
|
||||
enum {
|
||||
BTINTEL_PCIE_CORE_HALTED,
|
||||
BTINTEL_PCIE_HWEXP_INPROGRESS,
|
||||
BTINTEL_PCIE_COREDUMP_INPROGRESS,
|
||||
BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS,
|
||||
BTINTEL_PCIE_RECOVERY_IN_PROGRESS,
|
||||
|
|
@ -466,8 +465,11 @@ struct btintel_pcie_dump_header {
|
|||
* @workqueue: workqueue for RX work
|
||||
* @rx_skb_q: SKB queue for RX packet
|
||||
* @rx_work: RX work struct to process the RX packet in @rx_skb_q
|
||||
* @coredump_workqueue: dedicated workqueue for coredump collection
|
||||
* @coredump_work: work struct for coredump trace collection
|
||||
* @dump_workqueue: dedicated ordered workqueue serializing the coredump,
|
||||
* hardware exception, and firmware-trigger dump workers
|
||||
* @coredump_work: work struct for DRAM trace coredump collection
|
||||
* @hwexp_work: work struct for hardware exception event read
|
||||
* @fwtrigger_work: work struct for firmware-triggered diagnostic event read
|
||||
* @dma_pool: DMA pool for descriptors, index array and ci
|
||||
* @dma_p_addr: DMA address for pool
|
||||
* @dma_v_addr: address of pool
|
||||
|
|
@ -516,8 +518,10 @@ struct btintel_pcie_data {
|
|||
struct work_struct rx_work;
|
||||
struct work_struct reset_work;
|
||||
|
||||
struct workqueue_struct *coredump_workqueue;
|
||||
struct workqueue_struct *dump_workqueue;
|
||||
struct work_struct coredump_work;
|
||||
struct work_struct hwexp_work;
|
||||
struct work_struct fwtrigger_work;
|
||||
|
||||
struct dma_pool *dma_pool;
|
||||
dma_addr_t dma_p_addr;
|
||||
|
|
|
|||
|
|
@ -43,10 +43,17 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
|
|||
{
|
||||
struct hci_event_hdr *hdr = (void *) skb->data;
|
||||
|
||||
if (skb->len < sizeof(*hdr))
|
||||
return true;
|
||||
|
||||
if (hdr->evt == HCI_EV_CMD_COMPLETE) {
|
||||
struct hci_ev_cmd_complete *ec;
|
||||
u16 opcode;
|
||||
|
||||
if (hdr->plen < sizeof(*ec) ||
|
||||
skb->len < HCI_EVENT_HDR_SIZE + sizeof(*ec))
|
||||
return true;
|
||||
|
||||
ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE);
|
||||
opcode = __le16_to_cpu(ec->opcode);
|
||||
|
||||
|
|
@ -74,6 +81,9 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
|
|||
struct btmrvl_event *event;
|
||||
int ret = 0;
|
||||
|
||||
if (skb->len <= offsetof(typeof(*event), data[0]))
|
||||
return -EINVAL;
|
||||
|
||||
event = (struct btmrvl_event *) skb->data;
|
||||
if (event->ec != 0xff) {
|
||||
BT_DBG("Not Marvell Event=%x", event->ec);
|
||||
|
|
@ -83,6 +93,8 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
|
|||
|
||||
switch (event->data[0]) {
|
||||
case BT_EVENT_AUTO_SLEEP_MODE:
|
||||
if (skb->len <= offsetof(typeof(*event), data[2]))
|
||||
return -EINVAL;
|
||||
if (!event->data[2]) {
|
||||
if (event->data[1] == BT_PS_ENABLE)
|
||||
adapter->psmode = 1;
|
||||
|
|
@ -96,6 +108,8 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
|
|||
break;
|
||||
|
||||
case BT_EVENT_HOST_SLEEP_CONFIG:
|
||||
if (skb->len <= offsetof(typeof(*event), data[3]))
|
||||
return -EINVAL;
|
||||
if (!event->data[3])
|
||||
BT_DBG("gpio=%x, gap=%x", event->data[1],
|
||||
event->data[2]);
|
||||
|
|
@ -104,6 +118,8 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
|
|||
break;
|
||||
|
||||
case BT_EVENT_HOST_SLEEP_ENABLE:
|
||||
if (skb->len <= offsetof(typeof(*event), data[1]))
|
||||
return -EINVAL;
|
||||
if (!event->data[1]) {
|
||||
adapter->hs_state = HS_ACTIVATED;
|
||||
if (adapter->psmode)
|
||||
|
|
@ -116,6 +132,8 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
|
|||
break;
|
||||
|
||||
case BT_EVENT_MODULE_CFG_REQ:
|
||||
if (skb->len <= offsetof(typeof(*event), data[2]))
|
||||
return -EINVAL;
|
||||
if (priv->btmrvl_dev.sendcmdflag &&
|
||||
event->data[1] == MODULE_BRINGUP_REQ) {
|
||||
BT_DBG("EVENT:%s",
|
||||
|
|
@ -133,6 +151,8 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
|
|||
break;
|
||||
|
||||
case BT_EVENT_POWER_STATE:
|
||||
if (skb->len <= offsetof(typeof(*event), data[1]))
|
||||
return -EINVAL;
|
||||
if (event->data[1] == BT_PS_SLEEP)
|
||||
adapter->ps_state = PS_SLEEP;
|
||||
BT_DBG("EVENT:%s",
|
||||
|
|
|
|||
|
|
@ -799,7 +799,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
|
|||
skb_pull(skb, SDIO_HEADER_LEN);
|
||||
|
||||
if (btmrvl_process_event(priv, skb))
|
||||
hci_recv_frame(hdev, skb);
|
||||
kfree_skb(skb);
|
||||
|
||||
hdev->stat.byte_rx += buf_len;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1480,6 +1480,9 @@ static void btmtksdio_remove(struct sdio_func *func)
|
|||
if (test_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state))
|
||||
btmtksdio_close(hdev);
|
||||
|
||||
if (bdev->data->pm_runtime_supported)
|
||||
pm_runtime_dont_use_autosuspend(bdev->dev);
|
||||
|
||||
/* Be consistent the state in btmtksdio_probe */
|
||||
pm_runtime_get_noresume(bdev->dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include <linux/serdev.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/pwrseq/consumer.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/firmware.h>
|
||||
|
|
@ -211,6 +213,7 @@ struct btnxpuart_dev {
|
|||
|
||||
struct ps_data psdata;
|
||||
struct btnxpuart_data *nxp_data;
|
||||
struct pwrseq_desc *pwrseq;
|
||||
struct reset_control *pdn;
|
||||
struct hci_uart hu;
|
||||
};
|
||||
|
|
@ -1331,19 +1334,7 @@ static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev)
|
|||
|
||||
static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
|
||||
{
|
||||
static const u8 ir_hw_err[] = { HCI_EV_HARDWARE_ERROR,
|
||||
0x01, BTNXPUART_IR_HW_ERR };
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = bt_skb_alloc(3, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
|
||||
skb_put_data(skb, ir_hw_err, 3);
|
||||
|
||||
/* Inject Hardware Error to upper stack */
|
||||
return hci_recv_frame(hdev, skb);
|
||||
return __hci_reset_dev(hdev, BTNXPUART_IR_HW_ERR);
|
||||
}
|
||||
|
||||
/* Firmware dump */
|
||||
|
|
@ -1872,11 +1863,26 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
if (of_graph_is_present(dev_of_node(&serdev->ctrl->dev))) {
|
||||
struct pwrseq_desc *pwrseq;
|
||||
|
||||
pwrseq = pwrseq_get(&serdev->ctrl->dev, "uart");
|
||||
if (IS_ERR(pwrseq))
|
||||
return dev_err_probe(&serdev->dev, PTR_ERR(pwrseq),
|
||||
"failed to get pwrseq\n");
|
||||
|
||||
nxpdev->pwrseq = pwrseq;
|
||||
err = pwrseq_power_on(pwrseq);
|
||||
if (err)
|
||||
goto err_pwrseq_put;
|
||||
}
|
||||
|
||||
/* Initialize and register HCI device */
|
||||
hdev = hci_alloc_dev();
|
||||
if (!hdev) {
|
||||
dev_err(&serdev->dev, "Can't allocate HCI device\n");
|
||||
return -ENOMEM;
|
||||
err = -ENOMEM;
|
||||
goto err_pwrseq_put;
|
||||
}
|
||||
|
||||
reset_control_deassert(nxpdev->pdn);
|
||||
|
|
@ -1907,23 +1913,31 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
|
|||
if (bacmp(&ba, BDADDR_ANY))
|
||||
hci_set_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY);
|
||||
|
||||
if (hci_register_dev(hdev) < 0) {
|
||||
err = hci_register_dev(hdev);
|
||||
if (err < 0) {
|
||||
dev_err(&serdev->dev, "Can't register HCI device\n");
|
||||
goto probe_fail;
|
||||
}
|
||||
|
||||
if (ps_setup(hdev))
|
||||
goto probe_fail;
|
||||
if (ps_setup(hdev)) {
|
||||
err = -ENODEV;
|
||||
goto probe_fail_unregister;
|
||||
}
|
||||
|
||||
hci_devcd_register(hdev, nxp_coredump, nxp_coredump_hdr,
|
||||
nxp_coredump_notify);
|
||||
|
||||
return 0;
|
||||
|
||||
probe_fail_unregister:
|
||||
hci_unregister_dev(hdev);
|
||||
probe_fail:
|
||||
reset_control_assert(nxpdev->pdn);
|
||||
hci_free_dev(hdev);
|
||||
return -ENODEV;
|
||||
err_pwrseq_put:
|
||||
if (nxpdev->pwrseq)
|
||||
pwrseq_put(nxpdev->pwrseq);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void nxp_serdev_remove(struct serdev_device *serdev)
|
||||
|
|
@ -1950,6 +1964,8 @@ static void nxp_serdev_remove(struct serdev_device *serdev)
|
|||
ps_cleanup(nxpdev);
|
||||
hci_unregister_dev(hdev);
|
||||
reset_control_assert(nxpdev->pdn);
|
||||
if (nxpdev->pwrseq)
|
||||
pwrseq_put(nxpdev->pwrseq);
|
||||
hci_free_dev(hdev);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -190,25 +190,6 @@ static int qca_send_patch_config_cmd(struct hci_dev *hdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int qca_send_reset(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
bt_dev_dbg(hdev, "QCA HCI_RESET");
|
||||
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
bt_dev_err(hdev, "QCA Reset failed (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qca_read_fw_board_id(struct hci_dev *hdev, u16 *bid)
|
||||
{
|
||||
u8 cmd;
|
||||
|
|
@ -990,11 +971,12 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
|||
}
|
||||
|
||||
/* Perform HCI reset */
|
||||
err = qca_send_reset(hdev);
|
||||
err = __hci_reset_sync(hdev);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "QCA Failed to run HCI_RESET (%d)", err);
|
||||
return err;
|
||||
}
|
||||
bt_dev_dbg(hdev, "QCA HCI_RESET succeed");
|
||||
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3991:
|
||||
|
|
@ -1029,8 +1011,7 @@ int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
|||
baswap(&bdaddr_swapped, bdaddr);
|
||||
|
||||
skb = __hci_cmd_sync_ev(hdev, EDL_WRITE_BD_ADDR_OPCODE, 6,
|
||||
&bdaddr_swapped, HCI_EV_VENDOR,
|
||||
HCI_INIT_TIMEOUT);
|
||||
&bdaddr_swapped, 0, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
bt_dev_err(hdev, "QCA Change address cmd failed (%d)", err);
|
||||
|
|
|
|||
|
|
@ -107,7 +107,6 @@ static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
|
|||
return -ENOMEM;
|
||||
|
||||
h_adapter->priv = priv;
|
||||
ops->set_bt_context(priv, h_adapter);
|
||||
h_adapter->proto_ops = ops;
|
||||
|
||||
hdev = hci_alloc_dev();
|
||||
|
|
@ -136,6 +135,8 @@ static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
|
|||
goto err;
|
||||
}
|
||||
|
||||
ops->set_bt_context(priv, h_adapter);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
h_adapter->hdev = NULL;
|
||||
|
|
|
|||
|
|
@ -297,6 +297,8 @@ static const struct usb_device_id quirks_table[] = {
|
|||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3501), .driver_info = BTUSB_QCA_ROME |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3503), .driver_info = BTUSB_QCA_ROME |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* QCA WCN6855 chipset */
|
||||
{ USB_DEVICE(0x0489, 0xe0c7), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
|
|
@ -679,6 +681,8 @@ static const struct usb_device_id quirks_table[] = {
|
|||
{ USB_DEVICE(0x13d3, 0x3606), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
/* MediaTek MT7902 Bluetooth devices */
|
||||
{ USB_DEVICE(0x0489, 0xe156), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0e8d, 0x1ede), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3579), .driver_info = BTUSB_MEDIATEK |
|
||||
|
|
@ -796,6 +800,8 @@ static const struct usb_device_id quirks_table[] = {
|
|||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3613), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3625), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3627), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3628), .driver_info = BTUSB_MEDIATEK |
|
||||
|
|
@ -850,6 +856,12 @@ static const struct usb_device_id quirks_table[] = {
|
|||
{ USB_DEVICE(0x37ad, 0x0600), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Additional Realtek 8761CU Bluetooth devices */
|
||||
{ USB_DEVICE(0x0b05, 0x1bef), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0b05, 0x1d70), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Additional Realtek 8821AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK },
|
||||
|
|
@ -882,6 +894,8 @@ static const struct usb_device_id quirks_table[] = {
|
|||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0bda, 0xc123), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x1357, 0xc123), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0cb5, 0xc547), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
|
|
@ -937,6 +951,10 @@ struct qca_dump_info {
|
|||
u16 ram_dump_seqno;
|
||||
};
|
||||
|
||||
struct btqca_data {
|
||||
struct qca_dump_info qca_dump;
|
||||
};
|
||||
|
||||
#define BTUSB_MAX_ISOC_FRAMES 10
|
||||
|
||||
#define BTUSB_INTR_RUNNING 0
|
||||
|
|
@ -1010,6 +1028,7 @@ struct btusb_data {
|
|||
bool usb_alt6_packet_flow;
|
||||
int isoc_altsetting;
|
||||
int suspend_count;
|
||||
const struct usb_device_id *match_id;
|
||||
|
||||
int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
int (*recv_acl)(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
|
|
@ -1022,8 +1041,6 @@ struct btusb_data {
|
|||
int (*disconnect)(struct hci_dev *hdev);
|
||||
|
||||
int oob_wake_irq; /* irq for out-of-band wake-on-bt */
|
||||
|
||||
struct qca_dump_info qca_dump;
|
||||
};
|
||||
|
||||
static void btusb_reset(struct hci_dev *hdev)
|
||||
|
|
@ -1235,14 +1252,16 @@ static inline void btusb_free_frags(struct btusb_data *data)
|
|||
spin_unlock_irqrestore(&data->rxlock, flags);
|
||||
}
|
||||
|
||||
static int btusb_recv_event(struct btusb_data *data, struct sk_buff *skb)
|
||||
static int btusb_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
if (data->intr_interval) {
|
||||
/* Trigger dequeue immediately if an event is received */
|
||||
schedule_delayed_work(&data->rx_work, 0);
|
||||
}
|
||||
|
||||
return data->recv_event(data->hdev, skb);
|
||||
return data->recv_event(hdev, skb);
|
||||
}
|
||||
|
||||
static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
|
||||
|
|
@ -1302,7 +1321,7 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
|
|||
}
|
||||
|
||||
/* Complete frame */
|
||||
btusb_recv_event(data, skb);
|
||||
btusb_recv_event(data->hdev, skb);
|
||||
skb = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -1313,13 +1332,15 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int btusb_recv_acl(struct btusb_data *data, struct sk_buff *skb)
|
||||
static int btusb_recv_acl(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
/* Only queue ACL packet if intr_interval is set as it means
|
||||
* force_poll_sync has been enabled.
|
||||
*/
|
||||
if (!data->intr_interval)
|
||||
return data->recv_acl(data->hdev, skb);
|
||||
return data->recv_acl(hdev, skb);
|
||||
|
||||
skb_queue_tail(&data->acl_q, skb);
|
||||
schedule_delayed_work(&data->rx_work, data->intr_interval);
|
||||
|
|
@ -1358,10 +1379,8 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
|
|||
hci_skb_expect(skb) -= len;
|
||||
|
||||
if (skb->len == HCI_ACL_HDR_SIZE) {
|
||||
__le16 dlen = hci_acl_hdr(skb)->dlen;
|
||||
|
||||
/* Complete ACL header */
|
||||
hci_skb_expect(skb) = __le16_to_cpu(dlen);
|
||||
hci_skb_expect(skb) = hci_acl_dlen(skb);
|
||||
|
||||
if (skb_tailroom(skb) < hci_skb_expect(skb)) {
|
||||
kfree_skb(skb);
|
||||
|
|
@ -1374,7 +1393,7 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
|
|||
|
||||
if (!hci_skb_expect(skb)) {
|
||||
/* Complete frame */
|
||||
btusb_recv_acl(data, skb);
|
||||
btusb_recv_acl(data->hdev, skb);
|
||||
skb = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -2053,6 +2072,14 @@ static void btusb_stop_traffic(struct btusb_data *data)
|
|||
usb_kill_anchored_urbs(&data->ctrl_anchor);
|
||||
}
|
||||
|
||||
static void btusb_prepare_reset(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
btusb_stop_traffic(data);
|
||||
usb_kill_anchored_urbs(&data->tx_anchor);
|
||||
}
|
||||
|
||||
static int btusb_close(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
|
|
@ -2783,7 +2810,7 @@ static int btusb_setup_realtek(struct hci_dev *hdev)
|
|||
static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
if (skb->len >= HCI_EVENT_HDR_SIZE + 1 &&
|
||||
skb->data[0] == HCI_VENDOR_PKT &&
|
||||
skb->data[0] == HCI_EV_VENDOR &&
|
||||
skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
|
||||
struct rtk_dev_coredump_hdr hdr = {
|
||||
.code = RTK_DEVCOREDUMP_CODE_MEMDUMP,
|
||||
|
|
@ -2897,8 +2924,7 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
|
|||
/* Release MediaTek ISO data interface */
|
||||
btusb_mtk_release_iso_intf(hdev);
|
||||
|
||||
btusb_stop_traffic(data);
|
||||
usb_kill_anchored_urbs(&data->tx_anchor);
|
||||
btusb_prepare_reset(hdev);
|
||||
|
||||
/* Toggle the hard reset line. The MediaTek device is going to
|
||||
* yank itself off the USB and then replug. The cleanup is handled
|
||||
|
|
@ -3072,14 +3098,15 @@ static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev,
|
|||
static int btusb_set_bdaddr_wcn6855(struct hci_dev *hdev,
|
||||
const bdaddr_t *bdaddr)
|
||||
{
|
||||
bdaddr_t bdaddr_swapped;
|
||||
struct sk_buff *skb;
|
||||
u8 buf[6];
|
||||
long ret;
|
||||
|
||||
memcpy(buf, bdaddr, sizeof(bdaddr_t));
|
||||
baswap(&bdaddr_swapped, bdaddr);
|
||||
|
||||
skb = __hci_cmd_sync_ev(hdev, 0xfc14, sizeof(buf), buf,
|
||||
HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);
|
||||
skb = __hci_cmd_sync_ev(hdev, 0xfc14, sizeof(bdaddr_swapped),
|
||||
&bdaddr_swapped, HCI_EV_CMD_COMPLETE,
|
||||
HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
bt_dev_err(hdev, "Change address command failed (%ld)", ret);
|
||||
|
|
@ -3115,14 +3142,15 @@ struct qca_dump_hdr {
|
|||
static void btusb_dump_hdr_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
char buf[128];
|
||||
struct btusb_data *btdata = hci_get_drvdata(hdev);
|
||||
struct btqca_data *btqca_data = hci_get_priv(hdev);
|
||||
struct qca_dump_info *qca_dump_ptr = &btqca_data->qca_dump;
|
||||
|
||||
snprintf(buf, sizeof(buf), "Controller Name: 0x%x\n",
|
||||
btdata->qca_dump.controller_id);
|
||||
qca_dump_ptr->controller_id);
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "Firmware Version: 0x%x\n",
|
||||
btdata->qca_dump.fw_version);
|
||||
qca_dump_ptr->fw_version);
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "Driver: %s\nVendor: qca\n",
|
||||
|
|
@ -3130,7 +3158,7 @@ static void btusb_dump_hdr_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
skb_put_data(skb, buf, strlen(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "VID: 0x%x\nPID:0x%x\n",
|
||||
btdata->qca_dump.id_vendor, btdata->qca_dump.id_product);
|
||||
qca_dump_ptr->id_vendor, qca_dump_ptr->id_product);
|
||||
skb_put_data(skb, buf, strlen(buf));
|
||||
|
||||
snprintf(buf, sizeof(buf), "Lmp Subversion: 0x%x\n",
|
||||
|
|
@ -3159,6 +3187,8 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
|
||||
struct qca_dump_hdr *dump_hdr;
|
||||
struct btusb_data *btdata = hci_get_drvdata(hdev);
|
||||
struct btqca_data *btqca_data = hci_get_priv(hdev);
|
||||
struct qca_dump_info *qca_dump_ptr = &btqca_data->qca_dump;
|
||||
struct usb_device *udev = btdata->udev;
|
||||
|
||||
pkt_type = hci_skb_pkt_type(skb);
|
||||
|
|
@ -3186,8 +3216,8 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
goto out;
|
||||
}
|
||||
|
||||
btdata->qca_dump.ram_dump_size = dump_size;
|
||||
btdata->qca_dump.ram_dump_seqno = 0;
|
||||
qca_dump_ptr->ram_dump_size = dump_size;
|
||||
qca_dump_ptr->ram_dump_seqno = 0;
|
||||
|
||||
skb_pull(skb, offsetof(struct qca_dump_hdr, data0));
|
||||
|
||||
|
|
@ -3199,29 +3229,29 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
skb_pull(skb, offsetof(struct qca_dump_hdr, data));
|
||||
}
|
||||
|
||||
if (!btdata->qca_dump.ram_dump_size) {
|
||||
if (!qca_dump_ptr->ram_dump_size) {
|
||||
ret = -EINVAL;
|
||||
bt_dev_err(hdev, "memdump is not active");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((seqno > btdata->qca_dump.ram_dump_seqno + 1) && (seqno != QCA_LAST_SEQUENCE_NUM)) {
|
||||
dump_size = QCA_MEMDUMP_PKT_SIZE * (seqno - btdata->qca_dump.ram_dump_seqno - 1);
|
||||
if ((seqno > qca_dump_ptr->ram_dump_seqno + 1) && seqno != QCA_LAST_SEQUENCE_NUM) {
|
||||
dump_size = QCA_MEMDUMP_PKT_SIZE * (seqno - qca_dump_ptr->ram_dump_seqno - 1);
|
||||
hci_devcd_append_pattern(hdev, 0x0, dump_size);
|
||||
bt_dev_err(hdev,
|
||||
"expected memdump seqno(%u) is not received(%u)\n",
|
||||
btdata->qca_dump.ram_dump_seqno, seqno);
|
||||
btdata->qca_dump.ram_dump_seqno = seqno;
|
||||
qca_dump_ptr->ram_dump_seqno, seqno);
|
||||
qca_dump_ptr->ram_dump_seqno = seqno;
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
hci_devcd_append(hdev, skb);
|
||||
btdata->qca_dump.ram_dump_seqno++;
|
||||
qca_dump_ptr->ram_dump_seqno++;
|
||||
if (seqno == QCA_LAST_SEQUENCE_NUM) {
|
||||
bt_dev_info(hdev,
|
||||
"memdump done: pkts(%u), total(%u)\n",
|
||||
btdata->qca_dump.ram_dump_seqno, btdata->qca_dump.ram_dump_size);
|
||||
qca_dump_ptr->ram_dump_seqno, qca_dump_ptr->ram_dump_size);
|
||||
|
||||
hci_devcd_complete(hdev);
|
||||
goto out;
|
||||
|
|
@ -3229,10 +3259,10 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
return ret;
|
||||
|
||||
out:
|
||||
if (btdata->qca_dump.ram_dump_size)
|
||||
if (qca_dump_ptr->ram_dump_size)
|
||||
usb_enable_autosuspend(udev);
|
||||
btdata->qca_dump.ram_dump_size = 0;
|
||||
btdata->qca_dump.ram_dump_seqno = 0;
|
||||
qca_dump_ptr->ram_dump_size = 0;
|
||||
qca_dump_ptr->ram_dump_seqno = 0;
|
||||
clear_bit(BTUSB_HW_SSR_ACTIVE, &btdata->flags);
|
||||
|
||||
if (ret < 0)
|
||||
|
|
@ -3257,7 +3287,7 @@ static bool acl_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
goto out;
|
||||
|
||||
event_hdr = skb_pull_data(clone, sizeof(*event_hdr));
|
||||
if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT))
|
||||
if (!event_hdr || event_hdr->evt != HCI_EV_VENDOR)
|
||||
goto out;
|
||||
|
||||
dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr));
|
||||
|
|
@ -3283,7 +3313,7 @@ static bool evt_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
return false;
|
||||
|
||||
event_hdr = skb_pull_data(clone, sizeof(*event_hdr));
|
||||
if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT))
|
||||
if (!event_hdr || event_hdr->evt != HCI_EV_VENDOR)
|
||||
goto out;
|
||||
|
||||
dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr));
|
||||
|
|
@ -3695,8 +3725,12 @@ static int btusb_setup_qca(struct hci_dev *hdev)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
btdata->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
|
||||
btdata->qca_dump.controller_id = le32_to_cpu(ver.rom_version);
|
||||
if (btdata->match_id->driver_info & BTUSB_QCA_WCN6855) {
|
||||
struct btqca_data *btqca_data = hci_get_priv(hdev);
|
||||
|
||||
btqca_data->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
|
||||
btqca_data->qca_dump.controller_id = le32_to_cpu(ver.rom_version);
|
||||
}
|
||||
|
||||
if (!(status & QCA_SYSCFG_UPDATED)) {
|
||||
err = btusb_setup_qca_load_nvm(hdev, &ver, info);
|
||||
|
|
@ -3877,16 +3911,13 @@ static bool btusb_wakeup(struct hci_dev *hdev)
|
|||
|
||||
static int btusb_shutdown_qca(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
err = __hci_reset_sync(hdev);
|
||||
if (err)
|
||||
bt_dev_err(hdev, "HCI reset during shutdown failed");
|
||||
return PTR_ERR(skb);
|
||||
}
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static ssize_t force_poll_sync_read(struct file *file, char __user *user_buf,
|
||||
|
|
@ -4070,7 +4101,7 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
struct btusb_data *data;
|
||||
struct hci_dev *hdev;
|
||||
unsigned ifnum_base;
|
||||
int err, priv_size;
|
||||
int err, priv_size = 0;
|
||||
|
||||
BT_DBG("intf %p id %p", intf, id);
|
||||
|
||||
|
|
@ -4089,7 +4120,7 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
id = match;
|
||||
}
|
||||
|
||||
if (id->driver_info == BTUSB_IGNORE)
|
||||
if (id->driver_info & BTUSB_IGNORE)
|
||||
return -ENODEV;
|
||||
|
||||
if (id->driver_info & BTUSB_ATH3012) {
|
||||
|
|
@ -4107,6 +4138,7 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->match_id = id;
|
||||
err = usb_find_common_endpoints(intf->cur_altsetting, &data->bulk_rx_ep,
|
||||
&data->bulk_tx_ep, &data->intr_ep, NULL);
|
||||
if (err)
|
||||
|
|
@ -4140,8 +4172,6 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
init_usb_anchor(&data->ctrl_anchor);
|
||||
spin_lock_init(&data->rxlock);
|
||||
|
||||
priv_size = 0;
|
||||
|
||||
data->recv_event = hci_recv_frame;
|
||||
data->recv_bulk = btusb_recv_bulk;
|
||||
|
||||
|
|
@ -4160,6 +4190,9 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
} else if (id->driver_info & BTUSB_MEDIATEK) {
|
||||
/* Allocate extra space for Mediatek device */
|
||||
priv_size += sizeof(struct btmtk_data);
|
||||
} else if (id->driver_info & BTUSB_QCA_WCN6855) {
|
||||
/* Allocate extra space for QCA WCN6855 device */
|
||||
priv_size += sizeof(struct btqca_data);
|
||||
}
|
||||
|
||||
data->recv_acl = hci_recv_frame;
|
||||
|
|
@ -4302,8 +4335,10 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
}
|
||||
|
||||
if (id->driver_info & BTUSB_QCA_WCN6855) {
|
||||
data->qca_dump.id_vendor = id->idVendor;
|
||||
data->qca_dump.id_product = id->idProduct;
|
||||
struct btqca_data *btqca_data = hci_get_priv(hdev);
|
||||
|
||||
btqca_data->qca_dump.id_vendor = id->idVendor;
|
||||
btqca_data->qca_dump.id_product = id->idProduct;
|
||||
data->recv_event = btusb_recv_evt_qca;
|
||||
data->recv_acl = btusb_recv_acl_qca;
|
||||
hci_devcd_register(hdev, btusb_coredump_qca, btusb_dump_hdr_qca, NULL);
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ static int aml_download_firmware(struct hci_dev *hdev, const char *fw_name)
|
|||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
struct aml_serdev *amldev = serdev_device_get_drvdata(hu->serdev);
|
||||
const struct firmware *firmware = NULL;
|
||||
struct aml_fw_len *fw_len = NULL;
|
||||
const struct aml_fw_len *fw_len = NULL;
|
||||
u8 *iccm_start = NULL, *dccm_start = NULL;
|
||||
u32 iccm_len, dccm_len;
|
||||
u32 value = 0;
|
||||
|
|
@ -281,7 +281,21 @@ static int aml_download_firmware(struct hci_dev *hdev, const char *fw_name)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
fw_len = (struct aml_fw_len *)firmware->data;
|
||||
if (firmware->size < sizeof(*fw_len)) {
|
||||
bt_dev_err(hdev, "Firmware is too small for its header");
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
fw_len = (const struct aml_fw_len *)firmware->data;
|
||||
if (fw_len->iccm_len < amldev->aml_dev_data->iccm_offset ||
|
||||
fw_len->iccm_len > firmware->size - sizeof(*fw_len) ||
|
||||
fw_len->dccm_len > firmware->size - sizeof(*fw_len) -
|
||||
fw_len->iccm_len) {
|
||||
bt_dev_err(hdev, "Invalid firmware segment lengths");
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Download ICCM */
|
||||
iccm_start = (u8 *)(firmware->data) + sizeof(struct aml_fw_len)
|
||||
|
|
|
|||
|
|
@ -1314,174 +1314,174 @@ static struct bcm_device_data bcm43430_device_data = {
|
|||
};
|
||||
|
||||
static const struct acpi_device_id bcm_acpi_match[] = {
|
||||
{ "BCM2E00" },
|
||||
{ "BCM2E01" },
|
||||
{ "BCM2E02" },
|
||||
{ "BCM2E03" },
|
||||
{ "BCM2E04" },
|
||||
{ "BCM2E05" },
|
||||
{ "BCM2E06" },
|
||||
{ "BCM2E07" },
|
||||
{ "BCM2E08" },
|
||||
{ "BCM2E09" },
|
||||
{ "BCM2E0A" },
|
||||
{ "BCM2E0B" },
|
||||
{ "BCM2E0C" },
|
||||
{ "BCM2E0D" },
|
||||
{ "BCM2E0E" },
|
||||
{ "BCM2E0F" },
|
||||
{ "BCM2E10" },
|
||||
{ "BCM2E11" },
|
||||
{ "BCM2E12" },
|
||||
{ "BCM2E13" },
|
||||
{ "BCM2E14" },
|
||||
{ "BCM2E15" },
|
||||
{ "BCM2E16" },
|
||||
{ "BCM2E17" },
|
||||
{ "BCM2E18" },
|
||||
{ "BCM2E19" },
|
||||
{ "BCM2E1A" },
|
||||
{ "BCM2E1B" },
|
||||
{ "BCM2E1C" },
|
||||
{ "BCM2E1D" },
|
||||
{ "BCM2E1F" },
|
||||
{ "BCM2E20" },
|
||||
{ "BCM2E21" },
|
||||
{ "BCM2E22" },
|
||||
{ "BCM2E23" },
|
||||
{ "BCM2E24" },
|
||||
{ "BCM2E25" },
|
||||
{ "BCM2E26" },
|
||||
{ "BCM2E27" },
|
||||
{ "BCM2E28" },
|
||||
{ "BCM2E29" },
|
||||
{ "BCM2E2A" },
|
||||
{ "BCM2E2B" },
|
||||
{ "BCM2E2C" },
|
||||
{ "BCM2E2D" },
|
||||
{ "BCM2E2E" },
|
||||
{ "BCM2E2F" },
|
||||
{ "BCM2E30" },
|
||||
{ "BCM2E31" },
|
||||
{ "BCM2E32" },
|
||||
{ "BCM2E33" },
|
||||
{ "BCM2E34" },
|
||||
{ "BCM2E35" },
|
||||
{ "BCM2E36" },
|
||||
{ "BCM2E37" },
|
||||
{ "BCM2E38" },
|
||||
{ "BCM2E39" },
|
||||
{ "BCM2E3A" },
|
||||
{ "BCM2E3B" },
|
||||
{ "BCM2E3C" },
|
||||
{ "BCM2E3D" },
|
||||
{ "BCM2E3E" },
|
||||
{ "BCM2E3F" },
|
||||
{ "BCM2E40" },
|
||||
{ "BCM2E41" },
|
||||
{ "BCM2E42" },
|
||||
{ "BCM2E43" },
|
||||
{ "BCM2E44" },
|
||||
{ "BCM2E45" },
|
||||
{ "BCM2E46" },
|
||||
{ "BCM2E47" },
|
||||
{ "BCM2E48" },
|
||||
{ "BCM2E49" },
|
||||
{ "BCM2E4A" },
|
||||
{ "BCM2E4B" },
|
||||
{ "BCM2E4C" },
|
||||
{ "BCM2E4D" },
|
||||
{ "BCM2E4E" },
|
||||
{ "BCM2E4F" },
|
||||
{ "BCM2E50" },
|
||||
{ "BCM2E51" },
|
||||
{ "BCM2E52" },
|
||||
{ "BCM2E53" },
|
||||
{ "BCM2E54" },
|
||||
{ "BCM2E55" },
|
||||
{ "BCM2E56" },
|
||||
{ "BCM2E57" },
|
||||
{ "BCM2E58" },
|
||||
{ "BCM2E59" },
|
||||
{ "BCM2E5A" },
|
||||
{ "BCM2E5B" },
|
||||
{ "BCM2E5C" },
|
||||
{ "BCM2E5D" },
|
||||
{ "BCM2E5E" },
|
||||
{ "BCM2E5F" },
|
||||
{ "BCM2E60" },
|
||||
{ "BCM2E61" },
|
||||
{ "BCM2E62" },
|
||||
{ "BCM2E63" },
|
||||
{ "BCM2E64" },
|
||||
{ "BCM2E65" },
|
||||
{ "BCM2E66" },
|
||||
{ "BCM2E67" },
|
||||
{ "BCM2E68" },
|
||||
{ "BCM2E69" },
|
||||
{ "BCM2E6B" },
|
||||
{ "BCM2E6D" },
|
||||
{ "BCM2E6E" },
|
||||
{ "BCM2E6F" },
|
||||
{ "BCM2E70" },
|
||||
{ "BCM2E71" },
|
||||
{ "BCM2E72" },
|
||||
{ "BCM2E73" },
|
||||
{ "BCM2E74", (long)&bcm43430_device_data },
|
||||
{ "BCM2E75", (long)&bcm43430_device_data },
|
||||
{ "BCM2E76" },
|
||||
{ "BCM2E77" },
|
||||
{ "BCM2E78" },
|
||||
{ "BCM2E79" },
|
||||
{ "BCM2E7A" },
|
||||
{ "BCM2E7B", (long)&bcm43430_device_data },
|
||||
{ "BCM2E7C" },
|
||||
{ "BCM2E7D" },
|
||||
{ "BCM2E7E" },
|
||||
{ "BCM2E7F" },
|
||||
{ "BCM2E80", (long)&bcm43430_device_data },
|
||||
{ "BCM2E81" },
|
||||
{ "BCM2E82" },
|
||||
{ "BCM2E83" },
|
||||
{ "BCM2E84" },
|
||||
{ "BCM2E85" },
|
||||
{ "BCM2E86" },
|
||||
{ "BCM2E87" },
|
||||
{ "BCM2E88" },
|
||||
{ "BCM2E89", (long)&bcm43430_device_data },
|
||||
{ "BCM2E8A" },
|
||||
{ "BCM2E8B" },
|
||||
{ "BCM2E8C" },
|
||||
{ "BCM2E8D" },
|
||||
{ "BCM2E8E" },
|
||||
{ "BCM2E90" },
|
||||
{ "BCM2E92" },
|
||||
{ "BCM2E93" },
|
||||
{ "BCM2E94", (long)&bcm43430_device_data },
|
||||
{ "BCM2E95" },
|
||||
{ "BCM2E96" },
|
||||
{ "BCM2E97" },
|
||||
{ "BCM2E98" },
|
||||
{ "BCM2E99", (long)&bcm43430_device_data },
|
||||
{ "BCM2E9A" },
|
||||
{ "BCM2E9B", (long)&bcm43430_device_data },
|
||||
{ "BCM2E9C" },
|
||||
{ "BCM2E9D" },
|
||||
{ "BCM2E9F", (long)&bcm43430_device_data },
|
||||
{ "BCM2EA0" },
|
||||
{ "BCM2EA1" },
|
||||
{ "BCM2EA2", (long)&bcm43430_device_data },
|
||||
{ "BCM2EA3", (long)&bcm43430_device_data },
|
||||
{ "BCM2EA4", (long)&bcm43430_device_data }, /* bcm43455 */
|
||||
{ "BCM2EA5" },
|
||||
{ "BCM2EA6" },
|
||||
{ "BCM2EA7" },
|
||||
{ "BCM2EA8" },
|
||||
{ "BCM2EA9" },
|
||||
{ "BCM2EAA", (long)&bcm43430_device_data },
|
||||
{ "BCM2EAB", (long)&bcm43430_device_data },
|
||||
{ "BCM2EAC", (long)&bcm43430_device_data },
|
||||
{ },
|
||||
{ .id = "BCM2E00" },
|
||||
{ .id = "BCM2E01" },
|
||||
{ .id = "BCM2E02" },
|
||||
{ .id = "BCM2E03" },
|
||||
{ .id = "BCM2E04" },
|
||||
{ .id = "BCM2E05" },
|
||||
{ .id = "BCM2E06" },
|
||||
{ .id = "BCM2E07" },
|
||||
{ .id = "BCM2E08" },
|
||||
{ .id = "BCM2E09" },
|
||||
{ .id = "BCM2E0A" },
|
||||
{ .id = "BCM2E0B" },
|
||||
{ .id = "BCM2E0C" },
|
||||
{ .id = "BCM2E0D" },
|
||||
{ .id = "BCM2E0E" },
|
||||
{ .id = "BCM2E0F" },
|
||||
{ .id = "BCM2E10" },
|
||||
{ .id = "BCM2E11" },
|
||||
{ .id = "BCM2E12" },
|
||||
{ .id = "BCM2E13" },
|
||||
{ .id = "BCM2E14" },
|
||||
{ .id = "BCM2E15" },
|
||||
{ .id = "BCM2E16" },
|
||||
{ .id = "BCM2E17" },
|
||||
{ .id = "BCM2E18" },
|
||||
{ .id = "BCM2E19" },
|
||||
{ .id = "BCM2E1A" },
|
||||
{ .id = "BCM2E1B" },
|
||||
{ .id = "BCM2E1C" },
|
||||
{ .id = "BCM2E1D" },
|
||||
{ .id = "BCM2E1F" },
|
||||
{ .id = "BCM2E20" },
|
||||
{ .id = "BCM2E21" },
|
||||
{ .id = "BCM2E22" },
|
||||
{ .id = "BCM2E23" },
|
||||
{ .id = "BCM2E24" },
|
||||
{ .id = "BCM2E25" },
|
||||
{ .id = "BCM2E26" },
|
||||
{ .id = "BCM2E27" },
|
||||
{ .id = "BCM2E28" },
|
||||
{ .id = "BCM2E29" },
|
||||
{ .id = "BCM2E2A" },
|
||||
{ .id = "BCM2E2B" },
|
||||
{ .id = "BCM2E2C" },
|
||||
{ .id = "BCM2E2D" },
|
||||
{ .id = "BCM2E2E" },
|
||||
{ .id = "BCM2E2F" },
|
||||
{ .id = "BCM2E30" },
|
||||
{ .id = "BCM2E31" },
|
||||
{ .id = "BCM2E32" },
|
||||
{ .id = "BCM2E33" },
|
||||
{ .id = "BCM2E34" },
|
||||
{ .id = "BCM2E35" },
|
||||
{ .id = "BCM2E36" },
|
||||
{ .id = "BCM2E37" },
|
||||
{ .id = "BCM2E38" },
|
||||
{ .id = "BCM2E39" },
|
||||
{ .id = "BCM2E3A" },
|
||||
{ .id = "BCM2E3B" },
|
||||
{ .id = "BCM2E3C" },
|
||||
{ .id = "BCM2E3D" },
|
||||
{ .id = "BCM2E3E" },
|
||||
{ .id = "BCM2E3F" },
|
||||
{ .id = "BCM2E40" },
|
||||
{ .id = "BCM2E41" },
|
||||
{ .id = "BCM2E42" },
|
||||
{ .id = "BCM2E43" },
|
||||
{ .id = "BCM2E44" },
|
||||
{ .id = "BCM2E45" },
|
||||
{ .id = "BCM2E46" },
|
||||
{ .id = "BCM2E47" },
|
||||
{ .id = "BCM2E48" },
|
||||
{ .id = "BCM2E49" },
|
||||
{ .id = "BCM2E4A" },
|
||||
{ .id = "BCM2E4B" },
|
||||
{ .id = "BCM2E4C" },
|
||||
{ .id = "BCM2E4D" },
|
||||
{ .id = "BCM2E4E" },
|
||||
{ .id = "BCM2E4F" },
|
||||
{ .id = "BCM2E50" },
|
||||
{ .id = "BCM2E51" },
|
||||
{ .id = "BCM2E52" },
|
||||
{ .id = "BCM2E53" },
|
||||
{ .id = "BCM2E54" },
|
||||
{ .id = "BCM2E55" },
|
||||
{ .id = "BCM2E56" },
|
||||
{ .id = "BCM2E57" },
|
||||
{ .id = "BCM2E58" },
|
||||
{ .id = "BCM2E59" },
|
||||
{ .id = "BCM2E5A" },
|
||||
{ .id = "BCM2E5B" },
|
||||
{ .id = "BCM2E5C" },
|
||||
{ .id = "BCM2E5D" },
|
||||
{ .id = "BCM2E5E" },
|
||||
{ .id = "BCM2E5F" },
|
||||
{ .id = "BCM2E60" },
|
||||
{ .id = "BCM2E61" },
|
||||
{ .id = "BCM2E62" },
|
||||
{ .id = "BCM2E63" },
|
||||
{ .id = "BCM2E64" },
|
||||
{ .id = "BCM2E65" },
|
||||
{ .id = "BCM2E66" },
|
||||
{ .id = "BCM2E67" },
|
||||
{ .id = "BCM2E68" },
|
||||
{ .id = "BCM2E69" },
|
||||
{ .id = "BCM2E6B" },
|
||||
{ .id = "BCM2E6D" },
|
||||
{ .id = "BCM2E6E" },
|
||||
{ .id = "BCM2E6F" },
|
||||
{ .id = "BCM2E70" },
|
||||
{ .id = "BCM2E71" },
|
||||
{ .id = "BCM2E72" },
|
||||
{ .id = "BCM2E73" },
|
||||
{ .id = "BCM2E74", .driver_data = (long)&bcm43430_device_data },
|
||||
{ .id = "BCM2E75", .driver_data = (long)&bcm43430_device_data },
|
||||
{ .id = "BCM2E76" },
|
||||
{ .id = "BCM2E77" },
|
||||
{ .id = "BCM2E78" },
|
||||
{ .id = "BCM2E79" },
|
||||
{ .id = "BCM2E7A" },
|
||||
{ .id = "BCM2E7B", .driver_data = (long)&bcm43430_device_data },
|
||||
{ .id = "BCM2E7C" },
|
||||
{ .id = "BCM2E7D" },
|
||||
{ .id = "BCM2E7E" },
|
||||
{ .id = "BCM2E7F" },
|
||||
{ .id = "BCM2E80", .driver_data = (long)&bcm43430_device_data },
|
||||
{ .id = "BCM2E81" },
|
||||
{ .id = "BCM2E82" },
|
||||
{ .id = "BCM2E83" },
|
||||
{ .id = "BCM2E84" },
|
||||
{ .id = "BCM2E85" },
|
||||
{ .id = "BCM2E86" },
|
||||
{ .id = "BCM2E87" },
|
||||
{ .id = "BCM2E88" },
|
||||
{ .id = "BCM2E89", .driver_data = (long)&bcm43430_device_data },
|
||||
{ .id = "BCM2E8A" },
|
||||
{ .id = "BCM2E8B" },
|
||||
{ .id = "BCM2E8C" },
|
||||
{ .id = "BCM2E8D" },
|
||||
{ .id = "BCM2E8E" },
|
||||
{ .id = "BCM2E90" },
|
||||
{ .id = "BCM2E92" },
|
||||
{ .id = "BCM2E93" },
|
||||
{ .id = "BCM2E94", .driver_data = (long)&bcm43430_device_data },
|
||||
{ .id = "BCM2E95" },
|
||||
{ .id = "BCM2E96" },
|
||||
{ .id = "BCM2E97" },
|
||||
{ .id = "BCM2E98" },
|
||||
{ .id = "BCM2E99", .driver_data = (long)&bcm43430_device_data },
|
||||
{ .id = "BCM2E9A" },
|
||||
{ .id = "BCM2E9B", .driver_data = (long)&bcm43430_device_data },
|
||||
{ .id = "BCM2E9C" },
|
||||
{ .id = "BCM2E9D" },
|
||||
{ .id = "BCM2E9F", .driver_data = (long)&bcm43430_device_data },
|
||||
{ .id = "BCM2EA0" },
|
||||
{ .id = "BCM2EA1" },
|
||||
{ .id = "BCM2EA2", .driver_data = (long)&bcm43430_device_data },
|
||||
{ .id = "BCM2EA3", .driver_data = (long)&bcm43430_device_data },
|
||||
{ .id = "BCM2EA4", .driver_data = (long)&bcm43430_device_data }, /* bcm43455 */
|
||||
{ .id = "BCM2EA5" },
|
||||
{ .id = "BCM2EA6" },
|
||||
{ .id = "BCM2EA7" },
|
||||
{ .id = "BCM2EA8" },
|
||||
{ .id = "BCM2EA9" },
|
||||
{ .id = "BCM2EAA", .driver_data = (long)&bcm43430_device_data },
|
||||
{ .id = "BCM2EAB", .driver_data = (long)&bcm43430_device_data },
|
||||
{ .id = "BCM2EAC", .driver_data = (long)&bcm43430_device_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (hciextn && chan == 5) {
|
||||
if (hciextn && chan == 5 && len > HCI_COMMAND_HDR_SIZE) {
|
||||
__le16 opcode = ((struct hci_command_hdr *)data)->opcode;
|
||||
|
||||
/* Vendor specific commands */
|
||||
|
|
@ -402,6 +402,9 @@ static void bcsp_handle_le_pkt(struct hci_uart *hu)
|
|||
u8 sync_pkt[4] = { 0xda, 0xdc, 0xed, 0xed };
|
||||
|
||||
/* spot "conf" pkts and reply with a "conf rsp" pkt */
|
||||
if (bcsp->rx_skb->len < 8)
|
||||
return;
|
||||
|
||||
if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
|
||||
!memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) {
|
||||
struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC);
|
||||
|
|
|
|||
|
|
@ -1124,10 +1124,10 @@ static const struct h5_device_data h5_data_rtl8723bs = {
|
|||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id h5_acpi_match[] = {
|
||||
#ifdef CONFIG_BT_HCIUART_RTL
|
||||
{ "OBDA0623", (kernel_ulong_t)&h5_data_rtl8723bs },
|
||||
{ "OBDA8723", (kernel_ulong_t)&h5_data_rtl8723bs },
|
||||
{ .id = "OBDA0623", .driver_data = (kernel_ulong_t)&h5_data_rtl8723bs },
|
||||
{ .id = "OBDA8723", .driver_data = (kernel_ulong_t)&h5_data_rtl8723bs },
|
||||
#endif
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, h5_acpi_match);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1057,8 +1057,8 @@ static const struct hci_uart_proto intel_proto = {
|
|||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id intel_acpi_match[] = {
|
||||
{ "INT33E1", 0 },
|
||||
{ "INT33E3", 0 },
|
||||
{ .id = "INT33E1" },
|
||||
{ .id = "INT33E3" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, intel_acpi_match);
|
||||
|
|
|
|||
|
|
@ -163,6 +163,12 @@ static void hci_uart_write_work(struct work_struct *work)
|
|||
|
||||
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
|
||||
len = tty->ops->write(tty, skb->data, skb->len);
|
||||
if (len < 0 || len > skb->len) {
|
||||
hdev->stat.err_tx++;
|
||||
kfree_skb(skb);
|
||||
continue;
|
||||
}
|
||||
|
||||
hdev->stat.byte_tx += len;
|
||||
|
||||
skb_pull(skb, len);
|
||||
|
|
@ -756,9 +762,9 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id)
|
|||
hu->proto = p;
|
||||
|
||||
err = hci_uart_register_dev(hu);
|
||||
if (err) {
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
set_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||
clear_bit(HCI_UART_PROTO_INIT, &hu->flags);
|
||||
|
|
|
|||
|
|
@ -354,9 +354,29 @@ static int nokia_setup_fw(struct hci_uart *hu)
|
|||
u16 opcode;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (pkt_size > fw_size - 2) {
|
||||
err = -EINVAL;
|
||||
dev_err(dev, "%s: Malformed firmware packet\n",
|
||||
hu->hdev->name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
if (pkt_size < 1 + HCI_COMMAND_HDR_SIZE) {
|
||||
err = -EINVAL;
|
||||
dev_err(dev, "%s: Malformed firmware command\n",
|
||||
hu->hdev->name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
cmd = (struct hci_command_hdr *)(fw_ptr + 3);
|
||||
if (cmd->plen > pkt_size - 1 - HCI_COMMAND_HDR_SIZE) {
|
||||
err = -EINVAL;
|
||||
dev_err(dev, "%s: Truncated firmware command\n",
|
||||
hu->hdev->name);
|
||||
goto done;
|
||||
}
|
||||
opcode = le16_to_cpu(cmd->opcode);
|
||||
|
||||
skb = __hci_cmd_sync(hu->hdev, opcode, cmd->plen,
|
||||
|
|
|
|||
|
|
@ -1239,8 +1239,8 @@ static int qca_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
* received we store dump into a file before closing hci. This
|
||||
* dump will help in triaging the issues.
|
||||
*/
|
||||
if ((skb->data[0] == HCI_VENDOR_PKT) &&
|
||||
(get_unaligned_be16(skb->data + 2) == QCA_SSR_DUMP_HANDLE))
|
||||
if (skb->data[0] == HCI_EV_VENDOR &&
|
||||
get_unaligned_be16(skb->data + 2) == QCA_SSR_DUMP_HANDLE)
|
||||
return qca_controller_memdump_event(hdev, skb);
|
||||
|
||||
return hci_recv_frame(hdev, skb);
|
||||
|
|
@ -2792,12 +2792,12 @@ MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
|
|||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id qca_bluetooth_acpi_match[] = {
|
||||
{ "QCOM2066", (kernel_ulong_t)&qca_soc_data_qca2066 },
|
||||
{ "QCOM6390", (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
{ "DLA16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
{ "DLB16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
{ "DLB26390", (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
{ },
|
||||
{ .id = "QCOM2066", .driver_data = (kernel_ulong_t)&qca_soc_data_qca2066 },
|
||||
{ .id = "QCOM6390", .driver_data = (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
{ .id = "DLA16390", .driver_data = (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
{ .id = "DLB16390", .driver_data = (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
{ .id = "DLB26390", .driver_data = (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, qca_bluetooth_acpi_match);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -120,9 +120,13 @@ static int virtbt_setup_zephyr(struct hci_dev *hdev)
|
|||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
bt_dev_info(hdev, "%s", (char *)(skb->data + 1));
|
||||
/* Bounded print: the backend controls skb->len. */
|
||||
if (skb->len > 1) {
|
||||
int len = skb->len - 1;
|
||||
|
||||
hci_set_fw_info(hdev, "%s", skb->data + 1);
|
||||
bt_dev_info(hdev, "%.*s", len, (char *)(skb->data + 1));
|
||||
hci_set_fw_info(hdev, "%.*s", len, skb->data + 1);
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
|
|||
struct dentry *cxl_debugfs_create_dir(const char *dir);
|
||||
int cxl_dpa_set_part(struct cxl_endpoint_decoder *cxled,
|
||||
enum cxl_partition_mode mode);
|
||||
struct cxl_memdev_state;
|
||||
int cxl_mem_get_partition_info(struct cxl_memdev_state *mds);
|
||||
int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, u64 size);
|
||||
int cxl_dpa_free(struct cxl_endpoint_decoder *cxled);
|
||||
resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled);
|
||||
|
|
|
|||
|
|
@ -1152,7 +1152,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_mem_get_event_records, "CXL");
|
|||
*
|
||||
* See CXL @8.2.9.5.2.1 Get Partition Info
|
||||
*/
|
||||
static int cxl_mem_get_partition_info(struct cxl_memdev_state *mds)
|
||||
int cxl_mem_get_partition_info(struct cxl_memdev_state *mds)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
struct cxl_mbox_get_partition_info pi;
|
||||
|
|
@ -1308,55 +1308,6 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
static void add_part(struct cxl_dpa_info *info, u64 start, u64 size, enum cxl_partition_mode mode)
|
||||
{
|
||||
int i = info->nr_partitions;
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
info->part[i].range = (struct range) {
|
||||
.start = start,
|
||||
.end = start + size - 1,
|
||||
};
|
||||
info->part[i].mode = mode;
|
||||
info->nr_partitions++;
|
||||
}
|
||||
|
||||
int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
|
||||
{
|
||||
struct cxl_dev_state *cxlds = &mds->cxlds;
|
||||
struct device *dev = cxlds->dev;
|
||||
int rc;
|
||||
|
||||
if (!cxlds->media_ready) {
|
||||
info->size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
info->size = mds->total_bytes;
|
||||
|
||||
if (mds->partition_align_bytes == 0) {
|
||||
add_part(info, 0, mds->volatile_only_bytes, CXL_PARTMODE_RAM);
|
||||
add_part(info, mds->volatile_only_bytes,
|
||||
mds->persistent_only_bytes, CXL_PARTMODE_PMEM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = cxl_mem_get_partition_info(mds);
|
||||
if (rc) {
|
||||
dev_err(dev, "Failed to query partition information\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
add_part(info, 0, mds->active_volatile_bytes, CXL_PARTMODE_RAM);
|
||||
add_part(info, mds->active_volatile_bytes, mds->active_persistent_bytes,
|
||||
CXL_PARTMODE_PMEM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_mem_dpa_fetch, "CXL");
|
||||
|
||||
int cxl_get_dirty_count(struct cxl_memdev_state *mds, u32 *count)
|
||||
{
|
||||
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
|
||||
|
|
|
|||
|
|
@ -594,6 +594,73 @@ bool is_cxl_memdev(const struct device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_NS_GPL(is_cxl_memdev, "CXL");
|
||||
|
||||
static void add_part(struct cxl_dpa_info *info, u64 start, u64 size, enum cxl_partition_mode mode)
|
||||
{
|
||||
int i = info->nr_partitions;
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
info->part[i].range = (struct range) {
|
||||
.start = start,
|
||||
.end = start + size - 1,
|
||||
};
|
||||
info->part[i].mode = mode;
|
||||
info->nr_partitions++;
|
||||
}
|
||||
|
||||
int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
|
||||
{
|
||||
struct cxl_dev_state *cxlds = &mds->cxlds;
|
||||
struct device *dev = cxlds->dev;
|
||||
int rc;
|
||||
|
||||
if (!cxlds->media_ready) {
|
||||
info->size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
info->size = mds->total_bytes;
|
||||
|
||||
if (mds->partition_align_bytes == 0) {
|
||||
add_part(info, 0, mds->volatile_only_bytes, CXL_PARTMODE_RAM);
|
||||
add_part(info, mds->volatile_only_bytes,
|
||||
mds->persistent_only_bytes, CXL_PARTMODE_PMEM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = cxl_mem_get_partition_info(mds);
|
||||
if (rc) {
|
||||
dev_err(dev, "Failed to query partition information\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
add_part(info, 0, mds->active_volatile_bytes, CXL_PARTMODE_RAM);
|
||||
add_part(info, mds->active_volatile_bytes, mds->active_persistent_bytes,
|
||||
CXL_PARTMODE_PMEM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_mem_dpa_fetch, "CXL");
|
||||
|
||||
|
||||
/**
|
||||
* cxl_set_capacity: initialize dpa by a driver without a mailbox.
|
||||
*
|
||||
* @cxlds: pointer to cxl_dev_state
|
||||
* @capacity: device volatile memory size
|
||||
*/
|
||||
int cxl_set_capacity(struct cxl_dev_state *cxlds, u64 capacity)
|
||||
{
|
||||
struct cxl_dpa_info range_info = {
|
||||
.size = capacity,
|
||||
};
|
||||
|
||||
add_part(&range_info, 0, capacity, CXL_PARTMODE_RAM);
|
||||
return cxl_dpa_setup(cxlds, &range_info);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_set_capacity, "CXL");
|
||||
|
||||
/**
|
||||
* set_exclusive_cxl_commands() - atomically disable user cxl commands
|
||||
* @mds: The device state to operate on
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci-doe.h>
|
||||
#include <cxl/pci.h>
|
||||
#include <linux/aer.h>
|
||||
#include <cxlpci.h>
|
||||
#include <cxlmem.h>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/idr.h>
|
||||
#include <linux/node.h>
|
||||
#include <cxl/einj.h>
|
||||
#include <cxl/pci.h>
|
||||
#include <cxlmem.h>
|
||||
#include <cxlpci.h>
|
||||
#include <cxl.h>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
#include <cxl/pci.h>
|
||||
#include <cxlmem.h>
|
||||
#include <cxlpci.h>
|
||||
#include <pmu.h>
|
||||
|
|
|
|||
|
|
@ -13,16 +13,6 @@
|
|||
*/
|
||||
#define CXL_PCI_DEFAULT_MAX_VECTORS 16
|
||||
|
||||
/* Register Block Identifier (RBI) */
|
||||
enum cxl_regloc_type {
|
||||
CXL_REGLOC_RBI_EMPTY = 0,
|
||||
CXL_REGLOC_RBI_COMPONENT,
|
||||
CXL_REGLOC_RBI_VIRT,
|
||||
CXL_REGLOC_RBI_MEMDEV,
|
||||
CXL_REGLOC_RBI_PMU,
|
||||
CXL_REGLOC_RBI_TYPES
|
||||
};
|
||||
|
||||
/*
|
||||
* Table Access DOE, CDAT Read Entry Response
|
||||
*
|
||||
|
|
@ -112,6 +102,4 @@ static inline void devm_cxl_port_ras_setup(struct cxl_port *port)
|
|||
}
|
||||
#endif
|
||||
|
||||
int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type,
|
||||
struct cxl_register_map *map);
|
||||
#endif /* __CXL_PCI_H__ */
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/aer.h>
|
||||
#include <linux/io.h>
|
||||
#include <cxl/pci.h>
|
||||
#include <cxl/mailbox.h>
|
||||
#include "cxlmem.h"
|
||||
#include "cxlpci.h"
|
||||
|
|
|
|||
|
|
@ -876,19 +876,29 @@ int
|
|||
dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
|
||||
const struct dpll_pin_ops *ops, void *priv)
|
||||
{
|
||||
const struct dpll_device_ops *dev_ops;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!ops) ||
|
||||
WARN_ON(!ops->state_on_dpll_get) ||
|
||||
WARN_ON(!ops->direction_get) ||
|
||||
WARN_ON(ops->measured_freq_get &&
|
||||
(!dpll_device_ops(dpll)->freq_monitor_get ||
|
||||
!dpll_device_ops(dpll)->freq_monitor_set)) ||
|
||||
WARN_ON(ops->supported_ffo && !ops->ffo_get))
|
||||
WARN_ON(ops->supported_ffo && !ops->ffo_get) ||
|
||||
WARN_ON((pin->prop.capabilities &
|
||||
DPLL_PIN_CAPABILITIES_STATE_CONNECTED_OVERRIDE) &&
|
||||
!(pin->prop.capabilities &
|
||||
DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE)))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dpll_lock);
|
||||
|
||||
dev_ops = dpll_device_ops(dpll);
|
||||
if (WARN_ON(ops->measured_freq_get &&
|
||||
(!dev_ops || !dev_ops->freq_monitor_get ||
|
||||
!dev_ops->freq_monitor_set))) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* For pins identified via firmware (pin->fwnode), allow registration
|
||||
* even if the pin's (module, clock_id) differs from the target DPLL.
|
||||
|
|
@ -1081,12 +1091,8 @@ EXPORT_SYMBOL_GPL(dpll_pin_ref_sync_pair_add);
|
|||
static struct dpll_device_registration *
|
||||
dpll_device_registration_first(struct dpll_device *dpll)
|
||||
{
|
||||
struct dpll_device_registration *reg;
|
||||
|
||||
reg = list_first_entry_or_null((struct list_head *)&dpll->registration_list,
|
||||
struct dpll_device_registration, list);
|
||||
WARN_ON(!reg);
|
||||
return reg;
|
||||
return list_first_entry_or_null((struct list_head *)&dpll->registration_list,
|
||||
struct dpll_device_registration, list);
|
||||
}
|
||||
|
||||
void *dpll_priv(struct dpll_device *dpll)
|
||||
|
|
@ -1094,6 +1100,8 @@ void *dpll_priv(struct dpll_device *dpll)
|
|||
struct dpll_device_registration *reg;
|
||||
|
||||
reg = dpll_device_registration_first(dpll);
|
||||
if (!reg)
|
||||
return NULL;
|
||||
return reg->priv;
|
||||
}
|
||||
|
||||
|
|
@ -1102,6 +1110,8 @@ const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll)
|
|||
struct dpll_device_registration *reg;
|
||||
|
||||
reg = dpll_device_registration_first(dpll);
|
||||
if (!reg)
|
||||
return NULL;
|
||||
return reg->ops;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,22 @@ static bool dpll_pin_available(struct dpll_pin *pin)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool dpll_device_registered(struct dpll_device *dpll)
|
||||
{
|
||||
return dpll_device_ops(dpll);
|
||||
}
|
||||
|
||||
static struct dpll_pin_ref *dpll_pin_first_registered_ref(struct dpll_pin *pin)
|
||||
{
|
||||
struct dpll_pin_ref *ref;
|
||||
unsigned long i;
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref)
|
||||
if (dpll_device_registered(ref->dpll))
|
||||
return ref;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpll_msg_add_pin_handle - attach pin handle attribute to a given message
|
||||
* @msg: pointer to sk_buff message to attach a pin handle
|
||||
|
|
@ -656,6 +672,8 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
|
|||
int ret;
|
||||
|
||||
xa_for_each(&pin->dpll_refs, index, ref) {
|
||||
if (!dpll_device_registered(ref->dpll))
|
||||
continue;
|
||||
attr = nla_nest_start(msg, DPLL_A_PIN_PARENT_DEVICE);
|
||||
if (!attr)
|
||||
return -EMSGSIZE;
|
||||
|
|
@ -700,9 +718,10 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
|
|||
int ret;
|
||||
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref || !dpll_device_registered(ref->dpll))
|
||||
ref = dpll_pin_first_registered_ref(pin);
|
||||
if (!ref)
|
||||
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
|
||||
ASSERT_NOT_NULL(ref);
|
||||
return -ENODEV;
|
||||
|
||||
ret = dpll_msg_add_pin_handle(msg, pin);
|
||||
if (ret)
|
||||
|
|
@ -1079,10 +1098,9 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
|
|||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
u64 freq = nla_get_u64(a), old_freq;
|
||||
struct dpll_pin_ref *ref, *failed;
|
||||
const struct dpll_pin_ops *ops;
|
||||
struct dpll_pin_ref *ref;
|
||||
struct dpll_device *dpll;
|
||||
unsigned long i;
|
||||
int ret;
|
||||
|
||||
if (!dpll_pin_is_freq_supported(pin, freq)) {
|
||||
|
|
@ -1090,22 +1108,17 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
ops = dpll_pin_ops(ref);
|
||||
if ((!ops->frequency_set || !ops->frequency_get) &&
|
||||
ref->dpll->module == pin->module &&
|
||||
ref->dpll->clock_id == pin->clock_id) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"frequency set not supported by the device");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref) {
|
||||
if (!ref || !dpll_device_registered(ref->dpll)) {
|
||||
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->frequency_set || !ops->frequency_get) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"frequency set not supported by the device");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
dpll = ref->dpll;
|
||||
ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
|
||||
dpll_priv(dpll), &old_freq, extack);
|
||||
|
|
@ -1116,68 +1129,42 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
|
|||
if (freq == old_freq)
|
||||
return 0;
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->frequency_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
dpll, dpll_priv(dpll), freq, extack);
|
||||
if (ret) {
|
||||
failed = ref;
|
||||
NL_SET_ERR_MSG_FMT(extack, "frequency set failed for dpll_id:%u",
|
||||
dpll->id);
|
||||
goto rollback;
|
||||
}
|
||||
ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
dpll, dpll_priv(dpll), freq, extack);
|
||||
if (ret) {
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
"frequency set failed for dpll_id:%u",
|
||||
dpll->id);
|
||||
return ret;
|
||||
}
|
||||
__dpll_pin_change_ntf(pin);
|
||||
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
if (ref == failed)
|
||||
break;
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->frequency_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
if (ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
dpll, dpll_priv(dpll), old_freq, extack))
|
||||
NL_SET_ERR_MSG(extack, "set frequency rollback failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct dpll_pin_ref *ref, *failed;
|
||||
const struct dpll_pin_ops *ops;
|
||||
struct dpll_pin_esync esync;
|
||||
u64 freq = nla_get_u64(a);
|
||||
struct dpll_pin_ref *ref;
|
||||
struct dpll_device *dpll;
|
||||
bool supported = false;
|
||||
unsigned long i;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
ops = dpll_pin_ops(ref);
|
||||
if ((!ops->esync_set || !ops->esync_get) &&
|
||||
ref->dpll->module == pin->module &&
|
||||
ref->dpll->clock_id == pin->clock_id) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"embedded sync feature is not supported by this device");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref) {
|
||||
if (!ref || !dpll_device_registered(ref->dpll)) {
|
||||
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->esync_set || !ops->esync_get) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"embedded sync feature is not supported by this device");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
dpll = ref->dpll;
|
||||
ret = ops->esync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
|
||||
dpll_priv(dpll), &esync, extack);
|
||||
|
|
@ -1196,44 +1183,17 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
void *pin_dpll_priv;
|
||||
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->esync_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
|
||||
ret = ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
|
||||
freq, extack);
|
||||
if (ret) {
|
||||
failed = ref;
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
"embedded sync frequency set failed for dpll_id: %u",
|
||||
dpll->id);
|
||||
goto rollback;
|
||||
}
|
||||
ret = ops->esync_set(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
|
||||
dpll_priv(dpll), freq, extack);
|
||||
if (ret) {
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
"embedded sync frequency set failed for dpll_id: %u",
|
||||
dpll->id);
|
||||
return ret;
|
||||
}
|
||||
__dpll_pin_change_ntf(pin);
|
||||
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
void *pin_dpll_priv;
|
||||
|
||||
if (ref == failed)
|
||||
break;
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->esync_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
|
||||
if (ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
|
||||
esync.freq, extack))
|
||||
NL_SET_ERR_MSG(extack, "set embedded sync frequency rollback failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -1241,14 +1201,12 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
|
|||
unsigned long ref_sync_pin_idx,
|
||||
const enum dpll_pin_state state,
|
||||
struct netlink_ext_ack *extack)
|
||||
|
||||
{
|
||||
struct dpll_pin_ref *ref, *failed;
|
||||
const struct dpll_pin_ops *ops;
|
||||
enum dpll_pin_state old_state;
|
||||
struct dpll_pin *ref_sync_pin;
|
||||
struct dpll_pin_ref *ref;
|
||||
struct dpll_device *dpll;
|
||||
unsigned long i;
|
||||
int ret;
|
||||
|
||||
ref_sync_pin = xa_find(&pin->ref_sync_pins, &ref_sync_pin_idx,
|
||||
|
|
@ -1262,7 +1220,7 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
|
|||
return -EINVAL;
|
||||
}
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref) {
|
||||
if (!ref || !dpll_device_registered(ref->dpll)) {
|
||||
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
@ -1282,42 +1240,20 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
|
|||
}
|
||||
if (state == old_state)
|
||||
return 0;
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->ref_sync_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
ret = ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
ref_sync_pin,
|
||||
dpll_pin_on_dpll_priv(dpll,
|
||||
ref_sync_pin),
|
||||
state, extack);
|
||||
if (ret) {
|
||||
failed = ref;
|
||||
NL_SET_ERR_MSG_FMT(extack, "reference sync set failed for dpll_id:%u",
|
||||
dpll->id);
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
ret = ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
ref_sync_pin,
|
||||
dpll_pin_on_dpll_priv(dpll, ref_sync_pin),
|
||||
state, extack);
|
||||
if (ret) {
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
"reference sync set failed for dpll_id:%u",
|
||||
dpll->id);
|
||||
return ret;
|
||||
}
|
||||
__dpll_pin_change_ntf(pin);
|
||||
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
if (ref == failed)
|
||||
break;
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->ref_sync_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
if (ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
ref_sync_pin,
|
||||
dpll_pin_on_dpll_priv(dpll, ref_sync_pin),
|
||||
old_state, extack))
|
||||
NL_SET_ERR_MSG(extack, "set reference sync rollback failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -1478,11 +1414,10 @@ static int
|
|||
dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct dpll_pin_ref *ref, *failed;
|
||||
const struct dpll_pin_ops *ops;
|
||||
s32 phase_adj, old_phase_adj;
|
||||
struct dpll_pin_ref *ref;
|
||||
struct dpll_device *dpll;
|
||||
unsigned long i;
|
||||
int ret;
|
||||
|
||||
phase_adj = nla_get_s32(phase_adj_attr);
|
||||
|
|
@ -1499,21 +1434,16 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
ops = dpll_pin_ops(ref);
|
||||
if ((!ops->phase_adjust_set || !ops->phase_adjust_get) &&
|
||||
ref->dpll->module == pin->module &&
|
||||
ref->dpll->clock_id == pin->clock_id) {
|
||||
NL_SET_ERR_MSG(extack, "phase adjust not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
ref = dpll_pin_own_dpll_ref_first(pin);
|
||||
if (!ref) {
|
||||
if (!ref || !dpll_device_registered(ref->dpll)) {
|
||||
NL_SET_ERR_MSG(extack, "pin owner dpll not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->phase_adjust_set || !ops->phase_adjust_get) {
|
||||
NL_SET_ERR_MSG(extack, "phase adjust not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
dpll = ref->dpll;
|
||||
ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
dpll, dpll_priv(dpll), &old_phase_adj,
|
||||
|
|
@ -1525,41 +1455,17 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
|
|||
if (phase_adj == old_phase_adj)
|
||||
return 0;
|
||||
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->phase_adjust_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
ret = ops->phase_adjust_set(pin,
|
||||
dpll_pin_on_dpll_priv(dpll, pin),
|
||||
dpll, dpll_priv(dpll), phase_adj,
|
||||
extack);
|
||||
if (ret) {
|
||||
failed = ref;
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
"phase adjust set failed for dpll_id:%u",
|
||||
dpll->id);
|
||||
goto rollback;
|
||||
}
|
||||
ret = ops->phase_adjust_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
dpll, dpll_priv(dpll), phase_adj, extack);
|
||||
if (ret) {
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
"phase adjust set failed for dpll_id:%u",
|
||||
dpll->id);
|
||||
return ret;
|
||||
}
|
||||
__dpll_pin_change_ntf(pin);
|
||||
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||
if (ref == failed)
|
||||
break;
|
||||
ops = dpll_pin_ops(ref);
|
||||
if (!ops->phase_adjust_set)
|
||||
continue;
|
||||
dpll = ref->dpll;
|
||||
if (ops->phase_adjust_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
dpll, dpll_priv(dpll), old_phase_adj,
|
||||
extack))
|
||||
NL_SET_ERR_MSG(extack, "set phase adjust rollback failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -1581,7 +1487,7 @@ dpll_pin_parent_device_set(struct dpll_pin *pin, struct nlattr *parent_nest,
|
|||
return -EINVAL;
|
||||
}
|
||||
pdpll_idx = nla_get_u32(tb[DPLL_A_PIN_PARENT_ID]);
|
||||
dpll = xa_load(&dpll_device_xa, pdpll_idx);
|
||||
dpll = dpll_device_get_by_id(pdpll_idx);
|
||||
if (!dpll) {
|
||||
NL_SET_ERR_MSG(extack, "parent device not found");
|
||||
return -EINVAL;
|
||||
|
|
@ -1873,6 +1779,10 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
ret = dpll_cmd_pin_get_one(skb, pin, cb->extack);
|
||||
if (ret) {
|
||||
genlmsg_cancel(skb, hdr);
|
||||
if (ret == -ENODEV) {
|
||||
ret = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
genlmsg_end(skb, hdr);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ static const struct nla_policy dpll_pin_id_get_nl_policy[DPLL_A_PIN_TYPE + 1] =
|
|||
[DPLL_A_PIN_BOARD_LABEL] = { .type = NLA_NUL_STRING, },
|
||||
[DPLL_A_PIN_PANEL_LABEL] = { .type = NLA_NUL_STRING, },
|
||||
[DPLL_A_PIN_PACKAGE_LABEL] = { .type = NLA_NUL_STRING, },
|
||||
[DPLL_A_PIN_TYPE] = NLA_POLICY_RANGE(NLA_U32, 1, 5),
|
||||
[DPLL_A_PIN_TYPE] = NLA_POLICY_RANGE(NLA_U32, 1, 6),
|
||||
};
|
||||
|
||||
/* DPLL_CMD_PIN_GET - do */
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
config ZL3073X
|
||||
tristate "Microchip Azurite DPLL/PTP/SyncE devices" if COMPILE_TEST
|
||||
depends on NET
|
||||
depends on NET && PTP_1588_CLOCK
|
||||
select DPLL
|
||||
select NET_DEVLINK
|
||||
select REGMAP
|
||||
|
|
@ -16,7 +16,7 @@ config ZL3073X
|
|||
|
||||
config ZL3073X_I2C
|
||||
tristate "I2C bus implementation for Microchip Azurite devices"
|
||||
depends on I2C && NET
|
||||
depends on I2C && NET && PTP_1588_CLOCK
|
||||
select REGMAP_I2C
|
||||
select ZL3073X
|
||||
help
|
||||
|
|
@ -28,7 +28,7 @@ config ZL3073X_I2C
|
|||
|
||||
config ZL3073X_SPI
|
||||
tristate "SPI bus implementation for Microchip Azurite devices"
|
||||
depends on NET && SPI
|
||||
depends on NET && SPI && PTP_1588_CLOCK
|
||||
select REGMAP_SPI
|
||||
select ZL3073X
|
||||
help
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
|
|
@ -31,9 +33,18 @@ int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Read df_offset vs tracked reference */
|
||||
/* Read df_offset only when locked to a reference. In NCO mode
|
||||
* df_offset was captured at entry by nco_mode_set() - preserve it.
|
||||
*/
|
||||
if (!zl3073x_chan_is_locked(chan)) {
|
||||
if (!zl3073x_chan_mode_is_nco(chan))
|
||||
chan->df_offset = ZL_DPLL_DF_OFFSET_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_DF_READ(index),
|
||||
ZL_DPLL_DF_READ_SEM);
|
||||
ZL_DPLL_DF_READ_SEM,
|
||||
ZL_POLL_DF_READ_TIMEOUT_US);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -43,7 +54,8 @@ int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index)
|
|||
return rc;
|
||||
|
||||
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_DF_READ(index),
|
||||
ZL_DPLL_DF_READ_SEM);
|
||||
ZL_DPLL_DF_READ_SEM,
|
||||
ZL_POLL_DF_READ_TIMEOUT_US);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -56,13 +68,103 @@ int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_nco_mode_set - switch DPLL channel to NCO mode
|
||||
* @zldev: pointer to zl3073x_dev structure
|
||||
* @index: DPLL channel index
|
||||
*
|
||||
* Switches the channel to NCO mode and reads the df_offset
|
||||
* auto-captured by nco_auto_read directly from the register.
|
||||
* No DF_READ handshake is needed as nco_auto_read populates
|
||||
* the register before the mode switch completes.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_chan_nco_mode_set(struct zl3073x_dev *zldev, u8 index)
|
||||
{
|
||||
struct zl3073x_chan *chan = &zldev->chan[index];
|
||||
u8 prev_mode, df_read;
|
||||
u64 val;
|
||||
int rc;
|
||||
|
||||
prev_mode = zl3073x_chan_mode_get(chan);
|
||||
|
||||
/* nco_auto_read captures the tracking offset at NCO entry only
|
||||
* from reflock, auto or holdover mode. From freerun the captured
|
||||
* value is not meaningful.
|
||||
*/
|
||||
if (prev_mode == ZL_DPLL_MODE_REFSEL_MODE_FREERUN) {
|
||||
zl3073x_chan_mode_set(chan, ZL_DPLL_MODE_REFSEL_MODE_NCO);
|
||||
|
||||
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index),
|
||||
chan->mode_refsel);
|
||||
if (rc) {
|
||||
zl3073x_chan_mode_set(chan, prev_mode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
chan->df_offset = ZL_DPLL_DF_OFFSET_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Configure df_read for nco_auto_read:
|
||||
* ref_ofst=0 - reads offset relative to master clock (not input ref)
|
||||
* cmd=CMD_ACC_I - accumulated I-part covering both locked and
|
||||
* holdover entry.
|
||||
*
|
||||
* No semaphore is set - this only configures what the df_offset
|
||||
* value represents after the mode switch; nco_auto_read performs
|
||||
* the actual read automatically.
|
||||
*/
|
||||
df_read = FIELD_PREP(ZL_DPLL_DF_READ_REF_OFST, 0) |
|
||||
FIELD_PREP(ZL_DPLL_DF_READ_CMD, ZL_DPLL_DF_READ_CMD_ACC_I);
|
||||
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_DF_READ(index), df_read);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Wait for df_read configuration to take effect before
|
||||
* triggering nco_auto_read via mode switch. The worst-case
|
||||
* internal register update time is 25 ms.
|
||||
*/
|
||||
fsleep(25000);
|
||||
|
||||
zl3073x_chan_mode_set(chan, ZL_DPLL_MODE_REFSEL_MODE_NCO);
|
||||
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index),
|
||||
chan->mode_refsel);
|
||||
if (rc) {
|
||||
zl3073x_chan_mode_set(chan, prev_mode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Wait for nco_auto_read to populate df_offset. The worst-case
|
||||
* internal register update time is 25 ms.
|
||||
*/
|
||||
fsleep(25000);
|
||||
|
||||
/* Read df_offset captured by nco_auto_read during mode switch.
|
||||
* No DF_READ semaphore handshake needed. Mode switch already
|
||||
* succeeded, so don't propagate a read failure back to userspace.
|
||||
*/
|
||||
rc = zl3073x_read_u48(zldev, ZL_REG_DPLL_DF_OFFSET(index), &val);
|
||||
if (rc) {
|
||||
dev_warn(zldev->dev,
|
||||
"Failed to read DPLL%u df_offset: %pe\n",
|
||||
index, ERR_PTR(rc));
|
||||
chan->df_offset = ZL_DPLL_DF_OFFSET_UNKNOWN;
|
||||
} else {
|
||||
chan->df_offset = sign_extend64(val, 47);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_state_fetch - fetch DPLL channel state from hardware
|
||||
* @zldev: pointer to zl3073x_dev structure
|
||||
* @index: DPLL channel index to fetch state for
|
||||
*
|
||||
* Reads the mode_refsel register and reference priority registers for
|
||||
* the given DPLL channel and stores the raw values for later use.
|
||||
* Reads the mode_refsel, status and reference priority registers for
|
||||
* the given DPLL channel and stores the values for later use.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
|
|
@ -71,6 +173,10 @@ int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index)
|
|||
struct zl3073x_chan *chan = &zldev->chan[index];
|
||||
int rc, i;
|
||||
|
||||
rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_CTRL(index), &chan->ctrl);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index),
|
||||
&chan->mode_refsel);
|
||||
if (rc)
|
||||
|
|
@ -83,6 +189,13 @@ int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* If firmware left the channel in NCO mode, mark df_offset as
|
||||
* unknown - we cannot know whether the preconditions for a valid
|
||||
* nco_auto_read capture were met.
|
||||
*/
|
||||
if (zl3073x_chan_mode_is_nco(chan))
|
||||
chan->df_offset = ZL_DPLL_DF_OFFSET_UNKNOWN;
|
||||
|
||||
dev_dbg(zldev->dev,
|
||||
"DPLL%u lock_state: %u, ho: %u, sel_state: %u, sel_ref: %u\n",
|
||||
index, zl3073x_chan_lock_state_get(chan),
|
||||
|
|
@ -122,6 +235,322 @@ const struct zl3073x_chan *zl3073x_chan_state_get(struct zl3073x_dev *zldev,
|
|||
return &zldev->chan[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_tod_ready_wait - wait for ToD semaphore to clear
|
||||
* @zldev: pointer to zl3073x device
|
||||
* @ch: DPLL channel index
|
||||
*
|
||||
* Checks the ToD control register semaphore bit. If clear, returns
|
||||
* immediately. Otherwise polls until the bit is cleared by the device.
|
||||
*
|
||||
* Return:
|
||||
* * 0 - success
|
||||
* * %-EBUSY - timeout
|
||||
* * %-EOPNOTSUPP - unknown command detected
|
||||
* * negative - other error
|
||||
*/
|
||||
int zl3073x_chan_tod_ready_wait(struct zl3073x_dev *zldev, u8 ch)
|
||||
{
|
||||
unsigned int timeout;
|
||||
u8 tod_ctrl;
|
||||
int rc;
|
||||
|
||||
rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_TOD_CTRL(ch), &tod_ctrl);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (!(tod_ctrl & ZL_DPLL_TOD_CTRL_SEM))
|
||||
return 0;
|
||||
|
||||
switch (FIELD_GET(ZL_DPLL_TOD_CTRL_CMD, tod_ctrl)) {
|
||||
case ZL_DPLL_TOD_CTRL_CMD_WR_NEXT_1HZ:
|
||||
timeout = ZL_POLL_TOD_WR_TIMEOUT_US;
|
||||
break;
|
||||
case ZL_DPLL_TOD_CTRL_CMD_RD_CURRENT:
|
||||
case ZL_DPLL_TOD_CTRL_CMD_RD_NEXT_1HZ:
|
||||
timeout = ZL_POLL_TOD_RD_TIMEOUT_US;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_TOD_CTRL(ch),
|
||||
ZL_DPLL_TOD_CTRL_SEM, timeout);
|
||||
|
||||
return rc == -ETIMEDOUT ? -EBUSY : rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_tod_ctrl - issue ToD command
|
||||
* @zldev: pointer to zl3073x device
|
||||
* @ch: DPLL channel index
|
||||
* @cmd: ToD command to execute
|
||||
*
|
||||
* Writes the semaphore and command to dpll_tod_ctrl. The caller must
|
||||
* ensure the device is ready (semaphore clear) before calling and
|
||||
* must wait for completion if needed.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
static int zl3073x_chan_tod_ctrl(struct zl3073x_dev *zldev, u8 ch, u8 cmd)
|
||||
{
|
||||
return zl3073x_write_u8(zldev, ZL_REG_DPLL_TOD_CTRL(ch),
|
||||
ZL_DPLL_TOD_CTRL_SEM | cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_tod_read - read ToD registers after issuing a command
|
||||
* @zldev: pointer to zl3073x device
|
||||
* @ch: DPLL channel index
|
||||
* @next_hz: if true, read predicted ToD at next 1 Hz; otherwise read current
|
||||
* @ts: timespec to store the result
|
||||
* @sts: optional system timestamp pair for cross-timestamping
|
||||
*
|
||||
* Context: Caller must serialize all zl3073x_chan_tod_* calls externally.
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_chan_tod_read(struct zl3073x_dev *zldev, u8 ch,
|
||||
bool next_hz, struct timespec64 *ts,
|
||||
struct ptp_system_timestamp *sts)
|
||||
{
|
||||
u32 nsec;
|
||||
u64 sec;
|
||||
u8 cmd;
|
||||
int rc;
|
||||
|
||||
if (next_hz)
|
||||
cmd = ZL_DPLL_TOD_CTRL_CMD_RD_NEXT_1HZ;
|
||||
else
|
||||
cmd = ZL_DPLL_TOD_CTRL_CMD_RD_CURRENT;
|
||||
|
||||
/* Wait for any previous ToD operation to complete */
|
||||
rc = zl3073x_chan_tod_ready_wait(zldev, ch);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
ptp_read_system_prets(sts);
|
||||
rc = zl3073x_chan_tod_ctrl(zldev, ch, cmd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = zl3073x_chan_tod_ready_wait(zldev, ch);
|
||||
if (rc)
|
||||
return rc;
|
||||
ptp_read_system_postts(sts);
|
||||
|
||||
rc = zl3073x_read_u48(zldev, ZL_REG_DPLL_TOD_SEC(ch), &sec);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* HW nanoseconds are always in [0, NSEC_PER_SEC) range */
|
||||
rc = zl3073x_read_u32(zldev, ZL_REG_DPLL_TOD_NS(ch), &nsec);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
ts->tv_sec = sec;
|
||||
ts->tv_nsec = nsec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_tod_write - write ToD registers and trigger 1 Hz update
|
||||
* @zldev: pointer to zl3073x device
|
||||
* @ch: DPLL channel index
|
||||
* @ts: time to set
|
||||
*
|
||||
* Context: Caller must serialize all zl3073x_chan_tod_* calls externally.
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_chan_tod_write(struct zl3073x_dev *zldev, u8 ch,
|
||||
struct timespec64 ts)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Wait for any previous ToD operation to complete */
|
||||
rc = zl3073x_chan_tod_ready_wait(zldev, ch);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = zl3073x_write_u48(zldev, ZL_REG_DPLL_TOD_SEC(ch), ts.tv_sec);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = zl3073x_write_u32(zldev, ZL_REG_DPLL_TOD_NS(ch), ts.tv_nsec);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return zl3073x_chan_tod_ctrl(zldev, ch,
|
||||
ZL_DPLL_TOD_CTRL_CMD_WR_NEXT_1HZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_tod_adjust - atomic ToD read-modify-write with rollover guard
|
||||
* @zldev: pointer to zl3073x device
|
||||
* @ch: DPLL channel index
|
||||
* @delta: time adjustment to apply
|
||||
*
|
||||
* Reads the next-Hz ToD and current ToD, then checks whether enough time
|
||||
* remains before the next 1 Hz rollover to safely complete the write.
|
||||
* Re-reads if the 1 Hz tick crossed between the two reads or if less
|
||||
* than 20 ms remains before the next rollover. Applies @delta and writes
|
||||
* the result back.
|
||||
*
|
||||
* Context: Caller must serialize all zl3073x_chan_tod_* calls externally.
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_chan_tod_adjust(struct zl3073x_dev *zldev, u8 ch,
|
||||
struct timespec64 delta)
|
||||
{
|
||||
#define ZL_TOD_MAX_RETRIES 20
|
||||
static const long threshold_ns = 20 * NSEC_PER_MSEC;
|
||||
struct timespec64 ts_next, ts_cur, diff;
|
||||
int rc, i;
|
||||
|
||||
for (i = 0; i < ZL_TOD_MAX_RETRIES; i++) {
|
||||
rc = zl3073x_chan_tod_read(zldev, ch, true, &ts_next, NULL);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = zl3073x_chan_tod_read(zldev, ch, false, &ts_cur, NULL);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Ensure the 1 Hz tick did not cross between the two reads
|
||||
* and that enough margin remains to complete the write.
|
||||
*/
|
||||
diff = timespec64_sub(ts_next, ts_cur);
|
||||
if (diff.tv_sec > 0 ||
|
||||
(!diff.tv_sec && diff.tv_nsec >= threshold_ns))
|
||||
break;
|
||||
}
|
||||
if (i == ZL_TOD_MAX_RETRIES) {
|
||||
dev_warn(zldev->dev,
|
||||
"DPLL%u ToD adjust failed to get stable margin\n",
|
||||
ch);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Apply delta to the next-Hz ToD */
|
||||
ts_next = timespec64_add(ts_next, delta);
|
||||
if (!timespec64_valid_settod(&ts_next))
|
||||
return -EINVAL;
|
||||
|
||||
return zl3073x_chan_tod_write(zldev, ch, ts_next);
|
||||
#undef ZL_TOD_MAX_RETRIES
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_df_offset_set - write delta frequency offset to hardware
|
||||
* @zldev: pointer to zl3073x device
|
||||
* @ch: DPLL channel index
|
||||
* @offset: frequency offset in 2^-48 steps
|
||||
*
|
||||
* Context: Caller must hold the per-DPLL lock.
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_chan_df_offset_set(struct zl3073x_dev *zldev, u8 ch, s64 offset)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = zl3073x_write_u48(zldev, ZL_REG_DPLL_DF_OFFSET(ch), offset);
|
||||
if (!rc)
|
||||
zldev->chan[ch].df_offset = offset;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_tie_write - adjust DPLL phase using TIE write
|
||||
* @zldev: pointer to zl3073x device
|
||||
* @ch: DPLL channel index
|
||||
* @delta_ns: phase adjustment in nanoseconds (must be in (-1s, 1s))
|
||||
*
|
||||
* Converts nanoseconds to TIE units (0.01 ps) and writes TIE data
|
||||
* to the specified channel.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_chan_tie_write(struct zl3073x_dev *zldev, u8 ch, s64 delta_ns)
|
||||
{
|
||||
s64 tie_data;
|
||||
int rc;
|
||||
|
||||
guard(mutex)(&zldev->tie_lock);
|
||||
|
||||
/* Wait for any previous TIE operation to complete */
|
||||
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_TIE_CTRL,
|
||||
ZL_DPLL_TIE_CTRL_OP,
|
||||
ZL_POLL_TIE_WR_TIMEOUT_US);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Convert ns to TIE units (0.01 ps = 10^-14 s) */
|
||||
tie_data = delta_ns * 100000LL;
|
||||
|
||||
rc = zl3073x_write_u48(zldev, ZL_REG_DPLL_TIE_DATA(ch), tie_data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_TIE_CTRL_MASK, BIT(ch));
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return zl3073x_write_u8(zldev, ZL_REG_DPLL_TIE_CTRL,
|
||||
ZL_DPLL_TIE_CTRL_OP_WR);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_phase_step - execute one output phase step operation
|
||||
* @zldev: pointer to zl3073x device
|
||||
* @ch: DPLL channel index
|
||||
* @out_mask: bitmask of outputs to step
|
||||
* @step_cycles: phase step in synthesizer clock cycles
|
||||
* @tod_step: also step the ToD counter
|
||||
*
|
||||
* All masked outputs must use synthesizers of the same frequency since
|
||||
* the step value is in synthesizer clock cycles.
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_chan_phase_step(struct zl3073x_dev *zldev, u8 ch,
|
||||
u16 out_mask, s32 step_cycles,
|
||||
bool tod_step)
|
||||
{
|
||||
u8 ctrl;
|
||||
int rc;
|
||||
|
||||
guard(mutex)(&zldev->phase_step_lock);
|
||||
|
||||
/* Wait for any previous phase step operation to complete */
|
||||
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_OUTPUT_PHASE_STEP_CTRL,
|
||||
ZL_OUTPUT_PHASE_STEP_CTRL_OP,
|
||||
ZL_POLL_PHASE_STEP_TIMEOUT_US);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_STEP_DATA,
|
||||
step_cycles);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = zl3073x_write_u16(zldev, ZL_REG_OUTPUT_PHASE_STEP_MASK, out_mask);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = zl3073x_write_u8(zldev, ZL_REG_OUTPUT_PHASE_STEP_NUMBER, 1);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
ctrl = FIELD_PREP(ZL_OUTPUT_PHASE_STEP_CTRL_DPLL, ch) |
|
||||
FIELD_PREP(ZL_OUTPUT_PHASE_STEP_CTRL_OP,
|
||||
ZL_OUTPUT_PHASE_STEP_CTRL_OP_WRITE);
|
||||
if (tod_step)
|
||||
ctrl |= ZL_OUTPUT_PHASE_STEP_CTRL_TOD_STEP;
|
||||
|
||||
return zl3073x_write_u8(zldev, ZL_REG_OUTPUT_PHASE_STEP_CTRL, ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_state_set - commit DPLL channel state changes to hardware
|
||||
* @zldev: pointer to zl3073x_dev structure
|
||||
|
|
@ -145,7 +574,15 @@ int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index,
|
|||
if (!memcmp(&dchan->cfg, &chan->cfg, sizeof(chan->cfg)))
|
||||
return 0;
|
||||
|
||||
/* Direct register write for mode_refsel */
|
||||
/* Direct register writes for ctrl and mode_refsel */
|
||||
if (dchan->ctrl != chan->ctrl) {
|
||||
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_CTRL(index),
|
||||
chan->ctrl);
|
||||
if (rc)
|
||||
return rc;
|
||||
dchan->ctrl = chan->ctrl;
|
||||
}
|
||||
|
||||
if (dchan->mode_refsel != chan->mode_refsel) {
|
||||
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index),
|
||||
chan->mode_refsel);
|
||||
|
|
|
|||
|
|
@ -5,14 +5,17 @@
|
|||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/time64.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "regs.h"
|
||||
|
||||
struct ptp_system_timestamp;
|
||||
struct zl3073x_dev;
|
||||
|
||||
/**
|
||||
* struct zl3073x_chan - DPLL channel state
|
||||
* @ctrl: DPLL control register value
|
||||
* @mode_refsel: mode and reference selection register value
|
||||
* @ref_prio: reference priority registers (4 bits per ref, P/N packed)
|
||||
* @mon_status: monitor status register value
|
||||
|
|
@ -21,6 +24,7 @@ struct zl3073x_dev;
|
|||
*/
|
||||
struct zl3073x_chan {
|
||||
struct_group(cfg,
|
||||
u8 ctrl;
|
||||
u8 mode_refsel;
|
||||
u8 ref_prio[ZL3073X_NUM_REFS / 2];
|
||||
);
|
||||
|
|
@ -38,6 +42,22 @@ int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index,
|
|||
const struct zl3073x_chan *chan);
|
||||
|
||||
int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index);
|
||||
int zl3073x_chan_nco_mode_set(struct zl3073x_dev *zldev, u8 index);
|
||||
|
||||
int zl3073x_chan_tod_ready_wait(struct zl3073x_dev *zldev, u8 ch);
|
||||
int zl3073x_chan_tod_read(struct zl3073x_dev *zldev, u8 ch,
|
||||
bool next_hz, struct timespec64 *ts,
|
||||
struct ptp_system_timestamp *sts);
|
||||
int zl3073x_chan_tod_write(struct zl3073x_dev *zldev, u8 ch,
|
||||
struct timespec64 ts);
|
||||
int zl3073x_chan_tod_adjust(struct zl3073x_dev *zldev, u8 ch,
|
||||
struct timespec64 delta);
|
||||
int zl3073x_chan_phase_step(struct zl3073x_dev *zldev, u8 ch,
|
||||
u16 out_mask, s32 step_cycles, bool tod_step);
|
||||
|
||||
int zl3073x_chan_df_offset_set(struct zl3073x_dev *zldev, u8 ch, s64 offset);
|
||||
|
||||
int zl3073x_chan_tie_write(struct zl3073x_dev *zldev, u8 ch, s64 delta_ns);
|
||||
|
||||
/**
|
||||
* zl3073x_chan_df_offset_get - get cached df_offset vs tracked reference
|
||||
|
|
@ -152,6 +172,66 @@ static inline u8 zl3073x_chan_lock_state_get(const struct zl3073x_chan *chan)
|
|||
return FIELD_GET(ZL_DPLL_MON_STATUS_STATE, chan->mon_status);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_is_locked - check if channel is locked to a reference
|
||||
* @chan: pointer to channel state
|
||||
*
|
||||
* Return: true if channel is locked, false otherwise
|
||||
*/
|
||||
static inline bool zl3073x_chan_is_locked(const struct zl3073x_chan *chan)
|
||||
{
|
||||
u8 lock_state = zl3073x_chan_lock_state_get(chan);
|
||||
return lock_state == ZL_DPLL_MON_STATUS_STATE_LOCK;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_mode_is_auto - check if channel is in automatic mode
|
||||
* @chan: pointer to channel state
|
||||
*
|
||||
* Return: true if channel is in automatic mode, false otherwise
|
||||
*/
|
||||
static inline bool zl3073x_chan_mode_is_auto(const struct zl3073x_chan *chan)
|
||||
{
|
||||
return zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_AUTO;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_mode_is_nco - check if channel is in NCO mode
|
||||
* @chan: pointer to channel state
|
||||
*
|
||||
* Return: true if channel is in NCO mode, false otherwise
|
||||
*/
|
||||
static inline bool zl3073x_chan_mode_is_nco(const struct zl3073x_chan *chan)
|
||||
{
|
||||
return zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_NCO;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_mode_is_reflock - check if channel is in reflock mode
|
||||
* @chan: pointer to channel state
|
||||
*
|
||||
* Return: true if channel is in reflock mode, false otherwise
|
||||
*/
|
||||
static inline bool zl3073x_chan_mode_is_reflock(const struct zl3073x_chan *chan)
|
||||
{
|
||||
return zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_REFLOCK;
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_mode_supports_tie - check if channel mode supports TIE write
|
||||
* @chan: pointer to channel state
|
||||
*
|
||||
* TIE write is supported in AUTO and REFLOCK modes regardless of lock state.
|
||||
*
|
||||
* Return: true if TIE write is supported, false otherwise
|
||||
*/
|
||||
static inline bool
|
||||
zl3073x_chan_mode_supports_tie(const struct zl3073x_chan *chan)
|
||||
{
|
||||
return zl3073x_chan_mode_is_auto(chan) ||
|
||||
zl3073x_chan_mode_is_reflock(chan);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_chan_is_ho_ready - check if holdover is ready
|
||||
* @chan: pointer to channel state
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
static const struct zl3073x_chip_info zl3073x_chip_ids[] = {
|
||||
ZL_CHIP_INFO(0x0E30, 2, ZL3073X_FLAG_REF_PHASE_COMP_32),
|
||||
ZL_CHIP_INFO(0x0E3B, 3, ZL3073X_FLAG_REF_PHASE_COMP_32),
|
||||
ZL_CHIP_INFO(0x0E93, 1, ZL3073X_FLAG_REF_PHASE_COMP_32),
|
||||
ZL_CHIP_INFO(0x0E94, 2, ZL3073X_FLAG_REF_PHASE_COMP_32),
|
||||
ZL_CHIP_INFO(0x0E95, 3, ZL3073X_FLAG_REF_PHASE_COMP_32),
|
||||
|
|
@ -311,17 +312,17 @@ int zl3073x_write_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 val)
|
|||
* @zldev: zl3073x device pointer
|
||||
* @reg: register to poll (has to be 8bit register)
|
||||
* @mask: bit mask for polling
|
||||
* @timeout_us: timeout in microseconds
|
||||
*
|
||||
* Waits for bits specified by @mask in register @reg value to be cleared
|
||||
* by the device.
|
||||
*
|
||||
* Returns: 0 on success, <0 on error
|
||||
*/
|
||||
int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask)
|
||||
int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg,
|
||||
u8 mask, unsigned int timeout_us)
|
||||
{
|
||||
/* Register polling sleep & timeout */
|
||||
#define ZL_POLL_SLEEP_US 10
|
||||
#define ZL_POLL_TIMEOUT_US 2000000
|
||||
unsigned int sleep_us = timeout_us / 50;
|
||||
unsigned int val;
|
||||
|
||||
/* Check the register is 8bit */
|
||||
|
|
@ -335,7 +336,7 @@ int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask)
|
|||
reg = ZL_REG_ADDR(reg) + ZL_RANGE_OFFSET;
|
||||
|
||||
return regmap_read_poll_timeout(zldev->regmap, reg, val, !(val & mask),
|
||||
ZL_POLL_SLEEP_US, ZL_POLL_TIMEOUT_US);
|
||||
sleep_us, timeout_us);
|
||||
}
|
||||
|
||||
int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,
|
||||
|
|
@ -354,7 +355,8 @@ int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,
|
|||
return rc;
|
||||
|
||||
/* Wait for the operation to actually finish */
|
||||
return zl3073x_poll_zero_u8(zldev, op_reg, op_val);
|
||||
return zl3073x_poll_zero_u8(zldev, op_reg, op_val,
|
||||
ZL_POLL_MB_TIMEOUT_US);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -377,8 +379,8 @@ zl3073x_do_hwreg_op(struct zl3073x_dev *zldev, u8 op)
|
|||
return rc;
|
||||
|
||||
/* Poll for completion - pending bit cleared */
|
||||
return zl3073x_poll_zero_u8(zldev, ZL_REG_HWREG_OP,
|
||||
ZL_HWREG_OP_PENDING);
|
||||
return zl3073x_poll_zero_u8(zldev, ZL_REG_HWREG_OP, ZL_HWREG_OP_PENDING,
|
||||
ZL_POLL_HWREG_TIMEOUT_US);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -509,6 +511,11 @@ zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
|
|||
int rc;
|
||||
u8 i;
|
||||
|
||||
rc = zl3073x_read_u16(zldev, ZL_REG_OUTPUT_STEP_TIME_MASK,
|
||||
&zldev->out_step_time_mask);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
for (i = 0; i < ZL3073X_NUM_REFS; i++) {
|
||||
rc = zl3073x_ref_state_fetch(zldev, i);
|
||||
if (rc) {
|
||||
|
|
@ -566,19 +573,7 @@ zl3073x_dev_ref_states_update(struct zl3073x_dev *zldev)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
zl3073x_dev_chan_states_update(struct zl3073x_dev *zldev)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
for (i = 0; i < zldev->info->num_channels; i++) {
|
||||
rc = zl3073x_chan_state_update(zldev, i);
|
||||
if (rc)
|
||||
dev_warn(zldev->dev,
|
||||
"Failed to get DPLL%u state: %pe\n", i,
|
||||
ERR_PTR(rc));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_ref_phase_offsets_update - update reference phase offsets
|
||||
|
|
@ -609,7 +604,8 @@ int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel)
|
|||
* to be zero to ensure that the measured data are coherent.
|
||||
*/
|
||||
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_PHASE_ERR_READ_RQST,
|
||||
ZL_REF_PHASE_ERR_READ_RQST_RD);
|
||||
ZL_REF_PHASE_ERR_READ_RQST_RD,
|
||||
ZL_POLL_PHASE_ERR_TIMEOUT_US);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -628,7 +624,8 @@ int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel)
|
|||
|
||||
/* Wait for finish */
|
||||
return zl3073x_poll_zero_u8(zldev, ZL_REG_REF_PHASE_ERR_READ_RQST,
|
||||
ZL_REF_PHASE_ERR_READ_RQST_RD);
|
||||
ZL_REF_PHASE_ERR_READ_RQST_RD,
|
||||
ZL_POLL_PHASE_ERR_TIMEOUT_US);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -648,7 +645,8 @@ zl3073x_ref_freq_meas_latch(struct zl3073x_dev *zldev, u8 type)
|
|||
|
||||
/* Wait for previous measurement to finish */
|
||||
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL,
|
||||
ZL_REF_FREQ_MEAS_CTRL);
|
||||
ZL_REF_FREQ_MEAS_CTRL,
|
||||
ZL_POLL_FREQ_MEAS_TIMEOUT_US);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -669,7 +667,8 @@ zl3073x_ref_freq_meas_latch(struct zl3073x_dev *zldev, u8 type)
|
|||
|
||||
/* Wait for finish */
|
||||
return zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL,
|
||||
ZL_REF_FREQ_MEAS_CTRL);
|
||||
ZL_REF_FREQ_MEAS_CTRL,
|
||||
ZL_POLL_FREQ_MEAS_TIMEOUT_US);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -715,9 +714,6 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
|
|||
/* Update input references' states */
|
||||
zl3073x_dev_ref_states_update(zldev);
|
||||
|
||||
/* Update DPLL channels' states */
|
||||
zl3073x_dev_chan_states_update(zldev);
|
||||
|
||||
/* Update DPLL-to-connected-ref phase offsets registers */
|
||||
rc = zl3073x_ref_phase_offsets_update(zldev, -1);
|
||||
if (rc)
|
||||
|
|
@ -727,7 +723,7 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
|
|||
/* Update measured input reference frequencies if frequency
|
||||
* monitoring is enabled.
|
||||
*/
|
||||
if (zldev->freq_monitor) {
|
||||
if (READ_ONCE(zldev->freq_monitor)) {
|
||||
rc = zl3073x_ref_freq_meas_update(zldev);
|
||||
if (rc)
|
||||
dev_warn(zldev->dev,
|
||||
|
|
@ -763,7 +759,7 @@ int zl3073x_dev_phase_avg_factor_set(struct zl3073x_dev *zldev, u8 factor)
|
|||
return rc;
|
||||
|
||||
/* Save the new factor */
|
||||
zldev->phase_avg_factor = factor;
|
||||
WRITE_ONCE(zldev->phase_avg_factor, factor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1043,6 +1039,14 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev)
|
|||
* and/or polls are required to be done atomically.
|
||||
*/
|
||||
rc = devm_mutex_init(zldev->dev, &zldev->multiop_lock);
|
||||
if (rc)
|
||||
return dev_err_probe(zldev->dev, rc,
|
||||
"Failed to initialize mutex\n");
|
||||
rc = devm_mutex_init(zldev->dev, &zldev->phase_step_lock);
|
||||
if (rc)
|
||||
return dev_err_probe(zldev->dev, rc,
|
||||
"Failed to initialize mutex\n");
|
||||
rc = devm_mutex_init(zldev->dev, &zldev->tie_lock);
|
||||
if (rc)
|
||||
return dev_err_probe(zldev->dev, rc,
|
||||
"Failed to initialize mutex\n");
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/kthread.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/time64.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "chan.h"
|
||||
|
|
@ -19,6 +20,16 @@ struct device;
|
|||
struct regmap;
|
||||
struct zl3073x_dpll;
|
||||
|
||||
/* Per-operation poll timeouts */
|
||||
#define ZL_POLL_DF_READ_TIMEOUT_US (25 * USEC_PER_MSEC)
|
||||
#define ZL_POLL_FREQ_MEAS_TIMEOUT_US (50 * USEC_PER_MSEC)
|
||||
#define ZL_POLL_HWREG_TIMEOUT_US (50 * USEC_PER_MSEC)
|
||||
#define ZL_POLL_MB_TIMEOUT_US (30 * USEC_PER_MSEC)
|
||||
#define ZL_POLL_PHASE_ERR_TIMEOUT_US (50 * USEC_PER_MSEC)
|
||||
#define ZL_POLL_PHASE_STEP_TIMEOUT_US (3000 * USEC_PER_MSEC)
|
||||
#define ZL_POLL_TIE_WR_TIMEOUT_US (1000 * USEC_PER_MSEC)
|
||||
#define ZL_POLL_TOD_RD_TIMEOUT_US (30 * USEC_PER_MSEC)
|
||||
#define ZL_POLL_TOD_WR_TIMEOUT_US (1000 * USEC_PER_MSEC)
|
||||
|
||||
enum zl3073x_flags {
|
||||
ZL3073X_FLAG_REF_PHASE_COMP_32_BIT,
|
||||
|
|
@ -48,6 +59,8 @@ struct zl3073x_chip_info {
|
|||
* @regmap: regmap to access device registers
|
||||
* @info: detected chip info
|
||||
* @multiop_lock: to serialize multiple register operations
|
||||
* @tie_lock: to serialize TIE write operations
|
||||
* @phase_step_lock: to serialize output phase step operations
|
||||
* @ref: array of input references' invariants
|
||||
* @out: array of outs' invariants
|
||||
* @synth: array of synths' invariants
|
||||
|
|
@ -56,6 +69,7 @@ struct zl3073x_chip_info {
|
|||
* @kworker: thread for periodic work
|
||||
* @work: periodic work
|
||||
* @clock_id: clock id of the device
|
||||
* @out_step_time_mask: output step-time mask (device-global)
|
||||
* @phase_avg_factor: phase offset measurement averaging factor
|
||||
* @freq_monitor: is frequency monitor enabled
|
||||
*/
|
||||
|
|
@ -64,6 +78,8 @@ struct zl3073x_dev {
|
|||
struct regmap *regmap;
|
||||
const struct zl3073x_chip_info *info;
|
||||
struct mutex multiop_lock;
|
||||
struct mutex tie_lock;
|
||||
struct mutex phase_step_lock;
|
||||
|
||||
/* Invariants */
|
||||
struct zl3073x_ref ref[ZL3073X_NUM_REFS];
|
||||
|
|
@ -80,6 +96,7 @@ struct zl3073x_dev {
|
|||
|
||||
/* Per-chip parameters */
|
||||
u64 clock_id;
|
||||
u16 out_step_time_mask;
|
||||
u8 phase_avg_factor;
|
||||
bool freq_monitor;
|
||||
};
|
||||
|
|
@ -94,7 +111,7 @@ void zl3073x_dev_stop(struct zl3073x_dev *zldev);
|
|||
|
||||
static inline u8 zl3073x_dev_phase_avg_factor_get(struct zl3073x_dev *zldev)
|
||||
{
|
||||
return zldev->phase_avg_factor;
|
||||
return READ_ONCE(zldev->phase_avg_factor);
|
||||
}
|
||||
|
||||
int zl3073x_dev_phase_avg_factor_set(struct zl3073x_dev *zldev, u8 factor);
|
||||
|
|
@ -127,7 +144,8 @@ struct zl3073x_hwreg_seq_item {
|
|||
|
||||
int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,
|
||||
unsigned int mask_reg, u16 mask_val);
|
||||
int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask);
|
||||
int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg,
|
||||
u8 mask, unsigned int timeout_us);
|
||||
int zl3073x_read_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 *val);
|
||||
int zl3073x_read_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 *val);
|
||||
int zl3073x_read_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 *val);
|
||||
|
|
@ -300,6 +318,19 @@ zl3073x_dev_out_is_enabled(struct zl3073x_dev *zldev, u8 index)
|
|||
return zl3073x_synth_is_enabled(synth) && zl3073x_out_is_enabled(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_dev_out_is_stepped - check if output is in step-time mask
|
||||
* @zldev: pointer to zl3073x device
|
||||
* @index: output index
|
||||
*
|
||||
* Return: true if output is affected by step-time operations
|
||||
*/
|
||||
static inline bool
|
||||
zl3073x_dev_out_is_stepped(struct zl3073x_dev *zldev, u8 index)
|
||||
{
|
||||
return !!(zldev->out_step_time_mask & BIT(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* zl3073x_dev_out_dpll_get - get DPLL ID the output is driven by
|
||||
* @zldev: pointer to zl3073x device
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <linux/dpll.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
|
|
@ -18,8 +19,12 @@
|
|||
* @ops: DPLL device operations for this instance
|
||||
* @dpll_dev: pointer to registered DPLL device
|
||||
* @tracker: tracking object for the acquired reference
|
||||
* @lock: per-DPLL mutex serializing all operations
|
||||
* @type: DPLL type (PPS or EEC)
|
||||
* @lock_status: last saved DPLL lock status
|
||||
* @pins: list of pins
|
||||
* @ptp_info: PTP clock info
|
||||
* @ptp_clock: registered PTP clock (or NULL)
|
||||
*/
|
||||
struct zl3073x_dpll {
|
||||
struct list_head list;
|
||||
|
|
@ -30,8 +35,12 @@ struct zl3073x_dpll {
|
|||
struct dpll_device_ops ops;
|
||||
struct dpll_device *dpll_dev;
|
||||
dpll_tracker tracker;
|
||||
struct mutex lock;
|
||||
enum dpll_type type;
|
||||
enum dpll_lock_status lock_status;
|
||||
struct list_head pins;
|
||||
struct ptp_clock_info ptp_info;
|
||||
struct ptp_clock *ptp_clock;
|
||||
};
|
||||
|
||||
struct zl3073x_dpll *zl3073x_dpll_alloc(struct zl3073x_dev *zldev, u8 ch);
|
||||
|
|
|
|||
|
|
@ -85,12 +85,8 @@ int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP,
|
||||
&out->phase_comp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return rc;
|
||||
return zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP,
|
||||
&out->phase_comp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/limits.h>
|
||||
|
||||
/*
|
||||
* Hardware limits for ZL3073x chip family
|
||||
|
|
@ -17,6 +18,7 @@
|
|||
#define ZL3073X_NUM_OUTPUT_PINS (ZL3073X_NUM_OUTS * 2)
|
||||
#define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \
|
||||
ZL3073X_NUM_OUTPUT_PINS)
|
||||
#define ZL3073X_NCO_PIN_ID ZL3073X_NUM_PINS
|
||||
|
||||
/*
|
||||
* Register address structure:
|
||||
|
|
@ -164,10 +166,32 @@
|
|||
#define ZL_DPLL_MODE_REFSEL_MODE_NCO 4
|
||||
#define ZL_DPLL_MODE_REFSEL_REF GENMASK(7, 4)
|
||||
|
||||
#define ZL_REG_DPLL_CTRL(_idx) \
|
||||
ZL_REG_IDX(_idx, 5, 0x05, 1, ZL3073X_MAX_CHANNELS, 4)
|
||||
#define ZL_DPLL_CTRL_TIE_CLEAR BIT(0)
|
||||
#define ZL_DPLL_CTRL_TOD_STEP_RST BIT(2)
|
||||
#define ZL_DPLL_CTRL_NCO_AUTO_READ BIT(7)
|
||||
|
||||
#define ZL_REG_DPLL_DF_READ(_idx) \
|
||||
ZL_REG_IDX(_idx, 5, 0x28, 1, ZL3073X_MAX_CHANNELS, 1)
|
||||
#define ZL_DPLL_DF_READ_SEM BIT(4)
|
||||
#define ZL_DPLL_DF_READ_REF_OFST BIT(3)
|
||||
#define ZL_DPLL_DF_READ_CMD GENMASK(2, 0)
|
||||
#define ZL_DPLL_DF_READ_CMD_ACC_I 4
|
||||
|
||||
#define ZL_REG_DPLL_TIE_CTRL ZL_REG(5, 0x30, 1)
|
||||
#define ZL_DPLL_TIE_CTRL_OP GENMASK(2, 0)
|
||||
#define ZL_DPLL_TIE_CTRL_OP_WR 4
|
||||
|
||||
#define ZL_REG_DPLL_TIE_CTRL_MASK ZL_REG(5, 0x31, 1)
|
||||
|
||||
#define ZL_REG_DPLL_TOD_CTRL(_idx) \
|
||||
ZL_REG_IDX(_idx, 5, 0x38, 1, ZL3073X_MAX_CHANNELS, 1)
|
||||
#define ZL_DPLL_TOD_CTRL_SEM BIT(4)
|
||||
#define ZL_DPLL_TOD_CTRL_CMD GENMASK(3, 0)
|
||||
#define ZL_DPLL_TOD_CTRL_CMD_WR_NEXT_1HZ 1
|
||||
#define ZL_DPLL_TOD_CTRL_CMD_RD_CURRENT 8
|
||||
#define ZL_DPLL_TOD_CTRL_CMD_RD_NEXT_1HZ 9
|
||||
|
||||
#define ZL_REG_DPLL_MEAS_CTRL ZL_REG(5, 0x50, 1)
|
||||
#define ZL_DPLL_MEAS_CTRL_EN BIT(0)
|
||||
|
|
@ -183,6 +207,9 @@
|
|||
|
||||
/*******************************
|
||||
* Register Pages 6-7, DPLL Data
|
||||
*
|
||||
* Per-channel registers with stride 0x20. Channels 0-3 reside on page 6,
|
||||
* channel 4 on page 7.
|
||||
*******************************/
|
||||
|
||||
#define ZL_REG_DPLL_DF_OFFSET_03(_idx) \
|
||||
|
|
@ -190,6 +217,25 @@
|
|||
#define ZL_REG_DPLL_DF_OFFSET_4 ZL_REG(7, 0x00, 6)
|
||||
#define ZL_REG_DPLL_DF_OFFSET(_idx) \
|
||||
((_idx) < 4 ? ZL_REG_DPLL_DF_OFFSET_03(_idx) : ZL_REG_DPLL_DF_OFFSET_4)
|
||||
#define ZL_DPLL_DF_OFFSET_UNKNOWN S64_MIN
|
||||
|
||||
#define ZL_REG_DPLL_TIE_DATA_03(_idx) \
|
||||
ZL_REG_IDX(_idx, 6, 0x0C, 6, 4, 0x20)
|
||||
#define ZL_REG_DPLL_TIE_DATA_4 ZL_REG(7, 0x0C, 6)
|
||||
#define ZL_REG_DPLL_TIE_DATA(_idx) \
|
||||
((_idx) < 4 ? ZL_REG_DPLL_TIE_DATA_03(_idx) : ZL_REG_DPLL_TIE_DATA_4)
|
||||
|
||||
#define ZL_REG_DPLL_TOD_SEC_03(_idx) \
|
||||
ZL_REG_IDX(_idx, 6, 0x12, 6, 4, 0x20)
|
||||
#define ZL_REG_DPLL_TOD_SEC_4 ZL_REG(7, 0x12, 6)
|
||||
#define ZL_REG_DPLL_TOD_SEC(_idx) \
|
||||
((_idx) < 4 ? ZL_REG_DPLL_TOD_SEC_03(_idx) : ZL_REG_DPLL_TOD_SEC_4)
|
||||
|
||||
#define ZL_REG_DPLL_TOD_NS_03(_idx) \
|
||||
ZL_REG_IDX(_idx, 6, 0x18, 4, 4, 0x20)
|
||||
#define ZL_REG_DPLL_TOD_NS_4 ZL_REG(7, 0x18, 4)
|
||||
#define ZL_REG_DPLL_TOD_NS(_idx) \
|
||||
((_idx) < 4 ? ZL_REG_DPLL_TOD_NS_03(_idx) : ZL_REG_DPLL_TOD_NS_4)
|
||||
|
||||
/***********************************
|
||||
* Register Page 9, Synth and Output
|
||||
|
|
@ -210,6 +256,23 @@
|
|||
#define ZL_OUTPUT_CTRL_EN BIT(0)
|
||||
#define ZL_OUTPUT_CTRL_SYNTH_SEL GENMASK(6, 4)
|
||||
|
||||
#define ZL_REG_OUTPUT_STEP_TIME_MASK ZL_REG(9, 0x36, 2)
|
||||
|
||||
#define ZL_REG_OUTPUT_PHASE_STEP_CTRL ZL_REG(9, 0x38, 1)
|
||||
#define ZL_OUTPUT_PHASE_STEP_CTRL_DPLL GENMASK(6, 4)
|
||||
#define ZL_OUTPUT_PHASE_STEP_CTRL_TOD_STEP BIT(3)
|
||||
#define ZL_OUTPUT_PHASE_STEP_CTRL_OP GENMASK(1, 0)
|
||||
#define ZL_OUTPUT_PHASE_STEP_CTRL_OP_NONE 0
|
||||
#define ZL_OUTPUT_PHASE_STEP_CTRL_OP_RESET 1
|
||||
#define ZL_OUTPUT_PHASE_STEP_CTRL_OP_READ 2
|
||||
#define ZL_OUTPUT_PHASE_STEP_CTRL_OP_WRITE 3
|
||||
|
||||
#define ZL_REG_OUTPUT_PHASE_STEP_NUMBER ZL_REG(9, 0x39, 1)
|
||||
|
||||
#define ZL_REG_OUTPUT_PHASE_STEP_MASK ZL_REG(9, 0x3a, 2)
|
||||
|
||||
#define ZL_REG_OUTPUT_PHASE_STEP_DATA ZL_REG(9, 0x3c, 4)
|
||||
|
||||
/*******************************
|
||||
* Register Page 10, Ref Mailbox
|
||||
*******************************/
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ static struct sk_buff *rdma_build_skb(struct net_device *netdev,
|
|||
uh->source =
|
||||
htons(rdma_flow_label_to_udp_sport(ah_attr->grh.flow_label));
|
||||
uh->dest = htons(ROCE_V2_UDP_DPORT);
|
||||
uh->len = htons(sizeof(struct udphdr));
|
||||
udp_set_len_short(uh, sizeof(struct udphdr));
|
||||
|
||||
if (is_ipv4) {
|
||||
skb_push(skb, sizeof(struct iphdr));
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ static int rxe_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
|
|||
pkt->port_num = 1;
|
||||
pkt->hdr = (u8 *)(udph + 1);
|
||||
pkt->mask = RXE_GRH_MASK;
|
||||
pkt->paylen = be16_to_cpu(udph->len) - sizeof(*udph);
|
||||
pkt->paylen = udp_get_len_short(udph) - sizeof(*udph);
|
||||
|
||||
/* remove udp header */
|
||||
skb_pull(skb, sizeof(struct udphdr));
|
||||
|
|
@ -305,7 +305,7 @@ static void prepare_udp_hdr(struct sk_buff *skb, __be16 src_port,
|
|||
|
||||
udph->dest = dst_port;
|
||||
udph->source = src_port;
|
||||
udph->len = htons(skb->len);
|
||||
udp_set_len_short(udph, skb->len);
|
||||
udph->check = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -208,6 +208,9 @@ static const struct mmc_fixup __maybe_unused sdio_fixup_methods[] = {
|
|||
SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887_F0,
|
||||
add_limit_rate_quirk, 150000000),
|
||||
|
||||
SDIO_FIXUP(SDIO_VENDOR_ID_NXP, SDIO_DEVICE_ID_NXP_IW61X_BASE,
|
||||
add_quirk, MMC_QUIRK_BLKSZ_FOR_BYTE_MODE),
|
||||
|
||||
END_FIXUP
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -667,7 +667,7 @@ static void amt_send_discovery(struct amt_dev *amt)
|
|||
udph = udp_hdr(skb);
|
||||
udph->source = amt->gw_port;
|
||||
udph->dest = amt->relay_port;
|
||||
udph->len = htons(sizeof(*udph) + sizeof(*amtd));
|
||||
udp_set_len_short(udph, sizeof(*udph) + sizeof(*amtd));
|
||||
udph->check = 0;
|
||||
offset = skb_transport_offset(skb);
|
||||
skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
|
||||
|
|
@ -708,11 +708,13 @@ static void amt_send_request(struct amt_dev *amt, bool v6)
|
|||
struct iphdr *iph;
|
||||
struct rtable *rt;
|
||||
struct flowi4 fl4;
|
||||
__be32 remote_ip;
|
||||
struct sock *sk;
|
||||
u32 len;
|
||||
int err;
|
||||
|
||||
rcu_read_lock();
|
||||
remote_ip = READ_ONCE(amt->remote_ip);
|
||||
sk = rcu_dereference(amt->sk);
|
||||
if (!sk)
|
||||
goto out;
|
||||
|
|
@ -721,7 +723,7 @@ static void amt_send_request(struct amt_dev *amt, bool v6)
|
|||
goto out;
|
||||
|
||||
rt = ip_route_output_ports(amt->net, &fl4, sk,
|
||||
amt->remote_ip, amt->local_ip,
|
||||
remote_ip, amt->local_ip,
|
||||
amt->gw_port, amt->relay_port,
|
||||
IPPROTO_UDP, 0,
|
||||
amt->stream_dev->ifindex);
|
||||
|
|
@ -758,11 +760,11 @@ static void amt_send_request(struct amt_dev *amt, bool v6)
|
|||
udph = udp_hdr(skb);
|
||||
udph->source = amt->gw_port;
|
||||
udph->dest = amt->relay_port;
|
||||
udph->len = htons(sizeof(*amtrh) + sizeof(*udph));
|
||||
udp_set_len_short(udph, sizeof(*amtrh) + sizeof(*udph));
|
||||
udph->check = 0;
|
||||
offset = skb_transport_offset(skb);
|
||||
skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
|
||||
udph->check = csum_tcpudp_magic(amt->local_ip, amt->remote_ip,
|
||||
udph->check = csum_tcpudp_magic(amt->local_ip, remote_ip,
|
||||
sizeof(*udph) + sizeof(*amtrh),
|
||||
IPPROTO_UDP, skb->csum);
|
||||
|
||||
|
|
@ -773,7 +775,7 @@ static void amt_send_request(struct amt_dev *amt, bool v6)
|
|||
iph->tos = AMT_TOS;
|
||||
iph->frag_off = 0;
|
||||
iph->ttl = ip4_dst_hoplimit(&rt->dst);
|
||||
iph->daddr = amt->remote_ip;
|
||||
iph->daddr = remote_ip;
|
||||
iph->saddr = amt->local_ip;
|
||||
iph->protocol = IPPROTO_UDP;
|
||||
iph->tot_len = htons(len);
|
||||
|
|
@ -962,7 +964,7 @@ static void amt_event_send_request(struct amt_dev *amt)
|
|||
amt->qi = AMT_INIT_REQ_TIMEOUT;
|
||||
WRITE_ONCE(amt->ready4, false);
|
||||
WRITE_ONCE(amt->ready6, false);
|
||||
amt->remote_ip = 0;
|
||||
WRITE_ONCE(amt->remote_ip, 0);
|
||||
amt_update_gw_status(amt, AMT_STATUS_INIT, false);
|
||||
amt->req_cnt = 0;
|
||||
amt->nonce = 0;
|
||||
|
|
@ -999,6 +1001,7 @@ static bool amt_send_membership_update(struct amt_dev *amt,
|
|||
struct sk_buff *skb,
|
||||
bool v6)
|
||||
{
|
||||
__be32 remote_ip = READ_ONCE(amt->remote_ip);
|
||||
struct amt_header_membership_update *amtmu;
|
||||
struct iphdr *iph;
|
||||
struct flowi4 fl4;
|
||||
|
|
@ -1018,13 +1021,13 @@ static bool amt_send_membership_update(struct amt_dev *amt,
|
|||
skb_reset_inner_headers(skb);
|
||||
memset(&fl4, 0, sizeof(struct flowi4));
|
||||
fl4.flowi4_oif = amt->stream_dev->ifindex;
|
||||
fl4.daddr = amt->remote_ip;
|
||||
fl4.daddr = remote_ip;
|
||||
fl4.saddr = amt->local_ip;
|
||||
fl4.flowi4_dscp = inet_dsfield_to_dscp(AMT_TOS);
|
||||
fl4.flowi4_proto = IPPROTO_UDP;
|
||||
rt = ip_route_output_key(amt->net, &fl4);
|
||||
if (IS_ERR(rt)) {
|
||||
netdev_dbg(amt->dev, "no route to %pI4\n", &amt->remote_ip);
|
||||
netdev_dbg(amt->dev, "no route to %pI4\n", &remote_ip);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2286,8 +2289,8 @@ static bool amt_advertisement_handler(struct amt_dev *amt, struct sk_buff *skb)
|
|||
amt->nonce != amta->nonce)
|
||||
return true;
|
||||
|
||||
amt->remote_ip = amta->ip4;
|
||||
netdev_dbg(amt->dev, "advertised remote ip = %pI4\n", &amt->remote_ip);
|
||||
WRITE_ONCE(amt->remote_ip, amta->ip4);
|
||||
netdev_dbg(amt->dev, "advertised remote ip = %pI4\n", &amta->ip4);
|
||||
mod_delayed_work(amt_wq, &amt->req_wq, 0);
|
||||
|
||||
amt_update_gw_status(amt, AMT_STATUS_RECEIVED_ADVERTISEMENT, true);
|
||||
|
|
@ -2647,7 +2650,7 @@ static void amt_send_advertisement(struct amt_dev *amt, __be32 nonce,
|
|||
udph = udp_hdr(skb);
|
||||
udph->source = amt->relay_port;
|
||||
udph->dest = dport;
|
||||
udph->len = htons(sizeof(*amta) + sizeof(*udph));
|
||||
udp_set_len_short(udph, sizeof(*amta) + sizeof(*udph));
|
||||
udph->check = 0;
|
||||
offset = skb_transport_offset(skb);
|
||||
skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
|
||||
|
|
@ -2811,6 +2814,7 @@ static void amt_gw_rcv(struct amt_dev *amt, struct sk_buff *skb)
|
|||
static int amt_rcv(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct amt_dev *amt;
|
||||
__be32 remote_ip;
|
||||
__be32 saddr;
|
||||
int type;
|
||||
bool err;
|
||||
|
|
@ -2822,6 +2826,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
|
|||
kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
remote_ip = READ_ONCE(amt->remote_ip);
|
||||
|
||||
skb->dev = amt->dev;
|
||||
saddr = ip_hdr(skb)->saddr;
|
||||
|
|
@ -2846,7 +2851,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
|
|||
}
|
||||
goto out;
|
||||
case AMT_MSG_MULTICAST_DATA:
|
||||
if (saddr != amt->remote_ip) {
|
||||
if (saddr != remote_ip) {
|
||||
netdev_dbg(amt->dev, "Invalid Relay IP\n");
|
||||
err = true;
|
||||
goto drop;
|
||||
|
|
@ -2857,7 +2862,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
|
|||
else
|
||||
goto out;
|
||||
case AMT_MSG_MEMBERSHIP_QUERY:
|
||||
if (saddr != amt->remote_ip) {
|
||||
if (saddr != remote_ip) {
|
||||
netdev_dbg(amt->dev, "Invalid Relay IP\n");
|
||||
err = true;
|
||||
goto drop;
|
||||
|
|
@ -3045,7 +3050,7 @@ static int amt_dev_open(struct net_device *dev)
|
|||
}
|
||||
|
||||
amt->req_cnt = 0;
|
||||
amt->remote_ip = 0;
|
||||
WRITE_ONCE(amt->remote_ip, 0);
|
||||
amt->nonce = 0;
|
||||
get_random_bytes(&amt->key, sizeof(siphash_key_t));
|
||||
|
||||
|
|
@ -3090,7 +3095,7 @@ static int amt_dev_stop(struct net_device *dev)
|
|||
amt->ready4 = false;
|
||||
amt->ready6 = false;
|
||||
amt->req_cnt = 0;
|
||||
amt->remote_ip = 0;
|
||||
WRITE_ONCE(amt->remote_ip, 0);
|
||||
|
||||
list_for_each_entry_safe(tunnel, tmp, &amt->tunnel_list, list) {
|
||||
list_del_rcu(&tunnel->list);
|
||||
|
|
@ -3221,6 +3226,9 @@ static int amt_newlink(struct net_device *dev,
|
|||
struct nlattr **tb = params->tb;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (!net_eq(link_net, dev_net(dev)))
|
||||
return err;
|
||||
|
||||
amt->net = link_net;
|
||||
amt->mode = nla_get_u32(data[IFLA_AMT_MODE]);
|
||||
|
||||
|
|
@ -3289,7 +3297,7 @@ static int amt_newlink(struct net_device *dev,
|
|||
"gateway port must not be 0");
|
||||
goto err;
|
||||
}
|
||||
amt->remote_ip = 0;
|
||||
WRITE_ONCE(amt->remote_ip, 0);
|
||||
amt->discovery_ip = nla_get_in_addr(data[IFLA_AMT_DISCOVERY_IP]);
|
||||
if (ipv4_is_loopback(amt->discovery_ip) ||
|
||||
ipv4_is_zeronet(amt->discovery_ip) ||
|
||||
|
|
@ -3355,8 +3363,10 @@ static size_t amt_get_size(const struct net_device *dev)
|
|||
|
||||
static int amt_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
||||
{
|
||||
struct amt_dev *amt = netdev_priv(dev);
|
||||
const struct amt_dev *amt = netdev_priv(dev);
|
||||
__be32 remote_ip;
|
||||
|
||||
rcu_read_lock();
|
||||
if (nla_put_u32(skb, IFLA_AMT_MODE, amt->mode))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_be16(skb, IFLA_AMT_RELAY_PORT, amt->relay_port))
|
||||
|
|
@ -3369,15 +3379,19 @@ static int amt_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
|||
goto nla_put_failure;
|
||||
if (nla_put_in_addr(skb, IFLA_AMT_DISCOVERY_IP, amt->discovery_ip))
|
||||
goto nla_put_failure;
|
||||
if (amt->remote_ip)
|
||||
if (nla_put_in_addr(skb, IFLA_AMT_REMOTE_IP, amt->remote_ip))
|
||||
|
||||
remote_ip = READ_ONCE(amt->remote_ip);
|
||||
if (remote_ip)
|
||||
if (nla_put_in_addr(skb, IFLA_AMT_REMOTE_IP, remote_ip))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_u32(skb, IFLA_AMT_MAX_TUNNELS, amt->max_tunnels))
|
||||
goto nla_put_failure;
|
||||
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
rcu_read_unlock();
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ static unsigned int bareudp_net_id;
|
|||
|
||||
struct bareudp_net {
|
||||
struct list_head bareudp_list;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
struct bareudp_conf {
|
||||
|
|
@ -636,10 +637,15 @@ static struct bareudp_dev *bareudp_find_dev(struct bareudp_net *bn,
|
|||
{
|
||||
struct bareudp_dev *bareudp, *t = NULL;
|
||||
|
||||
mutex_lock(&bn->lock);
|
||||
|
||||
list_for_each_entry(bareudp, &bn->bareudp_list, next) {
|
||||
if (conf->port == bareudp->port)
|
||||
t = bareudp;
|
||||
}
|
||||
|
||||
mutex_unlock(&bn->lock);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
|
@ -675,7 +681,10 @@ static int bareudp_configure(struct net *net, struct net_device *dev,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&bn->lock);
|
||||
list_add(&bareudp->next, &bn->bareudp_list);
|
||||
mutex_unlock(&bn->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -692,12 +701,26 @@ static int bareudp_link_config(struct net_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void bareudp_dellink(struct net_device *dev, struct list_head *head)
|
||||
static void __bareudp_dellink(struct net *net, struct net_device *dev,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct bareudp_dev *bareudp = netdev_priv(dev);
|
||||
|
||||
list_del(&bareudp->next);
|
||||
unregister_netdevice_queue(dev, head);
|
||||
list_del_init(&bareudp->next);
|
||||
unregister_netdevice_queue_net(net, dev, head);
|
||||
}
|
||||
|
||||
static void bareudp_dellink(struct net_device *dev, struct list_head *head)
|
||||
{
|
||||
struct bareudp_dev *bareudp = netdev_priv(dev);
|
||||
struct bareudp_net *bn;
|
||||
|
||||
bn = net_generic(bareudp->net, bareudp_net_id);
|
||||
|
||||
mutex_lock(&bn->lock);
|
||||
if (!list_empty(&bareudp->next))
|
||||
__bareudp_dellink(dev_net(dev), dev, head);
|
||||
mutex_unlock(&bn->lock);
|
||||
}
|
||||
|
||||
static int bareudp_newlink(struct net_device *dev,
|
||||
|
|
@ -776,6 +799,8 @@ static __net_init int bareudp_init_net(struct net *net)
|
|||
struct bareudp_net *bn = net_generic(net, bareudp_net_id);
|
||||
|
||||
INIT_LIST_HEAD(&bn->bareudp_list);
|
||||
mutex_init(&bn->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -785,13 +810,25 @@ static void __net_exit bareudp_exit_rtnl_net(struct net *net,
|
|||
struct bareudp_net *bn = net_generic(net, bareudp_net_id);
|
||||
struct bareudp_dev *bareudp, *next;
|
||||
|
||||
mutex_lock(&bn->lock);
|
||||
|
||||
list_for_each_entry_safe(bareudp, next, &bn->bareudp_list, next)
|
||||
bareudp_dellink(bareudp->dev, dev_kill_list);
|
||||
__bareudp_dellink(net, bareudp->dev, dev_kill_list);
|
||||
|
||||
mutex_unlock(&bn->lock);
|
||||
}
|
||||
|
||||
static void __net_exit bareudp_exit_net(struct net *net)
|
||||
{
|
||||
struct bareudp_net *bn = net_generic(net, bareudp_net_id);
|
||||
|
||||
WARN_ON_ONCE(!list_empty(&bn->bareudp_list));
|
||||
}
|
||||
|
||||
static struct pernet_operations bareudp_net_ops = {
|
||||
.init = bareudp_init_net,
|
||||
.exit_rtnl = bareudp_exit_rtnl_net,
|
||||
.exit = bareudp_exit_net,
|
||||
.id = &bareudp_net_id,
|
||||
.size = sizeof(struct bareudp_net),
|
||||
};
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user