1f173c2b7SSean Bruno /* 2f173c2b7SSean Bruno * BSD LICENSE 3f173c2b7SSean Bruno * 4f173c2b7SSean Bruno * Copyright(c) 2017 Cavium, Inc.. All rights reserved. 5f173c2b7SSean Bruno * All rights reserved. 6f173c2b7SSean Bruno * 7f173c2b7SSean Bruno * Redistribution and use in source and binary forms, with or without 8f173c2b7SSean Bruno * modification, are permitted provided that the following conditions 9f173c2b7SSean Bruno * are met: 10f173c2b7SSean Bruno * 11f173c2b7SSean Bruno * * Redistributions of source code must retain the above copyright 12f173c2b7SSean Bruno * notice, this list of conditions and the following disclaimer. 13f173c2b7SSean Bruno * * Redistributions in binary form must reproduce the above copyright 14f173c2b7SSean Bruno * notice, this list of conditions and the following disclaimer in 15f173c2b7SSean Bruno * the documentation and/or other materials provided with the 16f173c2b7SSean Bruno * distribution. 17f173c2b7SSean Bruno * * Neither the name of Cavium, Inc. nor the names of its 18f173c2b7SSean Bruno * contributors may be used to endorse or promote products derived 19f173c2b7SSean Bruno * from this software without specific prior written permission. 20f173c2b7SSean Bruno * 21f173c2b7SSean Bruno * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22f173c2b7SSean Bruno * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23f173c2b7SSean Bruno * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24f173c2b7SSean Bruno * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25f173c2b7SSean Bruno * OWNER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26f173c2b7SSean Bruno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27f173c2b7SSean Bruno * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28f173c2b7SSean Bruno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29f173c2b7SSean Bruno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30f173c2b7SSean Bruno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31f173c2b7SSean Bruno * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32f173c2b7SSean Bruno */ 33f173c2b7SSean Bruno /*$FreeBSD$*/ 34f173c2b7SSean Bruno 35f173c2b7SSean Bruno #include "lio_bsd.h" 36f173c2b7SSean Bruno #include "lio_common.h" 37f173c2b7SSean Bruno #include "lio_droq.h" 38f173c2b7SSean Bruno #include "lio_iq.h" 39f173c2b7SSean Bruno #include "lio_response_manager.h" 40f173c2b7SSean Bruno #include "lio_device.h" 41f173c2b7SSean Bruno #include "lio_main.h" 42f173c2b7SSean Bruno #include "lio_network.h" 43f173c2b7SSean Bruno #include "cn23xx_pf_device.h" 44f173c2b7SSean Bruno #include "lio_rxtx.h" 45f173c2b7SSean Bruno 46f173c2b7SSean Bruno struct lio_iq_post_status { 47f173c2b7SSean Bruno int status; 48f173c2b7SSean Bruno int index; 49f173c2b7SSean Bruno }; 50f173c2b7SSean Bruno 51f173c2b7SSean Bruno static void lio_check_db_timeout(void *arg, int pending); 52f173c2b7SSean Bruno static void __lio_check_db_timeout(struct octeon_device *oct, 53f173c2b7SSean Bruno uint64_t iq_no); 54f173c2b7SSean Bruno 55f173c2b7SSean Bruno /* Return 0 on success, 1 on failure */ 56f173c2b7SSean Bruno int 57f173c2b7SSean Bruno lio_init_instr_queue(struct octeon_device *oct, union octeon_txpciq txpciq, 58f173c2b7SSean Bruno uint32_t num_descs) 59f173c2b7SSean Bruno { 60f173c2b7SSean Bruno struct lio_instr_queue *iq; 61f173c2b7SSean Bruno struct lio_iq_config *conf = NULL; 62f173c2b7SSean Bruno struct lio_tq *db_tq; 63f173c2b7SSean Bruno struct lio_request_list *request_buf; 64f173c2b7SSean Bruno bus_size_t max_size; 65f173c2b7SSean Bruno uint32_t iq_no = (uint32_t)txpciq.s.q_no; 66f173c2b7SSean Bruno uint32_t q_size; 67f173c2b7SSean Bruno int error, i; 68f173c2b7SSean Bruno 69f173c2b7SSean Bruno if (LIO_CN23XX_PF(oct)) 70f173c2b7SSean Bruno conf = &(LIO_GET_IQ_CFG(LIO_CHIP_CONF(oct, cn23xx_pf))); 71f173c2b7SSean Bruno if (conf == NULL) { 72f173c2b7SSean Bruno lio_dev_err(oct, "Unsupported Chip %x\n", oct->chip_id); 73f173c2b7SSean Bruno return (1); 74f173c2b7SSean Bruno } 75f173c2b7SSean Bruno 76f173c2b7SSean Bruno q_size = (uint32_t)conf->instr_type * num_descs; 77f173c2b7SSean Bruno iq = oct->instr_queue[iq_no]; 78f173c2b7SSean Bruno iq->oct_dev = oct; 79f173c2b7SSean Bruno 80f173c2b7SSean Bruno max_size = LIO_CN23XX_PKI_MAX_FRAME_SIZE * num_descs; 81f173c2b7SSean Bruno 82f173c2b7SSean Bruno error = bus_dma_tag_create(bus_get_dma_tag(oct->device), /* parent */ 83f173c2b7SSean Bruno 1, 0, /* alignment, bounds */ 84f173c2b7SSean Bruno BUS_SPACE_MAXADDR, /* lowaddr */ 85f173c2b7SSean Bruno BUS_SPACE_MAXADDR, /* highaddr */ 86f173c2b7SSean Bruno NULL, NULL, /* filter, filterarg */ 87f173c2b7SSean Bruno max_size, /* maxsize */ 88f173c2b7SSean Bruno LIO_MAX_SG, /* nsegments */ 89f173c2b7SSean Bruno PAGE_SIZE, /* maxsegsize */ 90f173c2b7SSean Bruno 0, /* flags */ 91f173c2b7SSean Bruno NULL, /* lockfunc */ 92f173c2b7SSean Bruno NULL, /* lockfuncarg */ 93f173c2b7SSean Bruno &iq->txtag); 94f173c2b7SSean Bruno if (error) { 95f173c2b7SSean Bruno lio_dev_err(oct, "Cannot allocate memory for instr queue %d\n", 96f173c2b7SSean Bruno iq_no); 97f173c2b7SSean Bruno return (1); 98f173c2b7SSean Bruno } 99f173c2b7SSean Bruno 1003de0952fSSean Bruno iq->base_addr = lio_dma_alloc(q_size, (vm_paddr_t *)&iq->base_addr_dma); 101f173c2b7SSean Bruno if (!iq->base_addr) { 102f173c2b7SSean Bruno lio_dev_err(oct, "Cannot allocate memory for instr queue %d\n", 103f173c2b7SSean Bruno iq_no); 104f173c2b7SSean Bruno return (1); 105f173c2b7SSean Bruno } 106f173c2b7SSean Bruno 107f173c2b7SSean Bruno iq->max_count = num_descs; 108f173c2b7SSean Bruno 109f173c2b7SSean Bruno /* 110f173c2b7SSean Bruno * Initialize a list to holds requests that have been posted to 111f173c2b7SSean Bruno * Octeon but has yet to be fetched by octeon 112f173c2b7SSean Bruno */ 113*ac2fffa4SPedro F. Giffuni iq->request_list = malloc(sizeof(*iq->request_list) * num_descs, 114f173c2b7SSean Bruno M_DEVBUF, M_NOWAIT | M_ZERO); 115f173c2b7SSean Bruno if (iq->request_list == NULL) { 116f173c2b7SSean Bruno lio_dev_err(oct, "Alloc failed for IQ[%d] nr free list\n", 117f173c2b7SSean Bruno iq_no); 118f173c2b7SSean Bruno return (1); 119f173c2b7SSean Bruno } 120f173c2b7SSean Bruno 1213de0952fSSean Bruno lio_dev_dbg(oct, "IQ[%d]: base: %p basedma: %llx count: %d\n", 1223de0952fSSean Bruno iq_no, iq->base_addr, LIO_CAST64(iq->base_addr_dma), 1233de0952fSSean Bruno iq->max_count); 124f173c2b7SSean Bruno 125f173c2b7SSean Bruno /* Create the descriptor buffer dma maps */ 126f173c2b7SSean Bruno request_buf = iq->request_list; 127f173c2b7SSean Bruno for (i = 0; i < num_descs; i++, request_buf++) { 128f173c2b7SSean Bruno error = bus_dmamap_create(iq->txtag, 0, &request_buf->map); 129f173c2b7SSean Bruno if (error) { 130f173c2b7SSean Bruno lio_dev_err(oct, "Unable to create TX DMA map\n"); 131f173c2b7SSean Bruno return (1); 132f173c2b7SSean Bruno } 133f173c2b7SSean Bruno } 134f173c2b7SSean Bruno 135f173c2b7SSean Bruno iq->txpciq.txpciq64 = txpciq.txpciq64; 136f173c2b7SSean Bruno iq->fill_cnt = 0; 137f173c2b7SSean Bruno iq->host_write_index = 0; 138f173c2b7SSean Bruno iq->octeon_read_index = 0; 139f173c2b7SSean Bruno iq->flush_index = 0; 140f173c2b7SSean Bruno iq->last_db_time = 0; 141f173c2b7SSean Bruno iq->db_timeout = (uint32_t)conf->db_timeout; 142f173c2b7SSean Bruno atomic_store_rel_int(&iq->instr_pending, 0); 143f173c2b7SSean Bruno 144f173c2b7SSean Bruno /* Initialize the lock for this instruction queue */ 145f173c2b7SSean Bruno mtx_init(&iq->lock, "Tx_lock", NULL, MTX_DEF); 146f173c2b7SSean Bruno mtx_init(&iq->post_lock, "iq_post_lock", NULL, MTX_DEF); 147f173c2b7SSean Bruno mtx_init(&iq->enq_lock, "enq_lock", NULL, MTX_DEF); 148f173c2b7SSean Bruno 149f173c2b7SSean Bruno mtx_init(&iq->iq_flush_running_lock, "iq_flush_running_lock", NULL, 150f173c2b7SSean Bruno MTX_DEF); 151f173c2b7SSean Bruno 152f173c2b7SSean Bruno oct->io_qmask.iq |= BIT_ULL(iq_no); 153f173c2b7SSean Bruno 154f173c2b7SSean Bruno /* Set the 32B/64B mode for each input queue */ 155f173c2b7SSean Bruno oct->io_qmask.iq64B |= ((conf->instr_type == 64) << iq_no); 156f173c2b7SSean Bruno iq->iqcmd_64B = (conf->instr_type == 64); 157f173c2b7SSean Bruno 158f173c2b7SSean Bruno oct->fn_list.setup_iq_regs(oct, iq_no); 159f173c2b7SSean Bruno 160f173c2b7SSean Bruno db_tq = &oct->check_db_tq[iq_no]; 161f173c2b7SSean Bruno db_tq->tq = taskqueue_create("lio_check_db_timeout", M_WAITOK, 162f173c2b7SSean Bruno taskqueue_thread_enqueue, &db_tq->tq); 163f173c2b7SSean Bruno if (db_tq->tq == NULL) { 164f173c2b7SSean Bruno lio_dev_err(oct, "check db wq create failed for iq %d\n", 165f173c2b7SSean Bruno iq_no); 166f173c2b7SSean Bruno return (1); 167f173c2b7SSean Bruno } 168f173c2b7SSean Bruno 169f173c2b7SSean Bruno TIMEOUT_TASK_INIT(db_tq->tq, &db_tq->work, 0, lio_check_db_timeout, 170f173c2b7SSean Bruno (void *)db_tq); 171f173c2b7SSean Bruno db_tq->ctxul = iq_no; 172f173c2b7SSean Bruno db_tq->ctxptr = oct; 173f173c2b7SSean Bruno 174f173c2b7SSean Bruno taskqueue_start_threads(&db_tq->tq, 1, PI_NET, 175f173c2b7SSean Bruno "lio%d_check_db_timeout:%d", 176f173c2b7SSean Bruno oct->octeon_id, iq_no); 177f173c2b7SSean Bruno taskqueue_enqueue_timeout(db_tq->tq, &db_tq->work, 1); 178f173c2b7SSean Bruno 179f173c2b7SSean Bruno /* Allocate a buf ring */ 180f173c2b7SSean Bruno oct->instr_queue[iq_no]->br = 181f173c2b7SSean Bruno buf_ring_alloc(LIO_BR_SIZE, M_DEVBUF, M_WAITOK, 182f173c2b7SSean Bruno &oct->instr_queue[iq_no]->enq_lock); 183f173c2b7SSean Bruno if (oct->instr_queue[iq_no]->br == NULL) { 184f173c2b7SSean Bruno lio_dev_err(oct, "Critical Failure setting up buf ring\n"); 185f173c2b7SSean Bruno return (1); 186f173c2b7SSean Bruno } 187f173c2b7SSean Bruno 188f173c2b7SSean Bruno return (0); 189f173c2b7SSean Bruno } 190f173c2b7SSean Bruno 191f173c2b7SSean Bruno int 192f173c2b7SSean Bruno lio_delete_instr_queue(struct octeon_device *oct, uint32_t iq_no) 193f173c2b7SSean Bruno { 194f173c2b7SSean Bruno struct lio_instr_queue *iq = oct->instr_queue[iq_no]; 195f173c2b7SSean Bruno struct lio_request_list *request_buf; 196f173c2b7SSean Bruno struct lio_mbuf_free_info *finfo; 197f173c2b7SSean Bruno uint64_t desc_size = 0, q_size; 198f173c2b7SSean Bruno int i; 199f173c2b7SSean Bruno 200f173c2b7SSean Bruno lio_dev_dbg(oct, "%s[%d]\n", __func__, iq_no); 201f173c2b7SSean Bruno 202f173c2b7SSean Bruno if (oct->check_db_tq[iq_no].tq != NULL) { 203f173c2b7SSean Bruno while (taskqueue_cancel_timeout(oct->check_db_tq[iq_no].tq, 204f173c2b7SSean Bruno &oct->check_db_tq[iq_no].work, 205f173c2b7SSean Bruno NULL)) 206f173c2b7SSean Bruno taskqueue_drain_timeout(oct->check_db_tq[iq_no].tq, 207f173c2b7SSean Bruno &oct->check_db_tq[iq_no].work); 208f173c2b7SSean Bruno taskqueue_free(oct->check_db_tq[iq_no].tq); 209f173c2b7SSean Bruno oct->check_db_tq[iq_no].tq = NULL; 210f173c2b7SSean Bruno } 211f173c2b7SSean Bruno 212f173c2b7SSean Bruno if (LIO_CN23XX_PF(oct)) 213f173c2b7SSean Bruno desc_size = 214f173c2b7SSean Bruno LIO_GET_IQ_INSTR_TYPE_CFG(LIO_CHIP_CONF(oct, cn23xx_pf)); 215f173c2b7SSean Bruno 216f173c2b7SSean Bruno request_buf = iq->request_list; 217f173c2b7SSean Bruno for (i = 0; i < iq->max_count; i++, request_buf++) { 218f173c2b7SSean Bruno if ((request_buf->reqtype == LIO_REQTYPE_NORESP_NET) || 219f173c2b7SSean Bruno (request_buf->reqtype == LIO_REQTYPE_NORESP_NET_SG)) { 220f173c2b7SSean Bruno if (request_buf->buf != NULL) { 221f173c2b7SSean Bruno finfo = request_buf->buf; 222f173c2b7SSean Bruno bus_dmamap_sync(iq->txtag, request_buf->map, 223f173c2b7SSean Bruno BUS_DMASYNC_POSTWRITE); 224f173c2b7SSean Bruno bus_dmamap_unload(iq->txtag, 225f173c2b7SSean Bruno request_buf->map); 226f173c2b7SSean Bruno m_freem(finfo->mb); 227f173c2b7SSean Bruno request_buf->buf = NULL; 228f173c2b7SSean Bruno if (request_buf->map != NULL) { 229f173c2b7SSean Bruno bus_dmamap_destroy(iq->txtag, 230f173c2b7SSean Bruno request_buf->map); 231f173c2b7SSean Bruno request_buf->map = NULL; 232f173c2b7SSean Bruno } 233f173c2b7SSean Bruno } else if (request_buf->map != NULL) { 234f173c2b7SSean Bruno bus_dmamap_unload(iq->txtag, request_buf->map); 235f173c2b7SSean Bruno bus_dmamap_destroy(iq->txtag, request_buf->map); 236f173c2b7SSean Bruno request_buf->map = NULL; 237f173c2b7SSean Bruno } 238f173c2b7SSean Bruno } 239f173c2b7SSean Bruno } 240f173c2b7SSean Bruno 241f173c2b7SSean Bruno if (iq->br != NULL) { 242f173c2b7SSean Bruno buf_ring_free(iq->br, M_DEVBUF); 243f173c2b7SSean Bruno iq->br = NULL; 244f173c2b7SSean Bruno } 245f173c2b7SSean Bruno 246f173c2b7SSean Bruno if (iq->request_list != NULL) { 247f173c2b7SSean Bruno free(iq->request_list, M_DEVBUF); 248f173c2b7SSean Bruno iq->request_list = NULL; 249f173c2b7SSean Bruno } 250f173c2b7SSean Bruno 251f173c2b7SSean Bruno if (iq->txtag != NULL) { 252f173c2b7SSean Bruno bus_dma_tag_destroy(iq->txtag); 253f173c2b7SSean Bruno iq->txtag = NULL; 254f173c2b7SSean Bruno } 255f173c2b7SSean Bruno 256f173c2b7SSean Bruno if (iq->base_addr) { 257f173c2b7SSean Bruno q_size = iq->max_count * desc_size; 258f173c2b7SSean Bruno lio_dma_free((uint32_t)q_size, iq->base_addr); 259f173c2b7SSean Bruno 260f173c2b7SSean Bruno oct->io_qmask.iq &= ~(1ULL << iq_no); 261f173c2b7SSean Bruno bzero(oct->instr_queue[iq_no], sizeof(struct lio_instr_queue)); 262f173c2b7SSean Bruno oct->num_iqs--; 263f173c2b7SSean Bruno 264f173c2b7SSean Bruno return (0); 265f173c2b7SSean Bruno } 266f173c2b7SSean Bruno 267f173c2b7SSean Bruno return (1); 268f173c2b7SSean Bruno } 269f173c2b7SSean Bruno 270f173c2b7SSean Bruno /* Return 0 on success, 1 on failure */ 271f173c2b7SSean Bruno int 272f173c2b7SSean Bruno lio_setup_iq(struct octeon_device *oct, int ifidx, int q_index, 273f173c2b7SSean Bruno union octeon_txpciq txpciq, uint32_t num_descs) 274f173c2b7SSean Bruno { 275f173c2b7SSean Bruno uint32_t iq_no = (uint32_t)txpciq.s.q_no; 276f173c2b7SSean Bruno 277f173c2b7SSean Bruno if (oct->instr_queue[iq_no]->oct_dev != NULL) { 278f173c2b7SSean Bruno lio_dev_dbg(oct, "IQ is in use. Cannot create the IQ: %d again\n", 279f173c2b7SSean Bruno iq_no); 280f173c2b7SSean Bruno oct->instr_queue[iq_no]->txpciq.txpciq64 = txpciq.txpciq64; 281f173c2b7SSean Bruno return (0); 282f173c2b7SSean Bruno } 283f173c2b7SSean Bruno 284f173c2b7SSean Bruno oct->instr_queue[iq_no]->q_index = q_index; 285f173c2b7SSean Bruno oct->instr_queue[iq_no]->ifidx = ifidx; 286f173c2b7SSean Bruno 287f173c2b7SSean Bruno if (lio_init_instr_queue(oct, txpciq, num_descs)) { 288f173c2b7SSean Bruno lio_delete_instr_queue(oct, iq_no); 289f173c2b7SSean Bruno return (1); 290f173c2b7SSean Bruno } 291f173c2b7SSean Bruno 292f173c2b7SSean Bruno oct->num_iqs++; 293f173c2b7SSean Bruno if (oct->fn_list.enable_io_queues(oct)) 294f173c2b7SSean Bruno return (1); 295f173c2b7SSean Bruno 296f173c2b7SSean Bruno return (0); 297f173c2b7SSean Bruno } 298f173c2b7SSean Bruno 299f173c2b7SSean Bruno int 300f173c2b7SSean Bruno lio_wait_for_instr_fetch(struct octeon_device *oct) 301f173c2b7SSean Bruno { 302f173c2b7SSean Bruno int i, retry = 1000, pending, instr_cnt = 0; 303f173c2b7SSean Bruno 304f173c2b7SSean Bruno do { 305f173c2b7SSean Bruno instr_cnt = 0; 306f173c2b7SSean Bruno 307f173c2b7SSean Bruno for (i = 0; i < LIO_MAX_INSTR_QUEUES(oct); i++) { 308f173c2b7SSean Bruno if (!(oct->io_qmask.iq & BIT_ULL(i))) 309f173c2b7SSean Bruno continue; 310f173c2b7SSean Bruno pending = atomic_load_acq_int( 311f173c2b7SSean Bruno &oct->instr_queue[i]->instr_pending); 312f173c2b7SSean Bruno if (pending) 313f173c2b7SSean Bruno __lio_check_db_timeout(oct, i); 314f173c2b7SSean Bruno instr_cnt += pending; 315f173c2b7SSean Bruno } 316f173c2b7SSean Bruno 317f173c2b7SSean Bruno if (instr_cnt == 0) 318f173c2b7SSean Bruno break; 319f173c2b7SSean Bruno 320f173c2b7SSean Bruno lio_sleep_timeout(1); 321f173c2b7SSean Bruno 322f173c2b7SSean Bruno } while (retry-- && instr_cnt); 323f173c2b7SSean Bruno 324f173c2b7SSean Bruno return (instr_cnt); 325f173c2b7SSean Bruno } 326f173c2b7SSean Bruno 327f173c2b7SSean Bruno static inline void 328f173c2b7SSean Bruno lio_ring_doorbell(struct octeon_device *oct, struct lio_instr_queue *iq) 329f173c2b7SSean Bruno { 330f173c2b7SSean Bruno 331f173c2b7SSean Bruno if (atomic_load_acq_int(&oct->status) == LIO_DEV_RUNNING) { 332f173c2b7SSean Bruno lio_write_csr32(oct, iq->doorbell_reg, iq->fill_cnt); 333f173c2b7SSean Bruno /* make sure doorbell write goes through */ 334f173c2b7SSean Bruno __compiler_membar(); 335f173c2b7SSean Bruno iq->fill_cnt = 0; 336f173c2b7SSean Bruno iq->last_db_time = ticks; 337f173c2b7SSean Bruno return; 338f173c2b7SSean Bruno } 339f173c2b7SSean Bruno } 340f173c2b7SSean Bruno 341f173c2b7SSean Bruno static inline void 342f173c2b7SSean Bruno __lio_copy_cmd_into_iq(struct lio_instr_queue *iq, uint8_t *cmd) 343f173c2b7SSean Bruno { 344f173c2b7SSean Bruno uint8_t *iqptr, cmdsize; 345f173c2b7SSean Bruno 346f173c2b7SSean Bruno cmdsize = ((iq->iqcmd_64B) ? 64 : 32); 347f173c2b7SSean Bruno iqptr = iq->base_addr + (cmdsize * iq->host_write_index); 348f173c2b7SSean Bruno 349f173c2b7SSean Bruno memcpy(iqptr, cmd, cmdsize); 350f173c2b7SSean Bruno } 351f173c2b7SSean Bruno 352f173c2b7SSean Bruno static inline struct lio_iq_post_status 353f173c2b7SSean Bruno __lio_post_command2(struct lio_instr_queue *iq, uint8_t *cmd) 354f173c2b7SSean Bruno { 355f173c2b7SSean Bruno struct lio_iq_post_status st; 356f173c2b7SSean Bruno 357f173c2b7SSean Bruno st.status = LIO_IQ_SEND_OK; 358f173c2b7SSean Bruno 359f173c2b7SSean Bruno /* 360f173c2b7SSean Bruno * This ensures that the read index does not wrap around to the same 361f173c2b7SSean Bruno * position if queue gets full before Octeon could fetch any instr. 362f173c2b7SSean Bruno */ 363f173c2b7SSean Bruno if (atomic_load_acq_int(&iq->instr_pending) >= 364f173c2b7SSean Bruno (int32_t)(iq->max_count - 1)) { 365f173c2b7SSean Bruno st.status = LIO_IQ_SEND_FAILED; 366f173c2b7SSean Bruno st.index = -1; 367f173c2b7SSean Bruno return (st); 368f173c2b7SSean Bruno } 369f173c2b7SSean Bruno 370f173c2b7SSean Bruno if (atomic_load_acq_int(&iq->instr_pending) >= 371f173c2b7SSean Bruno (int32_t)(iq->max_count - 2)) 372f173c2b7SSean Bruno st.status = LIO_IQ_SEND_STOP; 373f173c2b7SSean Bruno 374f173c2b7SSean Bruno __lio_copy_cmd_into_iq(iq, cmd); 375f173c2b7SSean Bruno 376f173c2b7SSean Bruno /* "index" is returned, host_write_index is modified. */ 377f173c2b7SSean Bruno st.index = iq->host_write_index; 378f173c2b7SSean Bruno iq->host_write_index = lio_incr_index(iq->host_write_index, 1, 379f173c2b7SSean Bruno iq->max_count); 380f173c2b7SSean Bruno iq->fill_cnt++; 381f173c2b7SSean Bruno 382f173c2b7SSean Bruno /* 383f173c2b7SSean Bruno * Flush the command into memory. We need to be sure the data is in 384f173c2b7SSean Bruno * memory before indicating that the instruction is pending. 385f173c2b7SSean Bruno */ 386f173c2b7SSean Bruno wmb(); 387f173c2b7SSean Bruno 388f173c2b7SSean Bruno atomic_add_int(&iq->instr_pending, 1); 389f173c2b7SSean Bruno 390f173c2b7SSean Bruno return (st); 391f173c2b7SSean Bruno } 392f173c2b7SSean Bruno 393f173c2b7SSean Bruno static inline void 394f173c2b7SSean Bruno __lio_add_to_request_list(struct lio_instr_queue *iq, int idx, void *buf, 395f173c2b7SSean Bruno int reqtype) 396f173c2b7SSean Bruno { 397f173c2b7SSean Bruno 398f173c2b7SSean Bruno iq->request_list[idx].buf = buf; 399f173c2b7SSean Bruno iq->request_list[idx].reqtype = reqtype; 400f173c2b7SSean Bruno } 401f173c2b7SSean Bruno 402f173c2b7SSean Bruno /* Can only run in process context */ 403f173c2b7SSean Bruno int 404f173c2b7SSean Bruno lio_process_iq_request_list(struct octeon_device *oct, 405f173c2b7SSean Bruno struct lio_instr_queue *iq, uint32_t budget) 406f173c2b7SSean Bruno { 407f173c2b7SSean Bruno struct lio_soft_command *sc; 408f173c2b7SSean Bruno struct octeon_instr_irh *irh = NULL; 409f173c2b7SSean Bruno struct lio_mbuf_free_info *finfo; 410f173c2b7SSean Bruno void *buf; 411f173c2b7SSean Bruno uint32_t inst_count = 0; 412f173c2b7SSean Bruno uint32_t old = iq->flush_index; 413f173c2b7SSean Bruno int reqtype; 414f173c2b7SSean Bruno 415f173c2b7SSean Bruno while (old != iq->octeon_read_index) { 416f173c2b7SSean Bruno reqtype = iq->request_list[old].reqtype; 417f173c2b7SSean Bruno buf = iq->request_list[old].buf; 418f173c2b7SSean Bruno finfo = buf; 419f173c2b7SSean Bruno 420f173c2b7SSean Bruno if (reqtype == LIO_REQTYPE_NONE) 421f173c2b7SSean Bruno goto skip_this; 422f173c2b7SSean Bruno 423f173c2b7SSean Bruno switch (reqtype) { 424f173c2b7SSean Bruno case LIO_REQTYPE_NORESP_NET: 425f173c2b7SSean Bruno lio_free_mbuf(iq, buf); 426f173c2b7SSean Bruno break; 427f173c2b7SSean Bruno case LIO_REQTYPE_NORESP_NET_SG: 428f173c2b7SSean Bruno lio_free_sgmbuf(iq, buf); 429f173c2b7SSean Bruno break; 430f173c2b7SSean Bruno case LIO_REQTYPE_RESP_NET: 431f173c2b7SSean Bruno case LIO_REQTYPE_SOFT_COMMAND: 432f173c2b7SSean Bruno sc = buf; 433f173c2b7SSean Bruno if (LIO_CN23XX_PF(oct)) 434f173c2b7SSean Bruno irh = (struct octeon_instr_irh *) 435f173c2b7SSean Bruno &sc->cmd.cmd3.irh; 436f173c2b7SSean Bruno if (irh->rflag) { 437f173c2b7SSean Bruno /* 438f173c2b7SSean Bruno * We're expecting a response from Octeon. 439f173c2b7SSean Bruno * It's up to lio_process_ordered_list() to 440f173c2b7SSean Bruno * process sc. Add sc to the ordered soft 441f173c2b7SSean Bruno * command response list because we expect 442f173c2b7SSean Bruno * a response from Octeon. 443f173c2b7SSean Bruno */ 444f173c2b7SSean Bruno mtx_lock(&oct->response_list 445f173c2b7SSean Bruno [LIO_ORDERED_SC_LIST].lock); 446f173c2b7SSean Bruno atomic_add_int(&oct->response_list 447f173c2b7SSean Bruno [LIO_ORDERED_SC_LIST]. 448f173c2b7SSean Bruno pending_req_count, 1); 449f173c2b7SSean Bruno STAILQ_INSERT_TAIL(&oct->response_list 450f173c2b7SSean Bruno [LIO_ORDERED_SC_LIST]. 451f173c2b7SSean Bruno head, &sc->node, entries); 452f173c2b7SSean Bruno mtx_unlock(&oct->response_list 453f173c2b7SSean Bruno [LIO_ORDERED_SC_LIST].lock); 454f173c2b7SSean Bruno } else { 455f173c2b7SSean Bruno if (sc->callback != NULL) { 456f173c2b7SSean Bruno /* This callback must not sleep */ 457f173c2b7SSean Bruno sc->callback(oct, LIO_REQUEST_DONE, 458f173c2b7SSean Bruno sc->callback_arg); 459f173c2b7SSean Bruno } 460f173c2b7SSean Bruno } 461f173c2b7SSean Bruno 462f173c2b7SSean Bruno break; 463f173c2b7SSean Bruno default: 464f173c2b7SSean Bruno lio_dev_err(oct, "%s Unknown reqtype: %d buf: %p at idx %d\n", 465f173c2b7SSean Bruno __func__, reqtype, buf, old); 466f173c2b7SSean Bruno } 467f173c2b7SSean Bruno 468f173c2b7SSean Bruno iq->request_list[old].buf = NULL; 469f173c2b7SSean Bruno iq->request_list[old].reqtype = 0; 470f173c2b7SSean Bruno 471f173c2b7SSean Bruno skip_this: 472f173c2b7SSean Bruno inst_count++; 473f173c2b7SSean Bruno old = lio_incr_index(old, 1, iq->max_count); 474f173c2b7SSean Bruno 475f173c2b7SSean Bruno if ((budget) && (inst_count >= budget)) 476f173c2b7SSean Bruno break; 477f173c2b7SSean Bruno } 478f173c2b7SSean Bruno 479f173c2b7SSean Bruno iq->flush_index = old; 480f173c2b7SSean Bruno 481f173c2b7SSean Bruno return (inst_count); 482f173c2b7SSean Bruno } 483f173c2b7SSean Bruno 484f173c2b7SSean Bruno /* Can only be called from process context */ 485f173c2b7SSean Bruno int 486f173c2b7SSean Bruno lio_flush_iq(struct octeon_device *oct, struct lio_instr_queue *iq, 487f173c2b7SSean Bruno uint32_t budget) 488f173c2b7SSean Bruno { 489f173c2b7SSean Bruno uint32_t inst_processed = 0; 490f173c2b7SSean Bruno uint32_t tot_inst_processed = 0; 491f173c2b7SSean Bruno int tx_done = 1; 492f173c2b7SSean Bruno 493f173c2b7SSean Bruno if (!mtx_trylock(&iq->iq_flush_running_lock)) 494f173c2b7SSean Bruno return (tx_done); 495f173c2b7SSean Bruno 496f173c2b7SSean Bruno mtx_lock(&iq->lock); 497f173c2b7SSean Bruno 498f173c2b7SSean Bruno iq->octeon_read_index = oct->fn_list.update_iq_read_idx(iq); 499f173c2b7SSean Bruno 500f173c2b7SSean Bruno do { 501f173c2b7SSean Bruno /* Process any outstanding IQ packets. */ 502f173c2b7SSean Bruno if (iq->flush_index == iq->octeon_read_index) 503f173c2b7SSean Bruno break; 504f173c2b7SSean Bruno 505f173c2b7SSean Bruno if (budget) 506f173c2b7SSean Bruno inst_processed = 507f173c2b7SSean Bruno lio_process_iq_request_list(oct, iq, 508f173c2b7SSean Bruno budget - 509f173c2b7SSean Bruno tot_inst_processed); 510f173c2b7SSean Bruno else 511f173c2b7SSean Bruno inst_processed = 512f173c2b7SSean Bruno lio_process_iq_request_list(oct, iq, 0); 513f173c2b7SSean Bruno 514f173c2b7SSean Bruno if (inst_processed) { 515f173c2b7SSean Bruno atomic_subtract_int(&iq->instr_pending, inst_processed); 516f173c2b7SSean Bruno iq->stats.instr_processed += inst_processed; 517f173c2b7SSean Bruno } 518f173c2b7SSean Bruno tot_inst_processed += inst_processed; 519f173c2b7SSean Bruno inst_processed = 0; 520f173c2b7SSean Bruno 521f173c2b7SSean Bruno } while (tot_inst_processed < budget); 522f173c2b7SSean Bruno 523f173c2b7SSean Bruno if (budget && (tot_inst_processed >= budget)) 524f173c2b7SSean Bruno tx_done = 0; 525f173c2b7SSean Bruno 526f173c2b7SSean Bruno iq->last_db_time = ticks; 527f173c2b7SSean Bruno 528f173c2b7SSean Bruno mtx_unlock(&iq->lock); 529f173c2b7SSean Bruno 530f173c2b7SSean Bruno mtx_unlock(&iq->iq_flush_running_lock); 531f173c2b7SSean Bruno 532f173c2b7SSean Bruno return (tx_done); 533f173c2b7SSean Bruno } 534f173c2b7SSean Bruno 535f173c2b7SSean Bruno /* 536f173c2b7SSean Bruno * Process instruction queue after timeout. 537f173c2b7SSean Bruno * This routine gets called from a taskqueue or when removing the module. 538f173c2b7SSean Bruno */ 539f173c2b7SSean Bruno static void 540f173c2b7SSean Bruno __lio_check_db_timeout(struct octeon_device *oct, uint64_t iq_no) 541f173c2b7SSean Bruno { 542f173c2b7SSean Bruno struct lio_instr_queue *iq; 543f173c2b7SSean Bruno uint64_t next_time; 544f173c2b7SSean Bruno 545f173c2b7SSean Bruno if (oct == NULL) 546f173c2b7SSean Bruno return; 547f173c2b7SSean Bruno 548f173c2b7SSean Bruno iq = oct->instr_queue[iq_no]; 549f173c2b7SSean Bruno if (iq == NULL) 550f173c2b7SSean Bruno return; 551f173c2b7SSean Bruno 552f173c2b7SSean Bruno if (atomic_load_acq_int(&iq->instr_pending)) { 553f173c2b7SSean Bruno /* If ticks - last_db_time < db_timeout do nothing */ 554f173c2b7SSean Bruno next_time = iq->last_db_time + lio_ms_to_ticks(iq->db_timeout); 555f173c2b7SSean Bruno if (!lio_check_timeout(ticks, next_time)) 556f173c2b7SSean Bruno return; 557f173c2b7SSean Bruno 558f173c2b7SSean Bruno iq->last_db_time = ticks; 559f173c2b7SSean Bruno 560f173c2b7SSean Bruno /* Flush the instruction queue */ 561f173c2b7SSean Bruno lio_flush_iq(oct, iq, 0); 562f173c2b7SSean Bruno 563f173c2b7SSean Bruno lio_enable_irq(NULL, iq); 564f173c2b7SSean Bruno } 565f173c2b7SSean Bruno 566f173c2b7SSean Bruno if (oct->props.ifp != NULL && iq->br != NULL) { 567f173c2b7SSean Bruno if (mtx_trylock(&iq->enq_lock)) { 568f173c2b7SSean Bruno if (!drbr_empty(oct->props.ifp, iq->br)) 569f173c2b7SSean Bruno lio_mq_start_locked(oct->props.ifp, iq); 570f173c2b7SSean Bruno 571f173c2b7SSean Bruno mtx_unlock(&iq->enq_lock); 572f173c2b7SSean Bruno } 573f173c2b7SSean Bruno } 574f173c2b7SSean Bruno } 575f173c2b7SSean Bruno 576f173c2b7SSean Bruno /* 577f173c2b7SSean Bruno * Called by the Poll thread at regular intervals to check the instruction 578f173c2b7SSean Bruno * queue for commands to be posted and for commands that were fetched by Octeon. 579f173c2b7SSean Bruno */ 580f173c2b7SSean Bruno static void 581f173c2b7SSean Bruno lio_check_db_timeout(void *arg, int pending) 582f173c2b7SSean Bruno { 583f173c2b7SSean Bruno struct lio_tq *db_tq = (struct lio_tq *)arg; 584f173c2b7SSean Bruno struct octeon_device *oct = db_tq->ctxptr; 585f173c2b7SSean Bruno uint64_t iq_no = db_tq->ctxul; 586f173c2b7SSean Bruno uint32_t delay = 10; 587f173c2b7SSean Bruno 588f173c2b7SSean Bruno __lio_check_db_timeout(oct, iq_no); 589f173c2b7SSean Bruno taskqueue_enqueue_timeout(db_tq->tq, &db_tq->work, 590f173c2b7SSean Bruno lio_ms_to_ticks(delay)); 591f173c2b7SSean Bruno } 592f173c2b7SSean Bruno 593f173c2b7SSean Bruno int 594f173c2b7SSean Bruno lio_send_command(struct octeon_device *oct, uint32_t iq_no, 595f173c2b7SSean Bruno uint32_t force_db, void *cmd, void *buf, 596f173c2b7SSean Bruno uint32_t datasize, uint32_t reqtype) 597f173c2b7SSean Bruno { 598f173c2b7SSean Bruno struct lio_iq_post_status st; 599f173c2b7SSean Bruno struct lio_instr_queue *iq = oct->instr_queue[iq_no]; 600f173c2b7SSean Bruno 601f173c2b7SSean Bruno /* 602f173c2b7SSean Bruno * Get the lock and prevent other tasks and tx interrupt handler 603f173c2b7SSean Bruno * from running. 604f173c2b7SSean Bruno */ 605f173c2b7SSean Bruno mtx_lock(&iq->post_lock); 606f173c2b7SSean Bruno 607f173c2b7SSean Bruno st = __lio_post_command2(iq, cmd); 608f173c2b7SSean Bruno 609f173c2b7SSean Bruno if (st.status != LIO_IQ_SEND_FAILED) { 610f173c2b7SSean Bruno __lio_add_to_request_list(iq, st.index, buf, reqtype); 611f173c2b7SSean Bruno LIO_INCR_INSTRQUEUE_PKT_COUNT(oct, iq_no, bytes_sent, datasize); 612f173c2b7SSean Bruno LIO_INCR_INSTRQUEUE_PKT_COUNT(oct, iq_no, instr_posted, 1); 613f173c2b7SSean Bruno 614f173c2b7SSean Bruno if (force_db || (st.status == LIO_IQ_SEND_STOP)) 615f173c2b7SSean Bruno lio_ring_doorbell(oct, iq); 616f173c2b7SSean Bruno } else { 617f173c2b7SSean Bruno LIO_INCR_INSTRQUEUE_PKT_COUNT(oct, iq_no, instr_dropped, 1); 618f173c2b7SSean Bruno } 619f173c2b7SSean Bruno 620f173c2b7SSean Bruno mtx_unlock(&iq->post_lock); 621f173c2b7SSean Bruno 622f173c2b7SSean Bruno /* 623f173c2b7SSean Bruno * This is only done here to expedite packets being flushed for 624f173c2b7SSean Bruno * cases where there are no IQ completion interrupts. 625f173c2b7SSean Bruno */ 626f173c2b7SSean Bruno 627f173c2b7SSean Bruno return (st.status); 628f173c2b7SSean Bruno } 629f173c2b7SSean Bruno 630f173c2b7SSean Bruno void 631f173c2b7SSean Bruno lio_prepare_soft_command(struct octeon_device *oct, struct lio_soft_command *sc, 632f173c2b7SSean Bruno uint8_t opcode, uint8_t subcode, uint32_t irh_ossp, 633f173c2b7SSean Bruno uint64_t ossp0, uint64_t ossp1) 634f173c2b7SSean Bruno { 635f173c2b7SSean Bruno struct lio_config *lio_cfg; 636f173c2b7SSean Bruno struct octeon_instr_ih3 *ih3; 637f173c2b7SSean Bruno struct octeon_instr_pki_ih3 *pki_ih3; 638f173c2b7SSean Bruno struct octeon_instr_irh *irh; 639f173c2b7SSean Bruno struct octeon_instr_rdp *rdp; 640f173c2b7SSean Bruno 641f173c2b7SSean Bruno KASSERT(opcode <= 15, ("%s, %d, opcode > 15", __func__, __LINE__)); 642f173c2b7SSean Bruno KASSERT(subcode <= 127, ("%s, %d, opcode > 127", __func__, __LINE__)); 643f173c2b7SSean Bruno 644f173c2b7SSean Bruno lio_cfg = lio_get_conf(oct); 645f173c2b7SSean Bruno 646f173c2b7SSean Bruno if (LIO_CN23XX_PF(oct)) { 647f173c2b7SSean Bruno ih3 = (struct octeon_instr_ih3 *)&sc->cmd.cmd3.ih3; 648f173c2b7SSean Bruno 649f173c2b7SSean Bruno ih3->pkind = oct->instr_queue[sc->iq_no]->txpciq.s.pkind; 650f173c2b7SSean Bruno 651f173c2b7SSean Bruno pki_ih3 = (struct octeon_instr_pki_ih3 *)&sc->cmd.cmd3.pki_ih3; 652f173c2b7SSean Bruno 653f173c2b7SSean Bruno pki_ih3->w = 1; 654f173c2b7SSean Bruno pki_ih3->raw = 1; 655f173c2b7SSean Bruno pki_ih3->utag = 1; 656f173c2b7SSean Bruno pki_ih3->uqpg = oct->instr_queue[sc->iq_no]->txpciq.s.use_qpg; 657f173c2b7SSean Bruno pki_ih3->utt = 1; 658f173c2b7SSean Bruno pki_ih3->tag = LIO_CONTROL; 659f173c2b7SSean Bruno pki_ih3->tagtype = LIO_ATOMIC_TAG; 660f173c2b7SSean Bruno pki_ih3->qpg = oct->instr_queue[sc->iq_no]->txpciq.s.qpg; 661f173c2b7SSean Bruno pki_ih3->pm = 0x7; 662f173c2b7SSean Bruno pki_ih3->sl = 8; 663f173c2b7SSean Bruno 664f173c2b7SSean Bruno if (sc->datasize) 665f173c2b7SSean Bruno ih3->dlengsz = sc->datasize; 666f173c2b7SSean Bruno 667f173c2b7SSean Bruno irh = (struct octeon_instr_irh *)&sc->cmd.cmd3.irh; 668f173c2b7SSean Bruno irh->opcode = opcode; 669f173c2b7SSean Bruno irh->subcode = subcode; 670f173c2b7SSean Bruno 671f173c2b7SSean Bruno /* opcode/subcode specific parameters (ossp) */ 672f173c2b7SSean Bruno irh->ossp = irh_ossp; 673f173c2b7SSean Bruno sc->cmd.cmd3.ossp[0] = ossp0; 674f173c2b7SSean Bruno sc->cmd.cmd3.ossp[1] = ossp1; 675f173c2b7SSean Bruno 676f173c2b7SSean Bruno if (sc->rdatasize) { 677f173c2b7SSean Bruno rdp = (struct octeon_instr_rdp *)&sc->cmd.cmd3.rdp; 678f173c2b7SSean Bruno rdp->pcie_port = oct->pcie_port; 679f173c2b7SSean Bruno rdp->rlen = sc->rdatasize; 680f173c2b7SSean Bruno 681f173c2b7SSean Bruno irh->rflag = 1; 682f173c2b7SSean Bruno /* PKI IH3 */ 683f173c2b7SSean Bruno /* pki_ih3 irh+ossp[0]+ossp[1]+rdp+rptr = 48 bytes */ 684f173c2b7SSean Bruno ih3->fsz = LIO_SOFTCMDRESP_IH3; 685f173c2b7SSean Bruno } else { 686f173c2b7SSean Bruno irh->rflag = 0; 687f173c2b7SSean Bruno /* PKI IH3 */ 688f173c2b7SSean Bruno /* pki_h3 + irh + ossp[0] + ossp[1] = 32 bytes */ 689f173c2b7SSean Bruno ih3->fsz = LIO_PCICMD_O3; 690f173c2b7SSean Bruno } 691f173c2b7SSean Bruno } 692f173c2b7SSean Bruno } 693f173c2b7SSean Bruno 694f173c2b7SSean Bruno int 695f173c2b7SSean Bruno lio_send_soft_command(struct octeon_device *oct, struct lio_soft_command *sc) 696f173c2b7SSean Bruno { 697f173c2b7SSean Bruno struct octeon_instr_ih3 *ih3; 698f173c2b7SSean Bruno struct octeon_instr_irh *irh; 699f173c2b7SSean Bruno uint32_t len = 0; 700f173c2b7SSean Bruno 701f173c2b7SSean Bruno if (LIO_CN23XX_PF(oct)) { 702f173c2b7SSean Bruno ih3 = (struct octeon_instr_ih3 *)&sc->cmd.cmd3.ih3; 703f173c2b7SSean Bruno if (ih3->dlengsz) { 704f173c2b7SSean Bruno KASSERT(sc->dmadptr, ("%s, %d, sc->dmadptr is NULL", 705f173c2b7SSean Bruno __func__, __LINE__)); 706f173c2b7SSean Bruno sc->cmd.cmd3.dptr = sc->dmadptr; 707f173c2b7SSean Bruno } 708f173c2b7SSean Bruno 709f173c2b7SSean Bruno irh = (struct octeon_instr_irh *)&sc->cmd.cmd3.irh; 710f173c2b7SSean Bruno if (irh->rflag) { 711f173c2b7SSean Bruno KASSERT(sc->dmarptr, ("%s, %d, sc->dmarptr is NULL", 712f173c2b7SSean Bruno __func__, __LINE__)); 713f173c2b7SSean Bruno KASSERT(sc->status_word, ("%s, %d, sc->status_word is NULL", 714f173c2b7SSean Bruno __func__, __LINE__)); 715f173c2b7SSean Bruno *sc->status_word = COMPLETION_WORD_INIT; 716f173c2b7SSean Bruno sc->cmd.cmd3.rptr = sc->dmarptr; 717f173c2b7SSean Bruno } 718f173c2b7SSean Bruno len = (uint32_t)ih3->dlengsz; 719f173c2b7SSean Bruno } 720f173c2b7SSean Bruno if (sc->wait_time) 721f173c2b7SSean Bruno sc->timeout = ticks + lio_ms_to_ticks(sc->wait_time); 722f173c2b7SSean Bruno 723f173c2b7SSean Bruno return (lio_send_command(oct, sc->iq_no, 1, &sc->cmd, sc, 724f173c2b7SSean Bruno len, LIO_REQTYPE_SOFT_COMMAND)); 725f173c2b7SSean Bruno } 726f173c2b7SSean Bruno 727f173c2b7SSean Bruno int 728f173c2b7SSean Bruno lio_setup_sc_buffer_pool(struct octeon_device *oct) 729f173c2b7SSean Bruno { 730f173c2b7SSean Bruno struct lio_soft_command *sc; 731f173c2b7SSean Bruno uint64_t dma_addr; 732f173c2b7SSean Bruno int i; 733f173c2b7SSean Bruno 734f173c2b7SSean Bruno STAILQ_INIT(&oct->sc_buf_pool.head); 735f173c2b7SSean Bruno mtx_init(&oct->sc_buf_pool.lock, "sc_pool_lock", NULL, MTX_DEF); 736f173c2b7SSean Bruno atomic_store_rel_int(&oct->sc_buf_pool.alloc_buf_count, 0); 737f173c2b7SSean Bruno 738f173c2b7SSean Bruno for (i = 0; i < LIO_MAX_SOFT_COMMAND_BUFFERS; i++) { 739f173c2b7SSean Bruno sc = (struct lio_soft_command *) 7403de0952fSSean Bruno lio_dma_alloc(LIO_SOFT_COMMAND_BUFFER_SIZE, (vm_paddr_t *)&dma_addr); 741f173c2b7SSean Bruno if (sc == NULL) { 742f173c2b7SSean Bruno lio_free_sc_buffer_pool(oct); 743f173c2b7SSean Bruno return (1); 744f173c2b7SSean Bruno } 745f173c2b7SSean Bruno 746f173c2b7SSean Bruno sc->dma_addr = dma_addr; 747f173c2b7SSean Bruno sc->size = LIO_SOFT_COMMAND_BUFFER_SIZE; 748f173c2b7SSean Bruno 749f173c2b7SSean Bruno STAILQ_INSERT_TAIL(&oct->sc_buf_pool.head, &sc->node, entries); 750f173c2b7SSean Bruno } 751f173c2b7SSean Bruno 752f173c2b7SSean Bruno return (0); 753f173c2b7SSean Bruno } 754f173c2b7SSean Bruno 755f173c2b7SSean Bruno int 756f173c2b7SSean Bruno lio_free_sc_buffer_pool(struct octeon_device *oct) 757f173c2b7SSean Bruno { 758f173c2b7SSean Bruno struct lio_stailq_node *tmp, *tmp2; 759f173c2b7SSean Bruno struct lio_soft_command *sc; 760f173c2b7SSean Bruno 761f173c2b7SSean Bruno mtx_lock(&oct->sc_buf_pool.lock); 762f173c2b7SSean Bruno 763f173c2b7SSean Bruno STAILQ_FOREACH_SAFE(tmp, &oct->sc_buf_pool.head, entries, tmp2) { 764f173c2b7SSean Bruno sc = LIO_STAILQ_FIRST_ENTRY(&oct->sc_buf_pool.head, 765f173c2b7SSean Bruno struct lio_soft_command, node); 766f173c2b7SSean Bruno 767f173c2b7SSean Bruno STAILQ_REMOVE_HEAD(&oct->sc_buf_pool.head, entries); 768f173c2b7SSean Bruno 769f173c2b7SSean Bruno lio_dma_free(sc->size, sc); 770f173c2b7SSean Bruno } 771f173c2b7SSean Bruno 772f173c2b7SSean Bruno STAILQ_INIT(&oct->sc_buf_pool.head); 773f173c2b7SSean Bruno 774f173c2b7SSean Bruno mtx_unlock(&oct->sc_buf_pool.lock); 775f173c2b7SSean Bruno 776f173c2b7SSean Bruno return (0); 777f173c2b7SSean Bruno } 778f173c2b7SSean Bruno 779f173c2b7SSean Bruno struct lio_soft_command * 780f173c2b7SSean Bruno lio_alloc_soft_command(struct octeon_device *oct, uint32_t datasize, 781f173c2b7SSean Bruno uint32_t rdatasize, uint32_t ctxsize) 782f173c2b7SSean Bruno { 783f173c2b7SSean Bruno struct lio_soft_command *sc = NULL; 784f173c2b7SSean Bruno struct lio_stailq_node *tmp; 785f173c2b7SSean Bruno uint64_t dma_addr; 786f173c2b7SSean Bruno uint32_t size; 787f173c2b7SSean Bruno uint32_t offset = sizeof(struct lio_soft_command); 788f173c2b7SSean Bruno 789f173c2b7SSean Bruno KASSERT((offset + datasize + rdatasize + ctxsize) <= 790f173c2b7SSean Bruno LIO_SOFT_COMMAND_BUFFER_SIZE, 791f173c2b7SSean Bruno ("%s, %d, offset + datasize + rdatasize + ctxsize > LIO_SOFT_COMMAND_BUFFER_SIZE", 792f173c2b7SSean Bruno __func__, __LINE__)); 793f173c2b7SSean Bruno 794f173c2b7SSean Bruno mtx_lock(&oct->sc_buf_pool.lock); 795f173c2b7SSean Bruno 796f173c2b7SSean Bruno if (STAILQ_EMPTY(&oct->sc_buf_pool.head)) { 797f173c2b7SSean Bruno mtx_unlock(&oct->sc_buf_pool.lock); 798f173c2b7SSean Bruno return (NULL); 799f173c2b7SSean Bruno } 800f173c2b7SSean Bruno tmp = STAILQ_LAST(&oct->sc_buf_pool.head, lio_stailq_node, entries); 801f173c2b7SSean Bruno 802f173c2b7SSean Bruno STAILQ_REMOVE(&oct->sc_buf_pool.head, tmp, lio_stailq_node, entries); 803f173c2b7SSean Bruno 804f173c2b7SSean Bruno atomic_add_int(&oct->sc_buf_pool.alloc_buf_count, 1); 805f173c2b7SSean Bruno 806f173c2b7SSean Bruno mtx_unlock(&oct->sc_buf_pool.lock); 807f173c2b7SSean Bruno 808f173c2b7SSean Bruno sc = (struct lio_soft_command *)tmp; 809f173c2b7SSean Bruno 810f173c2b7SSean Bruno dma_addr = sc->dma_addr; 811f173c2b7SSean Bruno size = sc->size; 812f173c2b7SSean Bruno 813f173c2b7SSean Bruno bzero(sc, sc->size); 814f173c2b7SSean Bruno 815f173c2b7SSean Bruno sc->dma_addr = dma_addr; 816f173c2b7SSean Bruno sc->size = size; 817f173c2b7SSean Bruno 818f173c2b7SSean Bruno if (ctxsize) { 819f173c2b7SSean Bruno sc->ctxptr = (uint8_t *)sc + offset; 820f173c2b7SSean Bruno sc->ctxsize = ctxsize; 821f173c2b7SSean Bruno } 822f173c2b7SSean Bruno 823f173c2b7SSean Bruno /* Start data at 128 byte boundary */ 824f173c2b7SSean Bruno offset = (offset + ctxsize + 127) & 0xffffff80; 825f173c2b7SSean Bruno 826f173c2b7SSean Bruno if (datasize) { 827f173c2b7SSean Bruno sc->virtdptr = (uint8_t *)sc + offset; 828f173c2b7SSean Bruno sc->dmadptr = dma_addr + offset; 829f173c2b7SSean Bruno sc->datasize = datasize; 830f173c2b7SSean Bruno } 831f173c2b7SSean Bruno /* Start rdata at 128 byte boundary */ 832f173c2b7SSean Bruno offset = (offset + datasize + 127) & 0xffffff80; 833f173c2b7SSean Bruno 834f173c2b7SSean Bruno if (rdatasize) { 835f173c2b7SSean Bruno KASSERT(rdatasize >= 16, ("%s, %d, rdatasize < 16", __func__, 836f173c2b7SSean Bruno __LINE__)); 837f173c2b7SSean Bruno sc->virtrptr = (uint8_t *)sc + offset; 838f173c2b7SSean Bruno sc->dmarptr = dma_addr + offset; 839f173c2b7SSean Bruno sc->rdatasize = rdatasize; 840f173c2b7SSean Bruno sc->status_word = (uint64_t *)((uint8_t *)(sc->virtrptr) + 841f173c2b7SSean Bruno rdatasize - 8); 842f173c2b7SSean Bruno } 843f173c2b7SSean Bruno return (sc); 844f173c2b7SSean Bruno } 845f173c2b7SSean Bruno 846f173c2b7SSean Bruno void 847f173c2b7SSean Bruno lio_free_soft_command(struct octeon_device *oct, 848f173c2b7SSean Bruno struct lio_soft_command *sc) 849f173c2b7SSean Bruno { 850f173c2b7SSean Bruno 851f173c2b7SSean Bruno mtx_lock(&oct->sc_buf_pool.lock); 852f173c2b7SSean Bruno 853f173c2b7SSean Bruno STAILQ_INSERT_TAIL(&oct->sc_buf_pool.head, &sc->node, entries); 854f173c2b7SSean Bruno 855f173c2b7SSean Bruno atomic_subtract_int(&oct->sc_buf_pool.alloc_buf_count, 1); 856f173c2b7SSean Bruno 857f173c2b7SSean Bruno mtx_unlock(&oct->sc_buf_pool.lock); 858f173c2b7SSean Bruno } 859