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>
|
Serge Hallyn <sergeh@kernel.org> <serue@us.ibm.com>
|
||||||
Seth Forshee <sforshee@kernel.org> <seth.forshee@canonical.com>
|
Seth Forshee <sforshee@kernel.org> <seth.forshee@canonical.com>
|
||||||
Shakeel Butt <shakeel.butt@linux.dev> <shakeelb@google.com>
|
Shakeel Butt <shakeel.butt@linux.dev> <shakeelb@google.com>
|
||||||
Shannon Nelson <shannon.nelson@amd.com> <snelson@pensando.io>
|
Shannon Nelson <sln@onemain.com> <shannon.nelson@amd.com>
|
||||||
Shannon Nelson <shannon.nelson@amd.com> <shannon.nelson@intel.com>
|
Shannon Nelson <sln@onemain.com> <snelson@pensando.io>
|
||||||
Shannon Nelson <shannon.nelson@amd.com> <shannon.nelson@oracle.com>
|
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>
|
Sharath Chandra Vurukala <quic_sharathv@quicinc.com> <sharathv@codeaurora.org>
|
||||||
Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
|
Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
|
||||||
Shuah Khan <shuah@kernel.org> <shuahkhan@gmail.com>
|
Shuah Khan <shuah@kernel.org> <shuahkhan@gmail.com>
|
||||||
|
@ -7,6 +7,9 @@ protocol: genetlink-legacy
|
|||||||
doc: Partial family for Ethtool Netlink.
|
doc: Partial family for Ethtool Netlink.
|
||||||
uapi-header: linux/ethtool_netlink_generated.h
|
uapi-header: linux/ethtool_netlink_generated.h
|
||||||
|
|
||||||
|
c-family-name: ethtool-genl-name
|
||||||
|
c-version-name: ethtool-genl-version
|
||||||
|
|
||||||
definitions:
|
definitions:
|
||||||
-
|
-
|
||||||
name: udp-tunnel-type
|
name: udp-tunnel-type
|
||||||
|
@ -1157,7 +1157,6 @@ F: arch/x86/include/asm/amd/node.h
|
|||||||
F: arch/x86/kernel/amd_node.c
|
F: arch/x86/kernel/amd_node.c
|
||||||
|
|
||||||
AMD PDS CORE DRIVER
|
AMD PDS CORE DRIVER
|
||||||
M: Shannon Nelson <shannon.nelson@amd.com>
|
|
||||||
M: Brett Creeley <brett.creeley@amd.com>
|
M: Brett Creeley <brett.creeley@amd.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
@ -9942,7 +9941,6 @@ F: drivers/fwctl/mlx5/
|
|||||||
|
|
||||||
FWCTL PDS DRIVER
|
FWCTL PDS DRIVER
|
||||||
M: Brett Creeley <brett.creeley@amd.com>
|
M: Brett Creeley <brett.creeley@amd.com>
|
||||||
R: Shannon Nelson <shannon.nelson@amd.com>
|
|
||||||
L: linux-kernel@vger.kernel.org
|
L: linux-kernel@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/fwctl/pds/
|
F: drivers/fwctl/pds/
|
||||||
@ -19379,7 +19377,7 @@ F: crypto/pcrypt.c
|
|||||||
F: include/crypto/pcrypt.h
|
F: include/crypto/pcrypt.h
|
||||||
|
|
||||||
PDS DSC VIRTIO DATA PATH ACCELERATOR
|
PDS DSC VIRTIO DATA PATH ACCELERATOR
|
||||||
R: Shannon Nelson <shannon.nelson@amd.com>
|
R: Brett Creeley <brett.creeley@amd.com>
|
||||||
F: drivers/vdpa/pds/
|
F: drivers/vdpa/pds/
|
||||||
|
|
||||||
PECI HARDWARE MONITORING DRIVERS
|
PECI HARDWARE MONITORING DRIVERS
|
||||||
@ -19401,7 +19399,6 @@ F: include/linux/peci-cpu.h
|
|||||||
F: include/linux/peci.h
|
F: include/linux/peci.h
|
||||||
|
|
||||||
PENSANDO ETHERNET DRIVERS
|
PENSANDO ETHERNET DRIVERS
|
||||||
M: Shannon Nelson <shannon.nelson@amd.com>
|
|
||||||
M: Brett Creeley <brett.creeley@amd.com>
|
M: Brett Creeley <brett.creeley@amd.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
@ -288,7 +288,9 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
|
|||||||
struct sk_buff *new_skb;
|
struct sk_buff *new_skb;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
if (!skb->len) return 0;
|
if (skb->len < sizeof(struct atmtcp_hdr))
|
||||||
|
goto done;
|
||||||
|
|
||||||
dev = vcc->dev_data;
|
dev = vcc->dev_data;
|
||||||
hdr = (struct atmtcp_hdr *) skb->data;
|
hdr = (struct atmtcp_hdr *) skb->data;
|
||||||
if (hdr->length == ATMTCP_HDR_MAGIC) {
|
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 = cdev_to_priv(mcan_class);
|
||||||
|
|
||||||
priv->power = devm_regulator_get_optional(&spi->dev, "vsup");
|
priv->power = devm_regulator_get_optional(&spi->dev, "vsup");
|
||||||
|
if (IS_ERR(priv->power)) {
|
||||||
if (PTR_ERR(priv->power) == -EPROBE_DEFER) {
|
if (PTR_ERR(priv->power) == -EPROBE_DEFER) {
|
||||||
ret = -EPROBE_DEFER;
|
ret = -EPROBE_DEFER;
|
||||||
goto out_m_can_class_free_dev;
|
goto out_m_can_class_free_dev;
|
||||||
} else {
|
}
|
||||||
priv->power = NULL;
|
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)
|
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;
|
struct airoha_eth *eth = qdma->eth;
|
||||||
int id = qdma - ð->qdma[0];
|
int id = qdma - ð->qdma[0];
|
||||||
|
u32 status, buf_size;
|
||||||
dma_addr_t dma_addr;
|
dma_addr_t dma_addr;
|
||||||
const char *name;
|
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);
|
name = devm_kasprintf(eth->dev, GFP_KERNEL, "qdma%d-buf", id);
|
||||||
if (!name)
|
if (!name)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
buf_size = id ? AIROHA_MAX_PACKET_SIZE / 2 : AIROHA_MAX_PACKET_SIZE;
|
||||||
index = of_property_match_string(eth->dev->of_node,
|
index = of_property_match_string(eth->dev->of_node,
|
||||||
"memory-region-names", name);
|
"memory-region-names", name);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
@ -1099,8 +1094,12 @@ static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma)
|
|||||||
rmem = of_reserved_mem_lookup(np);
|
rmem = of_reserved_mem_lookup(np);
|
||||||
of_node_put(np);
|
of_node_put(np);
|
||||||
dma_addr = rmem->base;
|
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 {
|
} else {
|
||||||
size = AIROHA_MAX_PACKET_SIZE * HW_DSCP_NUM;
|
size = buf_size * num_desc;
|
||||||
if (!dmam_alloc_coherent(eth->dev, size, &dma_addr,
|
if (!dmam_alloc_coherent(eth->dev, size, &dma_addr,
|
||||||
GFP_KERNEL))
|
GFP_KERNEL))
|
||||||
return -ENOMEM;
|
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);
|
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,
|
airoha_qdma_rmw(qdma, REG_HW_FWD_DSCP_CFG,
|
||||||
HW_FWD_DSCP_PAYLOAD_SIZE_MASK,
|
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,
|
airoha_qdma_rmw(qdma, REG_FWD_DSCP_LOW_THR, FWD_DSCP_LOW_THR_MASK,
|
||||||
FIELD_PREP(FWD_DSCP_LOW_THR_MASK, 128));
|
FIELD_PREP(FWD_DSCP_LOW_THR_MASK, 128));
|
||||||
airoha_qdma_rmw(qdma, REG_LMGR_INIT_CFG,
|
airoha_qdma_rmw(qdma, REG_LMGR_INIT_CFG,
|
||||||
LMGR_INIT_START | LMGR_SRAM_MODE_MASK |
|
LMGR_INIT_START | LMGR_SRAM_MODE_MASK |
|
||||||
HW_FWD_DESC_NUM_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);
|
LMGR_INIT_START | LMGR_SRAM_MODE_MASK);
|
||||||
|
|
||||||
return read_poll_timeout(airoha_qdma_rr, status,
|
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;
|
int idle;
|
||||||
|
|
||||||
hwe = airoha_ppe_foe_get_entry(ppe, iter->hash);
|
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);
|
state = FIELD_GET(AIROHA_FOE_IB1_BIND_STATE, ib1);
|
||||||
if (state != AIROHA_FOE_STATE_BIND) {
|
if (state != AIROHA_FOE_STATE_BIND) {
|
||||||
iter->hash = 0xffff;
|
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--;
|
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)
|
static void bnxt_hwrm_realloc_rss_ctx_vnic(struct bnxt *bp)
|
||||||
{
|
{
|
||||||
bool set_tpa = !!(bp->flags & BNXT_FLAG_TPA);
|
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_vnic_info *vnic;
|
||||||
struct bnxt_napi *bnapi;
|
struct bnxt_napi *bnapi;
|
||||||
int i, rc;
|
int i, rc;
|
||||||
|
u16 mru;
|
||||||
|
|
||||||
rxr = &bp->rx_ring[idx];
|
rxr = &bp->rx_ring[idx];
|
||||||
clone = qmem;
|
clone = qmem;
|
||||||
@ -15977,21 +16044,15 @@ static int bnxt_queue_start(struct net_device *dev, void *qmem, int idx)
|
|||||||
napi_enable_locked(&bnapi->napi);
|
napi_enable_locked(&bnapi->napi);
|
||||||
bnxt_db_nq_arm(bp, &cpr->cp_db, cpr->cp_raw_cons);
|
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++) {
|
for (i = 0; i < bp->nr_vnics; i++) {
|
||||||
vnic = &bp->vnic_info[i];
|
vnic = &bp->vnic_info[i];
|
||||||
|
|
||||||
rc = bnxt_hwrm_vnic_set_rss_p5(bp, vnic, true);
|
rc = bnxt_set_vnic_mru_p5(bp, vnic, mru, idx);
|
||||||
if (rc) {
|
if (rc)
|
||||||
netdev_err(bp->dev, "hwrm vnic %d set rss failure rc: %d\n",
|
|
||||||
vnic->vnic_id, rc);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
vnic->mru = bp->dev->mtu + ETH_HLEN + VLAN_HLEN;
|
return bnxt_set_rss_ctx_vnic_mru(bp, mru, idx);
|
||||||
bnxt_hwrm_vnic_update(bp, vnic,
|
|
||||||
VNIC_UPDATE_REQ_ENABLES_MRU_VALID);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err_reset:
|
err_reset:
|
||||||
netdev_err(bp->dev, "Unexpected HWRM error during queue start rc: %d\n",
|
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++) {
|
for (i = 0; i < bp->nr_vnics; i++) {
|
||||||
vnic = &bp->vnic_info[i];
|
vnic = &bp->vnic_info[i];
|
||||||
vnic->mru = 0;
|
|
||||||
bnxt_hwrm_vnic_update(bp, vnic,
|
bnxt_set_vnic_mru_p5(bp, vnic, 0, idx);
|
||||||
VNIC_UPDATE_REQ_ENABLES_MRU_VALID);
|
|
||||||
}
|
}
|
||||||
|
bnxt_set_rss_ctx_vnic_mru(bp, 0, idx);
|
||||||
/* Make sure NAPI sees that the VNIC is disabled */
|
/* Make sure NAPI sees that the VNIC is disabled */
|
||||||
synchronize_net();
|
synchronize_net();
|
||||||
rxr = &bp->rx_ring[idx];
|
rxr = &bp->rx_ring[idx];
|
||||||
|
@ -231,10 +231,9 @@ void bnxt_ulp_stop(struct bnxt *bp)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_lock(&edev->en_dev_lock);
|
mutex_lock(&edev->en_dev_lock);
|
||||||
if (!bnxt_ulp_registered(edev)) {
|
if (!bnxt_ulp_registered(edev) ||
|
||||||
mutex_unlock(&edev->en_dev_lock);
|
(edev->flags & BNXT_EN_FLAG_ULP_STOPPED))
|
||||||
return;
|
goto ulp_stop_exit;
|
||||||
}
|
|
||||||
|
|
||||||
edev->flags |= BNXT_EN_FLAG_ULP_STOPPED;
|
edev->flags |= BNXT_EN_FLAG_ULP_STOPPED;
|
||||||
if (aux_priv) {
|
if (aux_priv) {
|
||||||
@ -250,6 +249,7 @@ void bnxt_ulp_stop(struct bnxt *bp)
|
|||||||
adrv->suspend(adev, pm);
|
adrv->suspend(adev, pm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ulp_stop_exit:
|
||||||
mutex_unlock(&edev->en_dev_lock);
|
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_aux_priv *aux_priv = bp->aux_priv;
|
||||||
struct bnxt_en_dev *edev = bp->edev;
|
struct bnxt_en_dev *edev = bp->edev;
|
||||||
|
|
||||||
if (!edev)
|
if (!edev || err)
|
||||||
return;
|
|
||||||
|
|
||||||
edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_lock(&edev->en_dev_lock);
|
mutex_lock(&edev->en_dev_lock);
|
||||||
if (!bnxt_ulp_registered(edev)) {
|
if (!bnxt_ulp_registered(edev) ||
|
||||||
mutex_unlock(&edev->en_dev_lock);
|
!(edev->flags & BNXT_EN_FLAG_ULP_STOPPED))
|
||||||
return;
|
goto ulp_start_exit;
|
||||||
}
|
|
||||||
|
|
||||||
if (edev->ulp_tbl->msix_requested)
|
if (edev->ulp_tbl->msix_requested)
|
||||||
bnxt_fill_msix_vecs(bp, edev->msix_entries);
|
bnxt_fill_msix_vecs(bp, edev->msix_entries);
|
||||||
@ -287,6 +281,8 @@ void bnxt_ulp_start(struct bnxt *bp, int err)
|
|||||||
adrv->resume(adev);
|
adrv->resume(adev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ulp_start_exit:
|
||||||
|
edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
|
||||||
mutex_unlock(&edev->en_dev_lock);
|
mutex_unlock(&edev->en_dev_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ config FTGMAC100
|
|||||||
depends on ARM || COMPILE_TEST
|
depends on ARM || COMPILE_TEST
|
||||||
depends on !64BIT || BROKEN
|
depends on !64BIT || BROKEN
|
||||||
select PHYLIB
|
select PHYLIB
|
||||||
|
select FIXED_PHY
|
||||||
select MDIO_ASPEED if MACH_ASPEED_G6
|
select MDIO_ASPEED if MACH_ASPEED_G6
|
||||||
select CRC32
|
select CRC32
|
||||||
help
|
help
|
||||||
|
@ -3534,9 +3534,6 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
|
|||||||
case e1000_pch_cnp:
|
case e1000_pch_cnp:
|
||||||
case e1000_pch_tgp:
|
case e1000_pch_tgp:
|
||||||
case e1000_pch_adp:
|
case e1000_pch_adp:
|
||||||
case e1000_pch_mtp:
|
|
||||||
case e1000_pch_lnp:
|
|
||||||
case e1000_pch_ptp:
|
|
||||||
case e1000_pch_nvp:
|
case e1000_pch_nvp:
|
||||||
if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) {
|
if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) {
|
||||||
/* Stable 24MHz frequency */
|
/* Stable 24MHz frequency */
|
||||||
@ -3552,6 +3549,17 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
|
|||||||
adapter->cc.shift = shift;
|
adapter->cc.shift = shift;
|
||||||
}
|
}
|
||||||
break;
|
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_82574:
|
||||||
case e1000_82583:
|
case e1000_82583:
|
||||||
/* Stable 25MHz frequency */
|
/* Stable 25MHz frequency */
|
||||||
|
@ -295,15 +295,17 @@ void e1000e_ptp_init(struct e1000_adapter *adapter)
|
|||||||
case e1000_pch_cnp:
|
case e1000_pch_cnp:
|
||||||
case e1000_pch_tgp:
|
case e1000_pch_tgp:
|
||||||
case e1000_pch_adp:
|
case e1000_pch_adp:
|
||||||
case e1000_pch_mtp:
|
|
||||||
case e1000_pch_lnp:
|
|
||||||
case e1000_pch_ptp:
|
|
||||||
case e1000_pch_nvp:
|
case e1000_pch_nvp:
|
||||||
if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)
|
if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)
|
||||||
adapter->ptp_clock_info.max_adj = MAX_PPB_24MHZ;
|
adapter->ptp_clock_info.max_adj = MAX_PPB_24MHZ;
|
||||||
else
|
else
|
||||||
adapter->ptp_clock_info.max_adj = MAX_PPB_38400KHZ;
|
adapter->ptp_clock_info.max_adj = MAX_PPB_38400KHZ;
|
||||||
break;
|
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_82574:
|
||||||
case e1000_82583:
|
case e1000_82583:
|
||||||
adapter->ptp_clock_info.max_adj = MAX_PPB_25MHZ;
|
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;
|
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
|
* ice_rx_flow_steer - steer the Rx flow to where application is being run
|
||||||
* @netdev: ptr to the netdev being adjusted
|
* @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;
|
continue;
|
||||||
|
|
||||||
fltr_info = &arfs_entry->fltr_info;
|
fltr_info = &arfs_entry->fltr_info;
|
||||||
|
|
||||||
|
if (!ice_arfs_cmp(fltr_info, &fk, n_proto, ip_proto))
|
||||||
|
continue;
|
||||||
|
|
||||||
ret = fltr_info->fltr_id;
|
ret = fltr_info->fltr_id;
|
||||||
|
|
||||||
if (fltr_info->q_index == rxq_idx ||
|
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)
|
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 devlink *devlink = priv_to_devlink(pf);
|
||||||
|
struct ice_repr *repr;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (!ice_is_eswitch_mode_switchdev(pf))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
repr = ice_repr_create_vf(vf);
|
||||||
if (IS_ERR(repr))
|
if (IS_ERR(repr))
|
||||||
return PTR_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->chan_cnt = IEEE_8021QAZ_MAX_TCS;
|
||||||
req->bpid_per_chan = 1;
|
req->bpid_per_chan = 1;
|
||||||
} else {
|
} else {
|
||||||
req->chan_cnt = 1;
|
req->chan_cnt = pfvf->hw.rx_chan_cnt;
|
||||||
req->bpid_per_chan = 0;
|
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->chan_cnt = IEEE_8021QAZ_MAX_TCS;
|
||||||
req->bpid_per_chan = 1;
|
req->bpid_per_chan = 1;
|
||||||
} else {
|
} else {
|
||||||
req->chan_cnt = 1;
|
req->chan_cnt = pfvf->hw.rx_chan_cnt;
|
||||||
req->bpid_per_chan = 0;
|
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);
|
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);
|
phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy", 0);
|
||||||
if (phy_irq < 0) {
|
if (phy_irq == -EPROBE_DEFER) {
|
||||||
dev_err(&pdev->dev, "Error getting PHY irq. Use polling instead");
|
err = -EPROBE_DEFER;
|
||||||
|
goto out;
|
||||||
|
} else if (phy_irq < 0) {
|
||||||
phy_irq = PHY_POLL;
|
phy_irq = PHY_POLL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,11 +127,8 @@ static int fbnic_mbx_map_msg(struct fbnic_dev *fbd, int mbx_idx,
|
|||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
addr = dma_map_single(fbd->dev, msg, PAGE_SIZE, direction);
|
addr = dma_map_single(fbd->dev, msg, PAGE_SIZE, direction);
|
||||||
if (dma_mapping_error(fbd->dev, addr)) {
|
if (dma_mapping_error(fbd->dev, addr))
|
||||||
free_page((unsigned long)msg);
|
|
||||||
|
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
}
|
|
||||||
|
|
||||||
mbx->buf_info[tail].msg = msg;
|
mbx->buf_info[tail].msg = msg;
|
||||||
mbx->buf_info[tail].addr = addr;
|
mbx->buf_info[tail].addr = addr;
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
#define LAN743X_PTP_N_EVENT_CHAN 2
|
#define LAN743X_PTP_N_EVENT_CHAN 2
|
||||||
#define LAN743X_PTP_N_PEROUT LAN743X_PTP_N_EVENT_CHAN
|
#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 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
|
#define PTP_CMD_CTL_TIMEOUT_CNT 50
|
||||||
|
|
||||||
struct lan743x_adapter;
|
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 start_time;
|
||||||
unsigned long max_wait;
|
unsigned long max_wait;
|
||||||
unsigned long duration;
|
unsigned long duration;
|
||||||
int done = 0;
|
|
||||||
bool fw_up;
|
bool fw_up;
|
||||||
int opcode;
|
int opcode;
|
||||||
|
bool done;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* Wait for dev cmd to complete, retrying if we get EAGAIN,
|
/* 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);
|
max_wait = jiffies + (max_seconds * HZ);
|
||||||
try_again:
|
try_again:
|
||||||
|
done = false;
|
||||||
opcode = idev->opcode;
|
opcode = idev->opcode;
|
||||||
start_time = jiffies;
|
start_time = jiffies;
|
||||||
for (fw_up = ionic_is_fw_running(idev);
|
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;
|
struct cppi5_host_desc_t *first_desc, *next_desc;
|
||||||
dma_addr_t buf_dma, next_desc_dma;
|
dma_addr_t buf_dma, next_desc_dma;
|
||||||
struct prueth_swdata *swdata;
|
|
||||||
struct page *page;
|
|
||||||
u32 buf_dma_len;
|
u32 buf_dma_len;
|
||||||
|
|
||||||
first_desc = desc;
|
first_desc = desc;
|
||||||
next_desc = first_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);
|
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);
|
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);
|
k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_desc:
|
|
||||||
k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc);
|
k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(prueth_xmit_free);
|
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);
|
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);
|
cppi5_hdesc_attach_buf(first_desc, buf_dma, xdpf->len, buf_dma, xdpf->len);
|
||||||
swdata = cppi5_hdesc_get_swdata(first_desc);
|
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->type = PRUETH_SWDATA_XDPF;
|
||||||
swdata->data.xdpf = xdpf;
|
swdata->data.xdpf = xdpf;
|
||||||
}
|
|
||||||
|
|
||||||
/* Report BQL before sending the packet */
|
/* Report BQL before sending the packet */
|
||||||
netif_txq = netdev_get_tx_queue(ndev, tx_chn->id);
|
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.pdevs);
|
||||||
INIT_LIST_HEAD(&ar->fw_stats.bcn);
|
INIT_LIST_HEAD(&ar->fw_stats.bcn);
|
||||||
init_completion(&ar->fw_stats_complete);
|
init_completion(&ar->fw_stats_complete);
|
||||||
|
init_completion(&ar->fw_stats_done);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ath12k_fw_stats_free(struct ath12k_fw_stats *stats)
|
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)
|
void ath12k_fw_stats_reset(struct ath12k *ar)
|
||||||
{
|
{
|
||||||
spin_lock_bh(&ar->data_lock);
|
spin_lock_bh(&ar->data_lock);
|
||||||
ar->fw_stats.fw_stats_done = false;
|
|
||||||
ath12k_fw_stats_free(&ar->fw_stats);
|
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);
|
spin_unlock_bh(&ar->data_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,6 +601,12 @@ struct ath12k_sta {
|
|||||||
#define ATH12K_NUM_CHANS 101
|
#define ATH12K_NUM_CHANS 101
|
||||||
#define ATH12K_MAX_5GHZ_CHAN 173
|
#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 {
|
enum ath12k_hw_state {
|
||||||
ATH12K_HW_STATE_OFF,
|
ATH12K_HW_STATE_OFF,
|
||||||
ATH12K_HW_STATE_ON,
|
ATH12K_HW_STATE_ON,
|
||||||
@ -626,7 +632,8 @@ struct ath12k_fw_stats {
|
|||||||
struct list_head pdevs;
|
struct list_head pdevs;
|
||||||
struct list_head vdevs;
|
struct list_head vdevs;
|
||||||
struct list_head bcn;
|
struct list_head bcn;
|
||||||
bool fw_stats_done;
|
u32 num_vdev_recvd;
|
||||||
|
u32 num_bcn_recvd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ath12k_dbg_htt_stats {
|
struct ath12k_dbg_htt_stats {
|
||||||
@ -806,6 +813,7 @@ struct ath12k {
|
|||||||
bool regdom_set_by_user;
|
bool regdom_set_by_user;
|
||||||
|
|
||||||
struct completion fw_stats_complete;
|
struct completion fw_stats_complete;
|
||||||
|
struct completion fw_stats_done;
|
||||||
|
|
||||||
struct completion mlo_setup_done;
|
struct completion mlo_setup_done;
|
||||||
u32 mlo_setup_status;
|
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)
|
static int ath12k_open_vdev_stats(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct ath12k *ar = inode->i_private;
|
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_soc_destroy(struct ath12k_base *ab);
|
||||||
void ath12k_debugfs_register(struct ath12k *ar);
|
void ath12k_debugfs_register(struct ath12k *ar);
|
||||||
void ath12k_debugfs_unregister(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,
|
void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif);
|
struct ieee80211_vif *vif);
|
||||||
void ath12k_debugfs_pdev_create(struct ath12k_base *ab);
|
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)
|
static inline bool ath12k_debugfs_is_extd_rx_stats_enabled(struct ath12k *ar)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -4360,7 +4360,7 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar,
|
|||||||
{
|
{
|
||||||
struct ath12k_base *ab = ar->ab;
|
struct ath12k_base *ab = ar->ab;
|
||||||
struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
|
struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
|
||||||
unsigned long timeout, time_left;
|
unsigned long time_left;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
guard(mutex)(&ah->hw_mutex);
|
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)
|
if (ah->state != ATH12K_HW_STATE_ON)
|
||||||
return -ENETDOWN;
|
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);
|
ath12k_fw_stats_reset(ar);
|
||||||
|
|
||||||
reinit_completion(&ar->fw_stats_complete);
|
reinit_completion(&ar->fw_stats_complete);
|
||||||
|
reinit_completion(&ar->fw_stats_done);
|
||||||
|
|
||||||
ret = ath12k_wmi_send_stats_request_cmd(ar, param->stats_id,
|
ret = ath12k_wmi_send_stats_request_cmd(ar, param->stats_id,
|
||||||
param->vdev_id, param->pdev_id);
|
param->vdev_id, param->pdev_id);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath12k_warn(ab, "failed to request fw stats: %d\n", ret);
|
ath12k_warn(ab, "failed to request fw stats: %d\n", ret);
|
||||||
return 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);
|
param->pdev_id, param->vdev_id, param->stats_id);
|
||||||
|
|
||||||
time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ);
|
time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ);
|
||||||
|
|
||||||
if (!time_left) {
|
if (!time_left) {
|
||||||
ath12k_warn(ab, "time out while waiting for get fw stats\n");
|
ath12k_warn(ab, "time out while waiting for get fw stats\n");
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
@ -4400,20 +4393,15 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar,
|
|||||||
/* Firmware sends WMI_UPDATE_STATS_EVENTID back-to-back
|
/* Firmware sends WMI_UPDATE_STATS_EVENTID back-to-back
|
||||||
* when stats data buffer limit is reached. fw_stats_complete
|
* when stats data buffer limit is reached. fw_stats_complete
|
||||||
* is completed once host receives first event from firmware, but
|
* is completed once host receives first event from firmware, but
|
||||||
* still end might not be marked in the TLV.
|
* still there could be more events following. Below is to wait
|
||||||
* Below loop is to confirm that firmware completed sending all the event
|
* until firmware completes sending all the events.
|
||||||
* and fw_stats_done is marked true when end is marked in the TLV.
|
|
||||||
*/
|
*/
|
||||||
for (;;) {
|
time_left = wait_for_completion_timeout(&ar->fw_stats_done, 3 * HZ);
|
||||||
if (time_after(jiffies, timeout))
|
if (!time_left) {
|
||||||
break;
|
ath12k_warn(ab, "time out while waiting for fw stats done\n");
|
||||||
spin_lock_bh(&ar->data_lock);
|
return -ETIMEDOUT;
|
||||||
if (ar->fw_stats.fw_stats_done) {
|
|
||||||
spin_unlock_bh(&ar->data_lock);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
spin_unlock_bh(&ar->data_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5890,6 +5878,327 @@ exit:
|
|||||||
return ret;
|
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,
|
static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
struct ieee80211_sta *sta,
|
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_vif *ahvif = ath12k_vif_to_ahvif(vif);
|
||||||
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
|
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
|
||||||
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
|
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
|
||||||
|
struct ath12k_base *prev_ab = NULL, *ab;
|
||||||
struct ath12k_link_vif *arvif;
|
struct ath12k_link_vif *arvif;
|
||||||
struct ath12k_link_sta *arsta;
|
struct ath12k_link_sta *arsta;
|
||||||
unsigned long valid_links;
|
unsigned long valid_links;
|
||||||
u8 link_id = 0;
|
u16 selected_links = 0;
|
||||||
|
u8 link_id = 0, i;
|
||||||
|
struct ath12k *ar;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
lockdep_assert_wiphy(hw->wiphy);
|
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.
|
* about to move to the associated state.
|
||||||
*/
|
*/
|
||||||
if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION &&
|
if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION &&
|
||||||
old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC)
|
old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) {
|
||||||
ieee80211_set_active_links(vif, ieee80211_vif_usable_links(vif));
|
/* 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 */
|
/* Handle all the other state transitions in generic way */
|
||||||
valid_links = ahsta->links_map;
|
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:
|
/* IEEE80211_STA_NONE -> IEEE80211_STA_NOTEXIST:
|
||||||
* Remove the station from driver (handle ML sta here since that
|
* Remove the station from driver (handle ML sta here since that
|
||||||
* needs special handling. Normal sta will be handled in generic
|
* 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_DEFAULT_SCAN_LINK IEEE80211_MLD_MAX_NUM_LINKS
|
||||||
#define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + 1)
|
#define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + 1)
|
||||||
|
|
||||||
|
#define ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE 2
|
||||||
|
|
||||||
enum ath12k_supported_bw {
|
enum ath12k_supported_bw {
|
||||||
ATH12K_BW_20 = 0,
|
ATH12K_BW_20 = 0,
|
||||||
ATH12K_BW_40 = 1,
|
ATH12K_BW_40 = 1,
|
||||||
|
@ -91,6 +91,11 @@ struct ath12k_wmi_svc_rdy_ext2_parse {
|
|||||||
bool dma_ring_cap_done;
|
bool dma_ring_cap_done;
|
||||||
bool spectral_bin_scaling_done;
|
bool spectral_bin_scaling_done;
|
||||||
bool mac_phy_caps_ext_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 {
|
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,
|
static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc,
|
||||||
u16 len, const void *ptr, void *data)
|
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;
|
struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data;
|
||||||
const struct ath12k_wmi_hw_mode_cap_params *hw_mode_caps;
|
const struct ath12k_wmi_hw_mode_cap_params *hw_mode_caps;
|
||||||
enum wmi_host_hw_mode_config_type mode, pref;
|
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",
|
svc_ext_info->num_hw_modes = svc_rdy_ext->n_hw_mode_caps;
|
||||||
soc->wmi_ab.preferred_hw_mode);
|
|
||||||
|
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)
|
if (soc->wmi_ab.preferred_hw_mode == WMI_HOST_HW_MODE_MAX)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -4658,6 +4667,65 @@ free_dir_buff:
|
|||||||
return ret;
|
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,
|
static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab,
|
||||||
u16 tag, u16 len,
|
u16 tag, u16 len,
|
||||||
const void *ptr, void *data)
|
const void *ptr, void *data)
|
||||||
@ -4706,6 +4774,8 @@ static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ath12k_wmi_save_all_mac_phy_info(ab, svc_rdy_ext);
|
||||||
|
|
||||||
svc_rdy_ext->mac_phy_done = true;
|
svc_rdy_ext->mac_phy_done = true;
|
||||||
} else if (!svc_rdy_ext->ext_hal_reg_done) {
|
} else if (!svc_rdy_ext->ext_hal_reg_done) {
|
||||||
ret = ath12k_wmi_ext_hal_reg_caps(ab, len, ptr, svc_rdy_ext);
|
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;
|
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,
|
static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab,
|
||||||
u16 tag, u16 len,
|
u16 tag, u16 len,
|
||||||
const void *ptr, void *data)
|
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_pdev *wmi_handle = &ab->wmi_ab.wmi[0];
|
||||||
struct ath12k_wmi_svc_rdy_ext2_parse *parse = data;
|
struct ath12k_wmi_svc_rdy_ext2_parse *parse = data;
|
||||||
int ret;
|
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;
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -7626,6 +8160,64 @@ static int ath12k_wmi_pull_fw_stats(struct ath12k_base *ab, struct sk_buff *skb,
|
|||||||
&parse);
|
&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)
|
static void ath12k_update_stats_event(struct ath12k_base *ab, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct ath12k_fw_stats stats = {};
|
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);
|
spin_lock_bh(&ar->data_lock);
|
||||||
|
|
||||||
/* WMI_REQUEST_PDEV_STAT can be requested via .get_txpower mac ops or via
|
/* Handle WMI_REQUEST_PDEV_STAT status update */
|
||||||
* debugfs fw stats. Therefore, processing it separately.
|
|
||||||
*/
|
|
||||||
if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
|
if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
|
||||||
list_splice_tail_init(&stats.pdevs, &ar->fw_stats.pdevs);
|
list_splice_tail_init(&stats.pdevs, &ar->fw_stats.pdevs);
|
||||||
ar->fw_stats.fw_stats_done = true;
|
complete(&ar->fw_stats_done);
|
||||||
goto complete;
|
goto complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* WMI_REQUEST_VDEV_STAT and WMI_REQUEST_BCN_STAT are currently requested only
|
/* Handle WMI_REQUEST_VDEV_STAT and WMI_REQUEST_BCN_STAT updates. */
|
||||||
* via debugfs fw stats. Hence, processing these in debugfs context.
|
ath12k_wmi_fw_stats_process(ar, &stats);
|
||||||
*/
|
|
||||||
ath12k_debugfs_fw_stats_process(ar, &stats);
|
|
||||||
|
|
||||||
complete:
|
complete:
|
||||||
complete(&ar->fw_stats_complete);
|
complete(&ar->fw_stats_complete);
|
||||||
@ -9911,3 +10499,224 @@ int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
|
|||||||
|
|
||||||
return 0;
|
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_TPC_STATS_CTL_PWR_TABLE_EVENT,
|
||||||
WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5,
|
WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5,
|
||||||
WMI_TAG_VDEV_CH_POWER_INFO,
|
WMI_TAG_VDEV_CH_POWER_INFO,
|
||||||
|
WMI_TAG_MLO_LINK_SET_ACTIVE_CMD = 0x3BE,
|
||||||
WMI_TAG_EHT_RATE_SET = 0x3C4,
|
WMI_TAG_EHT_RATE_SET = 0x3C4,
|
||||||
WMI_TAG_DCS_AWGN_INT_TYPE = 0x3C5,
|
WMI_TAG_DCS_AWGN_INT_TYPE = 0x3C5,
|
||||||
WMI_TAG_MLO_TX_SEND_PARAMS,
|
WMI_TAG_MLO_TX_SEND_PARAMS,
|
||||||
@ -2617,6 +2618,8 @@ struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params {
|
|||||||
__le32 num_chainmask_tables;
|
__le32 num_chainmask_tables;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
#define WMI_HW_MODE_CAP_CFG_TYPE GENMASK(27, 0)
|
||||||
|
|
||||||
struct ath12k_wmi_hw_mode_cap_params {
|
struct ath12k_wmi_hw_mode_cap_params {
|
||||||
__le32 tlv_header;
|
__le32 tlv_header;
|
||||||
__le32 hw_mode_id;
|
__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_2g_ext;
|
||||||
__le32 he_cap_info_5g_ext;
|
__le32 he_cap_info_5g_ext;
|
||||||
__le32 he_cap_info_internal;
|
__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;
|
} __packed;
|
||||||
|
|
||||||
struct ath12k_wmi_hal_reg_caps_ext_params {
|
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;
|
__le32 default_num_msduq_supported_per_tid;
|
||||||
} __packed;
|
} __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 {
|
struct ath12k_wmi_caps_ext_params {
|
||||||
__le32 hw_mode_id;
|
__le32 hw_mode_id;
|
||||||
__le32 pdev_and_hw_link_ids;
|
__le32 pdev_and_hw_link_ids;
|
||||||
@ -5049,6 +5063,53 @@ struct ath12k_wmi_pdev {
|
|||||||
u32 rx_decap_mode;
|
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_wmi_base {
|
||||||
struct ath12k_base *ab;
|
struct ath12k_base *ab;
|
||||||
struct ath12k_wmi_pdev wmi[MAX_RADIOS];
|
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;
|
enum wmi_host_hw_mode_config_type preferred_hw_mode;
|
||||||
|
|
||||||
struct ath12k_wmi_target_cap_arg *targ_cap;
|
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 {
|
struct wmi_pdev_set_bios_interface_cmd {
|
||||||
@ -5997,6 +6062,118 @@ struct wmi_vdev_set_tpc_power_cmd {
|
|||||||
*/
|
*/
|
||||||
} __packed;
|
} __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,
|
void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
|
||||||
struct ath12k_wmi_resource_config_arg *config);
|
struct ath12k_wmi_resource_config_arg *config);
|
||||||
void ath12k_wmi_init_wcn7850(struct ath12k_base *ab,
|
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,
|
int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
|
||||||
u32 vdev_id,
|
u32 vdev_id,
|
||||||
struct ath12k_reg_tpc_power_info *param);
|
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
|
#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.
|
* We need to do some backwards compatibility to make this work.
|
||||||
*/
|
*/
|
||||||
if (le32_to_cpu(targ_info->byte_count) != sizeof(*targ_info)) {
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,14 +438,21 @@ static void carl9170_usb_rx_complete(struct urb *urb)
|
|||||||
|
|
||||||
if (atomic_read(&ar->rx_anch_urbs) == 0) {
|
if (atomic_read(&ar->rx_anch_urbs) == 0) {
|
||||||
/*
|
/*
|
||||||
* The system is too slow to cope with
|
* At this point, either the system is too slow to
|
||||||
* the enormous workload. We have simply
|
* cope with the enormous workload (so we have simply
|
||||||
* run out of active rx urbs and this
|
* run out of active rx urbs and this unfortunately
|
||||||
* unfortunately leads to an unpredictable
|
* leads to an unpredictable device), or the device
|
||||||
* 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).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (ar->registered)
|
||||||
ieee80211_queue_work(ar->hw, &ar->ping_work);
|
ieee80211_queue_work(ar->hw, &ar->ping_work);
|
||||||
|
else
|
||||||
|
pr_warn_once("device %s is not registered\n",
|
||||||
|
dev_name(&ar->udev->dev));
|
||||||
}
|
}
|
||||||
} else {
|
} 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));
|
sizeof(trans->conf.no_reclaim_cmds));
|
||||||
memcpy(trans->conf.no_reclaim_cmds, no_reclaim_cmds,
|
memcpy(trans->conf.no_reclaim_cmds, no_reclaim_cmds,
|
||||||
sizeof(no_reclaim_cmds));
|
sizeof(no_reclaim_cmds));
|
||||||
|
trans->conf.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
|
||||||
|
|
||||||
switch (iwlwifi_mod_params.amsdu_size) {
|
switch (iwlwifi_mod_params.amsdu_size) {
|
||||||
case IWL_AMSDU_DEF:
|
case IWL_AMSDU_DEF:
|
||||||
|
@ -77,6 +77,7 @@ void iwl_construct_mld(struct iwl_mld *mld, struct iwl_trans *trans,
|
|||||||
|
|
||||||
/* Setup async RX handling */
|
/* Setup async RX handling */
|
||||||
spin_lock_init(&mld->async_handlers_lock);
|
spin_lock_init(&mld->async_handlers_lock);
|
||||||
|
INIT_LIST_HEAD(&mld->async_handlers_list);
|
||||||
wiphy_work_init(&mld->async_handlers_wk,
|
wiphy_work_init(&mld->async_handlers_wk,
|
||||||
iwl_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,
|
WIDE_ID(MAC_CONF_GROUP,
|
||||||
MAC_CONFIG_CMD), 0);
|
MAC_CONFIG_CMD), 0);
|
||||||
|
|
||||||
if (WARN_ON(cmd_ver < 1 && cmd_ver > 3))
|
if (WARN_ON(cmd_ver < 1 || cmd_ver > 3))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cmd->id_and_color = cpu_to_le32(mvmvif->id);
|
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_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||||
struct iwl_context_info *ctxt_info;
|
struct iwl_context_info *ctxt_info;
|
||||||
struct iwl_context_info_rbd_cfg *rx_cfg;
|
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;
|
dma_addr_t phys;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -202,11 +202,12 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans,
|
|||||||
rb_size = IWL_CTXT_INFO_RB_SIZE_4K;
|
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 = IWL_CTXT_INFO_TFD_FORMAT_LONG;
|
||||||
control_flags |=
|
control_flags |= u32_encode_bits(cb_size, IWL_CTXT_INFO_RB_CB_SIZE);
|
||||||
u32_encode_bits(RX_QUEUE_CB_SIZE(iwl_trans_get_num_rbds(trans)),
|
|
||||||
IWL_CTXT_INFO_RB_CB_SIZE);
|
|
||||||
control_flags |= u32_encode_bits(rb_size, IWL_CTXT_INFO_RB_SIZE);
|
control_flags |= u32_encode_bits(rb_size, IWL_CTXT_INFO_RB_SIZE);
|
||||||
ctxt_info->control.control_flags = cpu_to_le32(control_flags);
|
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;
|
struct ptp_clock_info *ops;
|
||||||
int err = -EOPNOTSUPP;
|
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");
|
pr_err("ptp: physical clock is free running\n");
|
||||||
return -EBUSY;
|
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 */
|
/* Check if ptp virtual clock is in use */
|
||||||
static inline bool ptp_vclock_in_use(struct ptp_clock *ptp)
|
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 */
|
/* 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;
|
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)
|
static inline void atm_force_charge(struct atm_vcc *vcc,int truesize)
|
||||||
{
|
{
|
||||||
atomic_add(truesize, &sk_atm(vcc)->sk_rmem_alloc);
|
atomic_add(truesize, &sk_atm(vcc)->sk_rmem_alloc);
|
||||||
|
@ -1278,7 +1278,7 @@ struct ieee80211_ext {
|
|||||||
u8 sa[ETH_ALEN];
|
u8 sa[ETH_ALEN];
|
||||||
__le32 timestamp;
|
__le32 timestamp;
|
||||||
u8 change_seq;
|
u8 change_seq;
|
||||||
u8 variable[0];
|
u8 variable[];
|
||||||
} __packed s1g_beacon;
|
} __packed s1g_beacon;
|
||||||
} u;
|
} u;
|
||||||
} __packed __aligned(2);
|
} __packed __aligned(2);
|
||||||
@ -1536,7 +1536,7 @@ struct ieee80211_mgmt {
|
|||||||
u8 action_code;
|
u8 action_code;
|
||||||
u8 dialog_token;
|
u8 dialog_token;
|
||||||
__le16 capability;
|
__le16 capability;
|
||||||
u8 variable[0];
|
u8 variable[];
|
||||||
} __packed tdls_discover_resp;
|
} __packed tdls_discover_resp;
|
||||||
struct {
|
struct {
|
||||||
u8 action_code;
|
u8 action_code;
|
||||||
@ -1721,35 +1721,35 @@ struct ieee80211_tdls_data {
|
|||||||
struct {
|
struct {
|
||||||
u8 dialog_token;
|
u8 dialog_token;
|
||||||
__le16 capability;
|
__le16 capability;
|
||||||
u8 variable[0];
|
u8 variable[];
|
||||||
} __packed setup_req;
|
} __packed setup_req;
|
||||||
struct {
|
struct {
|
||||||
__le16 status_code;
|
__le16 status_code;
|
||||||
u8 dialog_token;
|
u8 dialog_token;
|
||||||
__le16 capability;
|
__le16 capability;
|
||||||
u8 variable[0];
|
u8 variable[];
|
||||||
} __packed setup_resp;
|
} __packed setup_resp;
|
||||||
struct {
|
struct {
|
||||||
__le16 status_code;
|
__le16 status_code;
|
||||||
u8 dialog_token;
|
u8 dialog_token;
|
||||||
u8 variable[0];
|
u8 variable[];
|
||||||
} __packed setup_cfm;
|
} __packed setup_cfm;
|
||||||
struct {
|
struct {
|
||||||
__le16 reason_code;
|
__le16 reason_code;
|
||||||
u8 variable[0];
|
u8 variable[];
|
||||||
} __packed teardown;
|
} __packed teardown;
|
||||||
struct {
|
struct {
|
||||||
u8 dialog_token;
|
u8 dialog_token;
|
||||||
u8 variable[0];
|
u8 variable[];
|
||||||
} __packed discover_req;
|
} __packed discover_req;
|
||||||
struct {
|
struct {
|
||||||
u8 target_channel;
|
u8 target_channel;
|
||||||
u8 oper_class;
|
u8 oper_class;
|
||||||
u8 variable[0];
|
u8 variable[];
|
||||||
} __packed chan_switch_req;
|
} __packed chan_switch_req;
|
||||||
struct {
|
struct {
|
||||||
__le16 status_code;
|
__le16 status_code;
|
||||||
u8 variable[0];
|
u8 variable[];
|
||||||
} __packed chan_switch_resp;
|
} __packed chan_switch_resp;
|
||||||
} u;
|
} u;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
@ -208,10 +208,6 @@ enum {
|
|||||||
ETHTOOL_A_STATS_PHY_MAX = (__ETHTOOL_A_STATS_PHY_CNT - 1)
|
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"
|
#define ETHTOOL_MCGRP_MONITOR_NAME "monitor"
|
||||||
|
|
||||||
#endif /* _UAPI_LINUX_ETHTOOL_NETLINK_H_ */
|
#endif /* _UAPI_LINUX_ETHTOOL_NETLINK_H_ */
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
#ifndef _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H
|
#ifndef _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H
|
||||||
#define _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H
|
#define _UAPI_LINUX_ETHTOOL_NETLINK_GENERATED_H
|
||||||
|
|
||||||
#define ETHTOOL_FAMILY_NAME "ethtool"
|
#define ETHTOOL_GENL_NAME "ethtool"
|
||||||
#define ETHTOOL_FAMILY_VERSION 1
|
#define ETHTOOL_GENL_VERSION 1
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ETHTOOL_UDP_TUNNEL_TYPE_VXLAN,
|
ETHTOOL_UDP_TUNNEL_TYPE_VXLAN,
|
||||||
|
@ -716,6 +716,7 @@ config GENERIC_LIB_DEVMEM_IS_ALLOWED
|
|||||||
|
|
||||||
config PLDMFW
|
config PLDMFW
|
||||||
bool
|
bool
|
||||||
|
select CRC32
|
||||||
default n
|
default n
|
||||||
|
|
||||||
config ASN1_ENCODER
|
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 */
|
skb->dev = NULL; /* for paths shared with net_device interfaces */
|
||||||
if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) {
|
if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) {
|
||||||
|
atm_return_tx(vcc, skb);
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
error = -EFAULT;
|
error = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -124,6 +124,7 @@ static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|||||||
|
|
||||||
/* Device structures */
|
/* Device structures */
|
||||||
static struct net_device *dev_lec[MAX_LEC_ITF];
|
static struct net_device *dev_lec[MAX_LEC_ITF];
|
||||||
|
static DEFINE_MUTEX(lec_mutex);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_BRIDGE)
|
#if IS_ENABLED(CONFIG_BRIDGE)
|
||||||
static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
|
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;
|
int bytes_left;
|
||||||
struct atmlec_ioc ioc_data;
|
struct atmlec_ioc ioc_data;
|
||||||
|
|
||||||
|
lockdep_assert_held(&lec_mutex);
|
||||||
/* Lecd must be up in this case */
|
/* Lecd must be up in this case */
|
||||||
bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
|
bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
|
||||||
if (bytes_left != 0)
|
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)
|
static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
|
||||||
{
|
{
|
||||||
|
lockdep_assert_held(&lec_mutex);
|
||||||
if (arg < 0 || arg >= MAX_LEC_ITF)
|
if (arg < 0 || arg >= MAX_LEC_ITF)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
arg = array_index_nospec(arg, MAX_LEC_ITF);
|
arg = array_index_nospec(arg, MAX_LEC_ITF);
|
||||||
@ -725,6 +728,7 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
|
|||||||
int i;
|
int i;
|
||||||
struct lec_priv *priv;
|
struct lec_priv *priv;
|
||||||
|
|
||||||
|
lockdep_assert_held(&lec_mutex);
|
||||||
if (arg < 0)
|
if (arg < 0)
|
||||||
arg = 0;
|
arg = 0;
|
||||||
if (arg >= MAX_LEC_ITF)
|
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);
|
snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
|
||||||
if (register_netdev(dev_lec[i])) {
|
if (register_netdev(dev_lec[i])) {
|
||||||
free_netdev(dev_lec[i]);
|
free_netdev(dev_lec[i]);
|
||||||
|
dev_lec[i] = NULL;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -904,7 +909,6 @@ static void *lec_itf_walk(struct lec_state *state, loff_t *l)
|
|||||||
v = (dev && netdev_priv(dev)) ?
|
v = (dev && netdev_priv(dev)) ?
|
||||||
lec_priv_walk(state, l, netdev_priv(dev)) : NULL;
|
lec_priv_walk(state, l, netdev_priv(dev)) : NULL;
|
||||||
if (!v && dev) {
|
if (!v && dev) {
|
||||||
dev_put(dev);
|
|
||||||
/* Partial state reset for the next time we get called */
|
/* Partial state reset for the next time we get called */
|
||||||
dev = NULL;
|
dev = NULL;
|
||||||
}
|
}
|
||||||
@ -928,6 +932,7 @@ static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
|
|||||||
{
|
{
|
||||||
struct lec_state *state = seq->private;
|
struct lec_state *state = seq->private;
|
||||||
|
|
||||||
|
mutex_lock(&lec_mutex);
|
||||||
state->itf = 0;
|
state->itf = 0;
|
||||||
state->dev = NULL;
|
state->dev = NULL;
|
||||||
state->locked = NULL;
|
state->locked = NULL;
|
||||||
@ -945,8 +950,9 @@ static void lec_seq_stop(struct seq_file *seq, void *v)
|
|||||||
if (state->dev) {
|
if (state->dev) {
|
||||||
spin_unlock_irqrestore(&state->locked->lec_arp_lock,
|
spin_unlock_irqrestore(&state->locked->lec_arp_lock,
|
||||||
state->flags);
|
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)
|
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;
|
return -ENOIOCTLCMD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&lec_mutex);
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case ATMLEC_CTRL:
|
case ATMLEC_CTRL:
|
||||||
err = lecd_attach(vcc, (int)arg);
|
err = lecd_attach(vcc, (int)arg);
|
||||||
@ -1017,6 +1024,7 @@ static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&lec_mutex);
|
||||||
return err;
|
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",
|
pr_debug("(%d) %d -= %d\n",
|
||||||
vcc->vci, sk_wmem_alloc_get(sk), ATM_SKB(skb)->acct_truesize);
|
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);
|
dev_kfree_skb_any(skb);
|
||||||
sk->sk_write_space(sk);
|
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))
|
if (!pskb_may_pull(skb, write_len))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (!skb_frags_readable(skb))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
if (!skb_cloned(skb) || skb_clone_writable(skb, write_len))
|
if (!skb_cloned(skb) || skb_clone_writable(skb, write_len))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <linux/tcp.h>
|
#include <linux/tcp.h>
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
#include <net/tcp.h>
|
#include <net/tcp.h>
|
||||||
|
#include <net/busy_poll.h>
|
||||||
|
|
||||||
void tcp_fastopen_init_key_once(struct net *net)
|
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);
|
refcount_set(&req->rsk_refcnt, 2);
|
||||||
|
|
||||||
|
sk_mark_napi_id_set(child, skb);
|
||||||
|
|
||||||
/* Now finish processing the fastopen child socket. */
|
/* Now finish processing the fastopen child socket. */
|
||||||
tcp_init_transfer(child, BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB, skb);
|
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;
|
const struct sock *sk = (const struct sock *)tp;
|
||||||
|
|
||||||
if (tp->retrans_stamp &&
|
/* Received an echoed timestamp before the first retransmission? */
|
||||||
tcp_tsopt_ecr_before(tp, tp->retrans_stamp))
|
if (tp->retrans_stamp)
|
||||||
return true; /* got echoed TS before first retransmission */
|
return tcp_tsopt_ecr_before(tp, tp->retrans_stamp);
|
||||||
|
|
||||||
/* Check if nothing was retransmitted (retrans_stamp==0), which may
|
/* We set tp->retrans_stamp upon the first retransmission of a loss
|
||||||
* happen in fast recovery due to TSQ. But we ignore zero retrans_stamp
|
* recovery episode, so normally if tp->retrans_stamp is 0 then no
|
||||||
* in TCP_SYN_SENT, since when we set FLAG_SYN_ACKED we also clear
|
* retransmission has happened yet (likely due to TSQ, which can cause
|
||||||
* retrans_stamp even if we had retransmitted the SYN.
|
* 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 */
|
|
||||||
|
|
||||||
|
/* (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;
|
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. */
|
/* Undo procedures. */
|
||||||
|
@ -1207,6 +1207,10 @@ static int calipso_req_setattr(struct request_sock *req,
|
|||||||
struct ipv6_opt_hdr *old, *new;
|
struct ipv6_opt_hdr *old, *new;
|
||||||
struct sock *sk = sk_to_full_sk(req_to_sk(req));
|
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)
|
if (req_inet->ipv6_opt && req_inet->ipv6_opt->hopopt)
|
||||||
old = req_inet->ipv6_opt->hopopt;
|
old = req_inet->ipv6_opt->hopopt;
|
||||||
else
|
else
|
||||||
@ -1247,6 +1251,10 @@ static void calipso_req_delattr(struct request_sock *req)
|
|||||||
struct ipv6_txoptions *txopts;
|
struct ipv6_txoptions *txopts;
|
||||||
struct sock *sk = sk_to_full_sk(req_to_sk(req));
|
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)
|
if (!req_inet->ipv6_opt || !req_inet->ipv6_opt->hopopt)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/*
|
/*
|
||||||
* Portions
|
* Portions
|
||||||
* Copyright (C) 2022 - 2024 Intel Corporation
|
* Copyright (C) 2022 - 2025 Intel Corporation
|
||||||
*/
|
*/
|
||||||
#ifndef __MAC80211_DEBUG_H
|
#ifndef __MAC80211_DEBUG_H
|
||||||
#define __MAC80211_DEBUG_H
|
#define __MAC80211_DEBUG_H
|
||||||
|
#include <linux/once_lite.h>
|
||||||
#include <net/cfg80211.h>
|
#include <net/cfg80211.h>
|
||||||
|
|
||||||
#ifdef CONFIG_MAC80211_OCB_DEBUG
|
#ifdef CONFIG_MAC80211_OCB_DEBUG
|
||||||
@ -152,6 +153,8 @@ do { \
|
|||||||
else \
|
else \
|
||||||
_sdata_err((link)->sdata, fmt, ##__VA_ARGS__); \
|
_sdata_err((link)->sdata, fmt, ##__VA_ARGS__); \
|
||||||
} while (0)
|
} 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, ...) \
|
#define link_id_info(sdata, link_id, fmt, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (ieee80211_vif_is_mld(&sdata->vif)) \
|
if (ieee80211_vif_is_mld(&sdata->vif)) \
|
||||||
|
@ -4432,6 +4432,10 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
|
|||||||
if (!multicast &&
|
if (!multicast &&
|
||||||
!ether_addr_equal(sdata->dev->dev_addr, hdr->addr1))
|
!ether_addr_equal(sdata->dev->dev_addr, hdr->addr1))
|
||||||
return false;
|
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) {
|
if (!rx->sta) {
|
||||||
int rate_idx;
|
int rate_idx;
|
||||||
if (status->encoding != RX_ENC_LEGACY)
|
if (status->encoding != RX_ENC_LEGACY)
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||||
* Copyright (C) 2018-2024 Intel Corporation
|
* Copyright (C) 2018-2025 Intel Corporation
|
||||||
*
|
*
|
||||||
* Transmit and frame generation functions.
|
* 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 */
|
beacon->cntdwn_current_counter--;
|
||||||
WARN_ON_ONCE(!beacon->cntdwn_current_counter);
|
|
||||||
|
|
||||||
return 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)
|
if (!beacon)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
count = __ieee80211_beacon_update_cntdwn(beacon);
|
count = __ieee80211_beacon_update_cntdwn(link, beacon);
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
@ -5450,7 +5463,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||||||
|
|
||||||
if (beacon->cntdwn_counter_offsets[0]) {
|
if (beacon->cntdwn_counter_offsets[0]) {
|
||||||
if (!is_template)
|
if (!is_template)
|
||||||
__ieee80211_beacon_update_cntdwn(beacon);
|
__ieee80211_beacon_update_cntdwn(link, beacon);
|
||||||
|
|
||||||
ieee80211_set_beacon_cntdwn(sdata, beacon, link);
|
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
|
* for now we leave it consistent with overall
|
||||||
* mac80211's behavior.
|
* mac80211's behavior.
|
||||||
*/
|
*/
|
||||||
__ieee80211_beacon_update_cntdwn(beacon);
|
__ieee80211_beacon_update_cntdwn(link, beacon);
|
||||||
|
|
||||||
ieee80211_set_beacon_cntdwn(sdata, beacon, link);
|
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) {
|
if (index < net->mpls.platform_labels) {
|
||||||
struct mpls_route __rcu **platform_label =
|
struct mpls_route __rcu **platform_label =
|
||||||
rcu_dereference(net->mpls.platform_label);
|
rcu_dereference_rtnl(net->mpls.platform_label);
|
||||||
rt = rcu_dereference(platform_label[index]);
|
rt = rcu_dereference_rtnl(platform_label[index]);
|
||||||
}
|
}
|
||||||
return rt;
|
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));
|
memcpy(nu, nci_uart_drivers[driver], sizeof(struct nci_uart));
|
||||||
nu->tty = tty;
|
nu->tty = tty;
|
||||||
tty->disc_data = nu;
|
|
||||||
skb_queue_head_init(&nu->tx_q);
|
skb_queue_head_init(&nu->tx_q);
|
||||||
INIT_WORK(&nu->write_work, nci_uart_write_work);
|
INIT_WORK(&nu->write_work, nci_uart_write_work);
|
||||||
spin_lock_init(&nu->rx_lock);
|
spin_lock_init(&nu->rx_lock);
|
||||||
|
|
||||||
ret = nu->ops.open(nu);
|
ret = nu->ops.open(nu);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
tty->disc_data = NULL;
|
|
||||||
kfree(nu);
|
kfree(nu);
|
||||||
|
return ret;
|
||||||
} else if (!try_module_get(nu->owner)) {
|
} else if (!try_module_get(nu->owner)) {
|
||||||
nu->ops.close(nu);
|
nu->ops.close(nu);
|
||||||
tty->disc_data = NULL;
|
|
||||||
kfree(nu);
|
kfree(nu);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
return ret;
|
tty->disc_data = nu;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------ LDISC part ------ */
|
/* ------ LDISC part ------ */
|
||||||
|
@ -39,16 +39,14 @@
|
|||||||
#include "flow_netlink.h"
|
#include "flow_netlink.h"
|
||||||
#include "openvswitch_trace.h"
|
#include "openvswitch_trace.h"
|
||||||
|
|
||||||
DEFINE_PER_CPU(struct ovs_pcpu_storage, ovs_pcpu_storage) = {
|
struct ovs_pcpu_storage __percpu *ovs_pcpu_storage;
|
||||||
.bh_lock = INIT_LOCAL_LOCK(bh_lock),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Make a clone of the 'key', using the pre-allocated percpu 'flow_keys'
|
/* Make a clone of the 'key', using the pre-allocated percpu 'flow_keys'
|
||||||
* space. Return NULL if out of key spaces.
|
* space. Return NULL if out of key spaces.
|
||||||
*/
|
*/
|
||||||
static struct sw_flow_key *clone_key(const struct sw_flow_key *key_)
|
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;
|
struct action_flow_keys *keys = &ovs_pcpu->flow_keys;
|
||||||
int level = ovs_pcpu->exec_level;
|
int level = ovs_pcpu->exec_level;
|
||||||
struct sw_flow_key *key = NULL;
|
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 struct nlattr *actions,
|
||||||
const int actions_len)
|
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;
|
struct deferred_action *da;
|
||||||
|
|
||||||
da = action_fifo_put(fifo);
|
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,
|
static int ovs_vport_output(struct net *net, struct sock *sk,
|
||||||
struct sk_buff *skb)
|
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;
|
struct vport *vport = data->vport;
|
||||||
|
|
||||||
if (skb_cow_head(skb, data->l2_len) < 0) {
|
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);
|
unsigned int hlen = skb_network_offset(skb);
|
||||||
struct ovs_frag_data *data;
|
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->dst = skb->_skb_refdst;
|
||||||
data->vport = vport;
|
data->vport = vport;
|
||||||
data->cb = *OVS_CB(skb);
|
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;
|
clone = clone_flow_key ? clone_key(key) : key;
|
||||||
if (clone) {
|
if (clone) {
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (actions) { /* Sample action */
|
if (actions) { /* Sample action */
|
||||||
if (clone_flow_key)
|
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,
|
err = do_execute_actions(dp, skb, clone,
|
||||||
actions, len);
|
actions, len);
|
||||||
|
|
||||||
if (clone_flow_key)
|
if (clone_flow_key)
|
||||||
__this_cpu_dec(ovs_pcpu_storage.exec_level);
|
__this_cpu_dec(ovs_pcpu_storage->exec_level);
|
||||||
} else { /* Recirc action */
|
} else { /* Recirc action */
|
||||||
clone->recirc_id = recirc_id;
|
clone->recirc_id = recirc_id;
|
||||||
ovs_dp_process_packet(skb, clone);
|
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)
|
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. */
|
/* Do not touch the FIFO in case there is no deferred actions. */
|
||||||
if (action_fifo_is_empty(fifo))
|
if (action_fifo_is_empty(fifo))
|
||||||
@ -1642,7 +1639,7 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
|
|||||||
{
|
{
|
||||||
int err, level;
|
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)) {
|
if (unlikely(level > OVS_RECURSION_LIMIT)) {
|
||||||
net_crit_ratelimited("ovs: recursion limit reached on datapath %s, probable configuration error\n",
|
net_crit_ratelimited("ovs: recursion limit reached on datapath %s, probable configuration error\n",
|
||||||
ovs_dp_name(dp));
|
ovs_dp_name(dp));
|
||||||
@ -1659,6 +1656,6 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
|
|||||||
process_deferred_actions(dp);
|
process_deferred_actions(dp);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
__this_cpu_dec(ovs_pcpu_storage.exec_level);
|
__this_cpu_dec(ovs_pcpu_storage->exec_level);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ void ovs_dp_detach_port(struct vport *p)
|
|||||||
/* Must be called with rcu_read_lock. */
|
/* Must be called with rcu_read_lock. */
|
||||||
void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
|
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;
|
const struct vport *p = OVS_CB(skb)->input_vport;
|
||||||
struct datapath *dp = p->dp;
|
struct datapath *dp = p->dp;
|
||||||
struct sw_flow *flow;
|
struct sw_flow *flow;
|
||||||
@ -299,7 +299,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
|
|||||||
* avoided.
|
* avoided.
|
||||||
*/
|
*/
|
||||||
if (IS_ENABLED(CONFIG_PREEMPT_RT) && ovs_pcpu->owner != current) {
|
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->owner = current;
|
||||||
ovs_pcpu_locked = true;
|
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);
|
ovs_dp_name(dp), error);
|
||||||
if (ovs_pcpu_locked) {
|
if (ovs_pcpu_locked) {
|
||||||
ovs_pcpu->owner = NULL;
|
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;
|
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);
|
sf_acts = rcu_dereference(flow->sf_acts);
|
||||||
|
|
||||||
local_bh_disable();
|
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))
|
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);
|
err = ovs_execute_actions(dp, packet, sf_acts, &flow->key);
|
||||||
if (IS_ENABLED(CONFIG_PREEMPT_RT))
|
if (IS_ENABLED(CONFIG_PREEMPT_RT))
|
||||||
this_cpu_write(ovs_pcpu_storage.owner, NULL);
|
this_cpu_write(ovs_pcpu_storage->owner, NULL);
|
||||||
local_unlock_nested_bh(&ovs_pcpu_storage.bh_lock);
|
local_unlock_nested_bh(&ovs_pcpu_storage->bh_lock);
|
||||||
local_bh_enable();
|
local_bh_enable();
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
@ -2744,6 +2744,28 @@ static struct drop_reason_list drop_reason_list_ovs = {
|
|||||||
.n_reasons = ARRAY_SIZE(ovs_drop_reasons),
|
.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)
|
static int __init dp_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@ -2753,6 +2775,10 @@ static int __init dp_init(void)
|
|||||||
|
|
||||||
pr_info("Open vSwitch switching datapath\n");
|
pr_info("Open vSwitch switching datapath\n");
|
||||||
|
|
||||||
|
err = ovs_alloc_percpu_storage();
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
err = ovs_internal_dev_rtnl_link_register();
|
err = ovs_internal_dev_rtnl_link_register();
|
||||||
if (err)
|
if (err)
|
||||||
goto error;
|
goto error;
|
||||||
@ -2799,6 +2825,7 @@ error_flow_exit:
|
|||||||
error_unreg_rtnl_link:
|
error_unreg_rtnl_link:
|
||||||
ovs_internal_dev_rtnl_link_unregister();
|
ovs_internal_dev_rtnl_link_unregister();
|
||||||
error:
|
error:
|
||||||
|
ovs_free_percpu_storage();
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2813,6 +2840,7 @@ static void dp_cleanup(void)
|
|||||||
ovs_vport_exit();
|
ovs_vport_exit();
|
||||||
ovs_flow_exit();
|
ovs_flow_exit();
|
||||||
ovs_internal_dev_rtnl_link_unregister();
|
ovs_internal_dev_rtnl_link_unregister();
|
||||||
|
ovs_free_percpu_storage();
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(dp_init);
|
module_init(dp_init);
|
||||||
|
@ -220,7 +220,8 @@ struct ovs_pcpu_storage {
|
|||||||
struct task_struct *owner;
|
struct task_struct *owner;
|
||||||
local_lock_t bh_lock;
|
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
|
* 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);
|
stab = rtnl_dereference(q->root->stab);
|
||||||
|
|
||||||
oper = rtnl_dereference(q->oper_sched);
|
rcu_read_lock();
|
||||||
|
oper = rcu_dereference(q->oper_sched);
|
||||||
if (oper)
|
if (oper)
|
||||||
taprio_update_queue_max_sdu(q, oper, stab);
|
taprio_update_queue_max_sdu(q, oper, stab);
|
||||||
|
|
||||||
admin = rtnl_dereference(q->admin_sched);
|
admin = rcu_dereference(q->admin_sched);
|
||||||
if (admin)
|
if (admin)
|
||||||
taprio_update_queue_max_sdu(q, admin, stab);
|
taprio_update_queue_max_sdu(q, admin, stab);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -489,7 +489,7 @@ int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb)
|
|||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
b = tipc_bearer_find(net, bname);
|
b = tipc_bearer_find(net, bname);
|
||||||
if (!b) {
|
if (!b || b->bcast_addr.media_id != TIPC_MEDIA_TYPE_UDP) {
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -500,7 +500,7 @@ int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb)
|
|||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
b = rtnl_dereference(tn->bearer_list[bid]);
|
b = rtnl_dereference(tn->bearer_list[bid]);
|
||||||
if (!b) {
|
if (!b || b->bcast_addr.media_id != TIPC_MEDIA_TYPE_UDP) {
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -231,14 +231,7 @@ class NlMsg:
|
|||||||
self.extack['unknown'].append(extack)
|
self.extack['unknown'].append(extack)
|
||||||
|
|
||||||
if attr_space:
|
if attr_space:
|
||||||
# We don't have the ability to parse nests yet, so only do global
|
self.annotate_extack(attr_space)
|
||||||
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 _decode_policy(self, raw):
|
def _decode_policy(self, raw):
|
||||||
policy = {}
|
policy = {}
|
||||||
@ -264,6 +257,18 @@ class NlMsg:
|
|||||||
policy['mask'] = attr.as_scalar('u64')
|
policy['mask'] = attr.as_scalar('u64')
|
||||||
return policy
|
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):
|
def cmd(self):
|
||||||
return self.nl_type
|
return self.nl_type
|
||||||
|
|
||||||
@ -277,12 +282,12 @@ class NlMsg:
|
|||||||
|
|
||||||
|
|
||||||
class NlMsgs:
|
class NlMsgs:
|
||||||
def __init__(self, data, attr_space=None):
|
def __init__(self, data):
|
||||||
self.msgs = []
|
self.msgs = []
|
||||||
|
|
||||||
offset = 0
|
offset = 0
|
||||||
while offset < len(data):
|
while offset < len(data):
|
||||||
msg = NlMsg(data, offset, attr_space=attr_space)
|
msg = NlMsg(data, offset)
|
||||||
offset += msg.nl_len
|
offset += msg.nl_len
|
||||||
self.msgs.append(msg)
|
self.msgs.append(msg)
|
||||||
|
|
||||||
@ -1034,12 +1039,13 @@ class YnlFamily(SpecFamily):
|
|||||||
op_rsp = []
|
op_rsp = []
|
||||||
while not done:
|
while not done:
|
||||||
reply = self.sock.recv(self._recv_size)
|
reply = self.sock.recv(self._recv_size)
|
||||||
nms = NlMsgs(reply, attr_space=op.attr_set)
|
nms = NlMsgs(reply)
|
||||||
self._recv_dbg_print(reply, nms)
|
self._recv_dbg_print(reply, nms)
|
||||||
for nl_msg in nms:
|
for nl_msg in nms:
|
||||||
if nl_msg.nl_seq in reqs_by_seq:
|
if nl_msg.nl_seq in reqs_by_seq:
|
||||||
(op, vals, req_msg, req_flags) = reqs_by_seq[nl_msg.nl_seq]
|
(op, vals, req_msg, req_flags) = reqs_by_seq[nl_msg.nl_seq]
|
||||||
if nl_msg.extack:
|
if nl_msg.extack:
|
||||||
|
nl_msg.annotate_extack(op.attr_set)
|
||||||
self._decode_extack(req_msg, op, nl_msg.extack, vals)
|
self._decode_extack(req_msg, op, nl_msg.extack, vals)
|
||||||
else:
|
else:
|
||||||
op = None
|
op = None
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# 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_ID=$((256 + RANDOM % 256))
|
||||||
NSIM_DEV_1_SYS=/sys/bus/netdevsim/devices/netdevsim$NSIM_DEV_1_ID
|
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_fastopen_backup_key
|
||||||
tcp_inq
|
tcp_inq
|
||||||
tcp_mmap
|
tcp_mmap
|
||||||
|
tfo
|
||||||
timestamping
|
timestamping
|
||||||
tls
|
tls
|
||||||
toeplitz
|
toeplitz
|
||||||
|
@ -110,6 +110,8 @@ TEST_GEN_PROGS += proc_net_pktgen
|
|||||||
TEST_PROGS += lwt_dst_cache_ref_loop.sh
|
TEST_PROGS += lwt_dst_cache_ref_loop.sh
|
||||||
TEST_PROGS += skf_net_off.sh
|
TEST_PROGS += skf_net_off.sh
|
||||||
TEST_GEN_FILES += skf_net_off
|
TEST_GEN_FILES += skf_net_off
|
||||||
|
TEST_GEN_FILES += tfo
|
||||||
|
TEST_PROGS += tfo_passive.sh
|
||||||
|
|
||||||
# YNL files, must be before "include ..lib.mk"
|
# YNL files, must be before "include ..lib.mk"
|
||||||
YNL_GEN_FILES := busy_poller netlink-dumps
|
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