18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright(c) 2015-2018 Intel Corporation. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 58c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 118c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 148c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 158c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 168c2ecf20Sopenharmony_ci * General Public License for more details. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * BSD LICENSE 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 218c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 228c2ecf20Sopenharmony_ci * are met: 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above copyright 258c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 268c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above copyright 278c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 288c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 298c2ecf20Sopenharmony_ci * distribution. 308c2ecf20Sopenharmony_ci * - Neither the name of Intel Corporation nor the names of its 318c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 328c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 358c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 368c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 378c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 388c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 398c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 408c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 418c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 428c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 438c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 448c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#include <linux/delay.h> 498c2ecf20Sopenharmony_ci#include "hfi.h" 508c2ecf20Sopenharmony_ci#include "qp.h" 518c2ecf20Sopenharmony_ci#include "trace.h" 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define SC(name) SEND_CTXT_##name 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * Send Context functions 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cistatic void sc_wait_for_packet_egress(struct send_context *sc, int pause); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* 608c2ecf20Sopenharmony_ci * Set the CM reset bit and wait for it to clear. Use the provided 618c2ecf20Sopenharmony_ci * sendctrl register. This routine has no locking. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_civoid __cm_reset(struct hfi1_devdata *dd, u64 sendctrl) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci write_csr(dd, SEND_CTRL, sendctrl | SEND_CTRL_CM_RESET_SMASK); 668c2ecf20Sopenharmony_ci while (1) { 678c2ecf20Sopenharmony_ci udelay(1); 688c2ecf20Sopenharmony_ci sendctrl = read_csr(dd, SEND_CTRL); 698c2ecf20Sopenharmony_ci if ((sendctrl & SEND_CTRL_CM_RESET_SMASK) == 0) 708c2ecf20Sopenharmony_ci break; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* global control of PIO send */ 758c2ecf20Sopenharmony_civoid pio_send_control(struct hfi1_devdata *dd, int op) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci u64 reg, mask; 788c2ecf20Sopenharmony_ci unsigned long flags; 798c2ecf20Sopenharmony_ci int write = 1; /* write sendctrl back */ 808c2ecf20Sopenharmony_ci int flush = 0; /* re-read sendctrl to make sure it is flushed */ 818c2ecf20Sopenharmony_ci int i; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci spin_lock_irqsave(&dd->sendctrl_lock, flags); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci reg = read_csr(dd, SEND_CTRL); 868c2ecf20Sopenharmony_ci switch (op) { 878c2ecf20Sopenharmony_ci case PSC_GLOBAL_ENABLE: 888c2ecf20Sopenharmony_ci reg |= SEND_CTRL_SEND_ENABLE_SMASK; 898c2ecf20Sopenharmony_ci fallthrough; 908c2ecf20Sopenharmony_ci case PSC_DATA_VL_ENABLE: 918c2ecf20Sopenharmony_ci mask = 0; 928c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dd->vld); i++) 938c2ecf20Sopenharmony_ci if (!dd->vld[i].mtu) 948c2ecf20Sopenharmony_ci mask |= BIT_ULL(i); 958c2ecf20Sopenharmony_ci /* Disallow sending on VLs not enabled */ 968c2ecf20Sopenharmony_ci mask = (mask & SEND_CTRL_UNSUPPORTED_VL_MASK) << 978c2ecf20Sopenharmony_ci SEND_CTRL_UNSUPPORTED_VL_SHIFT; 988c2ecf20Sopenharmony_ci reg = (reg & ~SEND_CTRL_UNSUPPORTED_VL_SMASK) | mask; 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci case PSC_GLOBAL_DISABLE: 1018c2ecf20Sopenharmony_ci reg &= ~SEND_CTRL_SEND_ENABLE_SMASK; 1028c2ecf20Sopenharmony_ci break; 1038c2ecf20Sopenharmony_ci case PSC_GLOBAL_VLARB_ENABLE: 1048c2ecf20Sopenharmony_ci reg |= SEND_CTRL_VL_ARBITER_ENABLE_SMASK; 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci case PSC_GLOBAL_VLARB_DISABLE: 1078c2ecf20Sopenharmony_ci reg &= ~SEND_CTRL_VL_ARBITER_ENABLE_SMASK; 1088c2ecf20Sopenharmony_ci break; 1098c2ecf20Sopenharmony_ci case PSC_CM_RESET: 1108c2ecf20Sopenharmony_ci __cm_reset(dd, reg); 1118c2ecf20Sopenharmony_ci write = 0; /* CSR already written (and flushed) */ 1128c2ecf20Sopenharmony_ci break; 1138c2ecf20Sopenharmony_ci case PSC_DATA_VL_DISABLE: 1148c2ecf20Sopenharmony_ci reg |= SEND_CTRL_UNSUPPORTED_VL_SMASK; 1158c2ecf20Sopenharmony_ci flush = 1; 1168c2ecf20Sopenharmony_ci break; 1178c2ecf20Sopenharmony_ci default: 1188c2ecf20Sopenharmony_ci dd_dev_err(dd, "%s: invalid control %d\n", __func__, op); 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (write) { 1238c2ecf20Sopenharmony_ci write_csr(dd, SEND_CTRL, reg); 1248c2ecf20Sopenharmony_ci if (flush) 1258c2ecf20Sopenharmony_ci (void)read_csr(dd, SEND_CTRL); /* flush write */ 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dd->sendctrl_lock, flags); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* number of send context memory pools */ 1328c2ecf20Sopenharmony_ci#define NUM_SC_POOLS 2 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* Send Context Size (SCS) wildcards */ 1358c2ecf20Sopenharmony_ci#define SCS_POOL_0 -1 1368c2ecf20Sopenharmony_ci#define SCS_POOL_1 -2 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* Send Context Count (SCC) wildcards */ 1398c2ecf20Sopenharmony_ci#define SCC_PER_VL -1 1408c2ecf20Sopenharmony_ci#define SCC_PER_CPU -2 1418c2ecf20Sopenharmony_ci#define SCC_PER_KRCVQ -3 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* Send Context Size (SCS) constants */ 1448c2ecf20Sopenharmony_ci#define SCS_ACK_CREDITS 32 1458c2ecf20Sopenharmony_ci#define SCS_VL15_CREDITS 102 /* 3 pkts of 2048B data + 128B header */ 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#define PIO_THRESHOLD_CEILING 4096 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci#define PIO_WAIT_BATCH_SIZE 5 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* default send context sizes */ 1528c2ecf20Sopenharmony_cistatic struct sc_config_sizes sc_config_sizes[SC_MAX] = { 1538c2ecf20Sopenharmony_ci [SC_KERNEL] = { .size = SCS_POOL_0, /* even divide, pool 0 */ 1548c2ecf20Sopenharmony_ci .count = SCC_PER_VL }, /* one per NUMA */ 1558c2ecf20Sopenharmony_ci [SC_ACK] = { .size = SCS_ACK_CREDITS, 1568c2ecf20Sopenharmony_ci .count = SCC_PER_KRCVQ }, 1578c2ecf20Sopenharmony_ci [SC_USER] = { .size = SCS_POOL_0, /* even divide, pool 0 */ 1588c2ecf20Sopenharmony_ci .count = SCC_PER_CPU }, /* one per CPU */ 1598c2ecf20Sopenharmony_ci [SC_VL15] = { .size = SCS_VL15_CREDITS, 1608c2ecf20Sopenharmony_ci .count = 1 }, 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* send context memory pool configuration */ 1658c2ecf20Sopenharmony_cistruct mem_pool_config { 1668c2ecf20Sopenharmony_ci int centipercent; /* % of memory, in 100ths of 1% */ 1678c2ecf20Sopenharmony_ci int absolute_blocks; /* absolute block count */ 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* default memory pool configuration: 100% in pool 0 */ 1718c2ecf20Sopenharmony_cistatic struct mem_pool_config sc_mem_pool_config[NUM_SC_POOLS] = { 1728c2ecf20Sopenharmony_ci /* centi%, abs blocks */ 1738c2ecf20Sopenharmony_ci { 10000, -1 }, /* pool 0 */ 1748c2ecf20Sopenharmony_ci { 0, -1 }, /* pool 1 */ 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/* memory pool information, used when calculating final sizes */ 1788c2ecf20Sopenharmony_cistruct mem_pool_info { 1798c2ecf20Sopenharmony_ci int centipercent; /* 1808c2ecf20Sopenharmony_ci * 100th of 1% of memory to use, -1 if blocks 1818c2ecf20Sopenharmony_ci * already set 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ci int count; /* count of contexts in the pool */ 1848c2ecf20Sopenharmony_ci int blocks; /* block size of the pool */ 1858c2ecf20Sopenharmony_ci int size; /* context size, in blocks */ 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/* 1898c2ecf20Sopenharmony_ci * Convert a pool wildcard to a valid pool index. The wildcards 1908c2ecf20Sopenharmony_ci * start at -1 and increase negatively. Map them as: 1918c2ecf20Sopenharmony_ci * -1 => 0 1928c2ecf20Sopenharmony_ci * -2 => 1 1938c2ecf20Sopenharmony_ci * etc. 1948c2ecf20Sopenharmony_ci * 1958c2ecf20Sopenharmony_ci * Return -1 on non-wildcard input, otherwise convert to a pool number. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cistatic int wildcard_to_pool(int wc) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci if (wc >= 0) 2008c2ecf20Sopenharmony_ci return -1; /* non-wildcard */ 2018c2ecf20Sopenharmony_ci return -wc - 1; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic const char *sc_type_names[SC_MAX] = { 2058c2ecf20Sopenharmony_ci "kernel", 2068c2ecf20Sopenharmony_ci "ack", 2078c2ecf20Sopenharmony_ci "user", 2088c2ecf20Sopenharmony_ci "vl15" 2098c2ecf20Sopenharmony_ci}; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic const char *sc_type_name(int index) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci if (index < 0 || index >= SC_MAX) 2148c2ecf20Sopenharmony_ci return "unknown"; 2158c2ecf20Sopenharmony_ci return sc_type_names[index]; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* 2198c2ecf20Sopenharmony_ci * Read the send context memory pool configuration and send context 2208c2ecf20Sopenharmony_ci * size configuration. Replace any wildcards and come up with final 2218c2ecf20Sopenharmony_ci * counts and sizes for the send context types. 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_ciint init_sc_pools_and_sizes(struct hfi1_devdata *dd) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct mem_pool_info mem_pool_info[NUM_SC_POOLS] = { { 0 } }; 2268c2ecf20Sopenharmony_ci int total_blocks = (chip_pio_mem_size(dd) / PIO_BLOCK_SIZE) - 1; 2278c2ecf20Sopenharmony_ci int total_contexts = 0; 2288c2ecf20Sopenharmony_ci int fixed_blocks; 2298c2ecf20Sopenharmony_ci int pool_blocks; 2308c2ecf20Sopenharmony_ci int used_blocks; 2318c2ecf20Sopenharmony_ci int cp_total; /* centipercent total */ 2328c2ecf20Sopenharmony_ci int ab_total; /* absolute block total */ 2338c2ecf20Sopenharmony_ci int extra; 2348c2ecf20Sopenharmony_ci int i; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* 2378c2ecf20Sopenharmony_ci * When SDMA is enabled, kernel context pio packet size is capped by 2388c2ecf20Sopenharmony_ci * "piothreshold". Reduce pio buffer allocation for kernel context by 2398c2ecf20Sopenharmony_ci * setting it to a fixed size. The allocation allows 3-deep buffering 2408c2ecf20Sopenharmony_ci * of the largest pio packets plus up to 128 bytes header, sufficient 2418c2ecf20Sopenharmony_ci * to maintain verbs performance. 2428c2ecf20Sopenharmony_ci * 2438c2ecf20Sopenharmony_ci * When SDMA is disabled, keep the default pooling allocation. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci if (HFI1_CAP_IS_KSET(SDMA)) { 2468c2ecf20Sopenharmony_ci u16 max_pkt_size = (piothreshold < PIO_THRESHOLD_CEILING) ? 2478c2ecf20Sopenharmony_ci piothreshold : PIO_THRESHOLD_CEILING; 2488c2ecf20Sopenharmony_ci sc_config_sizes[SC_KERNEL].size = 2498c2ecf20Sopenharmony_ci 3 * (max_pkt_size + 128) / PIO_BLOCK_SIZE; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* 2538c2ecf20Sopenharmony_ci * Step 0: 2548c2ecf20Sopenharmony_ci * - copy the centipercents/absolute sizes from the pool config 2558c2ecf20Sopenharmony_ci * - sanity check these values 2568c2ecf20Sopenharmony_ci * - add up centipercents, then later check for full value 2578c2ecf20Sopenharmony_ci * - add up absolute blocks, then later check for over-commit 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ci cp_total = 0; 2608c2ecf20Sopenharmony_ci ab_total = 0; 2618c2ecf20Sopenharmony_ci for (i = 0; i < NUM_SC_POOLS; i++) { 2628c2ecf20Sopenharmony_ci int cp = sc_mem_pool_config[i].centipercent; 2638c2ecf20Sopenharmony_ci int ab = sc_mem_pool_config[i].absolute_blocks; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* 2668c2ecf20Sopenharmony_ci * A negative value is "unused" or "invalid". Both *can* 2678c2ecf20Sopenharmony_ci * be valid, but centipercent wins, so check that first 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_ci if (cp >= 0) { /* centipercent valid */ 2708c2ecf20Sopenharmony_ci cp_total += cp; 2718c2ecf20Sopenharmony_ci } else if (ab >= 0) { /* absolute blocks valid */ 2728c2ecf20Sopenharmony_ci ab_total += ab; 2738c2ecf20Sopenharmony_ci } else { /* neither valid */ 2748c2ecf20Sopenharmony_ci dd_dev_err( 2758c2ecf20Sopenharmony_ci dd, 2768c2ecf20Sopenharmony_ci "Send context memory pool %d: both the block count and centipercent are invalid\n", 2778c2ecf20Sopenharmony_ci i); 2788c2ecf20Sopenharmony_ci return -EINVAL; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci mem_pool_info[i].centipercent = cp; 2828c2ecf20Sopenharmony_ci mem_pool_info[i].blocks = ab; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* do not use both % and absolute blocks for different pools */ 2868c2ecf20Sopenharmony_ci if (cp_total != 0 && ab_total != 0) { 2878c2ecf20Sopenharmony_ci dd_dev_err( 2888c2ecf20Sopenharmony_ci dd, 2898c2ecf20Sopenharmony_ci "All send context memory pools must be described as either centipercent or blocks, no mixing between pools\n"); 2908c2ecf20Sopenharmony_ci return -EINVAL; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* if any percentages are present, they must add up to 100% x 100 */ 2948c2ecf20Sopenharmony_ci if (cp_total != 0 && cp_total != 10000) { 2958c2ecf20Sopenharmony_ci dd_dev_err( 2968c2ecf20Sopenharmony_ci dd, 2978c2ecf20Sopenharmony_ci "Send context memory pool centipercent is %d, expecting 10000\n", 2988c2ecf20Sopenharmony_ci cp_total); 2998c2ecf20Sopenharmony_ci return -EINVAL; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* the absolute pool total cannot be more than the mem total */ 3038c2ecf20Sopenharmony_ci if (ab_total > total_blocks) { 3048c2ecf20Sopenharmony_ci dd_dev_err( 3058c2ecf20Sopenharmony_ci dd, 3068c2ecf20Sopenharmony_ci "Send context memory pool absolute block count %d is larger than the memory size %d\n", 3078c2ecf20Sopenharmony_ci ab_total, total_blocks); 3088c2ecf20Sopenharmony_ci return -EINVAL; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* 3128c2ecf20Sopenharmony_ci * Step 2: 3138c2ecf20Sopenharmony_ci * - copy from the context size config 3148c2ecf20Sopenharmony_ci * - replace context type wildcard counts with real values 3158c2ecf20Sopenharmony_ci * - add up non-memory pool block sizes 3168c2ecf20Sopenharmony_ci * - add up memory pool user counts 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ci fixed_blocks = 0; 3198c2ecf20Sopenharmony_ci for (i = 0; i < SC_MAX; i++) { 3208c2ecf20Sopenharmony_ci int count = sc_config_sizes[i].count; 3218c2ecf20Sopenharmony_ci int size = sc_config_sizes[i].size; 3228c2ecf20Sopenharmony_ci int pool; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* 3258c2ecf20Sopenharmony_ci * Sanity check count: Either a positive value or 3268c2ecf20Sopenharmony_ci * one of the expected wildcards is valid. The positive 3278c2ecf20Sopenharmony_ci * value is checked later when we compare against total 3288c2ecf20Sopenharmony_ci * memory available. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ci if (i == SC_ACK) { 3318c2ecf20Sopenharmony_ci count = dd->n_krcv_queues; 3328c2ecf20Sopenharmony_ci } else if (i == SC_KERNEL) { 3338c2ecf20Sopenharmony_ci count = INIT_SC_PER_VL * num_vls; 3348c2ecf20Sopenharmony_ci } else if (count == SCC_PER_CPU) { 3358c2ecf20Sopenharmony_ci count = dd->num_rcv_contexts - dd->n_krcv_queues; 3368c2ecf20Sopenharmony_ci } else if (count < 0) { 3378c2ecf20Sopenharmony_ci dd_dev_err( 3388c2ecf20Sopenharmony_ci dd, 3398c2ecf20Sopenharmony_ci "%s send context invalid count wildcard %d\n", 3408c2ecf20Sopenharmony_ci sc_type_name(i), count); 3418c2ecf20Sopenharmony_ci return -EINVAL; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci if (total_contexts + count > chip_send_contexts(dd)) 3448c2ecf20Sopenharmony_ci count = chip_send_contexts(dd) - total_contexts; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci total_contexts += count; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* 3498c2ecf20Sopenharmony_ci * Sanity check pool: The conversion will return a pool 3508c2ecf20Sopenharmony_ci * number or -1 if a fixed (non-negative) value. The fixed 3518c2ecf20Sopenharmony_ci * value is checked later when we compare against 3528c2ecf20Sopenharmony_ci * total memory available. 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_ci pool = wildcard_to_pool(size); 3558c2ecf20Sopenharmony_ci if (pool == -1) { /* non-wildcard */ 3568c2ecf20Sopenharmony_ci fixed_blocks += size * count; 3578c2ecf20Sopenharmony_ci } else if (pool < NUM_SC_POOLS) { /* valid wildcard */ 3588c2ecf20Sopenharmony_ci mem_pool_info[pool].count += count; 3598c2ecf20Sopenharmony_ci } else { /* invalid wildcard */ 3608c2ecf20Sopenharmony_ci dd_dev_err( 3618c2ecf20Sopenharmony_ci dd, 3628c2ecf20Sopenharmony_ci "%s send context invalid pool wildcard %d\n", 3638c2ecf20Sopenharmony_ci sc_type_name(i), size); 3648c2ecf20Sopenharmony_ci return -EINVAL; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci dd->sc_sizes[i].count = count; 3688c2ecf20Sopenharmony_ci dd->sc_sizes[i].size = size; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci if (fixed_blocks > total_blocks) { 3718c2ecf20Sopenharmony_ci dd_dev_err( 3728c2ecf20Sopenharmony_ci dd, 3738c2ecf20Sopenharmony_ci "Send context fixed block count, %u, larger than total block count %u\n", 3748c2ecf20Sopenharmony_ci fixed_blocks, total_blocks); 3758c2ecf20Sopenharmony_ci return -EINVAL; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* step 3: calculate the blocks in the pools, and pool context sizes */ 3798c2ecf20Sopenharmony_ci pool_blocks = total_blocks - fixed_blocks; 3808c2ecf20Sopenharmony_ci if (ab_total > pool_blocks) { 3818c2ecf20Sopenharmony_ci dd_dev_err( 3828c2ecf20Sopenharmony_ci dd, 3838c2ecf20Sopenharmony_ci "Send context fixed pool sizes, %u, larger than pool block count %u\n", 3848c2ecf20Sopenharmony_ci ab_total, pool_blocks); 3858c2ecf20Sopenharmony_ci return -EINVAL; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci /* subtract off the fixed pool blocks */ 3888c2ecf20Sopenharmony_ci pool_blocks -= ab_total; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci for (i = 0; i < NUM_SC_POOLS; i++) { 3918c2ecf20Sopenharmony_ci struct mem_pool_info *pi = &mem_pool_info[i]; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* % beats absolute blocks */ 3948c2ecf20Sopenharmony_ci if (pi->centipercent >= 0) 3958c2ecf20Sopenharmony_ci pi->blocks = (pool_blocks * pi->centipercent) / 10000; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (pi->blocks == 0 && pi->count != 0) { 3988c2ecf20Sopenharmony_ci dd_dev_err( 3998c2ecf20Sopenharmony_ci dd, 4008c2ecf20Sopenharmony_ci "Send context memory pool %d has %u contexts, but no blocks\n", 4018c2ecf20Sopenharmony_ci i, pi->count); 4028c2ecf20Sopenharmony_ci return -EINVAL; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci if (pi->count == 0) { 4058c2ecf20Sopenharmony_ci /* warn about wasted blocks */ 4068c2ecf20Sopenharmony_ci if (pi->blocks != 0) 4078c2ecf20Sopenharmony_ci dd_dev_err( 4088c2ecf20Sopenharmony_ci dd, 4098c2ecf20Sopenharmony_ci "Send context memory pool %d has %u blocks, but zero contexts\n", 4108c2ecf20Sopenharmony_ci i, pi->blocks); 4118c2ecf20Sopenharmony_ci pi->size = 0; 4128c2ecf20Sopenharmony_ci } else { 4138c2ecf20Sopenharmony_ci pi->size = pi->blocks / pi->count; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* step 4: fill in the context type sizes from the pool sizes */ 4188c2ecf20Sopenharmony_ci used_blocks = 0; 4198c2ecf20Sopenharmony_ci for (i = 0; i < SC_MAX; i++) { 4208c2ecf20Sopenharmony_ci if (dd->sc_sizes[i].size < 0) { 4218c2ecf20Sopenharmony_ci unsigned pool = wildcard_to_pool(dd->sc_sizes[i].size); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci WARN_ON_ONCE(pool >= NUM_SC_POOLS); 4248c2ecf20Sopenharmony_ci dd->sc_sizes[i].size = mem_pool_info[pool].size; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci /* make sure we are not larger than what is allowed by the HW */ 4278c2ecf20Sopenharmony_ci#define PIO_MAX_BLOCKS 1024 4288c2ecf20Sopenharmony_ci if (dd->sc_sizes[i].size > PIO_MAX_BLOCKS) 4298c2ecf20Sopenharmony_ci dd->sc_sizes[i].size = PIO_MAX_BLOCKS; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci /* calculate our total usage */ 4328c2ecf20Sopenharmony_ci used_blocks += dd->sc_sizes[i].size * dd->sc_sizes[i].count; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci extra = total_blocks - used_blocks; 4358c2ecf20Sopenharmony_ci if (extra != 0) 4368c2ecf20Sopenharmony_ci dd_dev_info(dd, "unused send context blocks: %d\n", extra); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci return total_contexts; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ciint init_send_contexts(struct hfi1_devdata *dd) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci u16 base; 4448c2ecf20Sopenharmony_ci int ret, i, j, context; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci ret = init_credit_return(dd); 4478c2ecf20Sopenharmony_ci if (ret) 4488c2ecf20Sopenharmony_ci return ret; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci dd->hw_to_sw = kmalloc_array(TXE_NUM_CONTEXTS, sizeof(u8), 4518c2ecf20Sopenharmony_ci GFP_KERNEL); 4528c2ecf20Sopenharmony_ci dd->send_contexts = kcalloc(dd->num_send_contexts, 4538c2ecf20Sopenharmony_ci sizeof(struct send_context_info), 4548c2ecf20Sopenharmony_ci GFP_KERNEL); 4558c2ecf20Sopenharmony_ci if (!dd->send_contexts || !dd->hw_to_sw) { 4568c2ecf20Sopenharmony_ci kfree(dd->hw_to_sw); 4578c2ecf20Sopenharmony_ci kfree(dd->send_contexts); 4588c2ecf20Sopenharmony_ci free_credit_return(dd); 4598c2ecf20Sopenharmony_ci return -ENOMEM; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* hardware context map starts with invalid send context indices */ 4638c2ecf20Sopenharmony_ci for (i = 0; i < TXE_NUM_CONTEXTS; i++) 4648c2ecf20Sopenharmony_ci dd->hw_to_sw[i] = INVALID_SCI; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* 4678c2ecf20Sopenharmony_ci * All send contexts have their credit sizes. Allocate credits 4688c2ecf20Sopenharmony_ci * for each context one after another from the global space. 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_ci context = 0; 4718c2ecf20Sopenharmony_ci base = 1; 4728c2ecf20Sopenharmony_ci for (i = 0; i < SC_MAX; i++) { 4738c2ecf20Sopenharmony_ci struct sc_config_sizes *scs = &dd->sc_sizes[i]; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci for (j = 0; j < scs->count; j++) { 4768c2ecf20Sopenharmony_ci struct send_context_info *sci = 4778c2ecf20Sopenharmony_ci &dd->send_contexts[context]; 4788c2ecf20Sopenharmony_ci sci->type = i; 4798c2ecf20Sopenharmony_ci sci->base = base; 4808c2ecf20Sopenharmony_ci sci->credits = scs->size; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci context++; 4838c2ecf20Sopenharmony_ci base += scs->size; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci return 0; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/* 4918c2ecf20Sopenharmony_ci * Allocate a software index and hardware context of the given type. 4928c2ecf20Sopenharmony_ci * 4938c2ecf20Sopenharmony_ci * Must be called with dd->sc_lock held. 4948c2ecf20Sopenharmony_ci */ 4958c2ecf20Sopenharmony_cistatic int sc_hw_alloc(struct hfi1_devdata *dd, int type, u32 *sw_index, 4968c2ecf20Sopenharmony_ci u32 *hw_context) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct send_context_info *sci; 4998c2ecf20Sopenharmony_ci u32 index; 5008c2ecf20Sopenharmony_ci u32 context; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci for (index = 0, sci = &dd->send_contexts[0]; 5038c2ecf20Sopenharmony_ci index < dd->num_send_contexts; index++, sci++) { 5048c2ecf20Sopenharmony_ci if (sci->type == type && sci->allocated == 0) { 5058c2ecf20Sopenharmony_ci sci->allocated = 1; 5068c2ecf20Sopenharmony_ci /* use a 1:1 mapping, but make them non-equal */ 5078c2ecf20Sopenharmony_ci context = chip_send_contexts(dd) - index - 1; 5088c2ecf20Sopenharmony_ci dd->hw_to_sw[context] = index; 5098c2ecf20Sopenharmony_ci *sw_index = index; 5108c2ecf20Sopenharmony_ci *hw_context = context; 5118c2ecf20Sopenharmony_ci return 0; /* success */ 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci dd_dev_err(dd, "Unable to locate a free type %d send context\n", type); 5158c2ecf20Sopenharmony_ci return -ENOSPC; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci/* 5198c2ecf20Sopenharmony_ci * Free the send context given by its software index. 5208c2ecf20Sopenharmony_ci * 5218c2ecf20Sopenharmony_ci * Must be called with dd->sc_lock held. 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_cistatic void sc_hw_free(struct hfi1_devdata *dd, u32 sw_index, u32 hw_context) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci struct send_context_info *sci; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci sci = &dd->send_contexts[sw_index]; 5288c2ecf20Sopenharmony_ci if (!sci->allocated) { 5298c2ecf20Sopenharmony_ci dd_dev_err(dd, "%s: sw_index %u not allocated? hw_context %u\n", 5308c2ecf20Sopenharmony_ci __func__, sw_index, hw_context); 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci sci->allocated = 0; 5338c2ecf20Sopenharmony_ci dd->hw_to_sw[hw_context] = INVALID_SCI; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci/* return the base context of a context in a group */ 5378c2ecf20Sopenharmony_cistatic inline u32 group_context(u32 context, u32 group) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci return (context >> group) << group; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci/* return the size of a group */ 5438c2ecf20Sopenharmony_cistatic inline u32 group_size(u32 group) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci return 1 << group; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci/* 5498c2ecf20Sopenharmony_ci * Obtain the credit return addresses, kernel virtual and bus, for the 5508c2ecf20Sopenharmony_ci * given sc. 5518c2ecf20Sopenharmony_ci * 5528c2ecf20Sopenharmony_ci * To understand this routine: 5538c2ecf20Sopenharmony_ci * o va and dma are arrays of struct credit_return. One for each physical 5548c2ecf20Sopenharmony_ci * send context, per NUMA. 5558c2ecf20Sopenharmony_ci * o Each send context always looks in its relative location in a struct 5568c2ecf20Sopenharmony_ci * credit_return for its credit return. 5578c2ecf20Sopenharmony_ci * o Each send context in a group must have its return address CSR programmed 5588c2ecf20Sopenharmony_ci * with the same value. Use the address of the first send context in the 5598c2ecf20Sopenharmony_ci * group. 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_cistatic void cr_group_addresses(struct send_context *sc, dma_addr_t *dma) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci u32 gc = group_context(sc->hw_context, sc->group); 5648c2ecf20Sopenharmony_ci u32 index = sc->hw_context & 0x7; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci sc->hw_free = &sc->dd->cr_base[sc->node].va[gc].cr[index]; 5678c2ecf20Sopenharmony_ci *dma = (unsigned long) 5688c2ecf20Sopenharmony_ci &((struct credit_return *)sc->dd->cr_base[sc->node].dma)[gc]; 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci/* 5728c2ecf20Sopenharmony_ci * Work queue function triggered in error interrupt routine for 5738c2ecf20Sopenharmony_ci * kernel contexts. 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_cistatic void sc_halted(struct work_struct *work) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct send_context *sc; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci sc = container_of(work, struct send_context, halt_work); 5808c2ecf20Sopenharmony_ci sc_restart(sc); 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci/* 5848c2ecf20Sopenharmony_ci * Calculate PIO block threshold for this send context using the given MTU. 5858c2ecf20Sopenharmony_ci * Trigger a return when one MTU plus optional header of credits remain. 5868c2ecf20Sopenharmony_ci * 5878c2ecf20Sopenharmony_ci * Parameter mtu is in bytes. 5888c2ecf20Sopenharmony_ci * Parameter hdrqentsize is in DWORDs. 5898c2ecf20Sopenharmony_ci * 5908c2ecf20Sopenharmony_ci * Return value is what to write into the CSR: trigger return when 5918c2ecf20Sopenharmony_ci * unreturned credits pass this count. 5928c2ecf20Sopenharmony_ci */ 5938c2ecf20Sopenharmony_ciu32 sc_mtu_to_threshold(struct send_context *sc, u32 mtu, u32 hdrqentsize) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci u32 release_credits; 5968c2ecf20Sopenharmony_ci u32 threshold; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* add in the header size, then divide by the PIO block size */ 5998c2ecf20Sopenharmony_ci mtu += hdrqentsize << 2; 6008c2ecf20Sopenharmony_ci release_credits = DIV_ROUND_UP(mtu, PIO_BLOCK_SIZE); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* check against this context's credits */ 6038c2ecf20Sopenharmony_ci if (sc->credits <= release_credits) 6048c2ecf20Sopenharmony_ci threshold = 1; 6058c2ecf20Sopenharmony_ci else 6068c2ecf20Sopenharmony_ci threshold = sc->credits - release_credits; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return threshold; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/* 6128c2ecf20Sopenharmony_ci * Calculate credit threshold in terms of percent of the allocated credits. 6138c2ecf20Sopenharmony_ci * Trigger when unreturned credits equal or exceed the percentage of the whole. 6148c2ecf20Sopenharmony_ci * 6158c2ecf20Sopenharmony_ci * Return value is what to write into the CSR: trigger return when 6168c2ecf20Sopenharmony_ci * unreturned credits pass this count. 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_ciu32 sc_percent_to_threshold(struct send_context *sc, u32 percent) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci return (sc->credits * percent) / 100; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci/* 6248c2ecf20Sopenharmony_ci * Set the credit return threshold. 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_civoid sc_set_cr_threshold(struct send_context *sc, u32 new_threshold) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci unsigned long flags; 6298c2ecf20Sopenharmony_ci u32 old_threshold; 6308c2ecf20Sopenharmony_ci int force_return = 0; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci spin_lock_irqsave(&sc->credit_ctrl_lock, flags); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci old_threshold = (sc->credit_ctrl >> 6358c2ecf20Sopenharmony_ci SC(CREDIT_CTRL_THRESHOLD_SHIFT)) 6368c2ecf20Sopenharmony_ci & SC(CREDIT_CTRL_THRESHOLD_MASK); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (new_threshold != old_threshold) { 6398c2ecf20Sopenharmony_ci sc->credit_ctrl = 6408c2ecf20Sopenharmony_ci (sc->credit_ctrl 6418c2ecf20Sopenharmony_ci & ~SC(CREDIT_CTRL_THRESHOLD_SMASK)) 6428c2ecf20Sopenharmony_ci | ((new_threshold 6438c2ecf20Sopenharmony_ci & SC(CREDIT_CTRL_THRESHOLD_MASK)) 6448c2ecf20Sopenharmony_ci << SC(CREDIT_CTRL_THRESHOLD_SHIFT)); 6458c2ecf20Sopenharmony_ci write_kctxt_csr(sc->dd, sc->hw_context, 6468c2ecf20Sopenharmony_ci SC(CREDIT_CTRL), sc->credit_ctrl); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci /* force a credit return on change to avoid a possible stall */ 6498c2ecf20Sopenharmony_ci force_return = 1; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->credit_ctrl_lock, flags); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (force_return) 6558c2ecf20Sopenharmony_ci sc_return_credits(sc); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci/* 6598c2ecf20Sopenharmony_ci * set_pio_integrity 6608c2ecf20Sopenharmony_ci * 6618c2ecf20Sopenharmony_ci * Set the CHECK_ENABLE register for the send context 'sc'. 6628c2ecf20Sopenharmony_ci */ 6638c2ecf20Sopenharmony_civoid set_pio_integrity(struct send_context *sc) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = sc->dd; 6668c2ecf20Sopenharmony_ci u32 hw_context = sc->hw_context; 6678c2ecf20Sopenharmony_ci int type = sc->type; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, 6708c2ecf20Sopenharmony_ci SC(CHECK_ENABLE), 6718c2ecf20Sopenharmony_ci hfi1_pkt_default_send_ctxt_mask(dd, type)); 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cistatic u32 get_buffers_allocated(struct send_context *sc) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci int cpu; 6778c2ecf20Sopenharmony_ci u32 ret = 0; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) 6808c2ecf20Sopenharmony_ci ret += *per_cpu_ptr(sc->buffers_allocated, cpu); 6818c2ecf20Sopenharmony_ci return ret; 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic void reset_buffers_allocated(struct send_context *sc) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci int cpu; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) 6898c2ecf20Sopenharmony_ci (*per_cpu_ptr(sc->buffers_allocated, cpu)) = 0; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci/* 6938c2ecf20Sopenharmony_ci * Allocate a NUMA relative send context structure of the given type along 6948c2ecf20Sopenharmony_ci * with a HW context. 6958c2ecf20Sopenharmony_ci */ 6968c2ecf20Sopenharmony_cistruct send_context *sc_alloc(struct hfi1_devdata *dd, int type, 6978c2ecf20Sopenharmony_ci uint hdrqentsize, int numa) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci struct send_context_info *sci; 7008c2ecf20Sopenharmony_ci struct send_context *sc = NULL; 7018c2ecf20Sopenharmony_ci dma_addr_t dma; 7028c2ecf20Sopenharmony_ci unsigned long flags; 7038c2ecf20Sopenharmony_ci u64 reg; 7048c2ecf20Sopenharmony_ci u32 thresh; 7058c2ecf20Sopenharmony_ci u32 sw_index; 7068c2ecf20Sopenharmony_ci u32 hw_context; 7078c2ecf20Sopenharmony_ci int ret; 7088c2ecf20Sopenharmony_ci u8 opval, opmask; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* do not allocate while frozen */ 7118c2ecf20Sopenharmony_ci if (dd->flags & HFI1_FROZEN) 7128c2ecf20Sopenharmony_ci return NULL; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci sc = kzalloc_node(sizeof(*sc), GFP_KERNEL, numa); 7158c2ecf20Sopenharmony_ci if (!sc) 7168c2ecf20Sopenharmony_ci return NULL; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci sc->buffers_allocated = alloc_percpu(u32); 7198c2ecf20Sopenharmony_ci if (!sc->buffers_allocated) { 7208c2ecf20Sopenharmony_ci kfree(sc); 7218c2ecf20Sopenharmony_ci dd_dev_err(dd, 7228c2ecf20Sopenharmony_ci "Cannot allocate buffers_allocated per cpu counters\n" 7238c2ecf20Sopenharmony_ci ); 7248c2ecf20Sopenharmony_ci return NULL; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci spin_lock_irqsave(&dd->sc_lock, flags); 7288c2ecf20Sopenharmony_ci ret = sc_hw_alloc(dd, type, &sw_index, &hw_context); 7298c2ecf20Sopenharmony_ci if (ret) { 7308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dd->sc_lock, flags); 7318c2ecf20Sopenharmony_ci free_percpu(sc->buffers_allocated); 7328c2ecf20Sopenharmony_ci kfree(sc); 7338c2ecf20Sopenharmony_ci return NULL; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci sci = &dd->send_contexts[sw_index]; 7378c2ecf20Sopenharmony_ci sci->sc = sc; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci sc->dd = dd; 7408c2ecf20Sopenharmony_ci sc->node = numa; 7418c2ecf20Sopenharmony_ci sc->type = type; 7428c2ecf20Sopenharmony_ci spin_lock_init(&sc->alloc_lock); 7438c2ecf20Sopenharmony_ci spin_lock_init(&sc->release_lock); 7448c2ecf20Sopenharmony_ci spin_lock_init(&sc->credit_ctrl_lock); 7458c2ecf20Sopenharmony_ci seqlock_init(&sc->waitlock); 7468c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sc->piowait); 7478c2ecf20Sopenharmony_ci INIT_WORK(&sc->halt_work, sc_halted); 7488c2ecf20Sopenharmony_ci init_waitqueue_head(&sc->halt_wait); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci /* grouping is always single context for now */ 7518c2ecf20Sopenharmony_ci sc->group = 0; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci sc->sw_index = sw_index; 7548c2ecf20Sopenharmony_ci sc->hw_context = hw_context; 7558c2ecf20Sopenharmony_ci cr_group_addresses(sc, &dma); 7568c2ecf20Sopenharmony_ci sc->credits = sci->credits; 7578c2ecf20Sopenharmony_ci sc->size = sc->credits * PIO_BLOCK_SIZE; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci/* PIO Send Memory Address details */ 7608c2ecf20Sopenharmony_ci#define PIO_ADDR_CONTEXT_MASK 0xfful 7618c2ecf20Sopenharmony_ci#define PIO_ADDR_CONTEXT_SHIFT 16 7628c2ecf20Sopenharmony_ci sc->base_addr = dd->piobase + ((hw_context & PIO_ADDR_CONTEXT_MASK) 7638c2ecf20Sopenharmony_ci << PIO_ADDR_CONTEXT_SHIFT); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* set base and credits */ 7668c2ecf20Sopenharmony_ci reg = ((sci->credits & SC(CTRL_CTXT_DEPTH_MASK)) 7678c2ecf20Sopenharmony_ci << SC(CTRL_CTXT_DEPTH_SHIFT)) 7688c2ecf20Sopenharmony_ci | ((sci->base & SC(CTRL_CTXT_BASE_MASK)) 7698c2ecf20Sopenharmony_ci << SC(CTRL_CTXT_BASE_SHIFT)); 7708c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(CTRL), reg); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci set_pio_integrity(sc); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* unmask all errors */ 7758c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(ERR_MASK), (u64)-1); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* set the default partition key */ 7788c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(CHECK_PARTITION_KEY), 7798c2ecf20Sopenharmony_ci (SC(CHECK_PARTITION_KEY_VALUE_MASK) & 7808c2ecf20Sopenharmony_ci DEFAULT_PKEY) << 7818c2ecf20Sopenharmony_ci SC(CHECK_PARTITION_KEY_VALUE_SHIFT)); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci /* per context type checks */ 7848c2ecf20Sopenharmony_ci if (type == SC_USER) { 7858c2ecf20Sopenharmony_ci opval = USER_OPCODE_CHECK_VAL; 7868c2ecf20Sopenharmony_ci opmask = USER_OPCODE_CHECK_MASK; 7878c2ecf20Sopenharmony_ci } else { 7888c2ecf20Sopenharmony_ci opval = OPCODE_CHECK_VAL_DISABLED; 7898c2ecf20Sopenharmony_ci opmask = OPCODE_CHECK_MASK_DISABLED; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci /* set the send context check opcode mask and value */ 7938c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(CHECK_OPCODE), 7948c2ecf20Sopenharmony_ci ((u64)opmask << SC(CHECK_OPCODE_MASK_SHIFT)) | 7958c2ecf20Sopenharmony_ci ((u64)opval << SC(CHECK_OPCODE_VALUE_SHIFT))); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci /* set up credit return */ 7988c2ecf20Sopenharmony_ci reg = dma & SC(CREDIT_RETURN_ADDR_ADDRESS_SMASK); 7998c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(CREDIT_RETURN_ADDR), reg); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci /* 8028c2ecf20Sopenharmony_ci * Calculate the initial credit return threshold. 8038c2ecf20Sopenharmony_ci * 8048c2ecf20Sopenharmony_ci * For Ack contexts, set a threshold for half the credits. 8058c2ecf20Sopenharmony_ci * For User contexts use the given percentage. This has been 8068c2ecf20Sopenharmony_ci * sanitized on driver start-up. 8078c2ecf20Sopenharmony_ci * For Kernel contexts, use the default MTU plus a header 8088c2ecf20Sopenharmony_ci * or half the credits, whichever is smaller. This should 8098c2ecf20Sopenharmony_ci * work for both the 3-deep buffering allocation and the 8108c2ecf20Sopenharmony_ci * pooling allocation. 8118c2ecf20Sopenharmony_ci */ 8128c2ecf20Sopenharmony_ci if (type == SC_ACK) { 8138c2ecf20Sopenharmony_ci thresh = sc_percent_to_threshold(sc, 50); 8148c2ecf20Sopenharmony_ci } else if (type == SC_USER) { 8158c2ecf20Sopenharmony_ci thresh = sc_percent_to_threshold(sc, 8168c2ecf20Sopenharmony_ci user_credit_return_threshold); 8178c2ecf20Sopenharmony_ci } else { /* kernel */ 8188c2ecf20Sopenharmony_ci thresh = min(sc_percent_to_threshold(sc, 50), 8198c2ecf20Sopenharmony_ci sc_mtu_to_threshold(sc, hfi1_max_mtu, 8208c2ecf20Sopenharmony_ci hdrqentsize)); 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci reg = thresh << SC(CREDIT_CTRL_THRESHOLD_SHIFT); 8238c2ecf20Sopenharmony_ci /* add in early return */ 8248c2ecf20Sopenharmony_ci if (type == SC_USER && HFI1_CAP_IS_USET(EARLY_CREDIT_RETURN)) 8258c2ecf20Sopenharmony_ci reg |= SC(CREDIT_CTRL_EARLY_RETURN_SMASK); 8268c2ecf20Sopenharmony_ci else if (HFI1_CAP_IS_KSET(EARLY_CREDIT_RETURN)) /* kernel, ack */ 8278c2ecf20Sopenharmony_ci reg |= SC(CREDIT_CTRL_EARLY_RETURN_SMASK); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* set up write-through credit_ctrl */ 8308c2ecf20Sopenharmony_ci sc->credit_ctrl = reg; 8318c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(CREDIT_CTRL), reg); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* User send contexts should not allow sending on VL15 */ 8348c2ecf20Sopenharmony_ci if (type == SC_USER) { 8358c2ecf20Sopenharmony_ci reg = 1ULL << 15; 8368c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(CHECK_VL), reg); 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dd->sc_lock, flags); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* 8428c2ecf20Sopenharmony_ci * Allocate shadow ring to track outstanding PIO buffers _after_ 8438c2ecf20Sopenharmony_ci * unlocking. We don't know the size until the lock is held and 8448c2ecf20Sopenharmony_ci * we can't allocate while the lock is held. No one is using 8458c2ecf20Sopenharmony_ci * the context yet, so allocate it now. 8468c2ecf20Sopenharmony_ci * 8478c2ecf20Sopenharmony_ci * User contexts do not get a shadow ring. 8488c2ecf20Sopenharmony_ci */ 8498c2ecf20Sopenharmony_ci if (type != SC_USER) { 8508c2ecf20Sopenharmony_ci /* 8518c2ecf20Sopenharmony_ci * Size the shadow ring 1 larger than the number of credits 8528c2ecf20Sopenharmony_ci * so head == tail can mean empty. 8538c2ecf20Sopenharmony_ci */ 8548c2ecf20Sopenharmony_ci sc->sr_size = sci->credits + 1; 8558c2ecf20Sopenharmony_ci sc->sr = kcalloc_node(sc->sr_size, 8568c2ecf20Sopenharmony_ci sizeof(union pio_shadow_ring), 8578c2ecf20Sopenharmony_ci GFP_KERNEL, numa); 8588c2ecf20Sopenharmony_ci if (!sc->sr) { 8598c2ecf20Sopenharmony_ci sc_free(sc); 8608c2ecf20Sopenharmony_ci return NULL; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci hfi1_cdbg(PIO, 8658c2ecf20Sopenharmony_ci "Send context %u(%u) %s group %u credits %u credit_ctrl 0x%llx threshold %u\n", 8668c2ecf20Sopenharmony_ci sw_index, 8678c2ecf20Sopenharmony_ci hw_context, 8688c2ecf20Sopenharmony_ci sc_type_name(type), 8698c2ecf20Sopenharmony_ci sc->group, 8708c2ecf20Sopenharmony_ci sc->credits, 8718c2ecf20Sopenharmony_ci sc->credit_ctrl, 8728c2ecf20Sopenharmony_ci thresh); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci return sc; 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci/* free a per-NUMA send context structure */ 8788c2ecf20Sopenharmony_civoid sc_free(struct send_context *sc) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci struct hfi1_devdata *dd; 8818c2ecf20Sopenharmony_ci unsigned long flags; 8828c2ecf20Sopenharmony_ci u32 sw_index; 8838c2ecf20Sopenharmony_ci u32 hw_context; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (!sc) 8868c2ecf20Sopenharmony_ci return; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci sc->flags |= SCF_IN_FREE; /* ensure no restarts */ 8898c2ecf20Sopenharmony_ci dd = sc->dd; 8908c2ecf20Sopenharmony_ci if (!list_empty(&sc->piowait)) 8918c2ecf20Sopenharmony_ci dd_dev_err(dd, "piowait list not empty!\n"); 8928c2ecf20Sopenharmony_ci sw_index = sc->sw_index; 8938c2ecf20Sopenharmony_ci hw_context = sc->hw_context; 8948c2ecf20Sopenharmony_ci sc_disable(sc); /* make sure the HW is disabled */ 8958c2ecf20Sopenharmony_ci flush_work(&sc->halt_work); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci spin_lock_irqsave(&dd->sc_lock, flags); 8988c2ecf20Sopenharmony_ci dd->send_contexts[sw_index].sc = NULL; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci /* clear/disable all registers set in sc_alloc */ 9018c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(CTRL), 0); 9028c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(CHECK_ENABLE), 0); 9038c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(ERR_MASK), 0); 9048c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(CHECK_PARTITION_KEY), 0); 9058c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(CHECK_OPCODE), 0); 9068c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(CREDIT_RETURN_ADDR), 0); 9078c2ecf20Sopenharmony_ci write_kctxt_csr(dd, hw_context, SC(CREDIT_CTRL), 0); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* release the index and context for re-use */ 9108c2ecf20Sopenharmony_ci sc_hw_free(dd, sw_index, hw_context); 9118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dd->sc_lock, flags); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci kfree(sc->sr); 9148c2ecf20Sopenharmony_ci free_percpu(sc->buffers_allocated); 9158c2ecf20Sopenharmony_ci kfree(sc); 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci/* disable the context */ 9198c2ecf20Sopenharmony_civoid sc_disable(struct send_context *sc) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci u64 reg; 9228c2ecf20Sopenharmony_ci struct pio_buf *pbuf; 9238c2ecf20Sopenharmony_ci LIST_HEAD(wake_list); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci if (!sc) 9268c2ecf20Sopenharmony_ci return; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci /* do all steps, even if already disabled */ 9298c2ecf20Sopenharmony_ci spin_lock_irq(&sc->alloc_lock); 9308c2ecf20Sopenharmony_ci reg = read_kctxt_csr(sc->dd, sc->hw_context, SC(CTRL)); 9318c2ecf20Sopenharmony_ci reg &= ~SC(CTRL_CTXT_ENABLE_SMASK); 9328c2ecf20Sopenharmony_ci sc->flags &= ~SCF_ENABLED; 9338c2ecf20Sopenharmony_ci sc_wait_for_packet_egress(sc, 1); 9348c2ecf20Sopenharmony_ci write_kctxt_csr(sc->dd, sc->hw_context, SC(CTRL), reg); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci /* 9378c2ecf20Sopenharmony_ci * Flush any waiters. Once the context is disabled, 9388c2ecf20Sopenharmony_ci * credit return interrupts are stopped (although there 9398c2ecf20Sopenharmony_ci * could be one in-process when the context is disabled). 9408c2ecf20Sopenharmony_ci * Wait one microsecond for any lingering interrupts, then 9418c2ecf20Sopenharmony_ci * proceed with the flush. 9428c2ecf20Sopenharmony_ci */ 9438c2ecf20Sopenharmony_ci udelay(1); 9448c2ecf20Sopenharmony_ci spin_lock(&sc->release_lock); 9458c2ecf20Sopenharmony_ci if (sc->sr) { /* this context has a shadow ring */ 9468c2ecf20Sopenharmony_ci while (sc->sr_tail != sc->sr_head) { 9478c2ecf20Sopenharmony_ci pbuf = &sc->sr[sc->sr_tail].pbuf; 9488c2ecf20Sopenharmony_ci if (pbuf->cb) 9498c2ecf20Sopenharmony_ci (*pbuf->cb)(pbuf->arg, PRC_SC_DISABLE); 9508c2ecf20Sopenharmony_ci sc->sr_tail++; 9518c2ecf20Sopenharmony_ci if (sc->sr_tail >= sc->sr_size) 9528c2ecf20Sopenharmony_ci sc->sr_tail = 0; 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci spin_unlock(&sc->release_lock); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci write_seqlock(&sc->waitlock); 9588c2ecf20Sopenharmony_ci list_splice_init(&sc->piowait, &wake_list); 9598c2ecf20Sopenharmony_ci write_sequnlock(&sc->waitlock); 9608c2ecf20Sopenharmony_ci while (!list_empty(&wake_list)) { 9618c2ecf20Sopenharmony_ci struct iowait *wait; 9628c2ecf20Sopenharmony_ci struct rvt_qp *qp; 9638c2ecf20Sopenharmony_ci struct hfi1_qp_priv *priv; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci wait = list_first_entry(&wake_list, struct iowait, list); 9668c2ecf20Sopenharmony_ci qp = iowait_to_qp(wait); 9678c2ecf20Sopenharmony_ci priv = qp->priv; 9688c2ecf20Sopenharmony_ci list_del_init(&priv->s_iowait.list); 9698c2ecf20Sopenharmony_ci priv->s_iowait.lock = NULL; 9708c2ecf20Sopenharmony_ci hfi1_qp_wakeup(qp, RVT_S_WAIT_PIO | HFI1_S_WAIT_PIO_DRAIN); 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci spin_unlock_irq(&sc->alloc_lock); 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci/* return SendEgressCtxtStatus.PacketOccupancy */ 9778c2ecf20Sopenharmony_cistatic u64 packet_occupancy(u64 reg) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci return (reg & 9808c2ecf20Sopenharmony_ci SEND_EGRESS_CTXT_STATUS_CTXT_EGRESS_PACKET_OCCUPANCY_SMASK) 9818c2ecf20Sopenharmony_ci >> SEND_EGRESS_CTXT_STATUS_CTXT_EGRESS_PACKET_OCCUPANCY_SHIFT; 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci/* is egress halted on the context? */ 9858c2ecf20Sopenharmony_cistatic bool egress_halted(u64 reg) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci return !!(reg & SEND_EGRESS_CTXT_STATUS_CTXT_EGRESS_HALT_STATUS_SMASK); 9888c2ecf20Sopenharmony_ci} 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci/* is the send context halted? */ 9918c2ecf20Sopenharmony_cistatic bool is_sc_halted(struct hfi1_devdata *dd, u32 hw_context) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci return !!(read_kctxt_csr(dd, hw_context, SC(STATUS)) & 9948c2ecf20Sopenharmony_ci SC(STATUS_CTXT_HALTED_SMASK)); 9958c2ecf20Sopenharmony_ci} 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci/** 9988c2ecf20Sopenharmony_ci * sc_wait_for_packet_egress 9998c2ecf20Sopenharmony_ci * @sc: valid send context 10008c2ecf20Sopenharmony_ci * @pause: wait for credit return 10018c2ecf20Sopenharmony_ci * 10028c2ecf20Sopenharmony_ci * Wait for packet egress, optionally pause for credit return 10038c2ecf20Sopenharmony_ci * 10048c2ecf20Sopenharmony_ci * Egress halt and Context halt are not necessarily the same thing, so 10058c2ecf20Sopenharmony_ci * check for both. 10068c2ecf20Sopenharmony_ci * 10078c2ecf20Sopenharmony_ci * NOTE: The context halt bit may not be set immediately. Because of this, 10088c2ecf20Sopenharmony_ci * it is necessary to check the SW SFC_HALTED bit (set in the IRQ) and the HW 10098c2ecf20Sopenharmony_ci * context bit to determine if the context is halted. 10108c2ecf20Sopenharmony_ci */ 10118c2ecf20Sopenharmony_cistatic void sc_wait_for_packet_egress(struct send_context *sc, int pause) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = sc->dd; 10148c2ecf20Sopenharmony_ci u64 reg = 0; 10158c2ecf20Sopenharmony_ci u64 reg_prev; 10168c2ecf20Sopenharmony_ci u32 loop = 0; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci while (1) { 10198c2ecf20Sopenharmony_ci reg_prev = reg; 10208c2ecf20Sopenharmony_ci reg = read_csr(dd, sc->hw_context * 8 + 10218c2ecf20Sopenharmony_ci SEND_EGRESS_CTXT_STATUS); 10228c2ecf20Sopenharmony_ci /* done if any halt bits, SW or HW are set */ 10238c2ecf20Sopenharmony_ci if (sc->flags & SCF_HALTED || 10248c2ecf20Sopenharmony_ci is_sc_halted(dd, sc->hw_context) || egress_halted(reg)) 10258c2ecf20Sopenharmony_ci break; 10268c2ecf20Sopenharmony_ci reg = packet_occupancy(reg); 10278c2ecf20Sopenharmony_ci if (reg == 0) 10288c2ecf20Sopenharmony_ci break; 10298c2ecf20Sopenharmony_ci /* counter is reset if occupancy count changes */ 10308c2ecf20Sopenharmony_ci if (reg != reg_prev) 10318c2ecf20Sopenharmony_ci loop = 0; 10328c2ecf20Sopenharmony_ci if (loop > 50000) { 10338c2ecf20Sopenharmony_ci /* timed out - bounce the link */ 10348c2ecf20Sopenharmony_ci dd_dev_err(dd, 10358c2ecf20Sopenharmony_ci "%s: context %u(%u) timeout waiting for packets to egress, remaining count %u, bouncing link\n", 10368c2ecf20Sopenharmony_ci __func__, sc->sw_index, 10378c2ecf20Sopenharmony_ci sc->hw_context, (u32)reg); 10388c2ecf20Sopenharmony_ci queue_work(dd->pport->link_wq, 10398c2ecf20Sopenharmony_ci &dd->pport->link_bounce_work); 10408c2ecf20Sopenharmony_ci break; 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci loop++; 10438c2ecf20Sopenharmony_ci udelay(1); 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci if (pause) 10478c2ecf20Sopenharmony_ci /* Add additional delay to ensure chip returns all credits */ 10488c2ecf20Sopenharmony_ci pause_for_credit_return(dd); 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_civoid sc_wait(struct hfi1_devdata *dd) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci int i; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci for (i = 0; i < dd->num_send_contexts; i++) { 10568c2ecf20Sopenharmony_ci struct send_context *sc = dd->send_contexts[i].sc; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (!sc) 10598c2ecf20Sopenharmony_ci continue; 10608c2ecf20Sopenharmony_ci sc_wait_for_packet_egress(sc, 0); 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci/* 10658c2ecf20Sopenharmony_ci * Restart a context after it has been halted due to error. 10668c2ecf20Sopenharmony_ci * 10678c2ecf20Sopenharmony_ci * If the first step fails - wait for the halt to be asserted, return early. 10688c2ecf20Sopenharmony_ci * Otherwise complain about timeouts but keep going. 10698c2ecf20Sopenharmony_ci * 10708c2ecf20Sopenharmony_ci * It is expected that allocations (enabled flag bit) have been shut off 10718c2ecf20Sopenharmony_ci * already (only applies to kernel contexts). 10728c2ecf20Sopenharmony_ci */ 10738c2ecf20Sopenharmony_ciint sc_restart(struct send_context *sc) 10748c2ecf20Sopenharmony_ci{ 10758c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = sc->dd; 10768c2ecf20Sopenharmony_ci u64 reg; 10778c2ecf20Sopenharmony_ci u32 loop; 10788c2ecf20Sopenharmony_ci int count; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci /* bounce off if not halted, or being free'd */ 10818c2ecf20Sopenharmony_ci if (!(sc->flags & SCF_HALTED) || (sc->flags & SCF_IN_FREE)) 10828c2ecf20Sopenharmony_ci return -EINVAL; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci dd_dev_info(dd, "restarting send context %u(%u)\n", sc->sw_index, 10858c2ecf20Sopenharmony_ci sc->hw_context); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* 10888c2ecf20Sopenharmony_ci * Step 1: Wait for the context to actually halt. 10898c2ecf20Sopenharmony_ci * 10908c2ecf20Sopenharmony_ci * The error interrupt is asynchronous to actually setting halt 10918c2ecf20Sopenharmony_ci * on the context. 10928c2ecf20Sopenharmony_ci */ 10938c2ecf20Sopenharmony_ci loop = 0; 10948c2ecf20Sopenharmony_ci while (1) { 10958c2ecf20Sopenharmony_ci reg = read_kctxt_csr(dd, sc->hw_context, SC(STATUS)); 10968c2ecf20Sopenharmony_ci if (reg & SC(STATUS_CTXT_HALTED_SMASK)) 10978c2ecf20Sopenharmony_ci break; 10988c2ecf20Sopenharmony_ci if (loop > 100) { 10998c2ecf20Sopenharmony_ci dd_dev_err(dd, "%s: context %u(%u) not halting, skipping\n", 11008c2ecf20Sopenharmony_ci __func__, sc->sw_index, sc->hw_context); 11018c2ecf20Sopenharmony_ci return -ETIME; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci loop++; 11048c2ecf20Sopenharmony_ci udelay(1); 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci /* 11088c2ecf20Sopenharmony_ci * Step 2: Ensure no users are still trying to write to PIO. 11098c2ecf20Sopenharmony_ci * 11108c2ecf20Sopenharmony_ci * For kernel contexts, we have already turned off buffer allocation. 11118c2ecf20Sopenharmony_ci * Now wait for the buffer count to go to zero. 11128c2ecf20Sopenharmony_ci * 11138c2ecf20Sopenharmony_ci * For user contexts, the user handling code has cut off write access 11148c2ecf20Sopenharmony_ci * to the context's PIO pages before calling this routine and will 11158c2ecf20Sopenharmony_ci * restore write access after this routine returns. 11168c2ecf20Sopenharmony_ci */ 11178c2ecf20Sopenharmony_ci if (sc->type != SC_USER) { 11188c2ecf20Sopenharmony_ci /* kernel context */ 11198c2ecf20Sopenharmony_ci loop = 0; 11208c2ecf20Sopenharmony_ci while (1) { 11218c2ecf20Sopenharmony_ci count = get_buffers_allocated(sc); 11228c2ecf20Sopenharmony_ci if (count == 0) 11238c2ecf20Sopenharmony_ci break; 11248c2ecf20Sopenharmony_ci if (loop > 100) { 11258c2ecf20Sopenharmony_ci dd_dev_err(dd, 11268c2ecf20Sopenharmony_ci "%s: context %u(%u) timeout waiting for PIO buffers to zero, remaining %d\n", 11278c2ecf20Sopenharmony_ci __func__, sc->sw_index, 11288c2ecf20Sopenharmony_ci sc->hw_context, count); 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci loop++; 11318c2ecf20Sopenharmony_ci udelay(1); 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci /* 11368c2ecf20Sopenharmony_ci * Step 3: Wait for all packets to egress. 11378c2ecf20Sopenharmony_ci * This is done while disabling the send context 11388c2ecf20Sopenharmony_ci * 11398c2ecf20Sopenharmony_ci * Step 4: Disable the context 11408c2ecf20Sopenharmony_ci * 11418c2ecf20Sopenharmony_ci * This is a superset of the halt. After the disable, the 11428c2ecf20Sopenharmony_ci * errors can be cleared. 11438c2ecf20Sopenharmony_ci */ 11448c2ecf20Sopenharmony_ci sc_disable(sc); 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci /* 11478c2ecf20Sopenharmony_ci * Step 5: Enable the context 11488c2ecf20Sopenharmony_ci * 11498c2ecf20Sopenharmony_ci * This enable will clear the halted flag and per-send context 11508c2ecf20Sopenharmony_ci * error flags. 11518c2ecf20Sopenharmony_ci */ 11528c2ecf20Sopenharmony_ci return sc_enable(sc); 11538c2ecf20Sopenharmony_ci} 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci/* 11568c2ecf20Sopenharmony_ci * PIO freeze processing. To be called after the TXE block is fully frozen. 11578c2ecf20Sopenharmony_ci * Go through all frozen send contexts and disable them. The contexts are 11588c2ecf20Sopenharmony_ci * already stopped by the freeze. 11598c2ecf20Sopenharmony_ci */ 11608c2ecf20Sopenharmony_civoid pio_freeze(struct hfi1_devdata *dd) 11618c2ecf20Sopenharmony_ci{ 11628c2ecf20Sopenharmony_ci struct send_context *sc; 11638c2ecf20Sopenharmony_ci int i; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci for (i = 0; i < dd->num_send_contexts; i++) { 11668c2ecf20Sopenharmony_ci sc = dd->send_contexts[i].sc; 11678c2ecf20Sopenharmony_ci /* 11688c2ecf20Sopenharmony_ci * Don't disable unallocated, unfrozen, or user send contexts. 11698c2ecf20Sopenharmony_ci * User send contexts will be disabled when the process 11708c2ecf20Sopenharmony_ci * calls into the driver to reset its context. 11718c2ecf20Sopenharmony_ci */ 11728c2ecf20Sopenharmony_ci if (!sc || !(sc->flags & SCF_FROZEN) || sc->type == SC_USER) 11738c2ecf20Sopenharmony_ci continue; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci /* only need to disable, the context is already stopped */ 11768c2ecf20Sopenharmony_ci sc_disable(sc); 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci/* 11818c2ecf20Sopenharmony_ci * Unfreeze PIO for kernel send contexts. The precondition for calling this 11828c2ecf20Sopenharmony_ci * is that all PIO send contexts have been disabled and the SPC freeze has 11838c2ecf20Sopenharmony_ci * been cleared. Now perform the last step and re-enable each kernel context. 11848c2ecf20Sopenharmony_ci * User (PSM) processing will occur when PSM calls into the kernel to 11858c2ecf20Sopenharmony_ci * acknowledge the freeze. 11868c2ecf20Sopenharmony_ci */ 11878c2ecf20Sopenharmony_civoid pio_kernel_unfreeze(struct hfi1_devdata *dd) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci struct send_context *sc; 11908c2ecf20Sopenharmony_ci int i; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci for (i = 0; i < dd->num_send_contexts; i++) { 11938c2ecf20Sopenharmony_ci sc = dd->send_contexts[i].sc; 11948c2ecf20Sopenharmony_ci if (!sc || !(sc->flags & SCF_FROZEN) || sc->type == SC_USER) 11958c2ecf20Sopenharmony_ci continue; 11968c2ecf20Sopenharmony_ci if (sc->flags & SCF_LINK_DOWN) 11978c2ecf20Sopenharmony_ci continue; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci sc_enable(sc); /* will clear the sc frozen flag */ 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci} 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci/** 12048c2ecf20Sopenharmony_ci * pio_kernel_linkup() - Re-enable send contexts after linkup event 12058c2ecf20Sopenharmony_ci * @dd: valid devive data 12068c2ecf20Sopenharmony_ci * 12078c2ecf20Sopenharmony_ci * When the link goes down, the freeze path is taken. However, a link down 12088c2ecf20Sopenharmony_ci * event is different from a freeze because if the send context is re-enabled 12098c2ecf20Sopenharmony_ci * whowever is sending data will start sending data again, which will hang 12108c2ecf20Sopenharmony_ci * any QP that is sending data. 12118c2ecf20Sopenharmony_ci * 12128c2ecf20Sopenharmony_ci * The freeze path now looks at the type of event that occurs and takes this 12138c2ecf20Sopenharmony_ci * path for link down event. 12148c2ecf20Sopenharmony_ci */ 12158c2ecf20Sopenharmony_civoid pio_kernel_linkup(struct hfi1_devdata *dd) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci struct send_context *sc; 12188c2ecf20Sopenharmony_ci int i; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci for (i = 0; i < dd->num_send_contexts; i++) { 12218c2ecf20Sopenharmony_ci sc = dd->send_contexts[i].sc; 12228c2ecf20Sopenharmony_ci if (!sc || !(sc->flags & SCF_LINK_DOWN) || sc->type == SC_USER) 12238c2ecf20Sopenharmony_ci continue; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci sc_enable(sc); /* will clear the sc link down flag */ 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci} 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci/* 12308c2ecf20Sopenharmony_ci * Wait for the SendPioInitCtxt.PioInitInProgress bit to clear. 12318c2ecf20Sopenharmony_ci * Returns: 12328c2ecf20Sopenharmony_ci * -ETIMEDOUT - if we wait too long 12338c2ecf20Sopenharmony_ci * -EIO - if there was an error 12348c2ecf20Sopenharmony_ci */ 12358c2ecf20Sopenharmony_cistatic int pio_init_wait_progress(struct hfi1_devdata *dd) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci u64 reg; 12388c2ecf20Sopenharmony_ci int max, count = 0; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci /* max is the longest possible HW init time / delay */ 12418c2ecf20Sopenharmony_ci max = (dd->icode == ICODE_FPGA_EMULATION) ? 120 : 5; 12428c2ecf20Sopenharmony_ci while (1) { 12438c2ecf20Sopenharmony_ci reg = read_csr(dd, SEND_PIO_INIT_CTXT); 12448c2ecf20Sopenharmony_ci if (!(reg & SEND_PIO_INIT_CTXT_PIO_INIT_IN_PROGRESS_SMASK)) 12458c2ecf20Sopenharmony_ci break; 12468c2ecf20Sopenharmony_ci if (count >= max) 12478c2ecf20Sopenharmony_ci return -ETIMEDOUT; 12488c2ecf20Sopenharmony_ci udelay(5); 12498c2ecf20Sopenharmony_ci count++; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci return reg & SEND_PIO_INIT_CTXT_PIO_INIT_ERR_SMASK ? -EIO : 0; 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci/* 12568c2ecf20Sopenharmony_ci * Reset all of the send contexts to their power-on state. Used 12578c2ecf20Sopenharmony_ci * only during manual init - no lock against sc_enable needed. 12588c2ecf20Sopenharmony_ci */ 12598c2ecf20Sopenharmony_civoid pio_reset_all(struct hfi1_devdata *dd) 12608c2ecf20Sopenharmony_ci{ 12618c2ecf20Sopenharmony_ci int ret; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci /* make sure the init engine is not busy */ 12648c2ecf20Sopenharmony_ci ret = pio_init_wait_progress(dd); 12658c2ecf20Sopenharmony_ci /* ignore any timeout */ 12668c2ecf20Sopenharmony_ci if (ret == -EIO) { 12678c2ecf20Sopenharmony_ci /* clear the error */ 12688c2ecf20Sopenharmony_ci write_csr(dd, SEND_PIO_ERR_CLEAR, 12698c2ecf20Sopenharmony_ci SEND_PIO_ERR_CLEAR_PIO_INIT_SM_IN_ERR_SMASK); 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci /* reset init all */ 12738c2ecf20Sopenharmony_ci write_csr(dd, SEND_PIO_INIT_CTXT, 12748c2ecf20Sopenharmony_ci SEND_PIO_INIT_CTXT_PIO_ALL_CTXT_INIT_SMASK); 12758c2ecf20Sopenharmony_ci udelay(2); 12768c2ecf20Sopenharmony_ci ret = pio_init_wait_progress(dd); 12778c2ecf20Sopenharmony_ci if (ret < 0) { 12788c2ecf20Sopenharmony_ci dd_dev_err(dd, 12798c2ecf20Sopenharmony_ci "PIO send context init %s while initializing all PIO blocks\n", 12808c2ecf20Sopenharmony_ci ret == -ETIMEDOUT ? "is stuck" : "had an error"); 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci/* enable the context */ 12858c2ecf20Sopenharmony_ciint sc_enable(struct send_context *sc) 12868c2ecf20Sopenharmony_ci{ 12878c2ecf20Sopenharmony_ci u64 sc_ctrl, reg, pio; 12888c2ecf20Sopenharmony_ci struct hfi1_devdata *dd; 12898c2ecf20Sopenharmony_ci unsigned long flags; 12908c2ecf20Sopenharmony_ci int ret = 0; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci if (!sc) 12938c2ecf20Sopenharmony_ci return -EINVAL; 12948c2ecf20Sopenharmony_ci dd = sc->dd; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci /* 12978c2ecf20Sopenharmony_ci * Obtain the allocator lock to guard against any allocation 12988c2ecf20Sopenharmony_ci * attempts (which should not happen prior to context being 12998c2ecf20Sopenharmony_ci * enabled). On the release/disable side we don't need to 13008c2ecf20Sopenharmony_ci * worry about locking since the releaser will not do anything 13018c2ecf20Sopenharmony_ci * if the context accounting values have not changed. 13028c2ecf20Sopenharmony_ci */ 13038c2ecf20Sopenharmony_ci spin_lock_irqsave(&sc->alloc_lock, flags); 13048c2ecf20Sopenharmony_ci sc_ctrl = read_kctxt_csr(dd, sc->hw_context, SC(CTRL)); 13058c2ecf20Sopenharmony_ci if ((sc_ctrl & SC(CTRL_CTXT_ENABLE_SMASK))) 13068c2ecf20Sopenharmony_ci goto unlock; /* already enabled */ 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci /* IMPORTANT: only clear free and fill if transitioning 0 -> 1 */ 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci *sc->hw_free = 0; 13118c2ecf20Sopenharmony_ci sc->free = 0; 13128c2ecf20Sopenharmony_ci sc->alloc_free = 0; 13138c2ecf20Sopenharmony_ci sc->fill = 0; 13148c2ecf20Sopenharmony_ci sc->fill_wrap = 0; 13158c2ecf20Sopenharmony_ci sc->sr_head = 0; 13168c2ecf20Sopenharmony_ci sc->sr_tail = 0; 13178c2ecf20Sopenharmony_ci sc->flags = 0; 13188c2ecf20Sopenharmony_ci /* the alloc lock insures no fast path allocation */ 13198c2ecf20Sopenharmony_ci reset_buffers_allocated(sc); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci /* 13228c2ecf20Sopenharmony_ci * Clear all per-context errors. Some of these will be set when 13238c2ecf20Sopenharmony_ci * we are re-enabling after a context halt. Now that the context 13248c2ecf20Sopenharmony_ci * is disabled, the halt will not clear until after the PIO init 13258c2ecf20Sopenharmony_ci * engine runs below. 13268c2ecf20Sopenharmony_ci */ 13278c2ecf20Sopenharmony_ci reg = read_kctxt_csr(dd, sc->hw_context, SC(ERR_STATUS)); 13288c2ecf20Sopenharmony_ci if (reg) 13298c2ecf20Sopenharmony_ci write_kctxt_csr(dd, sc->hw_context, SC(ERR_CLEAR), reg); 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci /* 13328c2ecf20Sopenharmony_ci * The HW PIO initialization engine can handle only one init 13338c2ecf20Sopenharmony_ci * request at a time. Serialize access to each device's engine. 13348c2ecf20Sopenharmony_ci */ 13358c2ecf20Sopenharmony_ci spin_lock(&dd->sc_init_lock); 13368c2ecf20Sopenharmony_ci /* 13378c2ecf20Sopenharmony_ci * Since access to this code block is serialized and 13388c2ecf20Sopenharmony_ci * each access waits for the initialization to complete 13398c2ecf20Sopenharmony_ci * before releasing the lock, the PIO initialization engine 13408c2ecf20Sopenharmony_ci * should not be in use, so we don't have to wait for the 13418c2ecf20Sopenharmony_ci * InProgress bit to go down. 13428c2ecf20Sopenharmony_ci */ 13438c2ecf20Sopenharmony_ci pio = ((sc->hw_context & SEND_PIO_INIT_CTXT_PIO_CTXT_NUM_MASK) << 13448c2ecf20Sopenharmony_ci SEND_PIO_INIT_CTXT_PIO_CTXT_NUM_SHIFT) | 13458c2ecf20Sopenharmony_ci SEND_PIO_INIT_CTXT_PIO_SINGLE_CTXT_INIT_SMASK; 13468c2ecf20Sopenharmony_ci write_csr(dd, SEND_PIO_INIT_CTXT, pio); 13478c2ecf20Sopenharmony_ci /* 13488c2ecf20Sopenharmony_ci * Wait until the engine is done. Give the chip the required time 13498c2ecf20Sopenharmony_ci * so, hopefully, we read the register just once. 13508c2ecf20Sopenharmony_ci */ 13518c2ecf20Sopenharmony_ci udelay(2); 13528c2ecf20Sopenharmony_ci ret = pio_init_wait_progress(dd); 13538c2ecf20Sopenharmony_ci spin_unlock(&dd->sc_init_lock); 13548c2ecf20Sopenharmony_ci if (ret) { 13558c2ecf20Sopenharmony_ci dd_dev_err(dd, 13568c2ecf20Sopenharmony_ci "sctxt%u(%u): Context not enabled due to init failure %d\n", 13578c2ecf20Sopenharmony_ci sc->sw_index, sc->hw_context, ret); 13588c2ecf20Sopenharmony_ci goto unlock; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci /* 13628c2ecf20Sopenharmony_ci * All is well. Enable the context. 13638c2ecf20Sopenharmony_ci */ 13648c2ecf20Sopenharmony_ci sc_ctrl |= SC(CTRL_CTXT_ENABLE_SMASK); 13658c2ecf20Sopenharmony_ci write_kctxt_csr(dd, sc->hw_context, SC(CTRL), sc_ctrl); 13668c2ecf20Sopenharmony_ci /* 13678c2ecf20Sopenharmony_ci * Read SendCtxtCtrl to force the write out and prevent a timing 13688c2ecf20Sopenharmony_ci * hazard where a PIO write may reach the context before the enable. 13698c2ecf20Sopenharmony_ci */ 13708c2ecf20Sopenharmony_ci read_kctxt_csr(dd, sc->hw_context, SC(CTRL)); 13718c2ecf20Sopenharmony_ci sc->flags |= SCF_ENABLED; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ciunlock: 13748c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->alloc_lock, flags); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci return ret; 13778c2ecf20Sopenharmony_ci} 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci/* force a credit return on the context */ 13808c2ecf20Sopenharmony_civoid sc_return_credits(struct send_context *sc) 13818c2ecf20Sopenharmony_ci{ 13828c2ecf20Sopenharmony_ci if (!sc) 13838c2ecf20Sopenharmony_ci return; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci /* a 0->1 transition schedules a credit return */ 13868c2ecf20Sopenharmony_ci write_kctxt_csr(sc->dd, sc->hw_context, SC(CREDIT_FORCE), 13878c2ecf20Sopenharmony_ci SC(CREDIT_FORCE_FORCE_RETURN_SMASK)); 13888c2ecf20Sopenharmony_ci /* 13898c2ecf20Sopenharmony_ci * Ensure that the write is flushed and the credit return is 13908c2ecf20Sopenharmony_ci * scheduled. We care more about the 0 -> 1 transition. 13918c2ecf20Sopenharmony_ci */ 13928c2ecf20Sopenharmony_ci read_kctxt_csr(sc->dd, sc->hw_context, SC(CREDIT_FORCE)); 13938c2ecf20Sopenharmony_ci /* set back to 0 for next time */ 13948c2ecf20Sopenharmony_ci write_kctxt_csr(sc->dd, sc->hw_context, SC(CREDIT_FORCE), 0); 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci/* allow all in-flight packets to drain on the context */ 13988c2ecf20Sopenharmony_civoid sc_flush(struct send_context *sc) 13998c2ecf20Sopenharmony_ci{ 14008c2ecf20Sopenharmony_ci if (!sc) 14018c2ecf20Sopenharmony_ci return; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci sc_wait_for_packet_egress(sc, 1); 14048c2ecf20Sopenharmony_ci} 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci/* drop all packets on the context, no waiting until they are sent */ 14078c2ecf20Sopenharmony_civoid sc_drop(struct send_context *sc) 14088c2ecf20Sopenharmony_ci{ 14098c2ecf20Sopenharmony_ci if (!sc) 14108c2ecf20Sopenharmony_ci return; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci dd_dev_info(sc->dd, "%s: context %u(%u) - not implemented\n", 14138c2ecf20Sopenharmony_ci __func__, sc->sw_index, sc->hw_context); 14148c2ecf20Sopenharmony_ci} 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci/* 14178c2ecf20Sopenharmony_ci * Start the software reaction to a context halt or SPC freeze: 14188c2ecf20Sopenharmony_ci * - mark the context as halted or frozen 14198c2ecf20Sopenharmony_ci * - stop buffer allocations 14208c2ecf20Sopenharmony_ci * 14218c2ecf20Sopenharmony_ci * Called from the error interrupt. Other work is deferred until 14228c2ecf20Sopenharmony_ci * out of the interrupt. 14238c2ecf20Sopenharmony_ci */ 14248c2ecf20Sopenharmony_civoid sc_stop(struct send_context *sc, int flag) 14258c2ecf20Sopenharmony_ci{ 14268c2ecf20Sopenharmony_ci unsigned long flags; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci /* stop buffer allocations */ 14298c2ecf20Sopenharmony_ci spin_lock_irqsave(&sc->alloc_lock, flags); 14308c2ecf20Sopenharmony_ci /* mark the context */ 14318c2ecf20Sopenharmony_ci sc->flags |= flag; 14328c2ecf20Sopenharmony_ci sc->flags &= ~SCF_ENABLED; 14338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->alloc_lock, flags); 14348c2ecf20Sopenharmony_ci wake_up(&sc->halt_wait); 14358c2ecf20Sopenharmony_ci} 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci#define BLOCK_DWORDS (PIO_BLOCK_SIZE / sizeof(u32)) 14388c2ecf20Sopenharmony_ci#define dwords_to_blocks(x) DIV_ROUND_UP(x, BLOCK_DWORDS) 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci/* 14418c2ecf20Sopenharmony_ci * The send context buffer "allocator". 14428c2ecf20Sopenharmony_ci * 14438c2ecf20Sopenharmony_ci * @sc: the PIO send context we are allocating from 14448c2ecf20Sopenharmony_ci * @len: length of whole packet - including PBC - in dwords 14458c2ecf20Sopenharmony_ci * @cb: optional callback to call when the buffer is finished sending 14468c2ecf20Sopenharmony_ci * @arg: argument for cb 14478c2ecf20Sopenharmony_ci * 14488c2ecf20Sopenharmony_ci * Return a pointer to a PIO buffer, NULL if not enough room, -ECOMM 14498c2ecf20Sopenharmony_ci * when link is down. 14508c2ecf20Sopenharmony_ci */ 14518c2ecf20Sopenharmony_cistruct pio_buf *sc_buffer_alloc(struct send_context *sc, u32 dw_len, 14528c2ecf20Sopenharmony_ci pio_release_cb cb, void *arg) 14538c2ecf20Sopenharmony_ci{ 14548c2ecf20Sopenharmony_ci struct pio_buf *pbuf = NULL; 14558c2ecf20Sopenharmony_ci unsigned long flags; 14568c2ecf20Sopenharmony_ci unsigned long avail; 14578c2ecf20Sopenharmony_ci unsigned long blocks = dwords_to_blocks(dw_len); 14588c2ecf20Sopenharmony_ci u32 fill_wrap; 14598c2ecf20Sopenharmony_ci int trycount = 0; 14608c2ecf20Sopenharmony_ci u32 head, next; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci spin_lock_irqsave(&sc->alloc_lock, flags); 14638c2ecf20Sopenharmony_ci if (!(sc->flags & SCF_ENABLED)) { 14648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->alloc_lock, flags); 14658c2ecf20Sopenharmony_ci return ERR_PTR(-ECOMM); 14668c2ecf20Sopenharmony_ci } 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ciretry: 14698c2ecf20Sopenharmony_ci avail = (unsigned long)sc->credits - (sc->fill - sc->alloc_free); 14708c2ecf20Sopenharmony_ci if (blocks > avail) { 14718c2ecf20Sopenharmony_ci /* not enough room */ 14728c2ecf20Sopenharmony_ci if (unlikely(trycount)) { /* already tried to get more room */ 14738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->alloc_lock, flags); 14748c2ecf20Sopenharmony_ci goto done; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci /* copy from receiver cache line and recalculate */ 14778c2ecf20Sopenharmony_ci sc->alloc_free = READ_ONCE(sc->free); 14788c2ecf20Sopenharmony_ci avail = 14798c2ecf20Sopenharmony_ci (unsigned long)sc->credits - 14808c2ecf20Sopenharmony_ci (sc->fill - sc->alloc_free); 14818c2ecf20Sopenharmony_ci if (blocks > avail) { 14828c2ecf20Sopenharmony_ci /* still no room, actively update */ 14838c2ecf20Sopenharmony_ci sc_release_update(sc); 14848c2ecf20Sopenharmony_ci sc->alloc_free = READ_ONCE(sc->free); 14858c2ecf20Sopenharmony_ci trycount++; 14868c2ecf20Sopenharmony_ci goto retry; 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci /* there is enough room */ 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci preempt_disable(); 14938c2ecf20Sopenharmony_ci this_cpu_inc(*sc->buffers_allocated); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci /* read this once */ 14968c2ecf20Sopenharmony_ci head = sc->sr_head; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci /* "allocate" the buffer */ 14998c2ecf20Sopenharmony_ci sc->fill += blocks; 15008c2ecf20Sopenharmony_ci fill_wrap = sc->fill_wrap; 15018c2ecf20Sopenharmony_ci sc->fill_wrap += blocks; 15028c2ecf20Sopenharmony_ci if (sc->fill_wrap >= sc->credits) 15038c2ecf20Sopenharmony_ci sc->fill_wrap = sc->fill_wrap - sc->credits; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci /* 15068c2ecf20Sopenharmony_ci * Fill the parts that the releaser looks at before moving the head. 15078c2ecf20Sopenharmony_ci * The only necessary piece is the sent_at field. The credits 15088c2ecf20Sopenharmony_ci * we have just allocated cannot have been returned yet, so the 15098c2ecf20Sopenharmony_ci * cb and arg will not be looked at for a "while". Put them 15108c2ecf20Sopenharmony_ci * on this side of the memory barrier anyway. 15118c2ecf20Sopenharmony_ci */ 15128c2ecf20Sopenharmony_ci pbuf = &sc->sr[head].pbuf; 15138c2ecf20Sopenharmony_ci pbuf->sent_at = sc->fill; 15148c2ecf20Sopenharmony_ci pbuf->cb = cb; 15158c2ecf20Sopenharmony_ci pbuf->arg = arg; 15168c2ecf20Sopenharmony_ci pbuf->sc = sc; /* could be filled in at sc->sr init time */ 15178c2ecf20Sopenharmony_ci /* make sure this is in memory before updating the head */ 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci /* calculate next head index, do not store */ 15208c2ecf20Sopenharmony_ci next = head + 1; 15218c2ecf20Sopenharmony_ci if (next >= sc->sr_size) 15228c2ecf20Sopenharmony_ci next = 0; 15238c2ecf20Sopenharmony_ci /* 15248c2ecf20Sopenharmony_ci * update the head - must be last! - the releaser can look at fields 15258c2ecf20Sopenharmony_ci * in pbuf once we move the head 15268c2ecf20Sopenharmony_ci */ 15278c2ecf20Sopenharmony_ci smp_wmb(); 15288c2ecf20Sopenharmony_ci sc->sr_head = next; 15298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->alloc_lock, flags); 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci /* finish filling in the buffer outside the lock */ 15328c2ecf20Sopenharmony_ci pbuf->start = sc->base_addr + fill_wrap * PIO_BLOCK_SIZE; 15338c2ecf20Sopenharmony_ci pbuf->end = sc->base_addr + sc->size; 15348c2ecf20Sopenharmony_ci pbuf->qw_written = 0; 15358c2ecf20Sopenharmony_ci pbuf->carry_bytes = 0; 15368c2ecf20Sopenharmony_ci pbuf->carry.val64 = 0; 15378c2ecf20Sopenharmony_cidone: 15388c2ecf20Sopenharmony_ci return pbuf; 15398c2ecf20Sopenharmony_ci} 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci/* 15428c2ecf20Sopenharmony_ci * There are at least two entities that can turn on credit return 15438c2ecf20Sopenharmony_ci * interrupts and they can overlap. Avoid problems by implementing 15448c2ecf20Sopenharmony_ci * a count scheme that is enforced by a lock. The lock is needed because 15458c2ecf20Sopenharmony_ci * the count and CSR write must be paired. 15468c2ecf20Sopenharmony_ci */ 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci/* 15498c2ecf20Sopenharmony_ci * Start credit return interrupts. This is managed by a count. If already 15508c2ecf20Sopenharmony_ci * on, just increment the count. 15518c2ecf20Sopenharmony_ci */ 15528c2ecf20Sopenharmony_civoid sc_add_credit_return_intr(struct send_context *sc) 15538c2ecf20Sopenharmony_ci{ 15548c2ecf20Sopenharmony_ci unsigned long flags; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci /* lock must surround both the count change and the CSR update */ 15578c2ecf20Sopenharmony_ci spin_lock_irqsave(&sc->credit_ctrl_lock, flags); 15588c2ecf20Sopenharmony_ci if (sc->credit_intr_count == 0) { 15598c2ecf20Sopenharmony_ci sc->credit_ctrl |= SC(CREDIT_CTRL_CREDIT_INTR_SMASK); 15608c2ecf20Sopenharmony_ci write_kctxt_csr(sc->dd, sc->hw_context, 15618c2ecf20Sopenharmony_ci SC(CREDIT_CTRL), sc->credit_ctrl); 15628c2ecf20Sopenharmony_ci } 15638c2ecf20Sopenharmony_ci sc->credit_intr_count++; 15648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->credit_ctrl_lock, flags); 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci/* 15688c2ecf20Sopenharmony_ci * Stop credit return interrupts. This is managed by a count. Decrement the 15698c2ecf20Sopenharmony_ci * count, if the last user, then turn the credit interrupts off. 15708c2ecf20Sopenharmony_ci */ 15718c2ecf20Sopenharmony_civoid sc_del_credit_return_intr(struct send_context *sc) 15728c2ecf20Sopenharmony_ci{ 15738c2ecf20Sopenharmony_ci unsigned long flags; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci WARN_ON(sc->credit_intr_count == 0); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci /* lock must surround both the count change and the CSR update */ 15788c2ecf20Sopenharmony_ci spin_lock_irqsave(&sc->credit_ctrl_lock, flags); 15798c2ecf20Sopenharmony_ci sc->credit_intr_count--; 15808c2ecf20Sopenharmony_ci if (sc->credit_intr_count == 0) { 15818c2ecf20Sopenharmony_ci sc->credit_ctrl &= ~SC(CREDIT_CTRL_CREDIT_INTR_SMASK); 15828c2ecf20Sopenharmony_ci write_kctxt_csr(sc->dd, sc->hw_context, 15838c2ecf20Sopenharmony_ci SC(CREDIT_CTRL), sc->credit_ctrl); 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->credit_ctrl_lock, flags); 15868c2ecf20Sopenharmony_ci} 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci/* 15898c2ecf20Sopenharmony_ci * The caller must be careful when calling this. All needint calls 15908c2ecf20Sopenharmony_ci * must be paired with !needint. 15918c2ecf20Sopenharmony_ci */ 15928c2ecf20Sopenharmony_civoid hfi1_sc_wantpiobuf_intr(struct send_context *sc, u32 needint) 15938c2ecf20Sopenharmony_ci{ 15948c2ecf20Sopenharmony_ci if (needint) 15958c2ecf20Sopenharmony_ci sc_add_credit_return_intr(sc); 15968c2ecf20Sopenharmony_ci else 15978c2ecf20Sopenharmony_ci sc_del_credit_return_intr(sc); 15988c2ecf20Sopenharmony_ci trace_hfi1_wantpiointr(sc, needint, sc->credit_ctrl); 15998c2ecf20Sopenharmony_ci if (needint) 16008c2ecf20Sopenharmony_ci sc_return_credits(sc); 16018c2ecf20Sopenharmony_ci} 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci/** 16048c2ecf20Sopenharmony_ci * sc_piobufavail - callback when a PIO buffer is available 16058c2ecf20Sopenharmony_ci * @sc: the send context 16068c2ecf20Sopenharmony_ci * 16078c2ecf20Sopenharmony_ci * This is called from the interrupt handler when a PIO buffer is 16088c2ecf20Sopenharmony_ci * available after hfi1_verbs_send() returned an error that no buffers were 16098c2ecf20Sopenharmony_ci * available. Disable the interrupt if there are no more QPs waiting. 16108c2ecf20Sopenharmony_ci */ 16118c2ecf20Sopenharmony_cistatic void sc_piobufavail(struct send_context *sc) 16128c2ecf20Sopenharmony_ci{ 16138c2ecf20Sopenharmony_ci struct hfi1_devdata *dd = sc->dd; 16148c2ecf20Sopenharmony_ci struct list_head *list; 16158c2ecf20Sopenharmony_ci struct rvt_qp *qps[PIO_WAIT_BATCH_SIZE]; 16168c2ecf20Sopenharmony_ci struct rvt_qp *qp; 16178c2ecf20Sopenharmony_ci struct hfi1_qp_priv *priv; 16188c2ecf20Sopenharmony_ci unsigned long flags; 16198c2ecf20Sopenharmony_ci uint i, n = 0, top_idx = 0; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (dd->send_contexts[sc->sw_index].type != SC_KERNEL && 16228c2ecf20Sopenharmony_ci dd->send_contexts[sc->sw_index].type != SC_VL15) 16238c2ecf20Sopenharmony_ci return; 16248c2ecf20Sopenharmony_ci list = &sc->piowait; 16258c2ecf20Sopenharmony_ci /* 16268c2ecf20Sopenharmony_ci * Note: checking that the piowait list is empty and clearing 16278c2ecf20Sopenharmony_ci * the buffer available interrupt needs to be atomic or we 16288c2ecf20Sopenharmony_ci * could end up with QPs on the wait list with the interrupt 16298c2ecf20Sopenharmony_ci * disabled. 16308c2ecf20Sopenharmony_ci */ 16318c2ecf20Sopenharmony_ci write_seqlock_irqsave(&sc->waitlock, flags); 16328c2ecf20Sopenharmony_ci while (!list_empty(list)) { 16338c2ecf20Sopenharmony_ci struct iowait *wait; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci if (n == ARRAY_SIZE(qps)) 16368c2ecf20Sopenharmony_ci break; 16378c2ecf20Sopenharmony_ci wait = list_first_entry(list, struct iowait, list); 16388c2ecf20Sopenharmony_ci iowait_get_priority(wait); 16398c2ecf20Sopenharmony_ci qp = iowait_to_qp(wait); 16408c2ecf20Sopenharmony_ci priv = qp->priv; 16418c2ecf20Sopenharmony_ci list_del_init(&priv->s_iowait.list); 16428c2ecf20Sopenharmony_ci priv->s_iowait.lock = NULL; 16438c2ecf20Sopenharmony_ci if (n) { 16448c2ecf20Sopenharmony_ci priv = qps[top_idx]->priv; 16458c2ecf20Sopenharmony_ci top_idx = iowait_priority_update_top(wait, 16468c2ecf20Sopenharmony_ci &priv->s_iowait, 16478c2ecf20Sopenharmony_ci n, top_idx); 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci /* refcount held until actual wake up */ 16518c2ecf20Sopenharmony_ci qps[n++] = qp; 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci /* 16548c2ecf20Sopenharmony_ci * If there had been waiters and there are more 16558c2ecf20Sopenharmony_ci * insure that we redo the force to avoid a potential hang. 16568c2ecf20Sopenharmony_ci */ 16578c2ecf20Sopenharmony_ci if (n) { 16588c2ecf20Sopenharmony_ci hfi1_sc_wantpiobuf_intr(sc, 0); 16598c2ecf20Sopenharmony_ci if (!list_empty(list)) 16608c2ecf20Sopenharmony_ci hfi1_sc_wantpiobuf_intr(sc, 1); 16618c2ecf20Sopenharmony_ci } 16628c2ecf20Sopenharmony_ci write_sequnlock_irqrestore(&sc->waitlock, flags); 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci /* Wake up the top-priority one first */ 16658c2ecf20Sopenharmony_ci if (n) 16668c2ecf20Sopenharmony_ci hfi1_qp_wakeup(qps[top_idx], 16678c2ecf20Sopenharmony_ci RVT_S_WAIT_PIO | HFI1_S_WAIT_PIO_DRAIN); 16688c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) 16698c2ecf20Sopenharmony_ci if (i != top_idx) 16708c2ecf20Sopenharmony_ci hfi1_qp_wakeup(qps[i], 16718c2ecf20Sopenharmony_ci RVT_S_WAIT_PIO | HFI1_S_WAIT_PIO_DRAIN); 16728c2ecf20Sopenharmony_ci} 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci/* translate a send credit update to a bit code of reasons */ 16758c2ecf20Sopenharmony_cistatic inline int fill_code(u64 hw_free) 16768c2ecf20Sopenharmony_ci{ 16778c2ecf20Sopenharmony_ci int code = 0; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci if (hw_free & CR_STATUS_SMASK) 16808c2ecf20Sopenharmony_ci code |= PRC_STATUS_ERR; 16818c2ecf20Sopenharmony_ci if (hw_free & CR_CREDIT_RETURN_DUE_TO_PBC_SMASK) 16828c2ecf20Sopenharmony_ci code |= PRC_PBC; 16838c2ecf20Sopenharmony_ci if (hw_free & CR_CREDIT_RETURN_DUE_TO_THRESHOLD_SMASK) 16848c2ecf20Sopenharmony_ci code |= PRC_THRESHOLD; 16858c2ecf20Sopenharmony_ci if (hw_free & CR_CREDIT_RETURN_DUE_TO_ERR_SMASK) 16868c2ecf20Sopenharmony_ci code |= PRC_FILL_ERR; 16878c2ecf20Sopenharmony_ci if (hw_free & CR_CREDIT_RETURN_DUE_TO_FORCE_SMASK) 16888c2ecf20Sopenharmony_ci code |= PRC_SC_DISABLE; 16898c2ecf20Sopenharmony_ci return code; 16908c2ecf20Sopenharmony_ci} 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci/* use the jiffies compare to get the wrap right */ 16938c2ecf20Sopenharmony_ci#define sent_before(a, b) time_before(a, b) /* a < b */ 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci/* 16968c2ecf20Sopenharmony_ci * The send context buffer "releaser". 16978c2ecf20Sopenharmony_ci */ 16988c2ecf20Sopenharmony_civoid sc_release_update(struct send_context *sc) 16998c2ecf20Sopenharmony_ci{ 17008c2ecf20Sopenharmony_ci struct pio_buf *pbuf; 17018c2ecf20Sopenharmony_ci u64 hw_free; 17028c2ecf20Sopenharmony_ci u32 head, tail; 17038c2ecf20Sopenharmony_ci unsigned long old_free; 17048c2ecf20Sopenharmony_ci unsigned long free; 17058c2ecf20Sopenharmony_ci unsigned long extra; 17068c2ecf20Sopenharmony_ci unsigned long flags; 17078c2ecf20Sopenharmony_ci int code; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci if (!sc) 17108c2ecf20Sopenharmony_ci return; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci spin_lock_irqsave(&sc->release_lock, flags); 17138c2ecf20Sopenharmony_ci /* update free */ 17148c2ecf20Sopenharmony_ci hw_free = le64_to_cpu(*sc->hw_free); /* volatile read */ 17158c2ecf20Sopenharmony_ci old_free = sc->free; 17168c2ecf20Sopenharmony_ci extra = (((hw_free & CR_COUNTER_SMASK) >> CR_COUNTER_SHIFT) 17178c2ecf20Sopenharmony_ci - (old_free & CR_COUNTER_MASK)) 17188c2ecf20Sopenharmony_ci & CR_COUNTER_MASK; 17198c2ecf20Sopenharmony_ci free = old_free + extra; 17208c2ecf20Sopenharmony_ci trace_hfi1_piofree(sc, extra); 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci /* call sent buffer callbacks */ 17238c2ecf20Sopenharmony_ci code = -1; /* code not yet set */ 17248c2ecf20Sopenharmony_ci head = READ_ONCE(sc->sr_head); /* snapshot the head */ 17258c2ecf20Sopenharmony_ci tail = sc->sr_tail; 17268c2ecf20Sopenharmony_ci while (head != tail) { 17278c2ecf20Sopenharmony_ci pbuf = &sc->sr[tail].pbuf; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci if (sent_before(free, pbuf->sent_at)) { 17308c2ecf20Sopenharmony_ci /* not sent yet */ 17318c2ecf20Sopenharmony_ci break; 17328c2ecf20Sopenharmony_ci } 17338c2ecf20Sopenharmony_ci if (pbuf->cb) { 17348c2ecf20Sopenharmony_ci if (code < 0) /* fill in code on first user */ 17358c2ecf20Sopenharmony_ci code = fill_code(hw_free); 17368c2ecf20Sopenharmony_ci (*pbuf->cb)(pbuf->arg, code); 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci tail++; 17408c2ecf20Sopenharmony_ci if (tail >= sc->sr_size) 17418c2ecf20Sopenharmony_ci tail = 0; 17428c2ecf20Sopenharmony_ci } 17438c2ecf20Sopenharmony_ci sc->sr_tail = tail; 17448c2ecf20Sopenharmony_ci /* make sure tail is updated before free */ 17458c2ecf20Sopenharmony_ci smp_wmb(); 17468c2ecf20Sopenharmony_ci sc->free = free; 17478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->release_lock, flags); 17488c2ecf20Sopenharmony_ci sc_piobufavail(sc); 17498c2ecf20Sopenharmony_ci} 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci/* 17528c2ecf20Sopenharmony_ci * Send context group releaser. Argument is the send context that caused 17538c2ecf20Sopenharmony_ci * the interrupt. Called from the send context interrupt handler. 17548c2ecf20Sopenharmony_ci * 17558c2ecf20Sopenharmony_ci * Call release on all contexts in the group. 17568c2ecf20Sopenharmony_ci * 17578c2ecf20Sopenharmony_ci * This routine takes the sc_lock without an irqsave because it is only 17588c2ecf20Sopenharmony_ci * called from an interrupt handler. Adjust if that changes. 17598c2ecf20Sopenharmony_ci */ 17608c2ecf20Sopenharmony_civoid sc_group_release_update(struct hfi1_devdata *dd, u32 hw_context) 17618c2ecf20Sopenharmony_ci{ 17628c2ecf20Sopenharmony_ci struct send_context *sc; 17638c2ecf20Sopenharmony_ci u32 sw_index; 17648c2ecf20Sopenharmony_ci u32 gc, gc_end; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci spin_lock(&dd->sc_lock); 17678c2ecf20Sopenharmony_ci sw_index = dd->hw_to_sw[hw_context]; 17688c2ecf20Sopenharmony_ci if (unlikely(sw_index >= dd->num_send_contexts)) { 17698c2ecf20Sopenharmony_ci dd_dev_err(dd, "%s: invalid hw (%u) to sw (%u) mapping\n", 17708c2ecf20Sopenharmony_ci __func__, hw_context, sw_index); 17718c2ecf20Sopenharmony_ci goto done; 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci sc = dd->send_contexts[sw_index].sc; 17748c2ecf20Sopenharmony_ci if (unlikely(!sc)) 17758c2ecf20Sopenharmony_ci goto done; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci gc = group_context(hw_context, sc->group); 17788c2ecf20Sopenharmony_ci gc_end = gc + group_size(sc->group); 17798c2ecf20Sopenharmony_ci for (; gc < gc_end; gc++) { 17808c2ecf20Sopenharmony_ci sw_index = dd->hw_to_sw[gc]; 17818c2ecf20Sopenharmony_ci if (unlikely(sw_index >= dd->num_send_contexts)) { 17828c2ecf20Sopenharmony_ci dd_dev_err(dd, 17838c2ecf20Sopenharmony_ci "%s: invalid hw (%u) to sw (%u) mapping\n", 17848c2ecf20Sopenharmony_ci __func__, hw_context, sw_index); 17858c2ecf20Sopenharmony_ci continue; 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci sc_release_update(dd->send_contexts[sw_index].sc); 17888c2ecf20Sopenharmony_ci } 17898c2ecf20Sopenharmony_cidone: 17908c2ecf20Sopenharmony_ci spin_unlock(&dd->sc_lock); 17918c2ecf20Sopenharmony_ci} 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci/* 17948c2ecf20Sopenharmony_ci * pio_select_send_context_vl() - select send context 17958c2ecf20Sopenharmony_ci * @dd: devdata 17968c2ecf20Sopenharmony_ci * @selector: a spreading factor 17978c2ecf20Sopenharmony_ci * @vl: this vl 17988c2ecf20Sopenharmony_ci * 17998c2ecf20Sopenharmony_ci * This function returns a send context based on the selector and a vl. 18008c2ecf20Sopenharmony_ci * The mapping fields are protected by RCU 18018c2ecf20Sopenharmony_ci */ 18028c2ecf20Sopenharmony_cistruct send_context *pio_select_send_context_vl(struct hfi1_devdata *dd, 18038c2ecf20Sopenharmony_ci u32 selector, u8 vl) 18048c2ecf20Sopenharmony_ci{ 18058c2ecf20Sopenharmony_ci struct pio_vl_map *m; 18068c2ecf20Sopenharmony_ci struct pio_map_elem *e; 18078c2ecf20Sopenharmony_ci struct send_context *rval; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci /* 18108c2ecf20Sopenharmony_ci * NOTE This should only happen if SC->VL changed after the initial 18118c2ecf20Sopenharmony_ci * checks on the QP/AH 18128c2ecf20Sopenharmony_ci * Default will return VL0's send context below 18138c2ecf20Sopenharmony_ci */ 18148c2ecf20Sopenharmony_ci if (unlikely(vl >= num_vls)) { 18158c2ecf20Sopenharmony_ci rval = NULL; 18168c2ecf20Sopenharmony_ci goto done; 18178c2ecf20Sopenharmony_ci } 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci rcu_read_lock(); 18208c2ecf20Sopenharmony_ci m = rcu_dereference(dd->pio_map); 18218c2ecf20Sopenharmony_ci if (unlikely(!m)) { 18228c2ecf20Sopenharmony_ci rcu_read_unlock(); 18238c2ecf20Sopenharmony_ci return dd->vld[0].sc; 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci e = m->map[vl & m->mask]; 18268c2ecf20Sopenharmony_ci rval = e->ksc[selector & e->mask]; 18278c2ecf20Sopenharmony_ci rcu_read_unlock(); 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_cidone: 18308c2ecf20Sopenharmony_ci rval = !rval ? dd->vld[0].sc : rval; 18318c2ecf20Sopenharmony_ci return rval; 18328c2ecf20Sopenharmony_ci} 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci/* 18358c2ecf20Sopenharmony_ci * pio_select_send_context_sc() - select send context 18368c2ecf20Sopenharmony_ci * @dd: devdata 18378c2ecf20Sopenharmony_ci * @selector: a spreading factor 18388c2ecf20Sopenharmony_ci * @sc5: the 5 bit sc 18398c2ecf20Sopenharmony_ci * 18408c2ecf20Sopenharmony_ci * This function returns an send context based on the selector and an sc 18418c2ecf20Sopenharmony_ci */ 18428c2ecf20Sopenharmony_cistruct send_context *pio_select_send_context_sc(struct hfi1_devdata *dd, 18438c2ecf20Sopenharmony_ci u32 selector, u8 sc5) 18448c2ecf20Sopenharmony_ci{ 18458c2ecf20Sopenharmony_ci u8 vl = sc_to_vlt(dd, sc5); 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci return pio_select_send_context_vl(dd, selector, vl); 18488c2ecf20Sopenharmony_ci} 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci/* 18518c2ecf20Sopenharmony_ci * Free the indicated map struct 18528c2ecf20Sopenharmony_ci */ 18538c2ecf20Sopenharmony_cistatic void pio_map_free(struct pio_vl_map *m) 18548c2ecf20Sopenharmony_ci{ 18558c2ecf20Sopenharmony_ci int i; 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci for (i = 0; m && i < m->actual_vls; i++) 18588c2ecf20Sopenharmony_ci kfree(m->map[i]); 18598c2ecf20Sopenharmony_ci kfree(m); 18608c2ecf20Sopenharmony_ci} 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci/* 18638c2ecf20Sopenharmony_ci * Handle RCU callback 18648c2ecf20Sopenharmony_ci */ 18658c2ecf20Sopenharmony_cistatic void pio_map_rcu_callback(struct rcu_head *list) 18668c2ecf20Sopenharmony_ci{ 18678c2ecf20Sopenharmony_ci struct pio_vl_map *m = container_of(list, struct pio_vl_map, list); 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci pio_map_free(m); 18708c2ecf20Sopenharmony_ci} 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci/* 18738c2ecf20Sopenharmony_ci * Set credit return threshold for the kernel send context 18748c2ecf20Sopenharmony_ci */ 18758c2ecf20Sopenharmony_cistatic void set_threshold(struct hfi1_devdata *dd, int scontext, int i) 18768c2ecf20Sopenharmony_ci{ 18778c2ecf20Sopenharmony_ci u32 thres; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci thres = min(sc_percent_to_threshold(dd->kernel_send_context[scontext], 18808c2ecf20Sopenharmony_ci 50), 18818c2ecf20Sopenharmony_ci sc_mtu_to_threshold(dd->kernel_send_context[scontext], 18828c2ecf20Sopenharmony_ci dd->vld[i].mtu, 18838c2ecf20Sopenharmony_ci dd->rcd[0]->rcvhdrqentsize)); 18848c2ecf20Sopenharmony_ci sc_set_cr_threshold(dd->kernel_send_context[scontext], thres); 18858c2ecf20Sopenharmony_ci} 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci/* 18888c2ecf20Sopenharmony_ci * pio_map_init - called when #vls change 18898c2ecf20Sopenharmony_ci * @dd: hfi1_devdata 18908c2ecf20Sopenharmony_ci * @port: port number 18918c2ecf20Sopenharmony_ci * @num_vls: number of vls 18928c2ecf20Sopenharmony_ci * @vl_scontexts: per vl send context mapping (optional) 18938c2ecf20Sopenharmony_ci * 18948c2ecf20Sopenharmony_ci * This routine changes the mapping based on the number of vls. 18958c2ecf20Sopenharmony_ci * 18968c2ecf20Sopenharmony_ci * vl_scontexts is used to specify a non-uniform vl/send context 18978c2ecf20Sopenharmony_ci * loading. NULL implies auto computing the loading and giving each 18988c2ecf20Sopenharmony_ci * VL an uniform distribution of send contexts per VL. 18998c2ecf20Sopenharmony_ci * 19008c2ecf20Sopenharmony_ci * The auto algorithm computers the sc_per_vl and the number of extra 19018c2ecf20Sopenharmony_ci * send contexts. Any extra send contexts are added from the last VL 19028c2ecf20Sopenharmony_ci * on down 19038c2ecf20Sopenharmony_ci * 19048c2ecf20Sopenharmony_ci * rcu locking is used here to control access to the mapping fields. 19058c2ecf20Sopenharmony_ci * 19068c2ecf20Sopenharmony_ci * If either the num_vls or num_send_contexts are non-power of 2, the 19078c2ecf20Sopenharmony_ci * array sizes in the struct pio_vl_map and the struct pio_map_elem are 19088c2ecf20Sopenharmony_ci * rounded up to the next highest power of 2 and the first entry is 19098c2ecf20Sopenharmony_ci * reused in a round robin fashion. 19108c2ecf20Sopenharmony_ci * 19118c2ecf20Sopenharmony_ci * If an error occurs the map change is not done and the mapping is not 19128c2ecf20Sopenharmony_ci * chaged. 19138c2ecf20Sopenharmony_ci * 19148c2ecf20Sopenharmony_ci */ 19158c2ecf20Sopenharmony_ciint pio_map_init(struct hfi1_devdata *dd, u8 port, u8 num_vls, u8 *vl_scontexts) 19168c2ecf20Sopenharmony_ci{ 19178c2ecf20Sopenharmony_ci int i, j; 19188c2ecf20Sopenharmony_ci int extra, sc_per_vl; 19198c2ecf20Sopenharmony_ci int scontext = 1; 19208c2ecf20Sopenharmony_ci int num_kernel_send_contexts = 0; 19218c2ecf20Sopenharmony_ci u8 lvl_scontexts[OPA_MAX_VLS]; 19228c2ecf20Sopenharmony_ci struct pio_vl_map *oldmap, *newmap; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci if (!vl_scontexts) { 19258c2ecf20Sopenharmony_ci for (i = 0; i < dd->num_send_contexts; i++) 19268c2ecf20Sopenharmony_ci if (dd->send_contexts[i].type == SC_KERNEL) 19278c2ecf20Sopenharmony_ci num_kernel_send_contexts++; 19288c2ecf20Sopenharmony_ci /* truncate divide */ 19298c2ecf20Sopenharmony_ci sc_per_vl = num_kernel_send_contexts / num_vls; 19308c2ecf20Sopenharmony_ci /* extras */ 19318c2ecf20Sopenharmony_ci extra = num_kernel_send_contexts % num_vls; 19328c2ecf20Sopenharmony_ci vl_scontexts = lvl_scontexts; 19338c2ecf20Sopenharmony_ci /* add extras from last vl down */ 19348c2ecf20Sopenharmony_ci for (i = num_vls - 1; i >= 0; i--, extra--) 19358c2ecf20Sopenharmony_ci vl_scontexts[i] = sc_per_vl + (extra > 0 ? 1 : 0); 19368c2ecf20Sopenharmony_ci } 19378c2ecf20Sopenharmony_ci /* build new map */ 19388c2ecf20Sopenharmony_ci newmap = kzalloc(sizeof(*newmap) + 19398c2ecf20Sopenharmony_ci roundup_pow_of_two(num_vls) * 19408c2ecf20Sopenharmony_ci sizeof(struct pio_map_elem *), 19418c2ecf20Sopenharmony_ci GFP_KERNEL); 19428c2ecf20Sopenharmony_ci if (!newmap) 19438c2ecf20Sopenharmony_ci goto bail; 19448c2ecf20Sopenharmony_ci newmap->actual_vls = num_vls; 19458c2ecf20Sopenharmony_ci newmap->vls = roundup_pow_of_two(num_vls); 19468c2ecf20Sopenharmony_ci newmap->mask = (1 << ilog2(newmap->vls)) - 1; 19478c2ecf20Sopenharmony_ci for (i = 0; i < newmap->vls; i++) { 19488c2ecf20Sopenharmony_ci /* save for wrap around */ 19498c2ecf20Sopenharmony_ci int first_scontext = scontext; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci if (i < newmap->actual_vls) { 19528c2ecf20Sopenharmony_ci int sz = roundup_pow_of_two(vl_scontexts[i]); 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci /* only allocate once */ 19558c2ecf20Sopenharmony_ci newmap->map[i] = kzalloc(sizeof(*newmap->map[i]) + 19568c2ecf20Sopenharmony_ci sz * sizeof(struct 19578c2ecf20Sopenharmony_ci send_context *), 19588c2ecf20Sopenharmony_ci GFP_KERNEL); 19598c2ecf20Sopenharmony_ci if (!newmap->map[i]) 19608c2ecf20Sopenharmony_ci goto bail; 19618c2ecf20Sopenharmony_ci newmap->map[i]->mask = (1 << ilog2(sz)) - 1; 19628c2ecf20Sopenharmony_ci /* 19638c2ecf20Sopenharmony_ci * assign send contexts and 19648c2ecf20Sopenharmony_ci * adjust credit return threshold 19658c2ecf20Sopenharmony_ci */ 19668c2ecf20Sopenharmony_ci for (j = 0; j < sz; j++) { 19678c2ecf20Sopenharmony_ci if (dd->kernel_send_context[scontext]) { 19688c2ecf20Sopenharmony_ci newmap->map[i]->ksc[j] = 19698c2ecf20Sopenharmony_ci dd->kernel_send_context[scontext]; 19708c2ecf20Sopenharmony_ci set_threshold(dd, scontext, i); 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci if (++scontext >= first_scontext + 19738c2ecf20Sopenharmony_ci vl_scontexts[i]) 19748c2ecf20Sopenharmony_ci /* wrap back to first send context */ 19758c2ecf20Sopenharmony_ci scontext = first_scontext; 19768c2ecf20Sopenharmony_ci } 19778c2ecf20Sopenharmony_ci } else { 19788c2ecf20Sopenharmony_ci /* just re-use entry without allocating */ 19798c2ecf20Sopenharmony_ci newmap->map[i] = newmap->map[i % num_vls]; 19808c2ecf20Sopenharmony_ci } 19818c2ecf20Sopenharmony_ci scontext = first_scontext + vl_scontexts[i]; 19828c2ecf20Sopenharmony_ci } 19838c2ecf20Sopenharmony_ci /* newmap in hand, save old map */ 19848c2ecf20Sopenharmony_ci spin_lock_irq(&dd->pio_map_lock); 19858c2ecf20Sopenharmony_ci oldmap = rcu_dereference_protected(dd->pio_map, 19868c2ecf20Sopenharmony_ci lockdep_is_held(&dd->pio_map_lock)); 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci /* publish newmap */ 19898c2ecf20Sopenharmony_ci rcu_assign_pointer(dd->pio_map, newmap); 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci spin_unlock_irq(&dd->pio_map_lock); 19928c2ecf20Sopenharmony_ci /* success, free any old map after grace period */ 19938c2ecf20Sopenharmony_ci if (oldmap) 19948c2ecf20Sopenharmony_ci call_rcu(&oldmap->list, pio_map_rcu_callback); 19958c2ecf20Sopenharmony_ci return 0; 19968c2ecf20Sopenharmony_cibail: 19978c2ecf20Sopenharmony_ci /* free any partial allocation */ 19988c2ecf20Sopenharmony_ci pio_map_free(newmap); 19998c2ecf20Sopenharmony_ci return -ENOMEM; 20008c2ecf20Sopenharmony_ci} 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_civoid free_pio_map(struct hfi1_devdata *dd) 20038c2ecf20Sopenharmony_ci{ 20048c2ecf20Sopenharmony_ci /* Free PIO map if allocated */ 20058c2ecf20Sopenharmony_ci if (rcu_access_pointer(dd->pio_map)) { 20068c2ecf20Sopenharmony_ci spin_lock_irq(&dd->pio_map_lock); 20078c2ecf20Sopenharmony_ci pio_map_free(rcu_access_pointer(dd->pio_map)); 20088c2ecf20Sopenharmony_ci RCU_INIT_POINTER(dd->pio_map, NULL); 20098c2ecf20Sopenharmony_ci spin_unlock_irq(&dd->pio_map_lock); 20108c2ecf20Sopenharmony_ci synchronize_rcu(); 20118c2ecf20Sopenharmony_ci } 20128c2ecf20Sopenharmony_ci kfree(dd->kernel_send_context); 20138c2ecf20Sopenharmony_ci dd->kernel_send_context = NULL; 20148c2ecf20Sopenharmony_ci} 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ciint init_pervl_scs(struct hfi1_devdata *dd) 20178c2ecf20Sopenharmony_ci{ 20188c2ecf20Sopenharmony_ci int i; 20198c2ecf20Sopenharmony_ci u64 mask, all_vl_mask = (u64)0x80ff; /* VLs 0-7, 15 */ 20208c2ecf20Sopenharmony_ci u64 data_vls_mask = (u64)0x00ff; /* VLs 0-7 */ 20218c2ecf20Sopenharmony_ci u32 ctxt; 20228c2ecf20Sopenharmony_ci struct hfi1_pportdata *ppd = dd->pport; 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci dd->vld[15].sc = sc_alloc(dd, SC_VL15, 20258c2ecf20Sopenharmony_ci dd->rcd[0]->rcvhdrqentsize, dd->node); 20268c2ecf20Sopenharmony_ci if (!dd->vld[15].sc) 20278c2ecf20Sopenharmony_ci return -ENOMEM; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci hfi1_init_ctxt(dd->vld[15].sc); 20308c2ecf20Sopenharmony_ci dd->vld[15].mtu = enum_to_mtu(OPA_MTU_2048); 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci dd->kernel_send_context = kcalloc_node(dd->num_send_contexts, 20338c2ecf20Sopenharmony_ci sizeof(struct send_context *), 20348c2ecf20Sopenharmony_ci GFP_KERNEL, dd->node); 20358c2ecf20Sopenharmony_ci if (!dd->kernel_send_context) 20368c2ecf20Sopenharmony_ci goto freesc15; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci dd->kernel_send_context[0] = dd->vld[15].sc; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci for (i = 0; i < num_vls; i++) { 20418c2ecf20Sopenharmony_ci /* 20428c2ecf20Sopenharmony_ci * Since this function does not deal with a specific 20438c2ecf20Sopenharmony_ci * receive context but we need the RcvHdrQ entry size, 20448c2ecf20Sopenharmony_ci * use the size from rcd[0]. It is guaranteed to be 20458c2ecf20Sopenharmony_ci * valid at this point and will remain the same for all 20468c2ecf20Sopenharmony_ci * receive contexts. 20478c2ecf20Sopenharmony_ci */ 20488c2ecf20Sopenharmony_ci dd->vld[i].sc = sc_alloc(dd, SC_KERNEL, 20498c2ecf20Sopenharmony_ci dd->rcd[0]->rcvhdrqentsize, dd->node); 20508c2ecf20Sopenharmony_ci if (!dd->vld[i].sc) 20518c2ecf20Sopenharmony_ci goto nomem; 20528c2ecf20Sopenharmony_ci dd->kernel_send_context[i + 1] = dd->vld[i].sc; 20538c2ecf20Sopenharmony_ci hfi1_init_ctxt(dd->vld[i].sc); 20548c2ecf20Sopenharmony_ci /* non VL15 start with the max MTU */ 20558c2ecf20Sopenharmony_ci dd->vld[i].mtu = hfi1_max_mtu; 20568c2ecf20Sopenharmony_ci } 20578c2ecf20Sopenharmony_ci for (i = num_vls; i < INIT_SC_PER_VL * num_vls; i++) { 20588c2ecf20Sopenharmony_ci dd->kernel_send_context[i + 1] = 20598c2ecf20Sopenharmony_ci sc_alloc(dd, SC_KERNEL, dd->rcd[0]->rcvhdrqentsize, dd->node); 20608c2ecf20Sopenharmony_ci if (!dd->kernel_send_context[i + 1]) 20618c2ecf20Sopenharmony_ci goto nomem; 20628c2ecf20Sopenharmony_ci hfi1_init_ctxt(dd->kernel_send_context[i + 1]); 20638c2ecf20Sopenharmony_ci } 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci sc_enable(dd->vld[15].sc); 20668c2ecf20Sopenharmony_ci ctxt = dd->vld[15].sc->hw_context; 20678c2ecf20Sopenharmony_ci mask = all_vl_mask & ~(1LL << 15); 20688c2ecf20Sopenharmony_ci write_kctxt_csr(dd, ctxt, SC(CHECK_VL), mask); 20698c2ecf20Sopenharmony_ci dd_dev_info(dd, 20708c2ecf20Sopenharmony_ci "Using send context %u(%u) for VL15\n", 20718c2ecf20Sopenharmony_ci dd->vld[15].sc->sw_index, ctxt); 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci for (i = 0; i < num_vls; i++) { 20748c2ecf20Sopenharmony_ci sc_enable(dd->vld[i].sc); 20758c2ecf20Sopenharmony_ci ctxt = dd->vld[i].sc->hw_context; 20768c2ecf20Sopenharmony_ci mask = all_vl_mask & ~(data_vls_mask); 20778c2ecf20Sopenharmony_ci write_kctxt_csr(dd, ctxt, SC(CHECK_VL), mask); 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci for (i = num_vls; i < INIT_SC_PER_VL * num_vls; i++) { 20808c2ecf20Sopenharmony_ci sc_enable(dd->kernel_send_context[i + 1]); 20818c2ecf20Sopenharmony_ci ctxt = dd->kernel_send_context[i + 1]->hw_context; 20828c2ecf20Sopenharmony_ci mask = all_vl_mask & ~(data_vls_mask); 20838c2ecf20Sopenharmony_ci write_kctxt_csr(dd, ctxt, SC(CHECK_VL), mask); 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci if (pio_map_init(dd, ppd->port - 1, num_vls, NULL)) 20878c2ecf20Sopenharmony_ci goto nomem; 20888c2ecf20Sopenharmony_ci return 0; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_cinomem: 20918c2ecf20Sopenharmony_ci for (i = 0; i < num_vls; i++) { 20928c2ecf20Sopenharmony_ci sc_free(dd->vld[i].sc); 20938c2ecf20Sopenharmony_ci dd->vld[i].sc = NULL; 20948c2ecf20Sopenharmony_ci } 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci for (i = num_vls; i < INIT_SC_PER_VL * num_vls; i++) 20978c2ecf20Sopenharmony_ci sc_free(dd->kernel_send_context[i + 1]); 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci kfree(dd->kernel_send_context); 21008c2ecf20Sopenharmony_ci dd->kernel_send_context = NULL; 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_cifreesc15: 21038c2ecf20Sopenharmony_ci sc_free(dd->vld[15].sc); 21048c2ecf20Sopenharmony_ci return -ENOMEM; 21058c2ecf20Sopenharmony_ci} 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ciint init_credit_return(struct hfi1_devdata *dd) 21088c2ecf20Sopenharmony_ci{ 21098c2ecf20Sopenharmony_ci int ret; 21108c2ecf20Sopenharmony_ci int i; 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci dd->cr_base = kcalloc( 21138c2ecf20Sopenharmony_ci node_affinity.num_possible_nodes, 21148c2ecf20Sopenharmony_ci sizeof(struct credit_return_base), 21158c2ecf20Sopenharmony_ci GFP_KERNEL); 21168c2ecf20Sopenharmony_ci if (!dd->cr_base) { 21178c2ecf20Sopenharmony_ci ret = -ENOMEM; 21188c2ecf20Sopenharmony_ci goto done; 21198c2ecf20Sopenharmony_ci } 21208c2ecf20Sopenharmony_ci for_each_node_with_cpus(i) { 21218c2ecf20Sopenharmony_ci int bytes = TXE_NUM_CONTEXTS * sizeof(struct credit_return); 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci set_dev_node(&dd->pcidev->dev, i); 21248c2ecf20Sopenharmony_ci dd->cr_base[i].va = dma_alloc_coherent(&dd->pcidev->dev, 21258c2ecf20Sopenharmony_ci bytes, 21268c2ecf20Sopenharmony_ci &dd->cr_base[i].dma, 21278c2ecf20Sopenharmony_ci GFP_KERNEL); 21288c2ecf20Sopenharmony_ci if (!dd->cr_base[i].va) { 21298c2ecf20Sopenharmony_ci set_dev_node(&dd->pcidev->dev, dd->node); 21308c2ecf20Sopenharmony_ci dd_dev_err(dd, 21318c2ecf20Sopenharmony_ci "Unable to allocate credit return DMA range for NUMA %d\n", 21328c2ecf20Sopenharmony_ci i); 21338c2ecf20Sopenharmony_ci ret = -ENOMEM; 21348c2ecf20Sopenharmony_ci goto done; 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci } 21378c2ecf20Sopenharmony_ci set_dev_node(&dd->pcidev->dev, dd->node); 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci ret = 0; 21408c2ecf20Sopenharmony_cidone: 21418c2ecf20Sopenharmony_ci return ret; 21428c2ecf20Sopenharmony_ci} 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_civoid free_credit_return(struct hfi1_devdata *dd) 21458c2ecf20Sopenharmony_ci{ 21468c2ecf20Sopenharmony_ci int i; 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci if (!dd->cr_base) 21498c2ecf20Sopenharmony_ci return; 21508c2ecf20Sopenharmony_ci for (i = 0; i < node_affinity.num_possible_nodes; i++) { 21518c2ecf20Sopenharmony_ci if (dd->cr_base[i].va) { 21528c2ecf20Sopenharmony_ci dma_free_coherent(&dd->pcidev->dev, 21538c2ecf20Sopenharmony_ci TXE_NUM_CONTEXTS * 21548c2ecf20Sopenharmony_ci sizeof(struct credit_return), 21558c2ecf20Sopenharmony_ci dd->cr_base[i].va, 21568c2ecf20Sopenharmony_ci dd->cr_base[i].dma); 21578c2ecf20Sopenharmony_ci } 21588c2ecf20Sopenharmony_ci } 21598c2ecf20Sopenharmony_ci kfree(dd->cr_base); 21608c2ecf20Sopenharmony_ci dd->cr_base = NULL; 21618c2ecf20Sopenharmony_ci} 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_civoid seqfile_dump_sci(struct seq_file *s, u32 i, 21648c2ecf20Sopenharmony_ci struct send_context_info *sci) 21658c2ecf20Sopenharmony_ci{ 21668c2ecf20Sopenharmony_ci struct send_context *sc = sci->sc; 21678c2ecf20Sopenharmony_ci u64 reg; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci seq_printf(s, "SCI %u: type %u base %u credits %u\n", 21708c2ecf20Sopenharmony_ci i, sci->type, sci->base, sci->credits); 21718c2ecf20Sopenharmony_ci seq_printf(s, " flags 0x%x sw_inx %u hw_ctxt %u grp %u\n", 21728c2ecf20Sopenharmony_ci sc->flags, sc->sw_index, sc->hw_context, sc->group); 21738c2ecf20Sopenharmony_ci seq_printf(s, " sr_size %u credits %u sr_head %u sr_tail %u\n", 21748c2ecf20Sopenharmony_ci sc->sr_size, sc->credits, sc->sr_head, sc->sr_tail); 21758c2ecf20Sopenharmony_ci seq_printf(s, " fill %lu free %lu fill_wrap %u alloc_free %lu\n", 21768c2ecf20Sopenharmony_ci sc->fill, sc->free, sc->fill_wrap, sc->alloc_free); 21778c2ecf20Sopenharmony_ci seq_printf(s, " credit_intr_count %u credit_ctrl 0x%llx\n", 21788c2ecf20Sopenharmony_ci sc->credit_intr_count, sc->credit_ctrl); 21798c2ecf20Sopenharmony_ci reg = read_kctxt_csr(sc->dd, sc->hw_context, SC(CREDIT_STATUS)); 21808c2ecf20Sopenharmony_ci seq_printf(s, " *hw_free %llu CurrentFree %llu LastReturned %llu\n", 21818c2ecf20Sopenharmony_ci (le64_to_cpu(*sc->hw_free) & CR_COUNTER_SMASK) >> 21828c2ecf20Sopenharmony_ci CR_COUNTER_SHIFT, 21838c2ecf20Sopenharmony_ci (reg >> SC(CREDIT_STATUS_CURRENT_FREE_COUNTER_SHIFT)) & 21848c2ecf20Sopenharmony_ci SC(CREDIT_STATUS_CURRENT_FREE_COUNTER_MASK), 21858c2ecf20Sopenharmony_ci reg & SC(CREDIT_STATUS_LAST_RETURNED_COUNTER_SMASK)); 21868c2ecf20Sopenharmony_ci} 2187