| From stable+bounces-172456-greg=kroah.com@vger.kernel.org Fri Aug 22 17:17:59 2025 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 22 Aug 2025 11:10:13 -0400 |
| Subject: scsi: mpi3mr: Serialize admin queue BAR writes on 32-bit systems |
| To: stable@vger.kernel.org |
| Cc: Ranjan Kumar <ranjan.kumar@broadcom.com>, "Martin K. Petersen" <martin.petersen@oracle.com>, Sasha Levin <sashal@kernel.org> |
| Message-ID: <20250822151013.1280211-2-sashal@kernel.org> |
| |
| From: Ranjan Kumar <ranjan.kumar@broadcom.com> |
| |
| [ Upstream commit c91e140c82eb58724c435f623702e51cc7896646 ] |
| |
| On 32-bit systems, 64-bit BAR writes to admin queue registers are |
| performed as two 32-bit writes. Without locking, this can cause partial |
| writes when accessed concurrently. |
| |
| Updated per-queue spinlocks is used to serialize these writes and prevent |
| race conditions. |
| |
| Fixes: 824a156633df ("scsi: mpi3mr: Base driver code") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com> |
| Link: https://lore.kernel.org/r/20250627194539.48851-4-ranjan.kumar@broadcom.com |
| Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/scsi/mpi3mr/mpi3mr.h | 4 ++++ |
| drivers/scsi/mpi3mr/mpi3mr_fw.c | 15 +++++++++++---- |
| drivers/scsi/mpi3mr/mpi3mr_os.c | 2 ++ |
| 3 files changed, 17 insertions(+), 4 deletions(-) |
| |
| --- a/drivers/scsi/mpi3mr/mpi3mr.h |
| +++ b/drivers/scsi/mpi3mr/mpi3mr.h |
| @@ -1005,6 +1005,8 @@ struct scmd_priv { |
| * @logdata_buf: Circular buffer to store log data entries |
| * @logdata_buf_idx: Index of entry in buffer to store |
| * @logdata_entry_sz: log data entry size |
| + * @adm_req_q_bar_writeq_lock: Admin request queue lock |
| + * @adm_reply_q_bar_writeq_lock: Admin reply queue lock |
| * @pend_large_data_sz: Counter to track pending large data |
| * @io_throttle_data_length: I/O size to track in 512b blocks |
| * @io_throttle_high: I/O size to start throttle in 512b blocks |
| @@ -1186,6 +1188,8 @@ struct mpi3mr_ioc { |
| u8 *logdata_buf; |
| u16 logdata_buf_idx; |
| u16 logdata_entry_sz; |
| + spinlock_t adm_req_q_bar_writeq_lock; |
| + spinlock_t adm_reply_q_bar_writeq_lock; |
| |
| atomic_t pend_large_data_sz; |
| u32 io_throttle_data_length; |
| --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c |
| +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c |
| @@ -23,17 +23,22 @@ module_param(poll_queues, int, 0444); |
| MODULE_PARM_DESC(poll_queues, "Number of queues for io_uring poll mode. (Range 1 - 126)"); |
| |
| #if defined(writeq) && defined(CONFIG_64BIT) |
| -static inline void mpi3mr_writeq(__u64 b, void __iomem *addr) |
| +static inline void mpi3mr_writeq(__u64 b, void __iomem *addr, |
| + spinlock_t *write_queue_lock) |
| { |
| writeq(b, addr); |
| } |
| #else |
| -static inline void mpi3mr_writeq(__u64 b, void __iomem *addr) |
| +static inline void mpi3mr_writeq(__u64 b, void __iomem *addr, |
| + spinlock_t *write_queue_lock) |
| { |
| __u64 data_out = b; |
| + unsigned long flags; |
| |
| + spin_lock_irqsave(write_queue_lock, flags); |
| writel((u32)(data_out), addr); |
| writel((u32)(data_out >> 32), (addr + 4)); |
| + spin_unlock_irqrestore(write_queue_lock, flags); |
| } |
| #endif |
| |
| @@ -2662,9 +2667,11 @@ static int mpi3mr_setup_admin_qpair(stru |
| (mrioc->num_admin_req); |
| writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries); |
| mpi3mr_writeq(mrioc->admin_req_dma, |
| - &mrioc->sysif_regs->admin_request_queue_address); |
| + &mrioc->sysif_regs->admin_request_queue_address, |
| + &mrioc->adm_req_q_bar_writeq_lock); |
| mpi3mr_writeq(mrioc->admin_reply_dma, |
| - &mrioc->sysif_regs->admin_reply_queue_address); |
| + &mrioc->sysif_regs->admin_reply_queue_address, |
| + &mrioc->adm_reply_q_bar_writeq_lock); |
| writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi); |
| writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); |
| return retval; |
| --- a/drivers/scsi/mpi3mr/mpi3mr_os.c |
| +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c |
| @@ -4966,6 +4966,8 @@ mpi3mr_probe(struct pci_dev *pdev, const |
| spin_lock_init(&mrioc->tgtdev_lock); |
| spin_lock_init(&mrioc->watchdog_lock); |
| spin_lock_init(&mrioc->chain_buf_lock); |
| + spin_lock_init(&mrioc->adm_req_q_bar_writeq_lock); |
| + spin_lock_init(&mrioc->adm_reply_q_bar_writeq_lock); |
| spin_lock_init(&mrioc->sas_node_lock); |
| |
| INIT_LIST_HEAD(&mrioc->fwevt_list); |