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/spinlock.h>
498c2ecf20Sopenharmony_ci#include <linux/seqlock.h>
508c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
518c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
528c2ecf20Sopenharmony_ci#include <linux/bitops.h>
538c2ecf20Sopenharmony_ci#include <linux/timer.h>
548c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
558c2ecf20Sopenharmony_ci#include <linux/highmem.h>
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#include "hfi.h"
588c2ecf20Sopenharmony_ci#include "common.h"
598c2ecf20Sopenharmony_ci#include "qp.h"
608c2ecf20Sopenharmony_ci#include "sdma.h"
618c2ecf20Sopenharmony_ci#include "iowait.h"
628c2ecf20Sopenharmony_ci#include "trace.h"
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/* must be a power of 2 >= 64 <= 32768 */
658c2ecf20Sopenharmony_ci#define SDMA_DESCQ_CNT 2048
668c2ecf20Sopenharmony_ci#define SDMA_DESC_INTR 64
678c2ecf20Sopenharmony_ci#define INVALID_TAIL 0xffff
688c2ecf20Sopenharmony_ci#define SDMA_PAD max_t(size_t, MAX_16B_PADDING, sizeof(u32))
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic uint sdma_descq_cnt = SDMA_DESCQ_CNT;
718c2ecf20Sopenharmony_cimodule_param(sdma_descq_cnt, uint, S_IRUGO);
728c2ecf20Sopenharmony_ciMODULE_PARM_DESC(sdma_descq_cnt, "Number of SDMA descq entries");
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic uint sdma_idle_cnt = 250;
758c2ecf20Sopenharmony_cimodule_param(sdma_idle_cnt, uint, S_IRUGO);
768c2ecf20Sopenharmony_ciMODULE_PARM_DESC(sdma_idle_cnt, "sdma interrupt idle delay (ns,default 250)");
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ciuint mod_num_sdma;
798c2ecf20Sopenharmony_cimodule_param_named(num_sdma, mod_num_sdma, uint, S_IRUGO);
808c2ecf20Sopenharmony_ciMODULE_PARM_DESC(num_sdma, "Set max number SDMA engines to use");
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic uint sdma_desct_intr = SDMA_DESC_INTR;
838c2ecf20Sopenharmony_cimodule_param_named(desct_intr, sdma_desct_intr, uint, S_IRUGO | S_IWUSR);
848c2ecf20Sopenharmony_ciMODULE_PARM_DESC(desct_intr, "Number of SDMA descriptor before interrupt");
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define SDMA_WAIT_BATCH_SIZE 20
878c2ecf20Sopenharmony_ci/* max wait time for a SDMA engine to indicate it has halted */
888c2ecf20Sopenharmony_ci#define SDMA_ERR_HALT_TIMEOUT 10 /* ms */
898c2ecf20Sopenharmony_ci/* all SDMA engine errors that cause a halt */
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci#define SD(name) SEND_DMA_##name
928c2ecf20Sopenharmony_ci#define ALL_SDMA_ENG_HALT_ERRS \
938c2ecf20Sopenharmony_ci	(SD(ENG_ERR_STATUS_SDMA_WRONG_DW_ERR_SMASK) \
948c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_GEN_MISMATCH_ERR_SMASK) \
958c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_TOO_LONG_ERR_SMASK) \
968c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_TAIL_OUT_OF_BOUNDS_ERR_SMASK) \
978c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_FIRST_DESC_ERR_SMASK) \
988c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_MEM_READ_ERR_SMASK) \
998c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_HALT_ERR_SMASK) \
1008c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_LENGTH_MISMATCH_ERR_SMASK) \
1018c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_PACKET_DESC_OVERFLOW_ERR_SMASK) \
1028c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_HEADER_SELECT_ERR_SMASK) \
1038c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_HEADER_ADDRESS_ERR_SMASK) \
1048c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_HEADER_LENGTH_ERR_SMASK) \
1058c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_TIMEOUT_ERR_SMASK) \
1068c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_DESC_TABLE_UNC_ERR_SMASK) \
1078c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_ASSEMBLY_UNC_ERR_SMASK) \
1088c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_PACKET_TRACKING_UNC_ERR_SMASK) \
1098c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_HEADER_STORAGE_UNC_ERR_SMASK) \
1108c2ecf20Sopenharmony_ci	| SD(ENG_ERR_STATUS_SDMA_HEADER_REQUEST_FIFO_UNC_ERR_SMASK))
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/* sdma_sendctrl operations */
1138c2ecf20Sopenharmony_ci#define SDMA_SENDCTRL_OP_ENABLE    BIT(0)
1148c2ecf20Sopenharmony_ci#define SDMA_SENDCTRL_OP_INTENABLE BIT(1)
1158c2ecf20Sopenharmony_ci#define SDMA_SENDCTRL_OP_HALT      BIT(2)
1168c2ecf20Sopenharmony_ci#define SDMA_SENDCTRL_OP_CLEANUP   BIT(3)
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/* handle long defines */
1198c2ecf20Sopenharmony_ci#define SDMA_EGRESS_PACKET_OCCUPANCY_SMASK \
1208c2ecf20Sopenharmony_ciSEND_EGRESS_SEND_DMA_STATUS_SDMA_EGRESS_PACKET_OCCUPANCY_SMASK
1218c2ecf20Sopenharmony_ci#define SDMA_EGRESS_PACKET_OCCUPANCY_SHIFT \
1228c2ecf20Sopenharmony_ciSEND_EGRESS_SEND_DMA_STATUS_SDMA_EGRESS_PACKET_OCCUPANCY_SHIFT
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic const char * const sdma_state_names[] = {
1258c2ecf20Sopenharmony_ci	[sdma_state_s00_hw_down]                = "s00_HwDown",
1268c2ecf20Sopenharmony_ci	[sdma_state_s10_hw_start_up_halt_wait]  = "s10_HwStartUpHaltWait",
1278c2ecf20Sopenharmony_ci	[sdma_state_s15_hw_start_up_clean_wait] = "s15_HwStartUpCleanWait",
1288c2ecf20Sopenharmony_ci	[sdma_state_s20_idle]                   = "s20_Idle",
1298c2ecf20Sopenharmony_ci	[sdma_state_s30_sw_clean_up_wait]       = "s30_SwCleanUpWait",
1308c2ecf20Sopenharmony_ci	[sdma_state_s40_hw_clean_up_wait]       = "s40_HwCleanUpWait",
1318c2ecf20Sopenharmony_ci	[sdma_state_s50_hw_halt_wait]           = "s50_HwHaltWait",
1328c2ecf20Sopenharmony_ci	[sdma_state_s60_idle_halt_wait]         = "s60_IdleHaltWait",
1338c2ecf20Sopenharmony_ci	[sdma_state_s80_hw_freeze]		= "s80_HwFreeze",
1348c2ecf20Sopenharmony_ci	[sdma_state_s82_freeze_sw_clean]	= "s82_FreezeSwClean",
1358c2ecf20Sopenharmony_ci	[sdma_state_s99_running]                = "s99_Running",
1368c2ecf20Sopenharmony_ci};
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci#ifdef CONFIG_SDMA_VERBOSITY
1398c2ecf20Sopenharmony_cistatic const char * const sdma_event_names[] = {
1408c2ecf20Sopenharmony_ci	[sdma_event_e00_go_hw_down]   = "e00_GoHwDown",
1418c2ecf20Sopenharmony_ci	[sdma_event_e10_go_hw_start]  = "e10_GoHwStart",
1428c2ecf20Sopenharmony_ci	[sdma_event_e15_hw_halt_done] = "e15_HwHaltDone",
1438c2ecf20Sopenharmony_ci	[sdma_event_e25_hw_clean_up_done] = "e25_HwCleanUpDone",
1448c2ecf20Sopenharmony_ci	[sdma_event_e30_go_running]   = "e30_GoRunning",
1458c2ecf20Sopenharmony_ci	[sdma_event_e40_sw_cleaned]   = "e40_SwCleaned",
1468c2ecf20Sopenharmony_ci	[sdma_event_e50_hw_cleaned]   = "e50_HwCleaned",
1478c2ecf20Sopenharmony_ci	[sdma_event_e60_hw_halted]    = "e60_HwHalted",
1488c2ecf20Sopenharmony_ci	[sdma_event_e70_go_idle]      = "e70_GoIdle",
1498c2ecf20Sopenharmony_ci	[sdma_event_e80_hw_freeze]    = "e80_HwFreeze",
1508c2ecf20Sopenharmony_ci	[sdma_event_e81_hw_frozen]    = "e81_HwFrozen",
1518c2ecf20Sopenharmony_ci	[sdma_event_e82_hw_unfreeze]  = "e82_HwUnfreeze",
1528c2ecf20Sopenharmony_ci	[sdma_event_e85_link_down]    = "e85_LinkDown",
1538c2ecf20Sopenharmony_ci	[sdma_event_e90_sw_halted]    = "e90_SwHalted",
1548c2ecf20Sopenharmony_ci};
1558c2ecf20Sopenharmony_ci#endif
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic const struct sdma_set_state_action sdma_action_table[] = {
1588c2ecf20Sopenharmony_ci	[sdma_state_s00_hw_down] = {
1598c2ecf20Sopenharmony_ci		.go_s99_running_tofalse = 1,
1608c2ecf20Sopenharmony_ci		.op_enable = 0,
1618c2ecf20Sopenharmony_ci		.op_intenable = 0,
1628c2ecf20Sopenharmony_ci		.op_halt = 0,
1638c2ecf20Sopenharmony_ci		.op_cleanup = 0,
1648c2ecf20Sopenharmony_ci	},
1658c2ecf20Sopenharmony_ci	[sdma_state_s10_hw_start_up_halt_wait] = {
1668c2ecf20Sopenharmony_ci		.op_enable = 0,
1678c2ecf20Sopenharmony_ci		.op_intenable = 0,
1688c2ecf20Sopenharmony_ci		.op_halt = 1,
1698c2ecf20Sopenharmony_ci		.op_cleanup = 0,
1708c2ecf20Sopenharmony_ci	},
1718c2ecf20Sopenharmony_ci	[sdma_state_s15_hw_start_up_clean_wait] = {
1728c2ecf20Sopenharmony_ci		.op_enable = 0,
1738c2ecf20Sopenharmony_ci		.op_intenable = 1,
1748c2ecf20Sopenharmony_ci		.op_halt = 0,
1758c2ecf20Sopenharmony_ci		.op_cleanup = 1,
1768c2ecf20Sopenharmony_ci	},
1778c2ecf20Sopenharmony_ci	[sdma_state_s20_idle] = {
1788c2ecf20Sopenharmony_ci		.op_enable = 0,
1798c2ecf20Sopenharmony_ci		.op_intenable = 1,
1808c2ecf20Sopenharmony_ci		.op_halt = 0,
1818c2ecf20Sopenharmony_ci		.op_cleanup = 0,
1828c2ecf20Sopenharmony_ci	},
1838c2ecf20Sopenharmony_ci	[sdma_state_s30_sw_clean_up_wait] = {
1848c2ecf20Sopenharmony_ci		.op_enable = 0,
1858c2ecf20Sopenharmony_ci		.op_intenable = 0,
1868c2ecf20Sopenharmony_ci		.op_halt = 0,
1878c2ecf20Sopenharmony_ci		.op_cleanup = 0,
1888c2ecf20Sopenharmony_ci	},
1898c2ecf20Sopenharmony_ci	[sdma_state_s40_hw_clean_up_wait] = {
1908c2ecf20Sopenharmony_ci		.op_enable = 0,
1918c2ecf20Sopenharmony_ci		.op_intenable = 0,
1928c2ecf20Sopenharmony_ci		.op_halt = 0,
1938c2ecf20Sopenharmony_ci		.op_cleanup = 1,
1948c2ecf20Sopenharmony_ci	},
1958c2ecf20Sopenharmony_ci	[sdma_state_s50_hw_halt_wait] = {
1968c2ecf20Sopenharmony_ci		.op_enable = 0,
1978c2ecf20Sopenharmony_ci		.op_intenable = 0,
1988c2ecf20Sopenharmony_ci		.op_halt = 0,
1998c2ecf20Sopenharmony_ci		.op_cleanup = 0,
2008c2ecf20Sopenharmony_ci	},
2018c2ecf20Sopenharmony_ci	[sdma_state_s60_idle_halt_wait] = {
2028c2ecf20Sopenharmony_ci		.go_s99_running_tofalse = 1,
2038c2ecf20Sopenharmony_ci		.op_enable = 0,
2048c2ecf20Sopenharmony_ci		.op_intenable = 0,
2058c2ecf20Sopenharmony_ci		.op_halt = 1,
2068c2ecf20Sopenharmony_ci		.op_cleanup = 0,
2078c2ecf20Sopenharmony_ci	},
2088c2ecf20Sopenharmony_ci	[sdma_state_s80_hw_freeze] = {
2098c2ecf20Sopenharmony_ci		.op_enable = 0,
2108c2ecf20Sopenharmony_ci		.op_intenable = 0,
2118c2ecf20Sopenharmony_ci		.op_halt = 0,
2128c2ecf20Sopenharmony_ci		.op_cleanup = 0,
2138c2ecf20Sopenharmony_ci	},
2148c2ecf20Sopenharmony_ci	[sdma_state_s82_freeze_sw_clean] = {
2158c2ecf20Sopenharmony_ci		.op_enable = 0,
2168c2ecf20Sopenharmony_ci		.op_intenable = 0,
2178c2ecf20Sopenharmony_ci		.op_halt = 0,
2188c2ecf20Sopenharmony_ci		.op_cleanup = 0,
2198c2ecf20Sopenharmony_ci	},
2208c2ecf20Sopenharmony_ci	[sdma_state_s99_running] = {
2218c2ecf20Sopenharmony_ci		.op_enable = 1,
2228c2ecf20Sopenharmony_ci		.op_intenable = 1,
2238c2ecf20Sopenharmony_ci		.op_halt = 0,
2248c2ecf20Sopenharmony_ci		.op_cleanup = 0,
2258c2ecf20Sopenharmony_ci		.go_s99_running_totrue = 1,
2268c2ecf20Sopenharmony_ci	},
2278c2ecf20Sopenharmony_ci};
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci#define SDMA_TAIL_UPDATE_THRESH 0x1F
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci/* declare all statics here rather than keep sorting */
2328c2ecf20Sopenharmony_cistatic void sdma_complete(struct kref *);
2338c2ecf20Sopenharmony_cistatic void sdma_finalput(struct sdma_state *);
2348c2ecf20Sopenharmony_cistatic void sdma_get(struct sdma_state *);
2358c2ecf20Sopenharmony_cistatic void sdma_hw_clean_up_task(struct tasklet_struct *);
2368c2ecf20Sopenharmony_cistatic void sdma_put(struct sdma_state *);
2378c2ecf20Sopenharmony_cistatic void sdma_set_state(struct sdma_engine *, enum sdma_states);
2388c2ecf20Sopenharmony_cistatic void sdma_start_hw_clean_up(struct sdma_engine *);
2398c2ecf20Sopenharmony_cistatic void sdma_sw_clean_up_task(struct tasklet_struct *);
2408c2ecf20Sopenharmony_cistatic void sdma_sendctrl(struct sdma_engine *, unsigned);
2418c2ecf20Sopenharmony_cistatic void init_sdma_regs(struct sdma_engine *, u32, uint);
2428c2ecf20Sopenharmony_cistatic void sdma_process_event(
2438c2ecf20Sopenharmony_ci	struct sdma_engine *sde,
2448c2ecf20Sopenharmony_ci	enum sdma_events event);
2458c2ecf20Sopenharmony_cistatic void __sdma_process_event(
2468c2ecf20Sopenharmony_ci	struct sdma_engine *sde,
2478c2ecf20Sopenharmony_ci	enum sdma_events event);
2488c2ecf20Sopenharmony_cistatic void dump_sdma_state(struct sdma_engine *sde);
2498c2ecf20Sopenharmony_cistatic void sdma_make_progress(struct sdma_engine *sde, u64 status);
2508c2ecf20Sopenharmony_cistatic void sdma_desc_avail(struct sdma_engine *sde, uint avail);
2518c2ecf20Sopenharmony_cistatic void sdma_flush_descq(struct sdma_engine *sde);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci/**
2548c2ecf20Sopenharmony_ci * sdma_state_name() - return state string from enum
2558c2ecf20Sopenharmony_ci * @state: state
2568c2ecf20Sopenharmony_ci */
2578c2ecf20Sopenharmony_cistatic const char *sdma_state_name(enum sdma_states state)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	return sdma_state_names[state];
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cistatic void sdma_get(struct sdma_state *ss)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	kref_get(&ss->kref);
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic void sdma_complete(struct kref *kref)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	struct sdma_state *ss =
2708c2ecf20Sopenharmony_ci		container_of(kref, struct sdma_state, kref);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	complete(&ss->comp);
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic void sdma_put(struct sdma_state *ss)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	kref_put(&ss->kref, sdma_complete);
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic void sdma_finalput(struct sdma_state *ss)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	sdma_put(ss);
2838c2ecf20Sopenharmony_ci	wait_for_completion(&ss->comp);
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic inline void write_sde_csr(
2878c2ecf20Sopenharmony_ci	struct sdma_engine *sde,
2888c2ecf20Sopenharmony_ci	u32 offset0,
2898c2ecf20Sopenharmony_ci	u64 value)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	write_kctxt_csr(sde->dd, sde->this_idx, offset0, value);
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic inline u64 read_sde_csr(
2958c2ecf20Sopenharmony_ci	struct sdma_engine *sde,
2968c2ecf20Sopenharmony_ci	u32 offset0)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	return read_kctxt_csr(sde->dd, sde->this_idx, offset0);
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci/*
3028c2ecf20Sopenharmony_ci * sdma_wait_for_packet_egress() - wait for the VL FIFO occupancy for
3038c2ecf20Sopenharmony_ci * sdma engine 'sde' to drop to 0.
3048c2ecf20Sopenharmony_ci */
3058c2ecf20Sopenharmony_cistatic void sdma_wait_for_packet_egress(struct sdma_engine *sde,
3068c2ecf20Sopenharmony_ci					int pause)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	u64 off = 8 * sde->this_idx;
3098c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd = sde->dd;
3108c2ecf20Sopenharmony_ci	int lcnt = 0;
3118c2ecf20Sopenharmony_ci	u64 reg_prev;
3128c2ecf20Sopenharmony_ci	u64 reg = 0;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	while (1) {
3158c2ecf20Sopenharmony_ci		reg_prev = reg;
3168c2ecf20Sopenharmony_ci		reg = read_csr(dd, off + SEND_EGRESS_SEND_DMA_STATUS);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci		reg &= SDMA_EGRESS_PACKET_OCCUPANCY_SMASK;
3198c2ecf20Sopenharmony_ci		reg >>= SDMA_EGRESS_PACKET_OCCUPANCY_SHIFT;
3208c2ecf20Sopenharmony_ci		if (reg == 0)
3218c2ecf20Sopenharmony_ci			break;
3228c2ecf20Sopenharmony_ci		/* counter is reest if accupancy count changes */
3238c2ecf20Sopenharmony_ci		if (reg != reg_prev)
3248c2ecf20Sopenharmony_ci			lcnt = 0;
3258c2ecf20Sopenharmony_ci		if (lcnt++ > 500) {
3268c2ecf20Sopenharmony_ci			/* timed out - bounce the link */
3278c2ecf20Sopenharmony_ci			dd_dev_err(dd, "%s: engine %u timeout waiting for packets to egress, remaining count %u, bouncing link\n",
3288c2ecf20Sopenharmony_ci				   __func__, sde->this_idx, (u32)reg);
3298c2ecf20Sopenharmony_ci			queue_work(dd->pport->link_wq,
3308c2ecf20Sopenharmony_ci				   &dd->pport->link_bounce_work);
3318c2ecf20Sopenharmony_ci			break;
3328c2ecf20Sopenharmony_ci		}
3338c2ecf20Sopenharmony_ci		udelay(1);
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci/*
3388c2ecf20Sopenharmony_ci * sdma_wait() - wait for packet egress to complete for all SDMA engines,
3398c2ecf20Sopenharmony_ci * and pause for credit return.
3408c2ecf20Sopenharmony_ci */
3418c2ecf20Sopenharmony_civoid sdma_wait(struct hfi1_devdata *dd)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	int i;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	for (i = 0; i < dd->num_sdma; i++) {
3468c2ecf20Sopenharmony_ci		struct sdma_engine *sde = &dd->per_sdma[i];
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		sdma_wait_for_packet_egress(sde, 0);
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic inline void sdma_set_desc_cnt(struct sdma_engine *sde, unsigned cnt)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	u64 reg;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (!(sde->dd->flags & HFI1_HAS_SDMA_TIMEOUT))
3578c2ecf20Sopenharmony_ci		return;
3588c2ecf20Sopenharmony_ci	reg = cnt;
3598c2ecf20Sopenharmony_ci	reg &= SD(DESC_CNT_CNT_MASK);
3608c2ecf20Sopenharmony_ci	reg <<= SD(DESC_CNT_CNT_SHIFT);
3618c2ecf20Sopenharmony_ci	write_sde_csr(sde, SD(DESC_CNT), reg);
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic inline void complete_tx(struct sdma_engine *sde,
3658c2ecf20Sopenharmony_ci			       struct sdma_txreq *tx,
3668c2ecf20Sopenharmony_ci			       int res)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	/* protect against complete modifying */
3698c2ecf20Sopenharmony_ci	struct iowait *wait = tx->wait;
3708c2ecf20Sopenharmony_ci	callback_t complete = tx->complete;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER
3738c2ecf20Sopenharmony_ci	trace_hfi1_sdma_out_sn(sde, tx->sn);
3748c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(sde->head_sn != tx->sn))
3758c2ecf20Sopenharmony_ci		dd_dev_err(sde->dd, "expected %llu got %llu\n",
3768c2ecf20Sopenharmony_ci			   sde->head_sn, tx->sn);
3778c2ecf20Sopenharmony_ci	sde->head_sn++;
3788c2ecf20Sopenharmony_ci#endif
3798c2ecf20Sopenharmony_ci	__sdma_txclean(sde->dd, tx);
3808c2ecf20Sopenharmony_ci	if (complete)
3818c2ecf20Sopenharmony_ci		(*complete)(tx, res);
3828c2ecf20Sopenharmony_ci	if (iowait_sdma_dec(wait))
3838c2ecf20Sopenharmony_ci		iowait_drain_wakeup(wait);
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci/*
3878c2ecf20Sopenharmony_ci * Complete all the sdma requests with a SDMA_TXREQ_S_ABORTED status
3888c2ecf20Sopenharmony_ci *
3898c2ecf20Sopenharmony_ci * Depending on timing there can be txreqs in two places:
3908c2ecf20Sopenharmony_ci * - in the descq ring
3918c2ecf20Sopenharmony_ci * - in the flush list
3928c2ecf20Sopenharmony_ci *
3938c2ecf20Sopenharmony_ci * To avoid ordering issues the descq ring needs to be flushed
3948c2ecf20Sopenharmony_ci * first followed by the flush list.
3958c2ecf20Sopenharmony_ci *
3968c2ecf20Sopenharmony_ci * This routine is called from two places
3978c2ecf20Sopenharmony_ci * - From a work queue item
3988c2ecf20Sopenharmony_ci * - Directly from the state machine just before setting the
3998c2ecf20Sopenharmony_ci *   state to running
4008c2ecf20Sopenharmony_ci *
4018c2ecf20Sopenharmony_ci * Must be called with head_lock held
4028c2ecf20Sopenharmony_ci *
4038c2ecf20Sopenharmony_ci */
4048c2ecf20Sopenharmony_cistatic void sdma_flush(struct sdma_engine *sde)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct sdma_txreq *txp, *txp_next;
4078c2ecf20Sopenharmony_ci	LIST_HEAD(flushlist);
4088c2ecf20Sopenharmony_ci	unsigned long flags;
4098c2ecf20Sopenharmony_ci	uint seq;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/* flush from head to tail */
4128c2ecf20Sopenharmony_ci	sdma_flush_descq(sde);
4138c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sde->flushlist_lock, flags);
4148c2ecf20Sopenharmony_ci	/* copy flush list */
4158c2ecf20Sopenharmony_ci	list_splice_init(&sde->flushlist, &flushlist);
4168c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sde->flushlist_lock, flags);
4178c2ecf20Sopenharmony_ci	/* flush from flush list */
4188c2ecf20Sopenharmony_ci	list_for_each_entry_safe(txp, txp_next, &flushlist, list)
4198c2ecf20Sopenharmony_ci		complete_tx(sde, txp, SDMA_TXREQ_S_ABORTED);
4208c2ecf20Sopenharmony_ci	/* wakeup QPs orphaned on the dmawait list */
4218c2ecf20Sopenharmony_ci	do {
4228c2ecf20Sopenharmony_ci		struct iowait *w, *nw;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		seq = read_seqbegin(&sde->waitlock);
4258c2ecf20Sopenharmony_ci		if (!list_empty(&sde->dmawait)) {
4268c2ecf20Sopenharmony_ci			write_seqlock(&sde->waitlock);
4278c2ecf20Sopenharmony_ci			list_for_each_entry_safe(w, nw, &sde->dmawait, list) {
4288c2ecf20Sopenharmony_ci				if (w->wakeup) {
4298c2ecf20Sopenharmony_ci					w->wakeup(w, SDMA_AVAIL_REASON);
4308c2ecf20Sopenharmony_ci					list_del_init(&w->list);
4318c2ecf20Sopenharmony_ci				}
4328c2ecf20Sopenharmony_ci			}
4338c2ecf20Sopenharmony_ci			write_sequnlock(&sde->waitlock);
4348c2ecf20Sopenharmony_ci		}
4358c2ecf20Sopenharmony_ci	} while (read_seqretry(&sde->waitlock, seq));
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci/*
4398c2ecf20Sopenharmony_ci * Fields a work request for flushing the descq ring
4408c2ecf20Sopenharmony_ci * and the flush list
4418c2ecf20Sopenharmony_ci *
4428c2ecf20Sopenharmony_ci * If the engine has been brought to running during
4438c2ecf20Sopenharmony_ci * the scheduling delay, the flush is ignored, assuming
4448c2ecf20Sopenharmony_ci * that the process of bringing the engine to running
4458c2ecf20Sopenharmony_ci * would have done this flush prior to going to running.
4468c2ecf20Sopenharmony_ci *
4478c2ecf20Sopenharmony_ci */
4488c2ecf20Sopenharmony_cistatic void sdma_field_flush(struct work_struct *work)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	unsigned long flags;
4518c2ecf20Sopenharmony_ci	struct sdma_engine *sde =
4528c2ecf20Sopenharmony_ci		container_of(work, struct sdma_engine, flush_worker);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	write_seqlock_irqsave(&sde->head_lock, flags);
4558c2ecf20Sopenharmony_ci	if (!__sdma_running(sde))
4568c2ecf20Sopenharmony_ci		sdma_flush(sde);
4578c2ecf20Sopenharmony_ci	write_sequnlock_irqrestore(&sde->head_lock, flags);
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic void sdma_err_halt_wait(struct work_struct *work)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	struct sdma_engine *sde = container_of(work, struct sdma_engine,
4638c2ecf20Sopenharmony_ci						err_halt_worker);
4648c2ecf20Sopenharmony_ci	u64 statuscsr;
4658c2ecf20Sopenharmony_ci	unsigned long timeout;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(SDMA_ERR_HALT_TIMEOUT);
4688c2ecf20Sopenharmony_ci	while (1) {
4698c2ecf20Sopenharmony_ci		statuscsr = read_sde_csr(sde, SD(STATUS));
4708c2ecf20Sopenharmony_ci		statuscsr &= SD(STATUS_ENG_HALTED_SMASK);
4718c2ecf20Sopenharmony_ci		if (statuscsr)
4728c2ecf20Sopenharmony_ci			break;
4738c2ecf20Sopenharmony_ci		if (time_after(jiffies, timeout)) {
4748c2ecf20Sopenharmony_ci			dd_dev_err(sde->dd,
4758c2ecf20Sopenharmony_ci				   "SDMA engine %d - timeout waiting for engine to halt\n",
4768c2ecf20Sopenharmony_ci				   sde->this_idx);
4778c2ecf20Sopenharmony_ci			/*
4788c2ecf20Sopenharmony_ci			 * Continue anyway.  This could happen if there was
4798c2ecf20Sopenharmony_ci			 * an uncorrectable error in the wrong spot.
4808c2ecf20Sopenharmony_ci			 */
4818c2ecf20Sopenharmony_ci			break;
4828c2ecf20Sopenharmony_ci		}
4838c2ecf20Sopenharmony_ci		usleep_range(80, 120);
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	sdma_process_event(sde, sdma_event_e15_hw_halt_done);
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_cistatic void sdma_err_progress_check_schedule(struct sdma_engine *sde)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	if (!is_bx(sde->dd) && HFI1_CAP_IS_KSET(SDMA_AHG)) {
4928c2ecf20Sopenharmony_ci		unsigned index;
4938c2ecf20Sopenharmony_ci		struct hfi1_devdata *dd = sde->dd;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci		for (index = 0; index < dd->num_sdma; index++) {
4968c2ecf20Sopenharmony_ci			struct sdma_engine *curr_sdma = &dd->per_sdma[index];
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci			if (curr_sdma != sde)
4998c2ecf20Sopenharmony_ci				curr_sdma->progress_check_head =
5008c2ecf20Sopenharmony_ci							curr_sdma->descq_head;
5018c2ecf20Sopenharmony_ci		}
5028c2ecf20Sopenharmony_ci		dd_dev_err(sde->dd,
5038c2ecf20Sopenharmony_ci			   "SDMA engine %d - check scheduled\n",
5048c2ecf20Sopenharmony_ci				sde->this_idx);
5058c2ecf20Sopenharmony_ci		mod_timer(&sde->err_progress_check_timer, jiffies + 10);
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic void sdma_err_progress_check(struct timer_list *t)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	unsigned index;
5128c2ecf20Sopenharmony_ci	struct sdma_engine *sde = from_timer(sde, t, err_progress_check_timer);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	dd_dev_err(sde->dd, "SDE progress check event\n");
5158c2ecf20Sopenharmony_ci	for (index = 0; index < sde->dd->num_sdma; index++) {
5168c2ecf20Sopenharmony_ci		struct sdma_engine *curr_sde = &sde->dd->per_sdma[index];
5178c2ecf20Sopenharmony_ci		unsigned long flags;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci		/* check progress on each engine except the current one */
5208c2ecf20Sopenharmony_ci		if (curr_sde == sde)
5218c2ecf20Sopenharmony_ci			continue;
5228c2ecf20Sopenharmony_ci		/*
5238c2ecf20Sopenharmony_ci		 * We must lock interrupts when acquiring sde->lock,
5248c2ecf20Sopenharmony_ci		 * to avoid a deadlock if interrupt triggers and spins on
5258c2ecf20Sopenharmony_ci		 * the same lock on same CPU
5268c2ecf20Sopenharmony_ci		 */
5278c2ecf20Sopenharmony_ci		spin_lock_irqsave(&curr_sde->tail_lock, flags);
5288c2ecf20Sopenharmony_ci		write_seqlock(&curr_sde->head_lock);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci		/* skip non-running queues */
5318c2ecf20Sopenharmony_ci		if (curr_sde->state.current_state != sdma_state_s99_running) {
5328c2ecf20Sopenharmony_ci			write_sequnlock(&curr_sde->head_lock);
5338c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&curr_sde->tail_lock, flags);
5348c2ecf20Sopenharmony_ci			continue;
5358c2ecf20Sopenharmony_ci		}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci		if ((curr_sde->descq_head != curr_sde->descq_tail) &&
5388c2ecf20Sopenharmony_ci		    (curr_sde->descq_head ==
5398c2ecf20Sopenharmony_ci				curr_sde->progress_check_head))
5408c2ecf20Sopenharmony_ci			__sdma_process_event(curr_sde,
5418c2ecf20Sopenharmony_ci					     sdma_event_e90_sw_halted);
5428c2ecf20Sopenharmony_ci		write_sequnlock(&curr_sde->head_lock);
5438c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&curr_sde->tail_lock, flags);
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci	schedule_work(&sde->err_halt_worker);
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic void sdma_hw_clean_up_task(struct tasklet_struct *t)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci	struct sdma_engine *sde = from_tasklet(sde, t,
5518c2ecf20Sopenharmony_ci					       sdma_hw_clean_up_task);
5528c2ecf20Sopenharmony_ci	u64 statuscsr;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	while (1) {
5558c2ecf20Sopenharmony_ci#ifdef CONFIG_SDMA_VERBOSITY
5568c2ecf20Sopenharmony_ci		dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n",
5578c2ecf20Sopenharmony_ci			   sde->this_idx, slashstrip(__FILE__), __LINE__,
5588c2ecf20Sopenharmony_ci			__func__);
5598c2ecf20Sopenharmony_ci#endif
5608c2ecf20Sopenharmony_ci		statuscsr = read_sde_csr(sde, SD(STATUS));
5618c2ecf20Sopenharmony_ci		statuscsr &= SD(STATUS_ENG_CLEANED_UP_SMASK);
5628c2ecf20Sopenharmony_ci		if (statuscsr)
5638c2ecf20Sopenharmony_ci			break;
5648c2ecf20Sopenharmony_ci		udelay(10);
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	sdma_process_event(sde, sdma_event_e25_hw_clean_up_done);
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_cistatic inline struct sdma_txreq *get_txhead(struct sdma_engine *sde)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	return sde->tx_ring[sde->tx_head & sde->sdma_mask];
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci/*
5768c2ecf20Sopenharmony_ci * flush ring for recovery
5778c2ecf20Sopenharmony_ci */
5788c2ecf20Sopenharmony_cistatic void sdma_flush_descq(struct sdma_engine *sde)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	u16 head, tail;
5818c2ecf20Sopenharmony_ci	int progress = 0;
5828c2ecf20Sopenharmony_ci	struct sdma_txreq *txp = get_txhead(sde);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	/* The reason for some of the complexity of this code is that
5858c2ecf20Sopenharmony_ci	 * not all descriptors have corresponding txps.  So, we have to
5868c2ecf20Sopenharmony_ci	 * be able to skip over descs until we wander into the range of
5878c2ecf20Sopenharmony_ci	 * the next txp on the list.
5888c2ecf20Sopenharmony_ci	 */
5898c2ecf20Sopenharmony_ci	head = sde->descq_head & sde->sdma_mask;
5908c2ecf20Sopenharmony_ci	tail = sde->descq_tail & sde->sdma_mask;
5918c2ecf20Sopenharmony_ci	while (head != tail) {
5928c2ecf20Sopenharmony_ci		/* advance head, wrap if needed */
5938c2ecf20Sopenharmony_ci		head = ++sde->descq_head & sde->sdma_mask;
5948c2ecf20Sopenharmony_ci		/* if now past this txp's descs, do the callback */
5958c2ecf20Sopenharmony_ci		if (txp && txp->next_descq_idx == head) {
5968c2ecf20Sopenharmony_ci			/* remove from list */
5978c2ecf20Sopenharmony_ci			sde->tx_ring[sde->tx_head++ & sde->sdma_mask] = NULL;
5988c2ecf20Sopenharmony_ci			complete_tx(sde, txp, SDMA_TXREQ_S_ABORTED);
5998c2ecf20Sopenharmony_ci			trace_hfi1_sdma_progress(sde, head, tail, txp);
6008c2ecf20Sopenharmony_ci			txp = get_txhead(sde);
6018c2ecf20Sopenharmony_ci		}
6028c2ecf20Sopenharmony_ci		progress++;
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci	if (progress)
6058c2ecf20Sopenharmony_ci		sdma_desc_avail(sde, sdma_descq_freecnt(sde));
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic void sdma_sw_clean_up_task(struct tasklet_struct *t)
6098c2ecf20Sopenharmony_ci{
6108c2ecf20Sopenharmony_ci	struct sdma_engine *sde = from_tasklet(sde, t, sdma_sw_clean_up_task);
6118c2ecf20Sopenharmony_ci	unsigned long flags;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sde->tail_lock, flags);
6148c2ecf20Sopenharmony_ci	write_seqlock(&sde->head_lock);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	/*
6178c2ecf20Sopenharmony_ci	 * At this point, the following should always be true:
6188c2ecf20Sopenharmony_ci	 * - We are halted, so no more descriptors are getting retired.
6198c2ecf20Sopenharmony_ci	 * - We are not running, so no one is submitting new work.
6208c2ecf20Sopenharmony_ci	 * - Only we can send the e40_sw_cleaned, so we can't start
6218c2ecf20Sopenharmony_ci	 *   running again until we say so.  So, the active list and
6228c2ecf20Sopenharmony_ci	 *   descq are ours to play with.
6238c2ecf20Sopenharmony_ci	 */
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	/*
6268c2ecf20Sopenharmony_ci	 * In the error clean up sequence, software clean must be called
6278c2ecf20Sopenharmony_ci	 * before the hardware clean so we can use the hardware head in
6288c2ecf20Sopenharmony_ci	 * the progress routine.  A hardware clean or SPC unfreeze will
6298c2ecf20Sopenharmony_ci	 * reset the hardware head.
6308c2ecf20Sopenharmony_ci	 *
6318c2ecf20Sopenharmony_ci	 * Process all retired requests. The progress routine will use the
6328c2ecf20Sopenharmony_ci	 * latest physical hardware head - we are not running so speed does
6338c2ecf20Sopenharmony_ci	 * not matter.
6348c2ecf20Sopenharmony_ci	 */
6358c2ecf20Sopenharmony_ci	sdma_make_progress(sde, 0);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	sdma_flush(sde);
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	/*
6408c2ecf20Sopenharmony_ci	 * Reset our notion of head and tail.
6418c2ecf20Sopenharmony_ci	 * Note that the HW registers have been reset via an earlier
6428c2ecf20Sopenharmony_ci	 * clean up.
6438c2ecf20Sopenharmony_ci	 */
6448c2ecf20Sopenharmony_ci	sde->descq_tail = 0;
6458c2ecf20Sopenharmony_ci	sde->descq_head = 0;
6468c2ecf20Sopenharmony_ci	sde->desc_avail = sdma_descq_freecnt(sde);
6478c2ecf20Sopenharmony_ci	*sde->head_dma = 0;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	__sdma_process_event(sde, sdma_event_e40_sw_cleaned);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	write_sequnlock(&sde->head_lock);
6528c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sde->tail_lock, flags);
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_cistatic void sdma_sw_tear_down(struct sdma_engine *sde)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	struct sdma_state *ss = &sde->state;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	/* Releasing this reference means the state machine has stopped. */
6608c2ecf20Sopenharmony_ci	sdma_put(ss);
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	/* stop waiting for all unfreeze events to complete */
6638c2ecf20Sopenharmony_ci	atomic_set(&sde->dd->sdma_unfreeze_count, -1);
6648c2ecf20Sopenharmony_ci	wake_up_interruptible(&sde->dd->sdma_unfreeze_wq);
6658c2ecf20Sopenharmony_ci}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_cistatic void sdma_start_hw_clean_up(struct sdma_engine *sde)
6688c2ecf20Sopenharmony_ci{
6698c2ecf20Sopenharmony_ci	tasklet_hi_schedule(&sde->sdma_hw_clean_up_task);
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_cistatic void sdma_set_state(struct sdma_engine *sde,
6738c2ecf20Sopenharmony_ci			   enum sdma_states next_state)
6748c2ecf20Sopenharmony_ci{
6758c2ecf20Sopenharmony_ci	struct sdma_state *ss = &sde->state;
6768c2ecf20Sopenharmony_ci	const struct sdma_set_state_action *action = sdma_action_table;
6778c2ecf20Sopenharmony_ci	unsigned op = 0;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	trace_hfi1_sdma_state(
6808c2ecf20Sopenharmony_ci		sde,
6818c2ecf20Sopenharmony_ci		sdma_state_names[ss->current_state],
6828c2ecf20Sopenharmony_ci		sdma_state_names[next_state]);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	/* debugging bookkeeping */
6858c2ecf20Sopenharmony_ci	ss->previous_state = ss->current_state;
6868c2ecf20Sopenharmony_ci	ss->previous_op = ss->current_op;
6878c2ecf20Sopenharmony_ci	ss->current_state = next_state;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	if (ss->previous_state != sdma_state_s99_running &&
6908c2ecf20Sopenharmony_ci	    next_state == sdma_state_s99_running)
6918c2ecf20Sopenharmony_ci		sdma_flush(sde);
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	if (action[next_state].op_enable)
6948c2ecf20Sopenharmony_ci		op |= SDMA_SENDCTRL_OP_ENABLE;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	if (action[next_state].op_intenable)
6978c2ecf20Sopenharmony_ci		op |= SDMA_SENDCTRL_OP_INTENABLE;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	if (action[next_state].op_halt)
7008c2ecf20Sopenharmony_ci		op |= SDMA_SENDCTRL_OP_HALT;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	if (action[next_state].op_cleanup)
7038c2ecf20Sopenharmony_ci		op |= SDMA_SENDCTRL_OP_CLEANUP;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	if (action[next_state].go_s99_running_tofalse)
7068c2ecf20Sopenharmony_ci		ss->go_s99_running = 0;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	if (action[next_state].go_s99_running_totrue)
7098c2ecf20Sopenharmony_ci		ss->go_s99_running = 1;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	ss->current_op = op;
7128c2ecf20Sopenharmony_ci	sdma_sendctrl(sde, ss->current_op);
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci/**
7168c2ecf20Sopenharmony_ci * sdma_get_descq_cnt() - called when device probed
7178c2ecf20Sopenharmony_ci *
7188c2ecf20Sopenharmony_ci * Return a validated descq count.
7198c2ecf20Sopenharmony_ci *
7208c2ecf20Sopenharmony_ci * This is currently only used in the verbs initialization to build the tx
7218c2ecf20Sopenharmony_ci * list.
7228c2ecf20Sopenharmony_ci *
7238c2ecf20Sopenharmony_ci * This will probably be deleted in favor of a more scalable approach to
7248c2ecf20Sopenharmony_ci * alloc tx's.
7258c2ecf20Sopenharmony_ci *
7268c2ecf20Sopenharmony_ci */
7278c2ecf20Sopenharmony_ciu16 sdma_get_descq_cnt(void)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	u16 count = sdma_descq_cnt;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	if (!count)
7328c2ecf20Sopenharmony_ci		return SDMA_DESCQ_CNT;
7338c2ecf20Sopenharmony_ci	/* count must be a power of 2 greater than 64 and less than
7348c2ecf20Sopenharmony_ci	 * 32768.   Otherwise return default.
7358c2ecf20Sopenharmony_ci	 */
7368c2ecf20Sopenharmony_ci	if (!is_power_of_2(count))
7378c2ecf20Sopenharmony_ci		return SDMA_DESCQ_CNT;
7388c2ecf20Sopenharmony_ci	if (count < 64 || count > 32768)
7398c2ecf20Sopenharmony_ci		return SDMA_DESCQ_CNT;
7408c2ecf20Sopenharmony_ci	return count;
7418c2ecf20Sopenharmony_ci}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci/**
7448c2ecf20Sopenharmony_ci * sdma_engine_get_vl() - return vl for a given sdma engine
7458c2ecf20Sopenharmony_ci * @sde: sdma engine
7468c2ecf20Sopenharmony_ci *
7478c2ecf20Sopenharmony_ci * This function returns the vl mapped to a given engine, or an error if
7488c2ecf20Sopenharmony_ci * the mapping can't be found. The mapping fields are protected by RCU.
7498c2ecf20Sopenharmony_ci */
7508c2ecf20Sopenharmony_ciint sdma_engine_get_vl(struct sdma_engine *sde)
7518c2ecf20Sopenharmony_ci{
7528c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd = sde->dd;
7538c2ecf20Sopenharmony_ci	struct sdma_vl_map *m;
7548c2ecf20Sopenharmony_ci	u8 vl;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	if (sde->this_idx >= TXE_NUM_SDMA_ENGINES)
7578c2ecf20Sopenharmony_ci		return -EINVAL;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	rcu_read_lock();
7608c2ecf20Sopenharmony_ci	m = rcu_dereference(dd->sdma_map);
7618c2ecf20Sopenharmony_ci	if (unlikely(!m)) {
7628c2ecf20Sopenharmony_ci		rcu_read_unlock();
7638c2ecf20Sopenharmony_ci		return -EINVAL;
7648c2ecf20Sopenharmony_ci	}
7658c2ecf20Sopenharmony_ci	vl = m->engine_to_vl[sde->this_idx];
7668c2ecf20Sopenharmony_ci	rcu_read_unlock();
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	return vl;
7698c2ecf20Sopenharmony_ci}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci/**
7728c2ecf20Sopenharmony_ci * sdma_select_engine_vl() - select sdma engine
7738c2ecf20Sopenharmony_ci * @dd: devdata
7748c2ecf20Sopenharmony_ci * @selector: a spreading factor
7758c2ecf20Sopenharmony_ci * @vl: this vl
7768c2ecf20Sopenharmony_ci *
7778c2ecf20Sopenharmony_ci *
7788c2ecf20Sopenharmony_ci * This function returns an engine based on the selector and a vl.  The
7798c2ecf20Sopenharmony_ci * mapping fields are protected by RCU.
7808c2ecf20Sopenharmony_ci */
7818c2ecf20Sopenharmony_cistruct sdma_engine *sdma_select_engine_vl(
7828c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd,
7838c2ecf20Sopenharmony_ci	u32 selector,
7848c2ecf20Sopenharmony_ci	u8 vl)
7858c2ecf20Sopenharmony_ci{
7868c2ecf20Sopenharmony_ci	struct sdma_vl_map *m;
7878c2ecf20Sopenharmony_ci	struct sdma_map_elem *e;
7888c2ecf20Sopenharmony_ci	struct sdma_engine *rval;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	/* NOTE This should only happen if SC->VL changed after the initial
7918c2ecf20Sopenharmony_ci	 *      checks on the QP/AH
7928c2ecf20Sopenharmony_ci	 *      Default will return engine 0 below
7938c2ecf20Sopenharmony_ci	 */
7948c2ecf20Sopenharmony_ci	if (vl >= num_vls) {
7958c2ecf20Sopenharmony_ci		rval = NULL;
7968c2ecf20Sopenharmony_ci		goto done;
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	rcu_read_lock();
8008c2ecf20Sopenharmony_ci	m = rcu_dereference(dd->sdma_map);
8018c2ecf20Sopenharmony_ci	if (unlikely(!m)) {
8028c2ecf20Sopenharmony_ci		rcu_read_unlock();
8038c2ecf20Sopenharmony_ci		return &dd->per_sdma[0];
8048c2ecf20Sopenharmony_ci	}
8058c2ecf20Sopenharmony_ci	e = m->map[vl & m->mask];
8068c2ecf20Sopenharmony_ci	rval = e->sde[selector & e->mask];
8078c2ecf20Sopenharmony_ci	rcu_read_unlock();
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_cidone:
8108c2ecf20Sopenharmony_ci	rval =  !rval ? &dd->per_sdma[0] : rval;
8118c2ecf20Sopenharmony_ci	trace_hfi1_sdma_engine_select(dd, selector, vl, rval->this_idx);
8128c2ecf20Sopenharmony_ci	return rval;
8138c2ecf20Sopenharmony_ci}
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci/**
8168c2ecf20Sopenharmony_ci * sdma_select_engine_sc() - select sdma engine
8178c2ecf20Sopenharmony_ci * @dd: devdata
8188c2ecf20Sopenharmony_ci * @selector: a spreading factor
8198c2ecf20Sopenharmony_ci * @sc5: the 5 bit sc
8208c2ecf20Sopenharmony_ci *
8218c2ecf20Sopenharmony_ci *
8228c2ecf20Sopenharmony_ci * This function returns an engine based on the selector and an sc.
8238c2ecf20Sopenharmony_ci */
8248c2ecf20Sopenharmony_cistruct sdma_engine *sdma_select_engine_sc(
8258c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd,
8268c2ecf20Sopenharmony_ci	u32 selector,
8278c2ecf20Sopenharmony_ci	u8 sc5)
8288c2ecf20Sopenharmony_ci{
8298c2ecf20Sopenharmony_ci	u8 vl = sc_to_vlt(dd, sc5);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	return sdma_select_engine_vl(dd, selector, vl);
8328c2ecf20Sopenharmony_ci}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_cistruct sdma_rht_map_elem {
8358c2ecf20Sopenharmony_ci	u32 mask;
8368c2ecf20Sopenharmony_ci	u8 ctr;
8378c2ecf20Sopenharmony_ci	struct sdma_engine *sde[];
8388c2ecf20Sopenharmony_ci};
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_cistruct sdma_rht_node {
8418c2ecf20Sopenharmony_ci	unsigned long cpu_id;
8428c2ecf20Sopenharmony_ci	struct sdma_rht_map_elem *map[HFI1_MAX_VLS_SUPPORTED];
8438c2ecf20Sopenharmony_ci	struct rhash_head node;
8448c2ecf20Sopenharmony_ci};
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci#define NR_CPUS_HINT 192
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_cistatic const struct rhashtable_params sdma_rht_params = {
8498c2ecf20Sopenharmony_ci	.nelem_hint = NR_CPUS_HINT,
8508c2ecf20Sopenharmony_ci	.head_offset = offsetof(struct sdma_rht_node, node),
8518c2ecf20Sopenharmony_ci	.key_offset = offsetof(struct sdma_rht_node, cpu_id),
8528c2ecf20Sopenharmony_ci	.key_len = sizeof_field(struct sdma_rht_node, cpu_id),
8538c2ecf20Sopenharmony_ci	.max_size = NR_CPUS,
8548c2ecf20Sopenharmony_ci	.min_size = 8,
8558c2ecf20Sopenharmony_ci	.automatic_shrinking = true,
8568c2ecf20Sopenharmony_ci};
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci/*
8598c2ecf20Sopenharmony_ci * sdma_select_user_engine() - select sdma engine based on user setup
8608c2ecf20Sopenharmony_ci * @dd: devdata
8618c2ecf20Sopenharmony_ci * @selector: a spreading factor
8628c2ecf20Sopenharmony_ci * @vl: this vl
8638c2ecf20Sopenharmony_ci *
8648c2ecf20Sopenharmony_ci * This function returns an sdma engine for a user sdma request.
8658c2ecf20Sopenharmony_ci * User defined sdma engine affinity setting is honored when applicable,
8668c2ecf20Sopenharmony_ci * otherwise system default sdma engine mapping is used. To ensure correct
8678c2ecf20Sopenharmony_ci * ordering, the mapping from <selector, vl> to sde must remain unchanged.
8688c2ecf20Sopenharmony_ci */
8698c2ecf20Sopenharmony_cistruct sdma_engine *sdma_select_user_engine(struct hfi1_devdata *dd,
8708c2ecf20Sopenharmony_ci					    u32 selector, u8 vl)
8718c2ecf20Sopenharmony_ci{
8728c2ecf20Sopenharmony_ci	struct sdma_rht_node *rht_node;
8738c2ecf20Sopenharmony_ci	struct sdma_engine *sde = NULL;
8748c2ecf20Sopenharmony_ci	unsigned long cpu_id;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	/*
8778c2ecf20Sopenharmony_ci	 * To ensure that always the same sdma engine(s) will be
8788c2ecf20Sopenharmony_ci	 * selected make sure the process is pinned to this CPU only.
8798c2ecf20Sopenharmony_ci	 */
8808c2ecf20Sopenharmony_ci	if (current->nr_cpus_allowed != 1)
8818c2ecf20Sopenharmony_ci		goto out;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	rcu_read_lock();
8848c2ecf20Sopenharmony_ci	cpu_id = smp_processor_id();
8858c2ecf20Sopenharmony_ci	rht_node = rhashtable_lookup(dd->sdma_rht, &cpu_id,
8868c2ecf20Sopenharmony_ci				     sdma_rht_params);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	if (rht_node && rht_node->map[vl]) {
8898c2ecf20Sopenharmony_ci		struct sdma_rht_map_elem *map = rht_node->map[vl];
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci		sde = map->sde[selector & map->mask];
8928c2ecf20Sopenharmony_ci	}
8938c2ecf20Sopenharmony_ci	rcu_read_unlock();
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	if (sde)
8968c2ecf20Sopenharmony_ci		return sde;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ciout:
8998c2ecf20Sopenharmony_ci	return sdma_select_engine_vl(dd, selector, vl);
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_cistatic void sdma_populate_sde_map(struct sdma_rht_map_elem *map)
9038c2ecf20Sopenharmony_ci{
9048c2ecf20Sopenharmony_ci	int i;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	for (i = 0; i < roundup_pow_of_two(map->ctr ? : 1) - map->ctr; i++)
9078c2ecf20Sopenharmony_ci		map->sde[map->ctr + i] = map->sde[i];
9088c2ecf20Sopenharmony_ci}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_cistatic void sdma_cleanup_sde_map(struct sdma_rht_map_elem *map,
9118c2ecf20Sopenharmony_ci				 struct sdma_engine *sde)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci	unsigned int i, pow;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	/* only need to check the first ctr entries for a match */
9168c2ecf20Sopenharmony_ci	for (i = 0; i < map->ctr; i++) {
9178c2ecf20Sopenharmony_ci		if (map->sde[i] == sde) {
9188c2ecf20Sopenharmony_ci			memmove(&map->sde[i], &map->sde[i + 1],
9198c2ecf20Sopenharmony_ci				(map->ctr - i - 1) * sizeof(map->sde[0]));
9208c2ecf20Sopenharmony_ci			map->ctr--;
9218c2ecf20Sopenharmony_ci			pow = roundup_pow_of_two(map->ctr ? : 1);
9228c2ecf20Sopenharmony_ci			map->mask = pow - 1;
9238c2ecf20Sopenharmony_ci			sdma_populate_sde_map(map);
9248c2ecf20Sopenharmony_ci			break;
9258c2ecf20Sopenharmony_ci		}
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci/*
9308c2ecf20Sopenharmony_ci * Prevents concurrent reads and writes of the sdma engine cpu_mask
9318c2ecf20Sopenharmony_ci */
9328c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(process_to_sde_mutex);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_cissize_t sdma_set_cpu_to_sde_map(struct sdma_engine *sde, const char *buf,
9358c2ecf20Sopenharmony_ci				size_t count)
9368c2ecf20Sopenharmony_ci{
9378c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd = sde->dd;
9388c2ecf20Sopenharmony_ci	cpumask_var_t mask, new_mask;
9398c2ecf20Sopenharmony_ci	unsigned long cpu;
9408c2ecf20Sopenharmony_ci	int ret, vl, sz;
9418c2ecf20Sopenharmony_ci	struct sdma_rht_node *rht_node;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	vl = sdma_engine_get_vl(sde);
9448c2ecf20Sopenharmony_ci	if (unlikely(vl < 0 || vl >= ARRAY_SIZE(rht_node->map)))
9458c2ecf20Sopenharmony_ci		return -EINVAL;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	ret = zalloc_cpumask_var(&mask, GFP_KERNEL);
9488c2ecf20Sopenharmony_ci	if (!ret)
9498c2ecf20Sopenharmony_ci		return -ENOMEM;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	ret = zalloc_cpumask_var(&new_mask, GFP_KERNEL);
9528c2ecf20Sopenharmony_ci	if (!ret) {
9538c2ecf20Sopenharmony_ci		free_cpumask_var(mask);
9548c2ecf20Sopenharmony_ci		return -ENOMEM;
9558c2ecf20Sopenharmony_ci	}
9568c2ecf20Sopenharmony_ci	ret = cpulist_parse(buf, mask);
9578c2ecf20Sopenharmony_ci	if (ret)
9588c2ecf20Sopenharmony_ci		goto out_free;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	if (!cpumask_subset(mask, cpu_online_mask)) {
9618c2ecf20Sopenharmony_ci		dd_dev_warn(sde->dd, "Invalid CPU mask\n");
9628c2ecf20Sopenharmony_ci		ret = -EINVAL;
9638c2ecf20Sopenharmony_ci		goto out_free;
9648c2ecf20Sopenharmony_ci	}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	sz = sizeof(struct sdma_rht_map_elem) +
9678c2ecf20Sopenharmony_ci			(TXE_NUM_SDMA_ENGINES * sizeof(struct sdma_engine *));
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	mutex_lock(&process_to_sde_mutex);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	for_each_cpu(cpu, mask) {
9728c2ecf20Sopenharmony_ci		/* Check if we have this already mapped */
9738c2ecf20Sopenharmony_ci		if (cpumask_test_cpu(cpu, &sde->cpu_mask)) {
9748c2ecf20Sopenharmony_ci			cpumask_set_cpu(cpu, new_mask);
9758c2ecf20Sopenharmony_ci			continue;
9768c2ecf20Sopenharmony_ci		}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci		rht_node = rhashtable_lookup_fast(dd->sdma_rht, &cpu,
9798c2ecf20Sopenharmony_ci						  sdma_rht_params);
9808c2ecf20Sopenharmony_ci		if (!rht_node) {
9818c2ecf20Sopenharmony_ci			rht_node = kzalloc(sizeof(*rht_node), GFP_KERNEL);
9828c2ecf20Sopenharmony_ci			if (!rht_node) {
9838c2ecf20Sopenharmony_ci				ret = -ENOMEM;
9848c2ecf20Sopenharmony_ci				goto out;
9858c2ecf20Sopenharmony_ci			}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci			rht_node->map[vl] = kzalloc(sz, GFP_KERNEL);
9888c2ecf20Sopenharmony_ci			if (!rht_node->map[vl]) {
9898c2ecf20Sopenharmony_ci				kfree(rht_node);
9908c2ecf20Sopenharmony_ci				ret = -ENOMEM;
9918c2ecf20Sopenharmony_ci				goto out;
9928c2ecf20Sopenharmony_ci			}
9938c2ecf20Sopenharmony_ci			rht_node->cpu_id = cpu;
9948c2ecf20Sopenharmony_ci			rht_node->map[vl]->mask = 0;
9958c2ecf20Sopenharmony_ci			rht_node->map[vl]->ctr = 1;
9968c2ecf20Sopenharmony_ci			rht_node->map[vl]->sde[0] = sde;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci			ret = rhashtable_insert_fast(dd->sdma_rht,
9998c2ecf20Sopenharmony_ci						     &rht_node->node,
10008c2ecf20Sopenharmony_ci						     sdma_rht_params);
10018c2ecf20Sopenharmony_ci			if (ret) {
10028c2ecf20Sopenharmony_ci				kfree(rht_node->map[vl]);
10038c2ecf20Sopenharmony_ci				kfree(rht_node);
10048c2ecf20Sopenharmony_ci				dd_dev_err(sde->dd, "Failed to set process to sde affinity for cpu %lu\n",
10058c2ecf20Sopenharmony_ci					   cpu);
10068c2ecf20Sopenharmony_ci				goto out;
10078c2ecf20Sopenharmony_ci			}
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci		} else {
10108c2ecf20Sopenharmony_ci			int ctr, pow;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci			/* Add new user mappings */
10138c2ecf20Sopenharmony_ci			if (!rht_node->map[vl])
10148c2ecf20Sopenharmony_ci				rht_node->map[vl] = kzalloc(sz, GFP_KERNEL);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci			if (!rht_node->map[vl]) {
10178c2ecf20Sopenharmony_ci				ret = -ENOMEM;
10188c2ecf20Sopenharmony_ci				goto out;
10198c2ecf20Sopenharmony_ci			}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci			rht_node->map[vl]->ctr++;
10228c2ecf20Sopenharmony_ci			ctr = rht_node->map[vl]->ctr;
10238c2ecf20Sopenharmony_ci			rht_node->map[vl]->sde[ctr - 1] = sde;
10248c2ecf20Sopenharmony_ci			pow = roundup_pow_of_two(ctr);
10258c2ecf20Sopenharmony_ci			rht_node->map[vl]->mask = pow - 1;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci			/* Populate the sde map table */
10288c2ecf20Sopenharmony_ci			sdma_populate_sde_map(rht_node->map[vl]);
10298c2ecf20Sopenharmony_ci		}
10308c2ecf20Sopenharmony_ci		cpumask_set_cpu(cpu, new_mask);
10318c2ecf20Sopenharmony_ci	}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	/* Clean up old mappings */
10348c2ecf20Sopenharmony_ci	for_each_cpu(cpu, cpu_online_mask) {
10358c2ecf20Sopenharmony_ci		struct sdma_rht_node *rht_node;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci		/* Don't cleanup sdes that are set in the new mask */
10388c2ecf20Sopenharmony_ci		if (cpumask_test_cpu(cpu, mask))
10398c2ecf20Sopenharmony_ci			continue;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci		rht_node = rhashtable_lookup_fast(dd->sdma_rht, &cpu,
10428c2ecf20Sopenharmony_ci						  sdma_rht_params);
10438c2ecf20Sopenharmony_ci		if (rht_node) {
10448c2ecf20Sopenharmony_ci			bool empty = true;
10458c2ecf20Sopenharmony_ci			int i;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci			/* Remove mappings for old sde */
10488c2ecf20Sopenharmony_ci			for (i = 0; i < HFI1_MAX_VLS_SUPPORTED; i++)
10498c2ecf20Sopenharmony_ci				if (rht_node->map[i])
10508c2ecf20Sopenharmony_ci					sdma_cleanup_sde_map(rht_node->map[i],
10518c2ecf20Sopenharmony_ci							     sde);
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci			/* Free empty hash table entries */
10548c2ecf20Sopenharmony_ci			for (i = 0; i < HFI1_MAX_VLS_SUPPORTED; i++) {
10558c2ecf20Sopenharmony_ci				if (!rht_node->map[i])
10568c2ecf20Sopenharmony_ci					continue;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci				if (rht_node->map[i]->ctr) {
10598c2ecf20Sopenharmony_ci					empty = false;
10608c2ecf20Sopenharmony_ci					break;
10618c2ecf20Sopenharmony_ci				}
10628c2ecf20Sopenharmony_ci			}
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci			if (empty) {
10658c2ecf20Sopenharmony_ci				ret = rhashtable_remove_fast(dd->sdma_rht,
10668c2ecf20Sopenharmony_ci							     &rht_node->node,
10678c2ecf20Sopenharmony_ci							     sdma_rht_params);
10688c2ecf20Sopenharmony_ci				WARN_ON(ret);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci				for (i = 0; i < HFI1_MAX_VLS_SUPPORTED; i++)
10718c2ecf20Sopenharmony_ci					kfree(rht_node->map[i]);
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci				kfree(rht_node);
10748c2ecf20Sopenharmony_ci			}
10758c2ecf20Sopenharmony_ci		}
10768c2ecf20Sopenharmony_ci	}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	cpumask_copy(&sde->cpu_mask, new_mask);
10798c2ecf20Sopenharmony_ciout:
10808c2ecf20Sopenharmony_ci	mutex_unlock(&process_to_sde_mutex);
10818c2ecf20Sopenharmony_ciout_free:
10828c2ecf20Sopenharmony_ci	free_cpumask_var(mask);
10838c2ecf20Sopenharmony_ci	free_cpumask_var(new_mask);
10848c2ecf20Sopenharmony_ci	return ret ? : strnlen(buf, PAGE_SIZE);
10858c2ecf20Sopenharmony_ci}
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_cissize_t sdma_get_cpu_to_sde_map(struct sdma_engine *sde, char *buf)
10888c2ecf20Sopenharmony_ci{
10898c2ecf20Sopenharmony_ci	mutex_lock(&process_to_sde_mutex);
10908c2ecf20Sopenharmony_ci	if (cpumask_empty(&sde->cpu_mask))
10918c2ecf20Sopenharmony_ci		snprintf(buf, PAGE_SIZE, "%s\n", "empty");
10928c2ecf20Sopenharmony_ci	else
10938c2ecf20Sopenharmony_ci		cpumap_print_to_pagebuf(true, buf, &sde->cpu_mask);
10948c2ecf20Sopenharmony_ci	mutex_unlock(&process_to_sde_mutex);
10958c2ecf20Sopenharmony_ci	return strnlen(buf, PAGE_SIZE);
10968c2ecf20Sopenharmony_ci}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_cistatic void sdma_rht_free(void *ptr, void *arg)
10998c2ecf20Sopenharmony_ci{
11008c2ecf20Sopenharmony_ci	struct sdma_rht_node *rht_node = ptr;
11018c2ecf20Sopenharmony_ci	int i;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	for (i = 0; i < HFI1_MAX_VLS_SUPPORTED; i++)
11048c2ecf20Sopenharmony_ci		kfree(rht_node->map[i]);
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	kfree(rht_node);
11078c2ecf20Sopenharmony_ci}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci/**
11108c2ecf20Sopenharmony_ci * sdma_seqfile_dump_cpu_list() - debugfs dump the cpu to sdma mappings
11118c2ecf20Sopenharmony_ci * @s: seq file
11128c2ecf20Sopenharmony_ci * @dd: hfi1_devdata
11138c2ecf20Sopenharmony_ci * @cpuid: cpu id
11148c2ecf20Sopenharmony_ci *
11158c2ecf20Sopenharmony_ci * This routine dumps the process to sde mappings per cpu
11168c2ecf20Sopenharmony_ci */
11178c2ecf20Sopenharmony_civoid sdma_seqfile_dump_cpu_list(struct seq_file *s,
11188c2ecf20Sopenharmony_ci				struct hfi1_devdata *dd,
11198c2ecf20Sopenharmony_ci				unsigned long cpuid)
11208c2ecf20Sopenharmony_ci{
11218c2ecf20Sopenharmony_ci	struct sdma_rht_node *rht_node;
11228c2ecf20Sopenharmony_ci	int i, j;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	rht_node = rhashtable_lookup_fast(dd->sdma_rht, &cpuid,
11258c2ecf20Sopenharmony_ci					  sdma_rht_params);
11268c2ecf20Sopenharmony_ci	if (!rht_node)
11278c2ecf20Sopenharmony_ci		return;
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	seq_printf(s, "cpu%3lu: ", cpuid);
11308c2ecf20Sopenharmony_ci	for (i = 0; i < HFI1_MAX_VLS_SUPPORTED; i++) {
11318c2ecf20Sopenharmony_ci		if (!rht_node->map[i] || !rht_node->map[i]->ctr)
11328c2ecf20Sopenharmony_ci			continue;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci		seq_printf(s, " vl%d: [", i);
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci		for (j = 0; j < rht_node->map[i]->ctr; j++) {
11378c2ecf20Sopenharmony_ci			if (!rht_node->map[i]->sde[j])
11388c2ecf20Sopenharmony_ci				continue;
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci			if (j > 0)
11418c2ecf20Sopenharmony_ci				seq_puts(s, ",");
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci			seq_printf(s, " sdma%2d",
11448c2ecf20Sopenharmony_ci				   rht_node->map[i]->sde[j]->this_idx);
11458c2ecf20Sopenharmony_ci		}
11468c2ecf20Sopenharmony_ci		seq_puts(s, " ]");
11478c2ecf20Sopenharmony_ci	}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	seq_puts(s, "\n");
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci/*
11538c2ecf20Sopenharmony_ci * Free the indicated map struct
11548c2ecf20Sopenharmony_ci */
11558c2ecf20Sopenharmony_cistatic void sdma_map_free(struct sdma_vl_map *m)
11568c2ecf20Sopenharmony_ci{
11578c2ecf20Sopenharmony_ci	int i;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	for (i = 0; m && i < m->actual_vls; i++)
11608c2ecf20Sopenharmony_ci		kfree(m->map[i]);
11618c2ecf20Sopenharmony_ci	kfree(m);
11628c2ecf20Sopenharmony_ci}
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci/*
11658c2ecf20Sopenharmony_ci * Handle RCU callback
11668c2ecf20Sopenharmony_ci */
11678c2ecf20Sopenharmony_cistatic void sdma_map_rcu_callback(struct rcu_head *list)
11688c2ecf20Sopenharmony_ci{
11698c2ecf20Sopenharmony_ci	struct sdma_vl_map *m = container_of(list, struct sdma_vl_map, list);
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	sdma_map_free(m);
11728c2ecf20Sopenharmony_ci}
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci/**
11758c2ecf20Sopenharmony_ci * sdma_map_init - called when # vls change
11768c2ecf20Sopenharmony_ci * @dd: hfi1_devdata
11778c2ecf20Sopenharmony_ci * @port: port number
11788c2ecf20Sopenharmony_ci * @num_vls: number of vls
11798c2ecf20Sopenharmony_ci * @vl_engines: per vl engine mapping (optional)
11808c2ecf20Sopenharmony_ci *
11818c2ecf20Sopenharmony_ci * This routine changes the mapping based on the number of vls.
11828c2ecf20Sopenharmony_ci *
11838c2ecf20Sopenharmony_ci * vl_engines is used to specify a non-uniform vl/engine loading. NULL
11848c2ecf20Sopenharmony_ci * implies auto computing the loading and giving each VLs a uniform
11858c2ecf20Sopenharmony_ci * distribution of engines per VL.
11868c2ecf20Sopenharmony_ci *
11878c2ecf20Sopenharmony_ci * The auto algorithm computes the sde_per_vl and the number of extra
11888c2ecf20Sopenharmony_ci * engines.  Any extra engines are added from the last VL on down.
11898c2ecf20Sopenharmony_ci *
11908c2ecf20Sopenharmony_ci * rcu locking is used here to control access to the mapping fields.
11918c2ecf20Sopenharmony_ci *
11928c2ecf20Sopenharmony_ci * If either the num_vls or num_sdma are non-power of 2, the array sizes
11938c2ecf20Sopenharmony_ci * in the struct sdma_vl_map and the struct sdma_map_elem are rounded
11948c2ecf20Sopenharmony_ci * up to the next highest power of 2 and the first entry is reused
11958c2ecf20Sopenharmony_ci * in a round robin fashion.
11968c2ecf20Sopenharmony_ci *
11978c2ecf20Sopenharmony_ci * If an error occurs the map change is not done and the mapping is
11988c2ecf20Sopenharmony_ci * not changed.
11998c2ecf20Sopenharmony_ci *
12008c2ecf20Sopenharmony_ci */
12018c2ecf20Sopenharmony_ciint sdma_map_init(struct hfi1_devdata *dd, u8 port, u8 num_vls, u8 *vl_engines)
12028c2ecf20Sopenharmony_ci{
12038c2ecf20Sopenharmony_ci	int i, j;
12048c2ecf20Sopenharmony_ci	int extra, sde_per_vl;
12058c2ecf20Sopenharmony_ci	int engine = 0;
12068c2ecf20Sopenharmony_ci	u8 lvl_engines[OPA_MAX_VLS];
12078c2ecf20Sopenharmony_ci	struct sdma_vl_map *oldmap, *newmap;
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	if (!(dd->flags & HFI1_HAS_SEND_DMA))
12108c2ecf20Sopenharmony_ci		return 0;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	if (!vl_engines) {
12138c2ecf20Sopenharmony_ci		/* truncate divide */
12148c2ecf20Sopenharmony_ci		sde_per_vl = dd->num_sdma / num_vls;
12158c2ecf20Sopenharmony_ci		/* extras */
12168c2ecf20Sopenharmony_ci		extra = dd->num_sdma % num_vls;
12178c2ecf20Sopenharmony_ci		vl_engines = lvl_engines;
12188c2ecf20Sopenharmony_ci		/* add extras from last vl down */
12198c2ecf20Sopenharmony_ci		for (i = num_vls - 1; i >= 0; i--, extra--)
12208c2ecf20Sopenharmony_ci			vl_engines[i] = sde_per_vl + (extra > 0 ? 1 : 0);
12218c2ecf20Sopenharmony_ci	}
12228c2ecf20Sopenharmony_ci	/* build new map */
12238c2ecf20Sopenharmony_ci	newmap = kzalloc(
12248c2ecf20Sopenharmony_ci		sizeof(struct sdma_vl_map) +
12258c2ecf20Sopenharmony_ci			roundup_pow_of_two(num_vls) *
12268c2ecf20Sopenharmony_ci			sizeof(struct sdma_map_elem *),
12278c2ecf20Sopenharmony_ci		GFP_KERNEL);
12288c2ecf20Sopenharmony_ci	if (!newmap)
12298c2ecf20Sopenharmony_ci		goto bail;
12308c2ecf20Sopenharmony_ci	newmap->actual_vls = num_vls;
12318c2ecf20Sopenharmony_ci	newmap->vls = roundup_pow_of_two(num_vls);
12328c2ecf20Sopenharmony_ci	newmap->mask = (1 << ilog2(newmap->vls)) - 1;
12338c2ecf20Sopenharmony_ci	/* initialize back-map */
12348c2ecf20Sopenharmony_ci	for (i = 0; i < TXE_NUM_SDMA_ENGINES; i++)
12358c2ecf20Sopenharmony_ci		newmap->engine_to_vl[i] = -1;
12368c2ecf20Sopenharmony_ci	for (i = 0; i < newmap->vls; i++) {
12378c2ecf20Sopenharmony_ci		/* save for wrap around */
12388c2ecf20Sopenharmony_ci		int first_engine = engine;
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci		if (i < newmap->actual_vls) {
12418c2ecf20Sopenharmony_ci			int sz = roundup_pow_of_two(vl_engines[i]);
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci			/* only allocate once */
12448c2ecf20Sopenharmony_ci			newmap->map[i] = kzalloc(
12458c2ecf20Sopenharmony_ci				sizeof(struct sdma_map_elem) +
12468c2ecf20Sopenharmony_ci					sz * sizeof(struct sdma_engine *),
12478c2ecf20Sopenharmony_ci				GFP_KERNEL);
12488c2ecf20Sopenharmony_ci			if (!newmap->map[i])
12498c2ecf20Sopenharmony_ci				goto bail;
12508c2ecf20Sopenharmony_ci			newmap->map[i]->mask = (1 << ilog2(sz)) - 1;
12518c2ecf20Sopenharmony_ci			/* assign engines */
12528c2ecf20Sopenharmony_ci			for (j = 0; j < sz; j++) {
12538c2ecf20Sopenharmony_ci				newmap->map[i]->sde[j] =
12548c2ecf20Sopenharmony_ci					&dd->per_sdma[engine];
12558c2ecf20Sopenharmony_ci				if (++engine >= first_engine + vl_engines[i])
12568c2ecf20Sopenharmony_ci					/* wrap back to first engine */
12578c2ecf20Sopenharmony_ci					engine = first_engine;
12588c2ecf20Sopenharmony_ci			}
12598c2ecf20Sopenharmony_ci			/* assign back-map */
12608c2ecf20Sopenharmony_ci			for (j = 0; j < vl_engines[i]; j++)
12618c2ecf20Sopenharmony_ci				newmap->engine_to_vl[first_engine + j] = i;
12628c2ecf20Sopenharmony_ci		} else {
12638c2ecf20Sopenharmony_ci			/* just re-use entry without allocating */
12648c2ecf20Sopenharmony_ci			newmap->map[i] = newmap->map[i % num_vls];
12658c2ecf20Sopenharmony_ci		}
12668c2ecf20Sopenharmony_ci		engine = first_engine + vl_engines[i];
12678c2ecf20Sopenharmony_ci	}
12688c2ecf20Sopenharmony_ci	/* newmap in hand, save old map */
12698c2ecf20Sopenharmony_ci	spin_lock_irq(&dd->sde_map_lock);
12708c2ecf20Sopenharmony_ci	oldmap = rcu_dereference_protected(dd->sdma_map,
12718c2ecf20Sopenharmony_ci					   lockdep_is_held(&dd->sde_map_lock));
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	/* publish newmap */
12748c2ecf20Sopenharmony_ci	rcu_assign_pointer(dd->sdma_map, newmap);
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	spin_unlock_irq(&dd->sde_map_lock);
12778c2ecf20Sopenharmony_ci	/* success, free any old map after grace period */
12788c2ecf20Sopenharmony_ci	if (oldmap)
12798c2ecf20Sopenharmony_ci		call_rcu(&oldmap->list, sdma_map_rcu_callback);
12808c2ecf20Sopenharmony_ci	return 0;
12818c2ecf20Sopenharmony_cibail:
12828c2ecf20Sopenharmony_ci	/* free any partial allocation */
12838c2ecf20Sopenharmony_ci	sdma_map_free(newmap);
12848c2ecf20Sopenharmony_ci	return -ENOMEM;
12858c2ecf20Sopenharmony_ci}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci/**
12888c2ecf20Sopenharmony_ci * sdma_clean()  Clean up allocated memory
12898c2ecf20Sopenharmony_ci * @dd:          struct hfi1_devdata
12908c2ecf20Sopenharmony_ci * @num_engines: num sdma engines
12918c2ecf20Sopenharmony_ci *
12928c2ecf20Sopenharmony_ci * This routine can be called regardless of the success of
12938c2ecf20Sopenharmony_ci * sdma_init()
12948c2ecf20Sopenharmony_ci */
12958c2ecf20Sopenharmony_civoid sdma_clean(struct hfi1_devdata *dd, size_t num_engines)
12968c2ecf20Sopenharmony_ci{
12978c2ecf20Sopenharmony_ci	size_t i;
12988c2ecf20Sopenharmony_ci	struct sdma_engine *sde;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	if (dd->sdma_pad_dma) {
13018c2ecf20Sopenharmony_ci		dma_free_coherent(&dd->pcidev->dev, SDMA_PAD,
13028c2ecf20Sopenharmony_ci				  (void *)dd->sdma_pad_dma,
13038c2ecf20Sopenharmony_ci				  dd->sdma_pad_phys);
13048c2ecf20Sopenharmony_ci		dd->sdma_pad_dma = NULL;
13058c2ecf20Sopenharmony_ci		dd->sdma_pad_phys = 0;
13068c2ecf20Sopenharmony_ci	}
13078c2ecf20Sopenharmony_ci	if (dd->sdma_heads_dma) {
13088c2ecf20Sopenharmony_ci		dma_free_coherent(&dd->pcidev->dev, dd->sdma_heads_size,
13098c2ecf20Sopenharmony_ci				  (void *)dd->sdma_heads_dma,
13108c2ecf20Sopenharmony_ci				  dd->sdma_heads_phys);
13118c2ecf20Sopenharmony_ci		dd->sdma_heads_dma = NULL;
13128c2ecf20Sopenharmony_ci		dd->sdma_heads_phys = 0;
13138c2ecf20Sopenharmony_ci	}
13148c2ecf20Sopenharmony_ci	for (i = 0; dd->per_sdma && i < num_engines; ++i) {
13158c2ecf20Sopenharmony_ci		sde = &dd->per_sdma[i];
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci		sde->head_dma = NULL;
13188c2ecf20Sopenharmony_ci		sde->head_phys = 0;
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci		if (sde->descq) {
13218c2ecf20Sopenharmony_ci			dma_free_coherent(
13228c2ecf20Sopenharmony_ci				&dd->pcidev->dev,
13238c2ecf20Sopenharmony_ci				sde->descq_cnt * sizeof(u64[2]),
13248c2ecf20Sopenharmony_ci				sde->descq,
13258c2ecf20Sopenharmony_ci				sde->descq_phys
13268c2ecf20Sopenharmony_ci			);
13278c2ecf20Sopenharmony_ci			sde->descq = NULL;
13288c2ecf20Sopenharmony_ci			sde->descq_phys = 0;
13298c2ecf20Sopenharmony_ci		}
13308c2ecf20Sopenharmony_ci		kvfree(sde->tx_ring);
13318c2ecf20Sopenharmony_ci		sde->tx_ring = NULL;
13328c2ecf20Sopenharmony_ci	}
13338c2ecf20Sopenharmony_ci	if (rcu_access_pointer(dd->sdma_map)) {
13348c2ecf20Sopenharmony_ci		spin_lock_irq(&dd->sde_map_lock);
13358c2ecf20Sopenharmony_ci		sdma_map_free(rcu_access_pointer(dd->sdma_map));
13368c2ecf20Sopenharmony_ci		RCU_INIT_POINTER(dd->sdma_map, NULL);
13378c2ecf20Sopenharmony_ci		spin_unlock_irq(&dd->sde_map_lock);
13388c2ecf20Sopenharmony_ci		synchronize_rcu();
13398c2ecf20Sopenharmony_ci	}
13408c2ecf20Sopenharmony_ci	kfree(dd->per_sdma);
13418c2ecf20Sopenharmony_ci	dd->per_sdma = NULL;
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	if (dd->sdma_rht) {
13448c2ecf20Sopenharmony_ci		rhashtable_free_and_destroy(dd->sdma_rht, sdma_rht_free, NULL);
13458c2ecf20Sopenharmony_ci		kfree(dd->sdma_rht);
13468c2ecf20Sopenharmony_ci		dd->sdma_rht = NULL;
13478c2ecf20Sopenharmony_ci	}
13488c2ecf20Sopenharmony_ci}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci/**
13518c2ecf20Sopenharmony_ci * sdma_init() - called when device probed
13528c2ecf20Sopenharmony_ci * @dd: hfi1_devdata
13538c2ecf20Sopenharmony_ci * @port: port number (currently only zero)
13548c2ecf20Sopenharmony_ci *
13558c2ecf20Sopenharmony_ci * Initializes each sde and its csrs.
13568c2ecf20Sopenharmony_ci * Interrupts are not required to be enabled.
13578c2ecf20Sopenharmony_ci *
13588c2ecf20Sopenharmony_ci * Returns:
13598c2ecf20Sopenharmony_ci * 0 - success, -errno on failure
13608c2ecf20Sopenharmony_ci */
13618c2ecf20Sopenharmony_ciint sdma_init(struct hfi1_devdata *dd, u8 port)
13628c2ecf20Sopenharmony_ci{
13638c2ecf20Sopenharmony_ci	unsigned this_idx;
13648c2ecf20Sopenharmony_ci	struct sdma_engine *sde;
13658c2ecf20Sopenharmony_ci	struct rhashtable *tmp_sdma_rht;
13668c2ecf20Sopenharmony_ci	u16 descq_cnt;
13678c2ecf20Sopenharmony_ci	void *curr_head;
13688c2ecf20Sopenharmony_ci	struct hfi1_pportdata *ppd = dd->pport + port;
13698c2ecf20Sopenharmony_ci	u32 per_sdma_credits;
13708c2ecf20Sopenharmony_ci	uint idle_cnt = sdma_idle_cnt;
13718c2ecf20Sopenharmony_ci	size_t num_engines = chip_sdma_engines(dd);
13728c2ecf20Sopenharmony_ci	int ret = -ENOMEM;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	if (!HFI1_CAP_IS_KSET(SDMA)) {
13758c2ecf20Sopenharmony_ci		HFI1_CAP_CLEAR(SDMA_AHG);
13768c2ecf20Sopenharmony_ci		return 0;
13778c2ecf20Sopenharmony_ci	}
13788c2ecf20Sopenharmony_ci	if (mod_num_sdma &&
13798c2ecf20Sopenharmony_ci	    /* can't exceed chip support */
13808c2ecf20Sopenharmony_ci	    mod_num_sdma <= chip_sdma_engines(dd) &&
13818c2ecf20Sopenharmony_ci	    /* count must be >= vls */
13828c2ecf20Sopenharmony_ci	    mod_num_sdma >= num_vls)
13838c2ecf20Sopenharmony_ci		num_engines = mod_num_sdma;
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	dd_dev_info(dd, "SDMA mod_num_sdma: %u\n", mod_num_sdma);
13868c2ecf20Sopenharmony_ci	dd_dev_info(dd, "SDMA chip_sdma_engines: %u\n", chip_sdma_engines(dd));
13878c2ecf20Sopenharmony_ci	dd_dev_info(dd, "SDMA chip_sdma_mem_size: %u\n",
13888c2ecf20Sopenharmony_ci		    chip_sdma_mem_size(dd));
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci	per_sdma_credits =
13918c2ecf20Sopenharmony_ci		chip_sdma_mem_size(dd) / (num_engines * SDMA_BLOCK_SIZE);
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	/* set up freeze waitqueue */
13948c2ecf20Sopenharmony_ci	init_waitqueue_head(&dd->sdma_unfreeze_wq);
13958c2ecf20Sopenharmony_ci	atomic_set(&dd->sdma_unfreeze_count, 0);
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	descq_cnt = sdma_get_descq_cnt();
13988c2ecf20Sopenharmony_ci	dd_dev_info(dd, "SDMA engines %zu descq_cnt %u\n",
13998c2ecf20Sopenharmony_ci		    num_engines, descq_cnt);
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	/* alloc memory for array of send engines */
14028c2ecf20Sopenharmony_ci	dd->per_sdma = kcalloc_node(num_engines, sizeof(*dd->per_sdma),
14038c2ecf20Sopenharmony_ci				    GFP_KERNEL, dd->node);
14048c2ecf20Sopenharmony_ci	if (!dd->per_sdma)
14058c2ecf20Sopenharmony_ci		return ret;
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	idle_cnt = ns_to_cclock(dd, idle_cnt);
14088c2ecf20Sopenharmony_ci	if (idle_cnt)
14098c2ecf20Sopenharmony_ci		dd->default_desc1 =
14108c2ecf20Sopenharmony_ci			SDMA_DESC1_HEAD_TO_HOST_FLAG;
14118c2ecf20Sopenharmony_ci	else
14128c2ecf20Sopenharmony_ci		dd->default_desc1 =
14138c2ecf20Sopenharmony_ci			SDMA_DESC1_INT_REQ_FLAG;
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	if (!sdma_desct_intr)
14168c2ecf20Sopenharmony_ci		sdma_desct_intr = SDMA_DESC_INTR;
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	/* Allocate memory for SendDMA descriptor FIFOs */
14198c2ecf20Sopenharmony_ci	for (this_idx = 0; this_idx < num_engines; ++this_idx) {
14208c2ecf20Sopenharmony_ci		sde = &dd->per_sdma[this_idx];
14218c2ecf20Sopenharmony_ci		sde->dd = dd;
14228c2ecf20Sopenharmony_ci		sde->ppd = ppd;
14238c2ecf20Sopenharmony_ci		sde->this_idx = this_idx;
14248c2ecf20Sopenharmony_ci		sde->descq_cnt = descq_cnt;
14258c2ecf20Sopenharmony_ci		sde->desc_avail = sdma_descq_freecnt(sde);
14268c2ecf20Sopenharmony_ci		sde->sdma_shift = ilog2(descq_cnt);
14278c2ecf20Sopenharmony_ci		sde->sdma_mask = (1 << sde->sdma_shift) - 1;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci		/* Create a mask specifically for each interrupt source */
14308c2ecf20Sopenharmony_ci		sde->int_mask = (u64)1 << (0 * TXE_NUM_SDMA_ENGINES +
14318c2ecf20Sopenharmony_ci					   this_idx);
14328c2ecf20Sopenharmony_ci		sde->progress_mask = (u64)1 << (1 * TXE_NUM_SDMA_ENGINES +
14338c2ecf20Sopenharmony_ci						this_idx);
14348c2ecf20Sopenharmony_ci		sde->idle_mask = (u64)1 << (2 * TXE_NUM_SDMA_ENGINES +
14358c2ecf20Sopenharmony_ci					    this_idx);
14368c2ecf20Sopenharmony_ci		/* Create a combined mask to cover all 3 interrupt sources */
14378c2ecf20Sopenharmony_ci		sde->imask = sde->int_mask | sde->progress_mask |
14388c2ecf20Sopenharmony_ci			     sde->idle_mask;
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci		spin_lock_init(&sde->tail_lock);
14418c2ecf20Sopenharmony_ci		seqlock_init(&sde->head_lock);
14428c2ecf20Sopenharmony_ci		spin_lock_init(&sde->senddmactrl_lock);
14438c2ecf20Sopenharmony_ci		spin_lock_init(&sde->flushlist_lock);
14448c2ecf20Sopenharmony_ci		seqlock_init(&sde->waitlock);
14458c2ecf20Sopenharmony_ci		/* insure there is always a zero bit */
14468c2ecf20Sopenharmony_ci		sde->ahg_bits = 0xfffffffe00000000ULL;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci		sdma_set_state(sde, sdma_state_s00_hw_down);
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci		/* set up reference counting */
14518c2ecf20Sopenharmony_ci		kref_init(&sde->state.kref);
14528c2ecf20Sopenharmony_ci		init_completion(&sde->state.comp);
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&sde->flushlist);
14558c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&sde->dmawait);
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci		sde->tail_csr =
14588c2ecf20Sopenharmony_ci			get_kctxt_csr_addr(dd, this_idx, SD(TAIL));
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci		tasklet_setup(&sde->sdma_hw_clean_up_task,
14618c2ecf20Sopenharmony_ci			      sdma_hw_clean_up_task);
14628c2ecf20Sopenharmony_ci		tasklet_setup(&sde->sdma_sw_clean_up_task,
14638c2ecf20Sopenharmony_ci			      sdma_sw_clean_up_task);
14648c2ecf20Sopenharmony_ci		INIT_WORK(&sde->err_halt_worker, sdma_err_halt_wait);
14658c2ecf20Sopenharmony_ci		INIT_WORK(&sde->flush_worker, sdma_field_flush);
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci		sde->progress_check_head = 0;
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci		timer_setup(&sde->err_progress_check_timer,
14708c2ecf20Sopenharmony_ci			    sdma_err_progress_check, 0);
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci		sde->descq = dma_alloc_coherent(&dd->pcidev->dev,
14738c2ecf20Sopenharmony_ci						descq_cnt * sizeof(u64[2]),
14748c2ecf20Sopenharmony_ci						&sde->descq_phys, GFP_KERNEL);
14758c2ecf20Sopenharmony_ci		if (!sde->descq)
14768c2ecf20Sopenharmony_ci			goto bail;
14778c2ecf20Sopenharmony_ci		sde->tx_ring =
14788c2ecf20Sopenharmony_ci			kvzalloc_node(array_size(descq_cnt,
14798c2ecf20Sopenharmony_ci						 sizeof(struct sdma_txreq *)),
14808c2ecf20Sopenharmony_ci				      GFP_KERNEL, dd->node);
14818c2ecf20Sopenharmony_ci		if (!sde->tx_ring)
14828c2ecf20Sopenharmony_ci			goto bail;
14838c2ecf20Sopenharmony_ci	}
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci	dd->sdma_heads_size = L1_CACHE_BYTES * num_engines;
14868c2ecf20Sopenharmony_ci	/* Allocate memory for DMA of head registers to memory */
14878c2ecf20Sopenharmony_ci	dd->sdma_heads_dma = dma_alloc_coherent(&dd->pcidev->dev,
14888c2ecf20Sopenharmony_ci						dd->sdma_heads_size,
14898c2ecf20Sopenharmony_ci						&dd->sdma_heads_phys,
14908c2ecf20Sopenharmony_ci						GFP_KERNEL);
14918c2ecf20Sopenharmony_ci	if (!dd->sdma_heads_dma) {
14928c2ecf20Sopenharmony_ci		dd_dev_err(dd, "failed to allocate SendDMA head memory\n");
14938c2ecf20Sopenharmony_ci		goto bail;
14948c2ecf20Sopenharmony_ci	}
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	/* Allocate memory for pad */
14978c2ecf20Sopenharmony_ci	dd->sdma_pad_dma = dma_alloc_coherent(&dd->pcidev->dev, SDMA_PAD,
14988c2ecf20Sopenharmony_ci					      &dd->sdma_pad_phys, GFP_KERNEL);
14998c2ecf20Sopenharmony_ci	if (!dd->sdma_pad_dma) {
15008c2ecf20Sopenharmony_ci		dd_dev_err(dd, "failed to allocate SendDMA pad memory\n");
15018c2ecf20Sopenharmony_ci		goto bail;
15028c2ecf20Sopenharmony_ci	}
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	/* assign each engine to different cacheline and init registers */
15058c2ecf20Sopenharmony_ci	curr_head = (void *)dd->sdma_heads_dma;
15068c2ecf20Sopenharmony_ci	for (this_idx = 0; this_idx < num_engines; ++this_idx) {
15078c2ecf20Sopenharmony_ci		unsigned long phys_offset;
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci		sde = &dd->per_sdma[this_idx];
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci		sde->head_dma = curr_head;
15128c2ecf20Sopenharmony_ci		curr_head += L1_CACHE_BYTES;
15138c2ecf20Sopenharmony_ci		phys_offset = (unsigned long)sde->head_dma -
15148c2ecf20Sopenharmony_ci			      (unsigned long)dd->sdma_heads_dma;
15158c2ecf20Sopenharmony_ci		sde->head_phys = dd->sdma_heads_phys + phys_offset;
15168c2ecf20Sopenharmony_ci		init_sdma_regs(sde, per_sdma_credits, idle_cnt);
15178c2ecf20Sopenharmony_ci	}
15188c2ecf20Sopenharmony_ci	dd->flags |= HFI1_HAS_SEND_DMA;
15198c2ecf20Sopenharmony_ci	dd->flags |= idle_cnt ? HFI1_HAS_SDMA_TIMEOUT : 0;
15208c2ecf20Sopenharmony_ci	dd->num_sdma = num_engines;
15218c2ecf20Sopenharmony_ci	ret = sdma_map_init(dd, port, ppd->vls_operational, NULL);
15228c2ecf20Sopenharmony_ci	if (ret < 0)
15238c2ecf20Sopenharmony_ci		goto bail;
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci	tmp_sdma_rht = kzalloc(sizeof(*tmp_sdma_rht), GFP_KERNEL);
15268c2ecf20Sopenharmony_ci	if (!tmp_sdma_rht) {
15278c2ecf20Sopenharmony_ci		ret = -ENOMEM;
15288c2ecf20Sopenharmony_ci		goto bail;
15298c2ecf20Sopenharmony_ci	}
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	ret = rhashtable_init(tmp_sdma_rht, &sdma_rht_params);
15328c2ecf20Sopenharmony_ci	if (ret < 0) {
15338c2ecf20Sopenharmony_ci		kfree(tmp_sdma_rht);
15348c2ecf20Sopenharmony_ci		goto bail;
15358c2ecf20Sopenharmony_ci	}
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	dd->sdma_rht = tmp_sdma_rht;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	dd_dev_info(dd, "SDMA num_sdma: %u\n", dd->num_sdma);
15408c2ecf20Sopenharmony_ci	return 0;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_cibail:
15438c2ecf20Sopenharmony_ci	sdma_clean(dd, num_engines);
15448c2ecf20Sopenharmony_ci	return ret;
15458c2ecf20Sopenharmony_ci}
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci/**
15488c2ecf20Sopenharmony_ci * sdma_all_running() - called when the link goes up
15498c2ecf20Sopenharmony_ci * @dd: hfi1_devdata
15508c2ecf20Sopenharmony_ci *
15518c2ecf20Sopenharmony_ci * This routine moves all engines to the running state.
15528c2ecf20Sopenharmony_ci */
15538c2ecf20Sopenharmony_civoid sdma_all_running(struct hfi1_devdata *dd)
15548c2ecf20Sopenharmony_ci{
15558c2ecf20Sopenharmony_ci	struct sdma_engine *sde;
15568c2ecf20Sopenharmony_ci	unsigned int i;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	/* move all engines to running */
15598c2ecf20Sopenharmony_ci	for (i = 0; i < dd->num_sdma; ++i) {
15608c2ecf20Sopenharmony_ci		sde = &dd->per_sdma[i];
15618c2ecf20Sopenharmony_ci		sdma_process_event(sde, sdma_event_e30_go_running);
15628c2ecf20Sopenharmony_ci	}
15638c2ecf20Sopenharmony_ci}
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci/**
15668c2ecf20Sopenharmony_ci * sdma_all_idle() - called when the link goes down
15678c2ecf20Sopenharmony_ci * @dd: hfi1_devdata
15688c2ecf20Sopenharmony_ci *
15698c2ecf20Sopenharmony_ci * This routine moves all engines to the idle state.
15708c2ecf20Sopenharmony_ci */
15718c2ecf20Sopenharmony_civoid sdma_all_idle(struct hfi1_devdata *dd)
15728c2ecf20Sopenharmony_ci{
15738c2ecf20Sopenharmony_ci	struct sdma_engine *sde;
15748c2ecf20Sopenharmony_ci	unsigned int i;
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	/* idle all engines */
15778c2ecf20Sopenharmony_ci	for (i = 0; i < dd->num_sdma; ++i) {
15788c2ecf20Sopenharmony_ci		sde = &dd->per_sdma[i];
15798c2ecf20Sopenharmony_ci		sdma_process_event(sde, sdma_event_e70_go_idle);
15808c2ecf20Sopenharmony_ci	}
15818c2ecf20Sopenharmony_ci}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci/**
15848c2ecf20Sopenharmony_ci * sdma_start() - called to kick off state processing for all engines
15858c2ecf20Sopenharmony_ci * @dd: hfi1_devdata
15868c2ecf20Sopenharmony_ci *
15878c2ecf20Sopenharmony_ci * This routine is for kicking off the state processing for all required
15888c2ecf20Sopenharmony_ci * sdma engines.  Interrupts need to be working at this point.
15898c2ecf20Sopenharmony_ci *
15908c2ecf20Sopenharmony_ci */
15918c2ecf20Sopenharmony_civoid sdma_start(struct hfi1_devdata *dd)
15928c2ecf20Sopenharmony_ci{
15938c2ecf20Sopenharmony_ci	unsigned i;
15948c2ecf20Sopenharmony_ci	struct sdma_engine *sde;
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci	/* kick off the engines state processing */
15978c2ecf20Sopenharmony_ci	for (i = 0; i < dd->num_sdma; ++i) {
15988c2ecf20Sopenharmony_ci		sde = &dd->per_sdma[i];
15998c2ecf20Sopenharmony_ci		sdma_process_event(sde, sdma_event_e10_go_hw_start);
16008c2ecf20Sopenharmony_ci	}
16018c2ecf20Sopenharmony_ci}
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci/**
16048c2ecf20Sopenharmony_ci * sdma_exit() - used when module is removed
16058c2ecf20Sopenharmony_ci * @dd: hfi1_devdata
16068c2ecf20Sopenharmony_ci */
16078c2ecf20Sopenharmony_civoid sdma_exit(struct hfi1_devdata *dd)
16088c2ecf20Sopenharmony_ci{
16098c2ecf20Sopenharmony_ci	unsigned this_idx;
16108c2ecf20Sopenharmony_ci	struct sdma_engine *sde;
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	for (this_idx = 0; dd->per_sdma && this_idx < dd->num_sdma;
16138c2ecf20Sopenharmony_ci			++this_idx) {
16148c2ecf20Sopenharmony_ci		sde = &dd->per_sdma[this_idx];
16158c2ecf20Sopenharmony_ci		if (!list_empty(&sde->dmawait))
16168c2ecf20Sopenharmony_ci			dd_dev_err(dd, "sde %u: dmawait list not empty!\n",
16178c2ecf20Sopenharmony_ci				   sde->this_idx);
16188c2ecf20Sopenharmony_ci		sdma_process_event(sde, sdma_event_e00_go_hw_down);
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci		del_timer_sync(&sde->err_progress_check_timer);
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci		/*
16238c2ecf20Sopenharmony_ci		 * This waits for the state machine to exit so it is not
16248c2ecf20Sopenharmony_ci		 * necessary to kill the sdma_sw_clean_up_task to make sure
16258c2ecf20Sopenharmony_ci		 * it is not running.
16268c2ecf20Sopenharmony_ci		 */
16278c2ecf20Sopenharmony_ci		sdma_finalput(&sde->state);
16288c2ecf20Sopenharmony_ci	}
16298c2ecf20Sopenharmony_ci}
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci/*
16328c2ecf20Sopenharmony_ci * unmap the indicated descriptor
16338c2ecf20Sopenharmony_ci */
16348c2ecf20Sopenharmony_cistatic inline void sdma_unmap_desc(
16358c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd,
16368c2ecf20Sopenharmony_ci	struct sdma_desc *descp)
16378c2ecf20Sopenharmony_ci{
16388c2ecf20Sopenharmony_ci	switch (sdma_mapping_type(descp)) {
16398c2ecf20Sopenharmony_ci	case SDMA_MAP_SINGLE:
16408c2ecf20Sopenharmony_ci		dma_unmap_single(&dd->pcidev->dev, sdma_mapping_addr(descp),
16418c2ecf20Sopenharmony_ci				 sdma_mapping_len(descp), DMA_TO_DEVICE);
16428c2ecf20Sopenharmony_ci		break;
16438c2ecf20Sopenharmony_ci	case SDMA_MAP_PAGE:
16448c2ecf20Sopenharmony_ci		dma_unmap_page(&dd->pcidev->dev, sdma_mapping_addr(descp),
16458c2ecf20Sopenharmony_ci			       sdma_mapping_len(descp), DMA_TO_DEVICE);
16468c2ecf20Sopenharmony_ci		break;
16478c2ecf20Sopenharmony_ci	}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	if (descp->pinning_ctx && descp->ctx_put)
16508c2ecf20Sopenharmony_ci		descp->ctx_put(descp->pinning_ctx);
16518c2ecf20Sopenharmony_ci	descp->pinning_ctx = NULL;
16528c2ecf20Sopenharmony_ci}
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci/*
16558c2ecf20Sopenharmony_ci * return the mode as indicated by the first
16568c2ecf20Sopenharmony_ci * descriptor in the tx.
16578c2ecf20Sopenharmony_ci */
16588c2ecf20Sopenharmony_cistatic inline u8 ahg_mode(struct sdma_txreq *tx)
16598c2ecf20Sopenharmony_ci{
16608c2ecf20Sopenharmony_ci	return (tx->descp[0].qw[1] & SDMA_DESC1_HEADER_MODE_SMASK)
16618c2ecf20Sopenharmony_ci		>> SDMA_DESC1_HEADER_MODE_SHIFT;
16628c2ecf20Sopenharmony_ci}
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci/**
16658c2ecf20Sopenharmony_ci * __sdma_txclean() - clean tx of mappings, descp *kmalloc's
16668c2ecf20Sopenharmony_ci * @dd: hfi1_devdata for unmapping
16678c2ecf20Sopenharmony_ci * @tx: tx request to clean
16688c2ecf20Sopenharmony_ci *
16698c2ecf20Sopenharmony_ci * This is used in the progress routine to clean the tx or
16708c2ecf20Sopenharmony_ci * by the ULP to toss an in-process tx build.
16718c2ecf20Sopenharmony_ci *
16728c2ecf20Sopenharmony_ci * The code can be called multiple times without issue.
16738c2ecf20Sopenharmony_ci *
16748c2ecf20Sopenharmony_ci */
16758c2ecf20Sopenharmony_civoid __sdma_txclean(
16768c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd,
16778c2ecf20Sopenharmony_ci	struct sdma_txreq *tx)
16788c2ecf20Sopenharmony_ci{
16798c2ecf20Sopenharmony_ci	u16 i;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	if (tx->num_desc) {
16828c2ecf20Sopenharmony_ci		u8 skip = 0, mode = ahg_mode(tx);
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_ci		/* unmap first */
16858c2ecf20Sopenharmony_ci		sdma_unmap_desc(dd, &tx->descp[0]);
16868c2ecf20Sopenharmony_ci		/* determine number of AHG descriptors to skip */
16878c2ecf20Sopenharmony_ci		if (mode > SDMA_AHG_APPLY_UPDATE1)
16888c2ecf20Sopenharmony_ci			skip = mode >> 1;
16898c2ecf20Sopenharmony_ci		for (i = 1 + skip; i < tx->num_desc; i++)
16908c2ecf20Sopenharmony_ci			sdma_unmap_desc(dd, &tx->descp[i]);
16918c2ecf20Sopenharmony_ci		tx->num_desc = 0;
16928c2ecf20Sopenharmony_ci	}
16938c2ecf20Sopenharmony_ci	kfree(tx->coalesce_buf);
16948c2ecf20Sopenharmony_ci	tx->coalesce_buf = NULL;
16958c2ecf20Sopenharmony_ci	/* kmalloc'ed descp */
16968c2ecf20Sopenharmony_ci	if (unlikely(tx->desc_limit > ARRAY_SIZE(tx->descs))) {
16978c2ecf20Sopenharmony_ci		tx->desc_limit = ARRAY_SIZE(tx->descs);
16988c2ecf20Sopenharmony_ci		kfree(tx->descp);
16998c2ecf20Sopenharmony_ci	}
17008c2ecf20Sopenharmony_ci}
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_cistatic inline u16 sdma_gethead(struct sdma_engine *sde)
17038c2ecf20Sopenharmony_ci{
17048c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd = sde->dd;
17058c2ecf20Sopenharmony_ci	int use_dmahead;
17068c2ecf20Sopenharmony_ci	u16 hwhead;
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci#ifdef CONFIG_SDMA_VERBOSITY
17098c2ecf20Sopenharmony_ci	dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n",
17108c2ecf20Sopenharmony_ci		   sde->this_idx, slashstrip(__FILE__), __LINE__, __func__);
17118c2ecf20Sopenharmony_ci#endif
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ciretry:
17148c2ecf20Sopenharmony_ci	use_dmahead = HFI1_CAP_IS_KSET(USE_SDMA_HEAD) && __sdma_running(sde) &&
17158c2ecf20Sopenharmony_ci					(dd->flags & HFI1_HAS_SDMA_TIMEOUT);
17168c2ecf20Sopenharmony_ci	hwhead = use_dmahead ?
17178c2ecf20Sopenharmony_ci		(u16)le64_to_cpu(*sde->head_dma) :
17188c2ecf20Sopenharmony_ci		(u16)read_sde_csr(sde, SD(HEAD));
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	if (unlikely(HFI1_CAP_IS_KSET(SDMA_HEAD_CHECK))) {
17218c2ecf20Sopenharmony_ci		u16 cnt;
17228c2ecf20Sopenharmony_ci		u16 swtail;
17238c2ecf20Sopenharmony_ci		u16 swhead;
17248c2ecf20Sopenharmony_ci		int sane;
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci		swhead = sde->descq_head & sde->sdma_mask;
17278c2ecf20Sopenharmony_ci		/* this code is really bad for cache line trading */
17288c2ecf20Sopenharmony_ci		swtail = READ_ONCE(sde->descq_tail) & sde->sdma_mask;
17298c2ecf20Sopenharmony_ci		cnt = sde->descq_cnt;
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci		if (swhead < swtail)
17328c2ecf20Sopenharmony_ci			/* not wrapped */
17338c2ecf20Sopenharmony_ci			sane = (hwhead >= swhead) & (hwhead <= swtail);
17348c2ecf20Sopenharmony_ci		else if (swhead > swtail)
17358c2ecf20Sopenharmony_ci			/* wrapped around */
17368c2ecf20Sopenharmony_ci			sane = ((hwhead >= swhead) && (hwhead < cnt)) ||
17378c2ecf20Sopenharmony_ci				(hwhead <= swtail);
17388c2ecf20Sopenharmony_ci		else
17398c2ecf20Sopenharmony_ci			/* empty */
17408c2ecf20Sopenharmony_ci			sane = (hwhead == swhead);
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci		if (unlikely(!sane)) {
17438c2ecf20Sopenharmony_ci			dd_dev_err(dd, "SDMA(%u) bad head (%s) hwhd=%hu swhd=%hu swtl=%hu cnt=%hu\n",
17448c2ecf20Sopenharmony_ci				   sde->this_idx,
17458c2ecf20Sopenharmony_ci				   use_dmahead ? "dma" : "kreg",
17468c2ecf20Sopenharmony_ci				   hwhead, swhead, swtail, cnt);
17478c2ecf20Sopenharmony_ci			if (use_dmahead) {
17488c2ecf20Sopenharmony_ci				/* try one more time, using csr */
17498c2ecf20Sopenharmony_ci				use_dmahead = 0;
17508c2ecf20Sopenharmony_ci				goto retry;
17518c2ecf20Sopenharmony_ci			}
17528c2ecf20Sopenharmony_ci			/* proceed as if no progress */
17538c2ecf20Sopenharmony_ci			hwhead = swhead;
17548c2ecf20Sopenharmony_ci		}
17558c2ecf20Sopenharmony_ci	}
17568c2ecf20Sopenharmony_ci	return hwhead;
17578c2ecf20Sopenharmony_ci}
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci/*
17608c2ecf20Sopenharmony_ci * This is called when there are send DMA descriptors that might be
17618c2ecf20Sopenharmony_ci * available.
17628c2ecf20Sopenharmony_ci *
17638c2ecf20Sopenharmony_ci * This is called with head_lock held.
17648c2ecf20Sopenharmony_ci */
17658c2ecf20Sopenharmony_cistatic void sdma_desc_avail(struct sdma_engine *sde, uint avail)
17668c2ecf20Sopenharmony_ci{
17678c2ecf20Sopenharmony_ci	struct iowait *wait, *nw, *twait;
17688c2ecf20Sopenharmony_ci	struct iowait *waits[SDMA_WAIT_BATCH_SIZE];
17698c2ecf20Sopenharmony_ci	uint i, n = 0, seq, tidx = 0;
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci#ifdef CONFIG_SDMA_VERBOSITY
17728c2ecf20Sopenharmony_ci	dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n", sde->this_idx,
17738c2ecf20Sopenharmony_ci		   slashstrip(__FILE__), __LINE__, __func__);
17748c2ecf20Sopenharmony_ci	dd_dev_err(sde->dd, "avail: %u\n", avail);
17758c2ecf20Sopenharmony_ci#endif
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	do {
17788c2ecf20Sopenharmony_ci		seq = read_seqbegin(&sde->waitlock);
17798c2ecf20Sopenharmony_ci		if (!list_empty(&sde->dmawait)) {
17808c2ecf20Sopenharmony_ci			/* at least one item */
17818c2ecf20Sopenharmony_ci			write_seqlock(&sde->waitlock);
17828c2ecf20Sopenharmony_ci			/* Harvest waiters wanting DMA descriptors */
17838c2ecf20Sopenharmony_ci			list_for_each_entry_safe(
17848c2ecf20Sopenharmony_ci					wait,
17858c2ecf20Sopenharmony_ci					nw,
17868c2ecf20Sopenharmony_ci					&sde->dmawait,
17878c2ecf20Sopenharmony_ci					list) {
17888c2ecf20Sopenharmony_ci				u32 num_desc;
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci				if (!wait->wakeup)
17918c2ecf20Sopenharmony_ci					continue;
17928c2ecf20Sopenharmony_ci				if (n == ARRAY_SIZE(waits))
17938c2ecf20Sopenharmony_ci					break;
17948c2ecf20Sopenharmony_ci				iowait_init_priority(wait);
17958c2ecf20Sopenharmony_ci				num_desc = iowait_get_all_desc(wait);
17968c2ecf20Sopenharmony_ci				if (num_desc > avail)
17978c2ecf20Sopenharmony_ci					break;
17988c2ecf20Sopenharmony_ci				avail -= num_desc;
17998c2ecf20Sopenharmony_ci				/* Find the top-priority wait memeber */
18008c2ecf20Sopenharmony_ci				if (n) {
18018c2ecf20Sopenharmony_ci					twait = waits[tidx];
18028c2ecf20Sopenharmony_ci					tidx =
18038c2ecf20Sopenharmony_ci					    iowait_priority_update_top(wait,
18048c2ecf20Sopenharmony_ci								       twait,
18058c2ecf20Sopenharmony_ci								       n,
18068c2ecf20Sopenharmony_ci								       tidx);
18078c2ecf20Sopenharmony_ci				}
18088c2ecf20Sopenharmony_ci				list_del_init(&wait->list);
18098c2ecf20Sopenharmony_ci				waits[n++] = wait;
18108c2ecf20Sopenharmony_ci			}
18118c2ecf20Sopenharmony_ci			write_sequnlock(&sde->waitlock);
18128c2ecf20Sopenharmony_ci			break;
18138c2ecf20Sopenharmony_ci		}
18148c2ecf20Sopenharmony_ci	} while (read_seqretry(&sde->waitlock, seq));
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci	/* Schedule the top-priority entry first */
18178c2ecf20Sopenharmony_ci	if (n)
18188c2ecf20Sopenharmony_ci		waits[tidx]->wakeup(waits[tidx], SDMA_AVAIL_REASON);
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++)
18218c2ecf20Sopenharmony_ci		if (i != tidx)
18228c2ecf20Sopenharmony_ci			waits[i]->wakeup(waits[i], SDMA_AVAIL_REASON);
18238c2ecf20Sopenharmony_ci}
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci/* head_lock must be held */
18268c2ecf20Sopenharmony_cistatic void sdma_make_progress(struct sdma_engine *sde, u64 status)
18278c2ecf20Sopenharmony_ci{
18288c2ecf20Sopenharmony_ci	struct sdma_txreq *txp = NULL;
18298c2ecf20Sopenharmony_ci	int progress = 0;
18308c2ecf20Sopenharmony_ci	u16 hwhead, swhead;
18318c2ecf20Sopenharmony_ci	int idle_check_done = 0;
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	hwhead = sdma_gethead(sde);
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	/* The reason for some of the complexity of this code is that
18368c2ecf20Sopenharmony_ci	 * not all descriptors have corresponding txps.  So, we have to
18378c2ecf20Sopenharmony_ci	 * be able to skip over descs until we wander into the range of
18388c2ecf20Sopenharmony_ci	 * the next txp on the list.
18398c2ecf20Sopenharmony_ci	 */
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ciretry:
18428c2ecf20Sopenharmony_ci	txp = get_txhead(sde);
18438c2ecf20Sopenharmony_ci	swhead = sde->descq_head & sde->sdma_mask;
18448c2ecf20Sopenharmony_ci	trace_hfi1_sdma_progress(sde, hwhead, swhead, txp);
18458c2ecf20Sopenharmony_ci	while (swhead != hwhead) {
18468c2ecf20Sopenharmony_ci		/* advance head, wrap if needed */
18478c2ecf20Sopenharmony_ci		swhead = ++sde->descq_head & sde->sdma_mask;
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci		/* if now past this txp's descs, do the callback */
18508c2ecf20Sopenharmony_ci		if (txp && txp->next_descq_idx == swhead) {
18518c2ecf20Sopenharmony_ci			/* remove from list */
18528c2ecf20Sopenharmony_ci			sde->tx_ring[sde->tx_head++ & sde->sdma_mask] = NULL;
18538c2ecf20Sopenharmony_ci			complete_tx(sde, txp, SDMA_TXREQ_S_OK);
18548c2ecf20Sopenharmony_ci			/* see if there is another txp */
18558c2ecf20Sopenharmony_ci			txp = get_txhead(sde);
18568c2ecf20Sopenharmony_ci		}
18578c2ecf20Sopenharmony_ci		trace_hfi1_sdma_progress(sde, hwhead, swhead, txp);
18588c2ecf20Sopenharmony_ci		progress++;
18598c2ecf20Sopenharmony_ci	}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	/*
18628c2ecf20Sopenharmony_ci	 * The SDMA idle interrupt is not guaranteed to be ordered with respect
18638c2ecf20Sopenharmony_ci	 * to updates to the the dma_head location in host memory. The head
18648c2ecf20Sopenharmony_ci	 * value read might not be fully up to date. If there are pending
18658c2ecf20Sopenharmony_ci	 * descriptors and the SDMA idle interrupt fired then read from the
18668c2ecf20Sopenharmony_ci	 * CSR SDMA head instead to get the latest value from the hardware.
18678c2ecf20Sopenharmony_ci	 * The hardware SDMA head should be read at most once in this invocation
18688c2ecf20Sopenharmony_ci	 * of sdma_make_progress(..) which is ensured by idle_check_done flag
18698c2ecf20Sopenharmony_ci	 */
18708c2ecf20Sopenharmony_ci	if ((status & sde->idle_mask) && !idle_check_done) {
18718c2ecf20Sopenharmony_ci		u16 swtail;
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci		swtail = READ_ONCE(sde->descq_tail) & sde->sdma_mask;
18748c2ecf20Sopenharmony_ci		if (swtail != hwhead) {
18758c2ecf20Sopenharmony_ci			hwhead = (u16)read_sde_csr(sde, SD(HEAD));
18768c2ecf20Sopenharmony_ci			idle_check_done = 1;
18778c2ecf20Sopenharmony_ci			goto retry;
18788c2ecf20Sopenharmony_ci		}
18798c2ecf20Sopenharmony_ci	}
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	sde->last_status = status;
18828c2ecf20Sopenharmony_ci	if (progress)
18838c2ecf20Sopenharmony_ci		sdma_desc_avail(sde, sdma_descq_freecnt(sde));
18848c2ecf20Sopenharmony_ci}
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci/*
18878c2ecf20Sopenharmony_ci * sdma_engine_interrupt() - interrupt handler for engine
18888c2ecf20Sopenharmony_ci * @sde: sdma engine
18898c2ecf20Sopenharmony_ci * @status: sdma interrupt reason
18908c2ecf20Sopenharmony_ci *
18918c2ecf20Sopenharmony_ci * Status is a mask of the 3 possible interrupts for this engine.  It will
18928c2ecf20Sopenharmony_ci * contain bits _only_ for this SDMA engine.  It will contain at least one
18938c2ecf20Sopenharmony_ci * bit, it may contain more.
18948c2ecf20Sopenharmony_ci */
18958c2ecf20Sopenharmony_civoid sdma_engine_interrupt(struct sdma_engine *sde, u64 status)
18968c2ecf20Sopenharmony_ci{
18978c2ecf20Sopenharmony_ci	trace_hfi1_sdma_engine_interrupt(sde, status);
18988c2ecf20Sopenharmony_ci	write_seqlock(&sde->head_lock);
18998c2ecf20Sopenharmony_ci	sdma_set_desc_cnt(sde, sdma_desct_intr);
19008c2ecf20Sopenharmony_ci	if (status & sde->idle_mask)
19018c2ecf20Sopenharmony_ci		sde->idle_int_cnt++;
19028c2ecf20Sopenharmony_ci	else if (status & sde->progress_mask)
19038c2ecf20Sopenharmony_ci		sde->progress_int_cnt++;
19048c2ecf20Sopenharmony_ci	else if (status & sde->int_mask)
19058c2ecf20Sopenharmony_ci		sde->sdma_int_cnt++;
19068c2ecf20Sopenharmony_ci	sdma_make_progress(sde, status);
19078c2ecf20Sopenharmony_ci	write_sequnlock(&sde->head_lock);
19088c2ecf20Sopenharmony_ci}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci/**
19118c2ecf20Sopenharmony_ci * sdma_engine_error() - error handler for engine
19128c2ecf20Sopenharmony_ci * @sde: sdma engine
19138c2ecf20Sopenharmony_ci * @status: sdma interrupt reason
19148c2ecf20Sopenharmony_ci */
19158c2ecf20Sopenharmony_civoid sdma_engine_error(struct sdma_engine *sde, u64 status)
19168c2ecf20Sopenharmony_ci{
19178c2ecf20Sopenharmony_ci	unsigned long flags;
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci#ifdef CONFIG_SDMA_VERBOSITY
19208c2ecf20Sopenharmony_ci	dd_dev_err(sde->dd, "CONFIG SDMA(%u) error status 0x%llx state %s\n",
19218c2ecf20Sopenharmony_ci		   sde->this_idx,
19228c2ecf20Sopenharmony_ci		   (unsigned long long)status,
19238c2ecf20Sopenharmony_ci		   sdma_state_names[sde->state.current_state]);
19248c2ecf20Sopenharmony_ci#endif
19258c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sde->tail_lock, flags);
19268c2ecf20Sopenharmony_ci	write_seqlock(&sde->head_lock);
19278c2ecf20Sopenharmony_ci	if (status & ALL_SDMA_ENG_HALT_ERRS)
19288c2ecf20Sopenharmony_ci		__sdma_process_event(sde, sdma_event_e60_hw_halted);
19298c2ecf20Sopenharmony_ci	if (status & ~SD(ENG_ERR_STATUS_SDMA_HALT_ERR_SMASK)) {
19308c2ecf20Sopenharmony_ci		dd_dev_err(sde->dd,
19318c2ecf20Sopenharmony_ci			   "SDMA (%u) engine error: 0x%llx state %s\n",
19328c2ecf20Sopenharmony_ci			   sde->this_idx,
19338c2ecf20Sopenharmony_ci			   (unsigned long long)status,
19348c2ecf20Sopenharmony_ci			   sdma_state_names[sde->state.current_state]);
19358c2ecf20Sopenharmony_ci		dump_sdma_state(sde);
19368c2ecf20Sopenharmony_ci	}
19378c2ecf20Sopenharmony_ci	write_sequnlock(&sde->head_lock);
19388c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sde->tail_lock, flags);
19398c2ecf20Sopenharmony_ci}
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_cistatic void sdma_sendctrl(struct sdma_engine *sde, unsigned op)
19428c2ecf20Sopenharmony_ci{
19438c2ecf20Sopenharmony_ci	u64 set_senddmactrl = 0;
19448c2ecf20Sopenharmony_ci	u64 clr_senddmactrl = 0;
19458c2ecf20Sopenharmony_ci	unsigned long flags;
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci#ifdef CONFIG_SDMA_VERBOSITY
19488c2ecf20Sopenharmony_ci	dd_dev_err(sde->dd, "CONFIG SDMA(%u) senddmactrl E=%d I=%d H=%d C=%d\n",
19498c2ecf20Sopenharmony_ci		   sde->this_idx,
19508c2ecf20Sopenharmony_ci		   (op & SDMA_SENDCTRL_OP_ENABLE) ? 1 : 0,
19518c2ecf20Sopenharmony_ci		   (op & SDMA_SENDCTRL_OP_INTENABLE) ? 1 : 0,
19528c2ecf20Sopenharmony_ci		   (op & SDMA_SENDCTRL_OP_HALT) ? 1 : 0,
19538c2ecf20Sopenharmony_ci		   (op & SDMA_SENDCTRL_OP_CLEANUP) ? 1 : 0);
19548c2ecf20Sopenharmony_ci#endif
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci	if (op & SDMA_SENDCTRL_OP_ENABLE)
19578c2ecf20Sopenharmony_ci		set_senddmactrl |= SD(CTRL_SDMA_ENABLE_SMASK);
19588c2ecf20Sopenharmony_ci	else
19598c2ecf20Sopenharmony_ci		clr_senddmactrl |= SD(CTRL_SDMA_ENABLE_SMASK);
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	if (op & SDMA_SENDCTRL_OP_INTENABLE)
19628c2ecf20Sopenharmony_ci		set_senddmactrl |= SD(CTRL_SDMA_INT_ENABLE_SMASK);
19638c2ecf20Sopenharmony_ci	else
19648c2ecf20Sopenharmony_ci		clr_senddmactrl |= SD(CTRL_SDMA_INT_ENABLE_SMASK);
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_ci	if (op & SDMA_SENDCTRL_OP_HALT)
19678c2ecf20Sopenharmony_ci		set_senddmactrl |= SD(CTRL_SDMA_HALT_SMASK);
19688c2ecf20Sopenharmony_ci	else
19698c2ecf20Sopenharmony_ci		clr_senddmactrl |= SD(CTRL_SDMA_HALT_SMASK);
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sde->senddmactrl_lock, flags);
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_ci	sde->p_senddmactrl |= set_senddmactrl;
19748c2ecf20Sopenharmony_ci	sde->p_senddmactrl &= ~clr_senddmactrl;
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci	if (op & SDMA_SENDCTRL_OP_CLEANUP)
19778c2ecf20Sopenharmony_ci		write_sde_csr(sde, SD(CTRL),
19788c2ecf20Sopenharmony_ci			      sde->p_senddmactrl |
19798c2ecf20Sopenharmony_ci			      SD(CTRL_SDMA_CLEANUP_SMASK));
19808c2ecf20Sopenharmony_ci	else
19818c2ecf20Sopenharmony_ci		write_sde_csr(sde, SD(CTRL), sde->p_senddmactrl);
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sde->senddmactrl_lock, flags);
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci#ifdef CONFIG_SDMA_VERBOSITY
19868c2ecf20Sopenharmony_ci	sdma_dumpstate(sde);
19878c2ecf20Sopenharmony_ci#endif
19888c2ecf20Sopenharmony_ci}
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_cistatic void sdma_setlengen(struct sdma_engine *sde)
19918c2ecf20Sopenharmony_ci{
19928c2ecf20Sopenharmony_ci#ifdef CONFIG_SDMA_VERBOSITY
19938c2ecf20Sopenharmony_ci	dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n",
19948c2ecf20Sopenharmony_ci		   sde->this_idx, slashstrip(__FILE__), __LINE__, __func__);
19958c2ecf20Sopenharmony_ci#endif
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_ci	/*
19988c2ecf20Sopenharmony_ci	 * Set SendDmaLenGen and clear-then-set the MSB of the generation
19998c2ecf20Sopenharmony_ci	 * count to enable generation checking and load the internal
20008c2ecf20Sopenharmony_ci	 * generation counter.
20018c2ecf20Sopenharmony_ci	 */
20028c2ecf20Sopenharmony_ci	write_sde_csr(sde, SD(LEN_GEN),
20038c2ecf20Sopenharmony_ci		      (sde->descq_cnt / 64) << SD(LEN_GEN_LENGTH_SHIFT));
20048c2ecf20Sopenharmony_ci	write_sde_csr(sde, SD(LEN_GEN),
20058c2ecf20Sopenharmony_ci		      ((sde->descq_cnt / 64) << SD(LEN_GEN_LENGTH_SHIFT)) |
20068c2ecf20Sopenharmony_ci		      (4ULL << SD(LEN_GEN_GENERATION_SHIFT)));
20078c2ecf20Sopenharmony_ci}
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_cistatic inline void sdma_update_tail(struct sdma_engine *sde, u16 tail)
20108c2ecf20Sopenharmony_ci{
20118c2ecf20Sopenharmony_ci	/* Commit writes to memory and advance the tail on the chip */
20128c2ecf20Sopenharmony_ci	smp_wmb(); /* see get_txhead() */
20138c2ecf20Sopenharmony_ci	writeq(tail, sde->tail_csr);
20148c2ecf20Sopenharmony_ci}
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci/*
20178c2ecf20Sopenharmony_ci * This is called when changing to state s10_hw_start_up_halt_wait as
20188c2ecf20Sopenharmony_ci * a result of send buffer errors or send DMA descriptor errors.
20198c2ecf20Sopenharmony_ci */
20208c2ecf20Sopenharmony_cistatic void sdma_hw_start_up(struct sdma_engine *sde)
20218c2ecf20Sopenharmony_ci{
20228c2ecf20Sopenharmony_ci	u64 reg;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci#ifdef CONFIG_SDMA_VERBOSITY
20258c2ecf20Sopenharmony_ci	dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n",
20268c2ecf20Sopenharmony_ci		   sde->this_idx, slashstrip(__FILE__), __LINE__, __func__);
20278c2ecf20Sopenharmony_ci#endif
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	sdma_setlengen(sde);
20308c2ecf20Sopenharmony_ci	sdma_update_tail(sde, 0); /* Set SendDmaTail */
20318c2ecf20Sopenharmony_ci	*sde->head_dma = 0;
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_ci	reg = SD(ENG_ERR_CLEAR_SDMA_HEADER_REQUEST_FIFO_UNC_ERR_MASK) <<
20348c2ecf20Sopenharmony_ci	      SD(ENG_ERR_CLEAR_SDMA_HEADER_REQUEST_FIFO_UNC_ERR_SHIFT);
20358c2ecf20Sopenharmony_ci	write_sde_csr(sde, SD(ENG_ERR_CLEAR), reg);
20368c2ecf20Sopenharmony_ci}
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci/*
20398c2ecf20Sopenharmony_ci * set_sdma_integrity
20408c2ecf20Sopenharmony_ci *
20418c2ecf20Sopenharmony_ci * Set the SEND_DMA_CHECK_ENABLE register for send DMA engine 'sde'.
20428c2ecf20Sopenharmony_ci */
20438c2ecf20Sopenharmony_cistatic void set_sdma_integrity(struct sdma_engine *sde)
20448c2ecf20Sopenharmony_ci{
20458c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd = sde->dd;
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci	write_sde_csr(sde, SD(CHECK_ENABLE),
20488c2ecf20Sopenharmony_ci		      hfi1_pkt_base_sdma_integrity(dd));
20498c2ecf20Sopenharmony_ci}
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_cistatic void init_sdma_regs(
20528c2ecf20Sopenharmony_ci	struct sdma_engine *sde,
20538c2ecf20Sopenharmony_ci	u32 credits,
20548c2ecf20Sopenharmony_ci	uint idle_cnt)
20558c2ecf20Sopenharmony_ci{
20568c2ecf20Sopenharmony_ci	u8 opval, opmask;
20578c2ecf20Sopenharmony_ci#ifdef CONFIG_SDMA_VERBOSITY
20588c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd = sde->dd;
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	dd_dev_err(dd, "CONFIG SDMA(%u) %s:%d %s()\n",
20618c2ecf20Sopenharmony_ci		   sde->this_idx, slashstrip(__FILE__), __LINE__, __func__);
20628c2ecf20Sopenharmony_ci#endif
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	write_sde_csr(sde, SD(BASE_ADDR), sde->descq_phys);
20658c2ecf20Sopenharmony_ci	sdma_setlengen(sde);
20668c2ecf20Sopenharmony_ci	sdma_update_tail(sde, 0); /* Set SendDmaTail */
20678c2ecf20Sopenharmony_ci	write_sde_csr(sde, SD(RELOAD_CNT), idle_cnt);
20688c2ecf20Sopenharmony_ci	write_sde_csr(sde, SD(DESC_CNT), 0);
20698c2ecf20Sopenharmony_ci	write_sde_csr(sde, SD(HEAD_ADDR), sde->head_phys);
20708c2ecf20Sopenharmony_ci	write_sde_csr(sde, SD(MEMORY),
20718c2ecf20Sopenharmony_ci		      ((u64)credits << SD(MEMORY_SDMA_MEMORY_CNT_SHIFT)) |
20728c2ecf20Sopenharmony_ci		      ((u64)(credits * sde->this_idx) <<
20738c2ecf20Sopenharmony_ci		       SD(MEMORY_SDMA_MEMORY_INDEX_SHIFT)));
20748c2ecf20Sopenharmony_ci	write_sde_csr(sde, SD(ENG_ERR_MASK), ~0ull);
20758c2ecf20Sopenharmony_ci	set_sdma_integrity(sde);
20768c2ecf20Sopenharmony_ci	opmask = OPCODE_CHECK_MASK_DISABLED;
20778c2ecf20Sopenharmony_ci	opval = OPCODE_CHECK_VAL_DISABLED;
20788c2ecf20Sopenharmony_ci	write_sde_csr(sde, SD(CHECK_OPCODE),
20798c2ecf20Sopenharmony_ci		      (opmask << SEND_CTXT_CHECK_OPCODE_MASK_SHIFT) |
20808c2ecf20Sopenharmony_ci		      (opval << SEND_CTXT_CHECK_OPCODE_VALUE_SHIFT));
20818c2ecf20Sopenharmony_ci}
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci#ifdef CONFIG_SDMA_VERBOSITY
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci#define sdma_dumpstate_helper0(reg) do { \
20868c2ecf20Sopenharmony_ci		csr = read_csr(sde->dd, reg); \
20878c2ecf20Sopenharmony_ci		dd_dev_err(sde->dd, "%36s     0x%016llx\n", #reg, csr); \
20888c2ecf20Sopenharmony_ci	} while (0)
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci#define sdma_dumpstate_helper(reg) do { \
20918c2ecf20Sopenharmony_ci		csr = read_sde_csr(sde, reg); \
20928c2ecf20Sopenharmony_ci		dd_dev_err(sde->dd, "%36s[%02u] 0x%016llx\n", \
20938c2ecf20Sopenharmony_ci			#reg, sde->this_idx, csr); \
20948c2ecf20Sopenharmony_ci	} while (0)
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci#define sdma_dumpstate_helper2(reg) do { \
20978c2ecf20Sopenharmony_ci		csr = read_csr(sde->dd, reg + (8 * i)); \
20988c2ecf20Sopenharmony_ci		dd_dev_err(sde->dd, "%33s_%02u     0x%016llx\n", \
20998c2ecf20Sopenharmony_ci				#reg, i, csr); \
21008c2ecf20Sopenharmony_ci	} while (0)
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_civoid sdma_dumpstate(struct sdma_engine *sde)
21038c2ecf20Sopenharmony_ci{
21048c2ecf20Sopenharmony_ci	u64 csr;
21058c2ecf20Sopenharmony_ci	unsigned i;
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(CTRL));
21088c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(STATUS));
21098c2ecf20Sopenharmony_ci	sdma_dumpstate_helper0(SD(ERR_STATUS));
21108c2ecf20Sopenharmony_ci	sdma_dumpstate_helper0(SD(ERR_MASK));
21118c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(ENG_ERR_STATUS));
21128c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(ENG_ERR_MASK));
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	for (i = 0; i < CCE_NUM_INT_CSRS; ++i) {
21158c2ecf20Sopenharmony_ci		sdma_dumpstate_helper2(CCE_INT_STATUS);
21168c2ecf20Sopenharmony_ci		sdma_dumpstate_helper2(CCE_INT_MASK);
21178c2ecf20Sopenharmony_ci		sdma_dumpstate_helper2(CCE_INT_BLOCKED);
21188c2ecf20Sopenharmony_ci	}
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(TAIL));
21218c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(HEAD));
21228c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(PRIORITY_THLD));
21238c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(IDLE_CNT));
21248c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(RELOAD_CNT));
21258c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(DESC_CNT));
21268c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(DESC_FETCHED_CNT));
21278c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(MEMORY));
21288c2ecf20Sopenharmony_ci	sdma_dumpstate_helper0(SD(ENGINES));
21298c2ecf20Sopenharmony_ci	sdma_dumpstate_helper0(SD(MEM_SIZE));
21308c2ecf20Sopenharmony_ci	/* sdma_dumpstate_helper(SEND_EGRESS_SEND_DMA_STATUS);  */
21318c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(BASE_ADDR));
21328c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(LEN_GEN));
21338c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(HEAD_ADDR));
21348c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(CHECK_ENABLE));
21358c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(CHECK_VL));
21368c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(CHECK_JOB_KEY));
21378c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(CHECK_PARTITION_KEY));
21388c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(CHECK_SLID));
21398c2ecf20Sopenharmony_ci	sdma_dumpstate_helper(SD(CHECK_OPCODE));
21408c2ecf20Sopenharmony_ci}
21418c2ecf20Sopenharmony_ci#endif
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_cistatic void dump_sdma_state(struct sdma_engine *sde)
21448c2ecf20Sopenharmony_ci{
21458c2ecf20Sopenharmony_ci	struct hw_sdma_desc *descqp;
21468c2ecf20Sopenharmony_ci	u64 desc[2];
21478c2ecf20Sopenharmony_ci	u64 addr;
21488c2ecf20Sopenharmony_ci	u8 gen;
21498c2ecf20Sopenharmony_ci	u16 len;
21508c2ecf20Sopenharmony_ci	u16 head, tail, cnt;
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci	head = sde->descq_head & sde->sdma_mask;
21538c2ecf20Sopenharmony_ci	tail = sde->descq_tail & sde->sdma_mask;
21548c2ecf20Sopenharmony_ci	cnt = sdma_descq_freecnt(sde);
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci	dd_dev_err(sde->dd,
21578c2ecf20Sopenharmony_ci		   "SDMA (%u) descq_head: %u descq_tail: %u freecnt: %u FLE %d\n",
21588c2ecf20Sopenharmony_ci		   sde->this_idx, head, tail, cnt,
21598c2ecf20Sopenharmony_ci		   !list_empty(&sde->flushlist));
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci	/* print info for each entry in the descriptor queue */
21628c2ecf20Sopenharmony_ci	while (head != tail) {
21638c2ecf20Sopenharmony_ci		char flags[6] = { 'x', 'x', 'x', 'x', 0 };
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_ci		descqp = &sde->descq[head];
21668c2ecf20Sopenharmony_ci		desc[0] = le64_to_cpu(descqp->qw[0]);
21678c2ecf20Sopenharmony_ci		desc[1] = le64_to_cpu(descqp->qw[1]);
21688c2ecf20Sopenharmony_ci		flags[0] = (desc[1] & SDMA_DESC1_INT_REQ_FLAG) ? 'I' : '-';
21698c2ecf20Sopenharmony_ci		flags[1] = (desc[1] & SDMA_DESC1_HEAD_TO_HOST_FLAG) ?
21708c2ecf20Sopenharmony_ci				'H' : '-';
21718c2ecf20Sopenharmony_ci		flags[2] = (desc[0] & SDMA_DESC0_FIRST_DESC_FLAG) ? 'F' : '-';
21728c2ecf20Sopenharmony_ci		flags[3] = (desc[0] & SDMA_DESC0_LAST_DESC_FLAG) ? 'L' : '-';
21738c2ecf20Sopenharmony_ci		addr = (desc[0] >> SDMA_DESC0_PHY_ADDR_SHIFT)
21748c2ecf20Sopenharmony_ci			& SDMA_DESC0_PHY_ADDR_MASK;
21758c2ecf20Sopenharmony_ci		gen = (desc[1] >> SDMA_DESC1_GENERATION_SHIFT)
21768c2ecf20Sopenharmony_ci			& SDMA_DESC1_GENERATION_MASK;
21778c2ecf20Sopenharmony_ci		len = (desc[0] >> SDMA_DESC0_BYTE_COUNT_SHIFT)
21788c2ecf20Sopenharmony_ci			& SDMA_DESC0_BYTE_COUNT_MASK;
21798c2ecf20Sopenharmony_ci		dd_dev_err(sde->dd,
21808c2ecf20Sopenharmony_ci			   "SDMA sdmadesc[%u]: flags:%s addr:0x%016llx gen:%u len:%u bytes\n",
21818c2ecf20Sopenharmony_ci			   head, flags, addr, gen, len);
21828c2ecf20Sopenharmony_ci		dd_dev_err(sde->dd,
21838c2ecf20Sopenharmony_ci			   "\tdesc0:0x%016llx desc1 0x%016llx\n",
21848c2ecf20Sopenharmony_ci			   desc[0], desc[1]);
21858c2ecf20Sopenharmony_ci		if (desc[0] & SDMA_DESC0_FIRST_DESC_FLAG)
21868c2ecf20Sopenharmony_ci			dd_dev_err(sde->dd,
21878c2ecf20Sopenharmony_ci				   "\taidx: %u amode: %u alen: %u\n",
21888c2ecf20Sopenharmony_ci				   (u8)((desc[1] &
21898c2ecf20Sopenharmony_ci					 SDMA_DESC1_HEADER_INDEX_SMASK) >>
21908c2ecf20Sopenharmony_ci					SDMA_DESC1_HEADER_INDEX_SHIFT),
21918c2ecf20Sopenharmony_ci				   (u8)((desc[1] &
21928c2ecf20Sopenharmony_ci					 SDMA_DESC1_HEADER_MODE_SMASK) >>
21938c2ecf20Sopenharmony_ci					SDMA_DESC1_HEADER_MODE_SHIFT),
21948c2ecf20Sopenharmony_ci				   (u8)((desc[1] &
21958c2ecf20Sopenharmony_ci					 SDMA_DESC1_HEADER_DWS_SMASK) >>
21968c2ecf20Sopenharmony_ci					SDMA_DESC1_HEADER_DWS_SHIFT));
21978c2ecf20Sopenharmony_ci		head++;
21988c2ecf20Sopenharmony_ci		head &= sde->sdma_mask;
21998c2ecf20Sopenharmony_ci	}
22008c2ecf20Sopenharmony_ci}
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci#define SDE_FMT \
22038c2ecf20Sopenharmony_ci	"SDE %u CPU %d STE %s C 0x%llx S 0x%016llx E 0x%llx T(HW) 0x%llx T(SW) 0x%x H(HW) 0x%llx H(SW) 0x%x H(D) 0x%llx DM 0x%llx GL 0x%llx R 0x%llx LIS 0x%llx AHGI 0x%llx TXT %u TXH %u DT %u DH %u FLNE %d DQF %u SLC 0x%llx\n"
22048c2ecf20Sopenharmony_ci/**
22058c2ecf20Sopenharmony_ci * sdma_seqfile_dump_sde() - debugfs dump of sde
22068c2ecf20Sopenharmony_ci * @s: seq file
22078c2ecf20Sopenharmony_ci * @sde: send dma engine to dump
22088c2ecf20Sopenharmony_ci *
22098c2ecf20Sopenharmony_ci * This routine dumps the sde to the indicated seq file.
22108c2ecf20Sopenharmony_ci */
22118c2ecf20Sopenharmony_civoid sdma_seqfile_dump_sde(struct seq_file *s, struct sdma_engine *sde)
22128c2ecf20Sopenharmony_ci{
22138c2ecf20Sopenharmony_ci	u16 head, tail;
22148c2ecf20Sopenharmony_ci	struct hw_sdma_desc *descqp;
22158c2ecf20Sopenharmony_ci	u64 desc[2];
22168c2ecf20Sopenharmony_ci	u64 addr;
22178c2ecf20Sopenharmony_ci	u8 gen;
22188c2ecf20Sopenharmony_ci	u16 len;
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci	head = sde->descq_head & sde->sdma_mask;
22218c2ecf20Sopenharmony_ci	tail = READ_ONCE(sde->descq_tail) & sde->sdma_mask;
22228c2ecf20Sopenharmony_ci	seq_printf(s, SDE_FMT, sde->this_idx,
22238c2ecf20Sopenharmony_ci		   sde->cpu,
22248c2ecf20Sopenharmony_ci		   sdma_state_name(sde->state.current_state),
22258c2ecf20Sopenharmony_ci		   (unsigned long long)read_sde_csr(sde, SD(CTRL)),
22268c2ecf20Sopenharmony_ci		   (unsigned long long)read_sde_csr(sde, SD(STATUS)),
22278c2ecf20Sopenharmony_ci		   (unsigned long long)read_sde_csr(sde, SD(ENG_ERR_STATUS)),
22288c2ecf20Sopenharmony_ci		   (unsigned long long)read_sde_csr(sde, SD(TAIL)), tail,
22298c2ecf20Sopenharmony_ci		   (unsigned long long)read_sde_csr(sde, SD(HEAD)), head,
22308c2ecf20Sopenharmony_ci		   (unsigned long long)le64_to_cpu(*sde->head_dma),
22318c2ecf20Sopenharmony_ci		   (unsigned long long)read_sde_csr(sde, SD(MEMORY)),
22328c2ecf20Sopenharmony_ci		   (unsigned long long)read_sde_csr(sde, SD(LEN_GEN)),
22338c2ecf20Sopenharmony_ci		   (unsigned long long)read_sde_csr(sde, SD(RELOAD_CNT)),
22348c2ecf20Sopenharmony_ci		   (unsigned long long)sde->last_status,
22358c2ecf20Sopenharmony_ci		   (unsigned long long)sde->ahg_bits,
22368c2ecf20Sopenharmony_ci		   sde->tx_tail,
22378c2ecf20Sopenharmony_ci		   sde->tx_head,
22388c2ecf20Sopenharmony_ci		   sde->descq_tail,
22398c2ecf20Sopenharmony_ci		   sde->descq_head,
22408c2ecf20Sopenharmony_ci		   !list_empty(&sde->flushlist),
22418c2ecf20Sopenharmony_ci		   sde->descq_full_count,
22428c2ecf20Sopenharmony_ci		   (unsigned long long)read_sde_csr(sde, SEND_DMA_CHECK_SLID));
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	/* print info for each entry in the descriptor queue */
22458c2ecf20Sopenharmony_ci	while (head != tail) {
22468c2ecf20Sopenharmony_ci		char flags[6] = { 'x', 'x', 'x', 'x', 0 };
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci		descqp = &sde->descq[head];
22498c2ecf20Sopenharmony_ci		desc[0] = le64_to_cpu(descqp->qw[0]);
22508c2ecf20Sopenharmony_ci		desc[1] = le64_to_cpu(descqp->qw[1]);
22518c2ecf20Sopenharmony_ci		flags[0] = (desc[1] & SDMA_DESC1_INT_REQ_FLAG) ? 'I' : '-';
22528c2ecf20Sopenharmony_ci		flags[1] = (desc[1] & SDMA_DESC1_HEAD_TO_HOST_FLAG) ?
22538c2ecf20Sopenharmony_ci				'H' : '-';
22548c2ecf20Sopenharmony_ci		flags[2] = (desc[0] & SDMA_DESC0_FIRST_DESC_FLAG) ? 'F' : '-';
22558c2ecf20Sopenharmony_ci		flags[3] = (desc[0] & SDMA_DESC0_LAST_DESC_FLAG) ? 'L' : '-';
22568c2ecf20Sopenharmony_ci		addr = (desc[0] >> SDMA_DESC0_PHY_ADDR_SHIFT)
22578c2ecf20Sopenharmony_ci			& SDMA_DESC0_PHY_ADDR_MASK;
22588c2ecf20Sopenharmony_ci		gen = (desc[1] >> SDMA_DESC1_GENERATION_SHIFT)
22598c2ecf20Sopenharmony_ci			& SDMA_DESC1_GENERATION_MASK;
22608c2ecf20Sopenharmony_ci		len = (desc[0] >> SDMA_DESC0_BYTE_COUNT_SHIFT)
22618c2ecf20Sopenharmony_ci			& SDMA_DESC0_BYTE_COUNT_MASK;
22628c2ecf20Sopenharmony_ci		seq_printf(s,
22638c2ecf20Sopenharmony_ci			   "\tdesc[%u]: flags:%s addr:0x%016llx gen:%u len:%u bytes\n",
22648c2ecf20Sopenharmony_ci			   head, flags, addr, gen, len);
22658c2ecf20Sopenharmony_ci		if (desc[0] & SDMA_DESC0_FIRST_DESC_FLAG)
22668c2ecf20Sopenharmony_ci			seq_printf(s, "\t\tahgidx: %u ahgmode: %u\n",
22678c2ecf20Sopenharmony_ci				   (u8)((desc[1] &
22688c2ecf20Sopenharmony_ci					 SDMA_DESC1_HEADER_INDEX_SMASK) >>
22698c2ecf20Sopenharmony_ci					SDMA_DESC1_HEADER_INDEX_SHIFT),
22708c2ecf20Sopenharmony_ci				   (u8)((desc[1] &
22718c2ecf20Sopenharmony_ci					 SDMA_DESC1_HEADER_MODE_SMASK) >>
22728c2ecf20Sopenharmony_ci					SDMA_DESC1_HEADER_MODE_SHIFT));
22738c2ecf20Sopenharmony_ci		head = (head + 1) & sde->sdma_mask;
22748c2ecf20Sopenharmony_ci	}
22758c2ecf20Sopenharmony_ci}
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci/*
22788c2ecf20Sopenharmony_ci * add the generation number into
22798c2ecf20Sopenharmony_ci * the qw1 and return
22808c2ecf20Sopenharmony_ci */
22818c2ecf20Sopenharmony_cistatic inline u64 add_gen(struct sdma_engine *sde, u64 qw1)
22828c2ecf20Sopenharmony_ci{
22838c2ecf20Sopenharmony_ci	u8 generation = (sde->descq_tail >> sde->sdma_shift) & 3;
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci	qw1 &= ~SDMA_DESC1_GENERATION_SMASK;
22868c2ecf20Sopenharmony_ci	qw1 |= ((u64)generation & SDMA_DESC1_GENERATION_MASK)
22878c2ecf20Sopenharmony_ci			<< SDMA_DESC1_GENERATION_SHIFT;
22888c2ecf20Sopenharmony_ci	return qw1;
22898c2ecf20Sopenharmony_ci}
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_ci/*
22928c2ecf20Sopenharmony_ci * This routine submits the indicated tx
22938c2ecf20Sopenharmony_ci *
22948c2ecf20Sopenharmony_ci * Space has already been guaranteed and
22958c2ecf20Sopenharmony_ci * tail side of ring is locked.
22968c2ecf20Sopenharmony_ci *
22978c2ecf20Sopenharmony_ci * The hardware tail update is done
22988c2ecf20Sopenharmony_ci * in the caller and that is facilitated
22998c2ecf20Sopenharmony_ci * by returning the new tail.
23008c2ecf20Sopenharmony_ci *
23018c2ecf20Sopenharmony_ci * There is special case logic for ahg
23028c2ecf20Sopenharmony_ci * to not add the generation number for
23038c2ecf20Sopenharmony_ci * up to 2 descriptors that follow the
23048c2ecf20Sopenharmony_ci * first descriptor.
23058c2ecf20Sopenharmony_ci *
23068c2ecf20Sopenharmony_ci */
23078c2ecf20Sopenharmony_cistatic inline u16 submit_tx(struct sdma_engine *sde, struct sdma_txreq *tx)
23088c2ecf20Sopenharmony_ci{
23098c2ecf20Sopenharmony_ci	int i;
23108c2ecf20Sopenharmony_ci	u16 tail;
23118c2ecf20Sopenharmony_ci	struct sdma_desc *descp = tx->descp;
23128c2ecf20Sopenharmony_ci	u8 skip = 0, mode = ahg_mode(tx);
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci	tail = sde->descq_tail & sde->sdma_mask;
23158c2ecf20Sopenharmony_ci	sde->descq[tail].qw[0] = cpu_to_le64(descp->qw[0]);
23168c2ecf20Sopenharmony_ci	sde->descq[tail].qw[1] = cpu_to_le64(add_gen(sde, descp->qw[1]));
23178c2ecf20Sopenharmony_ci	trace_hfi1_sdma_descriptor(sde, descp->qw[0], descp->qw[1],
23188c2ecf20Sopenharmony_ci				   tail, &sde->descq[tail]);
23198c2ecf20Sopenharmony_ci	tail = ++sde->descq_tail & sde->sdma_mask;
23208c2ecf20Sopenharmony_ci	descp++;
23218c2ecf20Sopenharmony_ci	if (mode > SDMA_AHG_APPLY_UPDATE1)
23228c2ecf20Sopenharmony_ci		skip = mode >> 1;
23238c2ecf20Sopenharmony_ci	for (i = 1; i < tx->num_desc; i++, descp++) {
23248c2ecf20Sopenharmony_ci		u64 qw1;
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci		sde->descq[tail].qw[0] = cpu_to_le64(descp->qw[0]);
23278c2ecf20Sopenharmony_ci		if (skip) {
23288c2ecf20Sopenharmony_ci			/* edits don't have generation */
23298c2ecf20Sopenharmony_ci			qw1 = descp->qw[1];
23308c2ecf20Sopenharmony_ci			skip--;
23318c2ecf20Sopenharmony_ci		} else {
23328c2ecf20Sopenharmony_ci			/* replace generation with real one for non-edits */
23338c2ecf20Sopenharmony_ci			qw1 = add_gen(sde, descp->qw[1]);
23348c2ecf20Sopenharmony_ci		}
23358c2ecf20Sopenharmony_ci		sde->descq[tail].qw[1] = cpu_to_le64(qw1);
23368c2ecf20Sopenharmony_ci		trace_hfi1_sdma_descriptor(sde, descp->qw[0], qw1,
23378c2ecf20Sopenharmony_ci					   tail, &sde->descq[tail]);
23388c2ecf20Sopenharmony_ci		tail = ++sde->descq_tail & sde->sdma_mask;
23398c2ecf20Sopenharmony_ci	}
23408c2ecf20Sopenharmony_ci	tx->next_descq_idx = tail;
23418c2ecf20Sopenharmony_ci#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER
23428c2ecf20Sopenharmony_ci	tx->sn = sde->tail_sn++;
23438c2ecf20Sopenharmony_ci	trace_hfi1_sdma_in_sn(sde, tx->sn);
23448c2ecf20Sopenharmony_ci	WARN_ON_ONCE(sde->tx_ring[sde->tx_tail & sde->sdma_mask]);
23458c2ecf20Sopenharmony_ci#endif
23468c2ecf20Sopenharmony_ci	sde->tx_ring[sde->tx_tail++ & sde->sdma_mask] = tx;
23478c2ecf20Sopenharmony_ci	sde->desc_avail -= tx->num_desc;
23488c2ecf20Sopenharmony_ci	return tail;
23498c2ecf20Sopenharmony_ci}
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_ci/*
23528c2ecf20Sopenharmony_ci * Check for progress
23538c2ecf20Sopenharmony_ci */
23548c2ecf20Sopenharmony_cistatic int sdma_check_progress(
23558c2ecf20Sopenharmony_ci	struct sdma_engine *sde,
23568c2ecf20Sopenharmony_ci	struct iowait_work *wait,
23578c2ecf20Sopenharmony_ci	struct sdma_txreq *tx,
23588c2ecf20Sopenharmony_ci	bool pkts_sent)
23598c2ecf20Sopenharmony_ci{
23608c2ecf20Sopenharmony_ci	int ret;
23618c2ecf20Sopenharmony_ci
23628c2ecf20Sopenharmony_ci	sde->desc_avail = sdma_descq_freecnt(sde);
23638c2ecf20Sopenharmony_ci	if (tx->num_desc <= sde->desc_avail)
23648c2ecf20Sopenharmony_ci		return -EAGAIN;
23658c2ecf20Sopenharmony_ci	/* pulse the head_lock */
23668c2ecf20Sopenharmony_ci	if (wait && iowait_ioww_to_iow(wait)->sleep) {
23678c2ecf20Sopenharmony_ci		unsigned seq;
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci		seq = raw_seqcount_begin(
23708c2ecf20Sopenharmony_ci			(const seqcount_t *)&sde->head_lock.seqcount);
23718c2ecf20Sopenharmony_ci		ret = wait->iow->sleep(sde, wait, tx, seq, pkts_sent);
23728c2ecf20Sopenharmony_ci		if (ret == -EAGAIN)
23738c2ecf20Sopenharmony_ci			sde->desc_avail = sdma_descq_freecnt(sde);
23748c2ecf20Sopenharmony_ci	} else {
23758c2ecf20Sopenharmony_ci		ret = -EBUSY;
23768c2ecf20Sopenharmony_ci	}
23778c2ecf20Sopenharmony_ci	return ret;
23788c2ecf20Sopenharmony_ci}
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_ci/**
23818c2ecf20Sopenharmony_ci * sdma_send_txreq() - submit a tx req to ring
23828c2ecf20Sopenharmony_ci * @sde: sdma engine to use
23838c2ecf20Sopenharmony_ci * @wait: SE wait structure to use when full (may be NULL)
23848c2ecf20Sopenharmony_ci * @tx: sdma_txreq to submit
23858c2ecf20Sopenharmony_ci * @pkts_sent: has any packet been sent yet?
23868c2ecf20Sopenharmony_ci *
23878c2ecf20Sopenharmony_ci * The call submits the tx into the ring.  If a iowait structure is non-NULL
23888c2ecf20Sopenharmony_ci * the packet will be queued to the list in wait.
23898c2ecf20Sopenharmony_ci *
23908c2ecf20Sopenharmony_ci * Return:
23918c2ecf20Sopenharmony_ci * 0 - Success, -EINVAL - sdma_txreq incomplete, -EBUSY - no space in
23928c2ecf20Sopenharmony_ci * ring (wait == NULL)
23938c2ecf20Sopenharmony_ci * -EIOCBQUEUED - tx queued to iowait, -ECOMM bad sdma state
23948c2ecf20Sopenharmony_ci */
23958c2ecf20Sopenharmony_ciint sdma_send_txreq(struct sdma_engine *sde,
23968c2ecf20Sopenharmony_ci		    struct iowait_work *wait,
23978c2ecf20Sopenharmony_ci		    struct sdma_txreq *tx,
23988c2ecf20Sopenharmony_ci		    bool pkts_sent)
23998c2ecf20Sopenharmony_ci{
24008c2ecf20Sopenharmony_ci	int ret = 0;
24018c2ecf20Sopenharmony_ci	u16 tail;
24028c2ecf20Sopenharmony_ci	unsigned long flags;
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci	/* user should have supplied entire packet */
24058c2ecf20Sopenharmony_ci	if (unlikely(tx->tlen))
24068c2ecf20Sopenharmony_ci		return -EINVAL;
24078c2ecf20Sopenharmony_ci	tx->wait = iowait_ioww_to_iow(wait);
24088c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sde->tail_lock, flags);
24098c2ecf20Sopenharmony_ciretry:
24108c2ecf20Sopenharmony_ci	if (unlikely(!__sdma_running(sde)))
24118c2ecf20Sopenharmony_ci		goto unlock_noconn;
24128c2ecf20Sopenharmony_ci	if (unlikely(tx->num_desc > sde->desc_avail))
24138c2ecf20Sopenharmony_ci		goto nodesc;
24148c2ecf20Sopenharmony_ci	tail = submit_tx(sde, tx);
24158c2ecf20Sopenharmony_ci	if (wait)
24168c2ecf20Sopenharmony_ci		iowait_sdma_inc(iowait_ioww_to_iow(wait));
24178c2ecf20Sopenharmony_ci	sdma_update_tail(sde, tail);
24188c2ecf20Sopenharmony_ciunlock:
24198c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sde->tail_lock, flags);
24208c2ecf20Sopenharmony_ci	return ret;
24218c2ecf20Sopenharmony_ciunlock_noconn:
24228c2ecf20Sopenharmony_ci	if (wait)
24238c2ecf20Sopenharmony_ci		iowait_sdma_inc(iowait_ioww_to_iow(wait));
24248c2ecf20Sopenharmony_ci	tx->next_descq_idx = 0;
24258c2ecf20Sopenharmony_ci#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER
24268c2ecf20Sopenharmony_ci	tx->sn = sde->tail_sn++;
24278c2ecf20Sopenharmony_ci	trace_hfi1_sdma_in_sn(sde, tx->sn);
24288c2ecf20Sopenharmony_ci#endif
24298c2ecf20Sopenharmony_ci	spin_lock(&sde->flushlist_lock);
24308c2ecf20Sopenharmony_ci	list_add_tail(&tx->list, &sde->flushlist);
24318c2ecf20Sopenharmony_ci	spin_unlock(&sde->flushlist_lock);
24328c2ecf20Sopenharmony_ci	iowait_inc_wait_count(wait, tx->num_desc);
24338c2ecf20Sopenharmony_ci	queue_work_on(sde->cpu, system_highpri_wq, &sde->flush_worker);
24348c2ecf20Sopenharmony_ci	ret = -ECOMM;
24358c2ecf20Sopenharmony_ci	goto unlock;
24368c2ecf20Sopenharmony_cinodesc:
24378c2ecf20Sopenharmony_ci	ret = sdma_check_progress(sde, wait, tx, pkts_sent);
24388c2ecf20Sopenharmony_ci	if (ret == -EAGAIN) {
24398c2ecf20Sopenharmony_ci		ret = 0;
24408c2ecf20Sopenharmony_ci		goto retry;
24418c2ecf20Sopenharmony_ci	}
24428c2ecf20Sopenharmony_ci	sde->descq_full_count++;
24438c2ecf20Sopenharmony_ci	goto unlock;
24448c2ecf20Sopenharmony_ci}
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci/**
24478c2ecf20Sopenharmony_ci * sdma_send_txlist() - submit a list of tx req to ring
24488c2ecf20Sopenharmony_ci * @sde: sdma engine to use
24498c2ecf20Sopenharmony_ci * @wait: SE wait structure to use when full (may be NULL)
24508c2ecf20Sopenharmony_ci * @tx_list: list of sdma_txreqs to submit
24518c2ecf20Sopenharmony_ci * @count: pointer to a u16 which, after return will contain the total number of
24528c2ecf20Sopenharmony_ci *         sdma_txreqs removed from the tx_list. This will include sdma_txreqs
24538c2ecf20Sopenharmony_ci *         whose SDMA descriptors are submitted to the ring and the sdma_txreqs
24548c2ecf20Sopenharmony_ci *         which are added to SDMA engine flush list if the SDMA engine state is
24558c2ecf20Sopenharmony_ci *         not running.
24568c2ecf20Sopenharmony_ci *
24578c2ecf20Sopenharmony_ci * The call submits the list into the ring.
24588c2ecf20Sopenharmony_ci *
24598c2ecf20Sopenharmony_ci * If the iowait structure is non-NULL and not equal to the iowait list
24608c2ecf20Sopenharmony_ci * the unprocessed part of the list  will be appended to the list in wait.
24618c2ecf20Sopenharmony_ci *
24628c2ecf20Sopenharmony_ci * In all cases, the tx_list will be updated so the head of the tx_list is
24638c2ecf20Sopenharmony_ci * the list of descriptors that have yet to be transmitted.
24648c2ecf20Sopenharmony_ci *
24658c2ecf20Sopenharmony_ci * The intent of this call is to provide a more efficient
24668c2ecf20Sopenharmony_ci * way of submitting multiple packets to SDMA while holding the tail
24678c2ecf20Sopenharmony_ci * side locking.
24688c2ecf20Sopenharmony_ci *
24698c2ecf20Sopenharmony_ci * Return:
24708c2ecf20Sopenharmony_ci * 0 - Success,
24718c2ecf20Sopenharmony_ci * -EINVAL - sdma_txreq incomplete, -EBUSY - no space in ring (wait == NULL)
24728c2ecf20Sopenharmony_ci * -EIOCBQUEUED - tx queued to iowait, -ECOMM bad sdma state
24738c2ecf20Sopenharmony_ci */
24748c2ecf20Sopenharmony_ciint sdma_send_txlist(struct sdma_engine *sde, struct iowait_work *wait,
24758c2ecf20Sopenharmony_ci		     struct list_head *tx_list, u16 *count_out)
24768c2ecf20Sopenharmony_ci{
24778c2ecf20Sopenharmony_ci	struct sdma_txreq *tx, *tx_next;
24788c2ecf20Sopenharmony_ci	int ret = 0;
24798c2ecf20Sopenharmony_ci	unsigned long flags;
24808c2ecf20Sopenharmony_ci	u16 tail = INVALID_TAIL;
24818c2ecf20Sopenharmony_ci	u32 submit_count = 0, flush_count = 0, total_count;
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sde->tail_lock, flags);
24848c2ecf20Sopenharmony_ciretry:
24858c2ecf20Sopenharmony_ci	list_for_each_entry_safe(tx, tx_next, tx_list, list) {
24868c2ecf20Sopenharmony_ci		tx->wait = iowait_ioww_to_iow(wait);
24878c2ecf20Sopenharmony_ci		if (unlikely(!__sdma_running(sde)))
24888c2ecf20Sopenharmony_ci			goto unlock_noconn;
24898c2ecf20Sopenharmony_ci		if (unlikely(tx->num_desc > sde->desc_avail))
24908c2ecf20Sopenharmony_ci			goto nodesc;
24918c2ecf20Sopenharmony_ci		if (unlikely(tx->tlen)) {
24928c2ecf20Sopenharmony_ci			ret = -EINVAL;
24938c2ecf20Sopenharmony_ci			goto update_tail;
24948c2ecf20Sopenharmony_ci		}
24958c2ecf20Sopenharmony_ci		list_del_init(&tx->list);
24968c2ecf20Sopenharmony_ci		tail = submit_tx(sde, tx);
24978c2ecf20Sopenharmony_ci		submit_count++;
24988c2ecf20Sopenharmony_ci		if (tail != INVALID_TAIL &&
24998c2ecf20Sopenharmony_ci		    (submit_count & SDMA_TAIL_UPDATE_THRESH) == 0) {
25008c2ecf20Sopenharmony_ci			sdma_update_tail(sde, tail);
25018c2ecf20Sopenharmony_ci			tail = INVALID_TAIL;
25028c2ecf20Sopenharmony_ci		}
25038c2ecf20Sopenharmony_ci	}
25048c2ecf20Sopenharmony_ciupdate_tail:
25058c2ecf20Sopenharmony_ci	total_count = submit_count + flush_count;
25068c2ecf20Sopenharmony_ci	if (wait) {
25078c2ecf20Sopenharmony_ci		iowait_sdma_add(iowait_ioww_to_iow(wait), total_count);
25088c2ecf20Sopenharmony_ci		iowait_starve_clear(submit_count > 0,
25098c2ecf20Sopenharmony_ci				    iowait_ioww_to_iow(wait));
25108c2ecf20Sopenharmony_ci	}
25118c2ecf20Sopenharmony_ci	if (tail != INVALID_TAIL)
25128c2ecf20Sopenharmony_ci		sdma_update_tail(sde, tail);
25138c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sde->tail_lock, flags);
25148c2ecf20Sopenharmony_ci	*count_out = total_count;
25158c2ecf20Sopenharmony_ci	return ret;
25168c2ecf20Sopenharmony_ciunlock_noconn:
25178c2ecf20Sopenharmony_ci	spin_lock(&sde->flushlist_lock);
25188c2ecf20Sopenharmony_ci	list_for_each_entry_safe(tx, tx_next, tx_list, list) {
25198c2ecf20Sopenharmony_ci		tx->wait = iowait_ioww_to_iow(wait);
25208c2ecf20Sopenharmony_ci		list_del_init(&tx->list);
25218c2ecf20Sopenharmony_ci		tx->next_descq_idx = 0;
25228c2ecf20Sopenharmony_ci#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER
25238c2ecf20Sopenharmony_ci		tx->sn = sde->tail_sn++;
25248c2ecf20Sopenharmony_ci		trace_hfi1_sdma_in_sn(sde, tx->sn);
25258c2ecf20Sopenharmony_ci#endif
25268c2ecf20Sopenharmony_ci		list_add_tail(&tx->list, &sde->flushlist);
25278c2ecf20Sopenharmony_ci		flush_count++;
25288c2ecf20Sopenharmony_ci		iowait_inc_wait_count(wait, tx->num_desc);
25298c2ecf20Sopenharmony_ci	}
25308c2ecf20Sopenharmony_ci	spin_unlock(&sde->flushlist_lock);
25318c2ecf20Sopenharmony_ci	queue_work_on(sde->cpu, system_highpri_wq, &sde->flush_worker);
25328c2ecf20Sopenharmony_ci	ret = -ECOMM;
25338c2ecf20Sopenharmony_ci	goto update_tail;
25348c2ecf20Sopenharmony_cinodesc:
25358c2ecf20Sopenharmony_ci	ret = sdma_check_progress(sde, wait, tx, submit_count > 0);
25368c2ecf20Sopenharmony_ci	if (ret == -EAGAIN) {
25378c2ecf20Sopenharmony_ci		ret = 0;
25388c2ecf20Sopenharmony_ci		goto retry;
25398c2ecf20Sopenharmony_ci	}
25408c2ecf20Sopenharmony_ci	sde->descq_full_count++;
25418c2ecf20Sopenharmony_ci	goto update_tail;
25428c2ecf20Sopenharmony_ci}
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_cistatic void sdma_process_event(struct sdma_engine *sde, enum sdma_events event)
25458c2ecf20Sopenharmony_ci{
25468c2ecf20Sopenharmony_ci	unsigned long flags;
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sde->tail_lock, flags);
25498c2ecf20Sopenharmony_ci	write_seqlock(&sde->head_lock);
25508c2ecf20Sopenharmony_ci
25518c2ecf20Sopenharmony_ci	__sdma_process_event(sde, event);
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci	if (sde->state.current_state == sdma_state_s99_running)
25548c2ecf20Sopenharmony_ci		sdma_desc_avail(sde, sdma_descq_freecnt(sde));
25558c2ecf20Sopenharmony_ci
25568c2ecf20Sopenharmony_ci	write_sequnlock(&sde->head_lock);
25578c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sde->tail_lock, flags);
25588c2ecf20Sopenharmony_ci}
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_cistatic void __sdma_process_event(struct sdma_engine *sde,
25618c2ecf20Sopenharmony_ci				 enum sdma_events event)
25628c2ecf20Sopenharmony_ci{
25638c2ecf20Sopenharmony_ci	struct sdma_state *ss = &sde->state;
25648c2ecf20Sopenharmony_ci	int need_progress = 0;
25658c2ecf20Sopenharmony_ci
25668c2ecf20Sopenharmony_ci	/* CONFIG SDMA temporary */
25678c2ecf20Sopenharmony_ci#ifdef CONFIG_SDMA_VERBOSITY
25688c2ecf20Sopenharmony_ci	dd_dev_err(sde->dd, "CONFIG SDMA(%u) [%s] %s\n", sde->this_idx,
25698c2ecf20Sopenharmony_ci		   sdma_state_names[ss->current_state],
25708c2ecf20Sopenharmony_ci		   sdma_event_names[event]);
25718c2ecf20Sopenharmony_ci#endif
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci	switch (ss->current_state) {
25748c2ecf20Sopenharmony_ci	case sdma_state_s00_hw_down:
25758c2ecf20Sopenharmony_ci		switch (event) {
25768c2ecf20Sopenharmony_ci		case sdma_event_e00_go_hw_down:
25778c2ecf20Sopenharmony_ci			break;
25788c2ecf20Sopenharmony_ci		case sdma_event_e30_go_running:
25798c2ecf20Sopenharmony_ci			/*
25808c2ecf20Sopenharmony_ci			 * If down, but running requested (usually result
25818c2ecf20Sopenharmony_ci			 * of link up, then we need to start up.
25828c2ecf20Sopenharmony_ci			 * This can happen when hw down is requested while
25838c2ecf20Sopenharmony_ci			 * bringing the link up with traffic active on
25848c2ecf20Sopenharmony_ci			 * 7220, e.g.
25858c2ecf20Sopenharmony_ci			 */
25868c2ecf20Sopenharmony_ci			ss->go_s99_running = 1;
25878c2ecf20Sopenharmony_ci			fallthrough;	/* and start dma engine */
25888c2ecf20Sopenharmony_ci		case sdma_event_e10_go_hw_start:
25898c2ecf20Sopenharmony_ci			/* This reference means the state machine is started */
25908c2ecf20Sopenharmony_ci			sdma_get(&sde->state);
25918c2ecf20Sopenharmony_ci			sdma_set_state(sde,
25928c2ecf20Sopenharmony_ci				       sdma_state_s10_hw_start_up_halt_wait);
25938c2ecf20Sopenharmony_ci			break;
25948c2ecf20Sopenharmony_ci		case sdma_event_e15_hw_halt_done:
25958c2ecf20Sopenharmony_ci			break;
25968c2ecf20Sopenharmony_ci		case sdma_event_e25_hw_clean_up_done:
25978c2ecf20Sopenharmony_ci			break;
25988c2ecf20Sopenharmony_ci		case sdma_event_e40_sw_cleaned:
25998c2ecf20Sopenharmony_ci			sdma_sw_tear_down(sde);
26008c2ecf20Sopenharmony_ci			break;
26018c2ecf20Sopenharmony_ci		case sdma_event_e50_hw_cleaned:
26028c2ecf20Sopenharmony_ci			break;
26038c2ecf20Sopenharmony_ci		case sdma_event_e60_hw_halted:
26048c2ecf20Sopenharmony_ci			break;
26058c2ecf20Sopenharmony_ci		case sdma_event_e70_go_idle:
26068c2ecf20Sopenharmony_ci			break;
26078c2ecf20Sopenharmony_ci		case sdma_event_e80_hw_freeze:
26088c2ecf20Sopenharmony_ci			break;
26098c2ecf20Sopenharmony_ci		case sdma_event_e81_hw_frozen:
26108c2ecf20Sopenharmony_ci			break;
26118c2ecf20Sopenharmony_ci		case sdma_event_e82_hw_unfreeze:
26128c2ecf20Sopenharmony_ci			break;
26138c2ecf20Sopenharmony_ci		case sdma_event_e85_link_down:
26148c2ecf20Sopenharmony_ci			break;
26158c2ecf20Sopenharmony_ci		case sdma_event_e90_sw_halted:
26168c2ecf20Sopenharmony_ci			break;
26178c2ecf20Sopenharmony_ci		}
26188c2ecf20Sopenharmony_ci		break;
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci	case sdma_state_s10_hw_start_up_halt_wait:
26218c2ecf20Sopenharmony_ci		switch (event) {
26228c2ecf20Sopenharmony_ci		case sdma_event_e00_go_hw_down:
26238c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s00_hw_down);
26248c2ecf20Sopenharmony_ci			sdma_sw_tear_down(sde);
26258c2ecf20Sopenharmony_ci			break;
26268c2ecf20Sopenharmony_ci		case sdma_event_e10_go_hw_start:
26278c2ecf20Sopenharmony_ci			break;
26288c2ecf20Sopenharmony_ci		case sdma_event_e15_hw_halt_done:
26298c2ecf20Sopenharmony_ci			sdma_set_state(sde,
26308c2ecf20Sopenharmony_ci				       sdma_state_s15_hw_start_up_clean_wait);
26318c2ecf20Sopenharmony_ci			sdma_start_hw_clean_up(sde);
26328c2ecf20Sopenharmony_ci			break;
26338c2ecf20Sopenharmony_ci		case sdma_event_e25_hw_clean_up_done:
26348c2ecf20Sopenharmony_ci			break;
26358c2ecf20Sopenharmony_ci		case sdma_event_e30_go_running:
26368c2ecf20Sopenharmony_ci			ss->go_s99_running = 1;
26378c2ecf20Sopenharmony_ci			break;
26388c2ecf20Sopenharmony_ci		case sdma_event_e40_sw_cleaned:
26398c2ecf20Sopenharmony_ci			break;
26408c2ecf20Sopenharmony_ci		case sdma_event_e50_hw_cleaned:
26418c2ecf20Sopenharmony_ci			break;
26428c2ecf20Sopenharmony_ci		case sdma_event_e60_hw_halted:
26438c2ecf20Sopenharmony_ci			schedule_work(&sde->err_halt_worker);
26448c2ecf20Sopenharmony_ci			break;
26458c2ecf20Sopenharmony_ci		case sdma_event_e70_go_idle:
26468c2ecf20Sopenharmony_ci			ss->go_s99_running = 0;
26478c2ecf20Sopenharmony_ci			break;
26488c2ecf20Sopenharmony_ci		case sdma_event_e80_hw_freeze:
26498c2ecf20Sopenharmony_ci			break;
26508c2ecf20Sopenharmony_ci		case sdma_event_e81_hw_frozen:
26518c2ecf20Sopenharmony_ci			break;
26528c2ecf20Sopenharmony_ci		case sdma_event_e82_hw_unfreeze:
26538c2ecf20Sopenharmony_ci			break;
26548c2ecf20Sopenharmony_ci		case sdma_event_e85_link_down:
26558c2ecf20Sopenharmony_ci			break;
26568c2ecf20Sopenharmony_ci		case sdma_event_e90_sw_halted:
26578c2ecf20Sopenharmony_ci			break;
26588c2ecf20Sopenharmony_ci		}
26598c2ecf20Sopenharmony_ci		break;
26608c2ecf20Sopenharmony_ci
26618c2ecf20Sopenharmony_ci	case sdma_state_s15_hw_start_up_clean_wait:
26628c2ecf20Sopenharmony_ci		switch (event) {
26638c2ecf20Sopenharmony_ci		case sdma_event_e00_go_hw_down:
26648c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s00_hw_down);
26658c2ecf20Sopenharmony_ci			sdma_sw_tear_down(sde);
26668c2ecf20Sopenharmony_ci			break;
26678c2ecf20Sopenharmony_ci		case sdma_event_e10_go_hw_start:
26688c2ecf20Sopenharmony_ci			break;
26698c2ecf20Sopenharmony_ci		case sdma_event_e15_hw_halt_done:
26708c2ecf20Sopenharmony_ci			break;
26718c2ecf20Sopenharmony_ci		case sdma_event_e25_hw_clean_up_done:
26728c2ecf20Sopenharmony_ci			sdma_hw_start_up(sde);
26738c2ecf20Sopenharmony_ci			sdma_set_state(sde, ss->go_s99_running ?
26748c2ecf20Sopenharmony_ci				       sdma_state_s99_running :
26758c2ecf20Sopenharmony_ci				       sdma_state_s20_idle);
26768c2ecf20Sopenharmony_ci			break;
26778c2ecf20Sopenharmony_ci		case sdma_event_e30_go_running:
26788c2ecf20Sopenharmony_ci			ss->go_s99_running = 1;
26798c2ecf20Sopenharmony_ci			break;
26808c2ecf20Sopenharmony_ci		case sdma_event_e40_sw_cleaned:
26818c2ecf20Sopenharmony_ci			break;
26828c2ecf20Sopenharmony_ci		case sdma_event_e50_hw_cleaned:
26838c2ecf20Sopenharmony_ci			break;
26848c2ecf20Sopenharmony_ci		case sdma_event_e60_hw_halted:
26858c2ecf20Sopenharmony_ci			break;
26868c2ecf20Sopenharmony_ci		case sdma_event_e70_go_idle:
26878c2ecf20Sopenharmony_ci			ss->go_s99_running = 0;
26888c2ecf20Sopenharmony_ci			break;
26898c2ecf20Sopenharmony_ci		case sdma_event_e80_hw_freeze:
26908c2ecf20Sopenharmony_ci			break;
26918c2ecf20Sopenharmony_ci		case sdma_event_e81_hw_frozen:
26928c2ecf20Sopenharmony_ci			break;
26938c2ecf20Sopenharmony_ci		case sdma_event_e82_hw_unfreeze:
26948c2ecf20Sopenharmony_ci			break;
26958c2ecf20Sopenharmony_ci		case sdma_event_e85_link_down:
26968c2ecf20Sopenharmony_ci			break;
26978c2ecf20Sopenharmony_ci		case sdma_event_e90_sw_halted:
26988c2ecf20Sopenharmony_ci			break;
26998c2ecf20Sopenharmony_ci		}
27008c2ecf20Sopenharmony_ci		break;
27018c2ecf20Sopenharmony_ci
27028c2ecf20Sopenharmony_ci	case sdma_state_s20_idle:
27038c2ecf20Sopenharmony_ci		switch (event) {
27048c2ecf20Sopenharmony_ci		case sdma_event_e00_go_hw_down:
27058c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s00_hw_down);
27068c2ecf20Sopenharmony_ci			sdma_sw_tear_down(sde);
27078c2ecf20Sopenharmony_ci			break;
27088c2ecf20Sopenharmony_ci		case sdma_event_e10_go_hw_start:
27098c2ecf20Sopenharmony_ci			break;
27108c2ecf20Sopenharmony_ci		case sdma_event_e15_hw_halt_done:
27118c2ecf20Sopenharmony_ci			break;
27128c2ecf20Sopenharmony_ci		case sdma_event_e25_hw_clean_up_done:
27138c2ecf20Sopenharmony_ci			break;
27148c2ecf20Sopenharmony_ci		case sdma_event_e30_go_running:
27158c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s99_running);
27168c2ecf20Sopenharmony_ci			ss->go_s99_running = 1;
27178c2ecf20Sopenharmony_ci			break;
27188c2ecf20Sopenharmony_ci		case sdma_event_e40_sw_cleaned:
27198c2ecf20Sopenharmony_ci			break;
27208c2ecf20Sopenharmony_ci		case sdma_event_e50_hw_cleaned:
27218c2ecf20Sopenharmony_ci			break;
27228c2ecf20Sopenharmony_ci		case sdma_event_e60_hw_halted:
27238c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s50_hw_halt_wait);
27248c2ecf20Sopenharmony_ci			schedule_work(&sde->err_halt_worker);
27258c2ecf20Sopenharmony_ci			break;
27268c2ecf20Sopenharmony_ci		case sdma_event_e70_go_idle:
27278c2ecf20Sopenharmony_ci			break;
27288c2ecf20Sopenharmony_ci		case sdma_event_e85_link_down:
27298c2ecf20Sopenharmony_ci		case sdma_event_e80_hw_freeze:
27308c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s80_hw_freeze);
27318c2ecf20Sopenharmony_ci			atomic_dec(&sde->dd->sdma_unfreeze_count);
27328c2ecf20Sopenharmony_ci			wake_up_interruptible(&sde->dd->sdma_unfreeze_wq);
27338c2ecf20Sopenharmony_ci			break;
27348c2ecf20Sopenharmony_ci		case sdma_event_e81_hw_frozen:
27358c2ecf20Sopenharmony_ci			break;
27368c2ecf20Sopenharmony_ci		case sdma_event_e82_hw_unfreeze:
27378c2ecf20Sopenharmony_ci			break;
27388c2ecf20Sopenharmony_ci		case sdma_event_e90_sw_halted:
27398c2ecf20Sopenharmony_ci			break;
27408c2ecf20Sopenharmony_ci		}
27418c2ecf20Sopenharmony_ci		break;
27428c2ecf20Sopenharmony_ci
27438c2ecf20Sopenharmony_ci	case sdma_state_s30_sw_clean_up_wait:
27448c2ecf20Sopenharmony_ci		switch (event) {
27458c2ecf20Sopenharmony_ci		case sdma_event_e00_go_hw_down:
27468c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s00_hw_down);
27478c2ecf20Sopenharmony_ci			break;
27488c2ecf20Sopenharmony_ci		case sdma_event_e10_go_hw_start:
27498c2ecf20Sopenharmony_ci			break;
27508c2ecf20Sopenharmony_ci		case sdma_event_e15_hw_halt_done:
27518c2ecf20Sopenharmony_ci			break;
27528c2ecf20Sopenharmony_ci		case sdma_event_e25_hw_clean_up_done:
27538c2ecf20Sopenharmony_ci			break;
27548c2ecf20Sopenharmony_ci		case sdma_event_e30_go_running:
27558c2ecf20Sopenharmony_ci			ss->go_s99_running = 1;
27568c2ecf20Sopenharmony_ci			break;
27578c2ecf20Sopenharmony_ci		case sdma_event_e40_sw_cleaned:
27588c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s40_hw_clean_up_wait);
27598c2ecf20Sopenharmony_ci			sdma_start_hw_clean_up(sde);
27608c2ecf20Sopenharmony_ci			break;
27618c2ecf20Sopenharmony_ci		case sdma_event_e50_hw_cleaned:
27628c2ecf20Sopenharmony_ci			break;
27638c2ecf20Sopenharmony_ci		case sdma_event_e60_hw_halted:
27648c2ecf20Sopenharmony_ci			break;
27658c2ecf20Sopenharmony_ci		case sdma_event_e70_go_idle:
27668c2ecf20Sopenharmony_ci			ss->go_s99_running = 0;
27678c2ecf20Sopenharmony_ci			break;
27688c2ecf20Sopenharmony_ci		case sdma_event_e80_hw_freeze:
27698c2ecf20Sopenharmony_ci			break;
27708c2ecf20Sopenharmony_ci		case sdma_event_e81_hw_frozen:
27718c2ecf20Sopenharmony_ci			break;
27728c2ecf20Sopenharmony_ci		case sdma_event_e82_hw_unfreeze:
27738c2ecf20Sopenharmony_ci			break;
27748c2ecf20Sopenharmony_ci		case sdma_event_e85_link_down:
27758c2ecf20Sopenharmony_ci			ss->go_s99_running = 0;
27768c2ecf20Sopenharmony_ci			break;
27778c2ecf20Sopenharmony_ci		case sdma_event_e90_sw_halted:
27788c2ecf20Sopenharmony_ci			break;
27798c2ecf20Sopenharmony_ci		}
27808c2ecf20Sopenharmony_ci		break;
27818c2ecf20Sopenharmony_ci
27828c2ecf20Sopenharmony_ci	case sdma_state_s40_hw_clean_up_wait:
27838c2ecf20Sopenharmony_ci		switch (event) {
27848c2ecf20Sopenharmony_ci		case sdma_event_e00_go_hw_down:
27858c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s00_hw_down);
27868c2ecf20Sopenharmony_ci			tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
27878c2ecf20Sopenharmony_ci			break;
27888c2ecf20Sopenharmony_ci		case sdma_event_e10_go_hw_start:
27898c2ecf20Sopenharmony_ci			break;
27908c2ecf20Sopenharmony_ci		case sdma_event_e15_hw_halt_done:
27918c2ecf20Sopenharmony_ci			break;
27928c2ecf20Sopenharmony_ci		case sdma_event_e25_hw_clean_up_done:
27938c2ecf20Sopenharmony_ci			sdma_hw_start_up(sde);
27948c2ecf20Sopenharmony_ci			sdma_set_state(sde, ss->go_s99_running ?
27958c2ecf20Sopenharmony_ci				       sdma_state_s99_running :
27968c2ecf20Sopenharmony_ci				       sdma_state_s20_idle);
27978c2ecf20Sopenharmony_ci			break;
27988c2ecf20Sopenharmony_ci		case sdma_event_e30_go_running:
27998c2ecf20Sopenharmony_ci			ss->go_s99_running = 1;
28008c2ecf20Sopenharmony_ci			break;
28018c2ecf20Sopenharmony_ci		case sdma_event_e40_sw_cleaned:
28028c2ecf20Sopenharmony_ci			break;
28038c2ecf20Sopenharmony_ci		case sdma_event_e50_hw_cleaned:
28048c2ecf20Sopenharmony_ci			break;
28058c2ecf20Sopenharmony_ci		case sdma_event_e60_hw_halted:
28068c2ecf20Sopenharmony_ci			break;
28078c2ecf20Sopenharmony_ci		case sdma_event_e70_go_idle:
28088c2ecf20Sopenharmony_ci			ss->go_s99_running = 0;
28098c2ecf20Sopenharmony_ci			break;
28108c2ecf20Sopenharmony_ci		case sdma_event_e80_hw_freeze:
28118c2ecf20Sopenharmony_ci			break;
28128c2ecf20Sopenharmony_ci		case sdma_event_e81_hw_frozen:
28138c2ecf20Sopenharmony_ci			break;
28148c2ecf20Sopenharmony_ci		case sdma_event_e82_hw_unfreeze:
28158c2ecf20Sopenharmony_ci			break;
28168c2ecf20Sopenharmony_ci		case sdma_event_e85_link_down:
28178c2ecf20Sopenharmony_ci			ss->go_s99_running = 0;
28188c2ecf20Sopenharmony_ci			break;
28198c2ecf20Sopenharmony_ci		case sdma_event_e90_sw_halted:
28208c2ecf20Sopenharmony_ci			break;
28218c2ecf20Sopenharmony_ci		}
28228c2ecf20Sopenharmony_ci		break;
28238c2ecf20Sopenharmony_ci
28248c2ecf20Sopenharmony_ci	case sdma_state_s50_hw_halt_wait:
28258c2ecf20Sopenharmony_ci		switch (event) {
28268c2ecf20Sopenharmony_ci		case sdma_event_e00_go_hw_down:
28278c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s00_hw_down);
28288c2ecf20Sopenharmony_ci			tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
28298c2ecf20Sopenharmony_ci			break;
28308c2ecf20Sopenharmony_ci		case sdma_event_e10_go_hw_start:
28318c2ecf20Sopenharmony_ci			break;
28328c2ecf20Sopenharmony_ci		case sdma_event_e15_hw_halt_done:
28338c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s30_sw_clean_up_wait);
28348c2ecf20Sopenharmony_ci			tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
28358c2ecf20Sopenharmony_ci			break;
28368c2ecf20Sopenharmony_ci		case sdma_event_e25_hw_clean_up_done:
28378c2ecf20Sopenharmony_ci			break;
28388c2ecf20Sopenharmony_ci		case sdma_event_e30_go_running:
28398c2ecf20Sopenharmony_ci			ss->go_s99_running = 1;
28408c2ecf20Sopenharmony_ci			break;
28418c2ecf20Sopenharmony_ci		case sdma_event_e40_sw_cleaned:
28428c2ecf20Sopenharmony_ci			break;
28438c2ecf20Sopenharmony_ci		case sdma_event_e50_hw_cleaned:
28448c2ecf20Sopenharmony_ci			break;
28458c2ecf20Sopenharmony_ci		case sdma_event_e60_hw_halted:
28468c2ecf20Sopenharmony_ci			schedule_work(&sde->err_halt_worker);
28478c2ecf20Sopenharmony_ci			break;
28488c2ecf20Sopenharmony_ci		case sdma_event_e70_go_idle:
28498c2ecf20Sopenharmony_ci			ss->go_s99_running = 0;
28508c2ecf20Sopenharmony_ci			break;
28518c2ecf20Sopenharmony_ci		case sdma_event_e80_hw_freeze:
28528c2ecf20Sopenharmony_ci			break;
28538c2ecf20Sopenharmony_ci		case sdma_event_e81_hw_frozen:
28548c2ecf20Sopenharmony_ci			break;
28558c2ecf20Sopenharmony_ci		case sdma_event_e82_hw_unfreeze:
28568c2ecf20Sopenharmony_ci			break;
28578c2ecf20Sopenharmony_ci		case sdma_event_e85_link_down:
28588c2ecf20Sopenharmony_ci			ss->go_s99_running = 0;
28598c2ecf20Sopenharmony_ci			break;
28608c2ecf20Sopenharmony_ci		case sdma_event_e90_sw_halted:
28618c2ecf20Sopenharmony_ci			break;
28628c2ecf20Sopenharmony_ci		}
28638c2ecf20Sopenharmony_ci		break;
28648c2ecf20Sopenharmony_ci
28658c2ecf20Sopenharmony_ci	case sdma_state_s60_idle_halt_wait:
28668c2ecf20Sopenharmony_ci		switch (event) {
28678c2ecf20Sopenharmony_ci		case sdma_event_e00_go_hw_down:
28688c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s00_hw_down);
28698c2ecf20Sopenharmony_ci			tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
28708c2ecf20Sopenharmony_ci			break;
28718c2ecf20Sopenharmony_ci		case sdma_event_e10_go_hw_start:
28728c2ecf20Sopenharmony_ci			break;
28738c2ecf20Sopenharmony_ci		case sdma_event_e15_hw_halt_done:
28748c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s30_sw_clean_up_wait);
28758c2ecf20Sopenharmony_ci			tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
28768c2ecf20Sopenharmony_ci			break;
28778c2ecf20Sopenharmony_ci		case sdma_event_e25_hw_clean_up_done:
28788c2ecf20Sopenharmony_ci			break;
28798c2ecf20Sopenharmony_ci		case sdma_event_e30_go_running:
28808c2ecf20Sopenharmony_ci			ss->go_s99_running = 1;
28818c2ecf20Sopenharmony_ci			break;
28828c2ecf20Sopenharmony_ci		case sdma_event_e40_sw_cleaned:
28838c2ecf20Sopenharmony_ci			break;
28848c2ecf20Sopenharmony_ci		case sdma_event_e50_hw_cleaned:
28858c2ecf20Sopenharmony_ci			break;
28868c2ecf20Sopenharmony_ci		case sdma_event_e60_hw_halted:
28878c2ecf20Sopenharmony_ci			schedule_work(&sde->err_halt_worker);
28888c2ecf20Sopenharmony_ci			break;
28898c2ecf20Sopenharmony_ci		case sdma_event_e70_go_idle:
28908c2ecf20Sopenharmony_ci			ss->go_s99_running = 0;
28918c2ecf20Sopenharmony_ci			break;
28928c2ecf20Sopenharmony_ci		case sdma_event_e80_hw_freeze:
28938c2ecf20Sopenharmony_ci			break;
28948c2ecf20Sopenharmony_ci		case sdma_event_e81_hw_frozen:
28958c2ecf20Sopenharmony_ci			break;
28968c2ecf20Sopenharmony_ci		case sdma_event_e82_hw_unfreeze:
28978c2ecf20Sopenharmony_ci			break;
28988c2ecf20Sopenharmony_ci		case sdma_event_e85_link_down:
28998c2ecf20Sopenharmony_ci			break;
29008c2ecf20Sopenharmony_ci		case sdma_event_e90_sw_halted:
29018c2ecf20Sopenharmony_ci			break;
29028c2ecf20Sopenharmony_ci		}
29038c2ecf20Sopenharmony_ci		break;
29048c2ecf20Sopenharmony_ci
29058c2ecf20Sopenharmony_ci	case sdma_state_s80_hw_freeze:
29068c2ecf20Sopenharmony_ci		switch (event) {
29078c2ecf20Sopenharmony_ci		case sdma_event_e00_go_hw_down:
29088c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s00_hw_down);
29098c2ecf20Sopenharmony_ci			tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
29108c2ecf20Sopenharmony_ci			break;
29118c2ecf20Sopenharmony_ci		case sdma_event_e10_go_hw_start:
29128c2ecf20Sopenharmony_ci			break;
29138c2ecf20Sopenharmony_ci		case sdma_event_e15_hw_halt_done:
29148c2ecf20Sopenharmony_ci			break;
29158c2ecf20Sopenharmony_ci		case sdma_event_e25_hw_clean_up_done:
29168c2ecf20Sopenharmony_ci			break;
29178c2ecf20Sopenharmony_ci		case sdma_event_e30_go_running:
29188c2ecf20Sopenharmony_ci			ss->go_s99_running = 1;
29198c2ecf20Sopenharmony_ci			break;
29208c2ecf20Sopenharmony_ci		case sdma_event_e40_sw_cleaned:
29218c2ecf20Sopenharmony_ci			break;
29228c2ecf20Sopenharmony_ci		case sdma_event_e50_hw_cleaned:
29238c2ecf20Sopenharmony_ci			break;
29248c2ecf20Sopenharmony_ci		case sdma_event_e60_hw_halted:
29258c2ecf20Sopenharmony_ci			break;
29268c2ecf20Sopenharmony_ci		case sdma_event_e70_go_idle:
29278c2ecf20Sopenharmony_ci			ss->go_s99_running = 0;
29288c2ecf20Sopenharmony_ci			break;
29298c2ecf20Sopenharmony_ci		case sdma_event_e80_hw_freeze:
29308c2ecf20Sopenharmony_ci			break;
29318c2ecf20Sopenharmony_ci		case sdma_event_e81_hw_frozen:
29328c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s82_freeze_sw_clean);
29338c2ecf20Sopenharmony_ci			tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
29348c2ecf20Sopenharmony_ci			break;
29358c2ecf20Sopenharmony_ci		case sdma_event_e82_hw_unfreeze:
29368c2ecf20Sopenharmony_ci			break;
29378c2ecf20Sopenharmony_ci		case sdma_event_e85_link_down:
29388c2ecf20Sopenharmony_ci			break;
29398c2ecf20Sopenharmony_ci		case sdma_event_e90_sw_halted:
29408c2ecf20Sopenharmony_ci			break;
29418c2ecf20Sopenharmony_ci		}
29428c2ecf20Sopenharmony_ci		break;
29438c2ecf20Sopenharmony_ci
29448c2ecf20Sopenharmony_ci	case sdma_state_s82_freeze_sw_clean:
29458c2ecf20Sopenharmony_ci		switch (event) {
29468c2ecf20Sopenharmony_ci		case sdma_event_e00_go_hw_down:
29478c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s00_hw_down);
29488c2ecf20Sopenharmony_ci			tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
29498c2ecf20Sopenharmony_ci			break;
29508c2ecf20Sopenharmony_ci		case sdma_event_e10_go_hw_start:
29518c2ecf20Sopenharmony_ci			break;
29528c2ecf20Sopenharmony_ci		case sdma_event_e15_hw_halt_done:
29538c2ecf20Sopenharmony_ci			break;
29548c2ecf20Sopenharmony_ci		case sdma_event_e25_hw_clean_up_done:
29558c2ecf20Sopenharmony_ci			break;
29568c2ecf20Sopenharmony_ci		case sdma_event_e30_go_running:
29578c2ecf20Sopenharmony_ci			ss->go_s99_running = 1;
29588c2ecf20Sopenharmony_ci			break;
29598c2ecf20Sopenharmony_ci		case sdma_event_e40_sw_cleaned:
29608c2ecf20Sopenharmony_ci			/* notify caller this engine is done cleaning */
29618c2ecf20Sopenharmony_ci			atomic_dec(&sde->dd->sdma_unfreeze_count);
29628c2ecf20Sopenharmony_ci			wake_up_interruptible(&sde->dd->sdma_unfreeze_wq);
29638c2ecf20Sopenharmony_ci			break;
29648c2ecf20Sopenharmony_ci		case sdma_event_e50_hw_cleaned:
29658c2ecf20Sopenharmony_ci			break;
29668c2ecf20Sopenharmony_ci		case sdma_event_e60_hw_halted:
29678c2ecf20Sopenharmony_ci			break;
29688c2ecf20Sopenharmony_ci		case sdma_event_e70_go_idle:
29698c2ecf20Sopenharmony_ci			ss->go_s99_running = 0;
29708c2ecf20Sopenharmony_ci			break;
29718c2ecf20Sopenharmony_ci		case sdma_event_e80_hw_freeze:
29728c2ecf20Sopenharmony_ci			break;
29738c2ecf20Sopenharmony_ci		case sdma_event_e81_hw_frozen:
29748c2ecf20Sopenharmony_ci			break;
29758c2ecf20Sopenharmony_ci		case sdma_event_e82_hw_unfreeze:
29768c2ecf20Sopenharmony_ci			sdma_hw_start_up(sde);
29778c2ecf20Sopenharmony_ci			sdma_set_state(sde, ss->go_s99_running ?
29788c2ecf20Sopenharmony_ci				       sdma_state_s99_running :
29798c2ecf20Sopenharmony_ci				       sdma_state_s20_idle);
29808c2ecf20Sopenharmony_ci			break;
29818c2ecf20Sopenharmony_ci		case sdma_event_e85_link_down:
29828c2ecf20Sopenharmony_ci			break;
29838c2ecf20Sopenharmony_ci		case sdma_event_e90_sw_halted:
29848c2ecf20Sopenharmony_ci			break;
29858c2ecf20Sopenharmony_ci		}
29868c2ecf20Sopenharmony_ci		break;
29878c2ecf20Sopenharmony_ci
29888c2ecf20Sopenharmony_ci	case sdma_state_s99_running:
29898c2ecf20Sopenharmony_ci		switch (event) {
29908c2ecf20Sopenharmony_ci		case sdma_event_e00_go_hw_down:
29918c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s00_hw_down);
29928c2ecf20Sopenharmony_ci			tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
29938c2ecf20Sopenharmony_ci			break;
29948c2ecf20Sopenharmony_ci		case sdma_event_e10_go_hw_start:
29958c2ecf20Sopenharmony_ci			break;
29968c2ecf20Sopenharmony_ci		case sdma_event_e15_hw_halt_done:
29978c2ecf20Sopenharmony_ci			break;
29988c2ecf20Sopenharmony_ci		case sdma_event_e25_hw_clean_up_done:
29998c2ecf20Sopenharmony_ci			break;
30008c2ecf20Sopenharmony_ci		case sdma_event_e30_go_running:
30018c2ecf20Sopenharmony_ci			break;
30028c2ecf20Sopenharmony_ci		case sdma_event_e40_sw_cleaned:
30038c2ecf20Sopenharmony_ci			break;
30048c2ecf20Sopenharmony_ci		case sdma_event_e50_hw_cleaned:
30058c2ecf20Sopenharmony_ci			break;
30068c2ecf20Sopenharmony_ci		case sdma_event_e60_hw_halted:
30078c2ecf20Sopenharmony_ci			need_progress = 1;
30088c2ecf20Sopenharmony_ci			sdma_err_progress_check_schedule(sde);
30098c2ecf20Sopenharmony_ci			fallthrough;
30108c2ecf20Sopenharmony_ci		case sdma_event_e90_sw_halted:
30118c2ecf20Sopenharmony_ci			/*
30128c2ecf20Sopenharmony_ci			* SW initiated halt does not perform engines
30138c2ecf20Sopenharmony_ci			* progress check
30148c2ecf20Sopenharmony_ci			*/
30158c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s50_hw_halt_wait);
30168c2ecf20Sopenharmony_ci			schedule_work(&sde->err_halt_worker);
30178c2ecf20Sopenharmony_ci			break;
30188c2ecf20Sopenharmony_ci		case sdma_event_e70_go_idle:
30198c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s60_idle_halt_wait);
30208c2ecf20Sopenharmony_ci			break;
30218c2ecf20Sopenharmony_ci		case sdma_event_e85_link_down:
30228c2ecf20Sopenharmony_ci			ss->go_s99_running = 0;
30238c2ecf20Sopenharmony_ci			fallthrough;
30248c2ecf20Sopenharmony_ci		case sdma_event_e80_hw_freeze:
30258c2ecf20Sopenharmony_ci			sdma_set_state(sde, sdma_state_s80_hw_freeze);
30268c2ecf20Sopenharmony_ci			atomic_dec(&sde->dd->sdma_unfreeze_count);
30278c2ecf20Sopenharmony_ci			wake_up_interruptible(&sde->dd->sdma_unfreeze_wq);
30288c2ecf20Sopenharmony_ci			break;
30298c2ecf20Sopenharmony_ci		case sdma_event_e81_hw_frozen:
30308c2ecf20Sopenharmony_ci			break;
30318c2ecf20Sopenharmony_ci		case sdma_event_e82_hw_unfreeze:
30328c2ecf20Sopenharmony_ci			break;
30338c2ecf20Sopenharmony_ci		}
30348c2ecf20Sopenharmony_ci		break;
30358c2ecf20Sopenharmony_ci	}
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci	ss->last_event = event;
30388c2ecf20Sopenharmony_ci	if (need_progress)
30398c2ecf20Sopenharmony_ci		sdma_make_progress(sde, 0);
30408c2ecf20Sopenharmony_ci}
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci/*
30438c2ecf20Sopenharmony_ci * _extend_sdma_tx_descs() - helper to extend txreq
30448c2ecf20Sopenharmony_ci *
30458c2ecf20Sopenharmony_ci * This is called once the initial nominal allocation
30468c2ecf20Sopenharmony_ci * of descriptors in the sdma_txreq is exhausted.
30478c2ecf20Sopenharmony_ci *
30488c2ecf20Sopenharmony_ci * The code will bump the allocation up to the max
30498c2ecf20Sopenharmony_ci * of MAX_DESC (64) descriptors. There doesn't seem
30508c2ecf20Sopenharmony_ci * much point in an interim step. The last descriptor
30518c2ecf20Sopenharmony_ci * is reserved for coalesce buffer in order to support
30528c2ecf20Sopenharmony_ci * cases where input packet has >MAX_DESC iovecs.
30538c2ecf20Sopenharmony_ci *
30548c2ecf20Sopenharmony_ci */
30558c2ecf20Sopenharmony_cistatic int _extend_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx)
30568c2ecf20Sopenharmony_ci{
30578c2ecf20Sopenharmony_ci	int i;
30588c2ecf20Sopenharmony_ci	struct sdma_desc *descp;
30598c2ecf20Sopenharmony_ci
30608c2ecf20Sopenharmony_ci	/* Handle last descriptor */
30618c2ecf20Sopenharmony_ci	if (unlikely((tx->num_desc == (MAX_DESC - 1)))) {
30628c2ecf20Sopenharmony_ci		/* if tlen is 0, it is for padding, release last descriptor */
30638c2ecf20Sopenharmony_ci		if (!tx->tlen) {
30648c2ecf20Sopenharmony_ci			tx->desc_limit = MAX_DESC;
30658c2ecf20Sopenharmony_ci		} else if (!tx->coalesce_buf) {
30668c2ecf20Sopenharmony_ci			/* allocate coalesce buffer with space for padding */
30678c2ecf20Sopenharmony_ci			tx->coalesce_buf = kmalloc(tx->tlen + sizeof(u32),
30688c2ecf20Sopenharmony_ci						   GFP_ATOMIC);
30698c2ecf20Sopenharmony_ci			if (!tx->coalesce_buf)
30708c2ecf20Sopenharmony_ci				goto enomem;
30718c2ecf20Sopenharmony_ci			tx->coalesce_idx = 0;
30728c2ecf20Sopenharmony_ci		}
30738c2ecf20Sopenharmony_ci		return 0;
30748c2ecf20Sopenharmony_ci	}
30758c2ecf20Sopenharmony_ci
30768c2ecf20Sopenharmony_ci	if (unlikely(tx->num_desc == MAX_DESC))
30778c2ecf20Sopenharmony_ci		goto enomem;
30788c2ecf20Sopenharmony_ci
30798c2ecf20Sopenharmony_ci	descp = kmalloc_array(MAX_DESC, sizeof(struct sdma_desc), GFP_ATOMIC);
30808c2ecf20Sopenharmony_ci	if (!descp)
30818c2ecf20Sopenharmony_ci		goto enomem;
30828c2ecf20Sopenharmony_ci	tx->descp = descp;
30838c2ecf20Sopenharmony_ci
30848c2ecf20Sopenharmony_ci	/* reserve last descriptor for coalescing */
30858c2ecf20Sopenharmony_ci	tx->desc_limit = MAX_DESC - 1;
30868c2ecf20Sopenharmony_ci	/* copy ones already built */
30878c2ecf20Sopenharmony_ci	for (i = 0; i < tx->num_desc; i++)
30888c2ecf20Sopenharmony_ci		tx->descp[i] = tx->descs[i];
30898c2ecf20Sopenharmony_ci	return 0;
30908c2ecf20Sopenharmony_cienomem:
30918c2ecf20Sopenharmony_ci	__sdma_txclean(dd, tx);
30928c2ecf20Sopenharmony_ci	return -ENOMEM;
30938c2ecf20Sopenharmony_ci}
30948c2ecf20Sopenharmony_ci
30958c2ecf20Sopenharmony_ci/*
30968c2ecf20Sopenharmony_ci * ext_coal_sdma_tx_descs() - extend or coalesce sdma tx descriptors
30978c2ecf20Sopenharmony_ci *
30988c2ecf20Sopenharmony_ci * This is called once the initial nominal allocation of descriptors
30998c2ecf20Sopenharmony_ci * in the sdma_txreq is exhausted.
31008c2ecf20Sopenharmony_ci *
31018c2ecf20Sopenharmony_ci * This function calls _extend_sdma_tx_descs to extend or allocate
31028c2ecf20Sopenharmony_ci * coalesce buffer. If there is a allocated coalesce buffer, it will
31038c2ecf20Sopenharmony_ci * copy the input packet data into the coalesce buffer. It also adds
31048c2ecf20Sopenharmony_ci * coalesce buffer descriptor once when whole packet is received.
31058c2ecf20Sopenharmony_ci *
31068c2ecf20Sopenharmony_ci * Return:
31078c2ecf20Sopenharmony_ci * <0 - error
31088c2ecf20Sopenharmony_ci * 0 - coalescing, don't populate descriptor
31098c2ecf20Sopenharmony_ci * 1 - continue with populating descriptor
31108c2ecf20Sopenharmony_ci */
31118c2ecf20Sopenharmony_ciint ext_coal_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx,
31128c2ecf20Sopenharmony_ci			   int type, void *kvaddr, struct page *page,
31138c2ecf20Sopenharmony_ci			   unsigned long offset, u16 len)
31148c2ecf20Sopenharmony_ci{
31158c2ecf20Sopenharmony_ci	int pad_len, rval;
31168c2ecf20Sopenharmony_ci	dma_addr_t addr;
31178c2ecf20Sopenharmony_ci
31188c2ecf20Sopenharmony_ci	rval = _extend_sdma_tx_descs(dd, tx);
31198c2ecf20Sopenharmony_ci	if (rval) {
31208c2ecf20Sopenharmony_ci		__sdma_txclean(dd, tx);
31218c2ecf20Sopenharmony_ci		return rval;
31228c2ecf20Sopenharmony_ci	}
31238c2ecf20Sopenharmony_ci
31248c2ecf20Sopenharmony_ci	/* If coalesce buffer is allocated, copy data into it */
31258c2ecf20Sopenharmony_ci	if (tx->coalesce_buf) {
31268c2ecf20Sopenharmony_ci		if (type == SDMA_MAP_NONE) {
31278c2ecf20Sopenharmony_ci			__sdma_txclean(dd, tx);
31288c2ecf20Sopenharmony_ci			return -EINVAL;
31298c2ecf20Sopenharmony_ci		}
31308c2ecf20Sopenharmony_ci
31318c2ecf20Sopenharmony_ci		if (type == SDMA_MAP_PAGE) {
31328c2ecf20Sopenharmony_ci			kvaddr = kmap(page);
31338c2ecf20Sopenharmony_ci			kvaddr += offset;
31348c2ecf20Sopenharmony_ci		} else if (WARN_ON(!kvaddr)) {
31358c2ecf20Sopenharmony_ci			__sdma_txclean(dd, tx);
31368c2ecf20Sopenharmony_ci			return -EINVAL;
31378c2ecf20Sopenharmony_ci		}
31388c2ecf20Sopenharmony_ci
31398c2ecf20Sopenharmony_ci		memcpy(tx->coalesce_buf + tx->coalesce_idx, kvaddr, len);
31408c2ecf20Sopenharmony_ci		tx->coalesce_idx += len;
31418c2ecf20Sopenharmony_ci		if (type == SDMA_MAP_PAGE)
31428c2ecf20Sopenharmony_ci			kunmap(page);
31438c2ecf20Sopenharmony_ci
31448c2ecf20Sopenharmony_ci		/* If there is more data, return */
31458c2ecf20Sopenharmony_ci		if (tx->tlen - tx->coalesce_idx)
31468c2ecf20Sopenharmony_ci			return 0;
31478c2ecf20Sopenharmony_ci
31488c2ecf20Sopenharmony_ci		/* Whole packet is received; add any padding */
31498c2ecf20Sopenharmony_ci		pad_len = tx->packet_len & (sizeof(u32) - 1);
31508c2ecf20Sopenharmony_ci		if (pad_len) {
31518c2ecf20Sopenharmony_ci			pad_len = sizeof(u32) - pad_len;
31528c2ecf20Sopenharmony_ci			memset(tx->coalesce_buf + tx->coalesce_idx, 0, pad_len);
31538c2ecf20Sopenharmony_ci			/* padding is taken care of for coalescing case */
31548c2ecf20Sopenharmony_ci			tx->packet_len += pad_len;
31558c2ecf20Sopenharmony_ci			tx->tlen += pad_len;
31568c2ecf20Sopenharmony_ci		}
31578c2ecf20Sopenharmony_ci
31588c2ecf20Sopenharmony_ci		/* dma map the coalesce buffer */
31598c2ecf20Sopenharmony_ci		addr = dma_map_single(&dd->pcidev->dev,
31608c2ecf20Sopenharmony_ci				      tx->coalesce_buf,
31618c2ecf20Sopenharmony_ci				      tx->tlen,
31628c2ecf20Sopenharmony_ci				      DMA_TO_DEVICE);
31638c2ecf20Sopenharmony_ci
31648c2ecf20Sopenharmony_ci		if (unlikely(dma_mapping_error(&dd->pcidev->dev, addr))) {
31658c2ecf20Sopenharmony_ci			__sdma_txclean(dd, tx);
31668c2ecf20Sopenharmony_ci			return -ENOSPC;
31678c2ecf20Sopenharmony_ci		}
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_ci		/* Add descriptor for coalesce buffer */
31708c2ecf20Sopenharmony_ci		tx->desc_limit = MAX_DESC;
31718c2ecf20Sopenharmony_ci		return _sdma_txadd_daddr(dd, SDMA_MAP_SINGLE, tx,
31728c2ecf20Sopenharmony_ci					 addr, tx->tlen, NULL, NULL, NULL);
31738c2ecf20Sopenharmony_ci	}
31748c2ecf20Sopenharmony_ci
31758c2ecf20Sopenharmony_ci	return 1;
31768c2ecf20Sopenharmony_ci}
31778c2ecf20Sopenharmony_ci
31788c2ecf20Sopenharmony_ci/* Update sdes when the lmc changes */
31798c2ecf20Sopenharmony_civoid sdma_update_lmc(struct hfi1_devdata *dd, u64 mask, u32 lid)
31808c2ecf20Sopenharmony_ci{
31818c2ecf20Sopenharmony_ci	struct sdma_engine *sde;
31828c2ecf20Sopenharmony_ci	int i;
31838c2ecf20Sopenharmony_ci	u64 sreg;
31848c2ecf20Sopenharmony_ci
31858c2ecf20Sopenharmony_ci	sreg = ((mask & SD(CHECK_SLID_MASK_MASK)) <<
31868c2ecf20Sopenharmony_ci		SD(CHECK_SLID_MASK_SHIFT)) |
31878c2ecf20Sopenharmony_ci		(((lid & mask) & SD(CHECK_SLID_VALUE_MASK)) <<
31888c2ecf20Sopenharmony_ci		SD(CHECK_SLID_VALUE_SHIFT));
31898c2ecf20Sopenharmony_ci
31908c2ecf20Sopenharmony_ci	for (i = 0; i < dd->num_sdma; i++) {
31918c2ecf20Sopenharmony_ci		hfi1_cdbg(LINKVERB, "SendDmaEngine[%d].SLID_CHECK = 0x%x",
31928c2ecf20Sopenharmony_ci			  i, (u32)sreg);
31938c2ecf20Sopenharmony_ci		sde = &dd->per_sdma[i];
31948c2ecf20Sopenharmony_ci		write_sde_csr(sde, SD(CHECK_SLID), sreg);
31958c2ecf20Sopenharmony_ci	}
31968c2ecf20Sopenharmony_ci}
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_ci/* tx not dword sized - pad */
31998c2ecf20Sopenharmony_ciint _pad_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx)
32008c2ecf20Sopenharmony_ci{
32018c2ecf20Sopenharmony_ci	int rval = 0;
32028c2ecf20Sopenharmony_ci
32038c2ecf20Sopenharmony_ci	if ((unlikely(tx->num_desc + 1 == tx->desc_limit))) {
32048c2ecf20Sopenharmony_ci		rval = _extend_sdma_tx_descs(dd, tx);
32058c2ecf20Sopenharmony_ci		if (rval) {
32068c2ecf20Sopenharmony_ci			__sdma_txclean(dd, tx);
32078c2ecf20Sopenharmony_ci			return rval;
32088c2ecf20Sopenharmony_ci		}
32098c2ecf20Sopenharmony_ci	}
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_ci	/* finish the one just added */
32128c2ecf20Sopenharmony_ci	make_tx_sdma_desc(
32138c2ecf20Sopenharmony_ci		tx,
32148c2ecf20Sopenharmony_ci		SDMA_MAP_NONE,
32158c2ecf20Sopenharmony_ci		dd->sdma_pad_phys,
32168c2ecf20Sopenharmony_ci		sizeof(u32) - (tx->packet_len & (sizeof(u32) - 1)),
32178c2ecf20Sopenharmony_ci		NULL, NULL, NULL);
32188c2ecf20Sopenharmony_ci	tx->num_desc++;
32198c2ecf20Sopenharmony_ci	_sdma_close_tx(dd, tx);
32208c2ecf20Sopenharmony_ci	return rval;
32218c2ecf20Sopenharmony_ci}
32228c2ecf20Sopenharmony_ci
32238c2ecf20Sopenharmony_ci/*
32248c2ecf20Sopenharmony_ci * Add ahg to the sdma_txreq
32258c2ecf20Sopenharmony_ci *
32268c2ecf20Sopenharmony_ci * The logic will consume up to 3
32278c2ecf20Sopenharmony_ci * descriptors at the beginning of
32288c2ecf20Sopenharmony_ci * sdma_txreq.
32298c2ecf20Sopenharmony_ci */
32308c2ecf20Sopenharmony_civoid _sdma_txreq_ahgadd(
32318c2ecf20Sopenharmony_ci	struct sdma_txreq *tx,
32328c2ecf20Sopenharmony_ci	u8 num_ahg,
32338c2ecf20Sopenharmony_ci	u8 ahg_entry,
32348c2ecf20Sopenharmony_ci	u32 *ahg,
32358c2ecf20Sopenharmony_ci	u8 ahg_hlen)
32368c2ecf20Sopenharmony_ci{
32378c2ecf20Sopenharmony_ci	u32 i, shift = 0, desc = 0;
32388c2ecf20Sopenharmony_ci	u8 mode;
32398c2ecf20Sopenharmony_ci
32408c2ecf20Sopenharmony_ci	WARN_ON_ONCE(num_ahg > 9 || (ahg_hlen & 3) || ahg_hlen == 4);
32418c2ecf20Sopenharmony_ci	/* compute mode */
32428c2ecf20Sopenharmony_ci	if (num_ahg == 1)
32438c2ecf20Sopenharmony_ci		mode = SDMA_AHG_APPLY_UPDATE1;
32448c2ecf20Sopenharmony_ci	else if (num_ahg <= 5)
32458c2ecf20Sopenharmony_ci		mode = SDMA_AHG_APPLY_UPDATE2;
32468c2ecf20Sopenharmony_ci	else
32478c2ecf20Sopenharmony_ci		mode = SDMA_AHG_APPLY_UPDATE3;
32488c2ecf20Sopenharmony_ci	tx->num_desc++;
32498c2ecf20Sopenharmony_ci	/* initialize to consumed descriptors to zero */
32508c2ecf20Sopenharmony_ci	switch (mode) {
32518c2ecf20Sopenharmony_ci	case SDMA_AHG_APPLY_UPDATE3:
32528c2ecf20Sopenharmony_ci		tx->num_desc++;
32538c2ecf20Sopenharmony_ci		tx->descs[2].qw[0] = 0;
32548c2ecf20Sopenharmony_ci		tx->descs[2].qw[1] = 0;
32558c2ecf20Sopenharmony_ci		fallthrough;
32568c2ecf20Sopenharmony_ci	case SDMA_AHG_APPLY_UPDATE2:
32578c2ecf20Sopenharmony_ci		tx->num_desc++;
32588c2ecf20Sopenharmony_ci		tx->descs[1].qw[0] = 0;
32598c2ecf20Sopenharmony_ci		tx->descs[1].qw[1] = 0;
32608c2ecf20Sopenharmony_ci		break;
32618c2ecf20Sopenharmony_ci	}
32628c2ecf20Sopenharmony_ci	ahg_hlen >>= 2;
32638c2ecf20Sopenharmony_ci	tx->descs[0].qw[1] |=
32648c2ecf20Sopenharmony_ci		(((u64)ahg_entry & SDMA_DESC1_HEADER_INDEX_MASK)
32658c2ecf20Sopenharmony_ci			<< SDMA_DESC1_HEADER_INDEX_SHIFT) |
32668c2ecf20Sopenharmony_ci		(((u64)ahg_hlen & SDMA_DESC1_HEADER_DWS_MASK)
32678c2ecf20Sopenharmony_ci			<< SDMA_DESC1_HEADER_DWS_SHIFT) |
32688c2ecf20Sopenharmony_ci		(((u64)mode & SDMA_DESC1_HEADER_MODE_MASK)
32698c2ecf20Sopenharmony_ci			<< SDMA_DESC1_HEADER_MODE_SHIFT) |
32708c2ecf20Sopenharmony_ci		(((u64)ahg[0] & SDMA_DESC1_HEADER_UPDATE1_MASK)
32718c2ecf20Sopenharmony_ci			<< SDMA_DESC1_HEADER_UPDATE1_SHIFT);
32728c2ecf20Sopenharmony_ci	for (i = 0; i < (num_ahg - 1); i++) {
32738c2ecf20Sopenharmony_ci		if (!shift && !(i & 2))
32748c2ecf20Sopenharmony_ci			desc++;
32758c2ecf20Sopenharmony_ci		tx->descs[desc].qw[!!(i & 2)] |=
32768c2ecf20Sopenharmony_ci			(((u64)ahg[i + 1])
32778c2ecf20Sopenharmony_ci				<< shift);
32788c2ecf20Sopenharmony_ci		shift = (shift + 32) & 63;
32798c2ecf20Sopenharmony_ci	}
32808c2ecf20Sopenharmony_ci}
32818c2ecf20Sopenharmony_ci
32828c2ecf20Sopenharmony_ci/**
32838c2ecf20Sopenharmony_ci * sdma_ahg_alloc - allocate an AHG entry
32848c2ecf20Sopenharmony_ci * @sde: engine to allocate from
32858c2ecf20Sopenharmony_ci *
32868c2ecf20Sopenharmony_ci * Return:
32878c2ecf20Sopenharmony_ci * 0-31 when successful, -EOPNOTSUPP if AHG is not enabled,
32888c2ecf20Sopenharmony_ci * -ENOSPC if an entry is not available
32898c2ecf20Sopenharmony_ci */
32908c2ecf20Sopenharmony_ciint sdma_ahg_alloc(struct sdma_engine *sde)
32918c2ecf20Sopenharmony_ci{
32928c2ecf20Sopenharmony_ci	int nr;
32938c2ecf20Sopenharmony_ci	int oldbit;
32948c2ecf20Sopenharmony_ci
32958c2ecf20Sopenharmony_ci	if (!sde) {
32968c2ecf20Sopenharmony_ci		trace_hfi1_ahg_allocate(sde, -EINVAL);
32978c2ecf20Sopenharmony_ci		return -EINVAL;
32988c2ecf20Sopenharmony_ci	}
32998c2ecf20Sopenharmony_ci	while (1) {
33008c2ecf20Sopenharmony_ci		nr = ffz(READ_ONCE(sde->ahg_bits));
33018c2ecf20Sopenharmony_ci		if (nr > 31) {
33028c2ecf20Sopenharmony_ci			trace_hfi1_ahg_allocate(sde, -ENOSPC);
33038c2ecf20Sopenharmony_ci			return -ENOSPC;
33048c2ecf20Sopenharmony_ci		}
33058c2ecf20Sopenharmony_ci		oldbit = test_and_set_bit(nr, &sde->ahg_bits);
33068c2ecf20Sopenharmony_ci		if (!oldbit)
33078c2ecf20Sopenharmony_ci			break;
33088c2ecf20Sopenharmony_ci		cpu_relax();
33098c2ecf20Sopenharmony_ci	}
33108c2ecf20Sopenharmony_ci	trace_hfi1_ahg_allocate(sde, nr);
33118c2ecf20Sopenharmony_ci	return nr;
33128c2ecf20Sopenharmony_ci}
33138c2ecf20Sopenharmony_ci
33148c2ecf20Sopenharmony_ci/**
33158c2ecf20Sopenharmony_ci * sdma_ahg_free - free an AHG entry
33168c2ecf20Sopenharmony_ci * @sde: engine to return AHG entry
33178c2ecf20Sopenharmony_ci * @ahg_index: index to free
33188c2ecf20Sopenharmony_ci *
33198c2ecf20Sopenharmony_ci * This routine frees the indicate AHG entry.
33208c2ecf20Sopenharmony_ci */
33218c2ecf20Sopenharmony_civoid sdma_ahg_free(struct sdma_engine *sde, int ahg_index)
33228c2ecf20Sopenharmony_ci{
33238c2ecf20Sopenharmony_ci	if (!sde)
33248c2ecf20Sopenharmony_ci		return;
33258c2ecf20Sopenharmony_ci	trace_hfi1_ahg_deallocate(sde, ahg_index);
33268c2ecf20Sopenharmony_ci	if (ahg_index < 0 || ahg_index > 31)
33278c2ecf20Sopenharmony_ci		return;
33288c2ecf20Sopenharmony_ci	clear_bit(ahg_index, &sde->ahg_bits);
33298c2ecf20Sopenharmony_ci}
33308c2ecf20Sopenharmony_ci
33318c2ecf20Sopenharmony_ci/*
33328c2ecf20Sopenharmony_ci * SPC freeze handling for SDMA engines.  Called when the driver knows
33338c2ecf20Sopenharmony_ci * the SPC is going into a freeze but before the freeze is fully
33348c2ecf20Sopenharmony_ci * settled.  Generally an error interrupt.
33358c2ecf20Sopenharmony_ci *
33368c2ecf20Sopenharmony_ci * This event will pull the engine out of running so no more entries can be
33378c2ecf20Sopenharmony_ci * added to the engine's queue.
33388c2ecf20Sopenharmony_ci */
33398c2ecf20Sopenharmony_civoid sdma_freeze_notify(struct hfi1_devdata *dd, int link_down)
33408c2ecf20Sopenharmony_ci{
33418c2ecf20Sopenharmony_ci	int i;
33428c2ecf20Sopenharmony_ci	enum sdma_events event = link_down ? sdma_event_e85_link_down :
33438c2ecf20Sopenharmony_ci					     sdma_event_e80_hw_freeze;
33448c2ecf20Sopenharmony_ci
33458c2ecf20Sopenharmony_ci	/* set up the wait but do not wait here */
33468c2ecf20Sopenharmony_ci	atomic_set(&dd->sdma_unfreeze_count, dd->num_sdma);
33478c2ecf20Sopenharmony_ci
33488c2ecf20Sopenharmony_ci	/* tell all engines to stop running and wait */
33498c2ecf20Sopenharmony_ci	for (i = 0; i < dd->num_sdma; i++)
33508c2ecf20Sopenharmony_ci		sdma_process_event(&dd->per_sdma[i], event);
33518c2ecf20Sopenharmony_ci
33528c2ecf20Sopenharmony_ci	/* sdma_freeze() will wait for all engines to have stopped */
33538c2ecf20Sopenharmony_ci}
33548c2ecf20Sopenharmony_ci
33558c2ecf20Sopenharmony_ci/*
33568c2ecf20Sopenharmony_ci * SPC freeze handling for SDMA engines.  Called when the driver knows
33578c2ecf20Sopenharmony_ci * the SPC is fully frozen.
33588c2ecf20Sopenharmony_ci */
33598c2ecf20Sopenharmony_civoid sdma_freeze(struct hfi1_devdata *dd)
33608c2ecf20Sopenharmony_ci{
33618c2ecf20Sopenharmony_ci	int i;
33628c2ecf20Sopenharmony_ci	int ret;
33638c2ecf20Sopenharmony_ci
33648c2ecf20Sopenharmony_ci	/*
33658c2ecf20Sopenharmony_ci	 * Make sure all engines have moved out of the running state before
33668c2ecf20Sopenharmony_ci	 * continuing.
33678c2ecf20Sopenharmony_ci	 */
33688c2ecf20Sopenharmony_ci	ret = wait_event_interruptible(dd->sdma_unfreeze_wq,
33698c2ecf20Sopenharmony_ci				       atomic_read(&dd->sdma_unfreeze_count) <=
33708c2ecf20Sopenharmony_ci				       0);
33718c2ecf20Sopenharmony_ci	/* interrupted or count is negative, then unloading - just exit */
33728c2ecf20Sopenharmony_ci	if (ret || atomic_read(&dd->sdma_unfreeze_count) < 0)
33738c2ecf20Sopenharmony_ci		return;
33748c2ecf20Sopenharmony_ci
33758c2ecf20Sopenharmony_ci	/* set up the count for the next wait */
33768c2ecf20Sopenharmony_ci	atomic_set(&dd->sdma_unfreeze_count, dd->num_sdma);
33778c2ecf20Sopenharmony_ci
33788c2ecf20Sopenharmony_ci	/* tell all engines that the SPC is frozen, they can start cleaning */
33798c2ecf20Sopenharmony_ci	for (i = 0; i < dd->num_sdma; i++)
33808c2ecf20Sopenharmony_ci		sdma_process_event(&dd->per_sdma[i], sdma_event_e81_hw_frozen);
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_ci	/*
33838c2ecf20Sopenharmony_ci	 * Wait for everyone to finish software clean before exiting.  The
33848c2ecf20Sopenharmony_ci	 * software clean will read engine CSRs, so must be completed before
33858c2ecf20Sopenharmony_ci	 * the next step, which will clear the engine CSRs.
33868c2ecf20Sopenharmony_ci	 */
33878c2ecf20Sopenharmony_ci	(void)wait_event_interruptible(dd->sdma_unfreeze_wq,
33888c2ecf20Sopenharmony_ci				atomic_read(&dd->sdma_unfreeze_count) <= 0);
33898c2ecf20Sopenharmony_ci	/* no need to check results - done no matter what */
33908c2ecf20Sopenharmony_ci}
33918c2ecf20Sopenharmony_ci
33928c2ecf20Sopenharmony_ci/*
33938c2ecf20Sopenharmony_ci * SPC freeze handling for the SDMA engines.  Called after the SPC is unfrozen.
33948c2ecf20Sopenharmony_ci *
33958c2ecf20Sopenharmony_ci * The SPC freeze acts like a SDMA halt and a hardware clean combined.  All
33968c2ecf20Sopenharmony_ci * that is left is a software clean.  We could do it after the SPC is fully
33978c2ecf20Sopenharmony_ci * frozen, but then we'd have to add another state to wait for the unfreeze.
33988c2ecf20Sopenharmony_ci * Instead, just defer the software clean until the unfreeze step.
33998c2ecf20Sopenharmony_ci */
34008c2ecf20Sopenharmony_civoid sdma_unfreeze(struct hfi1_devdata *dd)
34018c2ecf20Sopenharmony_ci{
34028c2ecf20Sopenharmony_ci	int i;
34038c2ecf20Sopenharmony_ci
34048c2ecf20Sopenharmony_ci	/* tell all engines start freeze clean up */
34058c2ecf20Sopenharmony_ci	for (i = 0; i < dd->num_sdma; i++)
34068c2ecf20Sopenharmony_ci		sdma_process_event(&dd->per_sdma[i],
34078c2ecf20Sopenharmony_ci				   sdma_event_e82_hw_unfreeze);
34088c2ecf20Sopenharmony_ci}
34098c2ecf20Sopenharmony_ci
34108c2ecf20Sopenharmony_ci/**
34118c2ecf20Sopenharmony_ci * _sdma_engine_progress_schedule() - schedule progress on engine
34128c2ecf20Sopenharmony_ci * @sde: sdma_engine to schedule progress
34138c2ecf20Sopenharmony_ci *
34148c2ecf20Sopenharmony_ci */
34158c2ecf20Sopenharmony_civoid _sdma_engine_progress_schedule(
34168c2ecf20Sopenharmony_ci	struct sdma_engine *sde)
34178c2ecf20Sopenharmony_ci{
34188c2ecf20Sopenharmony_ci	trace_hfi1_sdma_engine_progress(sde, sde->progress_mask);
34198c2ecf20Sopenharmony_ci	/* assume we have selected a good cpu */
34208c2ecf20Sopenharmony_ci	write_csr(sde->dd,
34218c2ecf20Sopenharmony_ci		  CCE_INT_FORCE + (8 * (IS_SDMA_START / 64)),
34228c2ecf20Sopenharmony_ci		  sde->progress_mask);
34238c2ecf20Sopenharmony_ci}
3424