diff options
Diffstat (limited to 'drivers')
51 files changed, 572 insertions, 193 deletions
diff --git a/drivers/dibs/dibs_main.c b/drivers/dibs/dibs_main.c index 14c3e2d84902..4c26fd06973f 100644 --- a/drivers/dibs/dibs_main.c +++ b/drivers/dibs/dibs_main.c @@ -138,6 +138,7 @@ struct dibs_dev *dibs_dev_alloc(void) dibs = kzalloc_obj(*dibs); if (!dibs) return dibs; + spin_lock_init(&dibs->lock); dibs->dev.release = dibs_dev_release; dibs->dev.class = &dibs_class; device_initialize(&dibs->dev); @@ -186,7 +187,6 @@ int dibs_dev_add(struct dibs_dev *dibs) int i, ret; max_dmbs = dibs->ops->max_dmbs(); - spin_lock_init(&dibs->lock); dibs->dmb_clientid_arr = kzalloc(max_dmbs, GFP_KERNEL); if (!dibs->dmb_clientid_arr) return -ENOMEM; diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 2d37b07c8215..839f7482dc18 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1534,8 +1534,8 @@ void bond_alb_monitor(struct work_struct *work) struct bonding *bond = container_of(work, struct bonding, alb_work.work); struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct slave *slave, *curr; struct list_head *iter; - struct slave *slave; if (!bond_has_slaves(bond)) { atomic_set(&bond_info->tx_rebalance_counter, 0); @@ -1597,9 +1597,11 @@ void bond_alb_monitor(struct work_struct *work) * because a slave was disabled then * it can now leave promiscuous mode. */ - dev_set_promiscuity(rtnl_dereference(bond->curr_active_slave)->dev, - -1); - bond_info->primary_is_promisc = 0; + curr = rtnl_dereference(bond->curr_active_slave); + if (bond_info->primary_is_promisc && curr) { + dev_set_promiscuity(curr->dev, -1); + bond_info->primary_is_promisc = 0; + } rtnl_unlock(); rcu_read_lock(); diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h index b7fe9ad73349..a1d41329209f 100644 --- a/drivers/net/ethernet/amd/pds_core/core.h +++ b/drivers/net/ethernet/amd/pds_core/core.h @@ -171,6 +171,7 @@ struct pdsc { struct timer_list wdtimer; unsigned int wdtimer_period; struct work_struct health_work; + bool health_stopped; struct devlink_health_reporter *fw_reporter; u32 fw_recoveries; diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c index 8d94a4d70395..9a2c64198d03 100644 --- a/drivers/net/ethernet/amd/pds_core/main.c +++ b/drivers/net/ethernet/amd/pds_core/main.c @@ -470,8 +470,10 @@ static void pdsc_stop_health_thread(struct pdsc *pdsc) return; timer_shutdown_sync(&pdsc->wdtimer); - if (pdsc->health_work.func) - cancel_work_sync(&pdsc->health_work); + if (pdsc->health_work.func && !pdsc->health_stopped) { + disable_work_sync(&pdsc->health_work); + pdsc->health_stopped = true; + } } static void pdsc_restart_health_thread(struct pdsc *pdsc) @@ -479,6 +481,10 @@ static void pdsc_restart_health_thread(struct pdsc *pdsc) if (pdsc->pdev->is_virtfn) return; + if (pdsc->health_stopped) { + enable_work(&pdsc->health_work); + pdsc->health_stopped = false; + } timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0); mod_timer(&pdsc->wdtimer, jiffies + 1); } @@ -555,7 +561,11 @@ static pci_ers_result_t pdsc_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t error) { if (error == pci_channel_io_frozen) { + struct pdsc *pdsc = pci_get_drvdata(pdev); + pdsc_reset_prepare(pdev); + if (!pdev->is_virtfn) + cancel_work_sync(&pdsc->pci_reset_work); return PCI_ERS_RESULT_NEED_RESET; } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index 8ff07de2bd52..e1193c6719d9 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -360,6 +360,35 @@ out: return !!budget; } +void aq_ring_tx_deinit(struct aq_ring_s *self) +{ + if (!self) + return; + + for (; self->sw_head != self->sw_tail; + self->sw_head = aq_ring_next_dx(self, self->sw_head)) { + struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head]; + struct device *ndev = aq_nic_get_dev(self->aq_nic); + + if (buff->is_mapped) { + if (buff->is_sop) { + dma_unmap_single(ndev, buff->pa, buff->len, + DMA_TO_DEVICE); + } else { + dma_unmap_page(ndev, buff->pa, buff->len, + DMA_TO_DEVICE); + } + } + + if (buff->is_eop) { + if (buff->skb) + dev_kfree_skb_any(buff->skb); + else if (buff->xdpf) + xdp_return_frame(buff->xdpf); + } + } +} + static void aq_rx_checksum(struct aq_ring_s *self, struct aq_ring_buff_s *buff, struct sk_buff *skb) @@ -921,15 +950,29 @@ err_exit: void aq_ring_rx_deinit(struct aq_ring_s *self) { - if (!self) + unsigned int i; + + if (!self || !self->buff_ring) return; - for (; self->sw_head != self->sw_tail; - self->sw_head = aq_ring_next_dx(self, self->sw_head)) { - struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head]; + /* Release every page still owned by the ring. + * + * Walking [sw_head, sw_tail) is not enough: refill is batched + * (aq_ring_rx_fill() waits for AQ_CFG_RX_REFILL_THRES free slots), + * so slots that were cleaned but not yet reposted accumulate in the + * [sw_tail, sw_head) gap, and they keep their page for reuse. Walk + * the whole ring and release whatever is left. + */ + for (i = 0; i < self->size; i++) { + struct aq_ring_buff_s *buff = &self->buff_ring[i]; + + if (!buff->rxdata.page) + continue; aq_free_rxpage(&buff->rxdata, aq_nic_get_dev(self->aq_nic)); } + + self->sw_head = self->sw_tail; } void aq_ring_free(struct aq_ring_s *self) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h index a70b880ada67..6431cc62962f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h @@ -202,6 +202,7 @@ void aq_ring_update_queue_state(struct aq_ring_s *ring); void aq_ring_queue_wake(struct aq_ring_s *ring); void aq_ring_queue_stop(struct aq_ring_s *ring); bool aq_ring_tx_clean(struct aq_ring_s *self); +void aq_ring_tx_deinit(struct aq_ring_s *self); int aq_xdp_xmit(struct net_device *dev, int num_frames, struct xdp_frame **frames, u32 flags); int aq_ring_rx_clean(struct aq_ring_s *self, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c index 2f9033ceed8c..05814fea0f5f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c @@ -275,7 +275,7 @@ void aq_vec_deinit(struct aq_vec_s *self) for (i = 0U; self->tx_rings > i; ++i) { ring = self->ring[i]; - aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]); + aq_ring_tx_deinit(&ring[AQ_VEC_TX_ID]); aq_ring_rx_deinit(&ring[AQ_VEC_RX_ID]); } diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_auxr.c b/drivers/net/ethernet/broadcom/bnge/bnge_auxr.c index 67e93e17d4d9..0955b488b6fe 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_auxr.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_auxr.c @@ -141,12 +141,15 @@ static void bnge_aux_dev_release(struct device *dev) { struct bnge_auxr_priv *aux_priv = container_of(dev, struct bnge_auxr_priv, aux_dev.dev); - struct bnge_dev *bd = pci_get_drvdata(aux_priv->auxr_dev->pdev); + struct bnge_auxr_dev *auxr_dev = aux_priv->auxr_dev; + struct bnge_dev *bd = pci_get_drvdata(to_pci_dev(dev->parent)); ida_free(&bnge_aux_dev_ids, aux_priv->id); - kfree(aux_priv->auxr_dev->auxr_info); + if (auxr_dev) { + kfree(auxr_dev->auxr_info); + kfree(auxr_dev); + } bd->auxr_dev = NULL; - kfree(aux_priv->auxr_dev); kfree(aux_priv); bd->aux_priv = NULL; } diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c index 6f7ef506d4e1..ac4c93e5b634 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c @@ -2768,8 +2768,6 @@ static int bnge_init_nic(struct bnge_net *bn) err_free_ring_grps: bnge_free_ring_grps(bn); - return rc; - err_free_rx_ring_pair_bufs: bnge_free_rx_ring_pair_bufs(bn); return rc; diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_resc.c b/drivers/net/ethernet/broadcom/bnge/bnge_resc.c index 0e94f092813e..4711dd4945ff 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_resc.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_resc.c @@ -163,7 +163,8 @@ static int bnge_adjust_rings(struct bnge_dev *bd, u16 *rx, u16 tx_chunks = bnge_num_tx_to_cp(bd, *tx); if (tx_chunks != *tx) { - u16 tx_saved = tx_chunks, rc; + u16 tx_saved = tx_chunks; + int rc; rc = bnge_fix_rings_count(rx, &tx_chunks, max_nq, sh); if (rc) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 7513618793da..25099077fe4f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4611,11 +4611,14 @@ static void bnxt_init_one_rx_agg_ring_rxbd(struct bnxt *bp, type = ((u32)rxr->rx_page_size << RX_BD_LEN_SHIFT) | RX_BD_TYPE_RX_AGG_BD; - /* On P7, setting EOP will cause the chip to disable - * Relaxed Ordering (RO) for TPA data. Disable EOP for - * potentially higher performance with RO. + /* Disable EOP if TPA is enabled to prevent overlapping zero + * padding with the next segment's data. On P7_PLUS, EOP will + * automatically disable Relaxed Ordering (RO) to prevent + * potential data corruption (and may degrade performance). On + * older chips, RO will not be automatically disabled and may + * cause corruption. */ - if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA)) + if (!(bp->flags & BNXT_FLAG_TPA)) type |= RX_BD_FLAGS_AGG_EOP; bnxt_init_rxbd_pages(ring, type); @@ -6704,22 +6707,36 @@ int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings) static void bnxt_fill_hw_rss_tbl(struct bnxt *bp, struct bnxt_vnic_info *vnic) { bool no_rss = !(vnic->flags & BNXT_VNIC_RSS_FLAG); - u16 i, j; + u16 i, j, min_j = bp->rx_nr_rings - 1; + + if (!vnic->rss_table) + goto skip_rss_tbl; /* Fill the RSS indirection table with ring group ids */ for (i = 0, j = 0; i < HW_HASH_INDEX_SIZE; i++) { if (!no_rss) j = bp->rss_indir_tbl[i]; + min_j = min(j, min_j); vnic->rss_table[i] = cpu_to_le16(vnic->fw_grp_ids[j]); } + +skip_rss_tbl: + if (vnic->rss_table && !no_rss) + vnic->default_rx_ring = min_j; + else if (vnic->flags & BNXT_VNIC_RFS_FLAG) + vnic->default_rx_ring = vnic->vnic_id - 1; + else if ((vnic->vnic_id == 1) && BNXT_CHIP_TYPE_NITRO_A0(bp)) + vnic->default_rx_ring = bp->rx_nr_rings - 1; + else + vnic->default_rx_ring = 0; } static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp, struct bnxt_vnic_info *vnic) { + u16 tbl_size, i, min_j = bp->rx_nr_rings - 1; __le16 *ring_tbl = vnic->rss_table; struct bnxt_rx_ring_info *rxr; - u16 tbl_size, i; tbl_size = bnxt_get_rxfh_indir_size(bp->dev); @@ -6732,6 +6749,7 @@ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp, j = ethtool_rxfh_context_indir(vnic->rss_ctx)[i]; else j = bp->rss_indir_tbl[i]; + min_j = min(j, min_j); rxr = &bp->rx_ring[j]; ring_id = rxr->rx_ring_struct.fw_ring_id; @@ -6739,19 +6757,15 @@ static void bnxt_fill_hw_rss_tbl_p5(struct bnxt *bp, ring_id = bnxt_cp_ring_for_rx(bp, rxr); *ring_tbl++ = cpu_to_le16(ring_id); } + vnic->default_rx_ring = min_j; } static void __bnxt_hwrm_vnic_set_rss(struct bnxt *bp, struct hwrm_vnic_rss_cfg_input *req, struct bnxt_vnic_info *vnic) { - if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { - bnxt_fill_hw_rss_tbl_p5(bp, vnic); - if (bp->flags & BNXT_FLAG_CHIP_P7) - req->flags |= VNIC_RSS_CFG_REQ_FLAGS_IPSEC_HASH_TYPE_CFG_SUPPORT; - } else { - bnxt_fill_hw_rss_tbl(bp, vnic); - } + if (bp->flags & BNXT_FLAG_CHIP_P7) + req->flags |= VNIC_RSS_CFG_REQ_FLAGS_IPSEC_HASH_TYPE_CFG_SUPPORT; if (bp->rss_hash_delta) { req->hash_type = cpu_to_le32(bp->rss_hash_delta); @@ -6803,6 +6817,7 @@ static int bnxt_hwrm_vnic_set_rss_p5(struct bnxt *bp, if (!set_rss) return hwrm_req_send(bp, req); + bnxt_fill_hw_rss_tbl_p5(bp, vnic); __bnxt_hwrm_vnic_set_rss(bp, req, vnic); ring_tbl_map = vnic->rss_table_dma_addr; nr_ctxs = bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings); @@ -6939,8 +6954,9 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic) return rc; if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { - struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0]; + struct bnxt_rx_ring_info *rxr; + rxr = &bp->rx_ring[vnic->default_rx_ring]; req->default_rx_ring_id = cpu_to_le16(rxr->rx_ring_struct.fw_ring_id); req->default_cmpl_ring_id = @@ -6973,13 +6989,7 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, struct bnxt_vnic_info *vnic) req->cos_rule = cpu_to_le16(0xffff); } - if (vnic->flags & BNXT_VNIC_RSS_FLAG) - ring = 0; - else if (vnic->flags & BNXT_VNIC_RFS_FLAG) - ring = vnic->vnic_id - 1; - else if ((vnic->vnic_id == 1) && BNXT_CHIP_TYPE_NITRO_A0(bp)) - ring = bp->rx_nr_rings - 1; - + ring = vnic->default_rx_ring; grp_idx = bp->rx_ring[ring].bnapi->index; req->dflt_ring_grp = cpu_to_le16(bp->grp_info[grp_idx].fw_grp_id); req->lb_rule = cpu_to_le16(0xffff); @@ -10866,6 +10876,7 @@ static int __bnxt_setup_vnic(struct bnxt *bp, struct bnxt_vnic_info *vnic) } skip_rss_ctx: + bnxt_fill_hw_rss_tbl(bp, vnic); /* configure default vnic, ring grp */ rc = bnxt_hwrm_vnic_cfg(bp, vnic); if (rc) { @@ -11090,6 +11101,11 @@ static int bnxt_set_vnic_mru_p5(struct bnxt *bp, struct bnxt_vnic_info *vnic, vnic->vnic_id, rc); return rc; } + if (rxr_id == vnic->default_rx_ring) { + rc = bnxt_hwrm_vnic_cfg(bp, vnic); + if (rc) + return rc; + } } vnic->mru = mru; bnxt_hwrm_vnic_update(bp, vnic, @@ -11171,6 +11187,9 @@ static int bnxt_setup_nitroa0_vnic(struct bnxt *bp) return rc; } + /* Setup the proper default RX ring */ + bnxt_fill_hw_rss_tbl(bp, vnic); + rc = bnxt_hwrm_vnic_cfg(bp, vnic); if (rc) { netdev_err(bp->dev, "Cannot allocate special vnic for NS2 A0: %x\n", @@ -16217,6 +16236,7 @@ static int bnxt_queue_mem_alloc(struct net_device *dev, clone->rx_next_cons = 0; clone->need_head_pool = false; clone->rx_page_size = qcfg->rx_page_size; + clone->rx_agg_bmap = NULL; rc = bnxt_alloc_rx_page_pool(bp, clone, rxr->page_pool->p.nid); if (rc) @@ -16269,6 +16289,8 @@ err_free_tpa_info: bnxt_free_one_tpa_info(bp, clone); err_free_rx_agg_ring: bnxt_free_ring(bp, &clone->rx_agg_ring_struct.ring_mem); + kfree(clone->rx_agg_bmap); + clone->rx_agg_bmap = NULL; err_free_rx_ring: bnxt_free_ring(bp, &clone->rx_ring_struct.ring_mem); err_rxq_info_unreg: diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 6335dfc14c98..44ea8fc7b766 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1334,6 +1334,7 @@ struct bnxt_vnic_info { #define BNXT_VNIC_RSSCTX_FLAG 0x40 struct ethtool_rxfh_context *rss_ctx; u32 vnic_id; + u16 default_rx_ring; }; struct bnxt_rss_ctx { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c index 5d41dc1bc782..b89293dfd2d1 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c @@ -495,12 +495,15 @@ static int bnxt_ptp_enable(struct ptp_clock_info *ptp_info, return rc; case PTP_CLK_REQ_PPS: /* Configure PHC PPS IN */ - rc = bnxt_ptp_cfg_pin(bp, 0, BNXT_PPS_PIN_PPS_IN); + pin_id = 0; + if (!on) + break; + rc = bnxt_ptp_cfg_pin(bp, pin_id, BNXT_PPS_PIN_PPS_IN); if (rc) return rc; rc = bnxt_ptp_cfg_event(bp, BNXT_PPS_EVENT_INTERNAL); if (!rc) - ptp->pps_info.pins[0].event = BNXT_PPS_EVENT_INTERNAL; + ptp->pps_info.pins[pin_id].event = BNXT_PPS_EVENT_INTERNAL; return rc; default: netdev_err(ptp->bp->dev, "Unrecognized PIN function\n"); diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index e7125b818087..d98f7e7ccab9 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -3011,8 +3011,9 @@ static void enic_remove(struct pci_dev *pdev) if (netdev) { struct enic *enic = netdev_priv(netdev); - cancel_work_sync(&enic->reset); - cancel_work_sync(&enic->change_mtu_work); + disable_work_sync(&enic->reset); + disable_work_sync(&enic->tx_hang_reset); + disable_work_sync(&enic->change_mtu_work); unregister_netdev(netdev); enic_dev_deinit(enic); vnic_dev_close(enic->vdev); diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c index e3e7f2270560..02282dc86faf 100644 --- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c @@ -1282,7 +1282,6 @@ static void hix5hd2_dev_remove(struct platform_device *pdev) struct net_device *ndev = platform_get_drvdata(pdev); struct hix5hd2_priv *priv = netdev_priv(ndev); - netif_napi_del(&priv->napi); unregister_netdev(ndev); mdiobus_unregister(priv->bus); mdiobus_free(priv->bus); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index fc8587c80813..164c3ecf195c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -9498,12 +9498,8 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) if (ret) goto err_ptp_uninit; - if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_COPPER) { + if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_COPPER) hdev->hw.mac.req_autoneg = hdev->hw.mac.autoneg; - if (hdev->hw.mac.autoneg == AUTONEG_DISABLE && - hdev->hw.mac.speed != SPEED_UNKNOWN) - hdev->hw.mac.req_speed = hdev->hw.mac.speed; - } ret = hclge_set_autoneg_speed_dup(hdev); if (ret) { diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index b3883a5a7d7a..39043d8ca1bf 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -3082,7 +3082,7 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring) meta_req.tx_buffer = bi; meta_req.meta = meta; meta_req.used_desc = 0; - xsk_tx_metadata_request(meta, &igc_xsk_tx_metadata_ops, + xsk_tx_metadata_request(pool, &meta, &igc_xsk_tx_metadata_ops, &meta_req); /* xsk_tx_metadata_request() may have updated next_to_use */ @@ -7585,11 +7585,13 @@ static int __igc_resume(struct device *dev, bool rpm) err = __igc_open(netdev, true); if (!rpm) rtnl_unlock(); - if (!err) - netif_device_attach(netdev); + if (err) + return err; } - return err; + netif_device_attach(netdev); + + return 0; } static int igc_resume(struct device *dev) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c index 0b46ec29e64e..039fd47ebf52 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c @@ -54,10 +54,12 @@ static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst, if (burst) { *burst_exp = ilog2(burst) ? ilog2(burst) - 1 : 0; tmp = burst - rounddown_pow_of_two(burst); - if (burst < max_mantissa) + if (burst <= max_mantissa) { *burst_mantissa = tmp * 2; - else + } else { + WARN_ON(*burst_exp < 7); *burst_mantissa = tmp / (1ULL << (*burst_exp - 7)); + } } else { *burst_exp = MAX_BURST_EXPONENT; *burst_mantissa = max_mantissa; diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c index 2989a77e3b42..1ad0e62a8433 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c @@ -684,6 +684,9 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw) struct prestera_fw_header *hdr; u32 magic; + if (fw->bin->size < sizeof(*hdr)) + return -EINVAL; + hdr = (struct prestera_fw_header *)fw->bin->data; magic = be32_to_cpu(hdr->magic_number); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c index adcc73e2a5b3..1493d8106c1a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c @@ -1025,13 +1025,11 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev) tracer = kvzalloc_obj(*tracer); if (!tracer) - return ERR_PTR(-ENOMEM); + return NULL; tracer->work_queue = create_singlethread_workqueue("mlx5_fw_tracer"); - if (!tracer->work_queue) { - err = -ENOMEM; + if (!tracer->work_queue) goto free_tracer; - } tracer->dev = dev; @@ -1073,7 +1071,7 @@ destroy_workqueue: destroy_workqueue(tracer->work_queue); free_tracer: kvfree(tracer); - return ERR_PTR(err); + return NULL; } static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data); @@ -1084,7 +1082,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer) struct mlx5_core_dev *dev; int err; - if (IS_ERR_OR_NULL(tracer)) + if (!tracer) return 0; if (!tracer->str_db.loaded) @@ -1134,7 +1132,7 @@ err_cancel_work: /* Stop tracer + Cleanup HW resources */ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer) { - if (IS_ERR_OR_NULL(tracer)) + if (!tracer) return; mutex_lock(&tracer->state_lock); @@ -1163,7 +1161,7 @@ unlock: /* Free software resources (Buffers, etc ..) */ void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer) { - if (IS_ERR_OR_NULL(tracer)) + if (!tracer) return; mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n"); @@ -1215,7 +1213,7 @@ int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer) struct mlx5_core_dev *dev; int err; - if (IS_ERR_OR_NULL(tracer)) + if (!tracer) return 0; dev = tracer->dev; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 6867a5aed42c..822859c360e7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -483,7 +483,7 @@ typedef int (*mlx5e_fp_xmit_xdp_frame_check)(struct mlx5e_xdpsq *); typedef bool (*mlx5e_fp_xmit_xdp_frame)(struct mlx5e_xdpsq *, struct mlx5e_xmit_data *, int, - struct xsk_tx_metadata *); + struct xsk_tx_metadata **); struct mlx5e_xdpsq { /* data path */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h index 28cab4bf525c..7bfe7cdc5770 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h @@ -30,6 +30,7 @@ enum { MLX5E_TC_FLOW_FLAG_FAILED = MLX5E_TC_FLOW_BASE + 9, MLX5E_TC_FLOW_FLAG_SAMPLE = MLX5E_TC_FLOW_BASE + 10, MLX5E_TC_FLOW_FLAG_USE_ACT_STATS = MLX5E_TC_FLOW_BASE + 11, + MLX5E_TC_FLOW_FLAG_PEER = MLX5E_TC_FLOW_BASE + 12, }; struct mlx5e_tc_flow_parse_attr { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c index d8c7cb8837d7..77ea51bfbaae 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c @@ -452,11 +452,11 @@ INDIRECT_CALLABLE_SCOPE int mlx5e_xmit_xdp_frame_check_mpwqe(struct mlx5e_xdpsq INDIRECT_CALLABLE_SCOPE bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd, - int check_result, struct xsk_tx_metadata *meta); + int check_result, struct xsk_tx_metadata **meta); INDIRECT_CALLABLE_SCOPE bool mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd, - int check_result, struct xsk_tx_metadata *meta) + int check_result, struct xsk_tx_metadata **meta) { struct mlx5e_tx_mpwqe *session = &sq->mpwqe; struct mlx5e_xdpsq_stats *stats = sq->stats; @@ -504,7 +504,10 @@ mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptx * and it's safe to complete it at any time. */ mlx5e_xdp_mpwqe_session_start(sq); - xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, &session->wqe->eth); + if (meta) + xsk_tx_metadata_request(sq->xsk_pool, meta, + &mlx5e_xsk_tx_metadata_ops, + &session->wqe->eth); } mlx5e_xdp_mpwqe_add_dseg(sq, p, stats); @@ -535,7 +538,7 @@ INDIRECT_CALLABLE_SCOPE int mlx5e_xmit_xdp_frame_check(struct mlx5e_xdpsq *sq) INDIRECT_CALLABLE_SCOPE bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd, - int check_result, struct xsk_tx_metadata *meta) + int check_result, struct xsk_tx_metadata **meta) { struct mlx5e_xmit_data_frags *xdptxdf = container_of(xdptxd, struct mlx5e_xmit_data_frags, xd); @@ -649,7 +652,9 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd, sq->pc += num_wqebbs; - xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, eseg); + if (meta) + xsk_tx_metadata_request(sq->xsk_pool, meta, + &mlx5e_xsk_tx_metadata_ops, eseg); sq->doorbell_cseg = cseg; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h index 3c54f8962664..5b8f4094d553 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h @@ -114,11 +114,11 @@ extern const struct xsk_tx_metadata_ops mlx5e_xsk_tx_metadata_ops; INDIRECT_CALLABLE_DECLARE(bool mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd, int check_result, - struct xsk_tx_metadata *meta)); + struct xsk_tx_metadata **meta)); INDIRECT_CALLABLE_DECLARE(bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd, int check_result, - struct xsk_tx_metadata *meta)); + struct xsk_tx_metadata **meta)); INDIRECT_CALLABLE_DECLARE(int mlx5e_xmit_xdp_frame_check_mpwqe(struct mlx5e_xdpsq *sq)); INDIRECT_CALLABLE_DECLARE(int mlx5e_xmit_xdp_frame_check(struct mlx5e_xdpsq *sq)); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c index 8aeab4b21035..3d19dad8f868 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c @@ -105,7 +105,7 @@ bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget) ret = INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe, mlx5e_xmit_xdp_frame, sq, &xdptxd, - check_result, meta); + check_result, &meta); if (unlikely(!ret)) { if (sq->mpwqe.wqe) mlx5e_xdp_mpwqe_complete(sq); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 7d47a1da8b6b..f0407a850ea8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1939,8 +1939,10 @@ err_free_txqsq: void mlx5e_activate_txqsq(struct mlx5e_txqsq *sq) { sq->txq = netdev_get_tx_queue(sq->netdev, sq->txq_ix); + /* Reset BQL only when the SQ has no bytes in flight. */ + if (sq->cc == sq->pc) + netdev_tx_reset_queue(sq->txq); set_bit(MLX5E_SQ_STATE_ENABLED, &sq->state); - netdev_tx_reset_queue(sq->txq); netif_tx_start_queue(sq->txq); netif_queue_set_napi(sq->netdev, sq->txq_ix, NETDEV_QUEUE_TYPE_TX, sq->cq.napi); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 1bc7b9019124..b290beb4369a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -2161,7 +2161,8 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, if (mlx5e_is_eswitch_flow(flow)) { struct mlx5_devcom_comp_dev *devcom = flow->priv->mdev->priv.eswitch->devcom; - if (!mlx5_devcom_for_each_peer_begin(devcom)) { + if (flow_flag_test(flow, PEER) || + !mlx5_devcom_for_each_peer_begin(devcom)) { mlx5e_tc_del_fdb_flow(priv, flow); return; } @@ -4628,6 +4629,7 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f, else in_mdev = priv->mdev; + flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_PEER); parse_attr = flow->attr->parse_attr; peer_flow = __mlx5e_add_fdb_flow(peer_priv, f, flow_flags, parse_attr->filter_dev, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 907ee83a722d..247e5d85ec36 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -3986,7 +3986,7 @@ static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw) mutex_destroy(&esw->fdb_table.offloads.vports.lock); } -static void esw_vfs_changed_event_handler(struct mlx5_eswitch *esw) +static void esw_changed_event_handler(struct mlx5_eswitch *esw) { struct mlx5_esw_pf_info host_pf_info; u16 new_num_vfs; @@ -3999,6 +3999,11 @@ static void esw_vfs_changed_event_handler(struct mlx5_eswitch *esw) host_pf_info = mlx5_esw_get_host_pf_info(esw->dev, out); new_num_vfs = host_pf_info.num_of_vfs; + if (host_pf_info.pf_disabled) { + mlx5_sf_table_esw_changed_event_handler(esw->dev); + mlx5_sf_hw_table_esw_changed_event_handler(esw->dev); + } + if (new_num_vfs == esw->esw_funcs.num_vfs || host_pf_info.pf_disabled) goto free; @@ -4091,8 +4096,7 @@ int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, esw_funcs = mlx5_nb_cof(nb, struct mlx5_esw_functions, nb); esw = container_of(esw_funcs, struct mlx5_eswitch, esw_funcs); - ret = mlx5_esw_add_work(esw, esw_vfs_changed_event_handler, - GFP_ATOMIC); + ret = mlx5_esw_add_work(esw, esw_changed_event_handler, GFP_ATOMIC); if (ret) return NOTIFY_DONE; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c index b6cecbcc392d..4564d460416b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c @@ -561,3 +561,32 @@ bool mlx5_sf_table_empty(const struct mlx5_core_dev *dev) return xa_empty(&table->function_ids); } + +void mlx5_sf_table_esw_changed_event_handler(struct mlx5_core_dev *dev) +{ + struct mlx5_sf_table *table = dev->priv.sf_table; + unsigned long index; + struct mlx5_sf *sf; + + trace_mlx5_sf_host_pf_disabled(dev); + + if (!table) + return; + + mutex_lock(&table->sf_state_lock); + xa_for_each(&table->function_ids, index, sf) { + if (!sf->controller) + continue; + + if (sf->hw_state == MLX5_VHCA_STATE_IN_USE) + sf->hw_state = MLX5_VHCA_STATE_ACTIVE; + else if (sf->hw_state == MLX5_VHCA_STATE_TEARDOWN_REQUEST) + sf->hw_state = MLX5_VHCA_STATE_ALLOCATED; + else + continue; + trace_mlx5_sf_update_state(table->dev, sf->port_index, + sf->controller, sf->hw_fn_id, + sf->hw_state); + } + mutex_unlock(&table->sf_state_lock); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/diag/sf_tracepoint.h b/drivers/net/ethernet/mellanox/mlx5/core/sf/diag/sf_tracepoint.h index 302ce00da5a9..9dc88a7e30ca 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/diag/sf_tracepoint.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/diag/sf_tracepoint.h @@ -11,6 +11,14 @@ #include <linux/mlx5/driver.h> #include "sf/vhca_event.h" +TRACE_EVENT(mlx5_sf_host_pf_disabled, + TP_PROTO(const struct mlx5_core_dev *dev), + TP_ARGS(dev), + TP_STRUCT__entry(__string(devname, dev_name(dev->device))), + TP_fast_assign(__assign_str(devname);), + TP_printk("(%s)\n", __get_str(devname)) +); + TRACE_EVENT(mlx5_sf_add, TP_PROTO(const struct mlx5_core_dev *dev, unsigned int port_index, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c index 0bc9146a3598..95a8b1e64ba4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/hw_table.c @@ -459,3 +459,25 @@ bool mlx5_sf_hw_table_supported(const struct mlx5_core_dev *dev) { return !!dev->priv.sf_hw_table; } + +void mlx5_sf_hw_table_esw_changed_event_handler(struct mlx5_core_dev *dev) +{ + struct mlx5_sf_hw_table *table; + struct mlx5_sf_hwc_table *hwc; + int i; + + table = dev->priv.sf_hw_table; + if (!table) + return; + + mutex_lock(&table->table_lock); + hwc = &table->hwc[MLX5_SF_HWC_EXT_HOST]; + for (i = 0; i < hwc->max_fn; i++) { + struct mlx5_sf_hw *sf_hw; + + sf_hw = &hwc->sfs[i]; + if (sf_hw->allocated && sf_hw->pending_delete) + mlx5_sf_hw_table_hwc_sf_free(dev, hwc, i); + } + mutex_unlock(&table->table_lock); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h index d8a934a0e968..ed784682b9b1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h @@ -15,12 +15,14 @@ void mlx5_sf_hw_table_cleanup(struct mlx5_core_dev *dev); int mlx5_sf_hw_notifier_init(struct mlx5_core_dev *dev); void mlx5_sf_hw_notifier_cleanup(struct mlx5_core_dev *dev); void mlx5_sf_hw_table_destroy(struct mlx5_core_dev *dev); +void mlx5_sf_hw_table_esw_changed_event_handler(struct mlx5_core_dev *dev); int mlx5_sf_notifiers_init(struct mlx5_core_dev *dev); int mlx5_sf_table_init(struct mlx5_core_dev *dev); void mlx5_sf_notifiers_cleanup(struct mlx5_core_dev *dev); void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev); bool mlx5_sf_table_empty(const struct mlx5_core_dev *dev); +void mlx5_sf_table_esw_changed_event_handler(struct mlx5_core_dev *dev); int mlx5_devlink_sf_port_new(struct devlink *devlink, const struct devlink_port_new_attrs *add_attr, @@ -60,6 +62,11 @@ static inline void mlx5_sf_hw_table_destroy(struct mlx5_core_dev *dev) { } +static inline void +mlx5_sf_hw_table_esw_changed_event_handler(struct mlx5_core_dev *dev) +{ +} + static inline int mlx5_sf_notifiers_init(struct mlx5_core_dev *dev) { return 0; @@ -83,6 +90,11 @@ static inline bool mlx5_sf_table_empty(const struct mlx5_core_dev *dev) return true; } +static inline void +mlx5_sf_table_esw_changed_event_handler(struct mlx5_core_dev *dev) +{ +} + #endif #endif diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 3801f9d45278..a71f0df26378 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2748,8 +2748,8 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) meta_req.set_ic = &set_ic; meta_req.tbs = tx_q->tbs; meta_req.edesc = &tx_q->dma_entx[entry]; - xsk_tx_metadata_request(meta, &stmmac_xsk_tx_metadata_ops, - &meta_req); + xsk_tx_metadata_request(pool, &meta, + &stmmac_xsk_tx_metadata_ops, &meta_req); if (set_ic) { tx_q->tx_count_frames = 0; stmmac_set_tx_ic(priv, tx_desc); @@ -4134,6 +4134,15 @@ static int __stmmac_open(struct net_device *dev, dma_conf->tx_queue[i].tbs = priv->dma_conf.tx_queue[i].tbs; memcpy(&priv->dma_conf, dma_conf, sizeof(*dma_conf)); + /* The PHY is suspended when the interface is reopened without + * disconnecting the PHY, e.g. on MTU change. IEEE 802.3 allows PHYs + * to stop their receive clock while powered down, but the DMA + * software reset in stmmac_hw_setup() requires a running receive + * clock, and phylink_start() below resumes the PHY only after the + * hardware setup. Resume a suspended PHY here first. + */ + phylink_prepare_resume(priv->phylink); + stmmac_reset_queues_param(priv); ret = stmmac_hw_setup(dev); diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c index 9993c1dfe471..168cfe9b59a9 100644 --- a/drivers/net/ovpn/main.c +++ b/drivers/net/ovpn/main.c @@ -35,25 +35,11 @@ static void ovpn_priv_free(struct net_device *net) static int ovpn_mp_alloc(struct ovpn_priv *ovpn) { - struct in_device *dev_v4; int i; if (ovpn->mode != OVPN_MODE_MP) return 0; - dev_v4 = __in_dev_get_rtnl(ovpn->dev); - if (dev_v4) { - /* disable redirects as Linux gets confused by ovpn - * handling same-LAN routing. - * This happens because a multipeer interface is used as - * relay point between hosts in the same subnet, while - * in a classic LAN this would not be needed because the - * two hosts would be able to talk directly. - */ - IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false); - IPV4_DEVCONF_ALL(dev_net(ovpn->dev), SEND_REDIRECTS) = false; - } - /* the peer container is fairly large, therefore we allocate it only in * MP mode */ @@ -97,9 +83,38 @@ static void ovpn_net_uninit(struct net_device *dev) gro_cells_destroy(&ovpn->gro_cells); } +static int ovpn_net_open(struct net_device *dev) +{ + struct ovpn_priv *ovpn = netdev_priv(dev); + struct in_device *dev_v4; + + /* the IPv4 in_device (and thus its config) is recreated whenever the + * interface is moved to a new netns, so redirects must be disabled on + * every bring-up rather than once at creation time, otherwise the + * setting is silently lost after such a move + */ + if (ovpn->mode == OVPN_MODE_MP) { + dev_v4 = __in_dev_get_rtnl(dev); + if (dev_v4) { + /* disable redirects as Linux gets confused by ovpn + * handling same-LAN routing. + * This happens because a multipeer interface is used as + * relay point between hosts in the same subnet, while + * in a classic LAN this would not be needed because the + * two hosts would be able to talk directly. + */ + IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false); + IPV4_DEVCONF_ALL(dev_net(dev), SEND_REDIRECTS) = false; + } + } + + return 0; +} + static const struct net_device_ops ovpn_netdev_ops = { .ndo_init = ovpn_net_init, .ndo_uninit = ovpn_net_uninit, + .ndo_open = ovpn_net_open, .ndo_start_xmit = ovpn_net_xmit, }; @@ -183,6 +198,7 @@ static int ovpn_newlink(struct net_device *dev, struct ovpn_priv *ovpn = netdev_priv(dev); struct nlattr **data = params->data; enum ovpn_mode mode = OVPN_MODE_P2P; + int ret; if (data && data[IFLA_OVPN_MODE]) { mode = nla_get_u8(data[IFLA_OVPN_MODE]); @@ -207,7 +223,17 @@ static int ovpn_newlink(struct net_device *dev, else netif_carrier_off(dev); - return register_netdevice(dev); + ret = register_netdevice(dev); + if (ret < 0) + return ret; + + return 0; +} + +static size_t ovpn_get_size(const struct net_device *dev) +{ + /* IFLA_OVPN_MODE */ + return nla_total_size(sizeof(u8)); } static int ovpn_fill_info(struct sk_buff *skb, const struct net_device *dev) @@ -228,13 +254,17 @@ static struct rtnl_link_ops ovpn_link_ops = { .policy = ovpn_policy, .maxtype = IFLA_OVPN_MAX, .newlink = ovpn_newlink, + .get_size = ovpn_get_size, .fill_info = ovpn_fill_info, }; static int __init ovpn_init(void) { - int err = rtnl_link_register(&ovpn_link_ops); + int err; + + ovpn_tcp_init(); + err = rtnl_link_register(&ovpn_link_ops); if (err) { pr_err("ovpn: can't register rtnl link ops: %d\n", err); return err; @@ -246,8 +276,6 @@ static int __init ovpn_init(void) goto unreg_rtnl; } - ovpn_tcp_init(); - return 0; unreg_rtnl: diff --git a/drivers/net/ovpn/netlink-gen.c b/drivers/net/ovpn/netlink-gen.c index 2147cec7c2c5..92d2fdc17c2e 100644 --- a/drivers/net/ovpn/netlink-gen.c +++ b/drivers/net/ovpn/netlink-gen.c @@ -16,6 +16,14 @@ static const struct netlink_range_validation ovpn_a_peer_id_range = { .max = 16777215ULL, }; +static const struct netlink_range_validation ovpn_a_peer_keepalive_interval_range = { + .max = 86400ULL, +}; + +static const struct netlink_range_validation ovpn_a_peer_keepalive_timeout_range = { + .max = 86400ULL, +}; + static const struct netlink_range_validation ovpn_a_peer_tx_id_range = { .max = 16777215ULL, }; @@ -68,8 +76,8 @@ const struct nla_policy ovpn_peer_nl_policy[OVPN_A_PEER_TX_ID + 1] = { [OVPN_A_PEER_LOCAL_IPV4] = { .type = NLA_BE32, }, [OVPN_A_PEER_LOCAL_IPV6] = NLA_POLICY_EXACT_LEN(16), [OVPN_A_PEER_LOCAL_PORT] = NLA_POLICY_MIN(NLA_BE16, 1), - [OVPN_A_PEER_KEEPALIVE_INTERVAL] = { .type = NLA_U32, }, - [OVPN_A_PEER_KEEPALIVE_TIMEOUT] = { .type = NLA_U32, }, + [OVPN_A_PEER_KEEPALIVE_INTERVAL] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_keepalive_interval_range), + [OVPN_A_PEER_KEEPALIVE_TIMEOUT] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_keepalive_timeout_range), [OVPN_A_PEER_DEL_REASON] = NLA_POLICY_MAX(NLA_U32, 4), [OVPN_A_PEER_VPN_RX_BYTES] = { .type = NLA_UINT, }, [OVPN_A_PEER_VPN_TX_BYTES] = { .type = NLA_UINT, }, @@ -97,8 +105,8 @@ const struct nla_policy ovpn_peer_new_input_nl_policy[OVPN_A_PEER_TX_ID + 1] = { [OVPN_A_PEER_VPN_IPV6] = NLA_POLICY_EXACT_LEN(16), [OVPN_A_PEER_LOCAL_IPV4] = { .type = NLA_BE32, }, [OVPN_A_PEER_LOCAL_IPV6] = NLA_POLICY_EXACT_LEN(16), - [OVPN_A_PEER_KEEPALIVE_INTERVAL] = { .type = NLA_U32, }, - [OVPN_A_PEER_KEEPALIVE_TIMEOUT] = { .type = NLA_U32, }, + [OVPN_A_PEER_KEEPALIVE_INTERVAL] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_keepalive_interval_range), + [OVPN_A_PEER_KEEPALIVE_TIMEOUT] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_keepalive_timeout_range), [OVPN_A_PEER_TX_ID] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_tx_id_range), }; @@ -112,8 +120,8 @@ const struct nla_policy ovpn_peer_set_input_nl_policy[OVPN_A_PEER_TX_ID + 1] = { [OVPN_A_PEER_VPN_IPV6] = NLA_POLICY_EXACT_LEN(16), [OVPN_A_PEER_LOCAL_IPV4] = { .type = NLA_BE32, }, [OVPN_A_PEER_LOCAL_IPV6] = NLA_POLICY_EXACT_LEN(16), - [OVPN_A_PEER_KEEPALIVE_INTERVAL] = { .type = NLA_U32, }, - [OVPN_A_PEER_KEEPALIVE_TIMEOUT] = { .type = NLA_U32, }, + [OVPN_A_PEER_KEEPALIVE_INTERVAL] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_keepalive_interval_range), + [OVPN_A_PEER_KEEPALIVE_TIMEOUT] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_keepalive_timeout_range), [OVPN_A_PEER_TX_ID] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_tx_id_range), }; diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c index 4c66c1ec497e..4dad85294198 100644 --- a/drivers/net/ovpn/netlink.c +++ b/drivers/net/ovpn/netlink.c @@ -534,6 +534,12 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info) */ if (ret > 0) ovpn_peer_hash_vpn_ip(peer); + /* if the remote endpoint was updated, the by_transp_addr hash bucket + * also needs to be refreshed, otherwise incoming packets from the new + * remote address would fail the lockless lookup + */ + if (attrs[OVPN_A_PEER_REMOTE_IPV4] || attrs[OVPN_A_PEER_REMOTE_IPV6]) + ovpn_peer_hash_transp_addr(peer); spin_unlock_bh(&ovpn->lock); ovpn_peer_put(peer); diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index a21d02ac715e..b0519f9840d8 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -189,6 +189,9 @@ int ovpn_peer_reset_sockaddr(struct ovpn_peer *peer, &(*__tbl1)[ovpn_get_hash_slot(*__tbl1, _key, _key_len)];\ }) +static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer, + const struct ovpn_bind *bind); + /** * ovpn_peer_endpoints_update - update remote or local endpoint for peer * @peer: peer to update the remote endpoint for @@ -196,7 +199,6 @@ int ovpn_peer_reset_sockaddr(struct ovpn_peer *peer, */ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb) { - struct hlist_nulls_head *nhead; struct sockaddr_storage ss; struct sockaddr_in6 *sa6; bool reset_cache = false; @@ -220,9 +222,16 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb) */ local_ip = &ip_hdr(skb)->daddr; sa = (struct sockaddr_in *)&ss; - sa->sin_family = AF_INET; - sa->sin_addr.s_addr = ip_hdr(skb)->saddr; - sa->sin_port = udp_hdr(skb)->source; + /* use a designated initializer so the sin_zero padding + * is zeroed (it ends up in the by_transp_addr hash key) + * without memset-ing the whole sockaddr_storage on the + * RX fast path + */ + *sa = (struct sockaddr_in) { + .sin_family = AF_INET, + .sin_addr.s_addr = ip_hdr(skb)->saddr, + .sin_port = udp_hdr(skb)->source, + }; salen = sizeof(*sa); reset_cache = true; break; @@ -248,11 +257,19 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb) */ local_ip = &ipv6_hdr(skb)->daddr; sa6 = (struct sockaddr_in6 *)&ss; - sa6->sin6_family = AF_INET6; - sa6->sin6_addr = ipv6_hdr(skb)->saddr; - sa6->sin6_port = udp_hdr(skb)->source; - sa6->sin6_scope_id = ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr, - skb->skb_iif); + /* use a designated initializer so the sin6_flowinfo + * padding is zeroed (it ends up in the by_transp_addr + * hash key) without memset-ing the whole + * sockaddr_storage on the RX fast path + */ + *sa6 = (struct sockaddr_in6) { + .sin6_family = AF_INET6, + .sin6_addr = ipv6_hdr(skb)->saddr, + .sin6_port = udp_hdr(skb)->source, + .sin6_scope_id = + ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr, + skb->skb_iif), + }; salen = sizeof(*sa6); reset_cache = true; break; @@ -295,42 +312,25 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb) ovpn_nl_peer_float_notify(peer, &ss); /* rehashing is required only in MP mode as P2P has one peer - * only and thus there is no hashtable + * only and thus there is no hashtable. + * + * This function may be invoked concurrently, so re-read peer->bind + * under the proper locks and rehash against its current value. */ - if (peer->ovpn->mode == OVPN_MODE_MP) { - spin_lock_bh(&peer->ovpn->lock); - spin_lock_bh(&peer->lock); - bind = rcu_dereference_protected(peer->bind, - lockdep_is_held(&peer->lock)); - if (unlikely(!bind)) { - spin_unlock_bh(&peer->lock); - spin_unlock_bh(&peer->ovpn->lock); - return; - } - - /* This function may be invoked concurrently, therefore another - * float may have happened in parallel: perform rehashing - * using the peer->bind->remote directly as key - */ - - switch (bind->remote.in4.sin_family) { - case AF_INET: - salen = sizeof(*sa); - break; - case AF_INET6: - salen = sizeof(*sa6); - break; - } + if (peer->ovpn->mode != OVPN_MODE_MP) + return; - /* remove old hashing */ - hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr); - /* re-add with new transport address */ - nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr, - &bind->remote, salen); - hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead); - spin_unlock_bh(&peer->lock); - spin_unlock_bh(&peer->ovpn->lock); - } + /* This function may be invoked concurrently, therefore another + * float may have happened in parallel: re-acquire the locks and + * rehash using the peer->bind->remote directly as key + */ + spin_lock_bh(&peer->ovpn->lock); + spin_lock_bh(&peer->lock); + bind = rcu_dereference_protected(peer->bind, + lockdep_is_held(&peer->lock)); + __ovpn_peer_hash_transp_addr(peer, bind); + spin_unlock_bh(&peer->lock); + spin_unlock_bh(&peer->ovpn->lock); return; unlock: spin_unlock_bh(&peer->lock); @@ -896,6 +896,83 @@ bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb, return match; } +/* Move @peer to the by_transp_addr bucket matching its current bind. + * + * Caller must hold both peer->ovpn->lock and peer->lock, and must have + * already dereferenced a valid (non-NULL) peer->bind, passed in as @bind. + */ +static void __ovpn_peer_hash_transp_addr(struct ovpn_peer *peer, + const struct ovpn_bind *bind) +{ + struct sockaddr_storage sa = {}; + struct hlist_nulls_head *nhead; + struct sockaddr_in6 *sa6; + struct sockaddr_in *sa4; + size_t salen; + + lockdep_assert_held(&peer->ovpn->lock); + lockdep_assert_held(&peer->lock); + + if (WARN_ON_ONCE(!bind)) + return; + + /* peer may have been concurrently removed between the caller's + * initial lookup and our acquisition of ovpn->lock; skip the + * rehash so we don't re-insert a removed peer + */ + if (unlikely(hlist_unhashed(&peer->hash_entry_id))) + return; + + /* Build the hash key from the transport identity only + * (family/address/port), matching ovpn_peer_add_mp() and the lookup + * in ovpn_peer_get_by_transp_addr(). Hashing bind->remote directly + * would fold in sin6_scope_id (set on the float path but never by the + * lookup), scattering the peer into a bucket lookups cannot reach. + */ + switch (bind->remote.in4.sin_family) { + case AF_INET: + sa4 = (struct sockaddr_in *)&sa; + sa4->sin_family = AF_INET; + sa4->sin_addr.s_addr = bind->remote.in4.sin_addr.s_addr; + sa4->sin_port = bind->remote.in4.sin_port; + salen = sizeof(*sa4); + break; + case AF_INET6: + sa6 = (struct sockaddr_in6 *)&sa; + sa6->sin6_family = AF_INET6; + sa6->sin6_addr = bind->remote.in6.sin6_addr; + sa6->sin6_port = bind->remote.in6.sin6_port; + salen = sizeof(*sa6); + break; + default: + return; + } + + /* remove old hashing (no-op if entry is not currently linked) */ + hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr); + /* re-add with current transport address */ + nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr, &sa, + salen); + hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead); +} + +void ovpn_peer_hash_transp_addr(struct ovpn_peer *peer) +{ + struct ovpn_bind *bind; + + lockdep_assert_held(&peer->ovpn->lock); + + /* rehashing makes sense only in multipeer mode */ + if (peer->ovpn->mode != OVPN_MODE_MP) + return; + + spin_lock_bh(&peer->lock); + bind = rcu_dereference_protected(peer->bind, + lockdep_is_held(&peer->lock)); + __ovpn_peer_hash_transp_addr(peer, bind); + spin_unlock_bh(&peer->lock); +} + void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer) { struct hlist_nulls_head *nhead; @@ -906,6 +983,13 @@ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer) if (peer->ovpn->mode != OVPN_MODE_MP) return; + /* peer may have been concurrently removed between the caller's + * initial lookup and our acquisition of ovpn->lock; skip the + * rehash so we don't re-insert a removed peer + */ + if (hlist_unhashed(&peer->hash_entry_id)) + return; + if (peer->vpn_addrs.ipv4.s_addr != htonl(INADDR_ANY)) { /* remove potential old hashing */ hlist_nulls_del_init_rcu(&peer->hash_entry_addr4); @@ -1165,7 +1249,7 @@ static void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct sock *sk, } if (sk) { - ovpn_sock = rcu_access_pointer(peer->sock); + ovpn_sock = rcu_dereference_bh(peer->sock); if (!ovpn_sock || ovpn_sock->sk != sk) { spin_unlock_bh(&ovpn->lock); return; diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h index 86c8cffada6d..dfa5c0037e02 100644 --- a/drivers/net/ovpn/peer.h +++ b/drivers/net/ovpn/peer.h @@ -150,6 +150,7 @@ struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_priv *ovpn, u32 peer_id); struct ovpn_peer *ovpn_peer_get_by_dst(struct ovpn_priv *ovpn, struct sk_buff *skb); void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer); +void ovpn_peer_hash_transp_addr(struct ovpn_peer *peer); bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb, struct ovpn_peer *peer); diff --git a/drivers/net/ovpn/socket.c b/drivers/net/ovpn/socket.c index 517caa64a4fe..6cbeb2caaeec 100644 --- a/drivers/net/ovpn/socket.c +++ b/drivers/net/ovpn/socket.c @@ -162,6 +162,15 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer) rcu_read_lock(); ovpn_sock = rcu_dereference_sk_user_data(sk); if (ovpn_sock) { + /* something else filled the sk_user_data without + * setting the encap_type. Reject the socket. + */ + if (!type) { + ovpn_sock = ERR_PTR(-EBUSY); + rcu_read_unlock(); + goto sock_release; + } + /* socket owned by another ovpn instance, we can't use it */ if (ovpn_sock->ovpn != peer->ovpn) { ovpn_sock = ERR_PTR(-EBUSY); diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h index 320f76ffa81f..79e09727b81b 100644 --- a/drivers/net/phy/mediatek/mtk.h +++ b/drivers/net/phy/mediatek/mtk.h @@ -53,15 +53,15 @@ #define MTK_GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \ MTK_PHY_LED_BLINK_100RX | \ MTK_PHY_LED_BLINK_10RX) -#define MTK_GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \ - MTK_PHY_LED_BLINK_100RX | \ - MTK_PHY_LED_BLINK_10RX) +#define MTK_GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_1000TX | \ + MTK_PHY_LED_BLINK_100TX | \ + MTK_PHY_LED_BLINK_10TX) #define MTK_2P5GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK2500 | \ MTK_GPHY_LED_ON_SET) #define MTK_2P5GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \ MTK_GPHY_LED_RX_BLINK_SET) -#define MTK_2P5GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \ +#define MTK_2P5GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_2500TX | \ MTK_GPHY_LED_TX_BLINK_SET) #define MTK_PHY_LED_STATE_FORCE_ON 0 diff --git a/drivers/net/tap.c b/drivers/net/tap.c index fae115915c8e..5d2d34d24ce8 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -1074,10 +1074,21 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp) skb_reset_mac_header(skb); skb->protocol = eth_hdr(skb)->h_proto; + rcu_read_lock(); + tap = rcu_dereference(q->tap); + if (!tap) { + kfree_skb(skb); + rcu_read_unlock(); + return 0; + } + skb->dev = tap->dev; + if (vnet_hdr_len) { err = tun_vnet_hdr_to_skb(q->flags, skb, gso); - if (err) + if (err) { + rcu_read_unlock(); goto err_kfree; + } } /* Move network header to the right position for VLAN tagged packets */ @@ -1085,15 +1096,8 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp) vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0) skb_set_network_header(skb, depth); - rcu_read_lock(); - tap = rcu_dereference(q->tap); - if (tap) { - skb->dev = tap->dev; - skb_probe_transport_header(skb); - dev_queue_xmit(skb); - } else { - kfree_skb(skb); - } + skb_probe_transport_header(skb); + dev_queue_xmit(skb); rcu_read_unlock(); return 0; diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c index 02a91650561a..98893732bc6e 100644 --- a/drivers/net/thunderbolt/main.c +++ b/drivers/net/thunderbolt/main.c @@ -386,11 +386,16 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout) break; } - tb_ring_stop(net->rx_ring.ring); - tb_ring_stop(net->tx_ring.ring); - tbnet_free_buffers(&net->rx_ring); - tbnet_free_buffers(&net->tx_ring); - + /* Tear the paths down before stopping the rings. This mirrors + * tbnet_connected_work(), which enables the paths last so the + * Rx ring is primed before packets can arrive. Stopping a + * ring zeroes its descriptor base and tbnet_free_buffers() + * unmaps and frees the frame buffers, leaving anything still + * in flight with nowhere to drain to; + * __tb_path_deactivate_hop() then waits for the hop's + * 'pending' bit, which on some host routers never clears in + * that state. + */ ret = tb_xdomain_disable_paths(net->xd, net->local_transmit_path, net->tx_ring.ring->hop, @@ -399,6 +404,11 @@ static void tbnet_tear_down(struct tbnet *net, bool send_logout) if (ret) netdev_warn(net->dev, "failed to disable DMA paths\n"); + tb_ring_stop(net->rx_ring.ring); + tb_ring_stop(net->tx_ring.ring); + tbnet_free_buffers(&net->rx_ring); + tbnet_free_buffers(&net->tx_ring); + tb_xdomain_release_in_hopid(net->xd, net->remote_transmit_path); net->remote_transmit_path = 0; } @@ -925,12 +935,8 @@ static int tbnet_open(struct net_device *dev) netif_carrier_off(dev); - flags = RING_FLAG_FRAME; - /* Only enable full E2E if the other end supports it too */ - if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E) - flags |= RING_FLAG_E2E; - - ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags); + ring = tb_ring_alloc_tx(xd->tb->nhi, -1, TBNET_RING_SIZE, + RING_FLAG_FRAME); if (!ring) { netdev_err(dev, "failed to allocate Tx ring\n"); return -ENOMEM; @@ -949,6 +955,11 @@ static int tbnet_open(struct net_device *dev) sof_mask = BIT(TBIP_PDF_FRAME_START); eof_mask = BIT(TBIP_PDF_FRAME_END); + flags = RING_FLAG_FRAME; + /* Only enable full E2E if the other end supports it too */ + if (tbnet_e2e && net->svc->prtcstns & TBNET_E2E) + flags |= RING_FLAG_E2E; + ring = tb_ring_alloc_rx(xd->tb->nhi, -1, TBNET_RING_SIZE, flags, net->tx_ring.ring->hop, sof_mask, eof_mask, tbnet_start_poll, net); diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 98f899ea2e94..81d8412ce8e2 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -1487,8 +1487,10 @@ ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) headroom = skb_headroom(skb) - 8; - if ((dev->net->features & NETIF_F_SG) && skb_linearize(skb)) + if ((dev->net->features & NETIF_F_SG) && skb_linearize(skb)) { + dev_kfree_skb_any(skb); return NULL; + } if ((skb_header_cloned(skb) || headroom < 0) && pskb_expand_head(skb, headroom < 0 ? 8 : 0, 0, GFP_ATOMIC)) { diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index bb1364f85bd1..2b490114d232 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -490,6 +490,7 @@ static int ipheth_open(struct net_device *net) if (retval) return retval; + enable_delayed_work(&dev->carrier_work); schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT); return retval; } @@ -499,7 +500,11 @@ static int ipheth_close(struct net_device *net) struct ipheth_device *dev = netdev_priv(net); netif_stop_queue(net); - cancel_delayed_work_sync(&dev->carrier_work); + /* A TX URB can still complete with an error after this point and + * try to re-arm the carrier work. Disable it instead of cancelling + * it, so that such a schedule_delayed_work() is a no-op. + */ + disable_delayed_work_sync(&dev->carrier_work); return 0; } @@ -629,6 +634,10 @@ static int ipheth_probe(struct usb_interface *intf, } INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work); + /* Armed only between ipheth_open() and ipheth_close(). Start out + * disabled so the enable/disable counts balance from the first open. + */ + disable_delayed_work(&dev->carrier_work); retval = ipheth_alloc_urbs(dev); if (retval) { diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 25518635b7b7..a19ecf718f36 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1794,7 +1794,7 @@ usbnet_probe(struct usb_interface *udev, const struct usb_device_id *prod) */ dev->hard_mtu = net->mtu + net->hard_header_len; net->min_mtu = 0; - net->max_mtu = ETH_MAX_MTU; + net->max_mtu = net->mtu; net->netdev_ops = &usbnet_netdev_ops; net->watchdog_timeo = TX_TIMEOUT_JIFFIES; @@ -1804,6 +1804,7 @@ usbnet_probe(struct usb_interface *udev, const struct usb_device_id *prod) // allow device-specific bind/init procedures // NOTE net->name still not usable ... if (info->bind) { + net->max_mtu = ETH_MAX_MTU; status = info->bind(dev, udev); if (status < 0) goto out1; diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 35e911f1ad78..3d26ec1f7b9e 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -2177,9 +2177,11 @@ ptp_ocp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, if (err) return err; + snprintf(buf, sizeof(buf), "%.*s", OCP_BOARD_ID_LEN, + (const char *)bp->board_id); err = devlink_info_version_fixed_put(req, DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, - bp->board_id); + buf); if (err) return err; diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c index d99c588d3e00..242da20f27e0 100644 --- a/drivers/s390/net/ism_drv.c +++ b/drivers/s390/net/ism_drv.c @@ -148,13 +148,16 @@ static int unregister_sba(struct ism_dev *ism) if (ret && ret != ISM_ERROR) return -EIO; + return 0; +} + +static void ism_free_sba(struct ism_dev *ism) +{ dma_free_coherent(&ism->pdev->dev, PAGE_SIZE, ism->sba, ism->sba_dma_addr); ism->sba = NULL; ism->sba_dma_addr = 0; - - return 0; } static int unregister_ieq(struct ism_dev *ism) @@ -168,13 +171,16 @@ static int unregister_ieq(struct ism_dev *ism) if (ret && ret != ISM_ERROR) return -EIO; + return 0; +} + +static void ism_free_ieq(struct ism_dev *ism) +{ dma_free_coherent(&ism->pdev->dev, PAGE_SIZE, ism->ieq, ism->ieq_dma_addr); ism->ieq = NULL; ism->ieq_dma_addr = 0; - - return 0; } static int ism_read_local_gid(struct dibs_dev *dibs) @@ -573,6 +579,7 @@ static int ism_dev_init(struct ism_dev *ism) unreg_sba: unregister_sba(ism); + ism_free_sba(ism); free_irq: free_irq(pci_irq_vector(pdev, 0), ism); free_vectors: @@ -585,9 +592,13 @@ static void ism_dev_exit(struct ism_dev *ism) { struct pci_dev *pdev = ism->pdev; + /* ism will only generate new IRQs while ieq & sba are registered */ unregister_ieq(ism); unregister_sba(ism); + /* drain ongoing irpt handlers */ free_irq(pci_irq_vector(pdev, 0), ism); + ism_free_ieq(ism); + ism_free_sba(ism); pci_free_irq_vectors(pdev); } diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index f18eed9df3c7..c3257b213360 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4710,6 +4710,9 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata) if (req_len > QETH_BUFSIZE) return -EINVAL; + if (qinfo.udata_len < sizeof(struct qeth_snmp_ureq_hdr)) + return -EINVAL; + iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_SNMP_CONTROL, req_len); if (!iob) return -ENOMEM; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 1542bfc9f561..f1ac9950dcb4 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1415,6 +1415,11 @@ static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata) rc = -EFAULT; goto out; } + + if (qinfo.udata_len < QETH_QARP_ENTRIES_OFFSET) { + rc = -EINVAL; + goto out; + } qinfo.udata = kzalloc(qinfo.udata_len, GFP_KERNEL); if (!qinfo.udata) { rc = -ENOMEM; diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile index b35d74592964..b5188dcde37a 100644 --- a/drivers/soc/aspeed/Makefile +++ b/drivers/soc/aspeed/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o obj-$(CONFIG_ASPEED_SOCINFO) += aspeed-socinfo.o +CONTEXT_ANALYSIS_aspeed-lpc-snoop.o := y diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c index 28e491fffc7d..b09dca34099f 100644 --- a/drivers/soc/aspeed/aspeed-lpc-snoop.c +++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c @@ -11,6 +11,7 @@ */ #include <linux/bitops.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/dev_printk.h> #include <linux/interrupt.h> @@ -74,7 +75,8 @@ struct aspeed_lpc_snoop_channel_cfg { struct aspeed_lpc_snoop_channel { const struct aspeed_lpc_snoop_channel_cfg *cfg; bool enabled; - struct kfifo fifo; + spinlock_t lock; + struct kfifo fifo __guarded_by(&lock); wait_queue_head_t wq; struct miscdevice miscdev; }; @@ -114,6 +116,7 @@ static ssize_t snoop_file_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct aspeed_lpc_snoop_channel *chan = snoop_file_to_chan(file); + u8 *buf __free(kfree) = NULL; unsigned int copied; int ret = 0; @@ -125,9 +128,16 @@ static ssize_t snoop_file_read(struct file *file, char __user *buffer, if (ret == -ERESTARTSYS) return -EINTR; } - ret = kfifo_to_user(&chan->fifo, buffer, count, &copied); - if (ret) - return ret; + + count = min_t(size_t, count, SNOOP_FIFO_SIZE); + + buf = kmalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + copied = kfifo_out_spinlocked(&chan->fifo, buf, count, &chan->lock); + if (copied && copy_to_user(buffer, buf, copied)) + return -EFAULT; return copied; } @@ -151,11 +161,13 @@ static const struct file_operations snoop_fops = { /* Save a byte to a FIFO and discard the oldest byte if FIFO is full */ static void put_fifo_with_discard(struct aspeed_lpc_snoop_channel *chan, u8 val) { - if (!kfifo_initialized(&chan->fifo)) - return; - if (kfifo_is_full(&chan->fifo)) - kfifo_skip(&chan->fifo); - kfifo_put(&chan->fifo, val); + scoped_guard(spinlock, &chan->lock) { + if (!kfifo_initialized(&chan->fifo)) + return; + if (kfifo_is_full(&chan->fifo)) + kfifo_skip(&chan->fifo); + kfifo_put(&chan->fifo, val); + } wake_up_interruptible(&chan->wq); } @@ -239,9 +251,11 @@ static int aspeed_lpc_enable_snoop(struct device *dev, if (!channel->miscdev.name) return -ENOMEM; - rc = kfifo_alloc(&channel->fifo, SNOOP_FIFO_SIZE, GFP_KERNEL); - if (rc) - return rc; + scoped_guard(spinlock_init, &channel->lock) { + rc = kfifo_alloc(&channel->fifo, SNOOP_FIFO_SIZE, GFP_KERNEL); + if (rc) + return rc; + } rc = misc_register(&channel->miscdev); if (rc) |
