mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
Including fixes from wireless. The ath12k fix to avoid FW crashes
requires adding support for a number of new FW commands so it's quite large in terms of LoC. The rest is relatively small. Current release - fix to a fix: - ptp: fix breakage after ptp_vclock_in_use() rework Current release - regressions: - openvswitch: allocate struct ovs_pcpu_storage dynamically, static allocation may exhaust module loader limit on smaller systems Previous releases - regressions: - tcp: fix tcp_packet_delayed() for peers with no selective ACK support Previous releases - always broken: - wifi: ath12k: don't activate more links than firmware supports - tcp: make sure sockets open via passive TFO have valid NAPI ID - eth: bnxt_en: update MRU and RSS table of RSS contexts on queue reset, prevent Rx queues from silently hanging after queue reset - NFC: uart: set tty->disc_data only in success path Signed-off-by: Jakub Kicinski <kuba@kernel.org> -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE6jPA+I1ugmIBA4hXMUZtbf5SIrsFAmhUPLgACgkQMUZtbf5S IrvrXxAAvREuPy2BhCrQW77TeVW2ikBlGYYp+dCIL4r4kfqquHU3C+R/GZ5yRbcA fiRMkRv7J4xhHOT8AnFmFiWGz6QEJfESy3jSQUfcLssHeandEjJbcZ0qVunEpE4e rt0leygfY+axEP3ewoGQEP7Ds2Ku+L3BrIetwsUZPFo9pVAtGJ4XOV56SRYPP7vL 7toaHcxXtx5vL9Wlb9vulom9kfZU4/hfDMS9/FES+aE4QnRDB+sh0v6wL4pocLrj 7swSqWCY7vjd7vJck4Ta/O9+bL6kz1wG4Qvv5enXGJlksiBgCpShfbzGMZTbegeP 8gCj4heAATCRmzCmfkRk5sWzPqedtLI5rzb7jUYYF4wiZpJwjwLzrDxopazFogXs kKDCD3lxDmUTV4AkT/5hn8Rlf4CApMrhPs+zhzQQ620Sj/G3k2lyepKmKjOUSAZ4 fEFKmP9Mzt3fKt2sOi5ETlrpuiSv5CCAZfnCg7UoBXrQM1Rxyn+utLMeGM6oHXRa iH9GwVN2cycEXl16y8HVCui8lzBYyZKVbyiRBM6k3Pl6ZozDuHvCRmHgs8g9pTja 3hGe2wjYcsi+HKrF1zDQrTJbhKzsNMpJej0KIZ06xjyXAgr1VV0noEq/iQsPEj4z 033DotqhyoFXc6ERmOaca8LfE2kHolwT+0leO+i0sbdmVlSFxB8= =2mAa -----END PGP SIGNATURE----- Merge tag 'net-6.16-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net Pull networking fixes from Jakub Kicinski: "Including fixes from wireless. The ath12k fix to avoid FW crashes requires adding support for a number of new FW commands so it's quite large in terms of LoC. The rest is relatively small. Current release - fix to a fix: - ptp: fix breakage after ptp_vclock_in_use() rework Current release - regressions: - openvswitch: allocate struct ovs_pcpu_storage dynamically, static allocation may exhaust module loader limit on smaller systems Previous releases - regressions: - tcp: fix tcp_packet_delayed() for peers with no selective ACK support Previous releases - always broken: - wifi: ath12k: don't activate more links than firmware supports - tcp: make sure sockets open via passive TFO have valid NAPI ID - eth: bnxt_en: update MRU and RSS table of RSS contexts on queue reset, prevent Rx queues from silently hanging after queue reset - NFC: uart: set tty->disc_data only in success path" * tag 'net-6.16-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (59 commits) net: airoha: Differentiate hwfd buffer size for QDMA0 and QDMA1 net: airoha: Compute number of descriptors according to reserved memory size tools: ynl: fix mixing ops and notifications on one socket net: atm: fix /proc/net/atm/lec handling net: atm: add lec_mutex mlxbf_gige: return EPROBE_DEFER if PHY IRQ is not available net: airoha: Always check return value from airoha_ppe_foe_get_entry() NFC: nci: uart: Set tty->disc_data only in success path calipso: Fix null-ptr-deref in calipso_req_{set,del}attr(). MAINTAINERS: Remove Shannon Nelson from MAINTAINERS file net: lan743x: fix potential out-of-bounds write in lan743x_ptp_io_event_clock_get() eth: fbnic: avoid double free when failing to DMA-map FW msg tcp: fix passive TFO socket having invalid NAPI ID selftests: net: add test for passive TFO socket NAPI ID selftests: net: add passive TFO test binary selftests: netdevsim: improve lib.sh include in peer.sh tipc: fix null-ptr-deref when acquiring remote ip of ethernet bearer Octeontx2-pf: Fix Backpresure configuration net: ftgmac100: select FIXED_PHY net: ethtool: remove duplicate defines for family info ...
This commit is contained in:
commit
5c8013ae2e
7
.mailmap
7
.mailmap
@ -693,9 +693,10 @@ Serge Hallyn <sergeh@kernel.org> <serge.hallyn@canonical.com>
|
||||
Serge Hallyn <sergeh@kernel.org> <serue@us.ibm.com>
|
||||
Seth Forshee <sforshee@kernel.org> <seth.forshee@canonical.com>
|
||||
Shakeel Butt <shakeel.butt@linux.dev> <shakeelb@google.com>
|
||||
Shannon Nelson <shannon.nelson@amd.com> <snelson@pensando.io>
|
||||
Shannon Nelson <shannon.nelson@amd.com> <shannon.nelson@intel.com>
|
||||
Shannon Nelson <shannon.nelson@amd.com> <shannon.nelson@oracle.com>
|
||||
Shannon Nelson <sln@onemain.com> <shannon.nelson@amd.com>
|
||||
Shannon Nelson <sln@onemain.com> <snelson@pensando.io>
|
||||
Shannon Nelson <sln@onemain.com> <shannon.nelson@intel.com>
|
||||
Shannon Nelson <sln@onemain.com> <shannon.nelson@oracle.com>
|
||||
Sharath Chandra Vurukala <quic_sharathv@quicinc.com> <sharathv@codeaurora.org>
|
||||
Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
|
||||
Shuah Khan <shuah@kernel.org> <shuahkhan@gmail.com>
|
||||
|
@ -7,6 +7,9 @@ protocol: genetlink-legacy
|
||||
doc: Partial family for Ethtool Netlink.
|
||||
uapi-header: linux/ethtool_netlink_generated.h
|
||||
|
||||
c-family-name: ethtool-genl-name
|
||||
c-version-name: ethtool-genl-version
|
||||
|
||||
definitions:
|
||||
-
|
||||
name: udp-tunnel-type
|
||||
|
@ -1157,7 +1157,6 @@ F: arch/x86/include/asm/amd/node.h
|
||||
F: arch/x86/kernel/amd_node.c
|
||||
|
||||
AMD PDS CORE DRIVER
|
||||
M: Shannon Nelson <shannon.nelson@amd.com>
|
||||
M: Brett Creeley <brett.creeley@amd.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
@ -9942,7 +9941,6 @@ F: drivers/fwctl/mlx5/
|
||||
|
||||
FWCTL PDS DRIVER
|
||||
M: Brett Creeley <brett.creeley@amd.com>
|
||||
R: Shannon Nelson <shannon.nelson@amd.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/fwctl/pds/
|
||||
@ -19379,7 +19377,7 @@ F: crypto/pcrypt.c
|
||||
F: include/crypto/pcrypt.h
|
||||
|
||||
PDS DSC VIRTIO DATA PATH ACCELERATOR
|
||||
R: Shannon Nelson <shannon.nelson@amd.com>
|
||||
R: Brett Creeley <brett.creeley@amd.com>
|
||||
F: drivers/vdpa/pds/
|
||||
|
||||
PECI HARDWARE MONITORING DRIVERS
|
||||
@ -19401,7 +19399,6 @@ F: include/linux/peci-cpu.h
|
||||
F: include/linux/peci.h
|
||||
|
||||
PENSANDO ETHERNET DRIVERS
|
||||
M: Shannon Nelson <shannon.nelson@amd.com>
|
||||
M: Brett Creeley <brett.creeley@amd.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
|
@ -288,7 +288,9 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
|
||||
struct sk_buff *new_skb;
|
||||
int result = 0;
|
||||
|
||||
if (!skb->len) return 0;
|
||||
if (skb->len < sizeof(struct atmtcp_hdr))
|
||||
goto done;
|
||||
|
||||
dev = vcc->dev_data;
|
||||
hdr = (struct atmtcp_hdr *) skb->data;
|
||||
if (hdr->length == ATMTCP_HDR_MAGIC) {
|
||||
|
@ -411,10 +411,11 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
|
||||
priv = cdev_to_priv(mcan_class);
|
||||
|
||||
priv->power = devm_regulator_get_optional(&spi->dev, "vsup");
|
||||
if (PTR_ERR(priv->power) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto out_m_can_class_free_dev;
|
||||
} else {
|
||||
if (IS_ERR(priv->power)) {
|
||||
if (PTR_ERR(priv->power) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto out_m_can_class_free_dev;
|
||||
}
|
||||
priv->power = NULL;
|
||||
}
|
||||
|
||||
|
@ -1065,23 +1065,18 @@ static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q)
|
||||
|
||||
static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma)
|
||||
{
|
||||
int size, index, num_desc = HW_DSCP_NUM;
|
||||
struct airoha_eth *eth = qdma->eth;
|
||||
int id = qdma - ð->qdma[0];
|
||||
u32 status, buf_size;
|
||||
dma_addr_t dma_addr;
|
||||
const char *name;
|
||||
int size, index;
|
||||
u32 status;
|
||||
|
||||
size = HW_DSCP_NUM * sizeof(struct airoha_qdma_fwd_desc);
|
||||
if (!dmam_alloc_coherent(eth->dev, size, &dma_addr, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
airoha_qdma_wr(qdma, REG_FWD_DSCP_BASE, dma_addr);
|
||||
|
||||
name = devm_kasprintf(eth->dev, GFP_KERNEL, "qdma%d-buf", id);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
buf_size = id ? AIROHA_MAX_PACKET_SIZE / 2 : AIROHA_MAX_PACKET_SIZE;
|
||||
index = of_property_match_string(eth->dev->of_node,
|
||||
"memory-region-names", name);
|
||||
if (index >= 0) {
|
||||
@ -1099,8 +1094,12 @@ static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma)
|
||||
rmem = of_reserved_mem_lookup(np);
|
||||
of_node_put(np);
|
||||
dma_addr = rmem->base;
|
||||
/* Compute the number of hw descriptors according to the
|
||||
* reserved memory size and the payload buffer size
|
||||
*/
|
||||
num_desc = div_u64(rmem->size, buf_size);
|
||||
} else {
|
||||
size = AIROHA_MAX_PACKET_SIZE * HW_DSCP_NUM;
|
||||
size = buf_size * num_desc;
|
||||
if (!dmam_alloc_coherent(eth->dev, size, &dma_addr,
|
||||
GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
@ -1108,15 +1107,21 @@ static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma)
|
||||
|
||||
airoha_qdma_wr(qdma, REG_FWD_BUF_BASE, dma_addr);
|
||||
|
||||
size = num_desc * sizeof(struct airoha_qdma_fwd_desc);
|
||||
if (!dmam_alloc_coherent(eth->dev, size, &dma_addr, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
airoha_qdma_wr(qdma, REG_FWD_DSCP_BASE, dma_addr);
|
||||
/* QDMA0: 2KB. QDMA1: 1KB */
|
||||
airoha_qdma_rmw(qdma, REG_HW_FWD_DSCP_CFG,
|
||||
HW_FWD_DSCP_PAYLOAD_SIZE_MASK,
|
||||
FIELD_PREP(HW_FWD_DSCP_PAYLOAD_SIZE_MASK, 0));
|
||||
FIELD_PREP(HW_FWD_DSCP_PAYLOAD_SIZE_MASK, !!id));
|
||||
airoha_qdma_rmw(qdma, REG_FWD_DSCP_LOW_THR, FWD_DSCP_LOW_THR_MASK,
|
||||
FIELD_PREP(FWD_DSCP_LOW_THR_MASK, 128));
|
||||
airoha_qdma_rmw(qdma, REG_LMGR_INIT_CFG,
|
||||
LMGR_INIT_START | LMGR_SRAM_MODE_MASK |
|
||||
HW_FWD_DESC_NUM_MASK,
|
||||
FIELD_PREP(HW_FWD_DESC_NUM_MASK, HW_DSCP_NUM) |
|
||||
FIELD_PREP(HW_FWD_DESC_NUM_MASK, num_desc) |
|
||||
LMGR_INIT_START | LMGR_SRAM_MODE_MASK);
|
||||
|
||||
return read_poll_timeout(airoha_qdma_rr, status,
|
||||
|
@ -809,8 +809,10 @@ airoha_ppe_foe_flow_l2_entry_update(struct airoha_ppe *ppe,
|
||||
int idle;
|
||||
|
||||
hwe = airoha_ppe_foe_get_entry(ppe, iter->hash);
|
||||
ib1 = READ_ONCE(hwe->ib1);
|
||||
if (!hwe)
|
||||
continue;
|
||||
|
||||
ib1 = READ_ONCE(hwe->ib1);
|
||||
state = FIELD_GET(AIROHA_FOE_IB1_BIND_STATE, ib1);
|
||||
if (state != AIROHA_FOE_STATE_BIND) {
|
||||
iter->hash = 0xffff;
|
||||
|
@ -10780,6 +10780,72 @@ void bnxt_del_one_rss_ctx(struct bnxt *bp, struct bnxt_rss_ctx *rss_ctx,
|
||||
bp->num_rss_ctx--;
|
||||
}
|
||||
|
||||
static bool bnxt_vnic_has_rx_ring(struct bnxt *bp, struct bnxt_vnic_info *vnic,
|
||||
int rxr_id)
|
||||
{
|
||||
u16 tbl_size = bnxt_get_rxfh_indir_size(bp->dev);
|
||||
int i, vnic_rx;
|
||||
|
||||
/* Ntuple VNIC always has all the rx rings. Any change of ring id
|
||||
* must be updated because a future filter may use it.
|
||||
*/
|
||||
if (vnic->flags & BNXT_VNIC_NTUPLE_FLAG)
|
||||
return true;
|
||||
|
||||
for (i = 0; i < tbl_size; i++) {
|
||||
if (vnic->flags & BNXT_VNIC_RSSCTX_FLAG)
|
||||
vnic_rx = ethtool_rxfh_context_indir(vnic->rss_ctx)[i];
|
||||
else
|
||||
vnic_rx = bp->rss_indir_tbl[i];
|
||||
|
||||
if (rxr_id == vnic_rx)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int bnxt_set_vnic_mru_p5(struct bnxt *bp, struct bnxt_vnic_info *vnic,
|
||||
u16 mru, int rxr_id)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!bnxt_vnic_has_rx_ring(bp, vnic, rxr_id))
|
||||
return 0;
|
||||
|
||||
if (mru) {
|
||||
rc = bnxt_hwrm_vnic_set_rss_p5(bp, vnic, true);
|
||||
if (rc) {
|
||||
netdev_err(bp->dev, "hwrm vnic %d set rss failure rc: %d\n",
|
||||
vnic->vnic_id, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
vnic->mru = mru;
|
||||
bnxt_hwrm_vnic_update(bp, vnic,
|
||||
VNIC_UPDATE_REQ_ENABLES_MRU_VALID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bnxt_set_rss_ctx_vnic_mru(struct bnxt *bp, u16 mru, int rxr_id)
|
||||
{
|
||||
struct ethtool_rxfh_context *ctx;
|
||||
unsigned long context;
|
||||
int rc;
|
||||
|
||||
xa_for_each(&bp->dev->ethtool->rss_ctx, context, ctx) {
|
||||
struct bnxt_rss_ctx *rss_ctx = ethtool_rxfh_context_priv(ctx);
|
||||
struct bnxt_vnic_info *vnic = &rss_ctx->vnic;
|
||||
|
||||
rc = bnxt_set_vnic_mru_p5(bp, vnic, mru, rxr_id);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bnxt_hwrm_realloc_rss_ctx_vnic(struct bnxt *bp)
|
||||
{
|
||||
bool set_tpa = !!(bp->flags & BNXT_FLAG_TPA);
|
||||
@ -15927,6 +15993,7 @@ static int bnxt_queue_start(struct net_device *dev, void *qmem, int idx)
|
||||
struct bnxt_vnic_info *vnic;
|
||||
struct bnxt_napi *bnapi;
|
||||
int i, rc;
|
||||
u16 mru;
|
||||
|
||||
rxr = &bp->rx_ring[idx];
|
||||
clone = qmem;
|
||||
@ -15977,21 +16044,15 @@ static int bnxt_queue_start(struct net_device *dev, void *qmem, int idx)
|
||||
napi_enable_locked(&bnapi->napi);
|
||||
bnxt_db_nq_arm(bp, &cpr->cp_db, cpr->cp_raw_cons);
|
||||
|
||||
mru = bp->dev->mtu + ETH_HLEN + VLAN_HLEN;
|
||||
for (i = 0; i < bp->nr_vnics; i++) {
|
||||
vnic = &bp->vnic_info[i];
|
||||
|
||||
rc = bnxt_hwrm_vnic_set_rss_p5(bp, vnic, true);
|
||||
if (rc) {
|
||||
netdev_err(bp->dev, "hwrm vnic %d set rss failure rc: %d\n",
|
||||
vnic->vnic_id, rc);
|
||||
rc = bnxt_set_vnic_mru_p5(bp, vnic, mru, idx);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
vnic->mru = bp->dev->mtu + ETH_HLEN + VLAN_HLEN;
|
||||
bnxt_hwrm_vnic_update(bp, vnic,
|
||||
VNIC_UPDATE_REQ_ENABLES_MRU_VALID);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return bnxt_set_rss_ctx_vnic_mru(bp, mru, idx);
|
||||
|
||||
err_reset:
|
||||
netdev_err(bp->dev, "Unexpected HWRM error during queue start rc: %d\n",
|
||||
@ -16013,10 +16074,10 @@ static int bnxt_queue_stop(struct net_device *dev, void *qmem, int idx)
|
||||
|
||||
for (i = 0; i < bp->nr_vnics; i++) {
|
||||
vnic = &bp->vnic_info[i];
|
||||
vnic->mru = 0;
|
||||
bnxt_hwrm_vnic_update(bp, vnic,
|
||||
VNIC_UPDATE_REQ_ENABLES_MRU_VALID);
|
||||
|
||||
bnxt_set_vnic_mru_p5(bp, vnic, 0, idx);
|
||||
}
|
||||
bnxt_set_rss_ctx_vnic_mru(bp, 0, idx);
|
||||
/* Make sure NAPI sees that the VNIC is disabled */
|
||||
synchronize_net();
|
||||
rxr = &bp->rx_ring[idx];
|
||||
|
@ -231,10 +231,9 @@ void bnxt_ulp_stop(struct bnxt *bp)
|
||||
return;
|
||||
|
||||
mutex_lock(&edev->en_dev_lock);
|
||||
if (!bnxt_ulp_registered(edev)) {
|
||||
mutex_unlock(&edev->en_dev_lock);
|
||||
return;
|
||||
}
|
||||
if (!bnxt_ulp_registered(edev) ||
|
||||
(edev->flags & BNXT_EN_FLAG_ULP_STOPPED))
|
||||
goto ulp_stop_exit;
|
||||
|
||||
edev->flags |= BNXT_EN_FLAG_ULP_STOPPED;
|
||||
if (aux_priv) {
|
||||
@ -250,6 +249,7 @@ void bnxt_ulp_stop(struct bnxt *bp)
|
||||
adrv->suspend(adev, pm);
|
||||
}
|
||||
}
|
||||
ulp_stop_exit:
|
||||
mutex_unlock(&edev->en_dev_lock);
|
||||
}
|
||||
|
||||
@ -258,19 +258,13 @@ void bnxt_ulp_start(struct bnxt *bp, int err)
|
||||
struct bnxt_aux_priv *aux_priv = bp->aux_priv;
|
||||
struct bnxt_en_dev *edev = bp->edev;
|
||||
|
||||
if (!edev)
|
||||
return;
|
||||
|
||||
edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
|
||||
|
||||
if (err)
|
||||
if (!edev || err)
|
||||
return;
|
||||
|
||||
mutex_lock(&edev->en_dev_lock);
|
||||
if (!bnxt_ulp_registered(edev)) {
|
||||
mutex_unlock(&edev->en_dev_lock);
|
||||
return;
|
||||
}
|
||||
if (!bnxt_ulp_registered(edev) ||
|
||||
!(edev->flags & BNXT_EN_FLAG_ULP_STOPPED))
|
||||
goto ulp_start_exit;
|
||||
|
||||
if (edev->ulp_tbl->msix_requested)
|
||||
bnxt_fill_msix_vecs(bp, edev->msix_entries);
|
||||
@ -287,6 +281,8 @@ void bnxt_ulp_start(struct bnxt *bp, int err)
|
||||
adrv->resume(adev);
|
||||
}
|
||||
}
|
||||
ulp_start_exit:
|
||||
edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
|
||||
mutex_unlock(&edev->en_dev_lock);
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ config FTGMAC100
|
||||
depends on ARM || COMPILE_TEST
|
||||
depends on !64BIT || BROKEN
|
||||
select PHYLIB
|
||||
select FIXED_PHY
|
||||
select MDIO_ASPEED if MACH_ASPEED_G6
|
||||
select CRC32
|
||||
help
|
||||
|
@ -3534,9 +3534,6 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
|
||||
case e1000_pch_cnp:
|
||||
case e1000_pch_tgp:
|
||||
case e1000_pch_adp:
|
||||
case e1000_pch_mtp:
|
||||
case e1000_pch_lnp:
|
||||
case e1000_pch_ptp:
|
||||
case e1000_pch_nvp:
|
||||
if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) {
|
||||
/* Stable 24MHz frequency */
|
||||
@ -3552,6 +3549,17 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
|
||||
adapter->cc.shift = shift;
|
||||
}
|
||||
break;
|
||||
case e1000_pch_mtp:
|
||||
case e1000_pch_lnp:
|
||||
case e1000_pch_ptp:
|
||||
/* System firmware can misreport this value, so set it to a
|
||||
* stable 38400KHz frequency.
|
||||
*/
|
||||
incperiod = INCPERIOD_38400KHZ;
|
||||
incvalue = INCVALUE_38400KHZ;
|
||||
shift = INCVALUE_SHIFT_38400KHZ;
|
||||
adapter->cc.shift = shift;
|
||||
break;
|
||||
case e1000_82574:
|
||||
case e1000_82583:
|
||||
/* Stable 25MHz frequency */
|
||||
|
@ -295,15 +295,17 @@ void e1000e_ptp_init(struct e1000_adapter *adapter)
|
||||
case e1000_pch_cnp:
|
||||
case e1000_pch_tgp:
|
||||
case e1000_pch_adp:
|
||||
case e1000_pch_mtp:
|
||||
case e1000_pch_lnp:
|
||||
case e1000_pch_ptp:
|
||||
case e1000_pch_nvp:
|
||||
if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)
|
||||
adapter->ptp_clock_info.max_adj = MAX_PPB_24MHZ;
|
||||
else
|
||||
adapter->ptp_clock_info.max_adj = MAX_PPB_38400KHZ;
|
||||
break;
|
||||
case e1000_pch_mtp:
|
||||
case e1000_pch_lnp:
|
||||
case e1000_pch_ptp:
|
||||
adapter->ptp_clock_info.max_adj = MAX_PPB_38400KHZ;
|
||||
break;
|
||||
case e1000_82574:
|
||||
case e1000_82583:
|
||||
adapter->ptp_clock_info.max_adj = MAX_PPB_25MHZ;
|
||||
|
@ -377,6 +377,50 @@ ice_arfs_is_perfect_flow_set(struct ice_hw *hw, __be16 l3_proto, u8 l4_proto)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_arfs_cmp - Check if aRFS filter matches this flow.
|
||||
* @fltr_info: filter info of the saved ARFS entry.
|
||||
* @fk: flow dissector keys.
|
||||
* @n_proto: One of htons(ETH_P_IP) or htons(ETH_P_IPV6).
|
||||
* @ip_proto: One of IPPROTO_TCP or IPPROTO_UDP.
|
||||
*
|
||||
* Since this function assumes limited values for n_proto and ip_proto, it
|
||||
* is meant to be called only from ice_rx_flow_steer().
|
||||
*
|
||||
* Return:
|
||||
* * true - fltr_info refers to the same flow as fk.
|
||||
* * false - fltr_info and fk refer to different flows.
|
||||
*/
|
||||
static bool
|
||||
ice_arfs_cmp(const struct ice_fdir_fltr *fltr_info, const struct flow_keys *fk,
|
||||
__be16 n_proto, u8 ip_proto)
|
||||
{
|
||||
/* Determine if the filter is for IPv4 or IPv6 based on flow_type,
|
||||
* which is one of ICE_FLTR_PTYPE_NONF_IPV{4,6}_{TCP,UDP}.
|
||||
*/
|
||||
bool is_v4 = fltr_info->flow_type == ICE_FLTR_PTYPE_NONF_IPV4_TCP ||
|
||||
fltr_info->flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP;
|
||||
|
||||
/* Following checks are arranged in the quickest and most discriminative
|
||||
* fields first for early failure.
|
||||
*/
|
||||
if (is_v4)
|
||||
return n_proto == htons(ETH_P_IP) &&
|
||||
fltr_info->ip.v4.src_port == fk->ports.src &&
|
||||
fltr_info->ip.v4.dst_port == fk->ports.dst &&
|
||||
fltr_info->ip.v4.src_ip == fk->addrs.v4addrs.src &&
|
||||
fltr_info->ip.v4.dst_ip == fk->addrs.v4addrs.dst &&
|
||||
fltr_info->ip.v4.proto == ip_proto;
|
||||
|
||||
return fltr_info->ip.v6.src_port == fk->ports.src &&
|
||||
fltr_info->ip.v6.dst_port == fk->ports.dst &&
|
||||
fltr_info->ip.v6.proto == ip_proto &&
|
||||
!memcmp(&fltr_info->ip.v6.src_ip, &fk->addrs.v6addrs.src,
|
||||
sizeof(struct in6_addr)) &&
|
||||
!memcmp(&fltr_info->ip.v6.dst_ip, &fk->addrs.v6addrs.dst,
|
||||
sizeof(struct in6_addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_rx_flow_steer - steer the Rx flow to where application is being run
|
||||
* @netdev: ptr to the netdev being adjusted
|
||||
@ -448,6 +492,10 @@ ice_rx_flow_steer(struct net_device *netdev, const struct sk_buff *skb,
|
||||
continue;
|
||||
|
||||
fltr_info = &arfs_entry->fltr_info;
|
||||
|
||||
if (!ice_arfs_cmp(fltr_info, &fk, n_proto, ip_proto))
|
||||
continue;
|
||||
|
||||
ret = fltr_info->fltr_id;
|
||||
|
||||
if (fltr_info->q_index == rxq_idx ||
|
||||
|
@ -508,10 +508,14 @@ err_create_repr:
|
||||
*/
|
||||
int ice_eswitch_attach_vf(struct ice_pf *pf, struct ice_vf *vf)
|
||||
{
|
||||
struct ice_repr *repr = ice_repr_create_vf(vf);
|
||||
struct devlink *devlink = priv_to_devlink(pf);
|
||||
struct ice_repr *repr;
|
||||
int err;
|
||||
|
||||
if (!ice_is_eswitch_mode_switchdev(pf))
|
||||
return 0;
|
||||
|
||||
repr = ice_repr_create_vf(vf);
|
||||
if (IS_ERR(repr))
|
||||
return PTR_ERR(repr);
|
||||
|
||||
|
@ -1822,7 +1822,7 @@ int otx2_nix_config_bp(struct otx2_nic *pfvf, bool enable)
|
||||
req->chan_cnt = IEEE_8021QAZ_MAX_TCS;
|
||||
req->bpid_per_chan = 1;
|
||||
} else {
|
||||
req->chan_cnt = 1;
|
||||
req->chan_cnt = pfvf->hw.rx_chan_cnt;
|
||||
req->bpid_per_chan = 0;
|
||||
}
|
||||
|
||||
@ -1847,7 +1847,7 @@ int otx2_nix_cpt_config_bp(struct otx2_nic *pfvf, bool enable)
|
||||
req->chan_cnt = IEEE_8021QAZ_MAX_TCS;
|
||||
req->bpid_per_chan = 1;
|
||||
} else {
|
||||
req->chan_cnt = 1;
|
||||
req->chan_cnt = pfvf->hw.rx_chan_cnt;
|
||||
req->bpid_per_chan = 0;
|
||||
}
|
||||
|
||||
|
@ -447,8 +447,10 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
|
||||
priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX);
|
||||
|
||||
phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy", 0);
|
||||
if (phy_irq < 0) {
|
||||
dev_err(&pdev->dev, "Error getting PHY irq. Use polling instead");
|
||||
if (phy_irq == -EPROBE_DEFER) {
|
||||
err = -EPROBE_DEFER;
|
||||
goto out;
|
||||
} else if (phy_irq < 0) {
|
||||
phy_irq = PHY_POLL;
|
||||
}
|
||||
|
||||
|
@ -127,11 +127,8 @@ static int fbnic_mbx_map_msg(struct fbnic_dev *fbd, int mbx_idx,
|
||||
return -EBUSY;
|
||||
|
||||
addr = dma_map_single(fbd->dev, msg, PAGE_SIZE, direction);
|
||||
if (dma_mapping_error(fbd->dev, addr)) {
|
||||
free_page((unsigned long)msg);
|
||||
|
||||
if (dma_mapping_error(fbd->dev, addr))
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
mbx->buf_info[tail].msg = msg;
|
||||
mbx->buf_info[tail].addr = addr;
|
||||
|
@ -18,9 +18,9 @@
|
||||
*/
|
||||
#define LAN743X_PTP_N_EVENT_CHAN 2
|
||||
#define LAN743X_PTP_N_PEROUT LAN743X_PTP_N_EVENT_CHAN
|
||||
#define LAN743X_PTP_N_EXTTS 4
|
||||
#define LAN743X_PTP_N_PPS 0
|
||||
#define PCI11X1X_PTP_IO_MAX_CHANNELS 8
|
||||
#define LAN743X_PTP_N_EXTTS PCI11X1X_PTP_IO_MAX_CHANNELS
|
||||
#define LAN743X_PTP_N_PPS 0
|
||||
#define PTP_CMD_CTL_TIMEOUT_CNT 50
|
||||
|
||||
struct lan743x_adapter;
|
||||
|
@ -516,9 +516,9 @@ static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds,
|
||||
unsigned long start_time;
|
||||
unsigned long max_wait;
|
||||
unsigned long duration;
|
||||
int done = 0;
|
||||
bool fw_up;
|
||||
int opcode;
|
||||
bool done;
|
||||
int err;
|
||||
|
||||
/* Wait for dev cmd to complete, retrying if we get EAGAIN,
|
||||
@ -526,6 +526,7 @@ static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds,
|
||||
*/
|
||||
max_wait = jiffies + (max_seconds * HZ);
|
||||
try_again:
|
||||
done = false;
|
||||
opcode = idev->opcode;
|
||||
start_time = jiffies;
|
||||
for (fw_up = ionic_is_fw_running(idev);
|
||||
|
@ -98,20 +98,11 @@ void prueth_xmit_free(struct prueth_tx_chn *tx_chn,
|
||||
{
|
||||
struct cppi5_host_desc_t *first_desc, *next_desc;
|
||||
dma_addr_t buf_dma, next_desc_dma;
|
||||
struct prueth_swdata *swdata;
|
||||
struct page *page;
|
||||
u32 buf_dma_len;
|
||||
|
||||
first_desc = desc;
|
||||
next_desc = first_desc;
|
||||
|
||||
swdata = cppi5_hdesc_get_swdata(desc);
|
||||
if (swdata->type == PRUETH_SWDATA_PAGE) {
|
||||
page = swdata->data.page;
|
||||
page_pool_recycle_direct(page->pp, swdata->data.page);
|
||||
goto free_desc;
|
||||
}
|
||||
|
||||
cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len);
|
||||
k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);
|
||||
|
||||
@ -135,7 +126,6 @@ void prueth_xmit_free(struct prueth_tx_chn *tx_chn,
|
||||
k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc);
|
||||
}
|
||||
|
||||
free_desc:
|
||||
k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prueth_xmit_free);
|
||||
@ -612,13 +602,8 @@ u32 emac_xmit_xdp_frame(struct prueth_emac *emac,
|
||||
k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma);
|
||||
cppi5_hdesc_attach_buf(first_desc, buf_dma, xdpf->len, buf_dma, xdpf->len);
|
||||
swdata = cppi5_hdesc_get_swdata(first_desc);
|
||||
if (page) {
|
||||
swdata->type = PRUETH_SWDATA_PAGE;
|
||||
swdata->data.page = page;
|
||||
} else {
|
||||
swdata->type = PRUETH_SWDATA_XDPF;
|
||||
swdata->data.xdpf = xdpf;
|
||||
}
|
||||
swdata->type = PRUETH_SWDATA_XDPF;
|
||||
swdata->data.xdpf = xdpf;
|
||||
|
||||
/* Report BQL before sending the packet */
|
||||
netif_txq = netdev_get_tx_queue(ndev, tx_chn->id);
|
||||
|
@ -1216,6 +1216,7 @@ void ath12k_fw_stats_init(struct ath12k *ar)
|
||||
INIT_LIST_HEAD(&ar->fw_stats.pdevs);
|
||||
INIT_LIST_HEAD(&ar->fw_stats.bcn);
|
||||
init_completion(&ar->fw_stats_complete);
|
||||
init_completion(&ar->fw_stats_done);
|
||||
}
|
||||
|
||||
void ath12k_fw_stats_free(struct ath12k_fw_stats *stats)
|
||||
@ -1228,8 +1229,9 @@ void ath12k_fw_stats_free(struct ath12k_fw_stats *stats)
|
||||
void ath12k_fw_stats_reset(struct ath12k *ar)
|
||||
{
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ar->fw_stats.fw_stats_done = false;
|
||||
ath12k_fw_stats_free(&ar->fw_stats);
|
||||
ar->fw_stats.num_vdev_recvd = 0;
|
||||
ar->fw_stats.num_bcn_recvd = 0;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
|
@ -601,6 +601,12 @@ struct ath12k_sta {
|
||||
#define ATH12K_NUM_CHANS 101
|
||||
#define ATH12K_MAX_5GHZ_CHAN 173
|
||||
|
||||
static inline bool ath12k_is_2ghz_channel_freq(u32 freq)
|
||||
{
|
||||
return freq >= ATH12K_MIN_2GHZ_FREQ &&
|
||||
freq <= ATH12K_MAX_2GHZ_FREQ;
|
||||
}
|
||||
|
||||
enum ath12k_hw_state {
|
||||
ATH12K_HW_STATE_OFF,
|
||||
ATH12K_HW_STATE_ON,
|
||||
@ -626,7 +632,8 @@ struct ath12k_fw_stats {
|
||||
struct list_head pdevs;
|
||||
struct list_head vdevs;
|
||||
struct list_head bcn;
|
||||
bool fw_stats_done;
|
||||
u32 num_vdev_recvd;
|
||||
u32 num_bcn_recvd;
|
||||
};
|
||||
|
||||
struct ath12k_dbg_htt_stats {
|
||||
@ -806,6 +813,7 @@ struct ath12k {
|
||||
bool regdom_set_by_user;
|
||||
|
||||
struct completion fw_stats_complete;
|
||||
struct completion fw_stats_done;
|
||||
|
||||
struct completion mlo_setup_done;
|
||||
u32 mlo_setup_status;
|
||||
|
@ -1251,64 +1251,6 @@ void ath12k_debugfs_soc_destroy(struct ath12k_base *ab)
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
ath12k_debugfs_fw_stats_process(struct ath12k *ar,
|
||||
struct ath12k_fw_stats *stats)
|
||||
{
|
||||
struct ath12k_base *ab = ar->ab;
|
||||
struct ath12k_pdev *pdev;
|
||||
bool is_end;
|
||||
static unsigned int num_vdev, num_bcn;
|
||||
size_t total_vdevs_started = 0;
|
||||
int i;
|
||||
|
||||
if (stats->stats_id == WMI_REQUEST_VDEV_STAT) {
|
||||
if (list_empty(&stats->vdevs)) {
|
||||
ath12k_warn(ab, "empty vdev stats");
|
||||
return;
|
||||
}
|
||||
/* FW sends all the active VDEV stats irrespective of PDEV,
|
||||
* hence limit until the count of all VDEVs started
|
||||
*/
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < ab->num_radios; i++) {
|
||||
pdev = rcu_dereference(ab->pdevs_active[i]);
|
||||
if (pdev && pdev->ar)
|
||||
total_vdevs_started += pdev->ar->num_started_vdevs;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
is_end = ((++num_vdev) == total_vdevs_started);
|
||||
|
||||
list_splice_tail_init(&stats->vdevs,
|
||||
&ar->fw_stats.vdevs);
|
||||
|
||||
if (is_end) {
|
||||
ar->fw_stats.fw_stats_done = true;
|
||||
num_vdev = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (stats->stats_id == WMI_REQUEST_BCN_STAT) {
|
||||
if (list_empty(&stats->bcn)) {
|
||||
ath12k_warn(ab, "empty beacon stats");
|
||||
return;
|
||||
}
|
||||
/* Mark end until we reached the count of all started VDEVs
|
||||
* within the PDEV
|
||||
*/
|
||||
is_end = ((++num_bcn) == ar->num_started_vdevs);
|
||||
|
||||
list_splice_tail_init(&stats->bcn,
|
||||
&ar->fw_stats.bcn);
|
||||
|
||||
if (is_end) {
|
||||
ar->fw_stats.fw_stats_done = true;
|
||||
num_bcn = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ath12k_open_vdev_stats(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ath12k *ar = inode->i_private;
|
||||
|
@ -12,8 +12,6 @@ void ath12k_debugfs_soc_create(struct ath12k_base *ab);
|
||||
void ath12k_debugfs_soc_destroy(struct ath12k_base *ab);
|
||||
void ath12k_debugfs_register(struct ath12k *ar);
|
||||
void ath12k_debugfs_unregister(struct ath12k *ar);
|
||||
void ath12k_debugfs_fw_stats_process(struct ath12k *ar,
|
||||
struct ath12k_fw_stats *stats);
|
||||
void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
void ath12k_debugfs_pdev_create(struct ath12k_base *ab);
|
||||
@ -126,11 +124,6 @@ static inline void ath12k_debugfs_unregister(struct ath12k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath12k_debugfs_fw_stats_process(struct ath12k *ar,
|
||||
struct ath12k_fw_stats *stats)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool ath12k_debugfs_is_extd_rx_stats_enabled(struct ath12k *ar)
|
||||
{
|
||||
return false;
|
||||
|
@ -4360,7 +4360,7 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar,
|
||||
{
|
||||
struct ath12k_base *ab = ar->ab;
|
||||
struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
|
||||
unsigned long timeout, time_left;
|
||||
unsigned long time_left;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&ah->hw_mutex);
|
||||
@ -4368,19 +4368,13 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar,
|
||||
if (ah->state != ATH12K_HW_STATE_ON)
|
||||
return -ENETDOWN;
|
||||
|
||||
/* FW stats can get split when exceeding the stats data buffer limit.
|
||||
* In that case, since there is no end marking for the back-to-back
|
||||
* received 'update stats' event, we keep a 3 seconds timeout in case,
|
||||
* fw_stats_done is not marked yet
|
||||
*/
|
||||
timeout = jiffies + msecs_to_jiffies(3 * 1000);
|
||||
ath12k_fw_stats_reset(ar);
|
||||
|
||||
reinit_completion(&ar->fw_stats_complete);
|
||||
reinit_completion(&ar->fw_stats_done);
|
||||
|
||||
ret = ath12k_wmi_send_stats_request_cmd(ar, param->stats_id,
|
||||
param->vdev_id, param->pdev_id);
|
||||
|
||||
if (ret) {
|
||||
ath12k_warn(ab, "failed to request fw stats: %d\n", ret);
|
||||
return ret;
|
||||
@ -4391,7 +4385,6 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar,
|
||||
param->pdev_id, param->vdev_id, param->stats_id);
|
||||
|
||||
time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ);
|
||||
|
||||
if (!time_left) {
|
||||
ath12k_warn(ab, "time out while waiting for get fw stats\n");
|
||||
return -ETIMEDOUT;
|
||||
@ -4400,20 +4393,15 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar,
|
||||
/* Firmware sends WMI_UPDATE_STATS_EVENTID back-to-back
|
||||
* when stats data buffer limit is reached. fw_stats_complete
|
||||
* is completed once host receives first event from firmware, but
|
||||
* still end might not be marked in the TLV.
|
||||
* Below loop is to confirm that firmware completed sending all the event
|
||||
* and fw_stats_done is marked true when end is marked in the TLV.
|
||||
* still there could be more events following. Below is to wait
|
||||
* until firmware completes sending all the events.
|
||||
*/
|
||||
for (;;) {
|
||||
if (time_after(jiffies, timeout))
|
||||
break;
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
if (ar->fw_stats.fw_stats_done) {
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
break;
|
||||
}
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
time_left = wait_for_completion_timeout(&ar->fw_stats_done, 3 * HZ);
|
||||
if (!time_left) {
|
||||
ath12k_warn(ab, "time out while waiting for fw stats done\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5890,6 +5878,327 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool ath12k_mac_is_freq_on_mac(struct ath12k_hw_mode_freq_range_arg *freq_range,
|
||||
u32 freq, u8 mac_id)
|
||||
{
|
||||
return (freq >= freq_range[mac_id].low_2ghz_freq &&
|
||||
freq <= freq_range[mac_id].high_2ghz_freq) ||
|
||||
(freq >= freq_range[mac_id].low_5ghz_freq &&
|
||||
freq <= freq_range[mac_id].high_5ghz_freq);
|
||||
}
|
||||
|
||||
static bool
|
||||
ath12k_mac_2_freq_same_mac_in_freq_range(struct ath12k_base *ab,
|
||||
struct ath12k_hw_mode_freq_range_arg *freq_range,
|
||||
u32 freq_link1, u32 freq_link2)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < MAX_RADIOS; i++) {
|
||||
if (ath12k_mac_is_freq_on_mac(freq_range, freq_link1, i) &&
|
||||
ath12k_mac_is_freq_on_mac(freq_range, freq_link2, i))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ath12k_mac_is_hw_dbs_capable(struct ath12k_base *ab)
|
||||
{
|
||||
return test_bit(WMI_TLV_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT,
|
||||
ab->wmi_ab.svc_map) &&
|
||||
ab->wmi_ab.hw_mode_info.support_dbs;
|
||||
}
|
||||
|
||||
static bool ath12k_mac_2_freq_same_mac_in_dbs(struct ath12k_base *ab,
|
||||
u32 freq_link1, u32 freq_link2)
|
||||
{
|
||||
struct ath12k_hw_mode_freq_range_arg *freq_range;
|
||||
|
||||
if (!ath12k_mac_is_hw_dbs_capable(ab))
|
||||
return true;
|
||||
|
||||
freq_range = ab->wmi_ab.hw_mode_info.freq_range_caps[ATH12K_HW_MODE_DBS];
|
||||
return ath12k_mac_2_freq_same_mac_in_freq_range(ab, freq_range,
|
||||
freq_link1, freq_link2);
|
||||
}
|
||||
|
||||
static bool ath12k_mac_is_hw_sbs_capable(struct ath12k_base *ab)
|
||||
{
|
||||
return test_bit(WMI_TLV_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT,
|
||||
ab->wmi_ab.svc_map) &&
|
||||
ab->wmi_ab.hw_mode_info.support_sbs;
|
||||
}
|
||||
|
||||
static bool ath12k_mac_2_freq_same_mac_in_sbs(struct ath12k_base *ab,
|
||||
u32 freq_link1, u32 freq_link2)
|
||||
{
|
||||
struct ath12k_hw_mode_info *info = &ab->wmi_ab.hw_mode_info;
|
||||
struct ath12k_hw_mode_freq_range_arg *sbs_uppr_share;
|
||||
struct ath12k_hw_mode_freq_range_arg *sbs_low_share;
|
||||
struct ath12k_hw_mode_freq_range_arg *sbs_range;
|
||||
|
||||
if (!ath12k_mac_is_hw_sbs_capable(ab))
|
||||
return true;
|
||||
|
||||
if (ab->wmi_ab.sbs_lower_band_end_freq) {
|
||||
sbs_uppr_share = info->freq_range_caps[ATH12K_HW_MODE_SBS_UPPER_SHARE];
|
||||
sbs_low_share = info->freq_range_caps[ATH12K_HW_MODE_SBS_LOWER_SHARE];
|
||||
|
||||
return ath12k_mac_2_freq_same_mac_in_freq_range(ab, sbs_low_share,
|
||||
freq_link1, freq_link2) ||
|
||||
ath12k_mac_2_freq_same_mac_in_freq_range(ab, sbs_uppr_share,
|
||||
freq_link1, freq_link2);
|
||||
}
|
||||
|
||||
sbs_range = info->freq_range_caps[ATH12K_HW_MODE_SBS];
|
||||
return ath12k_mac_2_freq_same_mac_in_freq_range(ab, sbs_range,
|
||||
freq_link1, freq_link2);
|
||||
}
|
||||
|
||||
static bool ath12k_mac_freqs_on_same_mac(struct ath12k_base *ab,
|
||||
u32 freq_link1, u32 freq_link2)
|
||||
{
|
||||
return ath12k_mac_2_freq_same_mac_in_dbs(ab, freq_link1, freq_link2) &&
|
||||
ath12k_mac_2_freq_same_mac_in_sbs(ab, freq_link1, freq_link2);
|
||||
}
|
||||
|
||||
static int ath12k_mac_mlo_sta_set_link_active(struct ath12k_base *ab,
|
||||
enum wmi_mlo_link_force_reason reason,
|
||||
enum wmi_mlo_link_force_mode mode,
|
||||
u8 *mlo_vdev_id_lst,
|
||||
u8 num_mlo_vdev,
|
||||
u8 *mlo_inactive_vdev_lst,
|
||||
u8 num_mlo_inactive_vdev)
|
||||
{
|
||||
struct wmi_mlo_link_set_active_arg param = {0};
|
||||
u32 entry_idx, entry_offset, vdev_idx;
|
||||
u8 vdev_id;
|
||||
|
||||
param.reason = reason;
|
||||
param.force_mode = mode;
|
||||
|
||||
for (vdev_idx = 0; vdev_idx < num_mlo_vdev; vdev_idx++) {
|
||||
vdev_id = mlo_vdev_id_lst[vdev_idx];
|
||||
entry_idx = vdev_id / 32;
|
||||
entry_offset = vdev_id % 32;
|
||||
if (entry_idx >= WMI_MLO_LINK_NUM_SZ) {
|
||||
ath12k_warn(ab, "Invalid entry_idx %d num_mlo_vdev %d vdev %d",
|
||||
entry_idx, num_mlo_vdev, vdev_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
param.vdev_bitmap[entry_idx] |= 1 << entry_offset;
|
||||
/* update entry number if entry index changed */
|
||||
if (param.num_vdev_bitmap < entry_idx + 1)
|
||||
param.num_vdev_bitmap = entry_idx + 1;
|
||||
}
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_MAC,
|
||||
"num_vdev_bitmap %d vdev_bitmap[0] = 0x%x, vdev_bitmap[1] = 0x%x",
|
||||
param.num_vdev_bitmap, param.vdev_bitmap[0], param.vdev_bitmap[1]);
|
||||
|
||||
if (mode == WMI_MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE) {
|
||||
for (vdev_idx = 0; vdev_idx < num_mlo_inactive_vdev; vdev_idx++) {
|
||||
vdev_id = mlo_inactive_vdev_lst[vdev_idx];
|
||||
entry_idx = vdev_id / 32;
|
||||
entry_offset = vdev_id % 32;
|
||||
if (entry_idx >= WMI_MLO_LINK_NUM_SZ) {
|
||||
ath12k_warn(ab, "Invalid entry_idx %d num_mlo_vdev %d vdev %d",
|
||||
entry_idx, num_mlo_inactive_vdev, vdev_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
param.inactive_vdev_bitmap[entry_idx] |= 1 << entry_offset;
|
||||
/* update entry number if entry index changed */
|
||||
if (param.num_inactive_vdev_bitmap < entry_idx + 1)
|
||||
param.num_inactive_vdev_bitmap = entry_idx + 1;
|
||||
}
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_MAC,
|
||||
"num_vdev_bitmap %d inactive_vdev_bitmap[0] = 0x%x, inactive_vdev_bitmap[1] = 0x%x",
|
||||
param.num_inactive_vdev_bitmap,
|
||||
param.inactive_vdev_bitmap[0],
|
||||
param.inactive_vdev_bitmap[1]);
|
||||
}
|
||||
|
||||
if (mode == WMI_MLO_LINK_FORCE_MODE_ACTIVE_LINK_NUM ||
|
||||
mode == WMI_MLO_LINK_FORCE_MODE_INACTIVE_LINK_NUM) {
|
||||
param.num_link_entry = 1;
|
||||
param.link_num[0].num_of_link = num_mlo_vdev - 1;
|
||||
}
|
||||
|
||||
return ath12k_wmi_send_mlo_link_set_active_cmd(ab, ¶m);
|
||||
}
|
||||
|
||||
static int ath12k_mac_mlo_sta_update_link_active(struct ath12k_base *ab,
|
||||
struct ieee80211_hw *hw,
|
||||
struct ath12k_vif *ahvif)
|
||||
{
|
||||
u8 mlo_vdev_id_lst[IEEE80211_MLD_MAX_NUM_LINKS] = {0};
|
||||
u32 mlo_freq_list[IEEE80211_MLD_MAX_NUM_LINKS] = {0};
|
||||
unsigned long links = ahvif->links_map;
|
||||
enum wmi_mlo_link_force_reason reason;
|
||||
struct ieee80211_chanctx_conf *conf;
|
||||
enum wmi_mlo_link_force_mode mode;
|
||||
struct ieee80211_bss_conf *info;
|
||||
struct ath12k_link_vif *arvif;
|
||||
u8 num_mlo_vdev = 0;
|
||||
u8 link_id;
|
||||
|
||||
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||
arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
|
||||
/* make sure vdev is created on this device */
|
||||
if (!arvif || !arvif->is_created || arvif->ar->ab != ab)
|
||||
continue;
|
||||
|
||||
info = ath12k_mac_get_link_bss_conf(arvif);
|
||||
conf = wiphy_dereference(hw->wiphy, info->chanctx_conf);
|
||||
mlo_freq_list[num_mlo_vdev] = conf->def.chan->center_freq;
|
||||
|
||||
mlo_vdev_id_lst[num_mlo_vdev] = arvif->vdev_id;
|
||||
num_mlo_vdev++;
|
||||
}
|
||||
|
||||
/* It is not allowed to activate more links than a single device
|
||||
* supported. Something goes wrong if we reach here.
|
||||
*/
|
||||
if (num_mlo_vdev > ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE) {
|
||||
WARN_ON_ONCE(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* if 2 links are established and both link channels fall on the
|
||||
* same hardware MAC, send command to firmware to deactivate one
|
||||
* of them.
|
||||
*/
|
||||
if (num_mlo_vdev == 2 &&
|
||||
ath12k_mac_freqs_on_same_mac(ab, mlo_freq_list[0],
|
||||
mlo_freq_list[1])) {
|
||||
mode = WMI_MLO_LINK_FORCE_MODE_INACTIVE_LINK_NUM;
|
||||
reason = WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT;
|
||||
return ath12k_mac_mlo_sta_set_link_active(ab, reason, mode,
|
||||
mlo_vdev_id_lst, num_mlo_vdev,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ath12k_mac_are_sbs_chan(struct ath12k_base *ab, u32 freq_1, u32 freq_2)
|
||||
{
|
||||
if (!ath12k_mac_is_hw_sbs_capable(ab))
|
||||
return false;
|
||||
|
||||
if (ath12k_is_2ghz_channel_freq(freq_1) ||
|
||||
ath12k_is_2ghz_channel_freq(freq_2))
|
||||
return false;
|
||||
|
||||
return !ath12k_mac_2_freq_same_mac_in_sbs(ab, freq_1, freq_2);
|
||||
}
|
||||
|
||||
static bool ath12k_mac_are_dbs_chan(struct ath12k_base *ab, u32 freq_1, u32 freq_2)
|
||||
{
|
||||
if (!ath12k_mac_is_hw_dbs_capable(ab))
|
||||
return false;
|
||||
|
||||
return !ath12k_mac_2_freq_same_mac_in_dbs(ab, freq_1, freq_2);
|
||||
}
|
||||
|
||||
static int ath12k_mac_select_links(struct ath12k_base *ab,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_hw *hw,
|
||||
u16 *selected_links)
|
||||
{
|
||||
unsigned long useful_links = ieee80211_vif_usable_links(vif);
|
||||
struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
|
||||
u8 num_useful_links = hweight_long(useful_links);
|
||||
struct ieee80211_chanctx_conf *chanctx;
|
||||
struct ath12k_link_vif *assoc_arvif;
|
||||
u32 assoc_link_freq, partner_freq;
|
||||
u16 sbs_links = 0, dbs_links = 0;
|
||||
struct ieee80211_bss_conf *info;
|
||||
struct ieee80211_channel *chan;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath12k_sta *ahsta;
|
||||
u8 link_id;
|
||||
|
||||
/* activate all useful links if less than max supported */
|
||||
if (num_useful_links <= ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE) {
|
||||
*selected_links = useful_links;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* only in station mode we can get here, so it's safe
|
||||
* to use ap_addr
|
||||
*/
|
||||
rcu_read_lock();
|
||||
sta = ieee80211_find_sta(vif, vif->cfg.ap_addr);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
ath12k_warn(ab, "failed to find sta with addr %pM\n", vif->cfg.ap_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ahsta = ath12k_sta_to_ahsta(sta);
|
||||
assoc_arvif = wiphy_dereference(hw->wiphy, ahvif->link[ahsta->assoc_link_id]);
|
||||
info = ath12k_mac_get_link_bss_conf(assoc_arvif);
|
||||
chanctx = rcu_dereference(info->chanctx_conf);
|
||||
assoc_link_freq = chanctx->def.chan->center_freq;
|
||||
rcu_read_unlock();
|
||||
ath12k_dbg(ab, ATH12K_DBG_MAC, "assoc link %u freq %u\n",
|
||||
assoc_arvif->link_id, assoc_link_freq);
|
||||
|
||||
/* assoc link is already activated and has to be kept active,
|
||||
* only need to select a partner link from others.
|
||||
*/
|
||||
useful_links &= ~BIT(assoc_arvif->link_id);
|
||||
for_each_set_bit(link_id, &useful_links, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||
info = wiphy_dereference(hw->wiphy, vif->link_conf[link_id]);
|
||||
if (!info) {
|
||||
ath12k_warn(ab, "failed to get link info for link: %u\n",
|
||||
link_id);
|
||||
return -ENOLINK;
|
||||
}
|
||||
|
||||
chan = info->chanreq.oper.chan;
|
||||
if (!chan) {
|
||||
ath12k_warn(ab, "failed to get chan for link: %u\n", link_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
partner_freq = chan->center_freq;
|
||||
if (ath12k_mac_are_sbs_chan(ab, assoc_link_freq, partner_freq)) {
|
||||
sbs_links |= BIT(link_id);
|
||||
ath12k_dbg(ab, ATH12K_DBG_MAC, "new SBS link %u freq %u\n",
|
||||
link_id, partner_freq);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ath12k_mac_are_dbs_chan(ab, assoc_link_freq, partner_freq)) {
|
||||
dbs_links |= BIT(link_id);
|
||||
ath12k_dbg(ab, ATH12K_DBG_MAC, "new DBS link %u freq %u\n",
|
||||
link_id, partner_freq);
|
||||
continue;
|
||||
}
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_MAC, "non DBS/SBS link %u freq %u\n",
|
||||
link_id, partner_freq);
|
||||
}
|
||||
|
||||
/* choose the first candidate no matter how many is in the list */
|
||||
if (sbs_links)
|
||||
link_id = __ffs(sbs_links);
|
||||
else if (dbs_links)
|
||||
link_id = __ffs(dbs_links);
|
||||
else
|
||||
link_id = ffs(useful_links) - 1;
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_MAC, "select partner link %u\n", link_id);
|
||||
|
||||
*selected_links = BIT(assoc_arvif->link_id) | BIT(link_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
@ -5899,10 +6208,13 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
|
||||
struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
|
||||
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
|
||||
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
|
||||
struct ath12k_base *prev_ab = NULL, *ab;
|
||||
struct ath12k_link_vif *arvif;
|
||||
struct ath12k_link_sta *arsta;
|
||||
unsigned long valid_links;
|
||||
u8 link_id = 0;
|
||||
u16 selected_links = 0;
|
||||
u8 link_id = 0, i;
|
||||
struct ath12k *ar;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_wiphy(hw->wiphy);
|
||||
@ -5972,8 +6284,24 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
|
||||
* about to move to the associated state.
|
||||
*/
|
||||
if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION &&
|
||||
old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC)
|
||||
ieee80211_set_active_links(vif, ieee80211_vif_usable_links(vif));
|
||||
old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) {
|
||||
/* TODO: for now only do link selection for single device
|
||||
* MLO case. Other cases would be handled in the future.
|
||||
*/
|
||||
ab = ah->radio[0].ab;
|
||||
if (ab->ag->num_devices == 1) {
|
||||
ret = ath12k_mac_select_links(ab, vif, hw, &selected_links);
|
||||
if (ret) {
|
||||
ath12k_warn(ab,
|
||||
"failed to get selected links: %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
selected_links = ieee80211_vif_usable_links(vif);
|
||||
}
|
||||
|
||||
ieee80211_set_active_links(vif, selected_links);
|
||||
}
|
||||
|
||||
/* Handle all the other state transitions in generic way */
|
||||
valid_links = ahsta->links_map;
|
||||
@ -5997,6 +6325,24 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
|
||||
}
|
||||
}
|
||||
|
||||
if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION &&
|
||||
old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTHORIZED) {
|
||||
for_each_ar(ah, ar, i) {
|
||||
ab = ar->ab;
|
||||
if (prev_ab == ab)
|
||||
continue;
|
||||
|
||||
ret = ath12k_mac_mlo_sta_update_link_active(ab, hw, ahvif);
|
||||
if (ret) {
|
||||
ath12k_warn(ab,
|
||||
"failed to update link active state on connect %d\n",
|
||||
ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
prev_ab = ab;
|
||||
}
|
||||
}
|
||||
/* IEEE80211_STA_NONE -> IEEE80211_STA_NOTEXIST:
|
||||
* Remove the station from driver (handle ML sta here since that
|
||||
* needs special handling. Normal sta will be handled in generic
|
||||
|
@ -54,6 +54,8 @@ struct ath12k_generic_iter {
|
||||
#define ATH12K_DEFAULT_SCAN_LINK IEEE80211_MLD_MAX_NUM_LINKS
|
||||
#define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + 1)
|
||||
|
||||
#define ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE 2
|
||||
|
||||
enum ath12k_supported_bw {
|
||||
ATH12K_BW_20 = 0,
|
||||
ATH12K_BW_40 = 1,
|
||||
|
@ -91,6 +91,11 @@ struct ath12k_wmi_svc_rdy_ext2_parse {
|
||||
bool dma_ring_cap_done;
|
||||
bool spectral_bin_scaling_done;
|
||||
bool mac_phy_caps_ext_done;
|
||||
bool hal_reg_caps_ext2_done;
|
||||
bool scan_radio_caps_ext2_done;
|
||||
bool twt_caps_done;
|
||||
bool htt_msdu_idx_to_qtype_map_done;
|
||||
bool dbs_or_sbs_cap_ext_done;
|
||||
};
|
||||
|
||||
struct ath12k_wmi_rdy_parse {
|
||||
@ -4395,6 +4400,7 @@ static int ath12k_wmi_hw_mode_caps_parse(struct ath12k_base *soc,
|
||||
static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc,
|
||||
u16 len, const void *ptr, void *data)
|
||||
{
|
||||
struct ath12k_svc_ext_info *svc_ext_info = &soc->wmi_ab.svc_ext_info;
|
||||
struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data;
|
||||
const struct ath12k_wmi_hw_mode_cap_params *hw_mode_caps;
|
||||
enum wmi_host_hw_mode_config_type mode, pref;
|
||||
@ -4427,8 +4433,11 @@ static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc,
|
||||
}
|
||||
}
|
||||
|
||||
ath12k_dbg(soc, ATH12K_DBG_WMI, "preferred_hw_mode:%d\n",
|
||||
soc->wmi_ab.preferred_hw_mode);
|
||||
svc_ext_info->num_hw_modes = svc_rdy_ext->n_hw_mode_caps;
|
||||
|
||||
ath12k_dbg(soc, ATH12K_DBG_WMI, "num hw modes %u preferred_hw_mode %d\n",
|
||||
svc_ext_info->num_hw_modes, soc->wmi_ab.preferred_hw_mode);
|
||||
|
||||
if (soc->wmi_ab.preferred_hw_mode == WMI_HOST_HW_MODE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
@ -4658,6 +4667,65 @@ free_dir_buff:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
ath12k_wmi_save_mac_phy_info(struct ath12k_base *ab,
|
||||
const struct ath12k_wmi_mac_phy_caps_params *mac_phy_cap,
|
||||
struct ath12k_svc_ext_mac_phy_info *mac_phy_info)
|
||||
{
|
||||
mac_phy_info->phy_id = __le32_to_cpu(mac_phy_cap->phy_id);
|
||||
mac_phy_info->supported_bands = __le32_to_cpu(mac_phy_cap->supported_bands);
|
||||
mac_phy_info->hw_freq_range.low_2ghz_freq =
|
||||
__le32_to_cpu(mac_phy_cap->low_2ghz_chan_freq);
|
||||
mac_phy_info->hw_freq_range.high_2ghz_freq =
|
||||
__le32_to_cpu(mac_phy_cap->high_2ghz_chan_freq);
|
||||
mac_phy_info->hw_freq_range.low_5ghz_freq =
|
||||
__le32_to_cpu(mac_phy_cap->low_5ghz_chan_freq);
|
||||
mac_phy_info->hw_freq_range.high_5ghz_freq =
|
||||
__le32_to_cpu(mac_phy_cap->high_5ghz_chan_freq);
|
||||
}
|
||||
|
||||
static void
|
||||
ath12k_wmi_save_all_mac_phy_info(struct ath12k_base *ab,
|
||||
struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext)
|
||||
{
|
||||
struct ath12k_svc_ext_info *svc_ext_info = &ab->wmi_ab.svc_ext_info;
|
||||
const struct ath12k_wmi_mac_phy_caps_params *mac_phy_cap;
|
||||
const struct ath12k_wmi_hw_mode_cap_params *hw_mode_cap;
|
||||
struct ath12k_svc_ext_mac_phy_info *mac_phy_info;
|
||||
u32 hw_mode_id, phy_bit_map;
|
||||
u8 hw_idx;
|
||||
|
||||
mac_phy_info = &svc_ext_info->mac_phy_info[0];
|
||||
mac_phy_cap = svc_rdy_ext->mac_phy_caps;
|
||||
|
||||
for (hw_idx = 0; hw_idx < svc_ext_info->num_hw_modes; hw_idx++) {
|
||||
hw_mode_cap = &svc_rdy_ext->hw_mode_caps[hw_idx];
|
||||
hw_mode_id = __le32_to_cpu(hw_mode_cap->hw_mode_id);
|
||||
phy_bit_map = __le32_to_cpu(hw_mode_cap->phy_id_map);
|
||||
|
||||
while (phy_bit_map) {
|
||||
ath12k_wmi_save_mac_phy_info(ab, mac_phy_cap, mac_phy_info);
|
||||
mac_phy_info->hw_mode_config_type =
|
||||
le32_get_bits(hw_mode_cap->hw_mode_config_type,
|
||||
WMI_HW_MODE_CAP_CFG_TYPE);
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"hw_idx %u hw_mode_id %u hw_mode_config_type %u supported_bands %u phy_id %u 2 GHz [%u - %u] 5 GHz [%u - %u]\n",
|
||||
hw_idx, hw_mode_id,
|
||||
mac_phy_info->hw_mode_config_type,
|
||||
mac_phy_info->supported_bands, mac_phy_info->phy_id,
|
||||
mac_phy_info->hw_freq_range.low_2ghz_freq,
|
||||
mac_phy_info->hw_freq_range.high_2ghz_freq,
|
||||
mac_phy_info->hw_freq_range.low_5ghz_freq,
|
||||
mac_phy_info->hw_freq_range.high_5ghz_freq);
|
||||
|
||||
mac_phy_cap++;
|
||||
mac_phy_info++;
|
||||
|
||||
phy_bit_map >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab,
|
||||
u16 tag, u16 len,
|
||||
const void *ptr, void *data)
|
||||
@ -4706,6 +4774,8 @@ static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath12k_wmi_save_all_mac_phy_info(ab, svc_rdy_ext);
|
||||
|
||||
svc_rdy_ext->mac_phy_done = true;
|
||||
} else if (!svc_rdy_ext->ext_hal_reg_done) {
|
||||
ret = ath12k_wmi_ext_hal_reg_caps(ab, len, ptr, svc_rdy_ext);
|
||||
@ -4922,10 +4992,449 @@ static int ath12k_wmi_tlv_mac_phy_caps_ext(struct ath12k_base *ab, u16 tag,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ath12k_wmi_update_freq_info(struct ath12k_base *ab,
|
||||
struct ath12k_svc_ext_mac_phy_info *mac_cap,
|
||||
enum ath12k_hw_mode mode,
|
||||
u32 phy_id)
|
||||
{
|
||||
struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info;
|
||||
struct ath12k_hw_mode_freq_range_arg *mac_range;
|
||||
|
||||
mac_range = &hw_mode_info->freq_range_caps[mode][phy_id];
|
||||
|
||||
if (mac_cap->supported_bands & WMI_HOST_WLAN_2GHZ_CAP) {
|
||||
mac_range->low_2ghz_freq = max_t(u32,
|
||||
mac_cap->hw_freq_range.low_2ghz_freq,
|
||||
ATH12K_MIN_2GHZ_FREQ);
|
||||
mac_range->high_2ghz_freq = mac_cap->hw_freq_range.high_2ghz_freq ?
|
||||
min_t(u32,
|
||||
mac_cap->hw_freq_range.high_2ghz_freq,
|
||||
ATH12K_MAX_2GHZ_FREQ) :
|
||||
ATH12K_MAX_2GHZ_FREQ;
|
||||
}
|
||||
|
||||
if (mac_cap->supported_bands & WMI_HOST_WLAN_5GHZ_CAP) {
|
||||
mac_range->low_5ghz_freq = max_t(u32,
|
||||
mac_cap->hw_freq_range.low_5ghz_freq,
|
||||
ATH12K_MIN_5GHZ_FREQ);
|
||||
mac_range->high_5ghz_freq = mac_cap->hw_freq_range.high_5ghz_freq ?
|
||||
min_t(u32,
|
||||
mac_cap->hw_freq_range.high_5ghz_freq,
|
||||
ATH12K_MAX_6GHZ_FREQ) :
|
||||
ATH12K_MAX_6GHZ_FREQ;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
ath12k_wmi_all_phy_range_updated(struct ath12k_base *ab,
|
||||
enum ath12k_hw_mode hwmode)
|
||||
{
|
||||
struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info;
|
||||
struct ath12k_hw_mode_freq_range_arg *mac_range;
|
||||
u8 phy_id;
|
||||
|
||||
for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) {
|
||||
mac_range = &hw_mode_info->freq_range_caps[hwmode][phy_id];
|
||||
/* modify SBS/DBS range only when both phy for DBS are filled */
|
||||
if (!mac_range->low_2ghz_freq && !mac_range->low_5ghz_freq)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ath12k_wmi_update_dbs_freq_info(struct ath12k_base *ab)
|
||||
{
|
||||
struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info;
|
||||
struct ath12k_hw_mode_freq_range_arg *mac_range;
|
||||
u8 phy_id;
|
||||
|
||||
mac_range = hw_mode_info->freq_range_caps[ATH12K_HW_MODE_DBS];
|
||||
/* Reset 5 GHz range for shared mac for DBS */
|
||||
for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) {
|
||||
if (mac_range[phy_id].low_2ghz_freq &&
|
||||
mac_range[phy_id].low_5ghz_freq) {
|
||||
mac_range[phy_id].low_5ghz_freq = 0;
|
||||
mac_range[phy_id].high_5ghz_freq = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u32
|
||||
ath12k_wmi_get_highest_5ghz_freq_from_range(struct ath12k_hw_mode_freq_range_arg *range)
|
||||
{
|
||||
u32 highest_freq = 0;
|
||||
u8 phy_id;
|
||||
|
||||
for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) {
|
||||
if (range[phy_id].high_5ghz_freq > highest_freq)
|
||||
highest_freq = range[phy_id].high_5ghz_freq;
|
||||
}
|
||||
|
||||
return highest_freq ? highest_freq : ATH12K_MAX_6GHZ_FREQ;
|
||||
}
|
||||
|
||||
static u32
|
||||
ath12k_wmi_get_lowest_5ghz_freq_from_range(struct ath12k_hw_mode_freq_range_arg *range)
|
||||
{
|
||||
u32 lowest_freq = 0;
|
||||
u8 phy_id;
|
||||
|
||||
for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) {
|
||||
if ((!lowest_freq && range[phy_id].low_5ghz_freq) ||
|
||||
range[phy_id].low_5ghz_freq < lowest_freq)
|
||||
lowest_freq = range[phy_id].low_5ghz_freq;
|
||||
}
|
||||
|
||||
return lowest_freq ? lowest_freq : ATH12K_MIN_5GHZ_FREQ;
|
||||
}
|
||||
|
||||
static void
|
||||
ath12k_wmi_fill_upper_share_sbs_freq(struct ath12k_base *ab,
|
||||
u16 sbs_range_sep,
|
||||
struct ath12k_hw_mode_freq_range_arg *ref_freq)
|
||||
{
|
||||
struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info;
|
||||
struct ath12k_hw_mode_freq_range_arg *upper_sbs_freq_range;
|
||||
u8 phy_id;
|
||||
|
||||
upper_sbs_freq_range =
|
||||
hw_mode_info->freq_range_caps[ATH12K_HW_MODE_SBS_UPPER_SHARE];
|
||||
|
||||
for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) {
|
||||
upper_sbs_freq_range[phy_id].low_2ghz_freq =
|
||||
ref_freq[phy_id].low_2ghz_freq;
|
||||
upper_sbs_freq_range[phy_id].high_2ghz_freq =
|
||||
ref_freq[phy_id].high_2ghz_freq;
|
||||
|
||||
/* update for shared mac */
|
||||
if (upper_sbs_freq_range[phy_id].low_2ghz_freq) {
|
||||
upper_sbs_freq_range[phy_id].low_5ghz_freq = sbs_range_sep + 10;
|
||||
upper_sbs_freq_range[phy_id].high_5ghz_freq =
|
||||
ath12k_wmi_get_highest_5ghz_freq_from_range(ref_freq);
|
||||
} else {
|
||||
upper_sbs_freq_range[phy_id].low_5ghz_freq =
|
||||
ath12k_wmi_get_lowest_5ghz_freq_from_range(ref_freq);
|
||||
upper_sbs_freq_range[phy_id].high_5ghz_freq = sbs_range_sep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ath12k_wmi_fill_lower_share_sbs_freq(struct ath12k_base *ab,
|
||||
u16 sbs_range_sep,
|
||||
struct ath12k_hw_mode_freq_range_arg *ref_freq)
|
||||
{
|
||||
struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info;
|
||||
struct ath12k_hw_mode_freq_range_arg *lower_sbs_freq_range;
|
||||
u8 phy_id;
|
||||
|
||||
lower_sbs_freq_range =
|
||||
hw_mode_info->freq_range_caps[ATH12K_HW_MODE_SBS_LOWER_SHARE];
|
||||
|
||||
for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) {
|
||||
lower_sbs_freq_range[phy_id].low_2ghz_freq =
|
||||
ref_freq[phy_id].low_2ghz_freq;
|
||||
lower_sbs_freq_range[phy_id].high_2ghz_freq =
|
||||
ref_freq[phy_id].high_2ghz_freq;
|
||||
|
||||
/* update for shared mac */
|
||||
if (lower_sbs_freq_range[phy_id].low_2ghz_freq) {
|
||||
lower_sbs_freq_range[phy_id].low_5ghz_freq =
|
||||
ath12k_wmi_get_lowest_5ghz_freq_from_range(ref_freq);
|
||||
lower_sbs_freq_range[phy_id].high_5ghz_freq = sbs_range_sep;
|
||||
} else {
|
||||
lower_sbs_freq_range[phy_id].low_5ghz_freq = sbs_range_sep + 10;
|
||||
lower_sbs_freq_range[phy_id].high_5ghz_freq =
|
||||
ath12k_wmi_get_highest_5ghz_freq_from_range(ref_freq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *ath12k_wmi_hw_mode_to_str(enum ath12k_hw_mode hw_mode)
|
||||
{
|
||||
static const char * const mode_str[] = {
|
||||
[ATH12K_HW_MODE_SMM] = "SMM",
|
||||
[ATH12K_HW_MODE_DBS] = "DBS",
|
||||
[ATH12K_HW_MODE_SBS] = "SBS",
|
||||
[ATH12K_HW_MODE_SBS_UPPER_SHARE] = "SBS_UPPER_SHARE",
|
||||
[ATH12K_HW_MODE_SBS_LOWER_SHARE] = "SBS_LOWER_SHARE",
|
||||
};
|
||||
|
||||
if (hw_mode >= ARRAY_SIZE(mode_str))
|
||||
return "Unknown";
|
||||
|
||||
return mode_str[hw_mode];
|
||||
}
|
||||
|
||||
static void
|
||||
ath12k_wmi_dump_freq_range_per_mac(struct ath12k_base *ab,
|
||||
struct ath12k_hw_mode_freq_range_arg *freq_range,
|
||||
enum ath12k_hw_mode hw_mode)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < MAX_RADIOS; i++)
|
||||
if (freq_range[i].low_2ghz_freq || freq_range[i].low_5ghz_freq)
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"frequency range: %s(%d) mac %d 2 GHz [%d - %d] 5 GHz [%d - %d]",
|
||||
ath12k_wmi_hw_mode_to_str(hw_mode),
|
||||
hw_mode, i,
|
||||
freq_range[i].low_2ghz_freq,
|
||||
freq_range[i].high_2ghz_freq,
|
||||
freq_range[i].low_5ghz_freq,
|
||||
freq_range[i].high_5ghz_freq);
|
||||
}
|
||||
|
||||
static void ath12k_wmi_dump_freq_range(struct ath12k_base *ab)
|
||||
{
|
||||
struct ath12k_hw_mode_freq_range_arg *freq_range;
|
||||
u8 i;
|
||||
|
||||
for (i = ATH12K_HW_MODE_SMM; i < ATH12K_HW_MODE_MAX; i++) {
|
||||
freq_range = ab->wmi_ab.hw_mode_info.freq_range_caps[i];
|
||||
ath12k_wmi_dump_freq_range_per_mac(ab, freq_range, i);
|
||||
}
|
||||
}
|
||||
|
||||
static int ath12k_wmi_modify_sbs_freq(struct ath12k_base *ab, u8 phy_id)
|
||||
{
|
||||
struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info;
|
||||
struct ath12k_hw_mode_freq_range_arg *sbs_mac_range, *shared_mac_range;
|
||||
struct ath12k_hw_mode_freq_range_arg *non_shared_range;
|
||||
u8 shared_phy_id;
|
||||
|
||||
sbs_mac_range = &hw_mode_info->freq_range_caps[ATH12K_HW_MODE_SBS][phy_id];
|
||||
|
||||
/* if SBS mac range has both 2.4 and 5 GHz ranges, i.e. shared phy_id
|
||||
* keep the range as it is in SBS
|
||||
*/
|
||||
if (sbs_mac_range->low_2ghz_freq && sbs_mac_range->low_5ghz_freq)
|
||||
return 0;
|
||||
|
||||
if (sbs_mac_range->low_2ghz_freq && !sbs_mac_range->low_5ghz_freq) {
|
||||
ath12k_err(ab, "Invalid DBS/SBS mode with only 2.4Ghz");
|
||||
ath12k_wmi_dump_freq_range_per_mac(ab, sbs_mac_range, ATH12K_HW_MODE_SBS);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
non_shared_range = sbs_mac_range;
|
||||
/* if SBS mac range has only 5 GHz then it's the non-shared phy, so
|
||||
* modify the range as per the shared mac.
|
||||
*/
|
||||
shared_phy_id = phy_id ? 0 : 1;
|
||||
shared_mac_range =
|
||||
&hw_mode_info->freq_range_caps[ATH12K_HW_MODE_SBS][shared_phy_id];
|
||||
|
||||
if (shared_mac_range->low_5ghz_freq > non_shared_range->low_5ghz_freq) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI, "high 5 GHz shared");
|
||||
/* If the shared mac lower 5 GHz frequency is greater than
|
||||
* non-shared mac lower 5 GHz frequency then the shared mac has
|
||||
* high 5 GHz shared with 2.4 GHz. So non-shared mac's 5 GHz high
|
||||
* freq should be less than the shared mac's low 5 GHz freq.
|
||||
*/
|
||||
if (non_shared_range->high_5ghz_freq >=
|
||||
shared_mac_range->low_5ghz_freq)
|
||||
non_shared_range->high_5ghz_freq =
|
||||
max_t(u32, shared_mac_range->low_5ghz_freq - 10,
|
||||
non_shared_range->low_5ghz_freq);
|
||||
} else if (shared_mac_range->high_5ghz_freq <
|
||||
non_shared_range->high_5ghz_freq) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI, "low 5 GHz shared");
|
||||
/* If the shared mac high 5 GHz frequency is less than
|
||||
* non-shared mac high 5 GHz frequency then the shared mac has
|
||||
* low 5 GHz shared with 2.4 GHz. So non-shared mac's 5 GHz low
|
||||
* freq should be greater than the shared mac's high 5 GHz freq.
|
||||
*/
|
||||
if (shared_mac_range->high_5ghz_freq >=
|
||||
non_shared_range->low_5ghz_freq)
|
||||
non_shared_range->low_5ghz_freq =
|
||||
min_t(u32, shared_mac_range->high_5ghz_freq + 10,
|
||||
non_shared_range->high_5ghz_freq);
|
||||
} else {
|
||||
ath12k_warn(ab, "invalid SBS range with all 5 GHz shared");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath12k_wmi_update_sbs_freq_info(struct ath12k_base *ab)
|
||||
{
|
||||
struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info;
|
||||
struct ath12k_hw_mode_freq_range_arg *mac_range;
|
||||
u16 sbs_range_sep;
|
||||
u8 phy_id;
|
||||
int ret;
|
||||
|
||||
mac_range = hw_mode_info->freq_range_caps[ATH12K_HW_MODE_SBS];
|
||||
|
||||
/* If sbs_lower_band_end_freq has a value, then the frequency range
|
||||
* will be split using that value.
|
||||
*/
|
||||
sbs_range_sep = ab->wmi_ab.sbs_lower_band_end_freq;
|
||||
if (sbs_range_sep) {
|
||||
ath12k_wmi_fill_upper_share_sbs_freq(ab, sbs_range_sep,
|
||||
mac_range);
|
||||
ath12k_wmi_fill_lower_share_sbs_freq(ab, sbs_range_sep,
|
||||
mac_range);
|
||||
/* Hardware specifies the range boundary with sbs_range_sep,
|
||||
* (i.e. the boundary between 5 GHz high and 5 GHz low),
|
||||
* reset the original one to make sure it will not get used.
|
||||
*/
|
||||
memset(mac_range, 0, sizeof(*mac_range) * MAX_RADIOS);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If sbs_lower_band_end_freq is not set that means firmware will send one
|
||||
* shared mac range and one non-shared mac range. so update that freq.
|
||||
*/
|
||||
for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) {
|
||||
ret = ath12k_wmi_modify_sbs_freq(ab, phy_id);
|
||||
if (ret) {
|
||||
memset(mac_range, 0, sizeof(*mac_range) * MAX_RADIOS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ath12k_wmi_update_mac_freq_info(struct ath12k_base *ab,
|
||||
enum wmi_host_hw_mode_config_type hw_config_type,
|
||||
u32 phy_id,
|
||||
struct ath12k_svc_ext_mac_phy_info *mac_cap)
|
||||
{
|
||||
if (phy_id >= MAX_RADIOS) {
|
||||
ath12k_err(ab, "mac more than two not supported: %d", phy_id);
|
||||
return;
|
||||
}
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"hw_mode_cfg %d mac %d band 0x%x SBS cutoff freq %d 2 GHz [%d - %d] 5 GHz [%d - %d]",
|
||||
hw_config_type, phy_id, mac_cap->supported_bands,
|
||||
ab->wmi_ab.sbs_lower_band_end_freq,
|
||||
mac_cap->hw_freq_range.low_2ghz_freq,
|
||||
mac_cap->hw_freq_range.high_2ghz_freq,
|
||||
mac_cap->hw_freq_range.low_5ghz_freq,
|
||||
mac_cap->hw_freq_range.high_5ghz_freq);
|
||||
|
||||
switch (hw_config_type) {
|
||||
case WMI_HOST_HW_MODE_SINGLE:
|
||||
if (phy_id) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI, "mac phy 1 is not supported");
|
||||
break;
|
||||
}
|
||||
ath12k_wmi_update_freq_info(ab, mac_cap, ATH12K_HW_MODE_SMM, phy_id);
|
||||
break;
|
||||
|
||||
case WMI_HOST_HW_MODE_DBS:
|
||||
if (!ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_DBS))
|
||||
ath12k_wmi_update_freq_info(ab, mac_cap,
|
||||
ATH12K_HW_MODE_DBS, phy_id);
|
||||
break;
|
||||
case WMI_HOST_HW_MODE_DBS_SBS:
|
||||
case WMI_HOST_HW_MODE_DBS_OR_SBS:
|
||||
ath12k_wmi_update_freq_info(ab, mac_cap, ATH12K_HW_MODE_DBS, phy_id);
|
||||
if (ab->wmi_ab.sbs_lower_band_end_freq ||
|
||||
mac_cap->hw_freq_range.low_5ghz_freq ||
|
||||
mac_cap->hw_freq_range.low_2ghz_freq)
|
||||
ath12k_wmi_update_freq_info(ab, mac_cap, ATH12K_HW_MODE_SBS,
|
||||
phy_id);
|
||||
|
||||
if (ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_DBS))
|
||||
ath12k_wmi_update_dbs_freq_info(ab);
|
||||
if (ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_SBS))
|
||||
ath12k_wmi_update_sbs_freq_info(ab);
|
||||
break;
|
||||
case WMI_HOST_HW_MODE_SBS:
|
||||
case WMI_HOST_HW_MODE_SBS_PASSIVE:
|
||||
ath12k_wmi_update_freq_info(ab, mac_cap, ATH12K_HW_MODE_SBS, phy_id);
|
||||
if (ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_SBS))
|
||||
ath12k_wmi_update_sbs_freq_info(ab);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ath12k_wmi_sbs_range_present(struct ath12k_base *ab)
|
||||
{
|
||||
if (ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_SBS) ||
|
||||
(ab->wmi_ab.sbs_lower_band_end_freq &&
|
||||
ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_SBS_LOWER_SHARE) &&
|
||||
ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_SBS_UPPER_SHARE)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int ath12k_wmi_update_hw_mode_list(struct ath12k_base *ab)
|
||||
{
|
||||
struct ath12k_svc_ext_info *svc_ext_info = &ab->wmi_ab.svc_ext_info;
|
||||
struct ath12k_hw_mode_info *info = &ab->wmi_ab.hw_mode_info;
|
||||
enum wmi_host_hw_mode_config_type hw_config_type;
|
||||
struct ath12k_svc_ext_mac_phy_info *tmp;
|
||||
bool dbs_mode = false, sbs_mode = false;
|
||||
u32 i, j = 0;
|
||||
|
||||
if (!svc_ext_info->num_hw_modes) {
|
||||
ath12k_err(ab, "invalid number of hw modes");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI, "updated HW mode list: num modes %d",
|
||||
svc_ext_info->num_hw_modes);
|
||||
|
||||
memset(info->freq_range_caps, 0, sizeof(info->freq_range_caps));
|
||||
|
||||
for (i = 0; i < svc_ext_info->num_hw_modes; i++) {
|
||||
if (j >= ATH12K_MAX_MAC_PHY_CAP)
|
||||
return -EINVAL;
|
||||
|
||||
/* Update for MAC0 */
|
||||
tmp = &svc_ext_info->mac_phy_info[j++];
|
||||
hw_config_type = tmp->hw_mode_config_type;
|
||||
ath12k_wmi_update_mac_freq_info(ab, hw_config_type, tmp->phy_id, tmp);
|
||||
|
||||
/* SBS and DBS have dual MAC. Up to 2 MACs are considered. */
|
||||
if (hw_config_type == WMI_HOST_HW_MODE_DBS ||
|
||||
hw_config_type == WMI_HOST_HW_MODE_SBS_PASSIVE ||
|
||||
hw_config_type == WMI_HOST_HW_MODE_SBS ||
|
||||
hw_config_type == WMI_HOST_HW_MODE_DBS_OR_SBS) {
|
||||
if (j >= ATH12K_MAX_MAC_PHY_CAP)
|
||||
return -EINVAL;
|
||||
/* Update for MAC1 */
|
||||
tmp = &svc_ext_info->mac_phy_info[j++];
|
||||
ath12k_wmi_update_mac_freq_info(ab, hw_config_type,
|
||||
tmp->phy_id, tmp);
|
||||
|
||||
if (hw_config_type == WMI_HOST_HW_MODE_DBS ||
|
||||
hw_config_type == WMI_HOST_HW_MODE_DBS_OR_SBS)
|
||||
dbs_mode = true;
|
||||
|
||||
if (ath12k_wmi_sbs_range_present(ab) &&
|
||||
(hw_config_type == WMI_HOST_HW_MODE_SBS_PASSIVE ||
|
||||
hw_config_type == WMI_HOST_HW_MODE_SBS ||
|
||||
hw_config_type == WMI_HOST_HW_MODE_DBS_OR_SBS))
|
||||
sbs_mode = true;
|
||||
}
|
||||
}
|
||||
|
||||
info->support_dbs = dbs_mode;
|
||||
info->support_sbs = sbs_mode;
|
||||
|
||||
ath12k_wmi_dump_freq_range(ab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab,
|
||||
u16 tag, u16 len,
|
||||
const void *ptr, void *data)
|
||||
{
|
||||
const struct ath12k_wmi_dbs_or_sbs_cap_params *dbs_or_sbs_caps;
|
||||
struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0];
|
||||
struct ath12k_wmi_svc_rdy_ext2_parse *parse = data;
|
||||
int ret;
|
||||
@ -4967,7 +5476,32 @@ static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab,
|
||||
}
|
||||
|
||||
parse->mac_phy_caps_ext_done = true;
|
||||
} else if (!parse->hal_reg_caps_ext2_done) {
|
||||
parse->hal_reg_caps_ext2_done = true;
|
||||
} else if (!parse->scan_radio_caps_ext2_done) {
|
||||
parse->scan_radio_caps_ext2_done = true;
|
||||
} else if (!parse->twt_caps_done) {
|
||||
parse->twt_caps_done = true;
|
||||
} else if (!parse->htt_msdu_idx_to_qtype_map_done) {
|
||||
parse->htt_msdu_idx_to_qtype_map_done = true;
|
||||
} else if (!parse->dbs_or_sbs_cap_ext_done) {
|
||||
dbs_or_sbs_caps = ptr;
|
||||
ab->wmi_ab.sbs_lower_band_end_freq =
|
||||
__le32_to_cpu(dbs_or_sbs_caps->sbs_lower_band_end_freq);
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI, "sbs_lower_band_end_freq %u\n",
|
||||
ab->wmi_ab.sbs_lower_band_end_freq);
|
||||
|
||||
ret = ath12k_wmi_update_hw_mode_list(ab);
|
||||
if (ret) {
|
||||
ath12k_warn(ab, "failed to update hw mode list: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
parse->dbs_or_sbs_cap_ext_done = true;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -7626,6 +8160,64 @@ static int ath12k_wmi_pull_fw_stats(struct ath12k_base *ab, struct sk_buff *skb,
|
||||
&parse);
|
||||
}
|
||||
|
||||
static void ath12k_wmi_fw_stats_process(struct ath12k *ar,
|
||||
struct ath12k_fw_stats *stats)
|
||||
{
|
||||
struct ath12k_base *ab = ar->ab;
|
||||
struct ath12k_pdev *pdev;
|
||||
bool is_end = true;
|
||||
size_t total_vdevs_started = 0;
|
||||
int i;
|
||||
|
||||
if (stats->stats_id == WMI_REQUEST_VDEV_STAT) {
|
||||
if (list_empty(&stats->vdevs)) {
|
||||
ath12k_warn(ab, "empty vdev stats");
|
||||
return;
|
||||
}
|
||||
/* FW sends all the active VDEV stats irrespective of PDEV,
|
||||
* hence limit until the count of all VDEVs started
|
||||
*/
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < ab->num_radios; i++) {
|
||||
pdev = rcu_dereference(ab->pdevs_active[i]);
|
||||
if (pdev && pdev->ar)
|
||||
total_vdevs_started += pdev->ar->num_started_vdevs;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (total_vdevs_started)
|
||||
is_end = ((++ar->fw_stats.num_vdev_recvd) ==
|
||||
total_vdevs_started);
|
||||
|
||||
list_splice_tail_init(&stats->vdevs,
|
||||
&ar->fw_stats.vdevs);
|
||||
|
||||
if (is_end)
|
||||
complete(&ar->fw_stats_done);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (stats->stats_id == WMI_REQUEST_BCN_STAT) {
|
||||
if (list_empty(&stats->bcn)) {
|
||||
ath12k_warn(ab, "empty beacon stats");
|
||||
return;
|
||||
}
|
||||
/* Mark end until we reached the count of all started VDEVs
|
||||
* within the PDEV
|
||||
*/
|
||||
if (ar->num_started_vdevs)
|
||||
is_end = ((++ar->fw_stats.num_bcn_recvd) ==
|
||||
ar->num_started_vdevs);
|
||||
|
||||
list_splice_tail_init(&stats->bcn,
|
||||
&ar->fw_stats.bcn);
|
||||
|
||||
if (is_end)
|
||||
complete(&ar->fw_stats_done);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath12k_update_stats_event(struct ath12k_base *ab, struct sk_buff *skb)
|
||||
{
|
||||
struct ath12k_fw_stats stats = {};
|
||||
@ -7655,19 +8247,15 @@ static void ath12k_update_stats_event(struct ath12k_base *ab, struct sk_buff *sk
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
/* WMI_REQUEST_PDEV_STAT can be requested via .get_txpower mac ops or via
|
||||
* debugfs fw stats. Therefore, processing it separately.
|
||||
*/
|
||||
/* Handle WMI_REQUEST_PDEV_STAT status update */
|
||||
if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
|
||||
list_splice_tail_init(&stats.pdevs, &ar->fw_stats.pdevs);
|
||||
ar->fw_stats.fw_stats_done = true;
|
||||
complete(&ar->fw_stats_done);
|
||||
goto complete;
|
||||
}
|
||||
|
||||
/* WMI_REQUEST_VDEV_STAT and WMI_REQUEST_BCN_STAT are currently requested only
|
||||
* via debugfs fw stats. Hence, processing these in debugfs context.
|
||||
*/
|
||||
ath12k_debugfs_fw_stats_process(ar, &stats);
|
||||
/* Handle WMI_REQUEST_VDEV_STAT and WMI_REQUEST_BCN_STAT updates. */
|
||||
ath12k_wmi_fw_stats_process(ar, &stats);
|
||||
|
||||
complete:
|
||||
complete(&ar->fw_stats_complete);
|
||||
@ -9911,3 +10499,224 @@ int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ath12k_wmi_fill_disallowed_bmap(struct ath12k_base *ab,
|
||||
struct wmi_disallowed_mlo_mode_bitmap_params *dislw_bmap,
|
||||
struct wmi_mlo_link_set_active_arg *arg)
|
||||
{
|
||||
struct wmi_ml_disallow_mode_bmap_arg *dislw_bmap_arg;
|
||||
u8 i;
|
||||
|
||||
if (arg->num_disallow_mode_comb >
|
||||
ARRAY_SIZE(arg->disallow_bmap)) {
|
||||
ath12k_warn(ab, "invalid num_disallow_mode_comb: %d",
|
||||
arg->num_disallow_mode_comb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dislw_bmap_arg = &arg->disallow_bmap[0];
|
||||
for (i = 0; i < arg->num_disallow_mode_comb; i++) {
|
||||
dislw_bmap->tlv_header =
|
||||
ath12k_wmi_tlv_cmd_hdr(0, sizeof(*dislw_bmap));
|
||||
dislw_bmap->disallowed_mode_bitmap =
|
||||
cpu_to_le32(dislw_bmap_arg->disallowed_mode);
|
||||
dislw_bmap->ieee_link_id_comb =
|
||||
le32_encode_bits(dislw_bmap_arg->ieee_link_id[0],
|
||||
WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_1) |
|
||||
le32_encode_bits(dislw_bmap_arg->ieee_link_id[1],
|
||||
WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_2) |
|
||||
le32_encode_bits(dislw_bmap_arg->ieee_link_id[2],
|
||||
WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_3) |
|
||||
le32_encode_bits(dislw_bmap_arg->ieee_link_id[3],
|
||||
WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_4);
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"entry %d disallowed_mode %d ieee_link_id_comb 0x%x",
|
||||
i, dislw_bmap_arg->disallowed_mode,
|
||||
dislw_bmap_arg->ieee_link_id_comb);
|
||||
dislw_bmap++;
|
||||
dislw_bmap_arg++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath12k_wmi_send_mlo_link_set_active_cmd(struct ath12k_base *ab,
|
||||
struct wmi_mlo_link_set_active_arg *arg)
|
||||
{
|
||||
struct wmi_disallowed_mlo_mode_bitmap_params *disallowed_mode_bmap;
|
||||
struct wmi_mlo_set_active_link_number_params *link_num_param;
|
||||
u32 num_link_num_param = 0, num_vdev_bitmap = 0;
|
||||
struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
|
||||
struct wmi_mlo_link_set_active_cmd *cmd;
|
||||
u32 num_inactive_vdev_bitmap = 0;
|
||||
u32 num_disallow_mode_comb = 0;
|
||||
struct wmi_tlv *tlv;
|
||||
struct sk_buff *skb;
|
||||
__le32 *vdev_bitmap;
|
||||
void *buf_ptr;
|
||||
int i, ret;
|
||||
u32 len;
|
||||
|
||||
if (!arg->num_vdev_bitmap && !arg->num_link_entry) {
|
||||
ath12k_warn(ab, "Invalid num_vdev_bitmap and num_link_entry");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (arg->force_mode) {
|
||||
case WMI_MLO_LINK_FORCE_MODE_ACTIVE_LINK_NUM:
|
||||
case WMI_MLO_LINK_FORCE_MODE_INACTIVE_LINK_NUM:
|
||||
num_link_num_param = arg->num_link_entry;
|
||||
fallthrough;
|
||||
case WMI_MLO_LINK_FORCE_MODE_ACTIVE:
|
||||
case WMI_MLO_LINK_FORCE_MODE_INACTIVE:
|
||||
case WMI_MLO_LINK_FORCE_MODE_NO_FORCE:
|
||||
num_vdev_bitmap = arg->num_vdev_bitmap;
|
||||
break;
|
||||
case WMI_MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE:
|
||||
num_vdev_bitmap = arg->num_vdev_bitmap;
|
||||
num_inactive_vdev_bitmap = arg->num_inactive_vdev_bitmap;
|
||||
break;
|
||||
default:
|
||||
ath12k_warn(ab, "Invalid force mode: %u", arg->force_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
num_disallow_mode_comb = arg->num_disallow_mode_comb;
|
||||
len = sizeof(*cmd) +
|
||||
TLV_HDR_SIZE + sizeof(*link_num_param) * num_link_num_param +
|
||||
TLV_HDR_SIZE + sizeof(*vdev_bitmap) * num_vdev_bitmap +
|
||||
TLV_HDR_SIZE + TLV_HDR_SIZE + TLV_HDR_SIZE +
|
||||
TLV_HDR_SIZE + sizeof(*disallowed_mode_bmap) * num_disallow_mode_comb;
|
||||
if (arg->force_mode == WMI_MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE)
|
||||
len += sizeof(*vdev_bitmap) * num_inactive_vdev_bitmap;
|
||||
|
||||
skb = ath12k_wmi_alloc_skb(wmi_ab, len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct wmi_mlo_link_set_active_cmd *)skb->data;
|
||||
cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_LINK_SET_ACTIVE_CMD,
|
||||
sizeof(*cmd));
|
||||
cmd->force_mode = cpu_to_le32(arg->force_mode);
|
||||
cmd->reason = cpu_to_le32(arg->reason);
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"mode %d reason %d num_link_num_param %d num_vdev_bitmap %d inactive %d num_disallow_mode_comb %d",
|
||||
arg->force_mode, arg->reason, num_link_num_param,
|
||||
num_vdev_bitmap, num_inactive_vdev_bitmap,
|
||||
num_disallow_mode_comb);
|
||||
|
||||
buf_ptr = skb->data + sizeof(*cmd);
|
||||
tlv = buf_ptr;
|
||||
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT,
|
||||
sizeof(*link_num_param) * num_link_num_param);
|
||||
buf_ptr += TLV_HDR_SIZE;
|
||||
|
||||
if (num_link_num_param) {
|
||||
cmd->ctrl_flags =
|
||||
le32_encode_bits(arg->ctrl_flags.dync_force_link_num ? 1 : 0,
|
||||
CRTL_F_DYNC_FORCE_LINK_NUM);
|
||||
|
||||
link_num_param = buf_ptr;
|
||||
for (i = 0; i < num_link_num_param; i++) {
|
||||
link_num_param->tlv_header =
|
||||
ath12k_wmi_tlv_cmd_hdr(0, sizeof(*link_num_param));
|
||||
link_num_param->num_of_link =
|
||||
cpu_to_le32(arg->link_num[i].num_of_link);
|
||||
link_num_param->vdev_type =
|
||||
cpu_to_le32(arg->link_num[i].vdev_type);
|
||||
link_num_param->vdev_subtype =
|
||||
cpu_to_le32(arg->link_num[i].vdev_subtype);
|
||||
link_num_param->home_freq =
|
||||
cpu_to_le32(arg->link_num[i].home_freq);
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"entry %d num_of_link %d vdev type %d subtype %d freq %d control_flags %d",
|
||||
i, arg->link_num[i].num_of_link,
|
||||
arg->link_num[i].vdev_type,
|
||||
arg->link_num[i].vdev_subtype,
|
||||
arg->link_num[i].home_freq,
|
||||
__le32_to_cpu(cmd->ctrl_flags));
|
||||
link_num_param++;
|
||||
}
|
||||
|
||||
buf_ptr += sizeof(*link_num_param) * num_link_num_param;
|
||||
}
|
||||
|
||||
tlv = buf_ptr;
|
||||
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32,
|
||||
sizeof(*vdev_bitmap) * num_vdev_bitmap);
|
||||
buf_ptr += TLV_HDR_SIZE;
|
||||
|
||||
if (num_vdev_bitmap) {
|
||||
vdev_bitmap = buf_ptr;
|
||||
for (i = 0; i < num_vdev_bitmap; i++) {
|
||||
vdev_bitmap[i] = cpu_to_le32(arg->vdev_bitmap[i]);
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI, "entry %d vdev_id_bitmap 0x%x",
|
||||
i, arg->vdev_bitmap[i]);
|
||||
}
|
||||
|
||||
buf_ptr += sizeof(*vdev_bitmap) * num_vdev_bitmap;
|
||||
}
|
||||
|
||||
if (arg->force_mode == WMI_MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE) {
|
||||
tlv = buf_ptr;
|
||||
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32,
|
||||
sizeof(*vdev_bitmap) *
|
||||
num_inactive_vdev_bitmap);
|
||||
buf_ptr += TLV_HDR_SIZE;
|
||||
|
||||
if (num_inactive_vdev_bitmap) {
|
||||
vdev_bitmap = buf_ptr;
|
||||
for (i = 0; i < num_inactive_vdev_bitmap; i++) {
|
||||
vdev_bitmap[i] =
|
||||
cpu_to_le32(arg->inactive_vdev_bitmap[i]);
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"entry %d inactive_vdev_id_bitmap 0x%x",
|
||||
i, arg->inactive_vdev_bitmap[i]);
|
||||
}
|
||||
|
||||
buf_ptr += sizeof(*vdev_bitmap) * num_inactive_vdev_bitmap;
|
||||
}
|
||||
} else {
|
||||
/* add empty vdev bitmap2 tlv */
|
||||
tlv = buf_ptr;
|
||||
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, 0);
|
||||
buf_ptr += TLV_HDR_SIZE;
|
||||
}
|
||||
|
||||
/* add empty ieee_link_id_bitmap tlv */
|
||||
tlv = buf_ptr;
|
||||
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, 0);
|
||||
buf_ptr += TLV_HDR_SIZE;
|
||||
|
||||
/* add empty ieee_link_id_bitmap2 tlv */
|
||||
tlv = buf_ptr;
|
||||
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, 0);
|
||||
buf_ptr += TLV_HDR_SIZE;
|
||||
|
||||
tlv = buf_ptr;
|
||||
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT,
|
||||
sizeof(*disallowed_mode_bmap) *
|
||||
arg->num_disallow_mode_comb);
|
||||
buf_ptr += TLV_HDR_SIZE;
|
||||
|
||||
ret = ath12k_wmi_fill_disallowed_bmap(ab, buf_ptr, arg);
|
||||
if (ret)
|
||||
goto free_skb;
|
||||
|
||||
ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_MLO_LINK_SET_ACTIVE_CMDID);
|
||||
if (ret) {
|
||||
ath12k_warn(ab,
|
||||
"failed to send WMI_MLO_LINK_SET_ACTIVE_CMDID: %d\n", ret);
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI, "WMI mlo link set active cmd");
|
||||
|
||||
return ret;
|
||||
|
||||
free_skb:
|
||||
dev_kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1974,6 +1974,7 @@ enum wmi_tlv_tag {
|
||||
WMI_TAG_TPC_STATS_CTL_PWR_TABLE_EVENT,
|
||||
WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5,
|
||||
WMI_TAG_VDEV_CH_POWER_INFO,
|
||||
WMI_TAG_MLO_LINK_SET_ACTIVE_CMD = 0x3BE,
|
||||
WMI_TAG_EHT_RATE_SET = 0x3C4,
|
||||
WMI_TAG_DCS_AWGN_INT_TYPE = 0x3C5,
|
||||
WMI_TAG_MLO_TX_SEND_PARAMS,
|
||||
@ -2617,6 +2618,8 @@ struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params {
|
||||
__le32 num_chainmask_tables;
|
||||
} __packed;
|
||||
|
||||
#define WMI_HW_MODE_CAP_CFG_TYPE GENMASK(27, 0)
|
||||
|
||||
struct ath12k_wmi_hw_mode_cap_params {
|
||||
__le32 tlv_header;
|
||||
__le32 hw_mode_id;
|
||||
@ -2666,6 +2669,12 @@ struct ath12k_wmi_mac_phy_caps_params {
|
||||
__le32 he_cap_info_2g_ext;
|
||||
__le32 he_cap_info_5g_ext;
|
||||
__le32 he_cap_info_internal;
|
||||
__le32 wireless_modes;
|
||||
__le32 low_2ghz_chan_freq;
|
||||
__le32 high_2ghz_chan_freq;
|
||||
__le32 low_5ghz_chan_freq;
|
||||
__le32 high_5ghz_chan_freq;
|
||||
__le32 nss_ratio;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_hal_reg_caps_ext_params {
|
||||
@ -2739,6 +2748,11 @@ struct wmi_service_ready_ext2_event {
|
||||
__le32 default_num_msduq_supported_per_tid;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_dbs_or_sbs_cap_params {
|
||||
__le32 hw_mode_id;
|
||||
__le32 sbs_lower_band_end_freq;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_caps_ext_params {
|
||||
__le32 hw_mode_id;
|
||||
__le32 pdev_and_hw_link_ids;
|
||||
@ -5049,6 +5063,53 @@ struct ath12k_wmi_pdev {
|
||||
u32 rx_decap_mode;
|
||||
};
|
||||
|
||||
struct ath12k_hw_mode_freq_range_arg {
|
||||
u32 low_2ghz_freq;
|
||||
u32 high_2ghz_freq;
|
||||
u32 low_5ghz_freq;
|
||||
u32 high_5ghz_freq;
|
||||
};
|
||||
|
||||
struct ath12k_svc_ext_mac_phy_info {
|
||||
enum wmi_host_hw_mode_config_type hw_mode_config_type;
|
||||
u32 phy_id;
|
||||
u32 supported_bands;
|
||||
struct ath12k_hw_mode_freq_range_arg hw_freq_range;
|
||||
};
|
||||
|
||||
#define ATH12K_MAX_MAC_PHY_CAP 8
|
||||
|
||||
struct ath12k_svc_ext_info {
|
||||
u32 num_hw_modes;
|
||||
struct ath12k_svc_ext_mac_phy_info mac_phy_info[ATH12K_MAX_MAC_PHY_CAP];
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ath12k_hw_mode - enum for host mode
|
||||
* @ATH12K_HW_MODE_SMM: Single mac mode
|
||||
* @ATH12K_HW_MODE_DBS: DBS mode
|
||||
* @ATH12K_HW_MODE_SBS: SBS mode with either high share or low share
|
||||
* @ATH12K_HW_MODE_SBS_UPPER_SHARE: Higher 5 GHz shared with 2.4 GHz
|
||||
* @ATH12K_HW_MODE_SBS_LOWER_SHARE: Lower 5 GHz shared with 2.4 GHz
|
||||
* @ATH12K_HW_MODE_MAX: Max, used to indicate invalid mode
|
||||
*/
|
||||
enum ath12k_hw_mode {
|
||||
ATH12K_HW_MODE_SMM,
|
||||
ATH12K_HW_MODE_DBS,
|
||||
ATH12K_HW_MODE_SBS,
|
||||
ATH12K_HW_MODE_SBS_UPPER_SHARE,
|
||||
ATH12K_HW_MODE_SBS_LOWER_SHARE,
|
||||
ATH12K_HW_MODE_MAX,
|
||||
};
|
||||
|
||||
struct ath12k_hw_mode_info {
|
||||
bool support_dbs:1;
|
||||
bool support_sbs:1;
|
||||
|
||||
struct ath12k_hw_mode_freq_range_arg freq_range_caps[ATH12K_HW_MODE_MAX]
|
||||
[MAX_RADIOS];
|
||||
};
|
||||
|
||||
struct ath12k_wmi_base {
|
||||
struct ath12k_base *ab;
|
||||
struct ath12k_wmi_pdev wmi[MAX_RADIOS];
|
||||
@ -5066,6 +5127,10 @@ struct ath12k_wmi_base {
|
||||
enum wmi_host_hw_mode_config_type preferred_hw_mode;
|
||||
|
||||
struct ath12k_wmi_target_cap_arg *targ_cap;
|
||||
|
||||
struct ath12k_svc_ext_info svc_ext_info;
|
||||
u32 sbs_lower_band_end_freq;
|
||||
struct ath12k_hw_mode_info hw_mode_info;
|
||||
};
|
||||
|
||||
struct wmi_pdev_set_bios_interface_cmd {
|
||||
@ -5997,6 +6062,118 @@ struct wmi_vdev_set_tpc_power_cmd {
|
||||
*/
|
||||
} __packed;
|
||||
|
||||
#define CRTL_F_DYNC_FORCE_LINK_NUM GENMASK(3, 2)
|
||||
|
||||
struct wmi_mlo_link_set_active_cmd {
|
||||
__le32 tlv_header;
|
||||
__le32 force_mode;
|
||||
__le32 reason;
|
||||
__le32 use_ieee_link_id_bitmap;
|
||||
struct ath12k_wmi_mac_addr_params ap_mld_mac_addr;
|
||||
__le32 ctrl_flags;
|
||||
} __packed;
|
||||
|
||||
struct wmi_mlo_set_active_link_number_params {
|
||||
__le32 tlv_header;
|
||||
__le32 num_of_link;
|
||||
__le32 vdev_type;
|
||||
__le32 vdev_subtype;
|
||||
__le32 home_freq;
|
||||
} __packed;
|
||||
|
||||
#define WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_1 GENMASK(7, 0)
|
||||
#define WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_2 GENMASK(15, 8)
|
||||
#define WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_3 GENMASK(23, 16)
|
||||
#define WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_4 GENMASK(31, 24)
|
||||
|
||||
struct wmi_disallowed_mlo_mode_bitmap_params {
|
||||
__le32 tlv_header;
|
||||
__le32 disallowed_mode_bitmap;
|
||||
__le32 ieee_link_id_comb;
|
||||
} __packed;
|
||||
|
||||
enum wmi_mlo_link_force_mode {
|
||||
WMI_MLO_LINK_FORCE_MODE_ACTIVE = 1,
|
||||
WMI_MLO_LINK_FORCE_MODE_INACTIVE = 2,
|
||||
WMI_MLO_LINK_FORCE_MODE_ACTIVE_LINK_NUM = 3,
|
||||
WMI_MLO_LINK_FORCE_MODE_INACTIVE_LINK_NUM = 4,
|
||||
WMI_MLO_LINK_FORCE_MODE_NO_FORCE = 5,
|
||||
WMI_MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE = 6,
|
||||
WMI_MLO_LINK_FORCE_MODE_NON_FORCE_UPDATE = 7,
|
||||
};
|
||||
|
||||
enum wmi_mlo_link_force_reason {
|
||||
WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT = 1,
|
||||
WMI_MLO_LINK_FORCE_REASON_NEW_DISCONNECT = 2,
|
||||
WMI_MLO_LINK_FORCE_REASON_LINK_REMOVAL = 3,
|
||||
WMI_MLO_LINK_FORCE_REASON_TDLS = 4,
|
||||
WMI_MLO_LINK_FORCE_REASON_REVERT_FAILURE = 5,
|
||||
WMI_MLO_LINK_FORCE_REASON_LINK_DELETE = 6,
|
||||
WMI_MLO_LINK_FORCE_REASON_SINGLE_LINK_EMLSR_OP = 7,
|
||||
};
|
||||
|
||||
struct wmi_mlo_link_num_arg {
|
||||
u32 num_of_link;
|
||||
u32 vdev_type;
|
||||
u32 vdev_subtype;
|
||||
u32 home_freq;
|
||||
};
|
||||
|
||||
struct wmi_mlo_control_flags_arg {
|
||||
bool overwrite_force_active_bitmap;
|
||||
bool overwrite_force_inactive_bitmap;
|
||||
bool dync_force_link_num;
|
||||
bool post_re_evaluate;
|
||||
u8 post_re_evaluate_loops;
|
||||
bool dont_reschedule_workqueue;
|
||||
};
|
||||
|
||||
struct wmi_ml_link_force_cmd_arg {
|
||||
u8 ap_mld_mac_addr[ETH_ALEN];
|
||||
u16 ieee_link_id_bitmap;
|
||||
u16 ieee_link_id_bitmap2;
|
||||
u8 link_num;
|
||||
};
|
||||
|
||||
struct wmi_ml_disallow_mode_bmap_arg {
|
||||
u32 disallowed_mode;
|
||||
union {
|
||||
u32 ieee_link_id_comb;
|
||||
u8 ieee_link_id[4];
|
||||
};
|
||||
};
|
||||
|
||||
/* maximum size of link number param array
|
||||
* for MLO link set active command
|
||||
*/
|
||||
#define WMI_MLO_LINK_NUM_SZ 2
|
||||
|
||||
/* maximum size of vdev bitmap array for
|
||||
* MLO link set active command
|
||||
*/
|
||||
#define WMI_MLO_VDEV_BITMAP_SZ 2
|
||||
|
||||
/* Max number of disallowed bitmap combination
|
||||
* sent to firmware
|
||||
*/
|
||||
#define WMI_ML_MAX_DISALLOW_BMAP_COMB 4
|
||||
|
||||
struct wmi_mlo_link_set_active_arg {
|
||||
enum wmi_mlo_link_force_mode force_mode;
|
||||
enum wmi_mlo_link_force_reason reason;
|
||||
u32 num_link_entry;
|
||||
u32 num_vdev_bitmap;
|
||||
u32 num_inactive_vdev_bitmap;
|
||||
struct wmi_mlo_link_num_arg link_num[WMI_MLO_LINK_NUM_SZ];
|
||||
u32 vdev_bitmap[WMI_MLO_VDEV_BITMAP_SZ];
|
||||
u32 inactive_vdev_bitmap[WMI_MLO_VDEV_BITMAP_SZ];
|
||||
struct wmi_mlo_control_flags_arg ctrl_flags;
|
||||
bool use_ieee_link_id;
|
||||
struct wmi_ml_link_force_cmd_arg force_cmd;
|
||||
u32 num_disallow_mode_comb;
|
||||
struct wmi_ml_disallow_mode_bmap_arg disallow_bmap[WMI_ML_MAX_DISALLOW_BMAP_COMB];
|
||||
};
|
||||
|
||||
void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
|
||||
struct ath12k_wmi_resource_config_arg *config);
|
||||
void ath12k_wmi_init_wcn7850(struct ath12k_base *ab,
|
||||
@ -6195,5 +6372,6 @@ bool ath12k_wmi_supports_6ghz_cc_ext(struct ath12k *ar);
|
||||
int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
|
||||
u32 vdev_id,
|
||||
struct ath12k_reg_tpc_power_info *param);
|
||||
|
||||
int ath12k_wmi_send_mlo_link_set_active_cmd(struct ath12k_base *ab,
|
||||
struct wmi_mlo_link_set_active_arg *param);
|
||||
#endif
|
||||
|
@ -87,7 +87,9 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
|
||||
* We need to do some backwards compatibility to make this work.
|
||||
*/
|
||||
if (le32_to_cpu(targ_info->byte_count) != sizeof(*targ_info)) {
|
||||
WARN_ON(1);
|
||||
ath6kl_err("mismatched byte count %d vs. expected %zd\n",
|
||||
le32_to_cpu(targ_info->byte_count),
|
||||
sizeof(*targ_info));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -438,14 +438,21 @@ static void carl9170_usb_rx_complete(struct urb *urb)
|
||||
|
||||
if (atomic_read(&ar->rx_anch_urbs) == 0) {
|
||||
/*
|
||||
* The system is too slow to cope with
|
||||
* the enormous workload. We have simply
|
||||
* run out of active rx urbs and this
|
||||
* unfortunately leads to an unpredictable
|
||||
* device.
|
||||
* At this point, either the system is too slow to
|
||||
* cope with the enormous workload (so we have simply
|
||||
* run out of active rx urbs and this unfortunately
|
||||
* leads to an unpredictable device), or the device
|
||||
* is not fully functional after an unsuccessful
|
||||
* firmware loading attempts (so it doesn't pass
|
||||
* ieee80211_register_hw() and there is no internal
|
||||
* workqueue at all).
|
||||
*/
|
||||
|
||||
ieee80211_queue_work(ar->hw, &ar->ping_work);
|
||||
if (ar->registered)
|
||||
ieee80211_queue_work(ar->hw, &ar->ping_work);
|
||||
else
|
||||
pr_warn_once("device %s is not registered\n",
|
||||
dev_name(&ar->udev->dev));
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
|
@ -1316,6 +1316,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
||||
sizeof(trans->conf.no_reclaim_cmds));
|
||||
memcpy(trans->conf.no_reclaim_cmds, no_reclaim_cmds,
|
||||
sizeof(no_reclaim_cmds));
|
||||
trans->conf.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
|
||||
|
||||
switch (iwlwifi_mod_params.amsdu_size) {
|
||||
case IWL_AMSDU_DEF:
|
||||
|
@ -77,6 +77,7 @@ void iwl_construct_mld(struct iwl_mld *mld, struct iwl_trans *trans,
|
||||
|
||||
/* Setup async RX handling */
|
||||
spin_lock_init(&mld->async_handlers_lock);
|
||||
INIT_LIST_HEAD(&mld->async_handlers_list);
|
||||
wiphy_work_init(&mld->async_handlers_wk,
|
||||
iwl_mld_async_handlers_wk);
|
||||
|
||||
|
@ -34,7 +34,7 @@ static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
|
||||
WIDE_ID(MAC_CONF_GROUP,
|
||||
MAC_CONFIG_CMD), 0);
|
||||
|
||||
if (WARN_ON(cmd_ver < 1 && cmd_ver > 3))
|
||||
if (WARN_ON(cmd_ver < 1 || cmd_ver > 3))
|
||||
return;
|
||||
|
||||
cmd->id_and_color = cpu_to_le32(mvmvif->id);
|
||||
|
@ -166,7 +166,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans,
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_context_info *ctxt_info;
|
||||
struct iwl_context_info_rbd_cfg *rx_cfg;
|
||||
u32 control_flags = 0, rb_size;
|
||||
u32 control_flags = 0, rb_size, cb_size;
|
||||
dma_addr_t phys;
|
||||
int ret;
|
||||
|
||||
@ -202,11 +202,12 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans,
|
||||
rb_size = IWL_CTXT_INFO_RB_SIZE_4K;
|
||||
}
|
||||
|
||||
WARN_ON(RX_QUEUE_CB_SIZE(iwl_trans_get_num_rbds(trans)) > 12);
|
||||
cb_size = RX_QUEUE_CB_SIZE(iwl_trans_get_num_rbds(trans));
|
||||
if (WARN_ON(cb_size > 12))
|
||||
cb_size = 12;
|
||||
|
||||
control_flags = IWL_CTXT_INFO_TFD_FORMAT_LONG;
|
||||
control_flags |=
|
||||
u32_encode_bits(RX_QUEUE_CB_SIZE(iwl_trans_get_num_rbds(trans)),
|
||||
IWL_CTXT_INFO_RB_CB_SIZE);
|
||||
control_flags |= u32_encode_bits(cb_size, IWL_CTXT_INFO_RB_CB_SIZE);
|
||||
control_flags |= u32_encode_bits(rb_size, IWL_CTXT_INFO_RB_SIZE);
|
||||
ctxt_info->control.control_flags = cpu_to_le32(control_flags);
|
||||
|
||||
|
@ -121,7 +121,8 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx)
|
||||
struct ptp_clock_info *ops;
|
||||
int err = -EOPNOTSUPP;
|
||||
|
||||
if (ptp_clock_freerun(ptp)) {
|
||||
if (tx->modes & (ADJ_SETOFFSET | ADJ_FREQUENCY | ADJ_OFFSET) &&
|
||||
ptp_clock_freerun(ptp)) {
|
||||
pr_err("ptp: physical clock is free running\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -98,7 +98,27 @@ static inline int queue_cnt(const struct timestamp_event_queue *q)
|
||||
/* Check if ptp virtual clock is in use */
|
||||
static inline bool ptp_vclock_in_use(struct ptp_clock *ptp)
|
||||
{
|
||||
return !ptp->is_virtual_clock;
|
||||
bool in_use = false;
|
||||
|
||||
/* Virtual clocks can't be stacked on top of virtual clocks.
|
||||
* Avoid acquiring the n_vclocks_mux on virtual clocks, to allow this
|
||||
* function to be called from code paths where the n_vclocks_mux of the
|
||||
* parent physical clock is already held. Functionally that's not an
|
||||
* issue, but lockdep would complain, because they have the same lock
|
||||
* class.
|
||||
*/
|
||||
if (ptp->is_virtual_clock)
|
||||
return false;
|
||||
|
||||
if (mutex_lock_interruptible(&ptp->n_vclocks_mux))
|
||||
return true;
|
||||
|
||||
if (ptp->n_vclocks)
|
||||
in_use = true;
|
||||
|
||||
mutex_unlock(&ptp->n_vclocks_mux);
|
||||
|
||||
return in_use;
|
||||
}
|
||||
|
||||
/* Check if ptp clock shall be free running */
|
||||
|
@ -249,6 +249,12 @@ static inline void atm_account_tx(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
ATM_SKB(skb)->atm_options = vcc->atm_options;
|
||||
}
|
||||
|
||||
static inline void atm_return_tx(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
{
|
||||
WARN_ON_ONCE(refcount_sub_and_test(ATM_SKB(skb)->acct_truesize,
|
||||
&sk_atm(vcc)->sk_wmem_alloc));
|
||||
}
|
||||
|
||||
static inline void atm_force_charge(struct atm_vcc *vcc,int truesize)
|
||||
{
|
||||
atomic_add(truesize, &sk_atm(vcc)->sk_rmem_alloc);
|
||||
|
@ -1278,7 +1278,7 @@ struct ieee80211_ext {
|
||||
u8 sa[ETH_ALEN];
|
||||
__le32 timestamp;
|
||||
u8 change_seq;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed s1g_beacon;
|
||||
} u;
|
||||
} __packed __aligned(2);
|
||||
@ -1536,7 +1536,7 @@ struct ieee80211_mgmt {
|
||||
u8 action_code;
|
||||
u8 dialog_token;
|
||||
__le16 capability;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed tdls_discover_resp;
|
||||
struct {
|
||||
u8 action_code;
|
||||
@ -1721,35 +1721,35 @@ struct ieee80211_tdls_data {
|
||||
struct {
|
||||
u8 dialog_token;
|
||||
__le16 capability;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed setup_req;
|
||||
struct {
|
||||
__le16 status_code;
|
||||
u8 dialog_token;
|
||||
__le16 capability;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed setup_resp;
|
||||
struct {
|
||||
__le16 status_code;
|
||||
u8 dialog_token;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed setup_cfm;
|
||||
struct {
|
||||
__le16 reason_code;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed teardown;
|
||||
struct {
|
||||
u8 dialog_token;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed discover_req;
|
||||
struct {
|
||||
u8 target_channel;
|
||||
u8 oper_class;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed chan_switch_req;
|
||||
struct {
|
||||
__le16 status_code;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} __packed chan_switch_resp;
|
||||
} u;
|
||||
} __packed;
|
||||
|
@ -208,10 +208,6 @@ enum {
|
||||
ETHTOOL_A_STATS_PHY_MAX = (__ETHTOOL_A_STATS_PHY_CNT - 1)
|
||||
};
|
||||
|
||||
/* generic netlink info */
|
||||
#define ETHTOOL_GENL_NAME "ethtool"
|
||||
#define ETHTOOL_GENL_VERSION 1
|
||||
|
||||
#define ETHTOOL_MCGRP_MONITOR_NAME "monitor"
|
||||
|
||||
#endif /* _UAPI_LINUX_ETHTOOL_NETLINK_H_ */
|
||||
|
@ -6,8 +6,8 @@
|
||||
#ifndef _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H
|
||||
#define _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H
|
||||
|
||||
#define ETHTOOL_FAMILY_NAME "ethtool"
|
||||
#define ETHTOOL_FAMILY_VERSION 1
|
||||
#define ETHTOOL_GENL_NAME "ethtool"
|
||||
#define ETHTOOL_GENL_VERSION 1
|
||||
|
||||
enum {
|
||||
ETHTOOL_UDP_TUNNEL_TYPE_VXLAN,
|
||||
|
@ -716,6 +716,7 @@ config GENERIC_LIB_DEVMEM_IS_ALLOWED
|
||||
|
||||
config PLDMFW
|
||||
bool
|
||||
select CRC32
|
||||
default n
|
||||
|
||||
config ASN1_ENCODER
|
||||
|
@ -635,6 +635,7 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size)
|
||||
|
||||
skb->dev = NULL; /* for paths shared with net_device interfaces */
|
||||
if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) {
|
||||
atm_return_tx(vcc, skb);
|
||||
kfree_skb(skb);
|
||||
error = -EFAULT;
|
||||
goto out;
|
||||
|
@ -124,6 +124,7 @@ static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
/* Device structures */
|
||||
static struct net_device *dev_lec[MAX_LEC_ITF];
|
||||
static DEFINE_MUTEX(lec_mutex);
|
||||
|
||||
#if IS_ENABLED(CONFIG_BRIDGE)
|
||||
static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
|
||||
@ -685,6 +686,7 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
|
||||
int bytes_left;
|
||||
struct atmlec_ioc ioc_data;
|
||||
|
||||
lockdep_assert_held(&lec_mutex);
|
||||
/* Lecd must be up in this case */
|
||||
bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
|
||||
if (bytes_left != 0)
|
||||
@ -710,6 +712,7 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
|
||||
|
||||
static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
|
||||
{
|
||||
lockdep_assert_held(&lec_mutex);
|
||||
if (arg < 0 || arg >= MAX_LEC_ITF)
|
||||
return -EINVAL;
|
||||
arg = array_index_nospec(arg, MAX_LEC_ITF);
|
||||
@ -725,6 +728,7 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
|
||||
int i;
|
||||
struct lec_priv *priv;
|
||||
|
||||
lockdep_assert_held(&lec_mutex);
|
||||
if (arg < 0)
|
||||
arg = 0;
|
||||
if (arg >= MAX_LEC_ITF)
|
||||
@ -742,6 +746,7 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
|
||||
snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
|
||||
if (register_netdev(dev_lec[i])) {
|
||||
free_netdev(dev_lec[i]);
|
||||
dev_lec[i] = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -904,7 +909,6 @@ static void *lec_itf_walk(struct lec_state *state, loff_t *l)
|
||||
v = (dev && netdev_priv(dev)) ?
|
||||
lec_priv_walk(state, l, netdev_priv(dev)) : NULL;
|
||||
if (!v && dev) {
|
||||
dev_put(dev);
|
||||
/* Partial state reset for the next time we get called */
|
||||
dev = NULL;
|
||||
}
|
||||
@ -928,6 +932,7 @@ static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
struct lec_state *state = seq->private;
|
||||
|
||||
mutex_lock(&lec_mutex);
|
||||
state->itf = 0;
|
||||
state->dev = NULL;
|
||||
state->locked = NULL;
|
||||
@ -945,8 +950,9 @@ static void lec_seq_stop(struct seq_file *seq, void *v)
|
||||
if (state->dev) {
|
||||
spin_unlock_irqrestore(&state->locked->lec_arp_lock,
|
||||
state->flags);
|
||||
dev_put(state->dev);
|
||||
state->dev = NULL;
|
||||
}
|
||||
mutex_unlock(&lec_mutex);
|
||||
}
|
||||
|
||||
static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
@ -1003,6 +1009,7 @@ static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
mutex_lock(&lec_mutex);
|
||||
switch (cmd) {
|
||||
case ATMLEC_CTRL:
|
||||
err = lecd_attach(vcc, (int)arg);
|
||||
@ -1017,6 +1024,7 @@ static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&lec_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ static void atm_pop_raw(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
|
||||
pr_debug("(%d) %d -= %d\n",
|
||||
vcc->vci, sk_wmem_alloc_get(sk), ATM_SKB(skb)->acct_truesize);
|
||||
WARN_ON(refcount_sub_and_test(ATM_SKB(skb)->acct_truesize, &sk->sk_wmem_alloc));
|
||||
atm_return_tx(vcc, skb);
|
||||
dev_kfree_skb_any(skb);
|
||||
sk->sk_write_space(sk);
|
||||
}
|
||||
|
@ -6261,9 +6261,6 @@ int skb_ensure_writable(struct sk_buff *skb, unsigned int write_len)
|
||||
if (!pskb_may_pull(skb, write_len))
|
||||
return -ENOMEM;
|
||||
|
||||
if (!skb_frags_readable(skb))
|
||||
return -EFAULT;
|
||||
|
||||
if (!skb_cloned(skb) || skb_clone_writable(skb, write_len))
|
||||
return 0;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/busy_poll.h>
|
||||
|
||||
void tcp_fastopen_init_key_once(struct net *net)
|
||||
{
|
||||
@ -279,6 +280,8 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk,
|
||||
|
||||
refcount_set(&req->rsk_refcnt, 2);
|
||||
|
||||
sk_mark_napi_id_set(child, skb);
|
||||
|
||||
/* Now finish processing the fastopen child socket. */
|
||||
tcp_init_transfer(child, BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB, skb);
|
||||
|
||||
|
@ -2479,20 +2479,33 @@ static inline bool tcp_packet_delayed(const struct tcp_sock *tp)
|
||||
{
|
||||
const struct sock *sk = (const struct sock *)tp;
|
||||
|
||||
if (tp->retrans_stamp &&
|
||||
tcp_tsopt_ecr_before(tp, tp->retrans_stamp))
|
||||
return true; /* got echoed TS before first retransmission */
|
||||
/* Received an echoed timestamp before the first retransmission? */
|
||||
if (tp->retrans_stamp)
|
||||
return tcp_tsopt_ecr_before(tp, tp->retrans_stamp);
|
||||
|
||||
/* Check if nothing was retransmitted (retrans_stamp==0), which may
|
||||
* happen in fast recovery due to TSQ. But we ignore zero retrans_stamp
|
||||
* in TCP_SYN_SENT, since when we set FLAG_SYN_ACKED we also clear
|
||||
* retrans_stamp even if we had retransmitted the SYN.
|
||||
/* We set tp->retrans_stamp upon the first retransmission of a loss
|
||||
* recovery episode, so normally if tp->retrans_stamp is 0 then no
|
||||
* retransmission has happened yet (likely due to TSQ, which can cause
|
||||
* fast retransmits to be delayed). So if snd_una advanced while
|
||||
* (tp->retrans_stamp is 0 then apparently a packet was merely delayed,
|
||||
* not lost. But there are exceptions where we retransmit but then
|
||||
* clear tp->retrans_stamp, so we check for those exceptions.
|
||||
*/
|
||||
if (!tp->retrans_stamp && /* no record of a retransmit/SYN? */
|
||||
sk->sk_state != TCP_SYN_SENT) /* not the FLAG_SYN_ACKED case? */
|
||||
return true; /* nothing was retransmitted */
|
||||
|
||||
return false;
|
||||
/* (1) For non-SACK connections, tcp_is_non_sack_preventing_reopen()
|
||||
* clears tp->retrans_stamp when snd_una == high_seq.
|
||||
*/
|
||||
if (!tcp_is_sack(tp) && !before(tp->snd_una, tp->high_seq))
|
||||
return false;
|
||||
|
||||
/* (2) In TCP_SYN_SENT tcp_clean_rtx_queue() clears tp->retrans_stamp
|
||||
* when setting FLAG_SYN_ACKED is set, even if the SYN was
|
||||
* retransmitted.
|
||||
*/
|
||||
if (sk->sk_state == TCP_SYN_SENT)
|
||||
return false;
|
||||
|
||||
return true; /* tp->retrans_stamp is zero; no retransmit yet */
|
||||
}
|
||||
|
||||
/* Undo procedures. */
|
||||
|
@ -1207,6 +1207,10 @@ static int calipso_req_setattr(struct request_sock *req,
|
||||
struct ipv6_opt_hdr *old, *new;
|
||||
struct sock *sk = sk_to_full_sk(req_to_sk(req));
|
||||
|
||||
/* sk is NULL for SYN+ACK w/ SYN Cookie */
|
||||
if (!sk)
|
||||
return -ENOMEM;
|
||||
|
||||
if (req_inet->ipv6_opt && req_inet->ipv6_opt->hopopt)
|
||||
old = req_inet->ipv6_opt->hopopt;
|
||||
else
|
||||
@ -1247,6 +1251,10 @@ static void calipso_req_delattr(struct request_sock *req)
|
||||
struct ipv6_txoptions *txopts;
|
||||
struct sock *sk = sk_to_full_sk(req_to_sk(req));
|
||||
|
||||
/* sk is NULL for SYN+ACK w/ SYN Cookie */
|
||||
if (!sk)
|
||||
return;
|
||||
|
||||
if (!req_inet->ipv6_opt || !req_inet->ipv6_opt->hopopt)
|
||||
return;
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Portions
|
||||
* Copyright (C) 2022 - 2024 Intel Corporation
|
||||
* Copyright (C) 2022 - 2025 Intel Corporation
|
||||
*/
|
||||
#ifndef __MAC80211_DEBUG_H
|
||||
#define __MAC80211_DEBUG_H
|
||||
#include <linux/once_lite.h>
|
||||
#include <net/cfg80211.h>
|
||||
|
||||
#ifdef CONFIG_MAC80211_OCB_DEBUG
|
||||
@ -152,6 +153,8 @@ do { \
|
||||
else \
|
||||
_sdata_err((link)->sdata, fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define link_err_once(link, fmt, ...) \
|
||||
DO_ONCE_LITE(link_err, link, fmt, ##__VA_ARGS__)
|
||||
#define link_id_info(sdata, link_id, fmt, ...) \
|
||||
do { \
|
||||
if (ieee80211_vif_is_mld(&sdata->vif)) \
|
||||
|
@ -4432,6 +4432,10 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
|
||||
if (!multicast &&
|
||||
!ether_addr_equal(sdata->dev->dev_addr, hdr->addr1))
|
||||
return false;
|
||||
/* reject invalid/our STA address */
|
||||
if (!is_valid_ether_addr(hdr->addr2) ||
|
||||
ether_addr_equal(sdata->dev->dev_addr, hdr->addr2))
|
||||
return false;
|
||||
if (!rx->sta) {
|
||||
int rate_idx;
|
||||
if (status->encoding != RX_ENC_LEGACY)
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2018-2024 Intel Corporation
|
||||
* Copyright (C) 2018-2025 Intel Corporation
|
||||
*
|
||||
* Transmit and frame generation functions.
|
||||
*/
|
||||
@ -5016,12 +5016,25 @@ static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
}
|
||||
|
||||
static u8 __ieee80211_beacon_update_cntdwn(struct beacon_data *beacon)
|
||||
static u8 __ieee80211_beacon_update_cntdwn(struct ieee80211_link_data *link,
|
||||
struct beacon_data *beacon)
|
||||
{
|
||||
beacon->cntdwn_current_counter--;
|
||||
if (beacon->cntdwn_current_counter == 1) {
|
||||
/*
|
||||
* Channel switch handling is done by a worker thread while
|
||||
* beacons get pulled from hardware timers. It's therefore
|
||||
* possible that software threads are slow enough to not be
|
||||
* able to complete CSA handling in a single beacon interval,
|
||||
* in which case we get here. There isn't much to do about
|
||||
* it, other than letting the user know that the AP isn't
|
||||
* behaving correctly.
|
||||
*/
|
||||
link_err_once(link,
|
||||
"beacon TX faster than countdown (channel/color switch) completion\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the counter should never reach 0 */
|
||||
WARN_ON_ONCE(!beacon->cntdwn_current_counter);
|
||||
beacon->cntdwn_current_counter--;
|
||||
|
||||
return beacon->cntdwn_current_counter;
|
||||
}
|
||||
@ -5052,7 +5065,7 @@ u8 ieee80211_beacon_update_cntdwn(struct ieee80211_vif *vif, unsigned int link_i
|
||||
if (!beacon)
|
||||
goto unlock;
|
||||
|
||||
count = __ieee80211_beacon_update_cntdwn(beacon);
|
||||
count = __ieee80211_beacon_update_cntdwn(link, beacon);
|
||||
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
@ -5450,7 +5463,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
|
||||
|
||||
if (beacon->cntdwn_counter_offsets[0]) {
|
||||
if (!is_template)
|
||||
__ieee80211_beacon_update_cntdwn(beacon);
|
||||
__ieee80211_beacon_update_cntdwn(link, beacon);
|
||||
|
||||
ieee80211_set_beacon_cntdwn(sdata, beacon, link);
|
||||
}
|
||||
@ -5482,7 +5495,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
|
||||
* for now we leave it consistent with overall
|
||||
* mac80211's behavior.
|
||||
*/
|
||||
__ieee80211_beacon_update_cntdwn(beacon);
|
||||
__ieee80211_beacon_update_cntdwn(link, beacon);
|
||||
|
||||
ieee80211_set_beacon_cntdwn(sdata, beacon, link);
|
||||
}
|
||||
|
@ -81,8 +81,8 @@ static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
|
||||
|
||||
if (index < net->mpls.platform_labels) {
|
||||
struct mpls_route __rcu **platform_label =
|
||||
rcu_dereference(net->mpls.platform_label);
|
||||
rt = rcu_dereference(platform_label[index]);
|
||||
rcu_dereference_rtnl(net->mpls.platform_label);
|
||||
rt = rcu_dereference_rtnl(platform_label[index]);
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
|
@ -119,22 +119,22 @@ static int nci_uart_set_driver(struct tty_struct *tty, unsigned int driver)
|
||||
|
||||
memcpy(nu, nci_uart_drivers[driver], sizeof(struct nci_uart));
|
||||
nu->tty = tty;
|
||||
tty->disc_data = nu;
|
||||
skb_queue_head_init(&nu->tx_q);
|
||||
INIT_WORK(&nu->write_work, nci_uart_write_work);
|
||||
spin_lock_init(&nu->rx_lock);
|
||||
|
||||
ret = nu->ops.open(nu);
|
||||
if (ret) {
|
||||
tty->disc_data = NULL;
|
||||
kfree(nu);
|
||||
return ret;
|
||||
} else if (!try_module_get(nu->owner)) {
|
||||
nu->ops.close(nu);
|
||||
tty->disc_data = NULL;
|
||||
kfree(nu);
|
||||
return -ENOENT;
|
||||
}
|
||||
return ret;
|
||||
tty->disc_data = nu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------ LDISC part ------ */
|
||||
|
@ -39,16 +39,14 @@
|
||||
#include "flow_netlink.h"
|
||||
#include "openvswitch_trace.h"
|
||||
|
||||
DEFINE_PER_CPU(struct ovs_pcpu_storage, ovs_pcpu_storage) = {
|
||||
.bh_lock = INIT_LOCAL_LOCK(bh_lock),
|
||||
};
|
||||
struct ovs_pcpu_storage __percpu *ovs_pcpu_storage;
|
||||
|
||||
/* Make a clone of the 'key', using the pre-allocated percpu 'flow_keys'
|
||||
* space. Return NULL if out of key spaces.
|
||||
*/
|
||||
static struct sw_flow_key *clone_key(const struct sw_flow_key *key_)
|
||||
{
|
||||
struct ovs_pcpu_storage *ovs_pcpu = this_cpu_ptr(&ovs_pcpu_storage);
|
||||
struct ovs_pcpu_storage *ovs_pcpu = this_cpu_ptr(ovs_pcpu_storage);
|
||||
struct action_flow_keys *keys = &ovs_pcpu->flow_keys;
|
||||
int level = ovs_pcpu->exec_level;
|
||||
struct sw_flow_key *key = NULL;
|
||||
@ -94,7 +92,7 @@ static struct deferred_action *add_deferred_actions(struct sk_buff *skb,
|
||||
const struct nlattr *actions,
|
||||
const int actions_len)
|
||||
{
|
||||
struct action_fifo *fifo = this_cpu_ptr(&ovs_pcpu_storage.action_fifos);
|
||||
struct action_fifo *fifo = this_cpu_ptr(&ovs_pcpu_storage->action_fifos);
|
||||
struct deferred_action *da;
|
||||
|
||||
da = action_fifo_put(fifo);
|
||||
@ -755,7 +753,7 @@ static int set_sctp(struct sk_buff *skb, struct sw_flow_key *flow_key,
|
||||
static int ovs_vport_output(struct net *net, struct sock *sk,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ovs_frag_data *data = this_cpu_ptr(&ovs_pcpu_storage.frag_data);
|
||||
struct ovs_frag_data *data = this_cpu_ptr(&ovs_pcpu_storage->frag_data);
|
||||
struct vport *vport = data->vport;
|
||||
|
||||
if (skb_cow_head(skb, data->l2_len) < 0) {
|
||||
@ -807,7 +805,7 @@ static void prepare_frag(struct vport *vport, struct sk_buff *skb,
|
||||
unsigned int hlen = skb_network_offset(skb);
|
||||
struct ovs_frag_data *data;
|
||||
|
||||
data = this_cpu_ptr(&ovs_pcpu_storage.frag_data);
|
||||
data = this_cpu_ptr(&ovs_pcpu_storage->frag_data);
|
||||
data->dst = skb->_skb_refdst;
|
||||
data->vport = vport;
|
||||
data->cb = *OVS_CB(skb);
|
||||
@ -1566,16 +1564,15 @@ static int clone_execute(struct datapath *dp, struct sk_buff *skb,
|
||||
clone = clone_flow_key ? clone_key(key) : key;
|
||||
if (clone) {
|
||||
int err = 0;
|
||||
|
||||
if (actions) { /* Sample action */
|
||||
if (clone_flow_key)
|
||||
__this_cpu_inc(ovs_pcpu_storage.exec_level);
|
||||
__this_cpu_inc(ovs_pcpu_storage->exec_level);
|
||||
|
||||
err = do_execute_actions(dp, skb, clone,
|
||||
actions, len);
|
||||
|
||||
if (clone_flow_key)
|
||||
__this_cpu_dec(ovs_pcpu_storage.exec_level);
|
||||
__this_cpu_dec(ovs_pcpu_storage->exec_level);
|
||||
} else { /* Recirc action */
|
||||
clone->recirc_id = recirc_id;
|
||||
ovs_dp_process_packet(skb, clone);
|
||||
@ -1611,7 +1608,7 @@ static int clone_execute(struct datapath *dp, struct sk_buff *skb,
|
||||
|
||||
static void process_deferred_actions(struct datapath *dp)
|
||||
{
|
||||
struct action_fifo *fifo = this_cpu_ptr(&ovs_pcpu_storage.action_fifos);
|
||||
struct action_fifo *fifo = this_cpu_ptr(&ovs_pcpu_storage->action_fifos);
|
||||
|
||||
/* Do not touch the FIFO in case there is no deferred actions. */
|
||||
if (action_fifo_is_empty(fifo))
|
||||
@ -1642,7 +1639,7 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
|
||||
{
|
||||
int err, level;
|
||||
|
||||
level = __this_cpu_inc_return(ovs_pcpu_storage.exec_level);
|
||||
level = __this_cpu_inc_return(ovs_pcpu_storage->exec_level);
|
||||
if (unlikely(level > OVS_RECURSION_LIMIT)) {
|
||||
net_crit_ratelimited("ovs: recursion limit reached on datapath %s, probable configuration error\n",
|
||||
ovs_dp_name(dp));
|
||||
@ -1659,6 +1656,6 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
|
||||
process_deferred_actions(dp);
|
||||
|
||||
out:
|
||||
__this_cpu_dec(ovs_pcpu_storage.exec_level);
|
||||
__this_cpu_dec(ovs_pcpu_storage->exec_level);
|
||||
return err;
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ void ovs_dp_detach_port(struct vport *p)
|
||||
/* Must be called with rcu_read_lock. */
|
||||
void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
|
||||
{
|
||||
struct ovs_pcpu_storage *ovs_pcpu = this_cpu_ptr(&ovs_pcpu_storage);
|
||||
struct ovs_pcpu_storage *ovs_pcpu = this_cpu_ptr(ovs_pcpu_storage);
|
||||
const struct vport *p = OVS_CB(skb)->input_vport;
|
||||
struct datapath *dp = p->dp;
|
||||
struct sw_flow *flow;
|
||||
@ -299,7 +299,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
|
||||
* avoided.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_PREEMPT_RT) && ovs_pcpu->owner != current) {
|
||||
local_lock_nested_bh(&ovs_pcpu_storage.bh_lock);
|
||||
local_lock_nested_bh(&ovs_pcpu_storage->bh_lock);
|
||||
ovs_pcpu->owner = current;
|
||||
ovs_pcpu_locked = true;
|
||||
}
|
||||
@ -310,7 +310,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
|
||||
ovs_dp_name(dp), error);
|
||||
if (ovs_pcpu_locked) {
|
||||
ovs_pcpu->owner = NULL;
|
||||
local_unlock_nested_bh(&ovs_pcpu_storage.bh_lock);
|
||||
local_unlock_nested_bh(&ovs_pcpu_storage->bh_lock);
|
||||
}
|
||||
|
||||
stats_counter = &stats->n_hit;
|
||||
@ -689,13 +689,13 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
|
||||
sf_acts = rcu_dereference(flow->sf_acts);
|
||||
|
||||
local_bh_disable();
|
||||
local_lock_nested_bh(&ovs_pcpu_storage.bh_lock);
|
||||
local_lock_nested_bh(&ovs_pcpu_storage->bh_lock);
|
||||
if (IS_ENABLED(CONFIG_PREEMPT_RT))
|
||||
this_cpu_write(ovs_pcpu_storage.owner, current);
|
||||
this_cpu_write(ovs_pcpu_storage->owner, current);
|
||||
err = ovs_execute_actions(dp, packet, sf_acts, &flow->key);
|
||||
if (IS_ENABLED(CONFIG_PREEMPT_RT))
|
||||
this_cpu_write(ovs_pcpu_storage.owner, NULL);
|
||||
local_unlock_nested_bh(&ovs_pcpu_storage.bh_lock);
|
||||
this_cpu_write(ovs_pcpu_storage->owner, NULL);
|
||||
local_unlock_nested_bh(&ovs_pcpu_storage->bh_lock);
|
||||
local_bh_enable();
|
||||
rcu_read_unlock();
|
||||
|
||||
@ -2744,6 +2744,28 @@ static struct drop_reason_list drop_reason_list_ovs = {
|
||||
.n_reasons = ARRAY_SIZE(ovs_drop_reasons),
|
||||
};
|
||||
|
||||
static int __init ovs_alloc_percpu_storage(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
ovs_pcpu_storage = alloc_percpu(*ovs_pcpu_storage);
|
||||
if (!ovs_pcpu_storage)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct ovs_pcpu_storage *ovs_pcpu;
|
||||
|
||||
ovs_pcpu = per_cpu_ptr(ovs_pcpu_storage, cpu);
|
||||
local_lock_init(&ovs_pcpu->bh_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ovs_free_percpu_storage(void)
|
||||
{
|
||||
free_percpu(ovs_pcpu_storage);
|
||||
}
|
||||
|
||||
static int __init dp_init(void)
|
||||
{
|
||||
int err;
|
||||
@ -2753,6 +2775,10 @@ static int __init dp_init(void)
|
||||
|
||||
pr_info("Open vSwitch switching datapath\n");
|
||||
|
||||
err = ovs_alloc_percpu_storage();
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
err = ovs_internal_dev_rtnl_link_register();
|
||||
if (err)
|
||||
goto error;
|
||||
@ -2799,6 +2825,7 @@ error_flow_exit:
|
||||
error_unreg_rtnl_link:
|
||||
ovs_internal_dev_rtnl_link_unregister();
|
||||
error:
|
||||
ovs_free_percpu_storage();
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2813,6 +2840,7 @@ static void dp_cleanup(void)
|
||||
ovs_vport_exit();
|
||||
ovs_flow_exit();
|
||||
ovs_internal_dev_rtnl_link_unregister();
|
||||
ovs_free_percpu_storage();
|
||||
}
|
||||
|
||||
module_init(dp_init);
|
||||
|
@ -220,7 +220,8 @@ struct ovs_pcpu_storage {
|
||||
struct task_struct *owner;
|
||||
local_lock_t bh_lock;
|
||||
};
|
||||
DECLARE_PER_CPU(struct ovs_pcpu_storage, ovs_pcpu_storage);
|
||||
|
||||
extern struct ovs_pcpu_storage __percpu *ovs_pcpu_storage;
|
||||
|
||||
/**
|
||||
* enum ovs_pkt_hash_types - hash info to include with a packet
|
||||
|
@ -1328,13 +1328,15 @@ static int taprio_dev_notifier(struct notifier_block *nb, unsigned long event,
|
||||
|
||||
stab = rtnl_dereference(q->root->stab);
|
||||
|
||||
oper = rtnl_dereference(q->oper_sched);
|
||||
rcu_read_lock();
|
||||
oper = rcu_dereference(q->oper_sched);
|
||||
if (oper)
|
||||
taprio_update_queue_max_sdu(q, oper, stab);
|
||||
|
||||
admin = rtnl_dereference(q->admin_sched);
|
||||
admin = rcu_dereference(q->admin_sched);
|
||||
if (admin)
|
||||
taprio_update_queue_max_sdu(q, admin, stab);
|
||||
rcu_read_unlock();
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -489,7 +489,7 @@ int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
|
||||
rtnl_lock();
|
||||
b = tipc_bearer_find(net, bname);
|
||||
if (!b) {
|
||||
if (!b || b->bcast_addr.media_id != TIPC_MEDIA_TYPE_UDP) {
|
||||
rtnl_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -500,7 +500,7 @@ int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
|
||||
rtnl_lock();
|
||||
b = rtnl_dereference(tn->bearer_list[bid]);
|
||||
if (!b) {
|
||||
if (!b || b->bcast_addr.media_id != TIPC_MEDIA_TYPE_UDP) {
|
||||
rtnl_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -231,14 +231,7 @@ class NlMsg:
|
||||
self.extack['unknown'].append(extack)
|
||||
|
||||
if attr_space:
|
||||
# We don't have the ability to parse nests yet, so only do global
|
||||
if 'miss-type' in self.extack and 'miss-nest' not in self.extack:
|
||||
miss_type = self.extack['miss-type']
|
||||
if miss_type in attr_space.attrs_by_val:
|
||||
spec = attr_space.attrs_by_val[miss_type]
|
||||
self.extack['miss-type'] = spec['name']
|
||||
if 'doc' in spec:
|
||||
self.extack['miss-type-doc'] = spec['doc']
|
||||
self.annotate_extack(attr_space)
|
||||
|
||||
def _decode_policy(self, raw):
|
||||
policy = {}
|
||||
@ -264,6 +257,18 @@ class NlMsg:
|
||||
policy['mask'] = attr.as_scalar('u64')
|
||||
return policy
|
||||
|
||||
def annotate_extack(self, attr_space):
|
||||
""" Make extack more human friendly with attribute information """
|
||||
|
||||
# We don't have the ability to parse nests yet, so only do global
|
||||
if 'miss-type' in self.extack and 'miss-nest' not in self.extack:
|
||||
miss_type = self.extack['miss-type']
|
||||
if miss_type in attr_space.attrs_by_val:
|
||||
spec = attr_space.attrs_by_val[miss_type]
|
||||
self.extack['miss-type'] = spec['name']
|
||||
if 'doc' in spec:
|
||||
self.extack['miss-type-doc'] = spec['doc']
|
||||
|
||||
def cmd(self):
|
||||
return self.nl_type
|
||||
|
||||
@ -277,12 +282,12 @@ class NlMsg:
|
||||
|
||||
|
||||
class NlMsgs:
|
||||
def __init__(self, data, attr_space=None):
|
||||
def __init__(self, data):
|
||||
self.msgs = []
|
||||
|
||||
offset = 0
|
||||
while offset < len(data):
|
||||
msg = NlMsg(data, offset, attr_space=attr_space)
|
||||
msg = NlMsg(data, offset)
|
||||
offset += msg.nl_len
|
||||
self.msgs.append(msg)
|
||||
|
||||
@ -1034,12 +1039,13 @@ class YnlFamily(SpecFamily):
|
||||
op_rsp = []
|
||||
while not done:
|
||||
reply = self.sock.recv(self._recv_size)
|
||||
nms = NlMsgs(reply, attr_space=op.attr_set)
|
||||
nms = NlMsgs(reply)
|
||||
self._recv_dbg_print(reply, nms)
|
||||
for nl_msg in nms:
|
||||
if nl_msg.nl_seq in reqs_by_seq:
|
||||
(op, vals, req_msg, req_flags) = reqs_by_seq[nl_msg.nl_seq]
|
||||
if nl_msg.extack:
|
||||
nl_msg.annotate_extack(op.attr_set)
|
||||
self._decode_extack(req_msg, op, nl_msg.extack, vals)
|
||||
else:
|
||||
op = None
|
||||
|
@ -1,7 +1,8 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
source ../../../net/lib.sh
|
||||
lib_dir=$(dirname $0)/../../../net
|
||||
source $lib_dir/lib.sh
|
||||
|
||||
NSIM_DEV_1_ID=$((256 + RANDOM % 256))
|
||||
NSIM_DEV_1_SYS=/sys/bus/netdevsim/devices/netdevsim$NSIM_DEV_1_ID
|
||||
|
1
tools/testing/selftests/net/.gitignore
vendored
1
tools/testing/selftests/net/.gitignore
vendored
@ -50,6 +50,7 @@ tap
|
||||
tcp_fastopen_backup_key
|
||||
tcp_inq
|
||||
tcp_mmap
|
||||
tfo
|
||||
timestamping
|
||||
tls
|
||||
toeplitz
|
||||
|
@ -110,6 +110,8 @@ TEST_GEN_PROGS += proc_net_pktgen
|
||||
TEST_PROGS += lwt_dst_cache_ref_loop.sh
|
||||
TEST_PROGS += skf_net_off.sh
|
||||
TEST_GEN_FILES += skf_net_off
|
||||
TEST_GEN_FILES += tfo
|
||||
TEST_PROGS += tfo_passive.sh
|
||||
|
||||
# YNL files, must be before "include ..lib.mk"
|
||||
YNL_GEN_FILES := busy_poller netlink-dumps
|
||||
|
171
tools/testing/selftests/net/tfo.c
Normal file
171
tools/testing/selftests/net/tfo.c
Normal file
@ -0,0 +1,171 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <error.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <errno.h>
|
||||
|
||||
static int cfg_server;
|
||||
static int cfg_client;
|
||||
static int cfg_port = 8000;
|
||||
static struct sockaddr_in6 cfg_addr;
|
||||
static char *cfg_outfile;
|
||||
|
||||
static int parse_address(const char *str, int port, struct sockaddr_in6 *sin6)
|
||||
{
|
||||
int ret;
|
||||
|
||||
sin6->sin6_family = AF_INET6;
|
||||
sin6->sin6_port = htons(port);
|
||||
|
||||
ret = inet_pton(sin6->sin6_family, str, &sin6->sin6_addr);
|
||||
if (ret != 1) {
|
||||
/* fallback to plain IPv4 */
|
||||
ret = inet_pton(AF_INET, str, &sin6->sin6_addr.s6_addr32[3]);
|
||||
if (ret != 1)
|
||||
return -1;
|
||||
|
||||
/* add ::ffff prefix */
|
||||
sin6->sin6_addr.s6_addr32[0] = 0;
|
||||
sin6->sin6_addr.s6_addr32[1] = 0;
|
||||
sin6->sin6_addr.s6_addr16[4] = 0;
|
||||
sin6->sin6_addr.s6_addr16[5] = 0xffff;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void run_server(void)
|
||||
{
|
||||
unsigned long qlen = 32;
|
||||
int fd, opt, connfd;
|
||||
socklen_t len;
|
||||
char buf[64];
|
||||
FILE *outfile;
|
||||
|
||||
outfile = fopen(cfg_outfile, "w");
|
||||
if (!outfile)
|
||||
error(1, errno, "fopen() outfile");
|
||||
|
||||
fd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
error(1, errno, "socket()");
|
||||
|
||||
opt = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
|
||||
error(1, errno, "setsockopt(SO_REUSEADDR)");
|
||||
|
||||
if (setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) < 0)
|
||||
error(1, errno, "setsockopt(TCP_FASTOPEN)");
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&cfg_addr, sizeof(cfg_addr)) < 0)
|
||||
error(1, errno, "bind()");
|
||||
|
||||
if (listen(fd, 5) < 0)
|
||||
error(1, errno, "listen()");
|
||||
|
||||
len = sizeof(cfg_addr);
|
||||
connfd = accept(fd, (struct sockaddr *)&cfg_addr, &len);
|
||||
if (connfd < 0)
|
||||
error(1, errno, "accept()");
|
||||
|
||||
len = sizeof(opt);
|
||||
if (getsockopt(connfd, SOL_SOCKET, SO_INCOMING_NAPI_ID, &opt, &len) < 0)
|
||||
error(1, errno, "getsockopt(SO_INCOMING_NAPI_ID)");
|
||||
|
||||
read(connfd, buf, 64);
|
||||
fprintf(outfile, "%d\n", opt);
|
||||
|
||||
fclose(outfile);
|
||||
close(connfd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void run_client(void)
|
||||
{
|
||||
int fd;
|
||||
char *msg = "Hello, world!";
|
||||
|
||||
fd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
error(1, errno, "socket()");
|
||||
|
||||
sendto(fd, msg, strlen(msg), MSG_FASTOPEN, (struct sockaddr *)&cfg_addr, sizeof(cfg_addr));
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void usage(const char *filepath)
|
||||
{
|
||||
error(1, 0, "Usage: %s (-s|-c) -h<server_ip> -p<port> -o<outfile> ", filepath);
|
||||
}
|
||||
|
||||
static void parse_opts(int argc, char **argv)
|
||||
{
|
||||
struct sockaddr_in6 *addr6 = (void *) &cfg_addr;
|
||||
char *addr = NULL;
|
||||
int ret;
|
||||
int c;
|
||||
|
||||
if (argc <= 1)
|
||||
usage(argv[0]);
|
||||
|
||||
while ((c = getopt(argc, argv, "sch:p:o:")) != -1) {
|
||||
switch (c) {
|
||||
case 's':
|
||||
if (cfg_client)
|
||||
error(1, 0, "Pass one of -s or -c");
|
||||
cfg_server = 1;
|
||||
break;
|
||||
case 'c':
|
||||
if (cfg_server)
|
||||
error(1, 0, "Pass one of -s or -c");
|
||||
cfg_client = 1;
|
||||
break;
|
||||
case 'h':
|
||||
addr = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
cfg_port = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'o':
|
||||
cfg_outfile = strdup(optarg);
|
||||
if (!cfg_outfile)
|
||||
error(1, 0, "outfile invalid");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg_server && addr)
|
||||
error(1, 0, "Server cannot have -h specified");
|
||||
|
||||
memset(addr6, 0, sizeof(*addr6));
|
||||
addr6->sin6_family = AF_INET6;
|
||||
addr6->sin6_port = htons(cfg_port);
|
||||
addr6->sin6_addr = in6addr_any;
|
||||
if (addr) {
|
||||
ret = parse_address(addr, cfg_port, addr6);
|
||||
if (ret)
|
||||
error(1, 0, "Client address parse error: %s", addr);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
parse_opts(argc, argv);
|
||||
|
||||
if (cfg_server)
|
||||
run_server();
|
||||
else if (cfg_client)
|
||||
run_client();
|
||||
|
||||
return 0;
|
||||
}
|
112
tools/testing/selftests/net/tfo_passive.sh
Executable file
112
tools/testing/selftests/net/tfo_passive.sh
Executable file
@ -0,0 +1,112 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
source lib.sh
|
||||
|
||||
NSIM_SV_ID=$((256 + RANDOM % 256))
|
||||
NSIM_SV_SYS=/sys/bus/netdevsim/devices/netdevsim$NSIM_SV_ID
|
||||
NSIM_CL_ID=$((512 + RANDOM % 256))
|
||||
NSIM_CL_SYS=/sys/bus/netdevsim/devices/netdevsim$NSIM_CL_ID
|
||||
|
||||
NSIM_DEV_SYS_NEW=/sys/bus/netdevsim/new_device
|
||||
NSIM_DEV_SYS_DEL=/sys/bus/netdevsim/del_device
|
||||
NSIM_DEV_SYS_LINK=/sys/bus/netdevsim/link_device
|
||||
NSIM_DEV_SYS_UNLINK=/sys/bus/netdevsim/unlink_device
|
||||
|
||||
SERVER_IP=192.168.1.1
|
||||
CLIENT_IP=192.168.1.2
|
||||
SERVER_PORT=48675
|
||||
|
||||
setup_ns()
|
||||
{
|
||||
set -e
|
||||
ip netns add nssv
|
||||
ip netns add nscl
|
||||
|
||||
NSIM_SV_NAME=$(find $NSIM_SV_SYS/net -maxdepth 1 -type d ! \
|
||||
-path $NSIM_SV_SYS/net -exec basename {} \;)
|
||||
NSIM_CL_NAME=$(find $NSIM_CL_SYS/net -maxdepth 1 -type d ! \
|
||||
-path $NSIM_CL_SYS/net -exec basename {} \;)
|
||||
|
||||
ip link set $NSIM_SV_NAME netns nssv
|
||||
ip link set $NSIM_CL_NAME netns nscl
|
||||
|
||||
ip netns exec nssv ip addr add "${SERVER_IP}/24" dev $NSIM_SV_NAME
|
||||
ip netns exec nscl ip addr add "${CLIENT_IP}/24" dev $NSIM_CL_NAME
|
||||
|
||||
ip netns exec nssv ip link set dev $NSIM_SV_NAME up
|
||||
ip netns exec nscl ip link set dev $NSIM_CL_NAME up
|
||||
|
||||
# Enable passive TFO
|
||||
ip netns exec nssv sysctl -w net.ipv4.tcp_fastopen=519 > /dev/null
|
||||
|
||||
set +e
|
||||
}
|
||||
|
||||
cleanup_ns()
|
||||
{
|
||||
ip netns del nscl
|
||||
ip netns del nssv
|
||||
}
|
||||
|
||||
###
|
||||
### Code start
|
||||
###
|
||||
|
||||
modprobe netdevsim
|
||||
|
||||
# linking
|
||||
|
||||
echo $NSIM_SV_ID > $NSIM_DEV_SYS_NEW
|
||||
echo $NSIM_CL_ID > $NSIM_DEV_SYS_NEW
|
||||
udevadm settle
|
||||
|
||||
setup_ns
|
||||
|
||||
NSIM_SV_FD=$((256 + RANDOM % 256))
|
||||
exec {NSIM_SV_FD}</var/run/netns/nssv
|
||||
NSIM_SV_IFIDX=$(ip netns exec nssv cat /sys/class/net/$NSIM_SV_NAME/ifindex)
|
||||
|
||||
NSIM_CL_FD=$((256 + RANDOM % 256))
|
||||
exec {NSIM_CL_FD}</var/run/netns/nscl
|
||||
NSIM_CL_IFIDX=$(ip netns exec nscl cat /sys/class/net/$NSIM_CL_NAME/ifindex)
|
||||
|
||||
echo "$NSIM_SV_FD:$NSIM_SV_IFIDX $NSIM_CL_FD:$NSIM_CL_IFIDX" > \
|
||||
$NSIM_DEV_SYS_LINK
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "linking netdevsim1 with netdevsim2 should succeed"
|
||||
cleanup_ns
|
||||
exit 1
|
||||
fi
|
||||
|
||||
out_file=$(mktemp)
|
||||
|
||||
timeout -k 1s 30s ip netns exec nssv ./tfo \
|
||||
-s \
|
||||
-p ${SERVER_PORT} \
|
||||
-o ${out_file}&
|
||||
|
||||
wait_local_port_listen nssv ${SERVER_PORT} tcp
|
||||
|
||||
ip netns exec nscl ./tfo -c -h ${SERVER_IP} -p ${SERVER_PORT}
|
||||
|
||||
wait
|
||||
|
||||
res=$(cat $out_file)
|
||||
rm $out_file
|
||||
|
||||
if [ $res -eq 0 ]; then
|
||||
echo "got invalid NAPI ID from passive TFO socket"
|
||||
cleanup_ns
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$NSIM_SV_FD:$NSIM_SV_IFIDX" > $NSIM_DEV_SYS_UNLINK
|
||||
|
||||
echo $NSIM_CL_ID > $NSIM_DEV_SYS_DEL
|
||||
|
||||
cleanup_ns
|
||||
|
||||
modprobe -r netdevsim
|
||||
|
||||
exit 0
|
Loading…
Reference in New Issue
Block a user