mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-10 05:39:42 -04:00
scsi: mpi3mr: Serialize admin queue BAR writes on 32-bit systems
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: 824a156633 ("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>
This commit is contained in:
committed by
Martin K. Petersen
parent
6853885b21
commit
c91e140c82
@@ -1137,6 +1137,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
|
||||
@@ -1339,6 +1341,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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2954,9 +2959,11 @@ static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc)
|
||||
(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;
|
||||
|
||||
@@ -5365,6 +5365,8 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
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);
|
||||
spin_lock_init(&mrioc->trigger_lock);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user