mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
Including fixes from CAN and WPAN.
Current release - regressions: - phy: micrel: correct KSZ9131RNX EEE capabilities and advertisement Current release - new code bugs: - eth: wangxun: fix vector length of interrupt cause - vsock/loopback: consistently protect the packet queue with sk_buff_head.lock - virtio/vsock: fix header length on skb merging - wpan: ca8210: fix unsigned mac_len comparison with zero Previous releases - regressions: - eth: stmmac: don't reject VLANs when IFF_PROMISC is set - eth: smsc911x: avoid PHY being resumed when interface is not up - eth: mtk_eth_soc: fix tx throughput regression with direct 1G links - eth: bnx2x: use the right build_skb() helper after core rework - wwan: iosm: fix 7560 modem crash on use on unsupported channel Previous releases - always broken: - eth: sfc: don't overwrite offload features at NIC reset - eth: r8169: fix RTL8168H and RTL8107E rx crc error - can: j1939: prevent deadlock by moving j1939_sk_errqueue() - virt: vmxnet3: use GRO callback when UPT is enabled - virt: xen: don't do grant copy across page boundary - phy: dp83869: fix default value for tx-/rx-internal-delay - dsa: ksz8: fix multiple issues with ksz8_fdb_dump - eth: mvpp2: fix classification/RSS of VLAN and fragmented packets - eth: mtk_eth_soc: fix flow block refcounting logic Misc: - constify fwnode pointers in SFP handling Signed-off-by: Jakub Kicinski <kuba@kernel.org> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmQl6Z8ACgkQMUZtbf5S Irsodw//SxeZ16kZHdSuLsUd1bWWPyANsNG4UzKsS912sD8yErzvy3OAiRvTWXxH A7t6QCFZeCHOHLXVuaHXqdyrWcC1eJdCaSnJiDffCwS2oeP9d4IBs3pyLJaeQSXJ 0bep4EcFpxPwCpzFCYNbShvKBLi8vRCX2ZjNii76eMAc0bZ/HvY0rCvULsJ3cwOo cDdsL+lbPSI6suMm5ekm8Hdt7NuSB5jxNFlj2ene4pV7DqHC/a8UErak4fOKbX4h QguePqawC22ZurzXeWvstgcNlJPoPLpcYyXGxSU8qirhbkn1WmkXR11TNEbYE4UD YvJlKIyYOxjN36/xBiJ8LpXV+BQBpfZEV/LSaWByhclVS4c2bY0KkSRfZKOBY82K ejBbMJiGaAyA86QUFkkWxC+zfHiFIywy2nOYCKBsDhW17krBOu3vaFS/jNVC7Ef4 ilk4tUXTYs3ojBUeROnuI1NcR2o0wNeCob/0U/bMMdn51khee70G/muHYTGr/NWA JAZIT/3bOWr5syarpnvtb/PtLlWcoClN022W4iExgFmzbMlQGyD46g+XhsvoXAYO wpo/js0/J+kVfuVsTSQT5MmsVjnzs1r9Y+wNJUM6dE35Z4iIXc1NJhmAZ7nJz0+P ryn8rdnIgCbqzX3DeJC0i9uv0alwLXA/xGCFRV3xflfV/nvxiR0= =/1Gi -----END PGP SIGNATURE----- Merge tag 'net-6.3-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net Pull networking fixes from Jakub Kicinski: "Including fixes from CAN and WPAN. Still quite a few bugs from this release. This pull is a bit smaller because major subtrees went into the previous one. Or maybe people took spring break off? Current release - regressions: - phy: micrel: correct KSZ9131RNX EEE capabilities and advertisement Current release - new code bugs: - eth: wangxun: fix vector length of interrupt cause - vsock/loopback: consistently protect the packet queue with sk_buff_head.lock - virtio/vsock: fix header length on skb merging - wpan: ca8210: fix unsigned mac_len comparison with zero Previous releases - regressions: - eth: stmmac: don't reject VLANs when IFF_PROMISC is set - eth: smsc911x: avoid PHY being resumed when interface is not up - eth: mtk_eth_soc: fix tx throughput regression with direct 1G links - eth: bnx2x: use the right build_skb() helper after core rework - wwan: iosm: fix 7560 modem crash on use on unsupported channel Previous releases - always broken: - eth: sfc: don't overwrite offload features at NIC reset - eth: r8169: fix RTL8168H and RTL8107E rx crc error - can: j1939: prevent deadlock by moving j1939_sk_errqueue() - virt: vmxnet3: use GRO callback when UPT is enabled - virt: xen: don't do grant copy across page boundary - phy: dp83869: fix default value for tx-/rx-internal-delay - dsa: ksz8: fix multiple issues with ksz8_fdb_dump - eth: mvpp2: fix classification/RSS of VLAN and fragmented packets - eth: mtk_eth_soc: fix flow block refcounting logic Misc: - constify fwnode pointers in SFP handling" * tag 'net-6.3-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (55 commits) net: ethernet: mtk_eth_soc: add missing ppe cache flush when deleting a flow net: ethernet: mtk_eth_soc: fix L2 offloading with DSA untag offload net: ethernet: mtk_eth_soc: fix flow block refcounting logic net: mvneta: fix potential double-frees in mvneta_txq_sw_deinit() net: dsa: sync unicast and multicast addresses for VLAN filters too net: dsa: mv88e6xxx: Enable IGMP snooping on user ports only xen/netback: use same error messages for same errors test/vsock: new skbuff appending test virtio/vsock: WARN_ONCE() for invalid state of socket virtio/vsock: fix header length on skb merging bnxt_en: Add missing 200G link speed reporting bnxt_en: Fix typo in PCI id to device description string mapping bnxt_en: Fix reporting of test result in ethtool selftest i40e: fix registers dump after run ethtool adapter self test bnx2x: use the right build_skb() helper net: ipa: compute DMA pool size properly net: wwan: iosm: fixes 7560 modem crash net: ethernet: mtk_eth_soc: fix tx throughput regression with direct 1G links ice: fix invalid check for empty list in ice_sched_assoc_vsi_to_agg() ice: add profile conflict check for AVF FDIR ...
This commit is contained in:
commit
b2bc47e9b2
54 changed files with 568 additions and 263 deletions
|
@ -8216,6 +8216,7 @@ F: drivers/net/ethernet/freescale/dpaa
|
||||||
|
|
||||||
FREESCALE QORIQ DPAA FMAN DRIVER
|
FREESCALE QORIQ DPAA FMAN DRIVER
|
||||||
M: Madalin Bucur <madalin.bucur@nxp.com>
|
M: Madalin Bucur <madalin.bucur@nxp.com>
|
||||||
|
R: Sean Anderson <sean.anderson@seco.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/devicetree/bindings/net/fsl-fman.txt
|
F: Documentation/devicetree/bindings/net/fsl-fman.txt
|
||||||
|
@ -14656,10 +14657,8 @@ F: net/ipv4/nexthop.c
|
||||||
|
|
||||||
NFC SUBSYSTEM
|
NFC SUBSYSTEM
|
||||||
M: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
|
M: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
|
||||||
L: linux-nfc@lists.01.org (subscribers-only)
|
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
B: mailto:linux-nfc@lists.01.org
|
|
||||||
F: Documentation/devicetree/bindings/net/nfc/
|
F: Documentation/devicetree/bindings/net/nfc/
|
||||||
F: drivers/nfc/
|
F: drivers/nfc/
|
||||||
F: include/linux/platform_data/nfcmrvl.h
|
F: include/linux/platform_data/nfcmrvl.h
|
||||||
|
@ -14670,7 +14669,6 @@ F: net/nfc/
|
||||||
NFC VIRTUAL NCI DEVICE DRIVER
|
NFC VIRTUAL NCI DEVICE DRIVER
|
||||||
M: Bongsu Jeon <bongsu.jeon@samsung.com>
|
M: Bongsu Jeon <bongsu.jeon@samsung.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
L: linux-nfc@lists.01.org (subscribers-only)
|
|
||||||
S: Supported
|
S: Supported
|
||||||
F: drivers/nfc/virtual_ncidev.c
|
F: drivers/nfc/virtual_ncidev.c
|
||||||
F: tools/testing/selftests/nci/
|
F: tools/testing/selftests/nci/
|
||||||
|
@ -15042,7 +15040,6 @@ F: Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml
|
||||||
F: sound/soc/codecs/tfa989x.c
|
F: sound/soc/codecs/tfa989x.c
|
||||||
|
|
||||||
NXP-NCI NFC DRIVER
|
NXP-NCI NFC DRIVER
|
||||||
L: linux-nfc@lists.01.org (subscribers-only)
|
|
||||||
S: Orphan
|
S: Orphan
|
||||||
F: Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml
|
F: Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml
|
||||||
F: drivers/nfc/nxp-nci
|
F: drivers/nfc/nxp-nci
|
||||||
|
@ -18487,7 +18484,6 @@ F: include/media/drv-intf/s3c_camif.h
|
||||||
|
|
||||||
SAMSUNG S3FWRN5 NFC DRIVER
|
SAMSUNG S3FWRN5 NFC DRIVER
|
||||||
M: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
|
M: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
|
||||||
L: linux-nfc@lists.01.org (subscribers-only)
|
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/devicetree/bindings/net/nfc/samsung,s3fwrn5.yaml
|
F: Documentation/devicetree/bindings/net/nfc/samsung,s3fwrn5.yaml
|
||||||
F: drivers/nfc/s3fwrn5
|
F: drivers/nfc/s3fwrn5
|
||||||
|
@ -20980,7 +20976,6 @@ F: drivers/iio/magnetometer/tmag5273.c
|
||||||
TI TRF7970A NFC DRIVER
|
TI TRF7970A NFC DRIVER
|
||||||
M: Mark Greer <mgreer@animalcreek.com>
|
M: Mark Greer <mgreer@animalcreek.com>
|
||||||
L: linux-wireless@vger.kernel.org
|
L: linux-wireless@vger.kernel.org
|
||||||
L: linux-nfc@lists.01.org (subscribers-only)
|
|
||||||
S: Supported
|
S: Supported
|
||||||
F: Documentation/devicetree/bindings/net/nfc/ti,trf7970a.yaml
|
F: Documentation/devicetree/bindings/net/nfc/ti,trf7970a.yaml
|
||||||
F: drivers/nfc/trf7970a.c
|
F: drivers/nfc/trf7970a.c
|
||||||
|
|
|
@ -216,6 +216,18 @@ static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int b53_mmap_phy_read16(struct b53_device *dev, int addr, int reg,
|
||||||
|
u16 *value)
|
||||||
|
{
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int b53_mmap_phy_write16(struct b53_device *dev, int addr, int reg,
|
||||||
|
u16 value)
|
||||||
|
{
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct b53_io_ops b53_mmap_ops = {
|
static const struct b53_io_ops b53_mmap_ops = {
|
||||||
.read8 = b53_mmap_read8,
|
.read8 = b53_mmap_read8,
|
||||||
.read16 = b53_mmap_read16,
|
.read16 = b53_mmap_read16,
|
||||||
|
@ -227,6 +239,8 @@ static const struct b53_io_ops b53_mmap_ops = {
|
||||||
.write32 = b53_mmap_write32,
|
.write32 = b53_mmap_write32,
|
||||||
.write48 = b53_mmap_write48,
|
.write48 = b53_mmap_write48,
|
||||||
.write64 = b53_mmap_write64,
|
.write64 = b53_mmap_write64,
|
||||||
|
.phy_read16 = b53_mmap_phy_read16,
|
||||||
|
.phy_write16 = b53_mmap_phy_write16,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int b53_mmap_probe_of(struct platform_device *pdev,
|
static int b53_mmap_probe_of(struct platform_device *pdev,
|
||||||
|
|
|
@ -958,15 +958,14 @@ int ksz8_fdb_dump(struct ksz_device *dev, int port,
|
||||||
u16 entries = 0;
|
u16 entries = 0;
|
||||||
u8 timestamp = 0;
|
u8 timestamp = 0;
|
||||||
u8 fid;
|
u8 fid;
|
||||||
u8 member;
|
u8 src_port;
|
||||||
struct alu_struct alu;
|
u8 mac[ETH_ALEN];
|
||||||
|
|
||||||
do {
|
do {
|
||||||
alu.is_static = false;
|
ret = ksz8_r_dyn_mac_table(dev, i, mac, &fid, &src_port,
|
||||||
ret = ksz8_r_dyn_mac_table(dev, i, alu.mac, &fid, &member,
|
|
||||||
×tamp, &entries);
|
×tamp, &entries);
|
||||||
if (!ret && (member & BIT(port))) {
|
if (!ret && port == src_port) {
|
||||||
ret = cb(alu.mac, alu.fid, alu.is_static, data);
|
ret = cb(mac, fid, false, data);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,22 +82,16 @@ static const struct regmap_bus regmap_smi[] = {
|
||||||
{
|
{
|
||||||
.read = ksz8863_mdio_read,
|
.read = ksz8863_mdio_read,
|
||||||
.write = ksz8863_mdio_write,
|
.write = ksz8863_mdio_write,
|
||||||
.max_raw_read = 1,
|
|
||||||
.max_raw_write = 1,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.read = ksz8863_mdio_read,
|
.read = ksz8863_mdio_read,
|
||||||
.write = ksz8863_mdio_write,
|
.write = ksz8863_mdio_write,
|
||||||
.val_format_endian_default = REGMAP_ENDIAN_BIG,
|
.val_format_endian_default = REGMAP_ENDIAN_BIG,
|
||||||
.max_raw_read = 2,
|
|
||||||
.max_raw_write = 2,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.read = ksz8863_mdio_read,
|
.read = ksz8863_mdio_read,
|
||||||
.write = ksz8863_mdio_write,
|
.write = ksz8863_mdio_write,
|
||||||
.val_format_endian_default = REGMAP_ENDIAN_BIG,
|
.val_format_endian_default = REGMAP_ENDIAN_BIG,
|
||||||
.max_raw_read = 4,
|
|
||||||
.max_raw_write = 4,
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -108,7 +102,6 @@ static const struct regmap_config ksz8863_regmap_config[] = {
|
||||||
.pad_bits = 24,
|
.pad_bits = 24,
|
||||||
.val_bits = 8,
|
.val_bits = 8,
|
||||||
.cache_type = REGCACHE_NONE,
|
.cache_type = REGCACHE_NONE,
|
||||||
.use_single_read = 1,
|
|
||||||
.lock = ksz_regmap_lock,
|
.lock = ksz_regmap_lock,
|
||||||
.unlock = ksz_regmap_unlock,
|
.unlock = ksz_regmap_unlock,
|
||||||
},
|
},
|
||||||
|
@ -118,7 +111,6 @@ static const struct regmap_config ksz8863_regmap_config[] = {
|
||||||
.pad_bits = 24,
|
.pad_bits = 24,
|
||||||
.val_bits = 16,
|
.val_bits = 16,
|
||||||
.cache_type = REGCACHE_NONE,
|
.cache_type = REGCACHE_NONE,
|
||||||
.use_single_read = 1,
|
|
||||||
.lock = ksz_regmap_lock,
|
.lock = ksz_regmap_lock,
|
||||||
.unlock = ksz_regmap_unlock,
|
.unlock = ksz_regmap_unlock,
|
||||||
},
|
},
|
||||||
|
@ -128,7 +120,6 @@ static const struct regmap_config ksz8863_regmap_config[] = {
|
||||||
.pad_bits = 24,
|
.pad_bits = 24,
|
||||||
.val_bits = 32,
|
.val_bits = 32,
|
||||||
.cache_type = REGCACHE_NONE,
|
.cache_type = REGCACHE_NONE,
|
||||||
.use_single_read = 1,
|
|
||||||
.lock = ksz_regmap_lock,
|
.lock = ksz_regmap_lock,
|
||||||
.unlock = ksz_regmap_unlock,
|
.unlock = ksz_regmap_unlock,
|
||||||
}
|
}
|
||||||
|
|
|
@ -404,13 +404,13 @@ static const u32 ksz8863_masks[] = {
|
||||||
[VLAN_TABLE_VALID] = BIT(19),
|
[VLAN_TABLE_VALID] = BIT(19),
|
||||||
[STATIC_MAC_TABLE_VALID] = BIT(19),
|
[STATIC_MAC_TABLE_VALID] = BIT(19),
|
||||||
[STATIC_MAC_TABLE_USE_FID] = BIT(21),
|
[STATIC_MAC_TABLE_USE_FID] = BIT(21),
|
||||||
[STATIC_MAC_TABLE_FID] = GENMASK(29, 26),
|
[STATIC_MAC_TABLE_FID] = GENMASK(25, 22),
|
||||||
[STATIC_MAC_TABLE_OVERRIDE] = BIT(20),
|
[STATIC_MAC_TABLE_OVERRIDE] = BIT(20),
|
||||||
[STATIC_MAC_TABLE_FWD_PORTS] = GENMASK(18, 16),
|
[STATIC_MAC_TABLE_FWD_PORTS] = GENMASK(18, 16),
|
||||||
[DYNAMIC_MAC_TABLE_ENTRIES_H] = GENMASK(5, 0),
|
[DYNAMIC_MAC_TABLE_ENTRIES_H] = GENMASK(1, 0),
|
||||||
[DYNAMIC_MAC_TABLE_MAC_EMPTY] = BIT(7),
|
[DYNAMIC_MAC_TABLE_MAC_EMPTY] = BIT(2),
|
||||||
[DYNAMIC_MAC_TABLE_NOT_READY] = BIT(7),
|
[DYNAMIC_MAC_TABLE_NOT_READY] = BIT(7),
|
||||||
[DYNAMIC_MAC_TABLE_ENTRIES] = GENMASK(31, 28),
|
[DYNAMIC_MAC_TABLE_ENTRIES] = GENMASK(31, 24),
|
||||||
[DYNAMIC_MAC_TABLE_FID] = GENMASK(19, 16),
|
[DYNAMIC_MAC_TABLE_FID] = GENMASK(19, 16),
|
||||||
[DYNAMIC_MAC_TABLE_SRC_PORT] = GENMASK(21, 20),
|
[DYNAMIC_MAC_TABLE_SRC_PORT] = GENMASK(21, 20),
|
||||||
[DYNAMIC_MAC_TABLE_TIMESTAMP] = GENMASK(23, 22),
|
[DYNAMIC_MAC_TABLE_TIMESTAMP] = GENMASK(23, 22),
|
||||||
|
@ -420,10 +420,10 @@ static u8 ksz8863_shifts[] = {
|
||||||
[VLAN_TABLE_MEMBERSHIP_S] = 16,
|
[VLAN_TABLE_MEMBERSHIP_S] = 16,
|
||||||
[STATIC_MAC_FWD_PORTS] = 16,
|
[STATIC_MAC_FWD_PORTS] = 16,
|
||||||
[STATIC_MAC_FID] = 22,
|
[STATIC_MAC_FID] = 22,
|
||||||
[DYNAMIC_MAC_ENTRIES_H] = 3,
|
[DYNAMIC_MAC_ENTRIES_H] = 8,
|
||||||
[DYNAMIC_MAC_ENTRIES] = 24,
|
[DYNAMIC_MAC_ENTRIES] = 24,
|
||||||
[DYNAMIC_MAC_FID] = 16,
|
[DYNAMIC_MAC_FID] = 16,
|
||||||
[DYNAMIC_MAC_TIMESTAMP] = 24,
|
[DYNAMIC_MAC_TIMESTAMP] = 22,
|
||||||
[DYNAMIC_MAC_SRC_PORT] = 20,
|
[DYNAMIC_MAC_SRC_PORT] = 20,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3354,9 +3354,14 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
|
||||||
* If this is the upstream port for this switch, enable
|
* If this is the upstream port for this switch, enable
|
||||||
* forwarding of unknown unicasts and multicasts.
|
* forwarding of unknown unicasts and multicasts.
|
||||||
*/
|
*/
|
||||||
reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP |
|
reg = MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
|
||||||
MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
|
|
||||||
MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
|
MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
|
||||||
|
/* Forward any IPv4 IGMP or IPv6 MLD frames received
|
||||||
|
* by a USER port to the CPU port to allow snooping.
|
||||||
|
*/
|
||||||
|
if (dsa_is_user_port(ds, port))
|
||||||
|
reg |= MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP;
|
||||||
|
|
||||||
err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
|
err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/overflow.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
#include "realtek.h"
|
#include "realtek.h"
|
||||||
|
@ -152,7 +153,9 @@ static int realtek_mdio_probe(struct mdio_device *mdiodev)
|
||||||
if (!var)
|
if (!var)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
|
priv = devm_kzalloc(&mdiodev->dev,
|
||||||
|
size_add(sizeof(*priv), var->chip_data_sz),
|
||||||
|
GFP_KERNEL);
|
||||||
if (!priv)
|
if (!priv)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
|
@ -672,6 +672,18 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct sk_buff *
|
||||||
|
bnx2x_build_skb(const struct bnx2x_fastpath *fp, void *data)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
if (fp->rx_frag_size)
|
||||||
|
skb = build_skb(data, fp->rx_frag_size);
|
||||||
|
else
|
||||||
|
skb = slab_build_skb(data);
|
||||||
|
return skb;
|
||||||
|
}
|
||||||
|
|
||||||
static void bnx2x_frag_free(const struct bnx2x_fastpath *fp, void *data)
|
static void bnx2x_frag_free(const struct bnx2x_fastpath *fp, void *data)
|
||||||
{
|
{
|
||||||
if (fp->rx_frag_size)
|
if (fp->rx_frag_size)
|
||||||
|
@ -779,7 +791,7 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
|
||||||
dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping),
|
dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping),
|
||||||
fp->rx_buf_size, DMA_FROM_DEVICE);
|
fp->rx_buf_size, DMA_FROM_DEVICE);
|
||||||
if (likely(new_data))
|
if (likely(new_data))
|
||||||
skb = build_skb(data, fp->rx_frag_size);
|
skb = bnx2x_build_skb(fp, data);
|
||||||
|
|
||||||
if (likely(skb)) {
|
if (likely(skb)) {
|
||||||
#ifdef BNX2X_STOP_ON_ERROR
|
#ifdef BNX2X_STOP_ON_ERROR
|
||||||
|
@ -1046,7 +1058,7 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
|
||||||
dma_unmap_addr(rx_buf, mapping),
|
dma_unmap_addr(rx_buf, mapping),
|
||||||
fp->rx_buf_size,
|
fp->rx_buf_size,
|
||||||
DMA_FROM_DEVICE);
|
DMA_FROM_DEVICE);
|
||||||
skb = build_skb(data, fp->rx_frag_size);
|
skb = bnx2x_build_skb(fp, data);
|
||||||
if (unlikely(!skb)) {
|
if (unlikely(!skb)) {
|
||||||
bnx2x_frag_free(fp, data);
|
bnx2x_frag_free(fp, data);
|
||||||
bnx2x_fp_qstats(bp, fp)->
|
bnx2x_fp_qstats(bp, fp)->
|
||||||
|
|
|
@ -175,12 +175,12 @@ static const struct pci_device_id bnxt_pci_tbl[] = {
|
||||||
{ PCI_VDEVICE(BROADCOM, 0x1750), .driver_data = BCM57508 },
|
{ PCI_VDEVICE(BROADCOM, 0x1750), .driver_data = BCM57508 },
|
||||||
{ PCI_VDEVICE(BROADCOM, 0x1751), .driver_data = BCM57504 },
|
{ PCI_VDEVICE(BROADCOM, 0x1751), .driver_data = BCM57504 },
|
||||||
{ PCI_VDEVICE(BROADCOM, 0x1752), .driver_data = BCM57502 },
|
{ PCI_VDEVICE(BROADCOM, 0x1752), .driver_data = BCM57502 },
|
||||||
{ PCI_VDEVICE(BROADCOM, 0x1800), .driver_data = BCM57508_NPAR },
|
{ PCI_VDEVICE(BROADCOM, 0x1800), .driver_data = BCM57502_NPAR },
|
||||||
{ PCI_VDEVICE(BROADCOM, 0x1801), .driver_data = BCM57504_NPAR },
|
{ PCI_VDEVICE(BROADCOM, 0x1801), .driver_data = BCM57504_NPAR },
|
||||||
{ PCI_VDEVICE(BROADCOM, 0x1802), .driver_data = BCM57502_NPAR },
|
{ PCI_VDEVICE(BROADCOM, 0x1802), .driver_data = BCM57508_NPAR },
|
||||||
{ PCI_VDEVICE(BROADCOM, 0x1803), .driver_data = BCM57508_NPAR },
|
{ PCI_VDEVICE(BROADCOM, 0x1803), .driver_data = BCM57502_NPAR },
|
||||||
{ PCI_VDEVICE(BROADCOM, 0x1804), .driver_data = BCM57504_NPAR },
|
{ PCI_VDEVICE(BROADCOM, 0x1804), .driver_data = BCM57504_NPAR },
|
||||||
{ PCI_VDEVICE(BROADCOM, 0x1805), .driver_data = BCM57502_NPAR },
|
{ PCI_VDEVICE(BROADCOM, 0x1805), .driver_data = BCM57508_NPAR },
|
||||||
{ PCI_VDEVICE(BROADCOM, 0xd802), .driver_data = BCM58802 },
|
{ PCI_VDEVICE(BROADCOM, 0xd802), .driver_data = BCM58802 },
|
||||||
{ PCI_VDEVICE(BROADCOM, 0xd804), .driver_data = BCM58804 },
|
{ PCI_VDEVICE(BROADCOM, 0xd804), .driver_data = BCM58804 },
|
||||||
#ifdef CONFIG_BNXT_SRIOV
|
#ifdef CONFIG_BNXT_SRIOV
|
||||||
|
|
|
@ -1226,6 +1226,7 @@ struct bnxt_link_info {
|
||||||
#define BNXT_LINK_SPEED_40GB PORT_PHY_QCFG_RESP_LINK_SPEED_40GB
|
#define BNXT_LINK_SPEED_40GB PORT_PHY_QCFG_RESP_LINK_SPEED_40GB
|
||||||
#define BNXT_LINK_SPEED_50GB PORT_PHY_QCFG_RESP_LINK_SPEED_50GB
|
#define BNXT_LINK_SPEED_50GB PORT_PHY_QCFG_RESP_LINK_SPEED_50GB
|
||||||
#define BNXT_LINK_SPEED_100GB PORT_PHY_QCFG_RESP_LINK_SPEED_100GB
|
#define BNXT_LINK_SPEED_100GB PORT_PHY_QCFG_RESP_LINK_SPEED_100GB
|
||||||
|
#define BNXT_LINK_SPEED_200GB PORT_PHY_QCFG_RESP_LINK_SPEED_200GB
|
||||||
u16 support_speeds;
|
u16 support_speeds;
|
||||||
u16 support_pam4_speeds;
|
u16 support_pam4_speeds;
|
||||||
u16 auto_link_speeds; /* fw adv setting */
|
u16 auto_link_speeds; /* fw adv setting */
|
||||||
|
|
|
@ -1714,6 +1714,8 @@ u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed)
|
||||||
return SPEED_50000;
|
return SPEED_50000;
|
||||||
case BNXT_LINK_SPEED_100GB:
|
case BNXT_LINK_SPEED_100GB:
|
||||||
return SPEED_100000;
|
return SPEED_100000;
|
||||||
|
case BNXT_LINK_SPEED_200GB:
|
||||||
|
return SPEED_200000;
|
||||||
default:
|
default:
|
||||||
return SPEED_UNKNOWN;
|
return SPEED_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
@ -3738,6 +3740,7 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest,
|
||||||
bnxt_ulp_stop(bp);
|
bnxt_ulp_stop(bp);
|
||||||
rc = bnxt_close_nic(bp, true, false);
|
rc = bnxt_close_nic(bp, true, false);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
etest->flags |= ETH_TEST_FL_FAILED;
|
||||||
bnxt_ulp_start(bp, rc);
|
bnxt_ulp_start(bp, rc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ static int i40e_diag_reg_pattern_test(struct i40e_hw *hw,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct i40e_diag_reg_test_info i40e_reg_list[] = {
|
const struct i40e_diag_reg_test_info i40e_reg_list[] = {
|
||||||
/* offset mask elements stride */
|
/* offset mask elements stride */
|
||||||
{I40E_QTX_CTL(0), 0x0000FFBF, 1,
|
{I40E_QTX_CTL(0), 0x0000FFBF, 1,
|
||||||
I40E_QTX_CTL(1) - I40E_QTX_CTL(0)},
|
I40E_QTX_CTL(1) - I40E_QTX_CTL(0)},
|
||||||
|
@ -78,27 +78,28 @@ int i40e_diag_reg_test(struct i40e_hw *hw)
|
||||||
{
|
{
|
||||||
int ret_code = 0;
|
int ret_code = 0;
|
||||||
u32 reg, mask;
|
u32 reg, mask;
|
||||||
|
u32 elements;
|
||||||
u32 i, j;
|
u32 i, j;
|
||||||
|
|
||||||
for (i = 0; i40e_reg_list[i].offset != 0 &&
|
for (i = 0; i40e_reg_list[i].offset != 0 &&
|
||||||
!ret_code; i++) {
|
!ret_code; i++) {
|
||||||
|
|
||||||
|
elements = i40e_reg_list[i].elements;
|
||||||
/* set actual reg range for dynamically allocated resources */
|
/* set actual reg range for dynamically allocated resources */
|
||||||
if (i40e_reg_list[i].offset == I40E_QTX_CTL(0) &&
|
if (i40e_reg_list[i].offset == I40E_QTX_CTL(0) &&
|
||||||
hw->func_caps.num_tx_qp != 0)
|
hw->func_caps.num_tx_qp != 0)
|
||||||
i40e_reg_list[i].elements = hw->func_caps.num_tx_qp;
|
elements = hw->func_caps.num_tx_qp;
|
||||||
if ((i40e_reg_list[i].offset == I40E_PFINT_ITRN(0, 0) ||
|
if ((i40e_reg_list[i].offset == I40E_PFINT_ITRN(0, 0) ||
|
||||||
i40e_reg_list[i].offset == I40E_PFINT_ITRN(1, 0) ||
|
i40e_reg_list[i].offset == I40E_PFINT_ITRN(1, 0) ||
|
||||||
i40e_reg_list[i].offset == I40E_PFINT_ITRN(2, 0) ||
|
i40e_reg_list[i].offset == I40E_PFINT_ITRN(2, 0) ||
|
||||||
i40e_reg_list[i].offset == I40E_QINT_TQCTL(0) ||
|
i40e_reg_list[i].offset == I40E_QINT_TQCTL(0) ||
|
||||||
i40e_reg_list[i].offset == I40E_QINT_RQCTL(0)) &&
|
i40e_reg_list[i].offset == I40E_QINT_RQCTL(0)) &&
|
||||||
hw->func_caps.num_msix_vectors != 0)
|
hw->func_caps.num_msix_vectors != 0)
|
||||||
i40e_reg_list[i].elements =
|
elements = hw->func_caps.num_msix_vectors - 1;
|
||||||
hw->func_caps.num_msix_vectors - 1;
|
|
||||||
|
|
||||||
/* test register access */
|
/* test register access */
|
||||||
mask = i40e_reg_list[i].mask;
|
mask = i40e_reg_list[i].mask;
|
||||||
for (j = 0; j < i40e_reg_list[i].elements && !ret_code; j++) {
|
for (j = 0; j < elements && !ret_code; j++) {
|
||||||
reg = i40e_reg_list[i].offset +
|
reg = i40e_reg_list[i].offset +
|
||||||
(j * i40e_reg_list[i].stride);
|
(j * i40e_reg_list[i].stride);
|
||||||
ret_code = i40e_diag_reg_pattern_test(hw, reg, mask);
|
ret_code = i40e_diag_reg_pattern_test(hw, reg, mask);
|
||||||
|
|
|
@ -20,7 +20,7 @@ struct i40e_diag_reg_test_info {
|
||||||
u32 stride; /* bytes between each element */
|
u32 stride; /* bytes between each element */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct i40e_diag_reg_test_info i40e_reg_list[];
|
extern const struct i40e_diag_reg_test_info i40e_reg_list[];
|
||||||
|
|
||||||
int i40e_diag_reg_test(struct i40e_hw *hw);
|
int i40e_diag_reg_test(struct i40e_hw *hw);
|
||||||
int i40e_diag_eeprom_test(struct i40e_hw *hw);
|
int i40e_diag_eeprom_test(struct i40e_hw *hw);
|
||||||
|
|
|
@ -2788,7 +2788,7 @@ static int
|
||||||
ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id,
|
ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id,
|
||||||
u16 vsi_handle, unsigned long *tc_bitmap)
|
u16 vsi_handle, unsigned long *tc_bitmap)
|
||||||
{
|
{
|
||||||
struct ice_sched_agg_vsi_info *agg_vsi_info, *old_agg_vsi_info = NULL;
|
struct ice_sched_agg_vsi_info *agg_vsi_info, *iter, *old_agg_vsi_info = NULL;
|
||||||
struct ice_sched_agg_info *agg_info, *old_agg_info;
|
struct ice_sched_agg_info *agg_info, *old_agg_info;
|
||||||
struct ice_hw *hw = pi->hw;
|
struct ice_hw *hw = pi->hw;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
@ -2806,11 +2806,13 @@ ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id,
|
||||||
if (old_agg_info && old_agg_info != agg_info) {
|
if (old_agg_info && old_agg_info != agg_info) {
|
||||||
struct ice_sched_agg_vsi_info *vtmp;
|
struct ice_sched_agg_vsi_info *vtmp;
|
||||||
|
|
||||||
list_for_each_entry_safe(old_agg_vsi_info, vtmp,
|
list_for_each_entry_safe(iter, vtmp,
|
||||||
&old_agg_info->agg_vsi_list,
|
&old_agg_info->agg_vsi_list,
|
||||||
list_entry)
|
list_entry)
|
||||||
if (old_agg_vsi_info->vsi_handle == vsi_handle)
|
if (iter->vsi_handle == vsi_handle) {
|
||||||
|
old_agg_vsi_info = iter;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if entry already exist */
|
/* check if entry already exist */
|
||||||
|
|
|
@ -1780,18 +1780,36 @@ ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
|
||||||
int
|
int
|
||||||
ice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable)
|
ice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable)
|
||||||
{
|
{
|
||||||
struct ice_vsi_ctx *ctx;
|
struct ice_vsi_ctx *ctx, *cached_ctx;
|
||||||
|
int status;
|
||||||
|
|
||||||
ctx = ice_get_vsi_ctx(hw, vsi_handle);
|
cached_ctx = ice_get_vsi_ctx(hw, vsi_handle);
|
||||||
|
if (!cached_ctx)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
return -EIO;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ctx->info.q_opt_rss = cached_ctx->info.q_opt_rss;
|
||||||
|
ctx->info.q_opt_tc = cached_ctx->info.q_opt_tc;
|
||||||
|
ctx->info.q_opt_flags = cached_ctx->info.q_opt_flags;
|
||||||
|
|
||||||
|
ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID);
|
||||||
|
|
||||||
if (enable)
|
if (enable)
|
||||||
ctx->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
|
ctx->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
|
||||||
else
|
else
|
||||||
ctx->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
|
ctx->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
|
||||||
|
|
||||||
return ice_update_vsi(hw, vsi_handle, ctx, NULL);
|
status = ice_update_vsi(hw, vsi_handle, ctx, NULL);
|
||||||
|
if (!status) {
|
||||||
|
cached_ctx->info.q_opt_flags = ctx->info.q_opt_flags;
|
||||||
|
cached_ctx->info.valid_sections |= ctx->info.valid_sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(ctx);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -938,6 +938,7 @@ ice_reuse_rx_page(struct ice_rx_ring *rx_ring, struct ice_rx_buf *old_buf)
|
||||||
* ice_get_rx_buf - Fetch Rx buffer and synchronize data for use
|
* ice_get_rx_buf - Fetch Rx buffer and synchronize data for use
|
||||||
* @rx_ring: Rx descriptor ring to transact packets on
|
* @rx_ring: Rx descriptor ring to transact packets on
|
||||||
* @size: size of buffer to add to skb
|
* @size: size of buffer to add to skb
|
||||||
|
* @ntc: index of next to clean element
|
||||||
*
|
*
|
||||||
* This function will pull an Rx buffer from the ring and synchronize it
|
* This function will pull an Rx buffer from the ring and synchronize it
|
||||||
* for use by the CPU.
|
* for use by the CPU.
|
||||||
|
@ -1026,7 +1027,6 @@ ice_build_skb(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp)
|
||||||
/**
|
/**
|
||||||
* ice_construct_skb - Allocate skb and populate it
|
* ice_construct_skb - Allocate skb and populate it
|
||||||
* @rx_ring: Rx descriptor ring to transact packets on
|
* @rx_ring: Rx descriptor ring to transact packets on
|
||||||
* @rx_buf: Rx buffer to pull data from
|
|
||||||
* @xdp: xdp_buff pointing to the data
|
* @xdp: xdp_buff pointing to the data
|
||||||
*
|
*
|
||||||
* This function allocates an skb. It then populates it with the page
|
* This function allocates an skb. It then populates it with the page
|
||||||
|
|
|
@ -438,6 +438,7 @@ busy:
|
||||||
* ice_finalize_xdp_rx - Bump XDP Tx tail and/or flush redirect map
|
* ice_finalize_xdp_rx - Bump XDP Tx tail and/or flush redirect map
|
||||||
* @xdp_ring: XDP ring
|
* @xdp_ring: XDP ring
|
||||||
* @xdp_res: Result of the receive batch
|
* @xdp_res: Result of the receive batch
|
||||||
|
* @first_idx: index to write from caller
|
||||||
*
|
*
|
||||||
* This function bumps XDP Tx tail and/or flush redirect map, and
|
* This function bumps XDP Tx tail and/or flush redirect map, and
|
||||||
* should be called when a batch of packets has been processed in the
|
* should be called when a batch of packets has been processed in the
|
||||||
|
|
|
@ -541,6 +541,72 @@ static void ice_vc_fdir_rem_prof_all(struct ice_vf *vf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ice_vc_fdir_has_prof_conflict
|
||||||
|
* @vf: pointer to the VF structure
|
||||||
|
* @conf: FDIR configuration for each filter
|
||||||
|
*
|
||||||
|
* Check if @conf has conflicting profile with existing profiles
|
||||||
|
*
|
||||||
|
* Return: true on success, and false on error.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ice_vc_fdir_has_prof_conflict(struct ice_vf *vf,
|
||||||
|
struct virtchnl_fdir_fltr_conf *conf)
|
||||||
|
{
|
||||||
|
struct ice_fdir_fltr *desc;
|
||||||
|
|
||||||
|
list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) {
|
||||||
|
struct virtchnl_fdir_fltr_conf *existing_conf;
|
||||||
|
enum ice_fltr_ptype flow_type_a, flow_type_b;
|
||||||
|
struct ice_fdir_fltr *a, *b;
|
||||||
|
|
||||||
|
existing_conf = to_fltr_conf_from_desc(desc);
|
||||||
|
a = &existing_conf->input;
|
||||||
|
b = &conf->input;
|
||||||
|
flow_type_a = a->flow_type;
|
||||||
|
flow_type_b = b->flow_type;
|
||||||
|
|
||||||
|
/* No need to compare two rules with different tunnel types or
|
||||||
|
* with the same protocol type.
|
||||||
|
*/
|
||||||
|
if (existing_conf->ttype != conf->ttype ||
|
||||||
|
flow_type_a == flow_type_b)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (flow_type_a) {
|
||||||
|
case ICE_FLTR_PTYPE_NONF_IPV4_UDP:
|
||||||
|
case ICE_FLTR_PTYPE_NONF_IPV4_TCP:
|
||||||
|
case ICE_FLTR_PTYPE_NONF_IPV4_SCTP:
|
||||||
|
if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_OTHER)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case ICE_FLTR_PTYPE_NONF_IPV4_OTHER:
|
||||||
|
if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_UDP ||
|
||||||
|
flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_TCP ||
|
||||||
|
flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_SCTP)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case ICE_FLTR_PTYPE_NONF_IPV6_UDP:
|
||||||
|
case ICE_FLTR_PTYPE_NONF_IPV6_TCP:
|
||||||
|
case ICE_FLTR_PTYPE_NONF_IPV6_SCTP:
|
||||||
|
if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_OTHER)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case ICE_FLTR_PTYPE_NONF_IPV6_OTHER:
|
||||||
|
if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_UDP ||
|
||||||
|
flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_TCP ||
|
||||||
|
flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_SCTP)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ice_vc_fdir_write_flow_prof
|
* ice_vc_fdir_write_flow_prof
|
||||||
* @vf: pointer to the VF structure
|
* @vf: pointer to the VF structure
|
||||||
|
@ -677,6 +743,13 @@ ice_vc_fdir_config_input_set(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
|
||||||
enum ice_fltr_ptype flow;
|
enum ice_fltr_ptype flow;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = ice_vc_fdir_has_prof_conflict(vf, conf);
|
||||||
|
if (ret) {
|
||||||
|
dev_dbg(dev, "Found flow profile conflict for VF %d\n",
|
||||||
|
vf->vf_id);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
flow = input->flow_type;
|
flow = input->flow_type;
|
||||||
ret = ice_vc_fdir_alloc_prof(vf, flow);
|
ret = ice_vc_fdir_alloc_prof(vf, flow);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
|
@ -3549,6 +3549,8 @@ static void mvneta_txq_sw_deinit(struct mvneta_port *pp,
|
||||||
|
|
||||||
netdev_tx_reset_queue(nq);
|
netdev_tx_reset_queue(nq);
|
||||||
|
|
||||||
|
txq->buf = NULL;
|
||||||
|
txq->tso_hdrs = NULL;
|
||||||
txq->descs = NULL;
|
txq->descs = NULL;
|
||||||
txq->last_desc = 0;
|
txq->last_desc = 0;
|
||||||
txq->next_desc_to_proc = 0;
|
txq->next_desc_to_proc = 0;
|
||||||
|
|
|
@ -62,35 +62,38 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
|
||||||
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
|
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
|
||||||
MVPP22_CLS_HEK_IP4_2T,
|
MVPP22_CLS_HEK_IP4_2T,
|
||||||
MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
|
MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
|
||||||
MVPP2_PRS_RI_L4_TCP,
|
MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,
|
||||||
MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
|
MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
|
||||||
|
|
||||||
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
|
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
|
||||||
MVPP22_CLS_HEK_IP4_2T,
|
MVPP22_CLS_HEK_IP4_2T,
|
||||||
MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
|
MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
|
||||||
MVPP2_PRS_RI_L4_TCP,
|
MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,
|
||||||
MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
|
MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
|
||||||
|
|
||||||
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
|
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
|
||||||
MVPP22_CLS_HEK_IP4_2T,
|
MVPP22_CLS_HEK_IP4_2T,
|
||||||
MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
|
MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
|
||||||
MVPP2_PRS_RI_L4_TCP,
|
MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,
|
||||||
MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
|
MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
|
||||||
|
|
||||||
/* TCP over IPv4 flows, fragmented, with vlan tag */
|
/* TCP over IPv4 flows, fragmented, with vlan tag */
|
||||||
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
|
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
|
||||||
MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
|
MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
|
||||||
MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_TCP,
|
MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_IP_FRAG_TRUE |
|
||||||
|
MVPP2_PRS_RI_L4_TCP,
|
||||||
MVPP2_PRS_IP_MASK),
|
MVPP2_PRS_IP_MASK),
|
||||||
|
|
||||||
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
|
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
|
||||||
MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
|
MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
|
||||||
MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_TCP,
|
MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_IP_FRAG_TRUE |
|
||||||
|
MVPP2_PRS_RI_L4_TCP,
|
||||||
MVPP2_PRS_IP_MASK),
|
MVPP2_PRS_IP_MASK),
|
||||||
|
|
||||||
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
|
MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
|
||||||
MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
|
MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
|
||||||
MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_TCP,
|
MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_IP_FRAG_TRUE |
|
||||||
|
MVPP2_PRS_RI_L4_TCP,
|
||||||
MVPP2_PRS_IP_MASK),
|
MVPP2_PRS_IP_MASK),
|
||||||
|
|
||||||
/* UDP over IPv4 flows, Not fragmented, no vlan tag */
|
/* UDP over IPv4 flows, Not fragmented, no vlan tag */
|
||||||
|
@ -132,35 +135,38 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
|
||||||
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
|
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
|
||||||
MVPP22_CLS_HEK_IP4_2T,
|
MVPP22_CLS_HEK_IP4_2T,
|
||||||
MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
|
MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
|
||||||
MVPP2_PRS_RI_L4_UDP,
|
MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,
|
||||||
MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
|
MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
|
||||||
|
|
||||||
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
|
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
|
||||||
MVPP22_CLS_HEK_IP4_2T,
|
MVPP22_CLS_HEK_IP4_2T,
|
||||||
MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
|
MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
|
||||||
MVPP2_PRS_RI_L4_UDP,
|
MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,
|
||||||
MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
|
MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
|
||||||
|
|
||||||
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
|
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
|
||||||
MVPP22_CLS_HEK_IP4_2T,
|
MVPP22_CLS_HEK_IP4_2T,
|
||||||
MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
|
MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
|
||||||
MVPP2_PRS_RI_L4_UDP,
|
MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,
|
||||||
MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
|
MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
|
||||||
|
|
||||||
/* UDP over IPv4 flows, fragmented, with vlan tag */
|
/* UDP over IPv4 flows, fragmented, with vlan tag */
|
||||||
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
|
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
|
||||||
MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
|
MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
|
||||||
MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_UDP,
|
MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_IP_FRAG_TRUE |
|
||||||
|
MVPP2_PRS_RI_L4_UDP,
|
||||||
MVPP2_PRS_IP_MASK),
|
MVPP2_PRS_IP_MASK),
|
||||||
|
|
||||||
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
|
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
|
||||||
MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
|
MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
|
||||||
MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_UDP,
|
MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_IP_FRAG_TRUE |
|
||||||
|
MVPP2_PRS_RI_L4_UDP,
|
||||||
MVPP2_PRS_IP_MASK),
|
MVPP2_PRS_IP_MASK),
|
||||||
|
|
||||||
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
|
MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
|
||||||
MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
|
MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
|
||||||
MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_UDP,
|
MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_IP_FRAG_TRUE |
|
||||||
|
MVPP2_PRS_RI_L4_UDP,
|
||||||
MVPP2_PRS_IP_MASK),
|
MVPP2_PRS_IP_MASK),
|
||||||
|
|
||||||
/* TCP over IPv6 flows, not fragmented, no vlan tag */
|
/* TCP over IPv6 flows, not fragmented, no vlan tag */
|
||||||
|
|
|
@ -1539,8 +1539,8 @@ static int mvpp2_prs_vlan_init(struct platform_device *pdev, struct mvpp2 *priv)
|
||||||
if (!priv->prs_double_vlans)
|
if (!priv->prs_double_vlans)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Double VLAN: 0x8100, 0x88A8 */
|
/* Double VLAN: 0x88A8, 0x8100 */
|
||||||
err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021Q, ETH_P_8021AD,
|
err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021AD, ETH_P_8021Q,
|
||||||
MVPP2_PRS_PORT_MASK);
|
MVPP2_PRS_PORT_MASK);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -1607,59 +1607,45 @@ static int mvpp2_prs_vlan_init(struct platform_device *pdev, struct mvpp2 *priv)
|
||||||
static int mvpp2_prs_pppoe_init(struct mvpp2 *priv)
|
static int mvpp2_prs_pppoe_init(struct mvpp2 *priv)
|
||||||
{
|
{
|
||||||
struct mvpp2_prs_entry pe;
|
struct mvpp2_prs_entry pe;
|
||||||
int tid;
|
int tid, ihl;
|
||||||
|
|
||||||
/* IPv4 over PPPoE with options */
|
/* IPv4 over PPPoE with header length >= 5 */
|
||||||
tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
|
for (ihl = MVPP2_PRS_IPV4_IHL_MIN; ihl <= MVPP2_PRS_IPV4_IHL_MAX; ihl++) {
|
||||||
MVPP2_PE_LAST_FREE_TID);
|
tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
|
||||||
if (tid < 0)
|
MVPP2_PE_LAST_FREE_TID);
|
||||||
return tid;
|
if (tid < 0)
|
||||||
|
return tid;
|
||||||
|
|
||||||
memset(&pe, 0, sizeof(pe));
|
memset(&pe, 0, sizeof(pe));
|
||||||
mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
|
mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
|
||||||
pe.index = tid;
|
pe.index = tid;
|
||||||
|
|
||||||
mvpp2_prs_match_etype(&pe, 0, PPP_IP);
|
mvpp2_prs_match_etype(&pe, 0, PPP_IP);
|
||||||
|
mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
|
||||||
|
MVPP2_PRS_IPV4_HEAD | ihl,
|
||||||
|
MVPP2_PRS_IPV4_HEAD_MASK |
|
||||||
|
MVPP2_PRS_IPV4_IHL_MASK);
|
||||||
|
|
||||||
mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
|
mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
|
||||||
mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4_OPT,
|
mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
|
||||||
MVPP2_PRS_RI_L3_PROTO_MASK);
|
MVPP2_PRS_RI_L3_PROTO_MASK);
|
||||||
/* goto ipv4 dest-address (skip eth_type + IP-header-size - 4) */
|
/* goto ipv4 dst-address (skip eth_type + IP-header-size - 4) */
|
||||||
mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN +
|
mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN +
|
||||||
sizeof(struct iphdr) - 4,
|
sizeof(struct iphdr) - 4,
|
||||||
MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
||||||
/* Set L3 offset */
|
/* Set L3 offset */
|
||||||
mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
|
mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
|
||||||
MVPP2_ETH_TYPE_LEN,
|
MVPP2_ETH_TYPE_LEN,
|
||||||
MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
|
MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
|
||||||
|
/* Set L4 offset */
|
||||||
|
mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
|
||||||
|
MVPP2_ETH_TYPE_LEN + (ihl * 4),
|
||||||
|
MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
|
||||||
|
|
||||||
/* Update shadow table and hw entry */
|
/* Update shadow table and hw entry */
|
||||||
mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
|
mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
|
||||||
mvpp2_prs_hw_write(priv, &pe);
|
mvpp2_prs_hw_write(priv, &pe);
|
||||||
|
}
|
||||||
/* IPv4 over PPPoE without options */
|
|
||||||
tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
|
|
||||||
MVPP2_PE_LAST_FREE_TID);
|
|
||||||
if (tid < 0)
|
|
||||||
return tid;
|
|
||||||
|
|
||||||
pe.index = tid;
|
|
||||||
|
|
||||||
mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
|
|
||||||
MVPP2_PRS_IPV4_HEAD |
|
|
||||||
MVPP2_PRS_IPV4_IHL_MIN,
|
|
||||||
MVPP2_PRS_IPV4_HEAD_MASK |
|
|
||||||
MVPP2_PRS_IPV4_IHL_MASK);
|
|
||||||
|
|
||||||
/* Clear ri before updating */
|
|
||||||
pe.sram[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
|
|
||||||
pe.sram[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
|
|
||||||
mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
|
|
||||||
MVPP2_PRS_RI_L3_PROTO_MASK);
|
|
||||||
|
|
||||||
/* Update shadow table and hw entry */
|
|
||||||
mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
|
|
||||||
mvpp2_prs_hw_write(priv, &pe);
|
|
||||||
|
|
||||||
/* IPv6 over PPPoE */
|
/* IPv6 over PPPoE */
|
||||||
tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
|
tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
|
||||||
|
|
|
@ -763,8 +763,6 @@ static void mtk_mac_link_up(struct phylink_config *config,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtk_set_queue_speed(mac->hw, mac->id, speed);
|
|
||||||
|
|
||||||
/* Configure duplex */
|
/* Configure duplex */
|
||||||
if (duplex == DUPLEX_FULL)
|
if (duplex == DUPLEX_FULL)
|
||||||
mcr |= MAC_MCR_FORCE_DPX;
|
mcr |= MAC_MCR_FORCE_DPX;
|
||||||
|
@ -2059,9 +2057,6 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
|
||||||
skb_checksum_none_assert(skb);
|
skb_checksum_none_assert(skb);
|
||||||
skb->protocol = eth_type_trans(skb, netdev);
|
skb->protocol = eth_type_trans(skb, netdev);
|
||||||
|
|
||||||
if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
|
|
||||||
mtk_ppe_check_skb(eth->ppe[0], skb, hash);
|
|
||||||
|
|
||||||
if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
|
if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
|
||||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
|
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
|
||||||
if (trxd.rxd3 & RX_DMA_VTAG_V2) {
|
if (trxd.rxd3 & RX_DMA_VTAG_V2) {
|
||||||
|
@ -2089,6 +2084,9 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
|
||||||
__vlan_hwaccel_put_tag(skb, htons(vlan_proto), vlan_tci);
|
__vlan_hwaccel_put_tag(skb, htons(vlan_proto), vlan_tci);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
|
||||||
|
mtk_ppe_check_skb(eth->ppe[0], skb, hash);
|
||||||
|
|
||||||
skb_record_rx_queue(skb, 0);
|
skb_record_rx_queue(skb, 0);
|
||||||
napi_gro_receive(napi, skb);
|
napi_gro_receive(napi, skb);
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/if_ether.h>
|
#include <linux/if_ether.h>
|
||||||
#include <linux/if_vlan.h>
|
#include <linux/if_vlan.h>
|
||||||
|
#include <net/dst_metadata.h>
|
||||||
#include <net/dsa.h>
|
#include <net/dsa.h>
|
||||||
#include "mtk_eth_soc.h"
|
#include "mtk_eth_soc.h"
|
||||||
#include "mtk_ppe.h"
|
#include "mtk_ppe.h"
|
||||||
|
@ -458,6 +459,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||||
hwe->ib1 &= ~MTK_FOE_IB1_STATE;
|
hwe->ib1 &= ~MTK_FOE_IB1_STATE;
|
||||||
hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID);
|
hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID);
|
||||||
dma_wmb();
|
dma_wmb();
|
||||||
|
mtk_ppe_cache_clear(ppe);
|
||||||
}
|
}
|
||||||
entry->hash = 0xffff;
|
entry->hash = 0xffff;
|
||||||
|
|
||||||
|
@ -699,7 +701,9 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
|
||||||
skb->dev->dsa_ptr->tag_ops->proto != DSA_TAG_PROTO_MTK)
|
skb->dev->dsa_ptr->tag_ops->proto != DSA_TAG_PROTO_MTK)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
tag += 4;
|
if (!skb_metadata_dst(skb))
|
||||||
|
tag += 4;
|
||||||
|
|
||||||
if (get_unaligned_be16(tag) != ETH_P_8021Q)
|
if (get_unaligned_be16(tag) != ETH_P_8021Q)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -576,6 +576,7 @@ mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
|
||||||
if (IS_ERR(block_cb))
|
if (IS_ERR(block_cb))
|
||||||
return PTR_ERR(block_cb);
|
return PTR_ERR(block_cb);
|
||||||
|
|
||||||
|
flow_block_cb_incref(block_cb);
|
||||||
flow_block_cb_add(block_cb, f);
|
flow_block_cb_add(block_cb, f);
|
||||||
list_add_tail(&block_cb->driver_list, &block_cb_list);
|
list_add_tail(&block_cb->driver_list, &block_cb_list);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -584,7 +585,7 @@ mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
|
||||||
if (!block_cb)
|
if (!block_cb)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
if (flow_block_cb_decref(block_cb)) {
|
if (!flow_block_cb_decref(block_cb)) {
|
||||||
flow_block_cb_remove(block_cb, f);
|
flow_block_cb_remove(block_cb, f);
|
||||||
list_del(&block_cb->driver_list);
|
list_del(&block_cb->driver_list);
|
||||||
}
|
}
|
||||||
|
|
|
@ -826,6 +826,9 @@ static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp,
|
||||||
/* disable phy pfm mode */
|
/* disable phy pfm mode */
|
||||||
phy_modify_paged(phydev, 0x0a44, 0x11, BIT(7), 0);
|
phy_modify_paged(phydev, 0x0a44, 0x11, BIT(7), 0);
|
||||||
|
|
||||||
|
/* disable 10m pll off */
|
||||||
|
phy_modify_paged(phydev, 0x0a43, 0x10, BIT(0), 0);
|
||||||
|
|
||||||
rtl8168g_disable_aldps(phydev);
|
rtl8168g_disable_aldps(phydev);
|
||||||
rtl8168g_config_eee_phy(phydev);
|
rtl8168g_config_eee_phy(phydev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1304,7 +1304,8 @@ static void efx_ef10_fini_nic(struct efx_nic *efx)
|
||||||
static int efx_ef10_init_nic(struct efx_nic *efx)
|
static int efx_ef10_init_nic(struct efx_nic *efx)
|
||||||
{
|
{
|
||||||
struct efx_ef10_nic_data *nic_data = efx->nic_data;
|
struct efx_ef10_nic_data *nic_data = efx->nic_data;
|
||||||
netdev_features_t hw_enc_features = 0;
|
struct net_device *net_dev = efx->net_dev;
|
||||||
|
netdev_features_t tun_feats, tso_feats;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (nic_data->must_check_datapath_caps) {
|
if (nic_data->must_check_datapath_caps) {
|
||||||
|
@ -1349,20 +1350,30 @@ static int efx_ef10_init_nic(struct efx_nic *efx)
|
||||||
nic_data->must_restore_piobufs = false;
|
nic_data->must_restore_piobufs = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add encapsulated checksum offload features */
|
/* encap features might change during reset if fw variant changed */
|
||||||
if (efx_has_cap(efx, VXLAN_NVGRE) && !efx_ef10_is_vf(efx))
|
if (efx_has_cap(efx, VXLAN_NVGRE) && !efx_ef10_is_vf(efx))
|
||||||
hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
|
net_dev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
|
||||||
/* add encapsulated TSO features */
|
else
|
||||||
|
net_dev->hw_enc_features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
|
||||||
|
|
||||||
|
tun_feats = NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_GRE |
|
||||||
|
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_GSO_GRE_CSUM;
|
||||||
|
tso_feats = NETIF_F_TSO | NETIF_F_TSO6;
|
||||||
|
|
||||||
if (efx_has_cap(efx, TX_TSO_V2_ENCAP)) {
|
if (efx_has_cap(efx, TX_TSO_V2_ENCAP)) {
|
||||||
netdev_features_t encap_tso_features;
|
/* If this is first nic_init, or if it is a reset and a new fw
|
||||||
|
* variant has added new features, enable them by default.
|
||||||
encap_tso_features = NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_GRE |
|
* If the features are not new, maintain their current value.
|
||||||
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_GSO_GRE_CSUM;
|
*/
|
||||||
|
if (!(net_dev->hw_features & tun_feats))
|
||||||
hw_enc_features |= encap_tso_features | NETIF_F_TSO;
|
net_dev->features |= tun_feats;
|
||||||
efx->net_dev->features |= encap_tso_features;
|
net_dev->hw_enc_features |= tun_feats | tso_feats;
|
||||||
|
net_dev->hw_features |= tun_feats;
|
||||||
|
} else {
|
||||||
|
net_dev->hw_enc_features &= ~(tun_feats | tso_feats);
|
||||||
|
net_dev->hw_features &= ~tun_feats;
|
||||||
|
net_dev->features &= ~tun_feats;
|
||||||
}
|
}
|
||||||
efx->net_dev->hw_enc_features = hw_enc_features;
|
|
||||||
|
|
||||||
/* don't fail init if RSS setup doesn't work */
|
/* don't fail init if RSS setup doesn't work */
|
||||||
rc = efx->type->rx_push_rss_config(efx, false,
|
rc = efx->type->rx_push_rss_config(efx, false,
|
||||||
|
@ -4021,7 +4032,10 @@ static unsigned int efx_ef10_recycle_ring_size(const struct efx_nic *efx)
|
||||||
NETIF_F_HW_VLAN_CTAG_FILTER | \
|
NETIF_F_HW_VLAN_CTAG_FILTER | \
|
||||||
NETIF_F_IPV6_CSUM | \
|
NETIF_F_IPV6_CSUM | \
|
||||||
NETIF_F_RXHASH | \
|
NETIF_F_RXHASH | \
|
||||||
NETIF_F_NTUPLE)
|
NETIF_F_NTUPLE | \
|
||||||
|
NETIF_F_SG | \
|
||||||
|
NETIF_F_RXCSUM | \
|
||||||
|
NETIF_F_RXALL)
|
||||||
|
|
||||||
const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
|
const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
|
||||||
.is_vf = true,
|
.is_vf = true,
|
||||||
|
|
|
@ -1001,21 +1001,18 @@ static int efx_pci_probe_post_io(struct efx_nic *efx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine netdevice features */
|
/* Determine netdevice features */
|
||||||
net_dev->features |= (efx->type->offload_features | NETIF_F_SG |
|
net_dev->features |= efx->type->offload_features;
|
||||||
NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_RXALL);
|
|
||||||
if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM)) {
|
/* Add TSO features */
|
||||||
net_dev->features |= NETIF_F_TSO6;
|
if (efx->type->tso_versions && efx->type->tso_versions(efx))
|
||||||
if (efx_has_cap(efx, TX_TSO_V2_ENCAP))
|
net_dev->features |= NETIF_F_TSO | NETIF_F_TSO6;
|
||||||
net_dev->hw_enc_features |= NETIF_F_TSO6;
|
|
||||||
}
|
|
||||||
/* Check whether device supports TSO */
|
|
||||||
if (!efx->type->tso_versions || !efx->type->tso_versions(efx))
|
|
||||||
net_dev->features &= ~NETIF_F_ALL_TSO;
|
|
||||||
/* Mask for features that also apply to VLAN devices */
|
/* Mask for features that also apply to VLAN devices */
|
||||||
net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG |
|
net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG |
|
||||||
NETIF_F_HIGHDMA | NETIF_F_ALL_TSO |
|
NETIF_F_HIGHDMA | NETIF_F_ALL_TSO |
|
||||||
NETIF_F_RXCSUM);
|
NETIF_F_RXCSUM);
|
||||||
|
|
||||||
|
/* Determine user configurable features */
|
||||||
net_dev->hw_features |= net_dev->features & ~efx->fixed_features;
|
net_dev->hw_features |= net_dev->features & ~efx->fixed_features;
|
||||||
|
|
||||||
/* Disable receiving frames with bad FCS, by default. */
|
/* Disable receiving frames with bad FCS, by default. */
|
||||||
|
|
|
@ -1037,8 +1037,6 @@ static int smsc911x_mii_probe(struct net_device *dev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Indicate that the MAC is responsible for managing PHY PM */
|
|
||||||
phydev->mac_managed_pm = true;
|
|
||||||
phy_attached_info(phydev);
|
phy_attached_info(phydev);
|
||||||
|
|
||||||
phy_set_max_speed(phydev, SPEED_100);
|
phy_set_max_speed(phydev, SPEED_100);
|
||||||
|
@ -1066,6 +1064,7 @@ static int smsc911x_mii_init(struct platform_device *pdev,
|
||||||
struct net_device *dev)
|
struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct smsc911x_data *pdata = netdev_priv(dev);
|
struct smsc911x_data *pdata = netdev_priv(dev);
|
||||||
|
struct phy_device *phydev;
|
||||||
int err = -ENXIO;
|
int err = -ENXIO;
|
||||||
|
|
||||||
pdata->mii_bus = mdiobus_alloc();
|
pdata->mii_bus = mdiobus_alloc();
|
||||||
|
@ -1108,6 +1107,10 @@ static int smsc911x_mii_init(struct platform_device *pdev,
|
||||||
goto err_out_free_bus_2;
|
goto err_out_free_bus_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
phydev = phy_find_first(pdata->mii_bus);
|
||||||
|
if (phydev)
|
||||||
|
phydev->mac_managed_pm = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_out_free_bus_2:
|
err_out_free_bus_2:
|
||||||
|
|
|
@ -532,7 +532,6 @@ struct mac_device_info {
|
||||||
unsigned int xlgmac;
|
unsigned int xlgmac;
|
||||||
unsigned int num_vlan;
|
unsigned int num_vlan;
|
||||||
u32 vlan_filter[32];
|
u32 vlan_filter[32];
|
||||||
unsigned int promisc;
|
|
||||||
bool vlan_fail_q_en;
|
bool vlan_fail_q_en;
|
||||||
u8 vlan_fail_q;
|
u8 vlan_fail_q;
|
||||||
};
|
};
|
||||||
|
|
|
@ -472,12 +472,6 @@ static int dwmac4_add_hw_vlan_rx_fltr(struct net_device *dev,
|
||||||
if (vid > 4095)
|
if (vid > 4095)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (hw->promisc) {
|
|
||||||
netdev_err(dev,
|
|
||||||
"Adding VLAN in promisc mode not supported\n");
|
|
||||||
return -EPERM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Single Rx VLAN Filter */
|
/* Single Rx VLAN Filter */
|
||||||
if (hw->num_vlan == 1) {
|
if (hw->num_vlan == 1) {
|
||||||
/* For single VLAN filter, VID 0 means VLAN promiscuous */
|
/* For single VLAN filter, VID 0 means VLAN promiscuous */
|
||||||
|
@ -527,12 +521,6 @@ static int dwmac4_del_hw_vlan_rx_fltr(struct net_device *dev,
|
||||||
{
|
{
|
||||||
int i, ret = 0;
|
int i, ret = 0;
|
||||||
|
|
||||||
if (hw->promisc) {
|
|
||||||
netdev_err(dev,
|
|
||||||
"Deleting VLAN in promisc mode not supported\n");
|
|
||||||
return -EPERM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Single Rx VLAN Filter */
|
/* Single Rx VLAN Filter */
|
||||||
if (hw->num_vlan == 1) {
|
if (hw->num_vlan == 1) {
|
||||||
if ((hw->vlan_filter[0] & GMAC_VLAN_TAG_VID) == vid) {
|
if ((hw->vlan_filter[0] & GMAC_VLAN_TAG_VID) == vid) {
|
||||||
|
@ -557,39 +545,6 @@ static int dwmac4_del_hw_vlan_rx_fltr(struct net_device *dev,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dwmac4_vlan_promisc_enable(struct net_device *dev,
|
|
||||||
struct mac_device_info *hw)
|
|
||||||
{
|
|
||||||
void __iomem *ioaddr = hw->pcsr;
|
|
||||||
u32 value;
|
|
||||||
u32 hash;
|
|
||||||
u32 val;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Single Rx VLAN Filter */
|
|
||||||
if (hw->num_vlan == 1) {
|
|
||||||
dwmac4_write_single_vlan(dev, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Extended Rx VLAN Filter Enable */
|
|
||||||
for (i = 0; i < hw->num_vlan; i++) {
|
|
||||||
if (hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VEN) {
|
|
||||||
val = hw->vlan_filter[i] & ~GMAC_VLAN_TAG_DATA_VEN;
|
|
||||||
dwmac4_write_vlan_filter(dev, hw, i, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hash = readl(ioaddr + GMAC_VLAN_HASH_TABLE);
|
|
||||||
if (hash & GMAC_VLAN_VLHT) {
|
|
||||||
value = readl(ioaddr + GMAC_VLAN_TAG);
|
|
||||||
if (value & GMAC_VLAN_VTHM) {
|
|
||||||
value &= ~GMAC_VLAN_VTHM;
|
|
||||||
writel(value, ioaddr + GMAC_VLAN_TAG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dwmac4_restore_hw_vlan_rx_fltr(struct net_device *dev,
|
static void dwmac4_restore_hw_vlan_rx_fltr(struct net_device *dev,
|
||||||
struct mac_device_info *hw)
|
struct mac_device_info *hw)
|
||||||
{
|
{
|
||||||
|
@ -709,22 +664,12 @@ static void dwmac4_set_filter(struct mac_device_info *hw,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* VLAN filtering */
|
/* VLAN filtering */
|
||||||
if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
|
if (dev->flags & IFF_PROMISC && !hw->vlan_fail_q_en)
|
||||||
|
value &= ~GMAC_PACKET_FILTER_VTFE;
|
||||||
|
else if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
|
||||||
value |= GMAC_PACKET_FILTER_VTFE;
|
value |= GMAC_PACKET_FILTER_VTFE;
|
||||||
|
|
||||||
writel(value, ioaddr + GMAC_PACKET_FILTER);
|
writel(value, ioaddr + GMAC_PACKET_FILTER);
|
||||||
|
|
||||||
if (dev->flags & IFF_PROMISC && !hw->vlan_fail_q_en) {
|
|
||||||
if (!hw->promisc) {
|
|
||||||
hw->promisc = 1;
|
|
||||||
dwmac4_vlan_promisc_enable(dev, hw);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (hw->promisc) {
|
|
||||||
hw->promisc = 0;
|
|
||||||
dwmac4_restore_hw_vlan_rx_fltr(dev, hw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
|
static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
|
||||||
|
|
|
@ -222,7 +222,7 @@
|
||||||
#define WX_PX_INTA 0x110
|
#define WX_PX_INTA 0x110
|
||||||
#define WX_PX_GPIE 0x118
|
#define WX_PX_GPIE 0x118
|
||||||
#define WX_PX_GPIE_MODEL BIT(0)
|
#define WX_PX_GPIE_MODEL BIT(0)
|
||||||
#define WX_PX_IC 0x120
|
#define WX_PX_IC(_i) (0x120 + (_i) * 4)
|
||||||
#define WX_PX_IMS(_i) (0x140 + (_i) * 4)
|
#define WX_PX_IMS(_i) (0x140 + (_i) * 4)
|
||||||
#define WX_PX_IMC(_i) (0x150 + (_i) * 4)
|
#define WX_PX_IMC(_i) (0x150 + (_i) * 4)
|
||||||
#define WX_PX_ISB_ADDR_L 0x160
|
#define WX_PX_ISB_ADDR_L 0x160
|
||||||
|
|
|
@ -352,7 +352,7 @@ static void ngbe_up(struct wx *wx)
|
||||||
netif_tx_start_all_queues(wx->netdev);
|
netif_tx_start_all_queues(wx->netdev);
|
||||||
|
|
||||||
/* clear any pending interrupts, may auto mask */
|
/* clear any pending interrupts, may auto mask */
|
||||||
rd32(wx, WX_PX_IC);
|
rd32(wx, WX_PX_IC(0));
|
||||||
rd32(wx, WX_PX_MISC_IC);
|
rd32(wx, WX_PX_MISC_IC);
|
||||||
ngbe_irq_enable(wx, true);
|
ngbe_irq_enable(wx, true);
|
||||||
if (wx->gpio_ctrl)
|
if (wx->gpio_ctrl)
|
||||||
|
|
|
@ -229,7 +229,8 @@ static void txgbe_up_complete(struct wx *wx)
|
||||||
wx_napi_enable_all(wx);
|
wx_napi_enable_all(wx);
|
||||||
|
|
||||||
/* clear any pending interrupts, may auto mask */
|
/* clear any pending interrupts, may auto mask */
|
||||||
rd32(wx, WX_PX_IC);
|
rd32(wx, WX_PX_IC(0));
|
||||||
|
rd32(wx, WX_PX_IC(1));
|
||||||
rd32(wx, WX_PX_MISC_IC);
|
rd32(wx, WX_PX_MISC_IC);
|
||||||
txgbe_irq_enable(wx, true);
|
txgbe_irq_enable(wx, true);
|
||||||
|
|
||||||
|
|
|
@ -1902,10 +1902,9 @@ static int ca8210_skb_tx(
|
||||||
struct ca8210_priv *priv
|
struct ca8210_priv *priv
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int status;
|
|
||||||
struct ieee802154_hdr header = { };
|
struct ieee802154_hdr header = { };
|
||||||
struct secspec secspec;
|
struct secspec secspec;
|
||||||
unsigned int mac_len;
|
int mac_len, status;
|
||||||
|
|
||||||
dev_dbg(&priv->spi->dev, "%s called\n", __func__);
|
dev_dbg(&priv->spi->dev, "%s called\n", __func__);
|
||||||
|
|
||||||
|
|
|
@ -156,7 +156,7 @@ int gsi_trans_pool_init_dma(struct device *dev, struct gsi_trans_pool *pool,
|
||||||
* gsi_trans_pool_exit_dma() can assume the total allocated
|
* gsi_trans_pool_exit_dma() can assume the total allocated
|
||||||
* size is exactly (count * size).
|
* size is exactly (count * size).
|
||||||
*/
|
*/
|
||||||
total_size = get_order(total_size) << PAGE_SHIFT;
|
total_size = PAGE_SIZE << get_order(total_size);
|
||||||
|
|
||||||
virt = dma_alloc_coherent(dev, total_size, &addr, GFP_KERNEL);
|
virt = dma_alloc_coherent(dev, total_size, &addr, GFP_KERNEL);
|
||||||
if (!virt)
|
if (!virt)
|
||||||
|
|
|
@ -130,14 +130,10 @@ static u16 net_failover_select_queue(struct net_device *dev,
|
||||||
txq = ops->ndo_select_queue(primary_dev, skb, sb_dev);
|
txq = ops->ndo_select_queue(primary_dev, skb, sb_dev);
|
||||||
else
|
else
|
||||||
txq = netdev_pick_tx(primary_dev, skb, NULL);
|
txq = netdev_pick_tx(primary_dev, skb, NULL);
|
||||||
|
} else {
|
||||||
qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping;
|
txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0;
|
||||||
|
|
||||||
return txq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0;
|
|
||||||
|
|
||||||
/* Save the original txq to restore before passing to the driver */
|
/* Save the original txq to restore before passing to the driver */
|
||||||
qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping;
|
qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping;
|
||||||
|
|
||||||
|
|
|
@ -588,15 +588,13 @@ static int dp83869_of_init(struct phy_device *phydev)
|
||||||
&dp83869_internal_delay[0],
|
&dp83869_internal_delay[0],
|
||||||
delay_size, true);
|
delay_size, true);
|
||||||
if (dp83869->rx_int_delay < 0)
|
if (dp83869->rx_int_delay < 0)
|
||||||
dp83869->rx_int_delay =
|
dp83869->rx_int_delay = DP83869_CLK_DELAY_DEF;
|
||||||
dp83869_internal_delay[DP83869_CLK_DELAY_DEF];
|
|
||||||
|
|
||||||
dp83869->tx_int_delay = phy_get_internal_delay(phydev, dev,
|
dp83869->tx_int_delay = phy_get_internal_delay(phydev, dev,
|
||||||
&dp83869_internal_delay[0],
|
&dp83869_internal_delay[0],
|
||||||
delay_size, false);
|
delay_size, false);
|
||||||
if (dp83869->tx_int_delay < 0)
|
if (dp83869->tx_int_delay < 0)
|
||||||
dp83869->tx_int_delay =
|
dp83869->tx_int_delay = DP83869_CLK_DELAY_DEF;
|
||||||
dp83869_internal_delay[DP83869_CLK_DELAY_DEF];
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4151,6 +4151,7 @@ static struct phy_driver ksphy_driver[] = {
|
||||||
.resume = kszphy_resume,
|
.resume = kszphy_resume,
|
||||||
.cable_test_start = ksz9x31_cable_test_start,
|
.cable_test_start = ksz9x31_cable_test_start,
|
||||||
.cable_test_get_status = ksz9x31_cable_test_get_status,
|
.cable_test_get_status = ksz9x31_cable_test_get_status,
|
||||||
|
.get_features = ksz9477_get_features,
|
||||||
}, {
|
}, {
|
||||||
.phy_id = PHY_ID_KSZ8873MLL,
|
.phy_id = PHY_ID_KSZ8873MLL,
|
||||||
.phy_id_mask = MICREL_PHY_ID_MASK,
|
.phy_id_mask = MICREL_PHY_ID_MASK,
|
||||||
|
|
|
@ -3057,7 +3057,7 @@ EXPORT_SYMBOL_GPL(device_phy_find_device);
|
||||||
* and "phy-device" are not supported in ACPI. DT supports all the three
|
* and "phy-device" are not supported in ACPI. DT supports all the three
|
||||||
* named references to the phy node.
|
* named references to the phy node.
|
||||||
*/
|
*/
|
||||||
struct fwnode_handle *fwnode_get_phy_node(struct fwnode_handle *fwnode)
|
struct fwnode_handle *fwnode_get_phy_node(const struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
struct fwnode_handle *phy_node;
|
struct fwnode_handle *phy_node;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ struct sfp_bus {
|
||||||
/* private: */
|
/* private: */
|
||||||
struct kref kref;
|
struct kref kref;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
struct fwnode_handle *fwnode;
|
const struct fwnode_handle *fwnode;
|
||||||
|
|
||||||
const struct sfp_socket_ops *socket_ops;
|
const struct sfp_socket_ops *socket_ops;
|
||||||
struct device *sfp_dev;
|
struct device *sfp_dev;
|
||||||
|
@ -390,7 +390,7 @@ static const struct sfp_upstream_ops *sfp_get_upstream_ops(struct sfp_bus *bus)
|
||||||
return bus->registered ? bus->upstream_ops : NULL;
|
return bus->registered ? bus->upstream_ops : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sfp_bus *sfp_bus_get(struct fwnode_handle *fwnode)
|
static struct sfp_bus *sfp_bus_get(const struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
struct sfp_bus *sfp, *new, *found = NULL;
|
struct sfp_bus *sfp, *new, *found = NULL;
|
||||||
|
|
||||||
|
@ -593,7 +593,7 @@ static void sfp_upstream_clear(struct sfp_bus *bus)
|
||||||
* - %-ENOMEM if we failed to allocate the bus.
|
* - %-ENOMEM if we failed to allocate the bus.
|
||||||
* - an error from the upstream's connect_phy() method.
|
* - an error from the upstream's connect_phy() method.
|
||||||
*/
|
*/
|
||||||
struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
|
struct sfp_bus *sfp_bus_find_fwnode(const struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
struct fwnode_reference_args ref;
|
struct fwnode_reference_args ref;
|
||||||
struct sfp_bus *bus;
|
struct sfp_bus *bus;
|
||||||
|
|
|
@ -1688,7 +1688,9 @@ not_lro:
|
||||||
if (unlikely(rcd->ts))
|
if (unlikely(rcd->ts))
|
||||||
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rcd->tci);
|
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rcd->tci);
|
||||||
|
|
||||||
if (adapter->netdev->features & NETIF_F_LRO)
|
/* Use GRO callback if UPT is enabled */
|
||||||
|
if ((adapter->netdev->features & NETIF_F_LRO) &&
|
||||||
|
!rq->shared->updateRxProd)
|
||||||
netif_receive_skb(skb);
|
netif_receive_skb(skb);
|
||||||
else
|
else
|
||||||
napi_gro_receive(&rq->napi, skb);
|
napi_gro_receive(&rq->napi, skb);
|
||||||
|
|
|
@ -587,6 +587,13 @@ static void ipc_imem_run_state_worker(struct work_struct *instance)
|
||||||
while (ctrl_chl_idx < IPC_MEM_MAX_CHANNELS) {
|
while (ctrl_chl_idx < IPC_MEM_MAX_CHANNELS) {
|
||||||
if (!ipc_chnl_cfg_get(&chnl_cfg_port, ctrl_chl_idx)) {
|
if (!ipc_chnl_cfg_get(&chnl_cfg_port, ctrl_chl_idx)) {
|
||||||
ipc_imem->ipc_port[ctrl_chl_idx] = NULL;
|
ipc_imem->ipc_port[ctrl_chl_idx] = NULL;
|
||||||
|
|
||||||
|
if (ipc_imem->pcie->pci->device == INTEL_CP_DEVICE_7560_ID &&
|
||||||
|
chnl_cfg_port.wwan_port_type == WWAN_PORT_XMMRPC) {
|
||||||
|
ctrl_chl_idx++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (ipc_imem->pcie->pci->device == INTEL_CP_DEVICE_7360_ID &&
|
if (ipc_imem->pcie->pci->device == INTEL_CP_DEVICE_7360_ID &&
|
||||||
chnl_cfg_port.wwan_port_type == WWAN_PORT_MBIM) {
|
chnl_cfg_port.wwan_port_type == WWAN_PORT_MBIM) {
|
||||||
ctrl_chl_idx++;
|
ctrl_chl_idx++;
|
||||||
|
|
|
@ -166,7 +166,7 @@ struct xenvif_queue { /* Per-queue data for xenvif */
|
||||||
struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
|
struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
|
||||||
grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
|
grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
|
||||||
|
|
||||||
struct gnttab_copy tx_copy_ops[MAX_PENDING_REQS];
|
struct gnttab_copy tx_copy_ops[2 * MAX_PENDING_REQS];
|
||||||
struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
|
struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
|
||||||
struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
|
struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
|
||||||
/* passed to gnttab_[un]map_refs with pages under (un)mapping */
|
/* passed to gnttab_[un]map_refs with pages under (un)mapping */
|
||||||
|
|
|
@ -334,6 +334,7 @@ static int xenvif_count_requests(struct xenvif_queue *queue,
|
||||||
struct xenvif_tx_cb {
|
struct xenvif_tx_cb {
|
||||||
u16 copy_pending_idx[XEN_NETBK_LEGACY_SLOTS_MAX + 1];
|
u16 copy_pending_idx[XEN_NETBK_LEGACY_SLOTS_MAX + 1];
|
||||||
u8 copy_count;
|
u8 copy_count;
|
||||||
|
u32 split_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb)
|
#define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb)
|
||||||
|
@ -361,6 +362,8 @@ static inline struct sk_buff *xenvif_alloc_skb(unsigned int size)
|
||||||
struct sk_buff *skb =
|
struct sk_buff *skb =
|
||||||
alloc_skb(size + NET_SKB_PAD + NET_IP_ALIGN,
|
alloc_skb(size + NET_SKB_PAD + NET_IP_ALIGN,
|
||||||
GFP_ATOMIC | __GFP_NOWARN);
|
GFP_ATOMIC | __GFP_NOWARN);
|
||||||
|
|
||||||
|
BUILD_BUG_ON(sizeof(*XENVIF_TX_CB(skb)) > sizeof(skb->cb));
|
||||||
if (unlikely(skb == NULL))
|
if (unlikely(skb == NULL))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -396,11 +399,13 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
|
||||||
nr_slots = shinfo->nr_frags + 1;
|
nr_slots = shinfo->nr_frags + 1;
|
||||||
|
|
||||||
copy_count(skb) = 0;
|
copy_count(skb) = 0;
|
||||||
|
XENVIF_TX_CB(skb)->split_mask = 0;
|
||||||
|
|
||||||
/* Create copy ops for exactly data_len bytes into the skb head. */
|
/* Create copy ops for exactly data_len bytes into the skb head. */
|
||||||
__skb_put(skb, data_len);
|
__skb_put(skb, data_len);
|
||||||
while (data_len > 0) {
|
while (data_len > 0) {
|
||||||
int amount = data_len > txp->size ? txp->size : data_len;
|
int amount = data_len > txp->size ? txp->size : data_len;
|
||||||
|
bool split = false;
|
||||||
|
|
||||||
cop->source.u.ref = txp->gref;
|
cop->source.u.ref = txp->gref;
|
||||||
cop->source.domid = queue->vif->domid;
|
cop->source.domid = queue->vif->domid;
|
||||||
|
@ -413,6 +418,13 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
|
||||||
cop->dest.u.gmfn = virt_to_gfn(skb->data + skb_headlen(skb)
|
cop->dest.u.gmfn = virt_to_gfn(skb->data + skb_headlen(skb)
|
||||||
- data_len);
|
- data_len);
|
||||||
|
|
||||||
|
/* Don't cross local page boundary! */
|
||||||
|
if (cop->dest.offset + amount > XEN_PAGE_SIZE) {
|
||||||
|
amount = XEN_PAGE_SIZE - cop->dest.offset;
|
||||||
|
XENVIF_TX_CB(skb)->split_mask |= 1U << copy_count(skb);
|
||||||
|
split = true;
|
||||||
|
}
|
||||||
|
|
||||||
cop->len = amount;
|
cop->len = amount;
|
||||||
cop->flags = GNTCOPY_source_gref;
|
cop->flags = GNTCOPY_source_gref;
|
||||||
|
|
||||||
|
@ -420,7 +432,8 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
|
||||||
pending_idx = queue->pending_ring[index];
|
pending_idx = queue->pending_ring[index];
|
||||||
callback_param(queue, pending_idx).ctx = NULL;
|
callback_param(queue, pending_idx).ctx = NULL;
|
||||||
copy_pending_idx(skb, copy_count(skb)) = pending_idx;
|
copy_pending_idx(skb, copy_count(skb)) = pending_idx;
|
||||||
copy_count(skb)++;
|
if (!split)
|
||||||
|
copy_count(skb)++;
|
||||||
|
|
||||||
cop++;
|
cop++;
|
||||||
data_len -= amount;
|
data_len -= amount;
|
||||||
|
@ -441,7 +454,8 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
|
||||||
nr_slots--;
|
nr_slots--;
|
||||||
} else {
|
} else {
|
||||||
/* The copy op partially covered the tx_request.
|
/* The copy op partially covered the tx_request.
|
||||||
* The remainder will be mapped.
|
* The remainder will be mapped or copied in the next
|
||||||
|
* iteration.
|
||||||
*/
|
*/
|
||||||
txp->offset += amount;
|
txp->offset += amount;
|
||||||
txp->size -= amount;
|
txp->size -= amount;
|
||||||
|
@ -539,6 +553,13 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue,
|
||||||
pending_idx = copy_pending_idx(skb, i);
|
pending_idx = copy_pending_idx(skb, i);
|
||||||
|
|
||||||
newerr = (*gopp_copy)->status;
|
newerr = (*gopp_copy)->status;
|
||||||
|
|
||||||
|
/* Split copies need to be handled together. */
|
||||||
|
if (XENVIF_TX_CB(skb)->split_mask & (1U << i)) {
|
||||||
|
(*gopp_copy)++;
|
||||||
|
if (!newerr)
|
||||||
|
newerr = (*gopp_copy)->status;
|
||||||
|
}
|
||||||
if (likely(!newerr)) {
|
if (likely(!newerr)) {
|
||||||
/* The first frag might still have this slot mapped */
|
/* The first frag might still have this slot mapped */
|
||||||
if (i < copy_count(skb) - 1 || !sharedslot)
|
if (i < copy_count(skb) - 1 || !sharedslot)
|
||||||
|
@ -973,10 +994,8 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
|
||||||
|
|
||||||
/* No crossing a page as the payload mustn't fragment. */
|
/* No crossing a page as the payload mustn't fragment. */
|
||||||
if (unlikely((txreq.offset + txreq.size) > XEN_PAGE_SIZE)) {
|
if (unlikely((txreq.offset + txreq.size) > XEN_PAGE_SIZE)) {
|
||||||
netdev_err(queue->vif->dev,
|
netdev_err(queue->vif->dev, "Cross page boundary, txreq.offset: %u, size: %u\n",
|
||||||
"txreq.offset: %u, size: %u, end: %lu\n",
|
txreq.offset, txreq.size);
|
||||||
txreq.offset, txreq.size,
|
|
||||||
(unsigned long)(txreq.offset&~XEN_PAGE_MASK) + txreq.size);
|
|
||||||
xenvif_fatal_tx_err(queue->vif);
|
xenvif_fatal_tx_err(queue->vif);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1061,10 +1080,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
|
||||||
__skb_queue_tail(&queue->tx_queue, skb);
|
__skb_queue_tail(&queue->tx_queue, skb);
|
||||||
|
|
||||||
queue->tx.req_cons = idx;
|
queue->tx.req_cons = idx;
|
||||||
|
|
||||||
if ((*map_ops >= ARRAY_SIZE(queue->tx_map_ops)) ||
|
|
||||||
(*copy_ops >= ARRAY_SIZE(queue->tx_copy_ops)))
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -637,7 +637,7 @@ static int ptp_qoriq_probe(struct platform_device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
no_clock:
|
no_clock:
|
||||||
iounmap(ptp_qoriq->base);
|
iounmap(base);
|
||||||
no_ioremap:
|
no_ioremap:
|
||||||
release_resource(ptp_qoriq->rsrc);
|
release_resource(ptp_qoriq->rsrc);
|
||||||
no_resource:
|
no_resource:
|
||||||
|
|
|
@ -1547,7 +1547,7 @@ int fwnode_get_phy_id(struct fwnode_handle *fwnode, u32 *phy_id);
|
||||||
struct mdio_device *fwnode_mdio_find_device(struct fwnode_handle *fwnode);
|
struct mdio_device *fwnode_mdio_find_device(struct fwnode_handle *fwnode);
|
||||||
struct phy_device *fwnode_phy_find_device(struct fwnode_handle *phy_fwnode);
|
struct phy_device *fwnode_phy_find_device(struct fwnode_handle *phy_fwnode);
|
||||||
struct phy_device *device_phy_find_device(struct device *dev);
|
struct phy_device *device_phy_find_device(struct device *dev);
|
||||||
struct fwnode_handle *fwnode_get_phy_node(struct fwnode_handle *fwnode);
|
struct fwnode_handle *fwnode_get_phy_node(const struct fwnode_handle *fwnode);
|
||||||
struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45);
|
struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45);
|
||||||
int phy_device_register(struct phy_device *phy);
|
int phy_device_register(struct phy_device *phy);
|
||||||
void phy_device_free(struct phy_device *phydev);
|
void phy_device_free(struct phy_device *phydev);
|
||||||
|
|
|
@ -557,7 +557,7 @@ int sfp_get_module_eeprom_by_page(struct sfp_bus *bus,
|
||||||
void sfp_upstream_start(struct sfp_bus *bus);
|
void sfp_upstream_start(struct sfp_bus *bus);
|
||||||
void sfp_upstream_stop(struct sfp_bus *bus);
|
void sfp_upstream_stop(struct sfp_bus *bus);
|
||||||
void sfp_bus_put(struct sfp_bus *bus);
|
void sfp_bus_put(struct sfp_bus *bus);
|
||||||
struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode);
|
struct sfp_bus *sfp_bus_find_fwnode(const struct fwnode_handle *fwnode);
|
||||||
int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
|
int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
|
||||||
const struct sfp_upstream_ops *ops);
|
const struct sfp_upstream_ops *ops);
|
||||||
void sfp_bus_del_upstream(struct sfp_bus *bus);
|
void sfp_bus_del_upstream(struct sfp_bus *bus);
|
||||||
|
@ -619,7 +619,8 @@ static inline void sfp_bus_put(struct sfp_bus *bus)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
|
static inline struct sfp_bus *
|
||||||
|
sfp_bus_find_fwnode(const struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -941,6 +941,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
||||||
|
|
||||||
cf = op->frames + op->cfsiz * i;
|
cf = op->frames + op->cfsiz * i;
|
||||||
err = memcpy_from_msg((u8 *)cf, msg, op->cfsiz);
|
err = memcpy_from_msg((u8 *)cf, msg, op->cfsiz);
|
||||||
|
if (err < 0)
|
||||||
|
goto free_op;
|
||||||
|
|
||||||
if (op->flags & CAN_FD_FRAME) {
|
if (op->flags & CAN_FD_FRAME) {
|
||||||
if (cf->len > 64)
|
if (cf->len > 64)
|
||||||
|
@ -950,12 +952,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
if (op->frames != &op->sframe)
|
goto free_op;
|
||||||
kfree(op->frames);
|
|
||||||
kfree(op);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg_head->flags & TX_CP_CAN_ID) {
|
if (msg_head->flags & TX_CP_CAN_ID) {
|
||||||
/* copy can_id into frame */
|
/* copy can_id into frame */
|
||||||
|
@ -1026,6 +1024,12 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
||||||
bcm_tx_start_timer(op);
|
bcm_tx_start_timer(op);
|
||||||
|
|
||||||
return msg_head->nframes * op->cfsiz + MHSIZ;
|
return msg_head->nframes * op->cfsiz + MHSIZ;
|
||||||
|
|
||||||
|
free_op:
|
||||||
|
if (op->frames != &op->sframe)
|
||||||
|
kfree(op->frames);
|
||||||
|
kfree(op);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1124,8 +1124,6 @@ static void __j1939_session_cancel(struct j1939_session *session,
|
||||||
|
|
||||||
if (session->sk)
|
if (session->sk)
|
||||||
j1939_sk_send_loop_abort(session->sk, session->err);
|
j1939_sk_send_loop_abort(session->sk, session->err);
|
||||||
else
|
|
||||||
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void j1939_session_cancel(struct j1939_session *session,
|
static void j1939_session_cancel(struct j1939_session *session,
|
||||||
|
@ -1140,6 +1138,9 @@ static void j1939_session_cancel(struct j1939_session *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
j1939_session_list_unlock(session->priv);
|
j1939_session_list_unlock(session->priv);
|
||||||
|
|
||||||
|
if (!session->sk)
|
||||||
|
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum hrtimer_restart j1939_tp_txtimer(struct hrtimer *hrtimer)
|
static enum hrtimer_restart j1939_tp_txtimer(struct hrtimer *hrtimer)
|
||||||
|
@ -1253,6 +1254,9 @@ static enum hrtimer_restart j1939_tp_rxtimer(struct hrtimer *hrtimer)
|
||||||
__j1939_session_cancel(session, J1939_XTP_ABORT_TIMEOUT);
|
__j1939_session_cancel(session, J1939_XTP_ABORT_TIMEOUT);
|
||||||
}
|
}
|
||||||
j1939_session_list_unlock(session->priv);
|
j1939_session_list_unlock(session->priv);
|
||||||
|
|
||||||
|
if (!session->sk)
|
||||||
|
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
j1939_session_put(session);
|
j1939_session_put(session);
|
||||||
|
|
121
net/dsa/slave.c
121
net/dsa/slave.c
|
@ -57,6 +57,12 @@ struct dsa_standalone_event_work {
|
||||||
u16 vid;
|
u16 vid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dsa_host_vlan_rx_filtering_ctx {
|
||||||
|
struct net_device *dev;
|
||||||
|
const unsigned char *addr;
|
||||||
|
enum dsa_standalone_event event;
|
||||||
|
};
|
||||||
|
|
||||||
static bool dsa_switch_supports_uc_filtering(struct dsa_switch *ds)
|
static bool dsa_switch_supports_uc_filtering(struct dsa_switch *ds)
|
||||||
{
|
{
|
||||||
return ds->ops->port_fdb_add && ds->ops->port_fdb_del &&
|
return ds->ops->port_fdb_add && ds->ops->port_fdb_del &&
|
||||||
|
@ -155,18 +161,37 @@ static int dsa_slave_schedule_standalone_work(struct net_device *dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dsa_slave_host_vlan_rx_filtering(struct net_device *vdev, int vid,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
struct dsa_host_vlan_rx_filtering_ctx *ctx = arg;
|
||||||
|
|
||||||
|
return dsa_slave_schedule_standalone_work(ctx->dev, ctx->event,
|
||||||
|
ctx->addr, vid);
|
||||||
|
}
|
||||||
|
|
||||||
static int dsa_slave_sync_uc(struct net_device *dev,
|
static int dsa_slave_sync_uc(struct net_device *dev,
|
||||||
const unsigned char *addr)
|
const unsigned char *addr)
|
||||||
{
|
{
|
||||||
struct net_device *master = dsa_slave_to_master(dev);
|
struct net_device *master = dsa_slave_to_master(dev);
|
||||||
struct dsa_port *dp = dsa_slave_to_port(dev);
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
||||||
|
struct dsa_host_vlan_rx_filtering_ctx ctx = {
|
||||||
|
.dev = dev,
|
||||||
|
.addr = addr,
|
||||||
|
.event = DSA_UC_ADD,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
dev_uc_add(master, addr);
|
dev_uc_add(master, addr);
|
||||||
|
|
||||||
if (!dsa_switch_supports_uc_filtering(dp->ds))
|
if (!dsa_switch_supports_uc_filtering(dp->ds))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return dsa_slave_schedule_standalone_work(dev, DSA_UC_ADD, addr, 0);
|
err = dsa_slave_schedule_standalone_work(dev, DSA_UC_ADD, addr, 0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, &ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dsa_slave_unsync_uc(struct net_device *dev,
|
static int dsa_slave_unsync_uc(struct net_device *dev,
|
||||||
|
@ -174,13 +199,23 @@ static int dsa_slave_unsync_uc(struct net_device *dev,
|
||||||
{
|
{
|
||||||
struct net_device *master = dsa_slave_to_master(dev);
|
struct net_device *master = dsa_slave_to_master(dev);
|
||||||
struct dsa_port *dp = dsa_slave_to_port(dev);
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
||||||
|
struct dsa_host_vlan_rx_filtering_ctx ctx = {
|
||||||
|
.dev = dev,
|
||||||
|
.addr = addr,
|
||||||
|
.event = DSA_UC_DEL,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
dev_uc_del(master, addr);
|
dev_uc_del(master, addr);
|
||||||
|
|
||||||
if (!dsa_switch_supports_uc_filtering(dp->ds))
|
if (!dsa_switch_supports_uc_filtering(dp->ds))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return dsa_slave_schedule_standalone_work(dev, DSA_UC_DEL, addr, 0);
|
err = dsa_slave_schedule_standalone_work(dev, DSA_UC_DEL, addr, 0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, &ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dsa_slave_sync_mc(struct net_device *dev,
|
static int dsa_slave_sync_mc(struct net_device *dev,
|
||||||
|
@ -188,13 +223,23 @@ static int dsa_slave_sync_mc(struct net_device *dev,
|
||||||
{
|
{
|
||||||
struct net_device *master = dsa_slave_to_master(dev);
|
struct net_device *master = dsa_slave_to_master(dev);
|
||||||
struct dsa_port *dp = dsa_slave_to_port(dev);
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
||||||
|
struct dsa_host_vlan_rx_filtering_ctx ctx = {
|
||||||
|
.dev = dev,
|
||||||
|
.addr = addr,
|
||||||
|
.event = DSA_MC_ADD,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
dev_mc_add(master, addr);
|
dev_mc_add(master, addr);
|
||||||
|
|
||||||
if (!dsa_switch_supports_mc_filtering(dp->ds))
|
if (!dsa_switch_supports_mc_filtering(dp->ds))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return dsa_slave_schedule_standalone_work(dev, DSA_MC_ADD, addr, 0);
|
err = dsa_slave_schedule_standalone_work(dev, DSA_MC_ADD, addr, 0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, &ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dsa_slave_unsync_mc(struct net_device *dev,
|
static int dsa_slave_unsync_mc(struct net_device *dev,
|
||||||
|
@ -202,13 +247,23 @@ static int dsa_slave_unsync_mc(struct net_device *dev,
|
||||||
{
|
{
|
||||||
struct net_device *master = dsa_slave_to_master(dev);
|
struct net_device *master = dsa_slave_to_master(dev);
|
||||||
struct dsa_port *dp = dsa_slave_to_port(dev);
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
||||||
|
struct dsa_host_vlan_rx_filtering_ctx ctx = {
|
||||||
|
.dev = dev,
|
||||||
|
.addr = addr,
|
||||||
|
.event = DSA_MC_DEL,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
dev_mc_del(master, addr);
|
dev_mc_del(master, addr);
|
||||||
|
|
||||||
if (!dsa_switch_supports_mc_filtering(dp->ds))
|
if (!dsa_switch_supports_mc_filtering(dp->ds))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return dsa_slave_schedule_standalone_work(dev, DSA_MC_DEL, addr, 0);
|
err = dsa_slave_schedule_standalone_work(dev, DSA_MC_DEL, addr, 0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, &ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsa_slave_sync_ha(struct net_device *dev)
|
void dsa_slave_sync_ha(struct net_device *dev)
|
||||||
|
@ -1702,6 +1757,8 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
struct netlink_ext_ack extack = {0};
|
struct netlink_ext_ack extack = {0};
|
||||||
|
struct dsa_switch *ds = dp->ds;
|
||||||
|
struct netdev_hw_addr *ha;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* User port... */
|
/* User port... */
|
||||||
|
@ -1721,6 +1778,30 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!dsa_switch_supports_uc_filtering(ds) &&
|
||||||
|
!dsa_switch_supports_mc_filtering(ds))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
netif_addr_lock_bh(dev);
|
||||||
|
|
||||||
|
if (dsa_switch_supports_mc_filtering(ds)) {
|
||||||
|
netdev_for_each_synced_mc_addr(ha, dev) {
|
||||||
|
dsa_slave_schedule_standalone_work(dev, DSA_MC_ADD,
|
||||||
|
ha->addr, vid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dsa_switch_supports_uc_filtering(ds)) {
|
||||||
|
netdev_for_each_synced_uc_addr(ha, dev) {
|
||||||
|
dsa_slave_schedule_standalone_work(dev, DSA_UC_ADD,
|
||||||
|
ha->addr, vid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
netif_addr_unlock_bh(dev);
|
||||||
|
|
||||||
|
dsa_flush_workqueue();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1733,13 +1814,43 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
|
||||||
/* This API only allows programming tagged, non-PVID VIDs */
|
/* This API only allows programming tagged, non-PVID VIDs */
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
|
struct dsa_switch *ds = dp->ds;
|
||||||
|
struct netdev_hw_addr *ha;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = dsa_port_vlan_del(dp, &vlan);
|
err = dsa_port_vlan_del(dp, &vlan);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
return dsa_port_host_vlan_del(dp, &vlan);
|
err = dsa_port_host_vlan_del(dp, &vlan);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (!dsa_switch_supports_uc_filtering(ds) &&
|
||||||
|
!dsa_switch_supports_mc_filtering(ds))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
netif_addr_lock_bh(dev);
|
||||||
|
|
||||||
|
if (dsa_switch_supports_mc_filtering(ds)) {
|
||||||
|
netdev_for_each_synced_mc_addr(ha, dev) {
|
||||||
|
dsa_slave_schedule_standalone_work(dev, DSA_MC_DEL,
|
||||||
|
ha->addr, vid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dsa_switch_supports_uc_filtering(ds)) {
|
||||||
|
netdev_for_each_synced_uc_addr(ha, dev) {
|
||||||
|
dsa_slave_schedule_standalone_work(dev, DSA_UC_DEL,
|
||||||
|
ha->addr, vid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
netif_addr_unlock_bh(dev);
|
||||||
|
|
||||||
|
dsa_flush_workqueue();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dsa_slave_restore_vlan(struct net_device *vdev, int vid, void *arg)
|
static int dsa_slave_restore_vlan(struct net_device *vdev, int vid, void *arg)
|
||||||
|
|
|
@ -2488,8 +2488,7 @@ static int nl802154_del_llsec_seclevel(struct sk_buff *skb,
|
||||||
if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
|
if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
if (!info->attrs[NL802154_ATTR_SEC_LEVEL] ||
|
if (llsec_parse_seclevel(info->attrs[NL802154_ATTR_SEC_LEVEL],
|
||||||
llsec_parse_seclevel(info->attrs[NL802154_ATTR_SEC_LEVEL],
|
|
||||||
&sl) < 0)
|
&sl) < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
|
|
@ -363,6 +363,13 @@ virtio_transport_stream_do_dequeue(struct vsock_sock *vsk,
|
||||||
u32 free_space;
|
u32 free_space;
|
||||||
|
|
||||||
spin_lock_bh(&vvs->rx_lock);
|
spin_lock_bh(&vvs->rx_lock);
|
||||||
|
|
||||||
|
if (WARN_ONCE(skb_queue_empty(&vvs->rx_queue) && vvs->rx_bytes,
|
||||||
|
"rx_queue is empty, but rx_bytes is non-zero\n")) {
|
||||||
|
spin_unlock_bh(&vvs->rx_lock);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
while (total < len && !skb_queue_empty(&vvs->rx_queue)) {
|
while (total < len && !skb_queue_empty(&vvs->rx_queue)) {
|
||||||
skb = skb_peek(&vvs->rx_queue);
|
skb = skb_peek(&vvs->rx_queue);
|
||||||
|
|
||||||
|
@ -1068,7 +1075,7 @@ virtio_transport_recv_enqueue(struct vsock_sock *vsk,
|
||||||
memcpy(skb_put(last_skb, skb->len), skb->data, skb->len);
|
memcpy(skb_put(last_skb, skb->len), skb->data, skb->len);
|
||||||
free_pkt = true;
|
free_pkt = true;
|
||||||
last_hdr->flags |= hdr->flags;
|
last_hdr->flags |= hdr->flags;
|
||||||
last_hdr->len = cpu_to_le32(last_skb->len);
|
le32_add_cpu(&last_hdr->len, len);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
struct vsock_loopback {
|
struct vsock_loopback {
|
||||||
struct workqueue_struct *workqueue;
|
struct workqueue_struct *workqueue;
|
||||||
|
|
||||||
spinlock_t pkt_list_lock; /* protects pkt_list */
|
|
||||||
struct sk_buff_head pkt_queue;
|
struct sk_buff_head pkt_queue;
|
||||||
struct work_struct pkt_work;
|
struct work_struct pkt_work;
|
||||||
};
|
};
|
||||||
|
@ -32,9 +31,7 @@ static int vsock_loopback_send_pkt(struct sk_buff *skb)
|
||||||
struct vsock_loopback *vsock = &the_vsock_loopback;
|
struct vsock_loopback *vsock = &the_vsock_loopback;
|
||||||
int len = skb->len;
|
int len = skb->len;
|
||||||
|
|
||||||
spin_lock_bh(&vsock->pkt_list_lock);
|
|
||||||
skb_queue_tail(&vsock->pkt_queue, skb);
|
skb_queue_tail(&vsock->pkt_queue, skb);
|
||||||
spin_unlock_bh(&vsock->pkt_list_lock);
|
|
||||||
|
|
||||||
queue_work(vsock->workqueue, &vsock->pkt_work);
|
queue_work(vsock->workqueue, &vsock->pkt_work);
|
||||||
|
|
||||||
|
@ -113,9 +110,9 @@ static void vsock_loopback_work(struct work_struct *work)
|
||||||
|
|
||||||
skb_queue_head_init(&pkts);
|
skb_queue_head_init(&pkts);
|
||||||
|
|
||||||
spin_lock_bh(&vsock->pkt_list_lock);
|
spin_lock_bh(&vsock->pkt_queue.lock);
|
||||||
skb_queue_splice_init(&vsock->pkt_queue, &pkts);
|
skb_queue_splice_init(&vsock->pkt_queue, &pkts);
|
||||||
spin_unlock_bh(&vsock->pkt_list_lock);
|
spin_unlock_bh(&vsock->pkt_queue.lock);
|
||||||
|
|
||||||
while ((skb = __skb_dequeue(&pkts))) {
|
while ((skb = __skb_dequeue(&pkts))) {
|
||||||
virtio_transport_deliver_tap_pkt(skb);
|
virtio_transport_deliver_tap_pkt(skb);
|
||||||
|
@ -132,7 +129,6 @@ static int __init vsock_loopback_init(void)
|
||||||
if (!vsock->workqueue)
|
if (!vsock->workqueue)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock_init(&vsock->pkt_list_lock);
|
|
||||||
skb_queue_head_init(&vsock->pkt_queue);
|
skb_queue_head_init(&vsock->pkt_queue);
|
||||||
INIT_WORK(&vsock->pkt_work, vsock_loopback_work);
|
INIT_WORK(&vsock->pkt_work, vsock_loopback_work);
|
||||||
|
|
||||||
|
@ -156,9 +152,7 @@ static void __exit vsock_loopback_exit(void)
|
||||||
|
|
||||||
flush_work(&vsock->pkt_work);
|
flush_work(&vsock->pkt_work);
|
||||||
|
|
||||||
spin_lock_bh(&vsock->pkt_list_lock);
|
|
||||||
virtio_vsock_skb_queue_purge(&vsock->pkt_queue);
|
virtio_vsock_skb_queue_purge(&vsock->pkt_queue);
|
||||||
spin_unlock_bh(&vsock->pkt_list_lock);
|
|
||||||
|
|
||||||
destroy_workqueue(vsock->workqueue);
|
destroy_workqueue(vsock->workqueue);
|
||||||
}
|
}
|
||||||
|
|
|
@ -968,6 +968,91 @@ static void test_seqpacket_inv_buf_server(const struct test_opts *opts)
|
||||||
test_inv_buf_server(opts, false);
|
test_inv_buf_server(opts, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HELLO_STR "HELLO"
|
||||||
|
#define WORLD_STR "WORLD"
|
||||||
|
|
||||||
|
static void test_stream_virtio_skb_merge_client(const struct test_opts *opts)
|
||||||
|
{
|
||||||
|
ssize_t res;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = vsock_stream_connect(opts->peer_cid, 1234);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("connect");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send first skbuff. */
|
||||||
|
res = send(fd, HELLO_STR, strlen(HELLO_STR), 0);
|
||||||
|
if (res != strlen(HELLO_STR)) {
|
||||||
|
fprintf(stderr, "unexpected send(2) result %zi\n", res);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
control_writeln("SEND0");
|
||||||
|
/* Peer reads part of first skbuff. */
|
||||||
|
control_expectln("REPLY0");
|
||||||
|
|
||||||
|
/* Send second skbuff, it will be appended to the first. */
|
||||||
|
res = send(fd, WORLD_STR, strlen(WORLD_STR), 0);
|
||||||
|
if (res != strlen(WORLD_STR)) {
|
||||||
|
fprintf(stderr, "unexpected send(2) result %zi\n", res);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
control_writeln("SEND1");
|
||||||
|
/* Peer reads merged skbuff packet. */
|
||||||
|
control_expectln("REPLY1");
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_stream_virtio_skb_merge_server(const struct test_opts *opts)
|
||||||
|
{
|
||||||
|
unsigned char buf[64];
|
||||||
|
ssize_t res;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("accept");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
control_expectln("SEND0");
|
||||||
|
|
||||||
|
/* Read skbuff partially. */
|
||||||
|
res = recv(fd, buf, 2, 0);
|
||||||
|
if (res != 2) {
|
||||||
|
fprintf(stderr, "expected recv(2) returns 2 bytes, got %zi\n", res);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
control_writeln("REPLY0");
|
||||||
|
control_expectln("SEND1");
|
||||||
|
|
||||||
|
res = recv(fd, buf + 2, sizeof(buf) - 2, 0);
|
||||||
|
if (res != 8) {
|
||||||
|
fprintf(stderr, "expected recv(2) returns 8 bytes, got %zi\n", res);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = recv(fd, buf, sizeof(buf) - 8 - 2, MSG_DONTWAIT);
|
||||||
|
if (res != -1) {
|
||||||
|
fprintf(stderr, "expected recv(2) failure, got %zi\n", res);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(buf, HELLO_STR WORLD_STR, strlen(HELLO_STR WORLD_STR))) {
|
||||||
|
fprintf(stderr, "pattern mismatch\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
control_writeln("REPLY1");
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
static struct test_case test_cases[] = {
|
static struct test_case test_cases[] = {
|
||||||
{
|
{
|
||||||
.name = "SOCK_STREAM connection reset",
|
.name = "SOCK_STREAM connection reset",
|
||||||
|
@ -1038,6 +1123,11 @@ static struct test_case test_cases[] = {
|
||||||
.run_client = test_seqpacket_inv_buf_client,
|
.run_client = test_seqpacket_inv_buf_client,
|
||||||
.run_server = test_seqpacket_inv_buf_server,
|
.run_server = test_seqpacket_inv_buf_server,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "SOCK_STREAM virtio skb merge",
|
||||||
|
.run_client = test_stream_virtio_skb_merge_client,
|
||||||
|
.run_server = test_stream_virtio_skb_merge_server,
|
||||||
|
},
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue