commit: 198bb8c524dfcb99110f48c17e71b32e08d37306 Author: Arisu Tachibana <alicef <AT> gentoo <DOT> org> AuthorDate: Fri Jul 11 02:32:22 2025 +0000 Commit: Arisu Tachibana <alicef <AT> gentoo <DOT> org> CommitDate: Fri Jul 11 02:32:22 2025 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=198bb8c5
Linux patch 5.4.267 Signed-off-by: Arisu Tachibana <alicef <AT> gentoo.org> 0000_README | 4 + 1266_linux-5.4.267.patch | 2143 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2147 insertions(+) diff --git a/0000_README b/0000_README index 08a41976..adfd42d8 100644 --- a/0000_README +++ b/0000_README @@ -1107,6 +1107,10 @@ Patch: 1265_linux-5.4.266.patch From: https://www.kernel.org Desc: Linux 5.4.266 +Patch: 1266_linux-5.4.267.patch +From: https://www.kernel.org +Desc: Linux 5.4.267 + Patch: 1500_XATTR_USER_PREFIX.patch From: https://bugs.gentoo.org/show_bug.cgi?id=470644 Desc: Support for namespace user.pax.* on tmpfs. diff --git a/1266_linux-5.4.267.patch b/1266_linux-5.4.267.patch new file mode 100644 index 00000000..6fc9f7af --- /dev/null +++ b/1266_linux-5.4.267.patch @@ -0,0 +1,2143 @@ +diff --git a/Makefile b/Makefile +index 500edb9d9f15f..7ce9119d77d29 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 5 + PATCHLEVEL = 4 +-SUBLEVEL = 266 ++SUBLEVEL = 267 + EXTRAVERSION = + NAME = Kleptomaniac Octopus + +diff --git a/arch/arm/mach-sunxi/mc_smp.c b/arch/arm/mach-sunxi/mc_smp.c +index 26cbce1353387..b2f5f4f28705f 100644 +--- a/arch/arm/mach-sunxi/mc_smp.c ++++ b/arch/arm/mach-sunxi/mc_smp.c +@@ -808,12 +808,12 @@ static int __init sunxi_mc_smp_init(void) + break; + } + +- is_a83t = sunxi_mc_smp_data[i].is_a83t; +- + of_node_put(node); + if (ret) + return -ENODEV; + ++ is_a83t = sunxi_mc_smp_data[i].is_a83t; ++ + if (!sunxi_mc_smp_cpu_table_init()) + return -EINVAL; + +diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c +index e1fa832f9fd72..6603f13f5de9b 100644 +--- a/drivers/firewire/ohci.c ++++ b/drivers/firewire/ohci.c +@@ -279,6 +279,51 @@ static char ohci_driver_name[] = KBUILD_MODNAME; + #define QUIRK_TI_SLLZ059 0x20 + #define QUIRK_IR_WAKE 0x40 + ++// On PCI Express Root Complex in any type of AMD Ryzen machine, VIA VT6306/6307/6308 with Asmedia ++// ASM1083/1085 brings an inconvenience that the read accesses to 'Isochronous Cycle Timer' register ++// (at offset 0xf0 in PCI I/O space) often causes unexpected system reboot. The mechanism is not ++// clear, since the read access to the other registers is enough safe; e.g. 'Node ID' register, ++// while it is probable due to detection of any type of PCIe error. ++#define QUIRK_REBOOT_BY_CYCLE_TIMER_READ 0x80000000 ++ ++#if IS_ENABLED(CONFIG_X86) ++ ++static bool has_reboot_by_cycle_timer_read_quirk(const struct fw_ohci *ohci) ++{ ++ return !!(ohci->quirks & QUIRK_REBOOT_BY_CYCLE_TIMER_READ); ++} ++ ++#define PCI_DEVICE_ID_ASMEDIA_ASM108X 0x1080 ++ ++static bool detect_vt630x_with_asm1083_on_amd_ryzen_machine(const struct pci_dev *pdev) ++{ ++ const struct pci_dev *pcie_to_pci_bridge; ++ ++ // Detect any type of AMD Ryzen machine. ++ if (!static_cpu_has(X86_FEATURE_ZEN)) ++ return false; ++ ++ // Detect VIA VT6306/6307/6308. ++ if (pdev->vendor != PCI_VENDOR_ID_VIA) ++ return false; ++ if (pdev->device != PCI_DEVICE_ID_VIA_VT630X) ++ return false; ++ ++ // Detect Asmedia ASM1083/1085. ++ pcie_to_pci_bridge = pdev->bus->self; ++ if (pcie_to_pci_bridge->vendor != PCI_VENDOR_ID_ASMEDIA) ++ return false; ++ if (pcie_to_pci_bridge->device != PCI_DEVICE_ID_ASMEDIA_ASM108X) ++ return false; ++ ++ return true; ++} ++ ++#else ++#define has_reboot_by_cycle_timer_read_quirk(ohci) false ++#define detect_vt630x_with_asm1083_on_amd_ryzen_machine(pdev) false ++#endif ++ + /* In case of multiple matches in ohci_quirks[], only the first one is used. */ + static const struct { + unsigned short vendor, device, revision, flags; +@@ -1717,6 +1762,9 @@ static u32 get_cycle_time(struct fw_ohci *ohci) + s32 diff01, diff12; + int i; + ++ if (has_reboot_by_cycle_timer_read_quirk(ohci)) ++ return 0; ++ + c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + + if (ohci->quirks & QUIRK_CYCLE_TIMER) { +@@ -3619,6 +3667,9 @@ static int pci_probe(struct pci_dev *dev, + if (param_quirks) + ohci->quirks = param_quirks; + ++ if (detect_vt630x_with_asm1083_on_amd_ryzen_machine(dev)) ++ ohci->quirks |= QUIRK_REBOOT_BY_CYCLE_TIMER_READ; ++ + /* + * Because dma_alloc_coherent() allocates at least one page, + * we save space by using a common buffer for the AR request/ +diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h +index 328a2fff1935d..1226617a27e1e 100644 +--- a/drivers/i2c/i2c-core.h ++++ b/drivers/i2c/i2c-core.h +@@ -3,6 +3,7 @@ + * i2c-core.h - interfaces internal to the I2C framework + */ + ++#include <linux/kconfig.h> + #include <linux/rwsem.h> + + struct i2c_devinfo { +@@ -29,7 +30,8 @@ int i2c_dev_irq_from_resources(const struct resource *resources, + */ + static inline bool i2c_in_atomic_xfer_mode(void) + { +- return system_state > SYSTEM_RUNNING && !preemptible(); ++ return system_state > SYSTEM_RUNNING && ++ (IS_ENABLED(CONFIG_PREEMPT_COUNT) ? !preemptible() : irqs_disabled()); + } + + static inline int __i2c_lock_bus_helper(struct i2c_adapter *adap) +diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c +index 010a6dc0e7cf3..db8c2e2193256 100644 +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -850,9 +850,10 @@ static const struct block_device_operations mmc_bdops = { + static int mmc_blk_part_switch_pre(struct mmc_card *card, + unsigned int part_type) + { ++ const unsigned int mask = EXT_CSD_PART_CONFIG_ACC_RPMB; + int ret = 0; + +- if (part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) { ++ if ((part_type & mask) == mask) { + if (card->ext_csd.cmdq_en) { + ret = mmc_cmdq_disable(card); + if (ret) +@@ -867,9 +868,10 @@ static int mmc_blk_part_switch_pre(struct mmc_card *card, + static int mmc_blk_part_switch_post(struct mmc_card *card, + unsigned int part_type) + { ++ const unsigned int mask = EXT_CSD_PART_CONFIG_ACC_RPMB; + int ret = 0; + +- if (part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) { ++ if ((part_type & mask) == mask) { + mmc_retune_unpause(card->host); + if (card->reenable_cmdq && !card->ext_csd.cmdq_en) + ret = mmc_cmdq_enable(card); +@@ -3091,4 +3093,3 @@ module_exit(mmc_blk_exit); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver"); +- +diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c +index 32801639e0be5..2d63c0f188e18 100644 +--- a/drivers/mmc/core/host.c ++++ b/drivers/mmc/core/host.c +@@ -570,6 +570,7 @@ EXPORT_SYMBOL(mmc_remove_host); + */ + void mmc_free_host(struct mmc_host *host) + { ++ cancel_delayed_work_sync(&host->detect); + mmc_pwrseq_free(host); + put_device(&host->class_dev); + } +diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c +index b624589e62a0e..ef89fdf1f904e 100644 +--- a/drivers/mmc/host/sdhci-sprd.c ++++ b/drivers/mmc/host/sdhci-sprd.c +@@ -223,15 +223,19 @@ static inline void _sdhci_sprd_set_clock(struct sdhci_host *host, + div = ((div & 0x300) >> 2) | ((div & 0xFF) << 8); + sdhci_enable_clk(host, div); + ++ val = sdhci_readl(host, SDHCI_SPRD_REG_32_BUSY_POSI); ++ mask = SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN | SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN; + /* Enable CLK_AUTO when the clock is greater than 400K. */ + if (clk > 400000) { +- val = sdhci_readl(host, SDHCI_SPRD_REG_32_BUSY_POSI); +- mask = SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN | +- SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN; + if (mask != (val & mask)) { + val |= mask; + sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI); + } ++ } else { ++ if (val & mask) { ++ val &= ~mask; ++ sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI); ++ } + } + } + +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +index 7f85315744009..2a12a41442611 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +@@ -10340,6 +10340,8 @@ static void bnxt_sp_task(struct work_struct *work) + bnxt_cfg_ntp_filters(bp); + if (test_and_clear_bit(BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT, &bp->sp_event)) + bnxt_hwrm_exec_fwd_req(bp); ++ if (test_and_clear_bit(BNXT_HWRM_PF_UNLOAD_SP_EVENT, &bp->sp_event)) ++ netdev_info(bp->dev, "Receive PF driver unload event!\n"); + if (test_and_clear_bit(BNXT_VXLAN_ADD_PORT_SP_EVENT, &bp->sp_event)) { + bnxt_hwrm_tunnel_dst_port_alloc( + bp, bp->vxlan_port, +@@ -11266,8 +11268,6 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp) + } + } + } +- if (test_and_clear_bit(BNXT_HWRM_PF_UNLOAD_SP_EVENT, &bp->sp_event)) +- netdev_info(bp->dev, "Receive PF driver unload event!"); + } + + #else +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 750acbf294640..eeadeeec17bab 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1648,8 +1648,10 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) + /* Note: if we ever change from DMA_TX_APPEND_CRC below we + * will need to restore software padding of "runt" packets + */ ++ len_stat |= DMA_TX_APPEND_CRC; ++ + if (!i) { +- len_stat |= DMA_TX_APPEND_CRC | DMA_SOP; ++ len_stat |= DMA_SOP; + if (skb->ip_summed == CHECKSUM_PARTIAL) + len_stat |= DMA_TX_DO_CSUM; + } +diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c +index 3ccc248b1a8a7..fa938281281a4 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_main.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c +@@ -110,12 +110,18 @@ static struct workqueue_struct *i40e_wq; + static void netdev_hw_addr_refcnt(struct i40e_mac_filter *f, + struct net_device *netdev, int delta) + { ++ struct netdev_hw_addr_list *ha_list; + struct netdev_hw_addr *ha; + + if (!f || !netdev) + return; + +- netdev_for_each_mc_addr(ha, netdev) { ++ if (is_unicast_ether_addr(f->macaddr) || is_link_local_ether_addr(f->macaddr)) ++ ha_list = &netdev->uc; ++ else ++ ha_list = &netdev->mc; ++ ++ netdev_hw_addr_list_for_each(ha, ha_list) { + if (ether_addr_equal(ha->addr, f->macaddr)) { + ha->refcount += delta; + if (ha->refcount <= 0) +@@ -15710,6 +15716,9 @@ static void i40e_pci_error_reset_done(struct pci_dev *pdev) + struct i40e_pf *pf = pci_get_drvdata(pdev); + + i40e_reset_and_rebuild(pf, false, false); ++#ifdef CONFIG_PCI_IOV ++ i40e_restore_all_vfs_msi_state(pdev); ++#endif /* CONFIG_PCI_IOV */ + } + + /** +diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +index 37ce764ed3730..e79b8dc5c2a5e 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +@@ -99,6 +99,32 @@ void i40e_vc_notify_reset(struct i40e_pf *pf) + (u8 *)&pfe, sizeof(struct virtchnl_pf_event)); + } + ++#ifdef CONFIG_PCI_IOV ++void i40e_restore_all_vfs_msi_state(struct pci_dev *pdev) ++{ ++ u16 vf_id; ++ u16 pos; ++ ++ /* Continue only if this is a PF */ ++ if (!pdev->is_physfn) ++ return; ++ ++ if (!pci_num_vf(pdev)) ++ return; ++ ++ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); ++ if (pos) { ++ struct pci_dev *vf_dev = NULL; ++ ++ pci_read_config_word(pdev, pos + PCI_SRIOV_VF_DID, &vf_id); ++ while ((vf_dev = pci_get_device(pdev->vendor, vf_id, vf_dev))) { ++ if (vf_dev->is_virtfn && vf_dev->physfn == pdev) ++ pci_restore_msi_state(vf_dev); ++ } ++ } ++} ++#endif /* CONFIG_PCI_IOV */ ++ + /** + * i40e_vc_notify_vf_reset + * @vf: pointer to the VF structure +@@ -3332,16 +3358,16 @@ static int i40e_validate_cloud_filter(struct i40e_vf *vf, + bool found = false; + int bkt; + +- if (!tc_filter->action) { ++ if (tc_filter->action != VIRTCHNL_ACTION_TC_REDIRECT) { + dev_info(&pf->pdev->dev, +- "VF %d: Currently ADq doesn't support Drop Action\n", +- vf->vf_id); ++ "VF %d: ADQ doesn't support this action (%d)\n", ++ vf->vf_id, tc_filter->action); + goto err; + } + + /* action_meta is TC number here to which the filter is applied */ + if (!tc_filter->action_meta || +- tc_filter->action_meta > I40E_MAX_VF_VSI) { ++ tc_filter->action_meta > vf->num_tc) { + dev_info(&pf->pdev->dev, "VF %d: Invalid TC number %u\n", + vf->vf_id, tc_filter->action_meta); + goto err; +diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +index 23182731a73d0..75d916714ad8a 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h ++++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +@@ -141,5 +141,8 @@ int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable); + + void i40e_vc_notify_link_state(struct i40e_pf *pf); + void i40e_vc_notify_reset(struct i40e_pf *pf); ++#ifdef CONFIG_PCI_IOV ++void i40e_restore_all_vfs_msi_state(struct pci_dev *pdev); ++#endif /* CONFIG_PCI_IOV */ + + #endif /* _I40E_VIRTCHNL_PF_H_ */ +diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c +index 2fa68592210d7..5d0e65a3b6a83 100644 +--- a/drivers/net/ethernet/qlogic/qla3xxx.c ++++ b/drivers/net/ethernet/qlogic/qla3xxx.c +@@ -316,12 +316,11 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev, + * buffer + */ + skb_reserve(lrg_buf_cb->skb, QL_HEADER_SPACE); +- map = pci_map_single(qdev->pdev, ++ map = dma_map_single(&qdev->pdev->dev, + lrg_buf_cb->skb->data, +- qdev->lrg_buffer_len - +- QL_HEADER_SPACE, +- PCI_DMA_FROMDEVICE); +- err = pci_dma_mapping_error(qdev->pdev, map); ++ qdev->lrg_buffer_len - QL_HEADER_SPACE, ++ DMA_FROM_DEVICE); ++ err = dma_mapping_error(&qdev->pdev->dev, map); + if (err) { + netdev_err(qdev->ndev, + "PCI mapping failed with error: %d\n", +@@ -1803,13 +1802,12 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev) + * first buffer + */ + skb_reserve(lrg_buf_cb->skb, QL_HEADER_SPACE); +- map = pci_map_single(qdev->pdev, ++ map = dma_map_single(&qdev->pdev->dev, + lrg_buf_cb->skb->data, +- qdev->lrg_buffer_len - +- QL_HEADER_SPACE, +- PCI_DMA_FROMDEVICE); ++ qdev->lrg_buffer_len - QL_HEADER_SPACE, ++ DMA_FROM_DEVICE); + +- err = pci_dma_mapping_error(qdev->pdev, map); ++ err = dma_mapping_error(&qdev->pdev->dev, map); + if (err) { + netdev_err(qdev->ndev, + "PCI mapping failed with error: %d\n", +@@ -1944,18 +1942,16 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, + goto invalid_seg_count; + } + +- pci_unmap_single(qdev->pdev, ++ dma_unmap_single(&qdev->pdev->dev, + dma_unmap_addr(&tx_cb->map[0], mapaddr), +- dma_unmap_len(&tx_cb->map[0], maplen), +- PCI_DMA_TODEVICE); ++ dma_unmap_len(&tx_cb->map[0], maplen), DMA_TO_DEVICE); + tx_cb->seg_count--; + if (tx_cb->seg_count) { + for (i = 1; i < tx_cb->seg_count; i++) { +- pci_unmap_page(qdev->pdev, +- dma_unmap_addr(&tx_cb->map[i], +- mapaddr), ++ dma_unmap_page(&qdev->pdev->dev, ++ dma_unmap_addr(&tx_cb->map[i], mapaddr), + dma_unmap_len(&tx_cb->map[i], maplen), +- PCI_DMA_TODEVICE); ++ DMA_TO_DEVICE); + } + } + qdev->ndev->stats.tx_packets++; +@@ -2022,10 +2018,9 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev, + qdev->ndev->stats.rx_bytes += length; + + skb_put(skb, length); +- pci_unmap_single(qdev->pdev, ++ dma_unmap_single(&qdev->pdev->dev, + dma_unmap_addr(lrg_buf_cb2, mapaddr), +- dma_unmap_len(lrg_buf_cb2, maplen), +- PCI_DMA_FROMDEVICE); ++ dma_unmap_len(lrg_buf_cb2, maplen), DMA_FROM_DEVICE); + prefetch(skb->data); + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, qdev->ndev); +@@ -2068,10 +2063,9 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, + skb2 = lrg_buf_cb2->skb; + + skb_put(skb2, length); /* Just the second buffer length here. */ +- pci_unmap_single(qdev->pdev, ++ dma_unmap_single(&qdev->pdev->dev, + dma_unmap_addr(lrg_buf_cb2, mapaddr), +- dma_unmap_len(lrg_buf_cb2, maplen), +- PCI_DMA_FROMDEVICE); ++ dma_unmap_len(lrg_buf_cb2, maplen), DMA_FROM_DEVICE); + prefetch(skb2->data); + + skb_checksum_none_assert(skb2); +@@ -2320,9 +2314,9 @@ static int ql_send_map(struct ql3_adapter *qdev, + /* + * Map the skb buffer first. + */ +- map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE); ++ map = dma_map_single(&qdev->pdev->dev, skb->data, len, DMA_TO_DEVICE); + +- err = pci_dma_mapping_error(qdev->pdev, map); ++ err = dma_mapping_error(&qdev->pdev->dev, map); + if (err) { + netdev_err(qdev->ndev, "PCI mapping failed with error: %d\n", + err); +@@ -2358,11 +2352,11 @@ static int ql_send_map(struct ql3_adapter *qdev, + (seg == 7 && seg_cnt > 8) || + (seg == 12 && seg_cnt > 13) || + (seg == 17 && seg_cnt > 18)) { +- map = pci_map_single(qdev->pdev, oal, ++ map = dma_map_single(&qdev->pdev->dev, oal, + sizeof(struct oal), +- PCI_DMA_TODEVICE); ++ DMA_TO_DEVICE); + +- err = pci_dma_mapping_error(qdev->pdev, map); ++ err = dma_mapping_error(&qdev->pdev->dev, map); + if (err) { + netdev_err(qdev->ndev, + "PCI mapping outbound address list with error: %d\n", +@@ -2424,24 +2418,24 @@ map_error: + (seg == 7 && seg_cnt > 8) || + (seg == 12 && seg_cnt > 13) || + (seg == 17 && seg_cnt > 18)) { +- pci_unmap_single(qdev->pdev, +- dma_unmap_addr(&tx_cb->map[seg], mapaddr), +- dma_unmap_len(&tx_cb->map[seg], maplen), +- PCI_DMA_TODEVICE); ++ dma_unmap_single(&qdev->pdev->dev, ++ dma_unmap_addr(&tx_cb->map[seg], mapaddr), ++ dma_unmap_len(&tx_cb->map[seg], maplen), ++ DMA_TO_DEVICE); + oal++; + seg++; + } + +- pci_unmap_page(qdev->pdev, ++ dma_unmap_page(&qdev->pdev->dev, + dma_unmap_addr(&tx_cb->map[seg], mapaddr), + dma_unmap_len(&tx_cb->map[seg], maplen), +- PCI_DMA_TODEVICE); ++ DMA_TO_DEVICE); + } + +- pci_unmap_single(qdev->pdev, ++ dma_unmap_single(&qdev->pdev->dev, + dma_unmap_addr(&tx_cb->map[0], mapaddr), + dma_unmap_addr(&tx_cb->map[0], maplen), +- PCI_DMA_TODEVICE); ++ DMA_TO_DEVICE); + + return NETDEV_TX_BUSY; + +@@ -2527,9 +2521,8 @@ static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev) + wmb(); + + qdev->req_q_virt_addr = +- pci_alloc_consistent(qdev->pdev, +- (size_t) qdev->req_q_size, +- &qdev->req_q_phy_addr); ++ dma_alloc_coherent(&qdev->pdev->dev, (size_t)qdev->req_q_size, ++ &qdev->req_q_phy_addr, GFP_KERNEL); + + if ((qdev->req_q_virt_addr == NULL) || + LS_64BITS(qdev->req_q_phy_addr) & (qdev->req_q_size - 1)) { +@@ -2538,16 +2531,14 @@ static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev) + } + + qdev->rsp_q_virt_addr = +- pci_alloc_consistent(qdev->pdev, +- (size_t) qdev->rsp_q_size, +- &qdev->rsp_q_phy_addr); ++ dma_alloc_coherent(&qdev->pdev->dev, (size_t)qdev->rsp_q_size, ++ &qdev->rsp_q_phy_addr, GFP_KERNEL); + + if ((qdev->rsp_q_virt_addr == NULL) || + LS_64BITS(qdev->rsp_q_phy_addr) & (qdev->rsp_q_size - 1)) { + netdev_err(qdev->ndev, "rspQ allocation failed\n"); +- pci_free_consistent(qdev->pdev, (size_t) qdev->req_q_size, +- qdev->req_q_virt_addr, +- qdev->req_q_phy_addr); ++ dma_free_coherent(&qdev->pdev->dev, (size_t)qdev->req_q_size, ++ qdev->req_q_virt_addr, qdev->req_q_phy_addr); + return -ENOMEM; + } + +@@ -2563,15 +2554,13 @@ static void ql_free_net_req_rsp_queues(struct ql3_adapter *qdev) + return; + } + +- pci_free_consistent(qdev->pdev, +- qdev->req_q_size, +- qdev->req_q_virt_addr, qdev->req_q_phy_addr); ++ dma_free_coherent(&qdev->pdev->dev, qdev->req_q_size, ++ qdev->req_q_virt_addr, qdev->req_q_phy_addr); + + qdev->req_q_virt_addr = NULL; + +- pci_free_consistent(qdev->pdev, +- qdev->rsp_q_size, +- qdev->rsp_q_virt_addr, qdev->rsp_q_phy_addr); ++ dma_free_coherent(&qdev->pdev->dev, qdev->rsp_q_size, ++ qdev->rsp_q_virt_addr, qdev->rsp_q_phy_addr); + + qdev->rsp_q_virt_addr = NULL; + +@@ -2595,12 +2584,13 @@ static int ql_alloc_buffer_queues(struct ql3_adapter *qdev) + return -ENOMEM; + + qdev->lrg_buf_q_alloc_virt_addr = +- pci_alloc_consistent(qdev->pdev, +- qdev->lrg_buf_q_alloc_size, +- &qdev->lrg_buf_q_alloc_phy_addr); ++ dma_alloc_coherent(&qdev->pdev->dev, ++ qdev->lrg_buf_q_alloc_size, ++ &qdev->lrg_buf_q_alloc_phy_addr, GFP_KERNEL); + + if (qdev->lrg_buf_q_alloc_virt_addr == NULL) { + netdev_err(qdev->ndev, "lBufQ failed\n"); ++ kfree(qdev->lrg_buf); + return -ENOMEM; + } + qdev->lrg_buf_q_virt_addr = qdev->lrg_buf_q_alloc_virt_addr; +@@ -2615,15 +2605,17 @@ static int ql_alloc_buffer_queues(struct ql3_adapter *qdev) + qdev->small_buf_q_alloc_size = qdev->small_buf_q_size * 2; + + qdev->small_buf_q_alloc_virt_addr = +- pci_alloc_consistent(qdev->pdev, +- qdev->small_buf_q_alloc_size, +- &qdev->small_buf_q_alloc_phy_addr); ++ dma_alloc_coherent(&qdev->pdev->dev, ++ qdev->small_buf_q_alloc_size, ++ &qdev->small_buf_q_alloc_phy_addr, GFP_KERNEL); + + if (qdev->small_buf_q_alloc_virt_addr == NULL) { + netdev_err(qdev->ndev, "Small Buffer Queue allocation failed\n"); +- pci_free_consistent(qdev->pdev, qdev->lrg_buf_q_alloc_size, +- qdev->lrg_buf_q_alloc_virt_addr, +- qdev->lrg_buf_q_alloc_phy_addr); ++ dma_free_coherent(&qdev->pdev->dev, ++ qdev->lrg_buf_q_alloc_size, ++ qdev->lrg_buf_q_alloc_virt_addr, ++ qdev->lrg_buf_q_alloc_phy_addr); ++ kfree(qdev->lrg_buf); + return -ENOMEM; + } + +@@ -2640,17 +2632,15 @@ static void ql_free_buffer_queues(struct ql3_adapter *qdev) + return; + } + kfree(qdev->lrg_buf); +- pci_free_consistent(qdev->pdev, +- qdev->lrg_buf_q_alloc_size, +- qdev->lrg_buf_q_alloc_virt_addr, +- qdev->lrg_buf_q_alloc_phy_addr); ++ dma_free_coherent(&qdev->pdev->dev, qdev->lrg_buf_q_alloc_size, ++ qdev->lrg_buf_q_alloc_virt_addr, ++ qdev->lrg_buf_q_alloc_phy_addr); + + qdev->lrg_buf_q_virt_addr = NULL; + +- pci_free_consistent(qdev->pdev, +- qdev->small_buf_q_alloc_size, +- qdev->small_buf_q_alloc_virt_addr, +- qdev->small_buf_q_alloc_phy_addr); ++ dma_free_coherent(&qdev->pdev->dev, qdev->small_buf_q_alloc_size, ++ qdev->small_buf_q_alloc_virt_addr, ++ qdev->small_buf_q_alloc_phy_addr); + + qdev->small_buf_q_virt_addr = NULL; + +@@ -2668,9 +2658,9 @@ static int ql_alloc_small_buffers(struct ql3_adapter *qdev) + QL_SMALL_BUFFER_SIZE); + + qdev->small_buf_virt_addr = +- pci_alloc_consistent(qdev->pdev, +- qdev->small_buf_total_size, +- &qdev->small_buf_phy_addr); ++ dma_alloc_coherent(&qdev->pdev->dev, ++ qdev->small_buf_total_size, ++ &qdev->small_buf_phy_addr, GFP_KERNEL); + + if (qdev->small_buf_virt_addr == NULL) { + netdev_err(qdev->ndev, "Failed to get small buffer memory\n"); +@@ -2703,10 +2693,10 @@ static void ql_free_small_buffers(struct ql3_adapter *qdev) + return; + } + if (qdev->small_buf_virt_addr != NULL) { +- pci_free_consistent(qdev->pdev, +- qdev->small_buf_total_size, +- qdev->small_buf_virt_addr, +- qdev->small_buf_phy_addr); ++ dma_free_coherent(&qdev->pdev->dev, ++ qdev->small_buf_total_size, ++ qdev->small_buf_virt_addr, ++ qdev->small_buf_phy_addr); + + qdev->small_buf_virt_addr = NULL; + } +@@ -2721,10 +2711,10 @@ static void ql_free_large_buffers(struct ql3_adapter *qdev) + lrg_buf_cb = &qdev->lrg_buf[i]; + if (lrg_buf_cb->skb) { + dev_kfree_skb(lrg_buf_cb->skb); +- pci_unmap_single(qdev->pdev, ++ dma_unmap_single(&qdev->pdev->dev, + dma_unmap_addr(lrg_buf_cb, mapaddr), + dma_unmap_len(lrg_buf_cb, maplen), +- PCI_DMA_FROMDEVICE); ++ DMA_FROM_DEVICE); + memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb)); + } else { + break; +@@ -2776,13 +2766,11 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev) + * buffer + */ + skb_reserve(skb, QL_HEADER_SPACE); +- map = pci_map_single(qdev->pdev, +- skb->data, +- qdev->lrg_buffer_len - +- QL_HEADER_SPACE, +- PCI_DMA_FROMDEVICE); ++ map = dma_map_single(&qdev->pdev->dev, skb->data, ++ qdev->lrg_buffer_len - QL_HEADER_SPACE, ++ DMA_FROM_DEVICE); + +- err = pci_dma_mapping_error(qdev->pdev, map); ++ err = dma_mapping_error(&qdev->pdev->dev, map); + if (err) { + netdev_err(qdev->ndev, + "PCI mapping failed with error: %d\n", +@@ -2867,8 +2855,8 @@ static int ql_alloc_mem_resources(struct ql3_adapter *qdev) + * Network Completion Queue Producer Index Register + */ + qdev->shadow_reg_virt_addr = +- pci_alloc_consistent(qdev->pdev, +- PAGE_SIZE, &qdev->shadow_reg_phy_addr); ++ dma_alloc_coherent(&qdev->pdev->dev, PAGE_SIZE, ++ &qdev->shadow_reg_phy_addr, GFP_KERNEL); + + if (qdev->shadow_reg_virt_addr != NULL) { + qdev->preq_consumer_index = qdev->shadow_reg_virt_addr; +@@ -2923,10 +2911,9 @@ err_small_buffers: + err_buffer_queues: + ql_free_net_req_rsp_queues(qdev); + err_req_rsp: +- pci_free_consistent(qdev->pdev, +- PAGE_SIZE, +- qdev->shadow_reg_virt_addr, +- qdev->shadow_reg_phy_addr); ++ dma_free_coherent(&qdev->pdev->dev, PAGE_SIZE, ++ qdev->shadow_reg_virt_addr, ++ qdev->shadow_reg_phy_addr); + + return -ENOMEM; + } +@@ -2939,10 +2926,9 @@ static void ql_free_mem_resources(struct ql3_adapter *qdev) + ql_free_buffer_queues(qdev); + ql_free_net_req_rsp_queues(qdev); + if (qdev->shadow_reg_virt_addr != NULL) { +- pci_free_consistent(qdev->pdev, +- PAGE_SIZE, +- qdev->shadow_reg_virt_addr, +- qdev->shadow_reg_phy_addr); ++ dma_free_coherent(&qdev->pdev->dev, PAGE_SIZE, ++ qdev->shadow_reg_virt_addr, ++ qdev->shadow_reg_phy_addr); + qdev->shadow_reg_virt_addr = NULL; + } + } +@@ -3643,18 +3629,15 @@ static void ql_reset_work(struct work_struct *work) + if (tx_cb->skb) { + netdev_printk(KERN_DEBUG, ndev, + "Freeing lost SKB\n"); +- pci_unmap_single(qdev->pdev, +- dma_unmap_addr(&tx_cb->map[0], +- mapaddr), +- dma_unmap_len(&tx_cb->map[0], maplen), +- PCI_DMA_TODEVICE); ++ dma_unmap_single(&qdev->pdev->dev, ++ dma_unmap_addr(&tx_cb->map[0], mapaddr), ++ dma_unmap_len(&tx_cb->map[0], maplen), ++ DMA_TO_DEVICE); + for (j = 1; j < tx_cb->seg_count; j++) { +- pci_unmap_page(qdev->pdev, +- dma_unmap_addr(&tx_cb->map[j], +- mapaddr), +- dma_unmap_len(&tx_cb->map[j], +- maplen), +- PCI_DMA_TODEVICE); ++ dma_unmap_page(&qdev->pdev->dev, ++ dma_unmap_addr(&tx_cb->map[j], mapaddr), ++ dma_unmap_len(&tx_cb->map[j], maplen), ++ DMA_TO_DEVICE); + } + dev_kfree_skb(tx_cb->skb); + tx_cb->skb = NULL; +@@ -3786,13 +3769,10 @@ static int ql3xxx_probe(struct pci_dev *pdev, + + pci_set_master(pdev); + +- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { ++ if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) + pci_using_dac = 1; +- err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); +- } else if (!(err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) { ++ else if (!(err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))) + pci_using_dac = 0; +- err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); +- } + + if (err) { + pr_err("%s no usable DMA configuration\n", pci_name(pdev)); +diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c +index 6101d82102e79..bf65262e2256d 100644 +--- a/drivers/net/usb/ax88172a.c ++++ b/drivers/net/usb/ax88172a.c +@@ -186,7 +186,9 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) + u8 buf[ETH_ALEN]; + struct ax88172a_private *priv; + +- usbnet_get_endpoints(dev, intf); ++ ret = usbnet_get_endpoints(dev, intf); ++ if (ret) ++ return ret; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) +diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c +index 01e05af5ae085..a03b7535c2544 100644 +--- a/drivers/net/wireless/ath/ath10k/ce.c ++++ b/drivers/net/wireless/ath/ath10k/ce.c +@@ -1299,29 +1299,24 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) + struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; + u32 ctrl_addr = ce_state->ctrl_addr; + +- spin_lock_bh(&ce->ce_lock); +- +- /* Clear the copy-complete interrupts that will be handled here. */ ++ /* ++ * Clear before handling ++ * ++ * Misc CE interrupts are not being handled, but still need ++ * to be cleared. ++ * ++ * NOTE: When the last copy engine interrupt is cleared the ++ * hardware will go to sleep. Once this happens any access to ++ * the CE registers can cause a hardware fault. ++ */ + ath10k_ce_engine_int_status_clear(ar, ctrl_addr, +- wm_regs->cc_mask); +- +- spin_unlock_bh(&ce->ce_lock); ++ wm_regs->cc_mask | wm_regs->wm_mask); + + if (ce_state->recv_cb) + ce_state->recv_cb(ce_state); + + if (ce_state->send_cb) + ce_state->send_cb(ce_state); +- +- spin_lock_bh(&ce->ce_lock); +- +- /* +- * Misc CE interrupts are not being handled, but still need +- * to be cleared. +- */ +- ath10k_ce_engine_int_status_clear(ar, ctrl_addr, wm_regs->wm_mask); +- +- spin_unlock_bh(&ce->ce_lock); + } + EXPORT_SYMBOL(ath10k_ce_per_engine_service); + +@@ -1372,45 +1367,55 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state) + ath10k_ce_watermark_intr_disable(ar, ctrl_addr); + } + +-int ath10k_ce_disable_interrupts(struct ath10k *ar) ++void ath10k_ce_disable_interrupt(struct ath10k *ar, int ce_id) + { + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_ce_pipe *ce_state; + u32 ctrl_addr; +- int ce_id; + +- for (ce_id = 0; ce_id < CE_COUNT; ce_id++) { +- ce_state = &ce->ce_states[ce_id]; +- if (ce_state->attr_flags & CE_ATTR_POLL) +- continue; ++ ce_state = &ce->ce_states[ce_id]; ++ if (ce_state->attr_flags & CE_ATTR_POLL) ++ return; + +- ctrl_addr = ath10k_ce_base_address(ar, ce_id); ++ ctrl_addr = ath10k_ce_base_address(ar, ce_id); + +- ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr); +- ath10k_ce_error_intr_disable(ar, ctrl_addr); +- ath10k_ce_watermark_intr_disable(ar, ctrl_addr); +- } ++ ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr); ++ ath10k_ce_error_intr_disable(ar, ctrl_addr); ++ ath10k_ce_watermark_intr_disable(ar, ctrl_addr); ++} ++EXPORT_SYMBOL(ath10k_ce_disable_interrupt); + +- return 0; ++void ath10k_ce_disable_interrupts(struct ath10k *ar) ++{ ++ int ce_id; ++ ++ for (ce_id = 0; ce_id < CE_COUNT; ce_id++) ++ ath10k_ce_disable_interrupt(ar, ce_id); + } + EXPORT_SYMBOL(ath10k_ce_disable_interrupts); + +-void ath10k_ce_enable_interrupts(struct ath10k *ar) ++void ath10k_ce_enable_interrupt(struct ath10k *ar, int ce_id) + { + struct ath10k_ce *ce = ath10k_ce_priv(ar); +- int ce_id; + struct ath10k_ce_pipe *ce_state; + ++ ce_state = &ce->ce_states[ce_id]; ++ if (ce_state->attr_flags & CE_ATTR_POLL) ++ return; ++ ++ ath10k_ce_per_engine_handler_adjust(ce_state); ++} ++EXPORT_SYMBOL(ath10k_ce_enable_interrupt); ++ ++void ath10k_ce_enable_interrupts(struct ath10k *ar) ++{ ++ int ce_id; ++ + /* Enable interrupts for copy engine that + * are not using polling mode. + */ +- for (ce_id = 0; ce_id < CE_COUNT; ce_id++) { +- ce_state = &ce->ce_states[ce_id]; +- if (ce_state->attr_flags & CE_ATTR_POLL) +- continue; +- +- ath10k_ce_per_engine_handler_adjust(ce_state); +- } ++ for (ce_id = 0; ce_id < CE_COUNT; ce_id++) ++ ath10k_ce_enable_interrupt(ar, ce_id); + } + EXPORT_SYMBOL(ath10k_ce_enable_interrupts); + +diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h +index a7478c240f784..fe07521550b7b 100644 +--- a/drivers/net/wireless/ath/ath10k/ce.h ++++ b/drivers/net/wireless/ath/ath10k/ce.h +@@ -255,10 +255,13 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, + /*==================CE Interrupt Handlers====================*/ + void ath10k_ce_per_engine_service_any(struct ath10k *ar); + void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id); +-int ath10k_ce_disable_interrupts(struct ath10k *ar); ++void ath10k_ce_disable_interrupt(struct ath10k *ar, int ce_id); ++void ath10k_ce_disable_interrupts(struct ath10k *ar); ++void ath10k_ce_enable_interrupt(struct ath10k *ar, int ce_id); + void ath10k_ce_enable_interrupts(struct ath10k *ar); + void ath10k_ce_dump_registers(struct ath10k *ar, + struct ath10k_fw_crash_data *crash_data); ++ + void ath10k_ce_alloc_rri(struct ath10k *ar); + void ath10k_ce_free_rri(struct ath10k *ar); + +@@ -369,18 +372,14 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) + (((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \ + CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) + #define CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000 +-#define CE_INTERRUPT_SUMMARY (GENMASK(CE_COUNT_MAX - 1, 0)) + + static inline u32 ath10k_ce_interrupt_summary(struct ath10k *ar) + { + struct ath10k_ce *ce = ath10k_ce_priv(ar); + +- if (!ar->hw_params.per_ce_irq) +- return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( +- ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS + +- CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)); +- else +- return CE_INTERRUPT_SUMMARY; ++ return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( ++ ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS + ++ CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)); + } + + /* Host software's Copy Engine configuration. */ +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index 3e1adfa2f2779..09e77be6e3142 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -118,7 +118,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .num_wds_entries = 0x20, + .target_64bit = false, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, +- .per_ce_irq = false, + .shadow_reg_support = false, + .rri_on_ddr = false, + .hw_filter_reset_required = true, +@@ -154,7 +153,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .num_wds_entries = 0x20, + .target_64bit = false, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, +- .per_ce_irq = false, + .shadow_reg_support = false, + .rri_on_ddr = false, + .hw_filter_reset_required = true, +@@ -217,7 +215,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .num_wds_entries = 0x20, + .target_64bit = false, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, +- .per_ce_irq = false, + .shadow_reg_support = false, + .rri_on_ddr = false, + .hw_filter_reset_required = true, +@@ -252,7 +249,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .num_wds_entries = 0x20, + .target_64bit = false, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, +- .per_ce_irq = false, + .shadow_reg_support = false, + .rri_on_ddr = false, + .hw_filter_reset_required = true, +@@ -287,7 +283,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .num_wds_entries = 0x20, + .target_64bit = false, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, +- .per_ce_irq = false, + .shadow_reg_support = false, + .rri_on_ddr = false, + .hw_filter_reset_required = true, +@@ -325,7 +320,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .num_wds_entries = 0x20, + .target_64bit = false, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, +- .per_ce_irq = false, + .shadow_reg_support = false, + .rri_on_ddr = false, + .hw_filter_reset_required = true, +@@ -366,7 +360,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .num_wds_entries = 0x20, + .target_64bit = false, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, +- .per_ce_irq = false, + .shadow_reg_support = false, + .rri_on_ddr = false, + .hw_filter_reset_required = true, +@@ -414,7 +407,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .num_wds_entries = 0x20, + .target_64bit = false, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, +- .per_ce_irq = false, + .shadow_reg_support = false, + .rri_on_ddr = false, + .hw_filter_reset_required = true, +@@ -459,7 +451,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .num_wds_entries = 0x20, + .target_64bit = false, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, +- .per_ce_irq = false, + .shadow_reg_support = false, + .rri_on_ddr = false, + .hw_filter_reset_required = true, +@@ -494,7 +485,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .num_wds_entries = 0x20, + .target_64bit = false, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, +- .per_ce_irq = false, + .shadow_reg_support = false, + .rri_on_ddr = false, + .hw_filter_reset_required = true, +@@ -531,7 +521,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .num_wds_entries = 0x20, + .target_64bit = false, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, +- .per_ce_irq = false, + .shadow_reg_support = false, + .rri_on_ddr = false, + .hw_filter_reset_required = true, +@@ -573,7 +562,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .num_wds_entries = 0x20, + .target_64bit = false, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, +- .per_ce_irq = false, + .shadow_reg_support = false, + .rri_on_ddr = false, + .hw_filter_reset_required = true, +@@ -601,7 +589,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { + .num_wds_entries = TARGET_HL_TLV_NUM_WDS_ENTRIES, + .target_64bit = true, + .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC, +- .per_ce_irq = true, + .shadow_reg_support = true, + .rri_on_ddr = true, + .hw_filter_reset_required = false, +diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h +index ae4c9edc445c3..705ab83cdff43 100644 +--- a/drivers/net/wireless/ath/ath10k/hw.h ++++ b/drivers/net/wireless/ath/ath10k/hw.h +@@ -590,9 +590,6 @@ struct ath10k_hw_params { + /* Target rx ring fill level */ + u32 rx_ring_fill_level; + +- /* target supporting per ce IRQ */ +- bool per_ce_irq; +- + /* target supporting shadow register for ce write */ + bool shadow_reg_support; + +diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c +index 29d52f7b4336d..e8700f0b23f76 100644 +--- a/drivers/net/wireless/ath/ath10k/snoc.c ++++ b/drivers/net/wireless/ath/ath10k/snoc.c +@@ -3,6 +3,7 @@ + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + */ + ++#include <linux/bits.h> + #include <linux/clk.h> + #include <linux/kernel.h> + #include <linux/module.h> +@@ -927,6 +928,7 @@ static int ath10k_snoc_hif_start(struct ath10k *ar) + { + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + ++ bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX); + napi_enable(&ar->napi); + ath10k_snoc_irq_enable(ar); + ath10k_snoc_rx_post(ar); +@@ -1166,7 +1168,9 @@ static irqreturn_t ath10k_snoc_per_engine_handler(int irq, void *arg) + return IRQ_HANDLED; + } + +- ath10k_snoc_irq_disable(ar); ++ ath10k_ce_disable_interrupt(ar, ce_id); ++ set_bit(ce_id, ar_snoc->pending_ce_irqs); ++ + napi_schedule(&ar->napi); + + return IRQ_HANDLED; +@@ -1175,20 +1179,25 @@ static irqreturn_t ath10k_snoc_per_engine_handler(int irq, void *arg) + static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget) + { + struct ath10k *ar = container_of(ctx, struct ath10k, napi); ++ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int done = 0; ++ int ce_id; + + if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) { + napi_complete(ctx); + return done; + } + +- ath10k_ce_per_engine_service_any(ar); ++ for (ce_id = 0; ce_id < CE_COUNT; ce_id++) ++ if (test_and_clear_bit(ce_id, ar_snoc->pending_ce_irqs)) { ++ ath10k_ce_per_engine_service(ar, ce_id); ++ ath10k_ce_enable_interrupt(ar, ce_id); ++ } ++ + done = ath10k_htt_txrx_compl_task(ar, budget); + +- if (done < budget) { ++ if (done < budget) + napi_complete(ctx); +- ath10k_snoc_irq_enable(ar); +- } + + return done; + } +diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h +index 9db823e46314d..d61ca374fdf6c 100644 +--- a/drivers/net/wireless/ath/ath10k/snoc.h ++++ b/drivers/net/wireless/ath/ath10k/snoc.h +@@ -81,6 +81,7 @@ struct ath10k_snoc { + struct ath10k_clk_info *clk; + struct ath10k_qmi *qmi; + unsigned long flags; ++ DECLARE_BITMAP(pending_ce_irqs, CE_COUNT_MAX); + }; + + static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 780223694c006..cc8f2ce1e8818 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5389,6 +5389,12 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0420, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0422, quirk_no_ext_tags); + + #ifdef CONFIG_PCI_ATS ++static void quirk_no_ats(struct pci_dev *pdev) ++{ ++ pci_info(pdev, "disabling ATS\n"); ++ pdev->ats_cap = 0; ++} ++ + /* + * Some devices require additional driver setup to enable ATS. Don't use + * ATS for those devices as ATS will be enabled before the driver has had a +@@ -5401,8 +5407,7 @@ static void quirk_amd_harvest_no_ats(struct pci_dev *pdev) + (pdev->device == 0x7341 && pdev->revision != 0x00)) + return; + +- pci_info(pdev, "disabling ATS\n"); +- pdev->ats_cap = 0; ++ quirk_no_ats(pdev); + } + + /* AMD Stoney platform GPU */ +@@ -5414,6 +5419,25 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7312, quirk_amd_harvest_no_ats); + /* AMD Navi14 dGPU */ + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7340, quirk_amd_harvest_no_ats); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7341, quirk_amd_harvest_no_ats); ++ ++/* ++ * Intel IPU E2000 revisions before C0 implement incorrect endianness ++ * in ATS Invalidate Request message body. Disable ATS for those devices. ++ */ ++static void quirk_intel_e2000_no_ats(struct pci_dev *pdev) ++{ ++ if (pdev->revision < 0x20) ++ quirk_no_ats(pdev); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1451, quirk_intel_e2000_no_ats); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1452, quirk_intel_e2000_no_ats); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1453, quirk_intel_e2000_no_ats); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1454, quirk_intel_e2000_no_ats); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1455, quirk_intel_e2000_no_ats); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1457, quirk_intel_e2000_no_ats); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1459, quirk_intel_e2000_no_ats); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x145a, quirk_intel_e2000_no_ats); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x145c, quirk_intel_e2000_no_ats); + #endif /* CONFIG_PCI_ATS */ + + /* Freescale PCIe doesn't support MSI in RC mode */ +diff --git a/include/net/dst_ops.h b/include/net/dst_ops.h +index 443863c7b8da3..632086b2f644a 100644 +--- a/include/net/dst_ops.h ++++ b/include/net/dst_ops.h +@@ -16,7 +16,7 @@ struct dst_ops { + unsigned short family; + unsigned int gc_thresh; + +- int (*gc)(struct dst_ops *ops); ++ void (*gc)(struct dst_ops *ops); + struct dst_entry * (*check)(struct dst_entry *, __u32 cookie); + unsigned int (*default_advmss)(const struct dst_entry *); + unsigned int (*mtu)(const struct dst_entry *); +@@ -53,9 +53,11 @@ static inline int dst_entries_get_slow(struct dst_ops *dst) + return percpu_counter_sum_positive(&dst->pcpuc_entries); + } + ++#define DST_PERCPU_COUNTER_BATCH 32 + static inline void dst_entries_add(struct dst_ops *dst, int val) + { +- percpu_counter_add(&dst->pcpuc_entries, val); ++ percpu_counter_add_batch(&dst->pcpuc_entries, val, ++ DST_PERCPU_COUNTER_BATCH); + } + + static inline int dst_entries_init(struct dst_ops *dst) +diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h +index 022a0fd1a5a46..bf9c23fac74fd 100644 +--- a/include/net/netns/ipv6.h ++++ b/include/net/netns/ipv6.h +@@ -78,8 +78,8 @@ struct netns_ipv6 { + struct dst_ops ip6_dst_ops; + rwlock_t fib6_walker_lock; + spinlock_t fib6_gc_lock; +- unsigned int ip6_rt_gc_expire; +- unsigned long ip6_rt_last_gc; ++ atomic_t ip6_rt_gc_expire; ++ unsigned long ip6_rt_last_gc; + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + unsigned int fib6_rules_require_fldissect; + bool fib6_has_custom_rules; +diff --git a/mm/memory-failure.c b/mm/memory-failure.c +index 9030ab0d9d975..c6453f9ffd4d9 100644 +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -986,7 +986,7 @@ static bool hwpoison_user_mappings(struct page *p, unsigned long pfn, + * This check implies we don't kill processes if their pages + * are in the swap cache early. Those are always late kills. + */ +- if (!page_mapped(hpage)) ++ if (!page_mapped(p)) + return true; + + if (PageKsm(p)) { +@@ -1030,10 +1030,10 @@ static bool hwpoison_user_mappings(struct page *p, unsigned long pfn, + if (kill) + collect_procs(hpage, &tokill, flags & MF_ACTION_REQUIRED); + +- unmap_success = try_to_unmap(hpage, ttu); ++ unmap_success = try_to_unmap(p, ttu); + if (!unmap_success) + pr_err("Memory failure: %#lx: failed to unmap page (mapcount=%d)\n", +- pfn, page_mapcount(hpage)); ++ pfn, page_mapcount(p)); + + /* + * try_to_unmap() might put mlocked page in lru cache, so call +diff --git a/mm/memory.c b/mm/memory.c +index d416e329442dc..d514f69d97179 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -2872,8 +2872,8 @@ void unmap_mapping_pages(struct address_space *mapping, pgoff_t start, + void unmap_mapping_range(struct address_space *mapping, + loff_t const holebegin, loff_t const holelen, int even_cows) + { +- pgoff_t hba = holebegin >> PAGE_SHIFT; +- pgoff_t hlen = (holelen + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ pgoff_t hba = (pgoff_t)(holebegin) >> PAGE_SHIFT; ++ pgoff_t hlen = ((pgoff_t)(holelen) + PAGE_SIZE - 1) >> PAGE_SHIFT; + + /* Check for overflow. */ + if (sizeof(holelen) > sizeof(hlen)) { +diff --git a/net/can/raw.c b/net/can/raw.c +index bb837019d1724..2f500d8a0af24 100644 +--- a/net/can/raw.c ++++ b/net/can/raw.c +@@ -770,6 +770,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) + { + struct sock *sk = sock->sk; + struct raw_sock *ro = raw_sk(sk); ++ struct sockcm_cookie sockc; + struct sk_buff *skb; + struct net_device *dev; + int ifindex; +@@ -815,11 +816,20 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) + if (err < 0) + goto free_skb; + +- skb_setup_tx_timestamp(skb, sk->sk_tsflags); ++ sockcm_init(&sockc, sk); ++ if (msg->msg_controllen) { ++ err = sock_cmsg_send(sk, msg, &sockc); ++ if (unlikely(err)) ++ goto free_skb; ++ } + + skb->dev = dev; + skb->sk = sk; + skb->priority = sk->sk_priority; ++ skb->mark = sk->sk_mark; ++ skb->tstamp = sockc.transmit_time; ++ ++ skb_setup_tx_timestamp(skb, sockc.tsflags); + + err = can_send(skb, ro->loopback); + +diff --git a/net/core/dst.c b/net/core/dst.c +index 193af526e908a..107aea25a5643 100644 +--- a/net/core/dst.c ++++ b/net/core/dst.c +@@ -81,14 +81,10 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev, + { + struct dst_entry *dst; + +- if (ops->gc && dst_entries_get_fast(ops) > ops->gc_thresh) { +- if (ops->gc(ops)) { +- printk_ratelimited(KERN_NOTICE "Route cache is full: " +- "consider increasing sysctl " +- "net.ipv[4|6].route.max_size.\n"); +- return NULL; +- } +- } ++ if (ops->gc && ++ !(flags & DST_NOCOUNT) && ++ dst_entries_get_fast(ops) > ops->gc_thresh) ++ ops->gc(ops); + + dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC); + if (!dst) +diff --git a/net/core/sock.c b/net/core/sock.c +index 2c3c5df139345..daeb0e69c71b4 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2303,6 +2303,7 @@ int __sock_cmsg_send(struct sock *sk, struct msghdr *msg, struct cmsghdr *cmsg, + sockc->mark = *(u32 *)CMSG_DATA(cmsg); + break; + case SO_TIMESTAMPING_OLD: ++ case SO_TIMESTAMPING_NEW: + if (cmsg->cmsg_len != CMSG_LEN(sizeof(u32))) + return -EINVAL; + +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index bf7c2333bc236..0f70c2dbbe5bb 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -993,7 +993,7 @@ static int __ip_append_data(struct sock *sk, + mtu = cork->gso_size ? IP_MAX_MTU : cork->fragsize; + paged = !!cork->gso_size; + +- if (cork->tx_flags & SKBTX_ANY_SW_TSTAMP && ++ if (cork->tx_flags & SKBTX_ANY_TSTAMP && + sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) + tskey = sk->sk_tskey++; + +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index d3455585e6a8c..c67d634dccd47 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1425,7 +1425,7 @@ static int __ip6_append_data(struct sock *sk, + mtu = cork->gso_size ? IP6_MAX_MTU : cork->fragsize; + orig_mtu = mtu; + +- if (cork->tx_flags & SKBTX_ANY_SW_TSTAMP && ++ if (cork->tx_flags & SKBTX_ANY_TSTAMP && + sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) + tskey = sk->sk_tskey++; + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 209d52ebbd199..c26e832fddb7d 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -88,7 +88,7 @@ static struct dst_entry *ip6_negative_advice(struct dst_entry *); + static void ip6_dst_destroy(struct dst_entry *); + static void ip6_dst_ifdown(struct dst_entry *, + struct net_device *dev, int how); +-static int ip6_dst_gc(struct dst_ops *ops); ++static void ip6_dst_gc(struct dst_ops *ops); + + static int ip6_pkt_discard(struct sk_buff *skb); + static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb); +@@ -3207,29 +3207,30 @@ out: + return dst; + } + +-static int ip6_dst_gc(struct dst_ops *ops) ++static void ip6_dst_gc(struct dst_ops *ops) + { + struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops); + int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval; +- int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size; + int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity; + int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout; + unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc; ++ unsigned int val; + int entries; + + entries = dst_entries_get_fast(ops); +- if (time_after(rt_last_gc + rt_min_interval, jiffies) && +- entries <= rt_max_size) ++ if (entries > ops->gc_thresh) ++ entries = dst_entries_get_slow(ops); ++ ++ if (time_after(rt_last_gc + rt_min_interval, jiffies)) + goto out; + +- net->ipv6.ip6_rt_gc_expire++; +- fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true); ++ fib6_run_gc(atomic_inc_return(&net->ipv6.ip6_rt_gc_expire), net, true); + entries = dst_entries_get_slow(ops); + if (entries < ops->gc_thresh) +- net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; ++ atomic_set(&net->ipv6.ip6_rt_gc_expire, rt_gc_timeout >> 1); + out: +- net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity; +- return entries > rt_max_size; ++ val = atomic_read(&net->ipv6.ip6_rt_gc_expire); ++ atomic_set(&net->ipv6.ip6_rt_gc_expire, val - (val >> rt_elasticity)); + } + + static int ip6_nh_lookup_table(struct net *net, struct fib6_config *cfg, +@@ -6317,7 +6318,7 @@ static int __net_init ip6_route_net_init(struct net *net) + #endif + + net->ipv6.sysctl.flush_delay = 0; +- net->ipv6.sysctl.ip6_rt_max_size = 4096; ++ net->ipv6.sysctl.ip6_rt_max_size = INT_MAX; + net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2; + net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ; + net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ; +@@ -6326,7 +6327,7 @@ static int __net_init ip6_route_net_init(struct net *net) + net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40; + net->ipv6.sysctl.skip_notify_on_dev_down = 0; + +- net->ipv6.ip6_rt_gc_expire = 30*HZ; ++ atomic_set(&net->ipv6.ip6_rt_gc_expire, 30*HZ); + + ret = 0; + out: +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 78be121f38ac6..915df77161e17 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -1005,6 +1005,30 @@ static int nft_objname_hash_cmp(struct rhashtable_compare_arg *arg, + return strcmp(obj->key.name, k->name); + } + ++static bool nft_supported_family(u8 family) ++{ ++ return false ++#ifdef CONFIG_NF_TABLES_INET ++ || family == NFPROTO_INET ++#endif ++#ifdef CONFIG_NF_TABLES_IPV4 ++ || family == NFPROTO_IPV4 ++#endif ++#ifdef CONFIG_NF_TABLES_ARP ++ || family == NFPROTO_ARP ++#endif ++#ifdef CONFIG_NF_TABLES_NETDEV ++ || family == NFPROTO_NETDEV ++#endif ++#if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE) ++ || family == NFPROTO_BRIDGE ++#endif ++#ifdef CONFIG_NF_TABLES_IPV6 ++ || family == NFPROTO_IPV6 ++#endif ++ ; ++} ++ + static int nf_tables_newtable(struct net *net, struct sock *nlsk, + struct sk_buff *skb, const struct nlmsghdr *nlh, + const struct nlattr * const nla[], +@@ -1020,6 +1044,9 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk, + struct nft_ctx ctx; + int err; + ++ if (!nft_supported_family(family)) ++ return -EOPNOTSUPP; ++ + lockdep_assert_held(&nft_net->commit_mutex); + attr = nla[NFTA_TABLE_NAME]; + table = nft_table_lookup(net, attr, family, genmask); +diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c +index 92f70686bee0a..da3cb0d29b972 100644 +--- a/net/nfc/llcp_core.c ++++ b/net/nfc/llcp_core.c +@@ -147,6 +147,13 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool device, + + static struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local) + { ++ /* Since using nfc_llcp_local may result in usage of nfc_dev, whenever ++ * we hold a reference to local, we also need to hold a reference to ++ * the device to avoid UAF. ++ */ ++ if (!nfc_get_device(local->dev->idx)) ++ return NULL; ++ + kref_get(&local->ref); + + return local; +@@ -179,10 +186,18 @@ static void local_release(struct kref *ref) + + int nfc_llcp_local_put(struct nfc_llcp_local *local) + { ++ struct nfc_dev *dev; ++ int ret; ++ + if (local == NULL) + return 0; + +- return kref_put(&local->ref, local_release); ++ dev = local->dev; ++ ++ ret = kref_put(&local->ref, local_release); ++ nfc_put_device(dev); ++ ++ return ret; + } + + static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, +@@ -968,8 +983,17 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, + } + + new_sock = nfc_llcp_sock(new_sk); +- new_sock->dev = local->dev; ++ + new_sock->local = nfc_llcp_local_get(local); ++ if (!new_sock->local) { ++ reason = LLCP_DM_REJ; ++ sock_put(&new_sock->sk); ++ release_sock(&sock->sk); ++ sock_put(&sock->sk); ++ goto fail; ++ } ++ ++ new_sock->dev = local->dev; + new_sock->rw = sock->rw; + new_sock->miux = sock->miux; + new_sock->nfc_protocol = sock->nfc_protocol; +@@ -1607,7 +1631,16 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) + if (local == NULL) + return -ENOMEM; + +- local->dev = ndev; ++ /* As we are going to initialize local's refcount, we need to get the ++ * nfc_dev to avoid UAF, otherwise there is no point in continuing. ++ * See nfc_llcp_local_get(). ++ */ ++ local->dev = nfc_get_device(ndev->idx); ++ if (!local->dev) { ++ kfree(local); ++ return -ENODEV; ++ } ++ + INIT_LIST_HEAD(&local->list); + kref_init(&local->ref); + mutex_init(&local->sdp_lock); +diff --git a/net/sched/em_text.c b/net/sched/em_text.c +index 6f3c1fb2fb44c..f176afb70559e 100644 +--- a/net/sched/em_text.c ++++ b/net/sched/em_text.c +@@ -97,8 +97,10 @@ retry: + + static void em_text_destroy(struct tcf_ematch *m) + { +- if (EM_TEXT_PRIV(m) && EM_TEXT_PRIV(m)->config) ++ if (EM_TEXT_PRIV(m) && EM_TEXT_PRIV(m)->config) { + textsearch_destroy(EM_TEXT_PRIV(m)->config); ++ kfree(EM_TEXT_PRIV(m)); ++ } + } + + static int em_text_dump(struct sk_buff *skb, struct tcf_ematch *m) +diff --git a/net/socket.c b/net/socket.c +index 38c26e20511d7..e3a50f107d64d 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -661,6 +661,7 @@ int sock_sendmsg(struct socket *sock, struct msghdr *msg) + { + struct sockaddr_storage *save_addr = (struct sockaddr_storage *)msg->msg_name; + struct sockaddr_storage address; ++ int save_len = msg->msg_namelen; + int ret; + + if (msg->msg_name) { +@@ -670,6 +671,7 @@ int sock_sendmsg(struct socket *sock, struct msghdr *msg) + + ret = __sock_sendmsg(sock, msg); + msg->msg_name = save_addr; ++ msg->msg_namelen = save_len; + + return ret; + } +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index 62bc7e5c58e53..38592d0871a3f 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -1211,6 +1211,8 @@ alloc_payload: + } + + sk_msg_page_add(msg_pl, page, copy, offset); ++ msg_pl->sg.copybreak = 0; ++ msg_pl->sg.curr = msg_pl->sg.end; + sk_mem_charge(sk, copy); + + offset += copy; +diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig +index e0d24592ebd70..f9188274f6b0f 100644 +--- a/sound/soc/meson/Kconfig ++++ b/sound/soc/meson/Kconfig +@@ -85,9 +85,13 @@ config SND_MESON_AXG_PDM + Select Y or M to add support for PDM input embedded + in the Amlogic AXG SoC family + ++config SND_MESON_CODEC_GLUE ++ tristate ++ + config SND_MESON_G12A_TOHDMITX + tristate "Amlogic G12A To HDMI TX Control Support" + select REGMAP_MMIO ++ select SND_MESON_CODEC_GLUE + imply SND_SOC_HDMI_CODEC + help + Select Y or M to add support for HDMI audio on the g12a SoC +diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile +index 1a8b1470ed843..529a807b3f376 100644 +--- a/sound/soc/meson/Makefile ++++ b/sound/soc/meson/Makefile +@@ -11,6 +11,7 @@ snd-soc-meson-axg-sound-card-objs := axg-card.o + snd-soc-meson-axg-spdifin-objs := axg-spdifin.o + snd-soc-meson-axg-spdifout-objs := axg-spdifout.o + snd-soc-meson-axg-pdm-objs := axg-pdm.o ++snd-soc-meson-codec-glue-objs := meson-codec-glue.o + snd-soc-meson-g12a-tohdmitx-objs := g12a-tohdmitx.o + + obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o +@@ -24,4 +25,5 @@ obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o + obj-$(CONFIG_SND_MESON_AXG_SPDIFIN) += snd-soc-meson-axg-spdifin.o + obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o + obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o ++obj-$(CONFIG_SND_MESON_CODEC_GLUE) += snd-soc-meson-codec-glue.o + obj-$(CONFIG_SND_MESON_G12A_TOHDMITX) += snd-soc-meson-g12a-tohdmitx.o +diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c +index cbe47e0cae426..c875c350be070 100644 +--- a/sound/soc/meson/g12a-tohdmitx.c ++++ b/sound/soc/meson/g12a-tohdmitx.c +@@ -12,112 +12,54 @@ + #include <sound/soc-dai.h> + + #include <dt-bindings/sound/meson-g12a-tohdmitx.h> ++#include "meson-codec-glue.h" + + #define G12A_TOHDMITX_DRV_NAME "g12a-tohdmitx" + + #define TOHDMITX_CTRL0 0x0 + #define CTRL0_ENABLE_SHIFT 31 +-#define CTRL0_I2S_DAT_SEL GENMASK(13, 12) ++#define CTRL0_I2S_DAT_SEL_SHIFT 12 ++#define CTRL0_I2S_DAT_SEL (0x3 << CTRL0_I2S_DAT_SEL_SHIFT) + #define CTRL0_I2S_LRCLK_SEL GENMASK(9, 8) + #define CTRL0_I2S_BLK_CAP_INV BIT(7) + #define CTRL0_I2S_BCLK_O_INV BIT(6) + #define CTRL0_I2S_BCLK_SEL GENMASK(5, 4) + #define CTRL0_SPDIF_CLK_CAP_INV BIT(3) + #define CTRL0_SPDIF_CLK_O_INV BIT(2) +-#define CTRL0_SPDIF_SEL BIT(1) ++#define CTRL0_SPDIF_SEL_SHIFT 1 ++#define CTRL0_SPDIF_SEL (0x1 << CTRL0_SPDIF_SEL_SHIFT) + #define CTRL0_SPDIF_CLK_SEL BIT(0) + +-struct g12a_tohdmitx_input { +- struct snd_soc_pcm_stream params; +- unsigned int fmt; +-}; +- +-static struct snd_soc_dapm_widget * +-g12a_tohdmitx_get_input(struct snd_soc_dapm_widget *w) +-{ +- struct snd_soc_dapm_path *p = NULL; +- struct snd_soc_dapm_widget *in; +- +- snd_soc_dapm_widget_for_each_source_path(w, p) { +- if (!p->connect) +- continue; +- +- /* Check that we still are in the same component */ +- if (snd_soc_dapm_to_component(w->dapm) != +- snd_soc_dapm_to_component(p->source->dapm)) +- continue; +- +- if (p->source->id == snd_soc_dapm_dai_in) +- return p->source; +- +- in = g12a_tohdmitx_get_input(p->source); +- if (in) +- return in; +- } +- +- return NULL; +-} +- +-static struct g12a_tohdmitx_input * +-g12a_tohdmitx_get_input_data(struct snd_soc_dapm_widget *w) +-{ +- struct snd_soc_dapm_widget *in = +- g12a_tohdmitx_get_input(w); +- struct snd_soc_dai *dai; +- +- if (WARN_ON(!in)) +- return NULL; +- +- dai = in->priv; +- +- return dai->playback_dma_data; +-} +- + static const char * const g12a_tohdmitx_i2s_mux_texts[] = { + "I2S A", "I2S B", "I2S C", + }; + +-static SOC_ENUM_SINGLE_EXT_DECL(g12a_tohdmitx_i2s_mux_enum, +- g12a_tohdmitx_i2s_mux_texts); +- +-static int g12a_tohdmitx_get_input_val(struct snd_soc_component *component, +- unsigned int mask) +-{ +- unsigned int val; +- +- snd_soc_component_read(component, TOHDMITX_CTRL0, &val); +- return (val & mask) >> __ffs(mask); +-} +- +-static int g12a_tohdmitx_i2s_mux_get_enum(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) +-{ +- struct snd_soc_component *component = +- snd_soc_dapm_kcontrol_component(kcontrol); +- +- ucontrol->value.enumerated.item[0] = +- g12a_tohdmitx_get_input_val(component, CTRL0_I2S_DAT_SEL); +- +- return 0; +-} +- + static int g12a_tohdmitx_i2s_mux_put_enum(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) ++ struct snd_ctl_elem_value *ucontrol) + { + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; +- unsigned int mux = ucontrol->value.enumerated.item[0]; +- unsigned int val = g12a_tohdmitx_get_input_val(component, +- CTRL0_I2S_DAT_SEL); ++ unsigned int mux, changed; ++ ++ if (ucontrol->value.enumerated.item[0] >= e->items) ++ return -EINVAL; ++ ++ mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]); ++ changed = snd_soc_component_test_bits(component, e->reg, ++ CTRL0_I2S_DAT_SEL, ++ FIELD_PREP(CTRL0_I2S_DAT_SEL, ++ mux)); ++ ++ if (!changed) ++ return 0; + + /* Force disconnect of the mux while updating */ +- if (val != mux) +- snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL); ++ snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL); + +- snd_soc_component_update_bits(component, TOHDMITX_CTRL0, ++ snd_soc_component_update_bits(component, e->reg, + CTRL0_I2S_DAT_SEL | + CTRL0_I2S_LRCLK_SEL | + CTRL0_I2S_BCLK_SEL, +@@ -130,30 +72,19 @@ static int g12a_tohdmitx_i2s_mux_put_enum(struct snd_kcontrol *kcontrol, + return 1; + } + ++static SOC_ENUM_SINGLE_DECL(g12a_tohdmitx_i2s_mux_enum, TOHDMITX_CTRL0, ++ CTRL0_I2S_DAT_SEL_SHIFT, ++ g12a_tohdmitx_i2s_mux_texts); ++ + static const struct snd_kcontrol_new g12a_tohdmitx_i2s_mux = + SOC_DAPM_ENUM_EXT("I2S Source", g12a_tohdmitx_i2s_mux_enum, +- g12a_tohdmitx_i2s_mux_get_enum, ++ snd_soc_dapm_get_enum_double, + g12a_tohdmitx_i2s_mux_put_enum); + + static const char * const g12a_tohdmitx_spdif_mux_texts[] = { + "SPDIF A", "SPDIF B", + }; + +-static SOC_ENUM_SINGLE_EXT_DECL(g12a_tohdmitx_spdif_mux_enum, +- g12a_tohdmitx_spdif_mux_texts); +- +-static int g12a_tohdmitx_spdif_mux_get_enum(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) +-{ +- struct snd_soc_component *component = +- snd_soc_dapm_kcontrol_component(kcontrol); +- +- ucontrol->value.enumerated.item[0] = +- g12a_tohdmitx_get_input_val(component, CTRL0_SPDIF_SEL); +- +- return 0; +-} +- + static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { +@@ -162,13 +93,21 @@ static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol, + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; +- unsigned int mux = ucontrol->value.enumerated.item[0]; +- unsigned int val = g12a_tohdmitx_get_input_val(component, +- CTRL0_SPDIF_SEL); ++ unsigned int mux, changed; ++ ++ if (ucontrol->value.enumerated.item[0] >= e->items) ++ return -EINVAL; ++ ++ mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]); ++ changed = snd_soc_component_test_bits(component, TOHDMITX_CTRL0, ++ CTRL0_SPDIF_SEL, ++ FIELD_PREP(CTRL0_SPDIF_SEL, mux)); ++ ++ if (!changed) ++ return 0; + + /* Force disconnect of the mux while updating */ +- if (val != mux) +- snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL); ++ snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL); + + snd_soc_component_update_bits(component, TOHDMITX_CTRL0, + CTRL0_SPDIF_SEL | +@@ -178,12 +117,16 @@ static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol, + + snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); + +- return 0; ++ return 1; + } + ++static SOC_ENUM_SINGLE_DECL(g12a_tohdmitx_spdif_mux_enum, TOHDMITX_CTRL0, ++ CTRL0_SPDIF_SEL_SHIFT, ++ g12a_tohdmitx_spdif_mux_texts); ++ + static const struct snd_kcontrol_new g12a_tohdmitx_spdif_mux = + SOC_DAPM_ENUM_EXT("SPDIF Source", g12a_tohdmitx_spdif_mux_enum, +- g12a_tohdmitx_spdif_mux_get_enum, ++ snd_soc_dapm_get_enum_double, + g12a_tohdmitx_spdif_mux_put_enum); + + static const struct snd_kcontrol_new g12a_tohdmitx_out_enable = +@@ -201,83 +144,13 @@ static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = { + &g12a_tohdmitx_out_enable), + }; + +-static int g12a_tohdmitx_input_probe(struct snd_soc_dai *dai) +-{ +- struct g12a_tohdmitx_input *data; +- +- data = kzalloc(sizeof(*data), GFP_KERNEL); +- if (!data) +- return -ENOMEM; +- +- dai->playback_dma_data = data; +- return 0; +-} +- +-static int g12a_tohdmitx_input_remove(struct snd_soc_dai *dai) +-{ +- kfree(dai->playback_dma_data); +- return 0; +-} +- +-static int g12a_tohdmitx_input_hw_params(struct snd_pcm_substream *substream, +- struct snd_pcm_hw_params *params, +- struct snd_soc_dai *dai) +-{ +- struct g12a_tohdmitx_input *data = dai->playback_dma_data; +- +- data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params)); +- data->params.rate_min = params_rate(params); +- data->params.rate_max = params_rate(params); +- data->params.formats = 1 << params_format(params); +- data->params.channels_min = params_channels(params); +- data->params.channels_max = params_channels(params); +- data->params.sig_bits = dai->driver->playback.sig_bits; +- +- return 0; +-} +- +- +-static int g12a_tohdmitx_input_set_fmt(struct snd_soc_dai *dai, +- unsigned int fmt) +-{ +- struct g12a_tohdmitx_input *data = dai->playback_dma_data; +- +- /* Save the source stream format for the downstream link */ +- data->fmt = fmt; +- return 0; +-} +- +-static int g12a_tohdmitx_output_startup(struct snd_pcm_substream *substream, +- struct snd_soc_dai *dai) +-{ +- struct snd_soc_pcm_runtime *rtd = substream->private_data; +- struct g12a_tohdmitx_input *in_data = +- g12a_tohdmitx_get_input_data(dai->capture_widget); +- +- if (!in_data) +- return -ENODEV; +- +- if (WARN_ON(!rtd->dai_link->params)) { +- dev_warn(dai->dev, "codec2codec link expected\n"); +- return -EINVAL; +- } +- +- /* Replace link params with the input params */ +- rtd->dai_link->params = &in_data->params; +- +- if (!in_data->fmt) +- return 0; +- +- return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt); +-} +- + static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = { +- .hw_params = g12a_tohdmitx_input_hw_params, +- .set_fmt = g12a_tohdmitx_input_set_fmt, ++ .hw_params = meson_codec_glue_input_hw_params, ++ .set_fmt = meson_codec_glue_input_set_fmt, + }; + + static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = { +- .startup = g12a_tohdmitx_output_startup, ++ .startup = meson_codec_glue_output_startup, + }; + + #define TOHDMITX_SPDIF_FORMATS \ +@@ -304,8 +177,8 @@ static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = { + .id = (xid), \ + .playback = TOHDMITX_STREAM(xname, "Playback", xfmt, xchmax), \ + .ops = &g12a_tohdmitx_input_ops, \ +- .probe = g12a_tohdmitx_input_probe, \ +- .remove = g12a_tohdmitx_input_remove, \ ++ .probe = meson_codec_glue_input_dai_probe, \ ++ .remove = meson_codec_glue_input_dai_remove, \ + } + + #define TOHDMITX_OUT(xname, xid, xfmt, xchmax) { \ +diff --git a/sound/soc/meson/meson-codec-glue.c b/sound/soc/meson/meson-codec-glue.c +new file mode 100644 +index 0000000000000..524a334723373 +--- /dev/null ++++ b/sound/soc/meson/meson-codec-glue.c +@@ -0,0 +1,149 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// ++// Copyright (c) 2019 BayLibre, SAS. ++// Author: Jerome Brunet <[email protected]> ++ ++#include <linux/module.h> ++#include <sound/pcm_params.h> ++#include <sound/soc.h> ++#include <sound/soc-dai.h> ++ ++#include "meson-codec-glue.h" ++ ++static struct snd_soc_dapm_widget * ++meson_codec_glue_get_input(struct snd_soc_dapm_widget *w) ++{ ++ struct snd_soc_dapm_path *p = NULL; ++ struct snd_soc_dapm_widget *in; ++ ++ snd_soc_dapm_widget_for_each_source_path(w, p) { ++ if (!p->connect) ++ continue; ++ ++ /* Check that we still are in the same component */ ++ if (snd_soc_dapm_to_component(w->dapm) != ++ snd_soc_dapm_to_component(p->source->dapm)) ++ continue; ++ ++ if (p->source->id == snd_soc_dapm_dai_in) ++ return p->source; ++ ++ in = meson_codec_glue_get_input(p->source); ++ if (in) ++ return in; ++ } ++ ++ return NULL; ++} ++ ++static void meson_codec_glue_input_set_data(struct snd_soc_dai *dai, ++ struct meson_codec_glue_input *data) ++{ ++ dai->playback_dma_data = data; ++} ++ ++struct meson_codec_glue_input * ++meson_codec_glue_input_get_data(struct snd_soc_dai *dai) ++{ ++ return dai->playback_dma_data; ++} ++EXPORT_SYMBOL_GPL(meson_codec_glue_input_get_data); ++ ++static struct meson_codec_glue_input * ++meson_codec_glue_output_get_input_data(struct snd_soc_dapm_widget *w) ++{ ++ struct snd_soc_dapm_widget *in = ++ meson_codec_glue_get_input(w); ++ struct snd_soc_dai *dai; ++ ++ if (WARN_ON(!in)) ++ return NULL; ++ ++ dai = in->priv; ++ ++ return meson_codec_glue_input_get_data(dai); ++} ++ ++int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_codec_glue_input *data = ++ meson_codec_glue_input_get_data(dai); ++ ++ data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params)); ++ data->params.rate_min = params_rate(params); ++ data->params.rate_max = params_rate(params); ++ data->params.formats = 1ULL << (__force int) params_format(params); ++ data->params.channels_min = params_channels(params); ++ data->params.channels_max = params_channels(params); ++ data->params.sig_bits = dai->driver->playback.sig_bits; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(meson_codec_glue_input_hw_params); ++ ++int meson_codec_glue_input_set_fmt(struct snd_soc_dai *dai, ++ unsigned int fmt) ++{ ++ struct meson_codec_glue_input *data = ++ meson_codec_glue_input_get_data(dai); ++ ++ /* Save the source stream format for the downstream link */ ++ data->fmt = fmt; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(meson_codec_glue_input_set_fmt); ++ ++int meson_codec_glue_output_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct meson_codec_glue_input *in_data = ++ meson_codec_glue_output_get_input_data(dai->capture_widget); ++ ++ if (!in_data) ++ return -ENODEV; ++ ++ if (WARN_ON(!rtd->dai_link->params)) { ++ dev_warn(dai->dev, "codec2codec link expected\n"); ++ return -EINVAL; ++ } ++ ++ /* Replace link params with the input params */ ++ rtd->dai_link->params = &in_data->params; ++ ++ if (!in_data->fmt) ++ return 0; ++ ++ return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt); ++} ++EXPORT_SYMBOL_GPL(meson_codec_glue_output_startup); ++ ++int meson_codec_glue_input_dai_probe(struct snd_soc_dai *dai) ++{ ++ struct meson_codec_glue_input *data; ++ ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ meson_codec_glue_input_set_data(dai, data); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_probe); ++ ++int meson_codec_glue_input_dai_remove(struct snd_soc_dai *dai) ++{ ++ struct meson_codec_glue_input *data = ++ meson_codec_glue_input_get_data(dai); ++ ++ kfree(data); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_remove); ++ ++MODULE_AUTHOR("Jerome Brunet <[email protected]>"); ++MODULE_DESCRIPTION("Amlogic Codec Glue Helpers"); ++MODULE_LICENSE("GPL v2"); ++ +diff --git a/sound/soc/meson/meson-codec-glue.h b/sound/soc/meson/meson-codec-glue.h +new file mode 100644 +index 0000000000000..07f99446c0c6b +--- /dev/null ++++ b/sound/soc/meson/meson-codec-glue.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 ++ * ++ * Copyright (c) 2018 Baylibre SAS. ++ * Author: Jerome Brunet <[email protected]> ++ */ ++ ++#ifndef _MESON_CODEC_GLUE_H ++#define _MESON_CODEC_GLUE_H ++ ++#include <sound/soc.h> ++ ++struct meson_codec_glue_input { ++ struct snd_soc_pcm_stream params; ++ unsigned int fmt; ++}; ++ ++/* Input helpers */ ++struct meson_codec_glue_input * ++meson_codec_glue_input_get_data(struct snd_soc_dai *dai); ++int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai); ++int meson_codec_glue_input_set_fmt(struct snd_soc_dai *dai, ++ unsigned int fmt); ++int meson_codec_glue_input_dai_probe(struct snd_soc_dai *dai); ++int meson_codec_glue_input_dai_remove(struct snd_soc_dai *dai); ++ ++/* Output helpers */ ++int meson_codec_glue_output_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai); ++ ++#endif /* _MESON_CODEC_GLUE_H */
