commit: 6d617305feb21ff027697aa0e5fcc277b67b23b3 Author: Mike Pagano <mpagano <AT> gentoo <DOT> org> AuthorDate: Wed Jun 14 10:19:54 2023 +0000 Commit: Mike Pagano <mpagano <AT> gentoo <DOT> org> CommitDate: Wed Jun 14 10:19:54 2023 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=6d617305
Linux patch 5.10.184 Signed-off-by: Mike Pagano <mpagano <AT> gentoo.org> 0000_README | 4 + 1183_linux-5.10.184.patch | 4008 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 4012 insertions(+) diff --git a/0000_README b/0000_README index 3ea4f952..3b319458 100644 --- a/0000_README +++ b/0000_README @@ -775,6 +775,10 @@ Patch: 1182_linux-5.10.183.patch From: https://www.kernel.org Desc: Linux 5.10.183 +Patch: 1183_linux-5.10.184.patch +From: https://www.kernel.org +Desc: Linux 5.10.184 + 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/1183_linux-5.10.184.patch b/1183_linux-5.10.184.patch new file mode 100644 index 00000000..ad847cfe --- /dev/null +++ b/1183_linux-5.10.184.patch @@ -0,0 +1,4008 @@ +diff --git a/Makefile b/Makefile +index 28115681fffda..3450b061e8d69 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 5 + PATCHLEVEL = 10 +-SUBLEVEL = 183 ++SUBLEVEL = 184 + EXTRAVERSION = + NAME = Dare mighty things + +diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h +index 27ad767915390..fd0e09033a7c3 100644 +--- a/arch/mips/include/asm/atomic.h ++++ b/arch/mips/include/asm/atomic.h +@@ -203,7 +203,7 @@ ATOMIC_OPS(atomic64, xor, s64, ^=, xor, lld, scd) + * The function returns the old value of @v minus @i. + */ + #define ATOMIC_SIP_OP(pfx, type, op, ll, sc) \ +-static __inline__ int pfx##_sub_if_positive(type i, pfx##_t * v) \ ++static __inline__ type pfx##_sub_if_positive(type i, pfx##_t * v) \ + { \ + type temp, result; \ + \ +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index c192bd7305dc6..b28fabfc91bf7 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -22,6 +22,7 @@ config RISCV + select ARCH_HAS_GIGANTIC_PAGE + select ARCH_HAS_KCOV + select ARCH_HAS_MMIOWB ++ select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE + select ARCH_HAS_PTE_SPECIAL + select ARCH_HAS_SET_DIRECT_MAP + select ARCH_HAS_SET_MEMORY +diff --git a/block/blk-iocost.c b/block/blk-iocost.c +index 9255b642d6adb..105ad23dff063 100644 +--- a/block/blk-iocost.c ++++ b/block/blk-iocost.c +@@ -232,7 +232,9 @@ enum { + + /* 1/64k is granular enough and can easily be handled w/ u32 */ + WEIGHT_ONE = 1 << 16, ++}; + ++enum { + /* + * As vtime is used to calculate the cost of each IO, it needs to + * be fairly high precision. For example, it should be able to +@@ -256,6 +258,11 @@ enum { + VRATE_MIN = VTIME_PER_USEC * VRATE_MIN_PPM / MILLION, + VRATE_CLAMP_ADJ_PCT = 4, + ++ /* switch iff the conditions are met for longer than this */ ++ AUTOP_CYCLE_NSEC = 10LLU * NSEC_PER_SEC, ++}; ++ ++enum { + /* if IOs end up waiting for requests, issue less */ + RQ_WAIT_BUSY_PCT = 5, + +@@ -294,9 +301,6 @@ enum { + /* don't let cmds which take a very long time pin lagging for too long */ + MAX_LAGGING_PERIODS = 10, + +- /* switch iff the conditions are met for longer than this */ +- AUTOP_CYCLE_NSEC = 10LLU * NSEC_PER_SEC, +- + /* + * Count IO size in 4k pages. The 12bit shift helps keeping + * size-proportional components of cost calculation in closer +diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h +index 1ce8973569933..7cc6feb17e972 100644 +--- a/drivers/ata/ahci.h ++++ b/drivers/ata/ahci.h +@@ -24,6 +24,7 @@ + #include <linux/libata.h> + #include <linux/phy/phy.h> + #include <linux/regulator/consumer.h> ++#include <linux/bits.h> + + /* Enclosure Management Control */ + #define EM_CTRL_MSG_TYPE 0x000f0000 +@@ -54,12 +55,12 @@ enum { + AHCI_PORT_PRIV_FBS_DMA_SZ = AHCI_CMD_SLOT_SZ + + AHCI_CMD_TBL_AR_SZ + + (AHCI_RX_FIS_SZ * 16), +- AHCI_IRQ_ON_SG = (1 << 31), +- AHCI_CMD_ATAPI = (1 << 5), +- AHCI_CMD_WRITE = (1 << 6), +- AHCI_CMD_PREFETCH = (1 << 7), +- AHCI_CMD_RESET = (1 << 8), +- AHCI_CMD_CLR_BUSY = (1 << 10), ++ AHCI_IRQ_ON_SG = BIT(31), ++ AHCI_CMD_ATAPI = BIT(5), ++ AHCI_CMD_WRITE = BIT(6), ++ AHCI_CMD_PREFETCH = BIT(7), ++ AHCI_CMD_RESET = BIT(8), ++ AHCI_CMD_CLR_BUSY = BIT(10), + + RX_FIS_PIO_SETUP = 0x20, /* offset of PIO Setup FIS data */ + RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ +@@ -77,37 +78,37 @@ enum { + HOST_CAP2 = 0x24, /* host capabilities, extended */ + + /* HOST_CTL bits */ +- HOST_RESET = (1 << 0), /* reset controller; self-clear */ +- HOST_IRQ_EN = (1 << 1), /* global IRQ enable */ +- HOST_MRSM = (1 << 2), /* MSI Revert to Single Message */ +- HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ ++ HOST_RESET = BIT(0), /* reset controller; self-clear */ ++ HOST_IRQ_EN = BIT(1), /* global IRQ enable */ ++ HOST_MRSM = BIT(2), /* MSI Revert to Single Message */ ++ HOST_AHCI_EN = BIT(31), /* AHCI enabled */ + + /* HOST_CAP bits */ +- HOST_CAP_SXS = (1 << 5), /* Supports External SATA */ +- HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */ +- HOST_CAP_CCC = (1 << 7), /* Command Completion Coalescing */ +- HOST_CAP_PART = (1 << 13), /* Partial state capable */ +- HOST_CAP_SSC = (1 << 14), /* Slumber state capable */ +- HOST_CAP_PIO_MULTI = (1 << 15), /* PIO multiple DRQ support */ +- HOST_CAP_FBS = (1 << 16), /* FIS-based switching support */ +- HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ +- HOST_CAP_ONLY = (1 << 18), /* Supports AHCI mode only */ +- HOST_CAP_CLO = (1 << 24), /* Command List Override support */ +- HOST_CAP_LED = (1 << 25), /* Supports activity LED */ +- HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */ +- HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ +- HOST_CAP_MPS = (1 << 28), /* Mechanical presence switch */ +- HOST_CAP_SNTF = (1 << 29), /* SNotification register */ +- HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ +- HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ ++ HOST_CAP_SXS = BIT(5), /* Supports External SATA */ ++ HOST_CAP_EMS = BIT(6), /* Enclosure Management support */ ++ HOST_CAP_CCC = BIT(7), /* Command Completion Coalescing */ ++ HOST_CAP_PART = BIT(13), /* Partial state capable */ ++ HOST_CAP_SSC = BIT(14), /* Slumber state capable */ ++ HOST_CAP_PIO_MULTI = BIT(15), /* PIO multiple DRQ support */ ++ HOST_CAP_FBS = BIT(16), /* FIS-based switching support */ ++ HOST_CAP_PMP = BIT(17), /* Port Multiplier support */ ++ HOST_CAP_ONLY = BIT(18), /* Supports AHCI mode only */ ++ HOST_CAP_CLO = BIT(24), /* Command List Override support */ ++ HOST_CAP_LED = BIT(25), /* Supports activity LED */ ++ HOST_CAP_ALPM = BIT(26), /* Aggressive Link PM support */ ++ HOST_CAP_SSS = BIT(27), /* Staggered Spin-up */ ++ HOST_CAP_MPS = BIT(28), /* Mechanical presence switch */ ++ HOST_CAP_SNTF = BIT(29), /* SNotification register */ ++ HOST_CAP_NCQ = BIT(30), /* Native Command Queueing */ ++ HOST_CAP_64 = BIT(31), /* PCI DAC (64-bit DMA) support */ + + /* HOST_CAP2 bits */ +- HOST_CAP2_BOH = (1 << 0), /* BIOS/OS handoff supported */ +- HOST_CAP2_NVMHCI = (1 << 1), /* NVMHCI supported */ +- HOST_CAP2_APST = (1 << 2), /* Automatic partial to slumber */ +- HOST_CAP2_SDS = (1 << 3), /* Support device sleep */ +- HOST_CAP2_SADM = (1 << 4), /* Support aggressive DevSlp */ +- HOST_CAP2_DESO = (1 << 5), /* DevSlp from slumber only */ ++ HOST_CAP2_BOH = BIT(0), /* BIOS/OS handoff supported */ ++ HOST_CAP2_NVMHCI = BIT(1), /* NVMHCI supported */ ++ HOST_CAP2_APST = BIT(2), /* Automatic partial to slumber */ ++ HOST_CAP2_SDS = BIT(3), /* Support device sleep */ ++ HOST_CAP2_SADM = BIT(4), /* Support aggressive DevSlp */ ++ HOST_CAP2_DESO = BIT(5), /* DevSlp from slumber only */ + + /* registers for each SATA port */ + PORT_LST_ADDR = 0x00, /* command list DMA addr */ +@@ -129,24 +130,24 @@ enum { + PORT_DEVSLP = 0x44, /* device sleep */ + + /* PORT_IRQ_{STAT,MASK} bits */ +- PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ +- PORT_IRQ_TF_ERR = (1 << 30), /* task file error */ +- PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */ +- PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */ +- PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */ +- PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */ +- PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */ +- PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */ +- +- PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */ +- PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */ +- PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */ +- PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */ +- PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */ +- PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */ +- PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */ +- PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ +- PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ ++ PORT_IRQ_COLD_PRES = BIT(31), /* cold presence detect */ ++ PORT_IRQ_TF_ERR = BIT(30), /* task file error */ ++ PORT_IRQ_HBUS_ERR = BIT(29), /* host bus fatal error */ ++ PORT_IRQ_HBUS_DATA_ERR = BIT(28), /* host bus data error */ ++ PORT_IRQ_IF_ERR = BIT(27), /* interface fatal error */ ++ PORT_IRQ_IF_NONFATAL = BIT(26), /* interface non-fatal error */ ++ PORT_IRQ_OVERFLOW = BIT(24), /* xfer exhausted available S/G */ ++ PORT_IRQ_BAD_PMP = BIT(23), /* incorrect port multiplier */ ++ ++ PORT_IRQ_PHYRDY = BIT(22), /* PhyRdy changed */ ++ PORT_IRQ_DEV_ILCK = BIT(7), /* device interlock */ ++ PORT_IRQ_CONNECT = BIT(6), /* port connect change status */ ++ PORT_IRQ_SG_DONE = BIT(5), /* descriptor processed */ ++ PORT_IRQ_UNK_FIS = BIT(4), /* unknown FIS rx'd */ ++ PORT_IRQ_SDB_FIS = BIT(3), /* Set Device Bits FIS rx'd */ ++ PORT_IRQ_DMAS_FIS = BIT(2), /* DMA Setup FIS rx'd */ ++ PORT_IRQ_PIOS_FIS = BIT(1), /* PIO Setup FIS rx'd */ ++ PORT_IRQ_D2H_REG_FIS = BIT(0), /* D2H Register FIS rx'd */ + + PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | + PORT_IRQ_IF_ERR | +@@ -162,34 +163,34 @@ enum { + PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, + + /* PORT_CMD bits */ +- PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */ +- PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */ +- PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ +- PORT_CMD_FBSCP = (1 << 22), /* FBS Capable Port */ +- PORT_CMD_ESP = (1 << 21), /* External Sata Port */ +- PORT_CMD_HPCP = (1 << 18), /* HotPlug Capable Port */ +- PORT_CMD_PMP = (1 << 17), /* PMP attached */ +- PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ +- PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ +- PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ +- PORT_CMD_CLO = (1 << 3), /* Command list override */ +- PORT_CMD_POWER_ON = (1 << 2), /* Power up device */ +- PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ +- PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ +- +- PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */ +- PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ +- PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ +- PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ ++ PORT_CMD_ASP = BIT(27), /* Aggressive Slumber/Partial */ ++ PORT_CMD_ALPE = BIT(26), /* Aggressive Link PM enable */ ++ PORT_CMD_ATAPI = BIT(24), /* Device is ATAPI */ ++ PORT_CMD_FBSCP = BIT(22), /* FBS Capable Port */ ++ PORT_CMD_ESP = BIT(21), /* External Sata Port */ ++ PORT_CMD_HPCP = BIT(18), /* HotPlug Capable Port */ ++ PORT_CMD_PMP = BIT(17), /* PMP attached */ ++ PORT_CMD_LIST_ON = BIT(15), /* cmd list DMA engine running */ ++ PORT_CMD_FIS_ON = BIT(14), /* FIS DMA engine running */ ++ PORT_CMD_FIS_RX = BIT(4), /* Enable FIS receive DMA engine */ ++ PORT_CMD_CLO = BIT(3), /* Command list override */ ++ PORT_CMD_POWER_ON = BIT(2), /* Power up device */ ++ PORT_CMD_SPIN_UP = BIT(1), /* Spin up device */ ++ PORT_CMD_START = BIT(0), /* Enable port DMA engine */ ++ ++ PORT_CMD_ICC_MASK = (0xfu << 28), /* i/f ICC state mask */ ++ PORT_CMD_ICC_ACTIVE = (0x1u << 28), /* Put i/f in active state */ ++ PORT_CMD_ICC_PARTIAL = (0x2u << 28), /* Put i/f in partial state */ ++ PORT_CMD_ICC_SLUMBER = (0x6u << 28), /* Put i/f in slumber state */ + + /* PORT_FBS bits */ + PORT_FBS_DWE_OFFSET = 16, /* FBS device with error offset */ + PORT_FBS_ADO_OFFSET = 12, /* FBS active dev optimization offset */ + PORT_FBS_DEV_OFFSET = 8, /* FBS device to issue offset */ + PORT_FBS_DEV_MASK = (0xf << PORT_FBS_DEV_OFFSET), /* FBS.DEV */ +- PORT_FBS_SDE = (1 << 2), /* FBS single device error */ +- PORT_FBS_DEC = (1 << 1), /* FBS device error clear */ +- PORT_FBS_EN = (1 << 0), /* Enable FBS */ ++ PORT_FBS_SDE = BIT(2), /* FBS single device error */ ++ PORT_FBS_DEC = BIT(1), /* FBS device error clear */ ++ PORT_FBS_EN = BIT(0), /* Enable FBS */ + + /* PORT_DEVSLP bits */ + PORT_DEVSLP_DM_OFFSET = 25, /* DITO multiplier offset */ +@@ -197,52 +198,52 @@ enum { + PORT_DEVSLP_DITO_OFFSET = 15, /* DITO offset */ + PORT_DEVSLP_MDAT_OFFSET = 10, /* Minimum assertion time */ + PORT_DEVSLP_DETO_OFFSET = 2, /* DevSlp exit timeout */ +- PORT_DEVSLP_DSP = (1 << 1), /* DevSlp present */ +- PORT_DEVSLP_ADSE = (1 << 0), /* Aggressive DevSlp enable */ ++ PORT_DEVSLP_DSP = BIT(1), /* DevSlp present */ ++ PORT_DEVSLP_ADSE = BIT(0), /* Aggressive DevSlp enable */ + + /* hpriv->flags bits */ + + #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) + +- AHCI_HFLAG_NO_NCQ = (1 << 0), +- AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ +- AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */ +- AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ +- AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ +- AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ +- AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ +- AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ +- AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ +- AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */ +- AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as +- link offline */ +- AHCI_HFLAG_NO_SNTF = (1 << 12), /* no sntf */ +- AHCI_HFLAG_NO_FPDMA_AA = (1 << 13), /* no FPDMA AA */ +- AHCI_HFLAG_YES_FBS = (1 << 14), /* force FBS cap on */ +- AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on +- port start (wait until +- error-handling stage) */ +- AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */ +- AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */ ++ AHCI_HFLAG_NO_NCQ = BIT(0), ++ AHCI_HFLAG_IGN_IRQ_IF_ERR = BIT(1), /* ignore IRQ_IF_ERR */ ++ AHCI_HFLAG_IGN_SERR_INTERNAL = BIT(2), /* ignore SERR_INTERNAL */ ++ AHCI_HFLAG_32BIT_ONLY = BIT(3), /* force 32bit */ ++ AHCI_HFLAG_MV_PATA = BIT(4), /* PATA port */ ++ AHCI_HFLAG_NO_MSI = BIT(5), /* no PCI MSI */ ++ AHCI_HFLAG_NO_PMP = BIT(6), /* no PMP */ ++ AHCI_HFLAG_SECT255 = BIT(8), /* max 255 sectors */ ++ AHCI_HFLAG_YES_NCQ = BIT(9), /* force NCQ cap on */ ++ AHCI_HFLAG_NO_SUSPEND = BIT(10), /* don't suspend */ ++ AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = BIT(11), /* treat SRST timeout as ++ link offline */ ++ AHCI_HFLAG_NO_SNTF = BIT(12), /* no sntf */ ++ AHCI_HFLAG_NO_FPDMA_AA = BIT(13), /* no FPDMA AA */ ++ AHCI_HFLAG_YES_FBS = BIT(14), /* force FBS cap on */ ++ AHCI_HFLAG_DELAY_ENGINE = BIT(15), /* do not start engine on ++ port start (wait until ++ error-handling stage) */ ++ AHCI_HFLAG_NO_DEVSLP = BIT(17), /* no device sleep */ ++ AHCI_HFLAG_NO_FBS = BIT(18), /* no FBS */ + + #ifdef CONFIG_PCI_MSI +- AHCI_HFLAG_MULTI_MSI = (1 << 20), /* per-port MSI(-X) */ ++ AHCI_HFLAG_MULTI_MSI = BIT(20), /* per-port MSI(-X) */ + #else + /* compile out MSI infrastructure */ + AHCI_HFLAG_MULTI_MSI = 0, + #endif +- AHCI_HFLAG_WAKE_BEFORE_STOP = (1 << 22), /* wake before DMA stop */ +- AHCI_HFLAG_YES_ALPM = (1 << 23), /* force ALPM cap on */ +- AHCI_HFLAG_NO_WRITE_TO_RO = (1 << 24), /* don't write to read +- only registers */ +- AHCI_HFLAG_IS_MOBILE = (1 << 25), /* mobile chipset, use +- SATA_MOBILE_LPM_POLICY +- as default lpm_policy */ +- AHCI_HFLAG_SUSPEND_PHYS = (1 << 26), /* handle PHYs during +- suspend/resume */ +- AHCI_HFLAG_IGN_NOTSUPP_POWER_ON = (1 << 27), /* ignore -EOPNOTSUPP +- from phy_power_on() */ +- AHCI_HFLAG_NO_SXS = (1 << 28), /* SXS not supported */ ++ AHCI_HFLAG_WAKE_BEFORE_STOP = BIT(22), /* wake before DMA stop */ ++ AHCI_HFLAG_YES_ALPM = BIT(23), /* force ALPM cap on */ ++ AHCI_HFLAG_NO_WRITE_TO_RO = BIT(24), /* don't write to read ++ only registers */ ++ AHCI_HFLAG_IS_MOBILE = BIT(25), /* mobile chipset, use ++ SATA_MOBILE_LPM_POLICY ++ as default lpm_policy */ ++ AHCI_HFLAG_SUSPEND_PHYS = BIT(26), /* handle PHYs during ++ suspend/resume */ ++ AHCI_HFLAG_IGN_NOTSUPP_POWER_ON = BIT(27), /* ignore -EOPNOTSUPP ++ from phy_power_on() */ ++ AHCI_HFLAG_NO_SXS = BIT(28), /* SXS not supported */ + + /* ap->flags bits */ + +@@ -258,22 +259,22 @@ enum { + EM_MAX_RETRY = 5, + + /* em_ctl bits */ +- EM_CTL_RST = (1 << 9), /* Reset */ +- EM_CTL_TM = (1 << 8), /* Transmit Message */ +- EM_CTL_MR = (1 << 0), /* Message Received */ +- EM_CTL_ALHD = (1 << 26), /* Activity LED */ +- EM_CTL_XMT = (1 << 25), /* Transmit Only */ +- EM_CTL_SMB = (1 << 24), /* Single Message Buffer */ +- EM_CTL_SGPIO = (1 << 19), /* SGPIO messages supported */ +- EM_CTL_SES = (1 << 18), /* SES-2 messages supported */ +- EM_CTL_SAFTE = (1 << 17), /* SAF-TE messages supported */ +- EM_CTL_LED = (1 << 16), /* LED messages supported */ ++ EM_CTL_RST = BIT(9), /* Reset */ ++ EM_CTL_TM = BIT(8), /* Transmit Message */ ++ EM_CTL_MR = BIT(0), /* Message Received */ ++ EM_CTL_ALHD = BIT(26), /* Activity LED */ ++ EM_CTL_XMT = BIT(25), /* Transmit Only */ ++ EM_CTL_SMB = BIT(24), /* Single Message Buffer */ ++ EM_CTL_SGPIO = BIT(19), /* SGPIO messages supported */ ++ EM_CTL_SES = BIT(18), /* SES-2 messages supported */ ++ EM_CTL_SAFTE = BIT(17), /* SAF-TE messages supported */ ++ EM_CTL_LED = BIT(16), /* LED messages supported */ + + /* em message type */ +- EM_MSG_TYPE_LED = (1 << 0), /* LED */ +- EM_MSG_TYPE_SAFTE = (1 << 1), /* SAF-TE */ +- EM_MSG_TYPE_SES2 = (1 << 2), /* SES-2 */ +- EM_MSG_TYPE_SGPIO = (1 << 3), /* SGPIO */ ++ EM_MSG_TYPE_LED = BIT(0), /* LED */ ++ EM_MSG_TYPE_SAFTE = BIT(1), /* SAF-TE */ ++ EM_MSG_TYPE_SES2 = BIT(2), /* SES-2 */ ++ EM_MSG_TYPE_SGPIO = BIT(3), /* SGPIO */ + }; + + struct ahci_cmd_hdr { +diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig +index 9617688b58b32..408c7428cca5e 100644 +--- a/drivers/block/Kconfig ++++ b/drivers/block/Kconfig +@@ -293,15 +293,6 @@ config BLK_DEV_SKD + + Use device /dev/skd$N amd /dev/skd$Np$M. + +-config BLK_DEV_SX8 +- tristate "Promise SATA SX8 support" +- depends on PCI +- help +- Saying Y or M here will enable support for the +- Promise SATA SX8 controllers. +- +- Use devices /dev/sx8/$N and /dev/sx8/$Np$M. +- + config BLK_DEV_RAM + tristate "RAM block device support" + help +diff --git a/drivers/block/Makefile b/drivers/block/Makefile +index a3170859e01d4..24427da7dd64a 100644 +--- a/drivers/block/Makefile ++++ b/drivers/block/Makefile +@@ -29,8 +29,6 @@ obj-$(CONFIG_BLK_DEV_NBD) += nbd.o + obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o + obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o + +-obj-$(CONFIG_BLK_DEV_SX8) += sx8.o +- + obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o + obj-$(CONFIG_XEN_BLKDEV_BACKEND) += xen-blkback/ + obj-$(CONFIG_BLK_DEV_DRBD) += drbd/ +diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c +index 932d4bb8e4035..63491748dc8d7 100644 +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -1397,14 +1397,30 @@ static bool rbd_obj_is_tail(struct rbd_obj_request *obj_req) + /* + * Must be called after rbd_obj_calc_img_extents(). + */ +-static bool rbd_obj_copyup_enabled(struct rbd_obj_request *obj_req) ++static void rbd_obj_set_copyup_enabled(struct rbd_obj_request *obj_req) + { +- if (!obj_req->num_img_extents || +- (rbd_obj_is_entire(obj_req) && +- !obj_req->img_request->snapc->num_snaps)) +- return false; ++ rbd_assert(obj_req->img_request->snapc); + +- return true; ++ if (obj_req->img_request->op_type == OBJ_OP_DISCARD) { ++ dout("%s %p objno %llu discard\n", __func__, obj_req, ++ obj_req->ex.oe_objno); ++ return; ++ } ++ ++ if (!obj_req->num_img_extents) { ++ dout("%s %p objno %llu not overlapping\n", __func__, obj_req, ++ obj_req->ex.oe_objno); ++ return; ++ } ++ ++ if (rbd_obj_is_entire(obj_req) && ++ !obj_req->img_request->snapc->num_snaps) { ++ dout("%s %p objno %llu entire\n", __func__, obj_req, ++ obj_req->ex.oe_objno); ++ return; ++ } ++ ++ obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED; + } + + static u64 rbd_obj_img_extents_bytes(struct rbd_obj_request *obj_req) +@@ -1505,6 +1521,7 @@ __rbd_obj_add_osd_request(struct rbd_obj_request *obj_req, + static struct ceph_osd_request * + rbd_obj_add_osd_request(struct rbd_obj_request *obj_req, int num_ops) + { ++ rbd_assert(obj_req->img_request->snapc); + return __rbd_obj_add_osd_request(obj_req, obj_req->img_request->snapc, + num_ops); + } +@@ -1641,15 +1658,18 @@ static void rbd_img_request_init(struct rbd_img_request *img_request, + mutex_init(&img_request->state_mutex); + } + ++/* ++ * Only snap_id is captured here, for reads. For writes, snapshot ++ * context is captured in rbd_img_object_requests() after exclusive ++ * lock is ensured to be held. ++ */ + static void rbd_img_capture_header(struct rbd_img_request *img_req) + { + struct rbd_device *rbd_dev = img_req->rbd_dev; + + lockdep_assert_held(&rbd_dev->header_rwsem); + +- if (rbd_img_is_write(img_req)) +- img_req->snapc = ceph_get_snap_context(rbd_dev->header.snapc); +- else ++ if (!rbd_img_is_write(img_req)) + img_req->snap_id = rbd_dev->spec->snap_id; + + if (rbd_dev_parent_get(rbd_dev)) +@@ -2296,9 +2316,6 @@ static int rbd_obj_init_write(struct rbd_obj_request *obj_req) + if (ret) + return ret; + +- if (rbd_obj_copyup_enabled(obj_req)) +- obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED; +- + obj_req->write_state = RBD_OBJ_WRITE_START; + return 0; + } +@@ -2404,8 +2421,6 @@ static int rbd_obj_init_zeroout(struct rbd_obj_request *obj_req) + if (ret) + return ret; + +- if (rbd_obj_copyup_enabled(obj_req)) +- obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED; + if (!obj_req->num_img_extents) { + obj_req->flags |= RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT; + if (rbd_obj_is_entire(obj_req)) +@@ -3351,6 +3366,7 @@ again: + case RBD_OBJ_WRITE_START: + rbd_assert(!*result); + ++ rbd_obj_set_copyup_enabled(obj_req); + if (rbd_obj_write_is_noop(obj_req)) + return true; + +@@ -3537,9 +3553,19 @@ static int rbd_img_exclusive_lock(struct rbd_img_request *img_req) + + static void rbd_img_object_requests(struct rbd_img_request *img_req) + { ++ struct rbd_device *rbd_dev = img_req->rbd_dev; + struct rbd_obj_request *obj_req; + + rbd_assert(!img_req->pending.result && !img_req->pending.num_pending); ++ rbd_assert(!need_exclusive_lock(img_req) || ++ __rbd_is_lock_owner(rbd_dev)); ++ ++ if (rbd_img_is_write(img_req)) { ++ rbd_assert(!img_req->snapc); ++ down_read(&rbd_dev->header_rwsem); ++ img_req->snapc = ceph_get_snap_context(rbd_dev->header.snapc); ++ up_read(&rbd_dev->header_rwsem); ++ } + + for_each_obj_request(img_req, obj_req) { + int result = 0; +@@ -3557,7 +3583,6 @@ static void rbd_img_object_requests(struct rbd_img_request *img_req) + + static bool rbd_img_advance(struct rbd_img_request *img_req, int *result) + { +- struct rbd_device *rbd_dev = img_req->rbd_dev; + int ret; + + again: +@@ -3578,9 +3603,6 @@ again: + if (*result) + return true; + +- rbd_assert(!need_exclusive_lock(img_req) || +- __rbd_is_lock_owner(rbd_dev)); +- + rbd_img_object_requests(img_req); + if (!img_req->pending.num_pending) { + *result = img_req->pending.result; +@@ -4038,6 +4060,10 @@ static int rbd_post_acquire_action(struct rbd_device *rbd_dev) + { + int ret; + ++ ret = rbd_dev_refresh(rbd_dev); ++ if (ret) ++ return ret; ++ + if (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP) { + ret = rbd_object_map_open(rbd_dev); + if (ret) +diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c +deleted file mode 100644 +index 4478eb7efee0b..0000000000000 +--- a/drivers/block/sx8.c ++++ /dev/null +@@ -1,1586 +0,0 @@ +-/* +- * sx8.c: Driver for Promise SATA SX8 looks-like-I2O hardware +- * +- * Copyright 2004-2005 Red Hat, Inc. +- * +- * Author/maintainer: Jeff Garzik <[email protected]> +- * +- * This file is subject to the terms and conditions of the GNU General Public +- * License. See the file "COPYING" in the main directory of this archive +- * for more details. +- */ +- +-#include <linux/kernel.h> +-#include <linux/module.h> +-#include <linux/init.h> +-#include <linux/pci.h> +-#include <linux/slab.h> +-#include <linux/spinlock.h> +-#include <linux/blk-mq.h> +-#include <linux/sched.h> +-#include <linux/interrupt.h> +-#include <linux/compiler.h> +-#include <linux/workqueue.h> +-#include <linux/bitops.h> +-#include <linux/delay.h> +-#include <linux/ktime.h> +-#include <linux/hdreg.h> +-#include <linux/dma-mapping.h> +-#include <linux/completion.h> +-#include <linux/scatterlist.h> +-#include <asm/io.h> +-#include <linux/uaccess.h> +- +-#if 0 +-#define CARM_DEBUG +-#define CARM_VERBOSE_DEBUG +-#else +-#undef CARM_DEBUG +-#undef CARM_VERBOSE_DEBUG +-#endif +-#undef CARM_NDEBUG +- +-#define DRV_NAME "sx8" +-#define DRV_VERSION "1.0" +-#define PFX DRV_NAME ": " +- +-MODULE_AUTHOR("Jeff Garzik"); +-MODULE_LICENSE("GPL"); +-MODULE_DESCRIPTION("Promise SATA SX8 block driver"); +-MODULE_VERSION(DRV_VERSION); +- +-/* +- * SX8 hardware has a single message queue for all ATA ports. +- * When this driver was written, the hardware (firmware?) would +- * corrupt data eventually, if more than one request was outstanding. +- * As one can imagine, having 8 ports bottlenecking on a single +- * command hurts performance. +- * +- * Based on user reports, later versions of the hardware (firmware?) +- * seem to be able to survive with more than one command queued. +- * +- * Therefore, we default to the safe option -- 1 command -- but +- * allow the user to increase this. +- * +- * SX8 should be able to support up to ~60 queued commands (CARM_MAX_REQ), +- * but problems seem to occur when you exceed ~30, even on newer hardware. +- */ +-static int max_queue = 1; +-module_param(max_queue, int, 0444); +-MODULE_PARM_DESC(max_queue, "Maximum number of queued commands. (min==1, max==30, safe==1)"); +- +- +-#define NEXT_RESP(idx) ((idx + 1) % RMSG_Q_LEN) +- +-/* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */ +-#define TAG_ENCODE(tag) (((tag) << 16) | 0xf) +-#define TAG_DECODE(tag) (((tag) >> 16) & 0x1f) +-#define TAG_VALID(tag) ((((tag) & 0xf) == 0xf) && (TAG_DECODE(tag) < 32)) +- +-/* note: prints function name for you */ +-#ifdef CARM_DEBUG +-#define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args) +-#ifdef CARM_VERBOSE_DEBUG +-#define VPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args) +-#else +-#define VPRINTK(fmt, args...) +-#endif /* CARM_VERBOSE_DEBUG */ +-#else +-#define DPRINTK(fmt, args...) +-#define VPRINTK(fmt, args...) +-#endif /* CARM_DEBUG */ +- +-#ifdef CARM_NDEBUG +-#define assert(expr) +-#else +-#define assert(expr) \ +- if(unlikely(!(expr))) { \ +- printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ +- #expr, __FILE__, __func__, __LINE__); \ +- } +-#endif +- +-/* defines only for the constants which don't work well as enums */ +-struct carm_host; +- +-enum { +- /* adapter-wide limits */ +- CARM_MAX_PORTS = 8, +- CARM_SHM_SIZE = (4096 << 7), +- CARM_MINORS_PER_MAJOR = 256 / CARM_MAX_PORTS, +- CARM_MAX_WAIT_Q = CARM_MAX_PORTS + 1, +- +- /* command message queue limits */ +- CARM_MAX_REQ = 64, /* max command msgs per host */ +- CARM_MSG_LOW_WATER = (CARM_MAX_REQ / 4), /* refill mark */ +- +- /* S/G limits, host-wide and per-request */ +- CARM_MAX_REQ_SG = 32, /* max s/g entries per request */ +- CARM_MAX_HOST_SG = 600, /* max s/g entries per host */ +- CARM_SG_LOW_WATER = (CARM_MAX_HOST_SG / 4), /* re-fill mark */ +- +- /* hardware registers */ +- CARM_IHQP = 0x1c, +- CARM_INT_STAT = 0x10, /* interrupt status */ +- CARM_INT_MASK = 0x14, /* interrupt mask */ +- CARM_HMUC = 0x18, /* host message unit control */ +- RBUF_ADDR_LO = 0x20, /* response msg DMA buf low 32 bits */ +- RBUF_ADDR_HI = 0x24, /* response msg DMA buf high 32 bits */ +- RBUF_BYTE_SZ = 0x28, +- CARM_RESP_IDX = 0x2c, +- CARM_CMS0 = 0x30, /* command message size reg 0 */ +- CARM_LMUC = 0x48, +- CARM_HMPHA = 0x6c, +- CARM_INITC = 0xb5, +- +- /* bits in CARM_INT_{STAT,MASK} */ +- INT_RESERVED = 0xfffffff0, +- INT_WATCHDOG = (1 << 3), /* watchdog timer */ +- INT_Q_OVERFLOW = (1 << 2), /* cmd msg q overflow */ +- INT_Q_AVAILABLE = (1 << 1), /* cmd msg q has free space */ +- INT_RESPONSE = (1 << 0), /* response msg available */ +- INT_ACK_MASK = INT_WATCHDOG | INT_Q_OVERFLOW, +- INT_DEF_MASK = INT_RESERVED | INT_Q_OVERFLOW | +- INT_RESPONSE, +- +- /* command messages, and related register bits */ +- CARM_HAVE_RESP = 0x01, +- CARM_MSG_READ = 1, +- CARM_MSG_WRITE = 2, +- CARM_MSG_VERIFY = 3, +- CARM_MSG_GET_CAPACITY = 4, +- CARM_MSG_FLUSH = 5, +- CARM_MSG_IOCTL = 6, +- CARM_MSG_ARRAY = 8, +- CARM_MSG_MISC = 9, +- CARM_CME = (1 << 2), +- CARM_RME = (1 << 1), +- CARM_WZBC = (1 << 0), +- CARM_RMI = (1 << 0), +- CARM_Q_FULL = (1 << 3), +- CARM_MSG_SIZE = 288, +- CARM_Q_LEN = 48, +- +- /* CARM_MSG_IOCTL messages */ +- CARM_IOC_SCAN_CHAN = 5, /* scan channels for devices */ +- CARM_IOC_GET_TCQ = 13, /* get tcq/ncq depth */ +- CARM_IOC_SET_TCQ = 14, /* set tcq/ncq depth */ +- +- IOC_SCAN_CHAN_NODEV = 0x1f, +- IOC_SCAN_CHAN_OFFSET = 0x40, +- +- /* CARM_MSG_ARRAY messages */ +- CARM_ARRAY_INFO = 0, +- +- ARRAY_NO_EXIST = (1 << 31), +- +- /* response messages */ +- RMSG_SZ = 8, /* sizeof(struct carm_response) */ +- RMSG_Q_LEN = 48, /* resp. msg list length */ +- RMSG_OK = 1, /* bit indicating msg was successful */ +- /* length of entire resp. msg buffer */ +- RBUF_LEN = RMSG_SZ * RMSG_Q_LEN, +- +- PDC_SHM_SIZE = (4096 << 7), /* length of entire h/w buffer */ +- +- /* CARM_MSG_MISC messages */ +- MISC_GET_FW_VER = 2, +- MISC_ALLOC_MEM = 3, +- MISC_SET_TIME = 5, +- +- /* MISC_GET_FW_VER feature bits */ +- FW_VER_4PORT = (1 << 2), /* 1=4 ports, 0=8 ports */ +- FW_VER_NON_RAID = (1 << 1), /* 1=non-RAID firmware, 0=RAID */ +- FW_VER_ZCR = (1 << 0), /* zero channel RAID (whatever that is) */ +- +- /* carm_host flags */ +- FL_NON_RAID = FW_VER_NON_RAID, +- FL_4PORT = FW_VER_4PORT, +- FL_FW_VER_MASK = (FW_VER_NON_RAID | FW_VER_4PORT), +- FL_DYN_MAJOR = (1 << 17), +-}; +- +-enum { +- CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */ +-}; +- +-enum scatter_gather_types { +- SGT_32BIT = 0, +- SGT_64BIT = 1, +-}; +- +-enum host_states { +- HST_INVALID, /* invalid state; never used */ +- HST_ALLOC_BUF, /* setting up master SHM area */ +- HST_ERROR, /* we never leave here */ +- HST_PORT_SCAN, /* start dev scan */ +- HST_DEV_SCAN_START, /* start per-device probe */ +- HST_DEV_SCAN, /* continue per-device probe */ +- HST_DEV_ACTIVATE, /* activate devices we found */ +- HST_PROBE_FINISHED, /* probe is complete */ +- HST_PROBE_START, /* initiate probe */ +- HST_SYNC_TIME, /* tell firmware what time it is */ +- HST_GET_FW_VER, /* get firmware version, adapter port cnt */ +-}; +- +-#ifdef CARM_DEBUG +-static const char *state_name[] = { +- "HST_INVALID", +- "HST_ALLOC_BUF", +- "HST_ERROR", +- "HST_PORT_SCAN", +- "HST_DEV_SCAN_START", +- "HST_DEV_SCAN", +- "HST_DEV_ACTIVATE", +- "HST_PROBE_FINISHED", +- "HST_PROBE_START", +- "HST_SYNC_TIME", +- "HST_GET_FW_VER", +-}; +-#endif +- +-struct carm_port { +- unsigned int port_no; +- struct gendisk *disk; +- struct carm_host *host; +- +- /* attached device characteristics */ +- u64 capacity; +- char name[41]; +- u16 dev_geom_head; +- u16 dev_geom_sect; +- u16 dev_geom_cyl; +-}; +- +-struct carm_request { +- int n_elem; +- unsigned int msg_type; +- unsigned int msg_subtype; +- unsigned int msg_bucket; +- struct scatterlist sg[CARM_MAX_REQ_SG]; +-}; +- +-struct carm_host { +- unsigned long flags; +- void __iomem *mmio; +- void *shm; +- dma_addr_t shm_dma; +- +- int major; +- int id; +- char name[32]; +- +- spinlock_t lock; +- struct pci_dev *pdev; +- unsigned int state; +- u32 fw_ver; +- +- struct blk_mq_tag_set tag_set; +- struct request_queue *oob_q; +- unsigned int n_oob; +- +- unsigned int hw_sg_used; +- +- unsigned int resp_idx; +- +- unsigned int wait_q_prod; +- unsigned int wait_q_cons; +- struct request_queue *wait_q[CARM_MAX_WAIT_Q]; +- +- void *msg_base; +- dma_addr_t msg_dma; +- +- int cur_scan_dev; +- unsigned long dev_active; +- unsigned long dev_present; +- struct carm_port port[CARM_MAX_PORTS]; +- +- struct work_struct fsm_task; +- +- struct completion probe_comp; +-}; +- +-struct carm_response { +- __le32 ret_handle; +- __le32 status; +-} __attribute__((packed)); +- +-struct carm_msg_sg { +- __le32 start; +- __le32 len; +-} __attribute__((packed)); +- +-struct carm_msg_rw { +- u8 type; +- u8 id; +- u8 sg_count; +- u8 sg_type; +- __le32 handle; +- __le32 lba; +- __le16 lba_count; +- __le16 lba_high; +- struct carm_msg_sg sg[32]; +-} __attribute__((packed)); +- +-struct carm_msg_allocbuf { +- u8 type; +- u8 subtype; +- u8 n_sg; +- u8 sg_type; +- __le32 handle; +- __le32 addr; +- __le32 len; +- __le32 evt_pool; +- __le32 n_evt; +- __le32 rbuf_pool; +- __le32 n_rbuf; +- __le32 msg_pool; +- __le32 n_msg; +- struct carm_msg_sg sg[8]; +-} __attribute__((packed)); +- +-struct carm_msg_ioctl { +- u8 type; +- u8 subtype; +- u8 array_id; +- u8 reserved1; +- __le32 handle; +- __le32 data_addr; +- u32 reserved2; +-} __attribute__((packed)); +- +-struct carm_msg_sync_time { +- u8 type; +- u8 subtype; +- u16 reserved1; +- __le32 handle; +- u32 reserved2; +- __le32 timestamp; +-} __attribute__((packed)); +- +-struct carm_msg_get_fw_ver { +- u8 type; +- u8 subtype; +- u16 reserved1; +- __le32 handle; +- __le32 data_addr; +- u32 reserved2; +-} __attribute__((packed)); +- +-struct carm_fw_ver { +- __le32 version; +- u8 features; +- u8 reserved1; +- u16 reserved2; +-} __attribute__((packed)); +- +-struct carm_array_info { +- __le32 size; +- +- __le16 size_hi; +- __le16 stripe_size; +- +- __le32 mode; +- +- __le16 stripe_blk_sz; +- __le16 reserved1; +- +- __le16 cyl; +- __le16 head; +- +- __le16 sect; +- u8 array_id; +- u8 reserved2; +- +- char name[40]; +- +- __le32 array_status; +- +- /* device list continues beyond this point? */ +-} __attribute__((packed)); +- +-static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +-static void carm_remove_one (struct pci_dev *pdev); +-static int carm_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo); +- +-static const struct pci_device_id carm_pci_tbl[] = { +- { PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, +- { PCI_VENDOR_ID_PROMISE, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, +- { } /* terminate list */ +-}; +-MODULE_DEVICE_TABLE(pci, carm_pci_tbl); +- +-static struct pci_driver carm_driver = { +- .name = DRV_NAME, +- .id_table = carm_pci_tbl, +- .probe = carm_init_one, +- .remove = carm_remove_one, +-}; +- +-static const struct block_device_operations carm_bd_ops = { +- .owner = THIS_MODULE, +- .getgeo = carm_bdev_getgeo, +-}; +- +-static unsigned int carm_host_id; +-static unsigned long carm_major_alloc; +- +- +- +-static int carm_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo) +-{ +- struct carm_port *port = bdev->bd_disk->private_data; +- +- geo->heads = (u8) port->dev_geom_head; +- geo->sectors = (u8) port->dev_geom_sect; +- geo->cylinders = port->dev_geom_cyl; +- return 0; +-} +- +-static const u32 msg_sizes[] = { 32, 64, 128, CARM_MSG_SIZE }; +- +-static inline int carm_lookup_bucket(u32 msg_size) +-{ +- int i; +- +- for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) +- if (msg_size <= msg_sizes[i]) +- return i; +- +- return -ENOENT; +-} +- +-static void carm_init_buckets(void __iomem *mmio) +-{ +- unsigned int i; +- +- for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) +- writel(msg_sizes[i], mmio + CARM_CMS0 + (4 * i)); +-} +- +-static inline void *carm_ref_msg(struct carm_host *host, +- unsigned int msg_idx) +-{ +- return host->msg_base + (msg_idx * CARM_MSG_SIZE); +-} +- +-static inline dma_addr_t carm_ref_msg_dma(struct carm_host *host, +- unsigned int msg_idx) +-{ +- return host->msg_dma + (msg_idx * CARM_MSG_SIZE); +-} +- +-static int carm_send_msg(struct carm_host *host, +- struct carm_request *crq, unsigned tag) +-{ +- void __iomem *mmio = host->mmio; +- u32 msg = (u32) carm_ref_msg_dma(host, tag); +- u32 cm_bucket = crq->msg_bucket; +- u32 tmp; +- int rc = 0; +- +- VPRINTK("ENTER\n"); +- +- tmp = readl(mmio + CARM_HMUC); +- if (tmp & CARM_Q_FULL) { +-#if 0 +- tmp = readl(mmio + CARM_INT_MASK); +- tmp |= INT_Q_AVAILABLE; +- writel(tmp, mmio + CARM_INT_MASK); +- readl(mmio + CARM_INT_MASK); /* flush */ +-#endif +- DPRINTK("host msg queue full\n"); +- rc = -EBUSY; +- } else { +- writel(msg | (cm_bucket << 1), mmio + CARM_IHQP); +- readl(mmio + CARM_IHQP); /* flush */ +- } +- +- return rc; +-} +- +-static int carm_array_info (struct carm_host *host, unsigned int array_idx) +-{ +- struct carm_msg_ioctl *ioc; +- u32 msg_data; +- dma_addr_t msg_dma; +- struct carm_request *crq; +- struct request *rq; +- int rc; +- +- rq = blk_mq_alloc_request(host->oob_q, REQ_OP_DRV_OUT, 0); +- if (IS_ERR(rq)) { +- rc = -ENOMEM; +- goto err_out; +- } +- crq = blk_mq_rq_to_pdu(rq); +- +- ioc = carm_ref_msg(host, rq->tag); +- msg_dma = carm_ref_msg_dma(host, rq->tag); +- msg_data = (u32) (msg_dma + sizeof(struct carm_array_info)); +- +- crq->msg_type = CARM_MSG_ARRAY; +- crq->msg_subtype = CARM_ARRAY_INFO; +- rc = carm_lookup_bucket(sizeof(struct carm_msg_ioctl) + +- sizeof(struct carm_array_info)); +- BUG_ON(rc < 0); +- crq->msg_bucket = (u32) rc; +- +- memset(ioc, 0, sizeof(*ioc)); +- ioc->type = CARM_MSG_ARRAY; +- ioc->subtype = CARM_ARRAY_INFO; +- ioc->array_id = (u8) array_idx; +- ioc->handle = cpu_to_le32(TAG_ENCODE(rq->tag)); +- ioc->data_addr = cpu_to_le32(msg_data); +- +- spin_lock_irq(&host->lock); +- assert(host->state == HST_DEV_SCAN_START || +- host->state == HST_DEV_SCAN); +- spin_unlock_irq(&host->lock); +- +- DPRINTK("blk_execute_rq_nowait, tag == %u\n", rq->tag); +- blk_execute_rq_nowait(host->oob_q, NULL, rq, true, NULL); +- +- return 0; +- +-err_out: +- spin_lock_irq(&host->lock); +- host->state = HST_ERROR; +- spin_unlock_irq(&host->lock); +- return rc; +-} +- +-typedef unsigned int (*carm_sspc_t)(struct carm_host *, unsigned int, void *); +- +-static int carm_send_special (struct carm_host *host, carm_sspc_t func) +-{ +- struct request *rq; +- struct carm_request *crq; +- struct carm_msg_ioctl *ioc; +- void *mem; +- unsigned int msg_size; +- int rc; +- +- rq = blk_mq_alloc_request(host->oob_q, REQ_OP_DRV_OUT, 0); +- if (IS_ERR(rq)) +- return -ENOMEM; +- crq = blk_mq_rq_to_pdu(rq); +- +- mem = carm_ref_msg(host, rq->tag); +- +- msg_size = func(host, rq->tag, mem); +- +- ioc = mem; +- crq->msg_type = ioc->type; +- crq->msg_subtype = ioc->subtype; +- rc = carm_lookup_bucket(msg_size); +- BUG_ON(rc < 0); +- crq->msg_bucket = (u32) rc; +- +- DPRINTK("blk_execute_rq_nowait, tag == %u\n", rq->tag); +- blk_execute_rq_nowait(host->oob_q, NULL, rq, true, NULL); +- +- return 0; +-} +- +-static unsigned int carm_fill_sync_time(struct carm_host *host, +- unsigned int idx, void *mem) +-{ +- struct carm_msg_sync_time *st = mem; +- +- time64_t tv = ktime_get_real_seconds(); +- +- memset(st, 0, sizeof(*st)); +- st->type = CARM_MSG_MISC; +- st->subtype = MISC_SET_TIME; +- st->handle = cpu_to_le32(TAG_ENCODE(idx)); +- st->timestamp = cpu_to_le32(tv); +- +- return sizeof(struct carm_msg_sync_time); +-} +- +-static unsigned int carm_fill_alloc_buf(struct carm_host *host, +- unsigned int idx, void *mem) +-{ +- struct carm_msg_allocbuf *ab = mem; +- +- memset(ab, 0, sizeof(*ab)); +- ab->type = CARM_MSG_MISC; +- ab->subtype = MISC_ALLOC_MEM; +- ab->handle = cpu_to_le32(TAG_ENCODE(idx)); +- ab->n_sg = 1; +- ab->sg_type = SGT_32BIT; +- ab->addr = cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1)); +- ab->len = cpu_to_le32(PDC_SHM_SIZE >> 1); +- ab->evt_pool = cpu_to_le32(host->shm_dma + (16 * 1024)); +- ab->n_evt = cpu_to_le32(1024); +- ab->rbuf_pool = cpu_to_le32(host->shm_dma); +- ab->n_rbuf = cpu_to_le32(RMSG_Q_LEN); +- ab->msg_pool = cpu_to_le32(host->shm_dma + RBUF_LEN); +- ab->n_msg = cpu_to_le32(CARM_Q_LEN); +- ab->sg[0].start = cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1)); +- ab->sg[0].len = cpu_to_le32(65536); +- +- return sizeof(struct carm_msg_allocbuf); +-} +- +-static unsigned int carm_fill_scan_channels(struct carm_host *host, +- unsigned int idx, void *mem) +-{ +- struct carm_msg_ioctl *ioc = mem; +- u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) + +- IOC_SCAN_CHAN_OFFSET); +- +- memset(ioc, 0, sizeof(*ioc)); +- ioc->type = CARM_MSG_IOCTL; +- ioc->subtype = CARM_IOC_SCAN_CHAN; +- ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); +- ioc->data_addr = cpu_to_le32(msg_data); +- +- /* fill output data area with "no device" default values */ +- mem += IOC_SCAN_CHAN_OFFSET; +- memset(mem, IOC_SCAN_CHAN_NODEV, CARM_MAX_PORTS); +- +- return IOC_SCAN_CHAN_OFFSET + CARM_MAX_PORTS; +-} +- +-static unsigned int carm_fill_get_fw_ver(struct carm_host *host, +- unsigned int idx, void *mem) +-{ +- struct carm_msg_get_fw_ver *ioc = mem; +- u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) + sizeof(*ioc)); +- +- memset(ioc, 0, sizeof(*ioc)); +- ioc->type = CARM_MSG_MISC; +- ioc->subtype = MISC_GET_FW_VER; +- ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); +- ioc->data_addr = cpu_to_le32(msg_data); +- +- return sizeof(struct carm_msg_get_fw_ver) + +- sizeof(struct carm_fw_ver); +-} +- +-static inline void carm_push_q (struct carm_host *host, struct request_queue *q) +-{ +- unsigned int idx = host->wait_q_prod % CARM_MAX_WAIT_Q; +- +- blk_mq_stop_hw_queues(q); +- VPRINTK("STOPPED QUEUE %p\n", q); +- +- host->wait_q[idx] = q; +- host->wait_q_prod++; +- BUG_ON(host->wait_q_prod == host->wait_q_cons); /* overrun */ +-} +- +-static inline struct request_queue *carm_pop_q(struct carm_host *host) +-{ +- unsigned int idx; +- +- if (host->wait_q_prod == host->wait_q_cons) +- return NULL; +- +- idx = host->wait_q_cons % CARM_MAX_WAIT_Q; +- host->wait_q_cons++; +- +- return host->wait_q[idx]; +-} +- +-static inline void carm_round_robin(struct carm_host *host) +-{ +- struct request_queue *q = carm_pop_q(host); +- if (q) { +- blk_mq_start_hw_queues(q); +- VPRINTK("STARTED QUEUE %p\n", q); +- } +-} +- +-static inline enum dma_data_direction carm_rq_dir(struct request *rq) +-{ +- return op_is_write(req_op(rq)) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; +-} +- +-static blk_status_t carm_queue_rq(struct blk_mq_hw_ctx *hctx, +- const struct blk_mq_queue_data *bd) +-{ +- struct request_queue *q = hctx->queue; +- struct request *rq = bd->rq; +- struct carm_port *port = q->queuedata; +- struct carm_host *host = port->host; +- struct carm_request *crq = blk_mq_rq_to_pdu(rq); +- struct carm_msg_rw *msg; +- struct scatterlist *sg; +- int i, n_elem = 0, rc; +- unsigned int msg_size; +- u32 tmp; +- +- crq->n_elem = 0; +- sg_init_table(crq->sg, CARM_MAX_REQ_SG); +- +- blk_mq_start_request(rq); +- +- spin_lock_irq(&host->lock); +- if (req_op(rq) == REQ_OP_DRV_OUT) +- goto send_msg; +- +- /* get scatterlist from block layer */ +- sg = &crq->sg[0]; +- n_elem = blk_rq_map_sg(q, rq, sg); +- if (n_elem <= 0) +- goto out_ioerr; +- +- /* map scatterlist to PCI bus addresses */ +- n_elem = dma_map_sg(&host->pdev->dev, sg, n_elem, carm_rq_dir(rq)); +- if (n_elem <= 0) +- goto out_ioerr; +- +- /* obey global hardware limit on S/G entries */ +- if (host->hw_sg_used >= CARM_MAX_HOST_SG - n_elem) +- goto out_resource; +- +- crq->n_elem = n_elem; +- host->hw_sg_used += n_elem; +- +- /* +- * build read/write message +- */ +- +- VPRINTK("build msg\n"); +- msg = (struct carm_msg_rw *) carm_ref_msg(host, rq->tag); +- +- if (rq_data_dir(rq) == WRITE) { +- msg->type = CARM_MSG_WRITE; +- crq->msg_type = CARM_MSG_WRITE; +- } else { +- msg->type = CARM_MSG_READ; +- crq->msg_type = CARM_MSG_READ; +- } +- +- msg->id = port->port_no; +- msg->sg_count = n_elem; +- msg->sg_type = SGT_32BIT; +- msg->handle = cpu_to_le32(TAG_ENCODE(rq->tag)); +- msg->lba = cpu_to_le32(blk_rq_pos(rq) & 0xffffffff); +- tmp = (blk_rq_pos(rq) >> 16) >> 16; +- msg->lba_high = cpu_to_le16( (u16) tmp ); +- msg->lba_count = cpu_to_le16(blk_rq_sectors(rq)); +- +- msg_size = sizeof(struct carm_msg_rw) - sizeof(msg->sg); +- for (i = 0; i < n_elem; i++) { +- struct carm_msg_sg *carm_sg = &msg->sg[i]; +- carm_sg->start = cpu_to_le32(sg_dma_address(&crq->sg[i])); +- carm_sg->len = cpu_to_le32(sg_dma_len(&crq->sg[i])); +- msg_size += sizeof(struct carm_msg_sg); +- } +- +- rc = carm_lookup_bucket(msg_size); +- BUG_ON(rc < 0); +- crq->msg_bucket = (u32) rc; +-send_msg: +- /* +- * queue read/write message to hardware +- */ +- VPRINTK("send msg, tag == %u\n", rq->tag); +- rc = carm_send_msg(host, crq, rq->tag); +- if (rc) { +- host->hw_sg_used -= n_elem; +- goto out_resource; +- } +- +- spin_unlock_irq(&host->lock); +- return BLK_STS_OK; +-out_resource: +- dma_unmap_sg(&host->pdev->dev, &crq->sg[0], n_elem, carm_rq_dir(rq)); +- carm_push_q(host, q); +- spin_unlock_irq(&host->lock); +- return BLK_STS_DEV_RESOURCE; +-out_ioerr: +- carm_round_robin(host); +- spin_unlock_irq(&host->lock); +- return BLK_STS_IOERR; +-} +- +-static void carm_handle_array_info(struct carm_host *host, +- struct carm_request *crq, u8 *mem, +- blk_status_t error) +-{ +- struct carm_port *port; +- u8 *msg_data = mem + sizeof(struct carm_array_info); +- struct carm_array_info *desc = (struct carm_array_info *) msg_data; +- u64 lo, hi; +- int cur_port; +- size_t slen; +- +- DPRINTK("ENTER\n"); +- +- if (error) +- goto out; +- if (le32_to_cpu(desc->array_status) & ARRAY_NO_EXIST) +- goto out; +- +- cur_port = host->cur_scan_dev; +- +- /* should never occur */ +- if ((cur_port < 0) || (cur_port >= CARM_MAX_PORTS)) { +- printk(KERN_ERR PFX "BUG: cur_scan_dev==%d, array_id==%d\n", +- cur_port, (int) desc->array_id); +- goto out; +- } +- +- port = &host->port[cur_port]; +- +- lo = (u64) le32_to_cpu(desc->size); +- hi = (u64) le16_to_cpu(desc->size_hi); +- +- port->capacity = lo | (hi << 32); +- port->dev_geom_head = le16_to_cpu(desc->head); +- port->dev_geom_sect = le16_to_cpu(desc->sect); +- port->dev_geom_cyl = le16_to_cpu(desc->cyl); +- +- host->dev_active |= (1 << cur_port); +- +- strncpy(port->name, desc->name, sizeof(port->name)); +- port->name[sizeof(port->name) - 1] = 0; +- slen = strlen(port->name); +- while (slen && (port->name[slen - 1] == ' ')) { +- port->name[slen - 1] = 0; +- slen--; +- } +- +- printk(KERN_INFO DRV_NAME "(%s): port %u device %Lu sectors\n", +- pci_name(host->pdev), port->port_no, +- (unsigned long long) port->capacity); +- printk(KERN_INFO DRV_NAME "(%s): port %u device \"%s\"\n", +- pci_name(host->pdev), port->port_no, port->name); +- +-out: +- assert(host->state == HST_DEV_SCAN); +- schedule_work(&host->fsm_task); +-} +- +-static void carm_handle_scan_chan(struct carm_host *host, +- struct carm_request *crq, u8 *mem, +- blk_status_t error) +-{ +- u8 *msg_data = mem + IOC_SCAN_CHAN_OFFSET; +- unsigned int i, dev_count = 0; +- int new_state = HST_DEV_SCAN_START; +- +- DPRINTK("ENTER\n"); +- +- if (error) { +- new_state = HST_ERROR; +- goto out; +- } +- +- /* TODO: scan and support non-disk devices */ +- for (i = 0; i < 8; i++) +- if (msg_data[i] == 0) { /* direct-access device (disk) */ +- host->dev_present |= (1 << i); +- dev_count++; +- } +- +- printk(KERN_INFO DRV_NAME "(%s): found %u interesting devices\n", +- pci_name(host->pdev), dev_count); +- +-out: +- assert(host->state == HST_PORT_SCAN); +- host->state = new_state; +- schedule_work(&host->fsm_task); +-} +- +-static void carm_handle_generic(struct carm_host *host, +- struct carm_request *crq, blk_status_t error, +- int cur_state, int next_state) +-{ +- DPRINTK("ENTER\n"); +- +- assert(host->state == cur_state); +- if (error) +- host->state = HST_ERROR; +- else +- host->state = next_state; +- schedule_work(&host->fsm_task); +-} +- +-static inline void carm_handle_resp(struct carm_host *host, +- __le32 ret_handle_le, u32 status) +-{ +- u32 handle = le32_to_cpu(ret_handle_le); +- unsigned int msg_idx; +- struct request *rq; +- struct carm_request *crq; +- blk_status_t error = (status == RMSG_OK) ? 0 : BLK_STS_IOERR; +- u8 *mem; +- +- VPRINTK("ENTER, handle == 0x%x\n", handle); +- +- if (unlikely(!TAG_VALID(handle))) { +- printk(KERN_ERR DRV_NAME "(%s): BUG: invalid tag 0x%x\n", +- pci_name(host->pdev), handle); +- return; +- } +- +- msg_idx = TAG_DECODE(handle); +- VPRINTK("tag == %u\n", msg_idx); +- +- rq = blk_mq_tag_to_rq(host->tag_set.tags[0], msg_idx); +- crq = blk_mq_rq_to_pdu(rq); +- +- /* fast path */ +- if (likely(crq->msg_type == CARM_MSG_READ || +- crq->msg_type == CARM_MSG_WRITE)) { +- dma_unmap_sg(&host->pdev->dev, &crq->sg[0], crq->n_elem, +- carm_rq_dir(rq)); +- goto done; +- } +- +- mem = carm_ref_msg(host, msg_idx); +- +- switch (crq->msg_type) { +- case CARM_MSG_IOCTL: { +- switch (crq->msg_subtype) { +- case CARM_IOC_SCAN_CHAN: +- carm_handle_scan_chan(host, crq, mem, error); +- goto done; +- default: +- /* unknown / invalid response */ +- goto err_out; +- } +- break; +- } +- +- case CARM_MSG_MISC: { +- switch (crq->msg_subtype) { +- case MISC_ALLOC_MEM: +- carm_handle_generic(host, crq, error, +- HST_ALLOC_BUF, HST_SYNC_TIME); +- goto done; +- case MISC_SET_TIME: +- carm_handle_generic(host, crq, error, +- HST_SYNC_TIME, HST_GET_FW_VER); +- goto done; +- case MISC_GET_FW_VER: { +- struct carm_fw_ver *ver = (struct carm_fw_ver *) +- (mem + sizeof(struct carm_msg_get_fw_ver)); +- if (!error) { +- host->fw_ver = le32_to_cpu(ver->version); +- host->flags |= (ver->features & FL_FW_VER_MASK); +- } +- carm_handle_generic(host, crq, error, +- HST_GET_FW_VER, HST_PORT_SCAN); +- goto done; +- } +- default: +- /* unknown / invalid response */ +- goto err_out; +- } +- break; +- } +- +- case CARM_MSG_ARRAY: { +- switch (crq->msg_subtype) { +- case CARM_ARRAY_INFO: +- carm_handle_array_info(host, crq, mem, error); +- break; +- default: +- /* unknown / invalid response */ +- goto err_out; +- } +- break; +- } +- +- default: +- /* unknown / invalid response */ +- goto err_out; +- } +- +- return; +- +-err_out: +- printk(KERN_WARNING DRV_NAME "(%s): BUG: unhandled message type %d/%d\n", +- pci_name(host->pdev), crq->msg_type, crq->msg_subtype); +- error = BLK_STS_IOERR; +-done: +- host->hw_sg_used -= crq->n_elem; +- blk_mq_end_request(blk_mq_rq_from_pdu(crq), error); +- +- if (host->hw_sg_used <= CARM_SG_LOW_WATER) +- carm_round_robin(host); +-} +- +-static inline void carm_handle_responses(struct carm_host *host) +-{ +- void __iomem *mmio = host->mmio; +- struct carm_response *resp = (struct carm_response *) host->shm; +- unsigned int work = 0; +- unsigned int idx = host->resp_idx % RMSG_Q_LEN; +- +- while (1) { +- u32 status = le32_to_cpu(resp[idx].status); +- +- if (status == 0xffffffff) { +- VPRINTK("ending response on index %u\n", idx); +- writel(idx << 3, mmio + CARM_RESP_IDX); +- break; +- } +- +- /* response to a message we sent */ +- else if ((status & (1 << 31)) == 0) { +- VPRINTK("handling msg response on index %u\n", idx); +- carm_handle_resp(host, resp[idx].ret_handle, status); +- resp[idx].status = cpu_to_le32(0xffffffff); +- } +- +- /* asynchronous events the hardware throws our way */ +- else if ((status & 0xff000000) == (1 << 31)) { +- u8 *evt_type_ptr = (u8 *) &resp[idx]; +- u8 evt_type = *evt_type_ptr; +- printk(KERN_WARNING DRV_NAME "(%s): unhandled event type %d\n", +- pci_name(host->pdev), (int) evt_type); +- resp[idx].status = cpu_to_le32(0xffffffff); +- } +- +- idx = NEXT_RESP(idx); +- work++; +- } +- +- VPRINTK("EXIT, work==%u\n", work); +- host->resp_idx += work; +-} +- +-static irqreturn_t carm_interrupt(int irq, void *__host) +-{ +- struct carm_host *host = __host; +- void __iomem *mmio; +- u32 mask; +- int handled = 0; +- unsigned long flags; +- +- if (!host) { +- VPRINTK("no host\n"); +- return IRQ_NONE; +- } +- +- spin_lock_irqsave(&host->lock, flags); +- +- mmio = host->mmio; +- +- /* reading should also clear interrupts */ +- mask = readl(mmio + CARM_INT_STAT); +- +- if (mask == 0 || mask == 0xffffffff) { +- VPRINTK("no work, mask == 0x%x\n", mask); +- goto out; +- } +- +- if (mask & INT_ACK_MASK) +- writel(mask, mmio + CARM_INT_STAT); +- +- if (unlikely(host->state == HST_INVALID)) { +- VPRINTK("not initialized yet, mask = 0x%x\n", mask); +- goto out; +- } +- +- if (mask & CARM_HAVE_RESP) { +- handled = 1; +- carm_handle_responses(host); +- } +- +-out: +- spin_unlock_irqrestore(&host->lock, flags); +- VPRINTK("EXIT\n"); +- return IRQ_RETVAL(handled); +-} +- +-static void carm_fsm_task (struct work_struct *work) +-{ +- struct carm_host *host = +- container_of(work, struct carm_host, fsm_task); +- unsigned long flags; +- unsigned int state; +- int rc, i, next_dev; +- int reschedule = 0; +- int new_state = HST_INVALID; +- +- spin_lock_irqsave(&host->lock, flags); +- state = host->state; +- spin_unlock_irqrestore(&host->lock, flags); +- +- DPRINTK("ENTER, state == %s\n", state_name[state]); +- +- switch (state) { +- case HST_PROBE_START: +- new_state = HST_ALLOC_BUF; +- reschedule = 1; +- break; +- +- case HST_ALLOC_BUF: +- rc = carm_send_special(host, carm_fill_alloc_buf); +- if (rc) { +- new_state = HST_ERROR; +- reschedule = 1; +- } +- break; +- +- case HST_SYNC_TIME: +- rc = carm_send_special(host, carm_fill_sync_time); +- if (rc) { +- new_state = HST_ERROR; +- reschedule = 1; +- } +- break; +- +- case HST_GET_FW_VER: +- rc = carm_send_special(host, carm_fill_get_fw_ver); +- if (rc) { +- new_state = HST_ERROR; +- reschedule = 1; +- } +- break; +- +- case HST_PORT_SCAN: +- rc = carm_send_special(host, carm_fill_scan_channels); +- if (rc) { +- new_state = HST_ERROR; +- reschedule = 1; +- } +- break; +- +- case HST_DEV_SCAN_START: +- host->cur_scan_dev = -1; +- new_state = HST_DEV_SCAN; +- reschedule = 1; +- break; +- +- case HST_DEV_SCAN: +- next_dev = -1; +- for (i = host->cur_scan_dev + 1; i < CARM_MAX_PORTS; i++) +- if (host->dev_present & (1 << i)) { +- next_dev = i; +- break; +- } +- +- if (next_dev >= 0) { +- host->cur_scan_dev = next_dev; +- rc = carm_array_info(host, next_dev); +- if (rc) { +- new_state = HST_ERROR; +- reschedule = 1; +- } +- } else { +- new_state = HST_DEV_ACTIVATE; +- reschedule = 1; +- } +- break; +- +- case HST_DEV_ACTIVATE: { +- int activated = 0; +- for (i = 0; i < CARM_MAX_PORTS; i++) +- if (host->dev_active & (1 << i)) { +- struct carm_port *port = &host->port[i]; +- struct gendisk *disk = port->disk; +- +- set_capacity(disk, port->capacity); +- add_disk(disk); +- activated++; +- } +- +- printk(KERN_INFO DRV_NAME "(%s): %d ports activated\n", +- pci_name(host->pdev), activated); +- +- new_state = HST_PROBE_FINISHED; +- reschedule = 1; +- break; +- } +- +- case HST_PROBE_FINISHED: +- complete(&host->probe_comp); +- break; +- +- case HST_ERROR: +- /* FIXME: TODO */ +- break; +- +- default: +- /* should never occur */ +- printk(KERN_ERR PFX "BUG: unknown state %d\n", state); +- assert(0); +- break; +- } +- +- if (new_state != HST_INVALID) { +- spin_lock_irqsave(&host->lock, flags); +- host->state = new_state; +- spin_unlock_irqrestore(&host->lock, flags); +- } +- if (reschedule) +- schedule_work(&host->fsm_task); +-} +- +-static int carm_init_wait(void __iomem *mmio, u32 bits, unsigned int test_bit) +-{ +- unsigned int i; +- +- for (i = 0; i < 50000; i++) { +- u32 tmp = readl(mmio + CARM_LMUC); +- udelay(100); +- +- if (test_bit) { +- if ((tmp & bits) == bits) +- return 0; +- } else { +- if ((tmp & bits) == 0) +- return 0; +- } +- +- cond_resched(); +- } +- +- printk(KERN_ERR PFX "carm_init_wait timeout, bits == 0x%x, test_bit == %s\n", +- bits, test_bit ? "yes" : "no"); +- return -EBUSY; +-} +- +-static void carm_init_responses(struct carm_host *host) +-{ +- void __iomem *mmio = host->mmio; +- unsigned int i; +- struct carm_response *resp = (struct carm_response *) host->shm; +- +- for (i = 0; i < RMSG_Q_LEN; i++) +- resp[i].status = cpu_to_le32(0xffffffff); +- +- writel(0, mmio + CARM_RESP_IDX); +-} +- +-static int carm_init_host(struct carm_host *host) +-{ +- void __iomem *mmio = host->mmio; +- u32 tmp; +- u8 tmp8; +- int rc; +- +- DPRINTK("ENTER\n"); +- +- writel(0, mmio + CARM_INT_MASK); +- +- tmp8 = readb(mmio + CARM_INITC); +- if (tmp8 & 0x01) { +- tmp8 &= ~0x01; +- writeb(tmp8, mmio + CARM_INITC); +- readb(mmio + CARM_INITC); /* flush */ +- +- DPRINTK("snooze...\n"); +- msleep(5000); +- } +- +- tmp = readl(mmio + CARM_HMUC); +- if (tmp & CARM_CME) { +- DPRINTK("CME bit present, waiting\n"); +- rc = carm_init_wait(mmio, CARM_CME, 1); +- if (rc) { +- DPRINTK("EXIT, carm_init_wait 1 failed\n"); +- return rc; +- } +- } +- if (tmp & CARM_RME) { +- DPRINTK("RME bit present, waiting\n"); +- rc = carm_init_wait(mmio, CARM_RME, 1); +- if (rc) { +- DPRINTK("EXIT, carm_init_wait 2 failed\n"); +- return rc; +- } +- } +- +- tmp &= ~(CARM_RME | CARM_CME); +- writel(tmp, mmio + CARM_HMUC); +- readl(mmio + CARM_HMUC); /* flush */ +- +- rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 0); +- if (rc) { +- DPRINTK("EXIT, carm_init_wait 3 failed\n"); +- return rc; +- } +- +- carm_init_buckets(mmio); +- +- writel(host->shm_dma & 0xffffffff, mmio + RBUF_ADDR_LO); +- writel((host->shm_dma >> 16) >> 16, mmio + RBUF_ADDR_HI); +- writel(RBUF_LEN, mmio + RBUF_BYTE_SZ); +- +- tmp = readl(mmio + CARM_HMUC); +- tmp |= (CARM_RME | CARM_CME | CARM_WZBC); +- writel(tmp, mmio + CARM_HMUC); +- readl(mmio + CARM_HMUC); /* flush */ +- +- rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 1); +- if (rc) { +- DPRINTK("EXIT, carm_init_wait 4 failed\n"); +- return rc; +- } +- +- writel(0, mmio + CARM_HMPHA); +- writel(INT_DEF_MASK, mmio + CARM_INT_MASK); +- +- carm_init_responses(host); +- +- /* start initialization, probing state machine */ +- spin_lock_irq(&host->lock); +- assert(host->state == HST_INVALID); +- host->state = HST_PROBE_START; +- spin_unlock_irq(&host->lock); +- schedule_work(&host->fsm_task); +- +- DPRINTK("EXIT\n"); +- return 0; +-} +- +-static const struct blk_mq_ops carm_mq_ops = { +- .queue_rq = carm_queue_rq, +-}; +- +-static int carm_init_disk(struct carm_host *host, unsigned int port_no) +-{ +- struct carm_port *port = &host->port[port_no]; +- struct gendisk *disk; +- struct request_queue *q; +- +- port->host = host; +- port->port_no = port_no; +- +- disk = alloc_disk(CARM_MINORS_PER_MAJOR); +- if (!disk) +- return -ENOMEM; +- +- port->disk = disk; +- sprintf(disk->disk_name, DRV_NAME "/%u", +- (unsigned int)host->id * CARM_MAX_PORTS + port_no); +- disk->major = host->major; +- disk->first_minor = port_no * CARM_MINORS_PER_MAJOR; +- disk->fops = &carm_bd_ops; +- disk->private_data = port; +- +- q = blk_mq_init_queue(&host->tag_set); +- if (IS_ERR(q)) +- return PTR_ERR(q); +- +- blk_queue_max_segments(q, CARM_MAX_REQ_SG); +- blk_queue_segment_boundary(q, CARM_SG_BOUNDARY); +- +- q->queuedata = port; +- disk->queue = q; +- return 0; +-} +- +-static void carm_free_disk(struct carm_host *host, unsigned int port_no) +-{ +- struct carm_port *port = &host->port[port_no]; +- struct gendisk *disk = port->disk; +- +- if (!disk) +- return; +- +- if (disk->flags & GENHD_FL_UP) +- del_gendisk(disk); +- if (disk->queue) +- blk_cleanup_queue(disk->queue); +- put_disk(disk); +-} +- +-static int carm_init_shm(struct carm_host *host) +-{ +- host->shm = dma_alloc_coherent(&host->pdev->dev, CARM_SHM_SIZE, +- &host->shm_dma, GFP_KERNEL); +- if (!host->shm) +- return -ENOMEM; +- +- host->msg_base = host->shm + RBUF_LEN; +- host->msg_dma = host->shm_dma + RBUF_LEN; +- +- memset(host->shm, 0xff, RBUF_LEN); +- memset(host->msg_base, 0, PDC_SHM_SIZE - RBUF_LEN); +- +- return 0; +-} +- +-static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +-{ +- struct carm_host *host; +- int rc; +- struct request_queue *q; +- unsigned int i; +- +- printk_once(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); +- +- rc = pci_enable_device(pdev); +- if (rc) +- return rc; +- +- rc = pci_request_regions(pdev, DRV_NAME); +- if (rc) +- goto err_out; +- +- rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); +- if (rc) { +- printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n", +- pci_name(pdev)); +- goto err_out_regions; +- } +- +- host = kzalloc(sizeof(*host), GFP_KERNEL); +- if (!host) { +- printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n", +- pci_name(pdev)); +- rc = -ENOMEM; +- goto err_out_regions; +- } +- +- host->pdev = pdev; +- spin_lock_init(&host->lock); +- INIT_WORK(&host->fsm_task, carm_fsm_task); +- init_completion(&host->probe_comp); +- +- host->mmio = ioremap(pci_resource_start(pdev, 0), +- pci_resource_len(pdev, 0)); +- if (!host->mmio) { +- printk(KERN_ERR DRV_NAME "(%s): MMIO alloc failure\n", +- pci_name(pdev)); +- rc = -ENOMEM; +- goto err_out_kfree; +- } +- +- rc = carm_init_shm(host); +- if (rc) { +- printk(KERN_ERR DRV_NAME "(%s): DMA SHM alloc failure\n", +- pci_name(pdev)); +- goto err_out_iounmap; +- } +- +- memset(&host->tag_set, 0, sizeof(host->tag_set)); +- host->tag_set.ops = &carm_mq_ops; +- host->tag_set.cmd_size = sizeof(struct carm_request); +- host->tag_set.nr_hw_queues = 1; +- host->tag_set.nr_maps = 1; +- host->tag_set.queue_depth = max_queue; +- host->tag_set.numa_node = NUMA_NO_NODE; +- host->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; +- +- rc = blk_mq_alloc_tag_set(&host->tag_set); +- if (rc) +- goto err_out_dma_free; +- +- q = blk_mq_init_queue(&host->tag_set); +- if (IS_ERR(q)) { +- rc = PTR_ERR(q); +- blk_mq_free_tag_set(&host->tag_set); +- goto err_out_dma_free; +- } +- +- host->oob_q = q; +- q->queuedata = host; +- +- /* +- * Figure out which major to use: 160, 161, or dynamic +- */ +- if (!test_and_set_bit(0, &carm_major_alloc)) +- host->major = 160; +- else if (!test_and_set_bit(1, &carm_major_alloc)) +- host->major = 161; +- else +- host->flags |= FL_DYN_MAJOR; +- +- host->id = carm_host_id; +- sprintf(host->name, DRV_NAME "%d", carm_host_id); +- +- rc = register_blkdev(host->major, host->name); +- if (rc < 0) +- goto err_out_free_majors; +- if (host->flags & FL_DYN_MAJOR) +- host->major = rc; +- +- for (i = 0; i < CARM_MAX_PORTS; i++) { +- rc = carm_init_disk(host, i); +- if (rc) +- goto err_out_blkdev_disks; +- } +- +- pci_set_master(pdev); +- +- rc = request_irq(pdev->irq, carm_interrupt, IRQF_SHARED, DRV_NAME, host); +- if (rc) { +- printk(KERN_ERR DRV_NAME "(%s): irq alloc failure\n", +- pci_name(pdev)); +- goto err_out_blkdev_disks; +- } +- +- rc = carm_init_host(host); +- if (rc) +- goto err_out_free_irq; +- +- DPRINTK("waiting for probe_comp\n"); +- wait_for_completion(&host->probe_comp); +- +- printk(KERN_INFO "%s: pci %s, ports %d, io %llx, irq %u, major %d\n", +- host->name, pci_name(pdev), (int) CARM_MAX_PORTS, +- (unsigned long long)pci_resource_start(pdev, 0), +- pdev->irq, host->major); +- +- carm_host_id++; +- pci_set_drvdata(pdev, host); +- return 0; +- +-err_out_free_irq: +- free_irq(pdev->irq, host); +-err_out_blkdev_disks: +- for (i = 0; i < CARM_MAX_PORTS; i++) +- carm_free_disk(host, i); +- unregister_blkdev(host->major, host->name); +-err_out_free_majors: +- if (host->major == 160) +- clear_bit(0, &carm_major_alloc); +- else if (host->major == 161) +- clear_bit(1, &carm_major_alloc); +- blk_cleanup_queue(host->oob_q); +- blk_mq_free_tag_set(&host->tag_set); +-err_out_dma_free: +- dma_free_coherent(&pdev->dev, CARM_SHM_SIZE, host->shm, host->shm_dma); +-err_out_iounmap: +- iounmap(host->mmio); +-err_out_kfree: +- kfree(host); +-err_out_regions: +- pci_release_regions(pdev); +-err_out: +- pci_disable_device(pdev); +- return rc; +-} +- +-static void carm_remove_one (struct pci_dev *pdev) +-{ +- struct carm_host *host = pci_get_drvdata(pdev); +- unsigned int i; +- +- if (!host) { +- printk(KERN_ERR PFX "BUG: no host data for PCI(%s)\n", +- pci_name(pdev)); +- return; +- } +- +- free_irq(pdev->irq, host); +- for (i = 0; i < CARM_MAX_PORTS; i++) +- carm_free_disk(host, i); +- unregister_blkdev(host->major, host->name); +- if (host->major == 160) +- clear_bit(0, &carm_major_alloc); +- else if (host->major == 161) +- clear_bit(1, &carm_major_alloc); +- blk_cleanup_queue(host->oob_q); +- blk_mq_free_tag_set(&host->tag_set); +- dma_free_coherent(&pdev->dev, CARM_SHM_SIZE, host->shm, host->shm_dma); +- iounmap(host->mmio); +- kfree(host); +- pci_release_regions(pdev); +- pci_disable_device(pdev); +-} +- +-module_pci_driver(carm_driver); +diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c +index 5347fc465ce89..bc0850d3f7d28 100644 +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -78,7 +78,8 @@ enum qca_flags { + QCA_HW_ERROR_EVENT, + QCA_SSR_TRIGGERED, + QCA_BT_OFF, +- QCA_ROM_FW ++ QCA_ROM_FW, ++ QCA_DEBUGFS_CREATED, + }; + + enum qca_capabilities { +@@ -633,6 +634,9 @@ static void qca_debugfs_init(struct hci_dev *hdev) + if (!hdev->debugfs) + return; + ++ if (test_and_set_bit(QCA_DEBUGFS_CREATED, &qca->flags)) ++ return; ++ + ibs_dir = debugfs_create_dir("ibs", hdev->debugfs); + + /* read only */ +diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c +index 9bcd0eebc6d7e..2e030a308b6e6 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vi.c ++++ b/drivers/gpu/drm/amd/amdgpu/vi.c +@@ -329,8 +329,15 @@ static u32 vi_get_xclk(struct amdgpu_device *adev) + u32 reference_clock = adev->clock.spll.reference_freq; + u32 tmp; + +- if (adev->flags & AMD_IS_APU) +- return reference_clock; ++ if (adev->flags & AMD_IS_APU) { ++ switch (adev->asic_type) { ++ case CHIP_STONEY: ++ /* vbios says 48Mhz, but the actual freq is 100Mhz */ ++ return 10000; ++ default: ++ return reference_clock; ++ } ++ } + + tmp = RREG32_SMC(ixCG_CLKPIN_CNTL_2); + if (REG_GET_FIELD(tmp, CG_CLKPIN_CNTL_2, MUX_TCLK_TO_XCLK)) +diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c +index 25c269bc46815..b6062833370f1 100644 +--- a/drivers/gpu/drm/drm_atomic_uapi.c ++++ b/drivers/gpu/drm/drm_atomic_uapi.c +@@ -75,15 +75,17 @@ int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, + state->mode_blob = NULL; + + if (mode) { ++ struct drm_property_blob *blob; ++ + drm_mode_convert_to_umode(&umode, mode); +- state->mode_blob = +- drm_property_create_blob(state->crtc->dev, +- sizeof(umode), +- &umode); +- if (IS_ERR(state->mode_blob)) +- return PTR_ERR(state->mode_blob); ++ blob = drm_property_create_blob(crtc->dev, ++ sizeof(umode), &umode); ++ if (IS_ERR(blob)) ++ return PTR_ERR(blob); + + drm_mode_copy(&state->mode, mode); ++ ++ state->mode_blob = blob; + state->enable = true; + DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n", + mode->name, crtc->base.id, crtc->name, state); +diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c +index 8ead7e021008c..a520aa06d2cb5 100644 +--- a/drivers/i2c/busses/i2c-sprd.c ++++ b/drivers/i2c/busses/i2c-sprd.c +@@ -576,12 +576,14 @@ static int sprd_i2c_remove(struct platform_device *pdev) + struct sprd_i2c *i2c_dev = platform_get_drvdata(pdev); + int ret; + +- ret = pm_runtime_resume_and_get(i2c_dev->dev); ++ ret = pm_runtime_get_sync(i2c_dev->dev); + if (ret < 0) +- return ret; ++ dev_err(&pdev->dev, "Failed to resume device (%pe)\n", ERR_PTR(ret)); + + i2c_del_adapter(&i2c_dev->adap); +- clk_disable_unprepare(i2c_dev->clk); ++ ++ if (ret >= 0) ++ clk_disable_unprepare(i2c_dev->clk); + + pm_runtime_put_noidle(i2c_dev->dev); + pm_runtime_disable(i2c_dev->dev); +diff --git a/drivers/infiniband/hw/i40iw/i40iw.h b/drivers/infiniband/hw/i40iw/i40iw.h +index 832b80de004fb..13545fcdc5ad6 100644 +--- a/drivers/infiniband/hw/i40iw/i40iw.h ++++ b/drivers/infiniband/hw/i40iw/i40iw.h +@@ -422,9 +422,8 @@ void i40iw_manage_arp_cache(struct i40iw_device *iwdev, + bool ipv4, + u32 action); + +-int i40iw_manage_apbvt(struct i40iw_device *iwdev, +- u16 accel_local_port, +- bool add_port); ++enum i40iw_status_code i40iw_manage_apbvt(struct i40iw_device *iwdev, ++ u16 accel_local_port, bool add_port); + + struct i40iw_cqp_request *i40iw_get_cqp_request(struct i40iw_cqp *cqp, bool wait); + void i40iw_free_cqp_request(struct i40iw_cqp *cqp, struct i40iw_cqp_request *cqp_request); +diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c +index 0bd55e1fca372..b99318fb58dc6 100644 +--- a/drivers/input/joystick/xpad.c ++++ b/drivers/input/joystick/xpad.c +@@ -262,7 +262,6 @@ static const struct xpad_device { + { 0x1430, 0xf801, "RedOctane Controller", 0, XTYPE_XBOX360 }, + { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 }, + { 0x146b, 0x0604, "Bigben Interactive DAIJA Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, +- { 0x1532, 0x0037, "Razer Sabertooth", 0, XTYPE_XBOX360 }, + { 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, + { 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE }, + { 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 }, +diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c +index 2e53ea261e014..598fcb99f6c9e 100644 +--- a/drivers/input/mouse/elantech.c ++++ b/drivers/input/mouse/elantech.c +@@ -674,10 +674,11 @@ static void process_packet_head_v4(struct psmouse *psmouse) + struct input_dev *dev = psmouse->dev; + struct elantech_data *etd = psmouse->private; + unsigned char *packet = psmouse->packet; +- int id = ((packet[3] & 0xe0) >> 5) - 1; ++ int id; + int pres, traces; + +- if (id < 0) ++ id = ((packet[3] & 0xe0) >> 5) - 1; ++ if (id < 0 || id >= ETP_MAX_FINGERS) + return; + + etd->mt[id].x = ((packet[1] & 0x0f) << 8) | packet[2]; +@@ -707,7 +708,7 @@ static void process_packet_motion_v4(struct psmouse *psmouse) + int id, sid; + + id = ((packet[0] & 0xe0) >> 5) - 1; +- if (id < 0) ++ if (id < 0 || id >= ETP_MAX_FINGERS) + return; + + sid = ((packet[3] & 0xe0) >> 5) - 1; +@@ -728,7 +729,7 @@ static void process_packet_motion_v4(struct psmouse *psmouse) + input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[id].x); + input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[id].y); + +- if (sid >= 0) { ++ if (sid >= 0 && sid < ETP_MAX_FINGERS) { + etd->mt[sid].x += delta_x2 * weight; + etd->mt[sid].y -= delta_y2 * weight; + input_mt_slot(dev, sid); +diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig +index 0f791bfdc1f58..c92f2cdf40263 100644 +--- a/drivers/misc/eeprom/Kconfig ++++ b/drivers/misc/eeprom/Kconfig +@@ -6,6 +6,7 @@ config EEPROM_AT24 + depends on I2C && SYSFS + select NVMEM + select NVMEM_SYSFS ++ select REGMAP + select REGMAP_I2C + help + Enable this driver to get read/write support to most I2C EEPROMs +diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c +index deeed50a42c05..f5ab0bff4ac29 100644 +--- a/drivers/net/dsa/lan9303-core.c ++++ b/drivers/net/dsa/lan9303-core.c +@@ -1187,8 +1187,6 @@ static int lan9303_port_fdb_add(struct dsa_switch *ds, int port, + struct lan9303 *chip = ds->priv; + + dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, addr, vid); +- if (vid) +- return -EOPNOTSUPP; + + return lan9303_alr_add_port(chip, addr, port, false); + } +@@ -1200,8 +1198,6 @@ static int lan9303_port_fdb_del(struct dsa_switch *ds, int port, + struct lan9303 *chip = ds->priv; + + dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, addr, vid); +- if (vid) +- return -EOPNOTSUPP; + lan9303_alr_del_port(chip, addr, port); + + return 0; +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +index 3a9fcf942a6de..d8366351cf14a 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +@@ -8337,6 +8337,9 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init) + goto err_out; + } + ++ if (BNXT_VF(bp)) ++ bnxt_hwrm_func_qcfg(bp); ++ + rc = bnxt_setup_vnic(bp, 0); + if (rc) + goto err_out; +@@ -12101,26 +12104,37 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp) + + #endif /* CONFIG_RFS_ACCEL */ + +-static int bnxt_udp_tunnel_sync(struct net_device *netdev, unsigned int table) ++static int bnxt_udp_tunnel_set_port(struct net_device *netdev, unsigned int table, ++ unsigned int entry, struct udp_tunnel_info *ti) + { + struct bnxt *bp = netdev_priv(netdev); +- struct udp_tunnel_info ti; + unsigned int cmd; + +- udp_tunnel_nic_get_port(netdev, table, 0, &ti); +- if (ti.type == UDP_TUNNEL_TYPE_VXLAN) ++ if (ti->type == UDP_TUNNEL_TYPE_VXLAN) + cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN; + else + cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GENEVE; + +- if (ti.port) +- return bnxt_hwrm_tunnel_dst_port_alloc(bp, ti.port, cmd); ++ return bnxt_hwrm_tunnel_dst_port_alloc(bp, ti->port, cmd); ++} ++ ++static int bnxt_udp_tunnel_unset_port(struct net_device *netdev, unsigned int table, ++ unsigned int entry, struct udp_tunnel_info *ti) ++{ ++ struct bnxt *bp = netdev_priv(netdev); ++ unsigned int cmd; ++ ++ if (ti->type == UDP_TUNNEL_TYPE_VXLAN) ++ cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN; ++ else ++ cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GENEVE; + + return bnxt_hwrm_tunnel_dst_port_free(bp, cmd); + } + + static const struct udp_tunnel_nic_info bnxt_udp_tunnels = { +- .sync_table = bnxt_udp_tunnel_sync, ++ .set_port = bnxt_udp_tunnel_set_port, ++ .unset_port = bnxt_udp_tunnel_unset_port, + .flags = UDP_TUNNEL_NIC_INFO_MAY_SLEEP | + UDP_TUNNEL_NIC_INFO_OPEN_ONLY, + .tables = { +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +index 1e67e86fc3344..2984234df67eb 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +@@ -3440,7 +3440,7 @@ static int bnxt_reset(struct net_device *dev, u32 *flags) + } + } + +- if (req & BNXT_FW_RESET_AP) { ++ if (!BNXT_CHIP_P4_PLUS(bp) && (req & BNXT_FW_RESET_AP)) { + /* This feature is not supported in older firmware versions */ + if (bp->hwrm_spec_code >= 0x10803) { + if (!bnxt_firmware_reset_ap(dev)) { +diff --git a/drivers/net/ethernet/intel/i40e/i40e_alloc.h b/drivers/net/ethernet/intel/i40e/i40e_alloc.h +index cb8689222c8b7..55ba6b690ab6c 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_alloc.h ++++ b/drivers/net/ethernet/intel/i40e/i40e_alloc.h +@@ -20,16 +20,11 @@ enum i40e_memory_type { + }; + + /* prototype for functions used for dynamic memory allocation */ +-i40e_status i40e_allocate_dma_mem(struct i40e_hw *hw, +- struct i40e_dma_mem *mem, +- enum i40e_memory_type type, +- u64 size, u32 alignment); +-i40e_status i40e_free_dma_mem(struct i40e_hw *hw, +- struct i40e_dma_mem *mem); +-i40e_status i40e_allocate_virt_mem(struct i40e_hw *hw, +- struct i40e_virt_mem *mem, +- u32 size); +-i40e_status i40e_free_virt_mem(struct i40e_hw *hw, +- struct i40e_virt_mem *mem); ++int i40e_allocate_dma_mem(struct i40e_hw *hw, struct i40e_dma_mem *mem, ++ enum i40e_memory_type type, u64 size, u32 alignment); ++int i40e_free_dma_mem(struct i40e_hw *hw, struct i40e_dma_mem *mem); ++int i40e_allocate_virt_mem(struct i40e_hw *hw, struct i40e_virt_mem *mem, ++ u32 size); ++int i40e_free_virt_mem(struct i40e_hw *hw, struct i40e_virt_mem *mem); + + #endif /* _I40E_ALLOC_H_ */ +diff --git a/drivers/net/ethernet/intel/ice/ice_fltr.c b/drivers/net/ethernet/intel/ice/ice_fltr.c +index 2418d4fff037f..e27b4de7e7aa3 100644 +--- a/drivers/net/ethernet/intel/ice/ice_fltr.c ++++ b/drivers/net/ethernet/intel/ice/ice_fltr.c +@@ -128,7 +128,7 @@ void ice_fltr_remove_all(struct ice_vsi *vsi) + * @mac: MAC address to add + * @action: filter action + */ +-int ++enum ice_status + ice_fltr_add_mac_to_list(struct ice_vsi *vsi, struct list_head *list, + const u8 *mac, enum ice_sw_fwd_act_type action) + { +diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c +index 07824bf9d68d9..0157bcd2efffa 100644 +--- a/drivers/net/ethernet/qlogic/qed/qed_l2.c ++++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c +@@ -1902,7 +1902,7 @@ void qed_get_vport_stats(struct qed_dev *cdev, struct qed_eth_stats *stats) + { + u32 i; + +- if (!cdev) { ++ if (!cdev || cdev->recov_in_prog) { + memset(stats, 0, sizeof(*stats)); + return; + } +diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h +index f313fd7303316..3251d58a263fa 100644 +--- a/drivers/net/ethernet/qlogic/qede/qede.h ++++ b/drivers/net/ethernet/qlogic/qede/qede.h +@@ -273,6 +273,10 @@ struct qede_dev { + #define QEDE_ERR_WARN 3 + + struct qede_dump_info dump_info; ++ struct delayed_work periodic_task; ++ unsigned long stats_coal_ticks; ++ u32 stats_coal_usecs; ++ spinlock_t stats_lock; /* lock for vport stats access */ + }; + + enum QEDE_STATE { +diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +index bedbb85a179ae..db104e035ba18 100644 +--- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c ++++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +@@ -426,6 +426,8 @@ static void qede_get_ethtool_stats(struct net_device *dev, + } + } + ++ spin_lock(&edev->stats_lock); ++ + for (i = 0; i < QEDE_NUM_STATS; i++) { + if (qede_is_irrelevant_stat(edev, i)) + continue; +@@ -435,6 +437,8 @@ static void qede_get_ethtool_stats(struct net_device *dev, + buf++; + } + ++ spin_unlock(&edev->stats_lock); ++ + __qede_unlock(edev); + } + +@@ -815,6 +819,7 @@ out: + + coal->rx_coalesce_usecs = rx_coal; + coal->tx_coalesce_usecs = tx_coal; ++ coal->stats_block_coalesce_usecs = edev->stats_coal_usecs; + + return rc; + } +@@ -827,6 +832,19 @@ static int qede_set_coalesce(struct net_device *dev, + int i, rc = 0; + u16 rxc, txc; + ++ if (edev->stats_coal_usecs != coal->stats_block_coalesce_usecs) { ++ edev->stats_coal_usecs = coal->stats_block_coalesce_usecs; ++ if (edev->stats_coal_usecs) { ++ edev->stats_coal_ticks = usecs_to_jiffies(edev->stats_coal_usecs); ++ schedule_delayed_work(&edev->periodic_task, 0); ++ ++ DP_INFO(edev, "Configured stats coal ticks=%lu jiffies\n", ++ edev->stats_coal_ticks); ++ } else { ++ cancel_delayed_work_sync(&edev->periodic_task); ++ } ++ } ++ + if (!netif_running(dev)) { + DP_INFO(edev, "Interface is down\n"); + return -EINVAL; +@@ -2106,7 +2124,8 @@ err: + } + + static const struct ethtool_ops qede_ethtool_ops = { +- .supported_coalesce_params = ETHTOOL_COALESCE_USECS, ++ .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ++ ETHTOOL_COALESCE_STATS_BLOCK_USECS, + .get_link_ksettings = qede_get_link_ksettings, + .set_link_ksettings = qede_set_link_ksettings, + .get_drvinfo = qede_get_drvinfo, +@@ -2155,7 +2174,8 @@ static const struct ethtool_ops qede_ethtool_ops = { + }; + + static const struct ethtool_ops qede_vf_ethtool_ops = { +- .supported_coalesce_params = ETHTOOL_COALESCE_USECS, ++ .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ++ ETHTOOL_COALESCE_STATS_BLOCK_USECS, + .get_link_ksettings = qede_get_link_ksettings, + .get_drvinfo = qede_get_drvinfo, + .get_msglevel = qede_get_msglevel, +diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c +index e93f06e4a1729..681ec142c23de 100644 +--- a/drivers/net/ethernet/qlogic/qede/qede_main.c ++++ b/drivers/net/ethernet/qlogic/qede/qede_main.c +@@ -313,6 +313,8 @@ void qede_fill_by_demand_stats(struct qede_dev *edev) + + edev->ops->get_vport_stats(edev->cdev, &stats); + ++ spin_lock(&edev->stats_lock); ++ + p_common->no_buff_discards = stats.common.no_buff_discards; + p_common->packet_too_big_discard = stats.common.packet_too_big_discard; + p_common->ttl0_discard = stats.common.ttl0_discard; +@@ -410,6 +412,8 @@ void qede_fill_by_demand_stats(struct qede_dev *edev) + p_ah->tx_1519_to_max_byte_packets = + stats.ah.tx_1519_to_max_byte_packets; + } ++ ++ spin_unlock(&edev->stats_lock); + } + + static void qede_get_stats64(struct net_device *dev, +@@ -418,9 +422,10 @@ static void qede_get_stats64(struct net_device *dev, + struct qede_dev *edev = netdev_priv(dev); + struct qede_stats_common *p_common; + +- qede_fill_by_demand_stats(edev); + p_common = &edev->stats.common; + ++ spin_lock(&edev->stats_lock); ++ + stats->rx_packets = p_common->rx_ucast_pkts + p_common->rx_mcast_pkts + + p_common->rx_bcast_pkts; + stats->tx_packets = p_common->tx_ucast_pkts + p_common->tx_mcast_pkts + +@@ -440,6 +445,8 @@ static void qede_get_stats64(struct net_device *dev, + stats->collisions = edev->stats.bb.tx_total_collisions; + stats->rx_crc_errors = p_common->rx_crc_errors; + stats->rx_frame_errors = p_common->rx_align_errors; ++ ++ spin_unlock(&edev->stats_lock); + } + + #ifdef CONFIG_QED_SRIOV +@@ -1001,6 +1008,23 @@ static void qede_unlock(struct qede_dev *edev) + rtnl_unlock(); + } + ++static void qede_periodic_task(struct work_struct *work) ++{ ++ struct qede_dev *edev = container_of(work, struct qede_dev, ++ periodic_task.work); ++ ++ qede_fill_by_demand_stats(edev); ++ schedule_delayed_work(&edev->periodic_task, edev->stats_coal_ticks); ++} ++ ++static void qede_init_periodic_task(struct qede_dev *edev) ++{ ++ INIT_DELAYED_WORK(&edev->periodic_task, qede_periodic_task); ++ spin_lock_init(&edev->stats_lock); ++ edev->stats_coal_usecs = USEC_PER_SEC; ++ edev->stats_coal_ticks = usecs_to_jiffies(USEC_PER_SEC); ++} ++ + static void qede_sp_task(struct work_struct *work) + { + struct qede_dev *edev = container_of(work, struct qede_dev, +@@ -1020,6 +1044,7 @@ static void qede_sp_task(struct work_struct *work) + */ + + if (test_and_clear_bit(QEDE_SP_RECOVERY, &edev->sp_flags)) { ++ cancel_delayed_work_sync(&edev->periodic_task); + #ifdef CONFIG_QED_SRIOV + /* SRIOV must be disabled outside the lock to avoid a deadlock. + * The recovery of the active VFs is currently not supported. +@@ -1216,6 +1241,7 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, + */ + INIT_DELAYED_WORK(&edev->sp_task, qede_sp_task); + mutex_init(&edev->qede_lock); ++ qede_init_periodic_task(edev); + + rc = register_netdev(edev->ndev); + if (rc) { +@@ -1240,6 +1266,11 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, + edev->rx_copybreak = QEDE_RX_HDR_SIZE; + + qede_log_probe(edev); ++ ++ /* retain user config (for example - after recovery) */ ++ if (edev->stats_coal_usecs) ++ schedule_delayed_work(&edev->periodic_task, 0); ++ + return 0; + + err4: +@@ -1308,6 +1339,7 @@ static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) + unregister_netdev(ndev); + + cancel_delayed_work_sync(&edev->sp_task); ++ cancel_delayed_work_sync(&edev->periodic_task); + + edev->ops->common->set_power_state(cdev, PCI_D0); + +diff --git a/drivers/net/ethernet/sfc/ef100_tx.c b/drivers/net/ethernet/sfc/ef100_tx.c +index a90e5a9d2a37a..6ddda1a5e5363 100644 +--- a/drivers/net/ethernet/sfc/ef100_tx.c ++++ b/drivers/net/ethernet/sfc/ef100_tx.c +@@ -333,7 +333,8 @@ void ef100_ev_tx(struct efx_channel *channel, const efx_qword_t *p_event) + * Returns 0 on success, error code otherwise. In case of an error this + * function will free the SKB. + */ +-int ef100_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) ++netdev_tx_t ef100_enqueue_skb(struct efx_tx_queue *tx_queue, ++ struct sk_buff *skb) + { + unsigned int old_insert_count = tx_queue->insert_count; + struct efx_nic *efx = tx_queue->efx; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +index b26617026e831..4364f73b501da 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +@@ -779,7 +779,10 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev) + + msta = list_first_entry(&sta_poll_list, struct mt7615_sta, + poll_list); ++ ++ spin_lock_bh(&dev->sta_poll_lock); + list_del_init(&msta->poll_list); ++ spin_unlock_bh(&dev->sta_poll_lock); + + addr = mt7615_mac_wtbl_addr(dev, msta->wcid.idx) + 19 * 4; + +diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg.c b/drivers/pinctrl/meson/pinctrl-meson-axg.c +index 072765db93d70..505466b06629f 100644 +--- a/drivers/pinctrl/meson/pinctrl-meson-axg.c ++++ b/drivers/pinctrl/meson/pinctrl-meson-axg.c +@@ -400,6 +400,7 @@ static struct meson_pmx_group meson_axg_periphs_groups[] = { + GPIO_GROUP(GPIOA_15), + GPIO_GROUP(GPIOA_16), + GPIO_GROUP(GPIOA_17), ++ GPIO_GROUP(GPIOA_18), + GPIO_GROUP(GPIOA_19), + GPIO_GROUP(GPIOA_20), + +diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c +index cb6427fb9f3d1..6d5c9cb83592f 100644 +--- a/drivers/s390/block/dasd_ioctl.c ++++ b/drivers/s390/block/dasd_ioctl.c +@@ -505,10 +505,10 @@ static int __dasd_ioctl_information(struct dasd_block *block, + + memcpy(dasd_info->type, base->discipline->name, 4); + +- spin_lock_irqsave(&block->queue_lock, flags); ++ spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); + list_for_each(l, &base->ccw_queue) + dasd_info->chanq_len++; +- spin_unlock_irqrestore(&block->queue_lock, flags); ++ spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); + return 0; + } + +diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c +index 8bf58510cca6d..2cc9bb413c108 100644 +--- a/drivers/spi/spi-qup.c ++++ b/drivers/spi/spi-qup.c +@@ -1030,23 +1030,8 @@ static int spi_qup_probe(struct platform_device *pdev) + return -ENXIO; + } + +- ret = clk_prepare_enable(cclk); +- if (ret) { +- dev_err(dev, "cannot enable core clock\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(iclk); +- if (ret) { +- clk_disable_unprepare(cclk); +- dev_err(dev, "cannot enable iface clock\n"); +- return ret; +- } +- + master = spi_alloc_master(dev, sizeof(struct spi_qup)); + if (!master) { +- clk_disable_unprepare(cclk); +- clk_disable_unprepare(iclk); + dev_err(dev, "cannot allocate master\n"); + return -ENOMEM; + } +@@ -1092,6 +1077,19 @@ static int spi_qup_probe(struct platform_device *pdev) + spin_lock_init(&controller->lock); + init_completion(&controller->done); + ++ ret = clk_prepare_enable(cclk); ++ if (ret) { ++ dev_err(dev, "cannot enable core clock\n"); ++ goto error_dma; ++ } ++ ++ ret = clk_prepare_enable(iclk); ++ if (ret) { ++ clk_disable_unprepare(cclk); ++ dev_err(dev, "cannot enable iface clock\n"); ++ goto error_dma; ++ } ++ + iomode = readl_relaxed(base + QUP_IO_M_MODES); + + size = QUP_IO_M_OUTPUT_BLOCK_SIZE(iomode); +@@ -1121,7 +1119,7 @@ static int spi_qup_probe(struct platform_device *pdev) + ret = spi_qup_set_state(controller, QUP_STATE_RESET); + if (ret) { + dev_err(dev, "cannot set RESET state\n"); +- goto error_dma; ++ goto error_clk; + } + + writel_relaxed(0, base + QUP_OPERATIONAL); +@@ -1145,7 +1143,7 @@ static int spi_qup_probe(struct platform_device *pdev) + ret = devm_request_irq(dev, irq, spi_qup_qup_irq, + IRQF_TRIGGER_HIGH, pdev->name, controller); + if (ret) +- goto error_dma; ++ goto error_clk; + + pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC); + pm_runtime_use_autosuspend(dev); +@@ -1160,11 +1158,12 @@ static int spi_qup_probe(struct platform_device *pdev) + + disable_pm: + pm_runtime_disable(&pdev->dev); ++error_clk: ++ clk_disable_unprepare(cclk); ++ clk_disable_unprepare(iclk); + error_dma: + spi_qup_release_dma(master); + error: +- clk_disable_unprepare(cclk); +- clk_disable_unprepare(iclk); + spi_master_put(master); + return ret; + } +diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +index 4c201679fc081..291f98251f7f7 100644 +--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c ++++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +@@ -50,9 +50,9 @@ static const struct rtl819x_ops rtl819xp_ops = { + }; + + static struct pci_device_id rtl8192_pci_id_tbl[] = { +- {PCI_DEVICE(0x10ec, 0x8192)}, +- {PCI_DEVICE(0x07aa, 0x0044)}, +- {PCI_DEVICE(0x07aa, 0x0047)}, ++ {RTL_PCI_DEVICE(0x10ec, 0x8192, rtl819xp_ops)}, ++ {RTL_PCI_DEVICE(0x07aa, 0x0044, rtl819xp_ops)}, ++ {RTL_PCI_DEVICE(0x07aa, 0x0047, rtl819xp_ops)}, + {} + }; + +diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +index 7bbd884aa5f13..736f1a824cd2e 100644 +--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h ++++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +@@ -55,6 +55,11 @@ + #define IS_HARDWARE_TYPE_8192SE(_priv) \ + (((struct r8192_priv *)rtllib_priv(dev))->card_8192 == NIC_8192SE) + ++#define RTL_PCI_DEVICE(vend, dev, cfg) \ ++ .vendor = (vend), .device = (dev), \ ++ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \ ++ .driver_data = (kernel_ulong_t)&(cfg) ++ + #define TOTAL_CAM_ENTRY 32 + #define CAM_CONTENT_COUNT 8 + +diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +index 3d378da119e7a..178cf90fb3e5a 100644 +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +@@ -147,12 +147,11 @@ vchiq_blocking_bulk_transfer(unsigned int handle, void *data, + unsigned int size, enum vchiq_bulk_dir dir); + + #define VCHIQ_INIT_RETRIES 10 +-enum vchiq_status vchiq_initialise(struct vchiq_instance **instance_out) ++int vchiq_initialise(struct vchiq_instance **instance_out) + { +- enum vchiq_status status = VCHIQ_ERROR; + struct vchiq_state *state; + struct vchiq_instance *instance = NULL; +- int i; ++ int i, ret; + + vchiq_log_trace(vchiq_core_log_level, "%s called", __func__); + +@@ -169,6 +168,7 @@ enum vchiq_status vchiq_initialise(struct vchiq_instance **instance_out) + if (i == VCHIQ_INIT_RETRIES) { + vchiq_log_error(vchiq_core_log_level, + "%s: videocore not initialized\n", __func__); ++ ret = -ENOTCONN; + goto failed; + } else if (i > 0) { + vchiq_log_warning(vchiq_core_log_level, +@@ -180,6 +180,7 @@ enum vchiq_status vchiq_initialise(struct vchiq_instance **instance_out) + if (!instance) { + vchiq_log_error(vchiq_core_log_level, + "%s: error allocating vchiq instance\n", __func__); ++ ret = -ENOMEM; + goto failed; + } + +@@ -190,13 +191,13 @@ enum vchiq_status vchiq_initialise(struct vchiq_instance **instance_out) + + *instance_out = instance; + +- status = VCHIQ_SUCCESS; ++ ret = 0; + + failed: + vchiq_log_trace(vchiq_core_log_level, +- "%s(%p): returning %d", __func__, instance, status); ++ "%s(%p): returning %d", __func__, instance, ret); + +- return status; ++ return ret; + } + EXPORT_SYMBOL(vchiq_initialise); + +@@ -2223,6 +2224,7 @@ vchiq_keepalive_thread_func(void *v) + enum vchiq_status status; + struct vchiq_instance *instance; + unsigned int ka_handle; ++ int ret; + + struct vchiq_service_params_kernel params = { + .fourcc = VCHIQ_MAKE_FOURCC('K', 'E', 'E', 'P'), +@@ -2231,10 +2233,10 @@ vchiq_keepalive_thread_func(void *v) + .version_min = KEEPALIVE_VER_MIN + }; + +- status = vchiq_initialise(&instance); +- if (status != VCHIQ_SUCCESS) { ++ ret = vchiq_initialise(&instance); ++ if (ret) { + vchiq_log_error(vchiq_susp_log_level, +- "%s vchiq_initialise failed %d", __func__, status); ++ "%s vchiq_initialise failed %d", __func__, ret); + goto exit; + } + +@@ -2313,7 +2315,7 @@ vchiq_arm_init_state(struct vchiq_state *state, + return VCHIQ_SUCCESS; + } + +-enum vchiq_status ++int + vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service, + enum USE_TYPE_E use_type) + { +@@ -2373,7 +2375,7 @@ out: + return ret; + } + +-enum vchiq_status ++int + vchiq_release_internal(struct vchiq_state *state, struct vchiq_service *service) + { + struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); +diff --git a/drivers/tee/amdtee/amdtee_if.h b/drivers/tee/amdtee/amdtee_if.h +index ff48c3e473750..e2014e21530ac 100644 +--- a/drivers/tee/amdtee/amdtee_if.h ++++ b/drivers/tee/amdtee/amdtee_if.h +@@ -118,16 +118,18 @@ struct tee_cmd_unmap_shared_mem { + + /** + * struct tee_cmd_load_ta - load Trusted Application (TA) binary into TEE +- * @low_addr: [in] bits [31:0] of the physical address of the TA binary +- * @hi_addr: [in] bits [63:32] of the physical address of the TA binary +- * @size: [in] size of TA binary in bytes +- * @ta_handle: [out] return handle of the loaded TA ++ * @low_addr: [in] bits [31:0] of the physical address of the TA binary ++ * @hi_addr: [in] bits [63:32] of the physical address of the TA binary ++ * @size: [in] size of TA binary in bytes ++ * @ta_handle: [out] return handle of the loaded TA ++ * @return_origin: [out] origin of return code after TEE processing + */ + struct tee_cmd_load_ta { + u32 low_addr; + u32 hi_addr; + u32 size; + u32 ta_handle; ++ u32 return_origin; + }; + + /** +diff --git a/drivers/tee/amdtee/call.c b/drivers/tee/amdtee/call.c +index 07f36ac834c88..63d428423e904 100644 +--- a/drivers/tee/amdtee/call.c ++++ b/drivers/tee/amdtee/call.c +@@ -423,19 +423,23 @@ int handle_load_ta(void *data, u32 size, struct tee_ioctl_open_session_arg *arg) + if (ret) { + arg->ret_origin = TEEC_ORIGIN_COMMS; + arg->ret = TEEC_ERROR_COMMUNICATION; +- } else if (arg->ret == TEEC_SUCCESS) { +- ret = get_ta_refcount(load_cmd.ta_handle); +- if (!ret) { +- arg->ret_origin = TEEC_ORIGIN_COMMS; +- arg->ret = TEEC_ERROR_OUT_OF_MEMORY; +- +- /* Unload the TA on error */ +- unload_cmd.ta_handle = load_cmd.ta_handle; +- psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA, +- (void *)&unload_cmd, +- sizeof(unload_cmd), &ret); +- } else { +- set_session_id(load_cmd.ta_handle, 0, &arg->session); ++ } else { ++ arg->ret_origin = load_cmd.return_origin; ++ ++ if (arg->ret == TEEC_SUCCESS) { ++ ret = get_ta_refcount(load_cmd.ta_handle); ++ if (!ret) { ++ arg->ret_origin = TEEC_ORIGIN_COMMS; ++ arg->ret = TEEC_ERROR_OUT_OF_MEMORY; ++ ++ /* Unload the TA on error */ ++ unload_cmd.ta_handle = load_cmd.ta_handle; ++ psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA, ++ (void *)&unload_cmd, ++ sizeof(unload_cmd), &ret); ++ } else { ++ set_session_id(load_cmd.ta_handle, 0, &arg->session); ++ } + } + } + mutex_unlock(&ta_refcount_mutex); +diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c +index 6cf22c27f2d24..be8738750948e 100644 +--- a/drivers/usb/core/buffer.c ++++ b/drivers/usb/core/buffer.c +@@ -170,3 +170,44 @@ void hcd_buffer_free( + } + dma_free_coherent(hcd->self.sysdev, size, addr, dma); + } ++ ++void *hcd_buffer_alloc_pages(struct usb_hcd *hcd, ++ size_t size, gfp_t mem_flags, dma_addr_t *dma) ++{ ++ if (size == 0) ++ return NULL; ++ ++ if (hcd->localmem_pool) ++ return gen_pool_dma_alloc_align(hcd->localmem_pool, ++ size, dma, PAGE_SIZE); ++ ++ /* some USB hosts just use PIO */ ++ if (!hcd_uses_dma(hcd)) { ++ *dma = DMA_MAPPING_ERROR; ++ return (void *)__get_free_pages(mem_flags, ++ get_order(size)); ++ } ++ ++ return dma_alloc_coherent(hcd->self.sysdev, ++ size, dma, mem_flags); ++} ++ ++void hcd_buffer_free_pages(struct usb_hcd *hcd, ++ size_t size, void *addr, dma_addr_t dma) ++{ ++ if (!addr) ++ return; ++ ++ if (hcd->localmem_pool) { ++ gen_pool_free(hcd->localmem_pool, ++ (unsigned long)addr, size); ++ return; ++ } ++ ++ if (!hcd_uses_dma(hcd)) { ++ free_pages((unsigned long)addr, get_order(size)); ++ return; ++ } ++ ++ dma_free_coherent(hcd->self.sysdev, size, addr, dma); ++} +diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c +index 73b60f013b205..2fe29319de441 100644 +--- a/drivers/usb/core/devio.c ++++ b/drivers/usb/core/devio.c +@@ -173,6 +173,7 @@ static int connected(struct usb_dev_state *ps) + static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count) + { + struct usb_dev_state *ps = usbm->ps; ++ struct usb_hcd *hcd = bus_to_hcd(ps->dev->bus); + unsigned long flags; + + spin_lock_irqsave(&ps->lock, flags); +@@ -181,8 +182,8 @@ static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count) + list_del(&usbm->memlist); + spin_unlock_irqrestore(&ps->lock, flags); + +- usb_free_coherent(ps->dev, usbm->size, usbm->mem, +- usbm->dma_handle); ++ hcd_buffer_free_pages(hcd, usbm->size, ++ usbm->mem, usbm->dma_handle); + usbfs_decrease_memory_usage( + usbm->size + sizeof(struct usb_memory)); + kfree(usbm); +@@ -221,7 +222,7 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma) + size_t size = vma->vm_end - vma->vm_start; + void *mem; + unsigned long flags; +- dma_addr_t dma_handle; ++ dma_addr_t dma_handle = DMA_MAPPING_ERROR; + int ret; + + ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory)); +@@ -234,8 +235,8 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma) + goto error_decrease_mem; + } + +- mem = usb_alloc_coherent(ps->dev, size, GFP_USER | __GFP_NOWARN, +- &dma_handle); ++ mem = hcd_buffer_alloc_pages(hcd, ++ size, GFP_USER | __GFP_NOWARN, &dma_handle); + if (!mem) { + ret = -ENOMEM; + goto error_free_usbm; +@@ -251,7 +252,14 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma) + usbm->vma_use_count = 1; + INIT_LIST_HEAD(&usbm->memlist); + +- if (hcd->localmem_pool || !hcd_uses_dma(hcd)) { ++ /* ++ * In DMA-unavailable cases, hcd_buffer_alloc_pages allocates ++ * normal pages and assigns DMA_MAPPING_ERROR to dma_handle. Check ++ * whether we are in such cases, and then use remap_pfn_range (or ++ * dma_mmap_coherent) to map normal (or DMA) pages into the user ++ * space, respectively. ++ */ ++ if (dma_handle == DMA_MAPPING_ERROR) { + if (remap_pfn_range(vma, vma->vm_start, + virt_to_phys(usbm->mem) >> PAGE_SHIFT, + size, vma->vm_page_prot) < 0) { +diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c +index 1f9a1554ce5f4..de110363af521 100644 +--- a/drivers/vhost/vhost.c ++++ b/drivers/vhost/vhost.c +@@ -1621,17 +1621,25 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg + r = -EFAULT; + break; + } +- if (s.num > 0xffff) { +- r = -EINVAL; +- break; ++ if (vhost_has_feature(vq, VIRTIO_F_RING_PACKED)) { ++ vq->last_avail_idx = s.num & 0xffff; ++ vq->last_used_idx = (s.num >> 16) & 0xffff; ++ } else { ++ if (s.num > 0xffff) { ++ r = -EINVAL; ++ break; ++ } ++ vq->last_avail_idx = s.num; + } +- vq->last_avail_idx = s.num; + /* Forget the cached index value. */ + vq->avail_idx = vq->last_avail_idx; + break; + case VHOST_GET_VRING_BASE: + s.index = idx; +- s.num = vq->last_avail_idx; ++ if (vhost_has_feature(vq, VIRTIO_F_RING_PACKED)) ++ s.num = (u32)vq->last_avail_idx | ((u32)vq->last_used_idx << 16); ++ else ++ s.num = vq->last_avail_idx; + if (copy_to_user(argp, &s, sizeof s)) + r = -EFAULT; + break; +diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h +index 8f80d6b0d843e..e00347f2b4d30 100644 +--- a/drivers/vhost/vhost.h ++++ b/drivers/vhost/vhost.h +@@ -87,13 +87,17 @@ struct vhost_virtqueue { + /* The routine to call when the Guest pings us, or timeout. */ + vhost_work_fn_t handle_kick; + +- /* Last available index we saw. */ ++ /* Last available index we saw. ++ * Values are limited to 0x7fff, and the high bit is used as ++ * a wrap counter when using VIRTIO_F_RING_PACKED. */ + u16 last_avail_idx; + + /* Caches available index value from user. */ + u16 avail_idx; + +- /* Last index we used. */ ++ /* Last index we used. ++ * Values are limited to 0x7fff, and the high bit is used as ++ * a wrap counter when using VIRTIO_F_RING_PACKED. */ + u16 last_used_idx; + + /* Used flags */ +diff --git a/fs/afs/dir.c b/fs/afs/dir.c +index 159795059547f..a59d6293a32b2 100644 +--- a/fs/afs/dir.c ++++ b/fs/afs/dir.c +@@ -1313,6 +1313,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) + op->dentry = dentry; + op->create.mode = S_IFDIR | mode; + op->create.reason = afs_edit_dir_for_mkdir; ++ op->mtime = current_time(dir); + op->ops = &afs_mkdir_operation; + return afs_do_sync_operation(op); + } +@@ -1616,6 +1617,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, + op->dentry = dentry; + op->create.mode = S_IFREG | mode; + op->create.reason = afs_edit_dir_for_create; ++ op->mtime = current_time(dir); + op->ops = &afs_create_operation; + return afs_do_sync_operation(op); + +@@ -1745,6 +1747,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, + op->ops = &afs_symlink_operation; + op->create.reason = afs_edit_dir_for_symlink; + op->create.symlink = content; ++ op->mtime = current_time(dir); + return afs_do_sync_operation(op); + + error: +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index c21545c5b34bd..93db4486a9433 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -1895,7 +1895,7 @@ again: + list_splice(&reloc_roots, &rc->reloc_roots); + + if (!err) +- btrfs_commit_transaction(trans); ++ err = btrfs_commit_transaction(trans); + else + btrfs_end_transaction(trans); + return err; +@@ -3270,8 +3270,12 @@ int prepare_to_relocate(struct reloc_control *rc) + */ + return PTR_ERR(trans); + } +- btrfs_commit_transaction(trans); +- return 0; ++ ++ ret = btrfs_commit_transaction(trans); ++ if (ret) ++ unset_reloc_control(rc); ++ ++ return ret; + } + + static noinline_for_stack int relocate_block_group(struct reloc_control *rc) +@@ -3443,7 +3447,9 @@ restart: + err = PTR_ERR(trans); + goto out_free; + } +- btrfs_commit_transaction(trans); ++ ret = btrfs_commit_transaction(trans); ++ if (ret && !err) ++ err = ret; + out_free: + ret = clean_dirty_subvols(rc); + if (ret < 0 && !err) +diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c +index 210496dc2fd49..e1fda3923944e 100644 +--- a/fs/ceph/caps.c ++++ b/fs/ceph/caps.c +@@ -1636,6 +1636,7 @@ void ceph_flush_snaps(struct ceph_inode_info *ci, + struct inode *inode = &ci->vfs_inode; + struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc; + struct ceph_mds_session *session = NULL; ++ bool need_put = false; + int mds; + + dout("ceph_flush_snaps %p\n", inode); +@@ -1687,8 +1688,13 @@ out: + } + /* we flushed them all; remove this inode from the queue */ + spin_lock(&mdsc->snap_flush_lock); ++ if (!list_empty(&ci->i_snap_flush_item)) ++ need_put = true; + list_del_init(&ci->i_snap_flush_item); + spin_unlock(&mdsc->snap_flush_lock); ++ ++ if (need_put) ++ iput(inode); + } + + /* +diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c +index 8e6fc45ccc9eb..db464682b2cb2 100644 +--- a/fs/ceph/snap.c ++++ b/fs/ceph/snap.c +@@ -647,8 +647,10 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci, + capsnap->size); + + spin_lock(&mdsc->snap_flush_lock); +- if (list_empty(&ci->i_snap_flush_item)) ++ if (list_empty(&ci->i_snap_flush_item)) { ++ ihold(inode); + list_add_tail(&ci->i_snap_flush_item, &mdsc->snap_flush_list); ++ } + spin_unlock(&mdsc->snap_flush_lock); + return 1; /* caller may want to ceph_flush_snaps */ + } +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index f72896384dbc9..84b4fc9833e38 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -5799,7 +5799,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) + ext4_group_t g; + unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO; + int err = 0; +- int enable_rw = 0; + #ifdef CONFIG_QUOTA + int enable_quota = 0; + int i, j; +@@ -5992,7 +5991,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) + if (err) + goto restore_opts; + +- enable_rw = 1; ++ sb->s_flags &= ~SB_RDONLY; + if (ext4_has_feature_mmp(sb)) { + err = ext4_multi_mount_protect(sb, + le64_to_cpu(es->s_mmp_block)); +@@ -6039,9 +6038,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) + if (!test_opt(sb, BLOCK_VALIDITY) && sbi->s_system_blks) + ext4_release_system_zone(sb); + +- if (enable_rw) +- sb->s_flags &= ~SB_RDONLY; +- + /* + * Reinitialize lazy itable initialization thread based on + * current settings +diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c +index 10b2f570d4003..ed39101dc7b6f 100644 +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -1999,8 +1999,9 @@ inserted: + else { + u32 ref; + ++#ifdef EXT4_XATTR_DEBUG + WARN_ON_ONCE(dquot_initialize_needed(inode)); +- ++#endif + /* The old block is released after updating + the inode. */ + error = dquot_alloc_block(inode, +@@ -2062,8 +2063,9 @@ inserted: + /* We need to allocate a new block */ + ext4_fsblk_t goal, block; + ++#ifdef EXT4_XATTR_DEBUG + WARN_ON_ONCE(dquot_initialize_needed(inode)); +- ++#endif + goal = ext4_group_first_block_no(sb, + EXT4_I(inode)->i_block_group); + block = ext4_new_meta_blocks(handle, inode, goal, 0, +diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c +index a7e7d68256e00..2501c11d8c468 100644 +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -403,9 +403,9 @@ out: + if (!strcmp(a->attr.name, "iostat_period_ms")) { + if (t < MIN_IOSTAT_PERIOD_MS || t > MAX_IOSTAT_PERIOD_MS) + return -EINVAL; +- spin_lock(&sbi->iostat_lock); ++ spin_lock_irq(&sbi->iostat_lock); + sbi->iostat_period_ms = (unsigned int)t; +- spin_unlock(&sbi->iostat_lock); ++ spin_unlock_irq(&sbi->iostat_lock); + return count; + } + +diff --git a/fs/xfs/xfs_buf_item_recover.c b/fs/xfs/xfs_buf_item_recover.c +index b374c9cee1177..a053b0bf79308 100644 +--- a/fs/xfs/xfs_buf_item_recover.c ++++ b/fs/xfs/xfs_buf_item_recover.c +@@ -924,6 +924,16 @@ xlog_recover_buf_commit_pass2( + if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) { + trace_xfs_log_recover_buf_skip(log, buf_f); + xlog_recover_validate_buf_type(mp, bp, buf_f, NULLCOMMITLSN); ++ ++ /* ++ * We're skipping replay of this buffer log item due to the log ++ * item LSN being behind the ondisk buffer. Verify the buffer ++ * contents since we aren't going to run the write verifier. ++ */ ++ if (bp->b_ops) { ++ bp->b_ops->verify_read(bp); ++ error = bp->b_error; ++ } + goto out_release; + } + +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index 9ef63bc14b002..24fe2cd4b0e8d 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -744,8 +744,11 @@ static inline void rps_record_sock_flow(struct rps_sock_flow_table *table, + /* We only give a hint, preemption can change CPU under us */ + val |= raw_smp_processor_id(); + +- if (table->ents[index] != val) +- table->ents[index] = val; ++ /* The following WRITE_ONCE() is paired with the READ_ONCE() ++ * here, and another one in get_rps_cpu(). ++ */ ++ if (READ_ONCE(table->ents[index]) != val) ++ WRITE_ONCE(table->ents[index], val); + } + } + +diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h +index c0cf20b19e637..528be670006f4 100644 +--- a/include/linux/usb/hcd.h ++++ b/include/linux/usb/hcd.h +@@ -504,6 +504,11 @@ void *hcd_buffer_alloc(struct usb_bus *bus, size_t size, + void hcd_buffer_free(struct usb_bus *bus, size_t size, + void *addr, dma_addr_t dma); + ++void *hcd_buffer_alloc_pages(struct usb_hcd *hcd, ++ size_t size, gfp_t mem_flags, dma_addr_t *dma); ++void hcd_buffer_free_pages(struct usb_hcd *hcd, ++ size_t size, void *addr, dma_addr_t dma); ++ + /* generic bus glue, needed for host controllers that don't use PCI */ + extern irqreturn_t usb_hcd_irq(int irq, void *__hcd); + +diff --git a/include/net/bond_alb.h b/include/net/bond_alb.h +index 191c36afa1f4a..9dc082b2d5430 100644 +--- a/include/net/bond_alb.h ++++ b/include/net/bond_alb.h +@@ -156,8 +156,8 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave); + void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave); + void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link); + void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave); +-int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev); +-int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev); ++netdev_tx_t bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev); ++netdev_tx_t bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev); + struct slave *bond_xmit_alb_slave_get(struct bonding *bond, + struct sk_buff *skb); + struct slave *bond_xmit_tlb_slave_get(struct bonding *bond, +diff --git a/include/net/neighbour.h b/include/net/neighbour.h +index d5767e25509cc..abb22cfd4827f 100644 +--- a/include/net/neighbour.h ++++ b/include/net/neighbour.h +@@ -174,7 +174,7 @@ struct pneigh_entry { + struct net_device *dev; + u8 flags; + u8 protocol; +- u8 key[]; ++ u32 key[]; + }; + + /* +diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h +index 50d5ffbad473e..ba781e0aaf566 100644 +--- a/include/net/pkt_sched.h ++++ b/include/net/pkt_sched.h +@@ -129,6 +129,8 @@ static inline void qdisc_run(struct Qdisc *q) + } + } + ++extern const struct nla_policy rtm_tca_policy[TCA_MAX + 1]; ++ + /* Calculate maximal size of packet seen by hard_start_xmit + routine of this device. + */ +diff --git a/include/net/rpl.h b/include/net/rpl.h +index 308ef0a05caef..30fe780d1e7c8 100644 +--- a/include/net/rpl.h ++++ b/include/net/rpl.h +@@ -23,9 +23,6 @@ static inline int rpl_init(void) + static inline void rpl_exit(void) {} + #endif + +-/* Worst decompression memory usage ipv6 address (16) + pad 7 */ +-#define IPV6_RPL_SRH_WORST_SWAP_SIZE (sizeof(struct in6_addr) + 7) +- + size_t ipv6_rpl_srh_size(unsigned char n, unsigned char cmpri, + unsigned char cmpre); + +diff --git a/include/net/sock.h b/include/net/sock.h +index 3da0601b573ed..51b499d745499 100644 +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -1073,8 +1073,12 @@ static inline void sock_rps_record_flow(const struct sock *sk) + * OR an additional socket flag + * [1] : sk_state and sk_prot are in the same cache line. + */ +- if (sk->sk_state == TCP_ESTABLISHED) +- sock_rps_record_flow_hash(sk->sk_rxhash); ++ if (sk->sk_state == TCP_ESTABLISHED) { ++ /* This READ_ONCE() is paired with the WRITE_ONCE() ++ * from sock_rps_save_rxhash() and sock_rps_reset_rxhash(). ++ */ ++ sock_rps_record_flow_hash(READ_ONCE(sk->sk_rxhash)); ++ } + } + #endif + } +@@ -1083,15 +1087,19 @@ static inline void sock_rps_save_rxhash(struct sock *sk, + const struct sk_buff *skb) + { + #ifdef CONFIG_RPS +- if (unlikely(sk->sk_rxhash != skb->hash)) +- sk->sk_rxhash = skb->hash; ++ /* The following WRITE_ONCE() is paired with the READ_ONCE() ++ * here, and another one in sock_rps_record_flow(). ++ */ ++ if (unlikely(READ_ONCE(sk->sk_rxhash) != skb->hash)) ++ WRITE_ONCE(sk->sk_rxhash, skb->hash); + #endif + } + + static inline void sock_rps_reset_rxhash(struct sock *sk) + { + #ifdef CONFIG_RPS +- sk->sk_rxhash = 0; ++ /* Paired with READ_ONCE() in sock_rps_record_flow() */ ++ WRITE_ONCE(sk->sk_rxhash, 0); + #endif + } + +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index 94e51d36fb497..9e90d1e7af2c8 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -1128,13 +1128,23 @@ static const struct bpf_func_proto bpf_send_signal_thread_proto = { + + BPF_CALL_3(bpf_d_path, struct path *, path, char *, buf, u32, sz) + { ++ struct path copy; + long len; + char *p; + + if (!sz) + return 0; + +- p = d_path(path, buf, sz); ++ /* ++ * The path pointer is verified as trusted and safe to use, ++ * but let's double check it's valid anyway to workaround ++ * potentially broken verifier. ++ */ ++ len = copy_from_kernel_nofault(©, path, sizeof(*path)); ++ if (len < 0) ++ return len; ++ ++ p = d_path(©, buf, sz); + if (IS_ERR(p)) { + len = PTR_ERR(p); + } else { +diff --git a/lib/cpu_rmap.c b/lib/cpu_rmap.c +index e77f12bb3c774..1833ad73de6fc 100644 +--- a/lib/cpu_rmap.c ++++ b/lib/cpu_rmap.c +@@ -268,8 +268,8 @@ static void irq_cpu_rmap_release(struct kref *ref) + struct irq_glue *glue = + container_of(ref, struct irq_glue, notify.kref); + +- cpu_rmap_put(glue->rmap); + glue->rmap->obj[glue->index] = NULL; ++ cpu_rmap_put(glue->rmap); + kfree(glue); + } + +diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c +index 338e4e9c33b8a..ddd3b4c70a516 100644 +--- a/net/batman-adv/distributed-arp-table.c ++++ b/net/batman-adv/distributed-arp-table.c +@@ -102,7 +102,6 @@ static void batadv_dat_purge(struct work_struct *work); + */ + static void batadv_dat_start_timer(struct batadv_priv *bat_priv) + { +- INIT_DELAYED_WORK(&bat_priv->dat.work, batadv_dat_purge); + queue_delayed_work(batadv_event_workqueue, &bat_priv->dat.work, + msecs_to_jiffies(10000)); + } +@@ -822,6 +821,7 @@ int batadv_dat_init(struct batadv_priv *bat_priv) + if (!bat_priv->dat.hash) + return -ENOMEM; + ++ INIT_DELAYED_WORK(&bat_priv->dat.work, batadv_dat_purge); + batadv_dat_start_timer(bat_priv); + + batadv_tvlv_handler_register(bat_priv, batadv_dat_tvlv_ogm_handler_v1, +diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c +index 08c473aa0113d..bd6f20ef13f35 100644 +--- a/net/bluetooth/hci_core.c ++++ b/net/bluetooth/hci_core.c +@@ -2685,10 +2685,10 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) + + int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type) + { +- struct smp_ltk *k; ++ struct smp_ltk *k, *tmp; + int removed = 0; + +- list_for_each_entry_rcu(k, &hdev->long_term_keys, list) { ++ list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { + if (bacmp(bdaddr, &k->bdaddr) || k->bdaddr_type != bdaddr_type) + continue; + +@@ -2704,9 +2704,9 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type) + + void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type) + { +- struct smp_irk *k; ++ struct smp_irk *k, *tmp; + +- list_for_each_entry_rcu(k, &hdev->identity_resolving_keys, list) { ++ list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) { + if (bacmp(bdaddr, &k->bdaddr) || k->addr_type != addr_type) + continue; + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index b85ce276e2a3c..568f0f072b3df 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -4303,6 +4303,10 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn, + result = __le16_to_cpu(rsp->result); + status = __le16_to_cpu(rsp->status); + ++ if (result == L2CAP_CR_SUCCESS && (dcid < L2CAP_CID_DYN_START || ++ dcid > L2CAP_CID_DYN_END)) ++ return -EPROTO; ++ + BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", + dcid, scid, result, status); + +@@ -4334,6 +4338,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn, + + switch (result) { + case L2CAP_CR_SUCCESS: ++ if (__l2cap_get_chan_by_dcid(conn, dcid)) { ++ err = -EBADSLT; ++ break; ++ } ++ + l2cap_state_change(chan, BT_CONFIG); + chan->ident = 0; + chan->dcid = dcid; +@@ -4659,7 +4668,9 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, + + chan->ops->set_shutdown(chan); + ++ l2cap_chan_unlock(chan); + mutex_lock(&conn->chan_lock); ++ l2cap_chan_lock(chan); + l2cap_chan_del(chan, ECONNRESET); + mutex_unlock(&conn->chan_lock); + +@@ -4698,7 +4709,9 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, + return 0; + } + ++ l2cap_chan_unlock(chan); + mutex_lock(&conn->chan_lock); ++ l2cap_chan_lock(chan); + l2cap_chan_del(chan, 0); + mutex_unlock(&conn->chan_lock); + +diff --git a/net/can/j1939/main.c b/net/can/j1939/main.c +index 9da8fbc81c04a..9169ef174ff09 100644 +--- a/net/can/j1939/main.c ++++ b/net/can/j1939/main.c +@@ -122,7 +122,7 @@ static void j1939_can_recv(struct sk_buff *iskb, void *data) + #define J1939_CAN_ID CAN_EFF_FLAG + #define J1939_CAN_MASK (CAN_EFF_FLAG | CAN_RTR_FLAG) + +-static DEFINE_SPINLOCK(j1939_netdev_lock); ++static DEFINE_MUTEX(j1939_netdev_lock); + + static struct j1939_priv *j1939_priv_create(struct net_device *ndev) + { +@@ -216,7 +216,7 @@ static void __j1939_rx_release(struct kref *kref) + j1939_can_rx_unregister(priv); + j1939_ecu_unmap_all(priv); + j1939_priv_set(priv->ndev, NULL); +- spin_unlock(&j1939_netdev_lock); ++ mutex_unlock(&j1939_netdev_lock); + } + + /* get pointer to priv without increasing ref counter */ +@@ -244,9 +244,9 @@ static struct j1939_priv *j1939_priv_get_by_ndev(struct net_device *ndev) + { + struct j1939_priv *priv; + +- spin_lock(&j1939_netdev_lock); ++ mutex_lock(&j1939_netdev_lock); + priv = j1939_priv_get_by_ndev_locked(ndev); +- spin_unlock(&j1939_netdev_lock); ++ mutex_unlock(&j1939_netdev_lock); + + return priv; + } +@@ -256,14 +256,14 @@ struct j1939_priv *j1939_netdev_start(struct net_device *ndev) + struct j1939_priv *priv, *priv_new; + int ret; + +- spin_lock(&j1939_netdev_lock); ++ mutex_lock(&j1939_netdev_lock); + priv = j1939_priv_get_by_ndev_locked(ndev); + if (priv) { + kref_get(&priv->rx_kref); +- spin_unlock(&j1939_netdev_lock); ++ mutex_unlock(&j1939_netdev_lock); + return priv; + } +- spin_unlock(&j1939_netdev_lock); ++ mutex_unlock(&j1939_netdev_lock); + + priv = j1939_priv_create(ndev); + if (!priv) +@@ -273,29 +273,31 @@ struct j1939_priv *j1939_netdev_start(struct net_device *ndev) + spin_lock_init(&priv->j1939_socks_lock); + INIT_LIST_HEAD(&priv->j1939_socks); + +- spin_lock(&j1939_netdev_lock); ++ mutex_lock(&j1939_netdev_lock); + priv_new = j1939_priv_get_by_ndev_locked(ndev); + if (priv_new) { + /* Someone was faster than us, use their priv and roll + * back our's. + */ + kref_get(&priv_new->rx_kref); +- spin_unlock(&j1939_netdev_lock); ++ mutex_unlock(&j1939_netdev_lock); + dev_put(ndev); + kfree(priv); + return priv_new; + } + j1939_priv_set(ndev, priv); +- spin_unlock(&j1939_netdev_lock); + + ret = j1939_can_rx_register(priv); + if (ret < 0) + goto out_priv_put; + ++ mutex_unlock(&j1939_netdev_lock); + return priv; + + out_priv_put: + j1939_priv_set(ndev, NULL); ++ mutex_unlock(&j1939_netdev_lock); ++ + dev_put(ndev); + kfree(priv); + +@@ -304,7 +306,7 @@ struct j1939_priv *j1939_netdev_start(struct net_device *ndev) + + void j1939_netdev_stop(struct j1939_priv *priv) + { +- kref_put_lock(&priv->rx_kref, __j1939_rx_release, &j1939_netdev_lock); ++ kref_put_mutex(&priv->rx_kref, __j1939_rx_release, &j1939_netdev_lock); + j1939_priv_put(priv); + } + +diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c +index 76cd5f43faf7a..906a08d38c1c8 100644 +--- a/net/can/j1939/socket.c ++++ b/net/can/j1939/socket.c +@@ -1013,6 +1013,11 @@ void j1939_sk_errqueue(struct j1939_session *session, + + void j1939_sk_send_loop_abort(struct sock *sk, int err) + { ++ struct j1939_sock *jsk = j1939_sk(sk); ++ ++ if (jsk->state & J1939_SOCK_ERRQUEUE) ++ return; ++ + sk->sk_err = err; + + sk->sk_error_report(sk); +diff --git a/net/core/dev.c b/net/core/dev.c +index 29e6e11c481c6..f4aad9b00cc90 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4385,8 +4385,10 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, + u32 next_cpu; + u32 ident; + +- /* First check into global flow table if there is a match */ +- ident = sock_flow_table->ents[hash & sock_flow_table->mask]; ++ /* First check into global flow table if there is a match. ++ * This READ_ONCE() pairs with WRITE_ONCE() from rps_record_sock_flow(). ++ */ ++ ident = READ_ONCE(sock_flow_table->ents[hash & sock_flow_table->mask]); + if ((ident ^ hash) & ~rps_cpu_mask) + goto try_rps; + +diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c +index 3a34e9768bff0..5aa8bde3e9c8e 100644 +--- a/net/ipv4/sysctl_net_ipv4.c ++++ b/net/ipv4/sysctl_net_ipv4.c +@@ -31,7 +31,6 @@ + static int two = 2; + static int four = 4; + static int thousand = 1000; +-static int gso_max_segs = GSO_MAX_SEGS; + static int tcp_retr1_max = 255; + static int ip_local_port_range_min[] = { 1, 1 }; + static int ip_local_port_range_max[] = { 65535, 65535 }; +@@ -1193,7 +1192,6 @@ static struct ctl_table ipv4_net_table[] = { + .mode = 0644, + .proc_handler = proc_dou8vec_minmax, + .extra1 = SYSCTL_ONE, +- .extra2 = &gso_max_segs, + }, + { + .procname = "tcp_min_rtt_wlen", +diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c +index 4932dea9820ba..cdad9019c77c4 100644 +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -552,24 +552,6 @@ looped_back: + return -1; + } + +- if (skb_cloned(skb)) { +- if (pskb_expand_head(skb, IPV6_RPL_SRH_WORST_SWAP_SIZE, 0, +- GFP_ATOMIC)) { +- __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), +- IPSTATS_MIB_OUTDISCARDS); +- kfree_skb(skb); +- return -1; +- } +- } else { +- err = skb_cow_head(skb, IPV6_RPL_SRH_WORST_SWAP_SIZE); +- if (unlikely(err)) { +- kfree_skb(skb); +- return -1; +- } +- } +- +- hdr = (struct ipv6_rpl_sr_hdr *)skb_transport_header(skb); +- + if (!pskb_may_pull(skb, ipv6_rpl_srh_size(n, hdr->cmpri, + hdr->cmpre))) { + kfree_skb(skb); +@@ -615,6 +597,17 @@ looped_back: + skb_pull(skb, ((hdr->hdrlen + 1) << 3)); + skb_postpull_rcsum(skb, oldhdr, + sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3)); ++ if (unlikely(!hdr->segments_left)) { ++ if (pskb_expand_head(skb, sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3), 0, ++ GFP_ATOMIC)) { ++ __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); ++ kfree_skb(skb); ++ kfree(buf); ++ return -1; ++ } ++ ++ oldhdr = ipv6_hdr(skb); ++ } + skb_push(skb, ((chdr->hdrlen + 1) << 3) + sizeof(struct ipv6hdr)); + skb_reset_network_header(skb); + skb_mac_header_rebuild(skb); +diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c +index 1bf6ab83644b3..55ac0cc12657c 100644 +--- a/net/netfilter/ipset/ip_set_core.c ++++ b/net/netfilter/ipset/ip_set_core.c +@@ -1704,6 +1704,14 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set, + bool eexist = flags & IPSET_FLAG_EXIST, retried = false; + + do { ++ if (retried) { ++ __ip_set_get(set); ++ nfnl_unlock(NFNL_SUBSYS_IPSET); ++ cond_resched(); ++ nfnl_lock(NFNL_SUBSYS_IPSET); ++ __ip_set_put(set); ++ } ++ + ip_set_lock(set); + ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried); + ip_set_unlock(set); +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 193a18bfddc0a..f82a234ac53a1 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -2075,6 +2075,9 @@ static int nf_confirm_cthelper(struct sk_buff *skb, struct nf_conn *ct, + return 0; + + helper = rcu_dereference(help->helper); ++ if (!helper) ++ return 0; ++ + if (!(helper->flags & NF_CT_HELPER_F_USERSPACE)) + return 0; + +diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c +index 53d315ed94307..befe42aad04ba 100644 +--- a/net/sched/cls_api.c ++++ b/net/sched/cls_api.c +@@ -41,8 +41,6 @@ + #include <net/tc_act/tc_gate.h> + #include <net/flow_offload.h> + +-extern const struct nla_policy rtm_tca_policy[TCA_MAX + 1]; +- + /* The list of all installed classifier types */ + static LIST_HEAD(tcf_proto_base); + +@@ -2774,6 +2772,7 @@ static int tc_chain_tmplt_add(struct tcf_chain *chain, struct net *net, + return PTR_ERR(ops); + if (!ops->tmplt_create || !ops->tmplt_destroy || !ops->tmplt_dump) { + NL_SET_ERR_MSG(extack, "Chain templates are not supported with specified classifier"); ++ module_put(ops->owner); + return -EOPNOTSUPP; + } + +diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c +index cf04f70e96bf1..4f6b5b6fba3ed 100644 +--- a/net/sched/sch_fq_pie.c ++++ b/net/sched/sch_fq_pie.c +@@ -201,6 +201,11 @@ out: + return NET_XMIT_CN; + } + ++static struct netlink_range_validation fq_pie_q_range = { ++ .min = 1, ++ .max = 1 << 20, ++}; ++ + static const struct nla_policy fq_pie_policy[TCA_FQ_PIE_MAX + 1] = { + [TCA_FQ_PIE_LIMIT] = {.type = NLA_U32}, + [TCA_FQ_PIE_FLOWS] = {.type = NLA_U32}, +@@ -208,7 +213,8 @@ static const struct nla_policy fq_pie_policy[TCA_FQ_PIE_MAX + 1] = { + [TCA_FQ_PIE_TUPDATE] = {.type = NLA_U32}, + [TCA_FQ_PIE_ALPHA] = {.type = NLA_U32}, + [TCA_FQ_PIE_BETA] = {.type = NLA_U32}, +- [TCA_FQ_PIE_QUANTUM] = {.type = NLA_U32}, ++ [TCA_FQ_PIE_QUANTUM] = ++ NLA_POLICY_FULL_RANGE(NLA_U32, &fq_pie_q_range), + [TCA_FQ_PIE_MEMORY_LIMIT] = {.type = NLA_U32}, + [TCA_FQ_PIE_ECN_PROB] = {.type = NLA_U32}, + [TCA_FQ_PIE_ECN] = {.type = NLA_U32}, +diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c +index 0ef15f8fba902..d5ee961ca72d5 100644 +--- a/net/smc/smc_llc.c ++++ b/net/smc/smc_llc.c +@@ -716,6 +716,8 @@ static int smc_llc_add_link_cont(struct smc_link *link, + addc_llc->num_rkeys = *num_rkeys_todo; + n = *num_rkeys_todo; + for (i = 0; i < min_t(u8, n, SMC_LLC_RKEYS_PER_CONT_MSG); i++) { ++ while (*buf_pos && !(*buf_pos)->used) ++ *buf_pos = smc_llc_get_next_rmb(lgr, buf_lst, *buf_pos); + if (!*buf_pos) { + addc_llc->num_rkeys = addc_llc->num_rkeys - + *num_rkeys_todo; +@@ -731,8 +733,6 @@ static int smc_llc_add_link_cont(struct smc_link *link, + + (*num_rkeys_todo)--; + *buf_pos = smc_llc_get_next_rmb(lgr, buf_lst, *buf_pos); +- while (*buf_pos && !(*buf_pos)->used) +- *buf_pos = smc_llc_get_next_rmb(lgr, buf_lst, *buf_pos); + } + addc_llc->hd.common.type = SMC_LLC_ADD_LINK_CONT; + addc_llc->hd.length = sizeof(struct smc_llc_msg_add_link_cont); +diff --git a/scripts/gcc-plugins/gcc-common.h b/scripts/gcc-plugins/gcc-common.h +index 9ad76b7f3f10e..6d4563b8a52c6 100644 +--- a/scripts/gcc-plugins/gcc-common.h ++++ b/scripts/gcc-plugins/gcc-common.h +@@ -108,7 +108,13 @@ + #include "varasm.h" + #include "stor-layout.h" + #include "internal-fn.h" ++#endif ++ ++#include "gimple.h" ++ ++#if BUILDING_GCC_VERSION >= 4009 + #include "gimple-expr.h" ++#include "gimple-iterator.h" + #include "gimple-fold.h" + #include "context.h" + #include "tree-ssa-alias.h" +@@ -124,13 +130,10 @@ + #include "gimplify.h" + #endif + +-#include "gimple.h" +- + #if BUILDING_GCC_VERSION >= 4009 + #include "tree-ssa-operands.h" + #include "tree-phinodes.h" + #include "tree-cfg.h" +-#include "gimple-iterator.h" + #include "gimple-ssa.h" + #include "ssa-iterators.h" + #endif +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 21c8b474a4dfb..8a42262dd7faf 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -11162,6 +11162,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB), + SND_PCI_QUIRK(0x103c, 0x872b, "HP", ALC897_FIXUP_HP_HSMIC_VERB), + SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2), ++ SND_PCI_QUIRK(0x103c, 0x8768, "HP Slim Desktop S01", ALC671_FIXUP_HP_HEADSET_MIC2), + SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2), + SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2), + SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE), +@@ -11183,6 +11184,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { + SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE), + SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS), + SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN), ++ SND_PCI_QUIRK(0x17aa, 0x1064, "Lenovo P3 Tower", ALC897_FIXUP_HEADSET_MIC_PIN), + SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN), + SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN), + SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN), +diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c +index 15b3f47fbfa35..9f66f6dc2c67f 100644 +--- a/sound/soc/codecs/wsa881x.c ++++ b/sound/soc/codecs/wsa881x.c +@@ -646,7 +646,6 @@ static struct regmap_config wsa881x_regmap_config = { + .readable_reg = wsa881x_readable_register, + .reg_format_endian = REGMAP_ENDIAN_NATIVE, + .val_format_endian = REGMAP_ENDIAN_NATIVE, +- .can_multi_write = true, + }; + + enum {
