1e2cf422bSJames Smart // SPDX-License-Identifier: GPL-2.0 2e2cf422bSJames Smart /* 3e2cf422bSJames Smart * Copyright (C) 2021 Broadcom. All Rights Reserved. The term 4e2cf422bSJames Smart * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 5e2cf422bSJames Smart */ 6e2cf422bSJames Smart 7e2cf422bSJames Smart #include "efct_driver.h" 8e2cf422bSJames Smart #include "efct_hw.h" 9e2cf422bSJames Smart #include "efct_io.h" 10e2cf422bSJames Smart 11e2cf422bSJames Smart struct efct_io_pool { 12e2cf422bSJames Smart struct efct *efct; 13e2cf422bSJames Smart spinlock_t lock; /* IO pool lock */ 14e2cf422bSJames Smart u32 io_num_ios; /* Total IOs allocated */ 15e2cf422bSJames Smart struct efct_io *ios[EFCT_NUM_SCSI_IOS]; 16e2cf422bSJames Smart struct list_head freelist; 17e2cf422bSJames Smart 18e2cf422bSJames Smart }; 19e2cf422bSJames Smart 20e2cf422bSJames Smart struct efct_io_pool * 21e2cf422bSJames Smart efct_io_pool_create(struct efct *efct, u32 num_sgl) 22e2cf422bSJames Smart { 23e2cf422bSJames Smart u32 i = 0; 24e2cf422bSJames Smart struct efct_io_pool *io_pool; 25e2cf422bSJames Smart struct efct_io *io; 26e2cf422bSJames Smart 27e2cf422bSJames Smart /* Allocate the IO pool */ 28e2cf422bSJames Smart io_pool = kzalloc(sizeof(*io_pool), GFP_KERNEL); 29e2cf422bSJames Smart if (!io_pool) 30e2cf422bSJames Smart return NULL; 31e2cf422bSJames Smart 32e2cf422bSJames Smart io_pool->efct = efct; 33e2cf422bSJames Smart INIT_LIST_HEAD(&io_pool->freelist); 34e2cf422bSJames Smart /* initialize IO pool lock */ 35e2cf422bSJames Smart spin_lock_init(&io_pool->lock); 36e2cf422bSJames Smart 37e2cf422bSJames Smart for (i = 0; i < EFCT_NUM_SCSI_IOS; i++) { 38e2cf422bSJames Smart io = kzalloc(sizeof(*io), GFP_KERNEL); 39e2cf422bSJames Smart if (!io) 40e2cf422bSJames Smart break; 41e2cf422bSJames Smart 42e2cf422bSJames Smart io_pool->io_num_ios++; 43e2cf422bSJames Smart io_pool->ios[i] = io; 44e2cf422bSJames Smart io->tag = i; 45e2cf422bSJames Smart io->instance_index = i; 46e2cf422bSJames Smart 47e2cf422bSJames Smart /* Allocate a response buffer */ 48e2cf422bSJames Smart io->rspbuf.size = SCSI_RSP_BUF_LENGTH; 49e2cf422bSJames Smart io->rspbuf.virt = dma_alloc_coherent(&efct->pci->dev, 50e2cf422bSJames Smart io->rspbuf.size, 51*efac162aSChristoph Hellwig &io->rspbuf.phys, GFP_KERNEL); 52e2cf422bSJames Smart if (!io->rspbuf.virt) { 53e2cf422bSJames Smart efc_log_err(efct, "dma_alloc rspbuf failed\n"); 54e2cf422bSJames Smart efct_io_pool_free(io_pool); 55e2cf422bSJames Smart return NULL; 56e2cf422bSJames Smart } 57e2cf422bSJames Smart 58e2cf422bSJames Smart /* Allocate SGL */ 59e2cf422bSJames Smart io->sgl = kzalloc(sizeof(*io->sgl) * num_sgl, GFP_KERNEL); 60e2cf422bSJames Smart if (!io->sgl) { 61e2cf422bSJames Smart efct_io_pool_free(io_pool); 62e2cf422bSJames Smart return NULL; 63e2cf422bSJames Smart } 64e2cf422bSJames Smart 65e2cf422bSJames Smart memset(io->sgl, 0, sizeof(*io->sgl) * num_sgl); 66e2cf422bSJames Smart io->sgl_allocated = num_sgl; 67e2cf422bSJames Smart io->sgl_count = 0; 68e2cf422bSJames Smart 69e2cf422bSJames Smart INIT_LIST_HEAD(&io->list_entry); 70e2cf422bSJames Smart list_add_tail(&io->list_entry, &io_pool->freelist); 71e2cf422bSJames Smart } 72e2cf422bSJames Smart 73e2cf422bSJames Smart return io_pool; 74e2cf422bSJames Smart } 75e2cf422bSJames Smart 76e2cf422bSJames Smart int 77e2cf422bSJames Smart efct_io_pool_free(struct efct_io_pool *io_pool) 78e2cf422bSJames Smart { 79e2cf422bSJames Smart struct efct *efct; 80e2cf422bSJames Smart u32 i; 81e2cf422bSJames Smart struct efct_io *io; 82e2cf422bSJames Smart 83e2cf422bSJames Smart if (io_pool) { 84e2cf422bSJames Smart efct = io_pool->efct; 85e2cf422bSJames Smart 86e2cf422bSJames Smart for (i = 0; i < io_pool->io_num_ios; i++) { 87e2cf422bSJames Smart io = io_pool->ios[i]; 88e2cf422bSJames Smart if (!io) 89e2cf422bSJames Smart continue; 90e2cf422bSJames Smart 91e2cf422bSJames Smart kfree(io->sgl); 92e2cf422bSJames Smart dma_free_coherent(&efct->pci->dev, 93e2cf422bSJames Smart io->rspbuf.size, io->rspbuf.virt, 94e2cf422bSJames Smart io->rspbuf.phys); 95e2cf422bSJames Smart memset(&io->rspbuf, 0, sizeof(struct efc_dma)); 96e2cf422bSJames Smart } 97e2cf422bSJames Smart 98e2cf422bSJames Smart kfree(io_pool); 99e2cf422bSJames Smart efct->xport->io_pool = NULL; 100e2cf422bSJames Smart } 101e2cf422bSJames Smart 102e2cf422bSJames Smart return 0; 103e2cf422bSJames Smart } 104e2cf422bSJames Smart 105e2cf422bSJames Smart struct efct_io * 106e2cf422bSJames Smart efct_io_pool_io_alloc(struct efct_io_pool *io_pool) 107e2cf422bSJames Smart { 108e2cf422bSJames Smart struct efct_io *io = NULL; 109e2cf422bSJames Smart struct efct *efct; 110e2cf422bSJames Smart unsigned long flags = 0; 111e2cf422bSJames Smart 112e2cf422bSJames Smart efct = io_pool->efct; 113e2cf422bSJames Smart 114e2cf422bSJames Smart spin_lock_irqsave(&io_pool->lock, flags); 115e2cf422bSJames Smart 116e2cf422bSJames Smart if (!list_empty(&io_pool->freelist)) { 117e2cf422bSJames Smart io = list_first_entry(&io_pool->freelist, struct efct_io, 118e2cf422bSJames Smart list_entry); 119e2cf422bSJames Smart list_del_init(&io->list_entry); 120e2cf422bSJames Smart } 121e2cf422bSJames Smart 122e2cf422bSJames Smart spin_unlock_irqrestore(&io_pool->lock, flags); 123e2cf422bSJames Smart 124e2cf422bSJames Smart if (!io) 125e2cf422bSJames Smart return NULL; 126e2cf422bSJames Smart 127e2cf422bSJames Smart io->io_type = EFCT_IO_TYPE_MAX; 128e2cf422bSJames Smart io->hio_type = EFCT_HW_IO_MAX; 129e2cf422bSJames Smart io->hio = NULL; 130e2cf422bSJames Smart io->transferred = 0; 131e2cf422bSJames Smart io->efct = efct; 132e2cf422bSJames Smart io->timeout = 0; 133e2cf422bSJames Smart io->sgl_count = 0; 134e2cf422bSJames Smart io->tgt_task_tag = 0; 135e2cf422bSJames Smart io->init_task_tag = 0; 136e2cf422bSJames Smart io->hw_tag = 0; 137e2cf422bSJames Smart io->display_name = "pending"; 138e2cf422bSJames Smart io->seq_init = 0; 139e2cf422bSJames Smart io->io_free = 0; 140e2cf422bSJames Smart io->release = NULL; 141e2cf422bSJames Smart atomic_add_return(1, &efct->xport->io_active_count); 142e2cf422bSJames Smart atomic_add_return(1, &efct->xport->io_total_alloc); 143e2cf422bSJames Smart return io; 144e2cf422bSJames Smart } 145e2cf422bSJames Smart 146e2cf422bSJames Smart /* Free an object used to track an IO */ 147e2cf422bSJames Smart void 148e2cf422bSJames Smart efct_io_pool_io_free(struct efct_io_pool *io_pool, struct efct_io *io) 149e2cf422bSJames Smart { 150e2cf422bSJames Smart struct efct *efct; 151e2cf422bSJames Smart struct efct_hw_io *hio = NULL; 152e2cf422bSJames Smart unsigned long flags = 0; 153e2cf422bSJames Smart 154e2cf422bSJames Smart efct = io_pool->efct; 155e2cf422bSJames Smart 156e2cf422bSJames Smart spin_lock_irqsave(&io_pool->lock, flags); 157e2cf422bSJames Smart hio = io->hio; 158e2cf422bSJames Smart io->hio = NULL; 159e2cf422bSJames Smart io->io_free = 1; 160e2cf422bSJames Smart INIT_LIST_HEAD(&io->list_entry); 161e2cf422bSJames Smart list_add(&io->list_entry, &io_pool->freelist); 162e2cf422bSJames Smart spin_unlock_irqrestore(&io_pool->lock, flags); 163e2cf422bSJames Smart 164e2cf422bSJames Smart if (hio) 165e2cf422bSJames Smart efct_hw_io_free(&efct->hw, hio); 166e2cf422bSJames Smart 167e2cf422bSJames Smart atomic_sub_return(1, &efct->xport->io_active_count); 168e2cf422bSJames Smart atomic_add_return(1, &efct->xport->io_total_free); 169e2cf422bSJames Smart } 170e2cf422bSJames Smart 171e2cf422bSJames Smart /* Find an I/O given it's node and ox_id */ 172e2cf422bSJames Smart struct efct_io * 173e2cf422bSJames Smart efct_io_find_tgt_io(struct efct *efct, struct efct_node *node, 174e2cf422bSJames Smart u16 ox_id, u16 rx_id) 175e2cf422bSJames Smart { 176e2cf422bSJames Smart struct efct_io *io = NULL; 177e2cf422bSJames Smart unsigned long flags = 0; 178e2cf422bSJames Smart u8 found = false; 179e2cf422bSJames Smart 180e2cf422bSJames Smart spin_lock_irqsave(&node->active_ios_lock, flags); 181e2cf422bSJames Smart list_for_each_entry(io, &node->active_ios, list_entry) { 182e2cf422bSJames Smart if ((io->cmd_tgt && io->init_task_tag == ox_id) && 183e2cf422bSJames Smart (rx_id == 0xffff || io->tgt_task_tag == rx_id)) { 184e2cf422bSJames Smart if (kref_get_unless_zero(&io->ref)) 185e2cf422bSJames Smart found = true; 186e2cf422bSJames Smart break; 187e2cf422bSJames Smart } 188e2cf422bSJames Smart } 189e2cf422bSJames Smart spin_unlock_irqrestore(&node->active_ios_lock, flags); 190e2cf422bSJames Smart return found ? io : NULL; 191e2cf422bSJames Smart } 192