18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Microsemi Switchtec(tm) PCIe Management Driver
48c2ecf20Sopenharmony_ci * Copyright (c) 2017, Microsemi Corporation
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
88c2ecf20Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h>
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/kthread.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/ntb.h>
138c2ecf20Sopenharmony_ci#include <linux/pci.h>
148c2ecf20Sopenharmony_ci#include <linux/switchtec.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver");
178c2ecf20Sopenharmony_ciMODULE_VERSION("0.1");
188c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
198c2ecf20Sopenharmony_ciMODULE_AUTHOR("Microsemi Corporation");
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic ulong max_mw_size = SZ_2M;
228c2ecf20Sopenharmony_cimodule_param(max_mw_size, ulong, 0644);
238c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_mw_size,
248c2ecf20Sopenharmony_ci	"Max memory window size reported to the upper layer");
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic bool use_lut_mws;
278c2ecf20Sopenharmony_cimodule_param(use_lut_mws, bool, 0644);
288c2ecf20Sopenharmony_ciMODULE_PARM_DESC(use_lut_mws,
298c2ecf20Sopenharmony_ci		 "Enable the use of the LUT based memory windows");
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define SWITCHTEC_NTB_MAGIC 0x45CC0001
328c2ecf20Sopenharmony_ci#define MAX_MWS     128
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct shared_mw {
358c2ecf20Sopenharmony_ci	u32 magic;
368c2ecf20Sopenharmony_ci	u32 link_sta;
378c2ecf20Sopenharmony_ci	u32 partition_id;
388c2ecf20Sopenharmony_ci	u64 mw_sizes[MAX_MWS];
398c2ecf20Sopenharmony_ci	u32 spad[128];
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define MAX_DIRECT_MW ARRAY_SIZE(((struct ntb_ctrl_regs *)(0))->bar_entry)
438c2ecf20Sopenharmony_ci#define LUT_SIZE SZ_64K
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistruct switchtec_ntb {
468c2ecf20Sopenharmony_ci	struct ntb_dev ntb;
478c2ecf20Sopenharmony_ci	struct switchtec_dev *stdev;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	int self_partition;
508c2ecf20Sopenharmony_ci	int peer_partition;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	int doorbell_irq;
538c2ecf20Sopenharmony_ci	int message_irq;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	struct ntb_info_regs __iomem *mmio_ntb;
568c2ecf20Sopenharmony_ci	struct ntb_ctrl_regs __iomem *mmio_ctrl;
578c2ecf20Sopenharmony_ci	struct ntb_dbmsg_regs __iomem *mmio_dbmsg;
588c2ecf20Sopenharmony_ci	struct ntb_ctrl_regs __iomem *mmio_self_ctrl;
598c2ecf20Sopenharmony_ci	struct ntb_ctrl_regs __iomem *mmio_peer_ctrl;
608c2ecf20Sopenharmony_ci	struct ntb_dbmsg_regs __iomem *mmio_self_dbmsg;
618c2ecf20Sopenharmony_ci	struct ntb_dbmsg_regs __iomem *mmio_peer_dbmsg;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	void __iomem *mmio_xlink_win;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	struct shared_mw *self_shared;
668c2ecf20Sopenharmony_ci	struct shared_mw __iomem *peer_shared;
678c2ecf20Sopenharmony_ci	dma_addr_t self_shared_dma;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	u64 db_mask;
708c2ecf20Sopenharmony_ci	u64 db_valid_mask;
718c2ecf20Sopenharmony_ci	int db_shift;
728c2ecf20Sopenharmony_ci	int db_peer_shift;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/* synchronize rmw access of db_mask and hw reg */
758c2ecf20Sopenharmony_ci	spinlock_t db_mask_lock;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	int nr_direct_mw;
788c2ecf20Sopenharmony_ci	int nr_lut_mw;
798c2ecf20Sopenharmony_ci	int nr_rsvd_luts;
808c2ecf20Sopenharmony_ci	int direct_mw_to_bar[MAX_DIRECT_MW];
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	int peer_nr_direct_mw;
838c2ecf20Sopenharmony_ci	int peer_nr_lut_mw;
848c2ecf20Sopenharmony_ci	int peer_direct_mw_to_bar[MAX_DIRECT_MW];
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	bool link_is_up;
878c2ecf20Sopenharmony_ci	enum ntb_speed link_speed;
888c2ecf20Sopenharmony_ci	enum ntb_width link_width;
898c2ecf20Sopenharmony_ci	struct work_struct check_link_status_work;
908c2ecf20Sopenharmony_ci	bool link_force_down;
918c2ecf20Sopenharmony_ci};
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	return container_of(ntb, struct switchtec_ntb, ntb);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int switchtec_ntb_part_op(struct switchtec_ntb *sndev,
998c2ecf20Sopenharmony_ci				 struct ntb_ctrl_regs __iomem *ctl,
1008c2ecf20Sopenharmony_ci				 u32 op, int wait_status)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	static const char * const op_text[] = {
1038c2ecf20Sopenharmony_ci		[NTB_CTRL_PART_OP_LOCK] = "lock",
1048c2ecf20Sopenharmony_ci		[NTB_CTRL_PART_OP_CFG] = "configure",
1058c2ecf20Sopenharmony_ci		[NTB_CTRL_PART_OP_RESET] = "reset",
1068c2ecf20Sopenharmony_ci	};
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	int i;
1098c2ecf20Sopenharmony_ci	u32 ps;
1108c2ecf20Sopenharmony_ci	int status;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	switch (op) {
1138c2ecf20Sopenharmony_ci	case NTB_CTRL_PART_OP_LOCK:
1148c2ecf20Sopenharmony_ci		status = NTB_CTRL_PART_STATUS_LOCKING;
1158c2ecf20Sopenharmony_ci		break;
1168c2ecf20Sopenharmony_ci	case NTB_CTRL_PART_OP_CFG:
1178c2ecf20Sopenharmony_ci		status = NTB_CTRL_PART_STATUS_CONFIGURING;
1188c2ecf20Sopenharmony_ci		break;
1198c2ecf20Sopenharmony_ci	case NTB_CTRL_PART_OP_RESET:
1208c2ecf20Sopenharmony_ci		status = NTB_CTRL_PART_STATUS_RESETTING;
1218c2ecf20Sopenharmony_ci		break;
1228c2ecf20Sopenharmony_ci	default:
1238c2ecf20Sopenharmony_ci		return -EINVAL;
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	iowrite32(op, &ctl->partition_op);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	for (i = 0; i < 1000; i++) {
1298c2ecf20Sopenharmony_ci		if (msleep_interruptible(50) != 0) {
1308c2ecf20Sopenharmony_ci			iowrite32(NTB_CTRL_PART_OP_RESET, &ctl->partition_op);
1318c2ecf20Sopenharmony_ci			return -EINTR;
1328c2ecf20Sopenharmony_ci		}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci		ps = ioread32(&ctl->partition_status) & 0xFFFF;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci		if (ps != status)
1378c2ecf20Sopenharmony_ci			break;
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (ps == wait_status)
1418c2ecf20Sopenharmony_ci		return 0;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	if (ps == status) {
1448c2ecf20Sopenharmony_ci		dev_err(&sndev->stdev->dev,
1458c2ecf20Sopenharmony_ci			"Timed out while performing %s (%d). (%08x)\n",
1468c2ecf20Sopenharmony_ci			op_text[op], op,
1478c2ecf20Sopenharmony_ci			ioread32(&ctl->partition_status));
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	return -EIO;
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic int switchtec_ntb_send_msg(struct switchtec_ntb *sndev, int idx,
1568c2ecf20Sopenharmony_ci				  u32 val)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	if (idx < 0 || idx >= ARRAY_SIZE(sndev->mmio_peer_dbmsg->omsg))
1598c2ecf20Sopenharmony_ci		return -EINVAL;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	iowrite32(val, &sndev->mmio_peer_dbmsg->omsg[idx].msg);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	return 0;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
1698c2ecf20Sopenharmony_ci	int nr_direct_mw = sndev->peer_nr_direct_mw;
1708c2ecf20Sopenharmony_ci	int nr_lut_mw = sndev->peer_nr_lut_mw - sndev->nr_rsvd_luts;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	if (pidx != NTB_DEF_PEER_IDX)
1738c2ecf20Sopenharmony_ci		return -EINVAL;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (!use_lut_mws)
1768c2ecf20Sopenharmony_ci		nr_lut_mw = 0;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	return nr_direct_mw + nr_lut_mw;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic int lut_index(struct switchtec_ntb *sndev, int mw_idx)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	return mw_idx - sndev->nr_direct_mw + sndev->nr_rsvd_luts;
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic int peer_lut_index(struct switchtec_ntb *sndev, int mw_idx)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	return mw_idx - sndev->peer_nr_direct_mw + sndev->nr_rsvd_luts;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx,
1928c2ecf20Sopenharmony_ci				      int widx, resource_size_t *addr_align,
1938c2ecf20Sopenharmony_ci				      resource_size_t *size_align,
1948c2ecf20Sopenharmony_ci				      resource_size_t *size_max)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
1978c2ecf20Sopenharmony_ci	int lut;
1988c2ecf20Sopenharmony_ci	resource_size_t size;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (pidx != NTB_DEF_PEER_IDX)
2018c2ecf20Sopenharmony_ci		return -EINVAL;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	lut = widx >= sndev->peer_nr_direct_mw;
2048c2ecf20Sopenharmony_ci	size = ioread64(&sndev->peer_shared->mw_sizes[widx]);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	if (size == 0)
2078c2ecf20Sopenharmony_ci		return -EINVAL;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if (addr_align)
2108c2ecf20Sopenharmony_ci		*addr_align = lut ? size : SZ_4K;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if (size_align)
2138c2ecf20Sopenharmony_ci		*size_align = lut ? size : SZ_4K;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	if (size_max)
2168c2ecf20Sopenharmony_ci		*size_max = size;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return 0;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic void switchtec_ntb_mw_clr_direct(struct switchtec_ntb *sndev, int idx)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
2248c2ecf20Sopenharmony_ci	int bar = sndev->peer_direct_mw_to_bar[idx];
2258c2ecf20Sopenharmony_ci	u32 ctl_val;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	ctl_val = ioread32(&ctl->bar_entry[bar].ctl);
2288c2ecf20Sopenharmony_ci	ctl_val &= ~NTB_CTRL_BAR_DIR_WIN_EN;
2298c2ecf20Sopenharmony_ci	iowrite32(ctl_val, &ctl->bar_entry[bar].ctl);
2308c2ecf20Sopenharmony_ci	iowrite32(0, &ctl->bar_entry[bar].win_size);
2318c2ecf20Sopenharmony_ci	iowrite32(0, &ctl->bar_ext_entry[bar].win_size);
2328c2ecf20Sopenharmony_ci	iowrite64(sndev->self_partition, &ctl->bar_entry[bar].xlate_addr);
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic void switchtec_ntb_mw_clr_lut(struct switchtec_ntb *sndev, int idx)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	iowrite64(0, &ctl->lut_entry[peer_lut_index(sndev, idx)]);
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic void switchtec_ntb_mw_set_direct(struct switchtec_ntb *sndev, int idx,
2438c2ecf20Sopenharmony_ci					dma_addr_t addr, resource_size_t size)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	int xlate_pos = ilog2(size);
2468c2ecf20Sopenharmony_ci	int bar = sndev->peer_direct_mw_to_bar[idx];
2478c2ecf20Sopenharmony_ci	struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
2488c2ecf20Sopenharmony_ci	u32 ctl_val;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	ctl_val = ioread32(&ctl->bar_entry[bar].ctl);
2518c2ecf20Sopenharmony_ci	ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	iowrite32(ctl_val, &ctl->bar_entry[bar].ctl);
2548c2ecf20Sopenharmony_ci	iowrite32(xlate_pos | (lower_32_bits(size) & 0xFFFFF000),
2558c2ecf20Sopenharmony_ci		  &ctl->bar_entry[bar].win_size);
2568c2ecf20Sopenharmony_ci	iowrite32(upper_32_bits(size), &ctl->bar_ext_entry[bar].win_size);
2578c2ecf20Sopenharmony_ci	iowrite64(sndev->self_partition | addr,
2588c2ecf20Sopenharmony_ci		  &ctl->bar_entry[bar].xlate_addr);
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic void switchtec_ntb_mw_set_lut(struct switchtec_ntb *sndev, int idx,
2628c2ecf20Sopenharmony_ci				     dma_addr_t addr, resource_size_t size)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) | addr),
2678c2ecf20Sopenharmony_ci		  &ctl->lut_entry[peer_lut_index(sndev, idx)]);
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
2718c2ecf20Sopenharmony_ci				      dma_addr_t addr, resource_size_t size)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
2748c2ecf20Sopenharmony_ci	struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
2758c2ecf20Sopenharmony_ci	int xlate_pos = ilog2(size);
2768c2ecf20Sopenharmony_ci	int nr_direct_mw = sndev->peer_nr_direct_mw;
2778c2ecf20Sopenharmony_ci	int rc;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (pidx != NTB_DEF_PEER_IDX)
2808c2ecf20Sopenharmony_ci		return -EINVAL;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	dev_dbg(&sndev->stdev->dev, "MW %d: part %d addr %pad size %pap\n",
2838c2ecf20Sopenharmony_ci		widx, pidx, &addr, &size);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	if (widx >= switchtec_ntb_mw_count(ntb, pidx))
2868c2ecf20Sopenharmony_ci		return -EINVAL;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (size != 0 && xlate_pos < 12)
2898c2ecf20Sopenharmony_ci		return -EINVAL;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (!IS_ALIGNED(addr, BIT_ULL(xlate_pos))) {
2928c2ecf20Sopenharmony_ci		/*
2938c2ecf20Sopenharmony_ci		 * In certain circumstances we can get a buffer that is
2948c2ecf20Sopenharmony_ci		 * not aligned to its size. (Most of the time
2958c2ecf20Sopenharmony_ci		 * dma_alloc_coherent ensures this). This can happen when
2968c2ecf20Sopenharmony_ci		 * using large buffers allocated by the CMA
2978c2ecf20Sopenharmony_ci		 * (see CMA_CONFIG_ALIGNMENT)
2988c2ecf20Sopenharmony_ci		 */
2998c2ecf20Sopenharmony_ci		dev_err(&sndev->stdev->dev,
3008c2ecf20Sopenharmony_ci			"ERROR: Memory window address is not aligned to it's size!\n");
3018c2ecf20Sopenharmony_ci		return -EINVAL;
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK,
3058c2ecf20Sopenharmony_ci				   NTB_CTRL_PART_STATUS_LOCKED);
3068c2ecf20Sopenharmony_ci	if (rc)
3078c2ecf20Sopenharmony_ci		return rc;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	if (size == 0) {
3108c2ecf20Sopenharmony_ci		if (widx < nr_direct_mw)
3118c2ecf20Sopenharmony_ci			switchtec_ntb_mw_clr_direct(sndev, widx);
3128c2ecf20Sopenharmony_ci		else
3138c2ecf20Sopenharmony_ci			switchtec_ntb_mw_clr_lut(sndev, widx);
3148c2ecf20Sopenharmony_ci	} else {
3158c2ecf20Sopenharmony_ci		if (widx < nr_direct_mw)
3168c2ecf20Sopenharmony_ci			switchtec_ntb_mw_set_direct(sndev, widx, addr, size);
3178c2ecf20Sopenharmony_ci		else
3188c2ecf20Sopenharmony_ci			switchtec_ntb_mw_set_lut(sndev, widx, addr, size);
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG,
3228c2ecf20Sopenharmony_ci				   NTB_CTRL_PART_STATUS_NORMAL);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	if (rc == -EIO) {
3258c2ecf20Sopenharmony_ci		dev_err(&sndev->stdev->dev,
3268c2ecf20Sopenharmony_ci			"Hardware reported an error configuring mw %d: %08x\n",
3278c2ecf20Sopenharmony_ci			widx, ioread32(&ctl->bar_error));
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci		if (widx < nr_direct_mw)
3308c2ecf20Sopenharmony_ci			switchtec_ntb_mw_clr_direct(sndev, widx);
3318c2ecf20Sopenharmony_ci		else
3328c2ecf20Sopenharmony_ci			switchtec_ntb_mw_clr_lut(sndev, widx);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci		switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG,
3358c2ecf20Sopenharmony_ci				      NTB_CTRL_PART_STATUS_NORMAL);
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	return rc;
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic int switchtec_ntb_peer_mw_count(struct ntb_dev *ntb)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
3448c2ecf20Sopenharmony_ci	int nr_lut_mw = sndev->nr_lut_mw - sndev->nr_rsvd_luts;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return sndev->nr_direct_mw + (use_lut_mws ? nr_lut_mw : 0);
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int switchtec_ntb_direct_get_addr(struct switchtec_ntb *sndev,
3508c2ecf20Sopenharmony_ci					 int idx, phys_addr_t *base,
3518c2ecf20Sopenharmony_ci					 resource_size_t *size)
3528c2ecf20Sopenharmony_ci{
3538c2ecf20Sopenharmony_ci	int bar = sndev->direct_mw_to_bar[idx];
3548c2ecf20Sopenharmony_ci	size_t offset = 0;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (bar < 0)
3578c2ecf20Sopenharmony_ci		return -EINVAL;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (idx == 0) {
3608c2ecf20Sopenharmony_ci		/*
3618c2ecf20Sopenharmony_ci		 * This is the direct BAR shared with the LUTs
3628c2ecf20Sopenharmony_ci		 * which means the actual window will be offset
3638c2ecf20Sopenharmony_ci		 * by the size of all the LUT entries.
3648c2ecf20Sopenharmony_ci		 */
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci		offset = LUT_SIZE * sndev->nr_lut_mw;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if (base)
3708c2ecf20Sopenharmony_ci		*base = pci_resource_start(sndev->ntb.pdev, bar) + offset;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (size) {
3738c2ecf20Sopenharmony_ci		*size = pci_resource_len(sndev->ntb.pdev, bar) - offset;
3748c2ecf20Sopenharmony_ci		if (offset && *size > offset)
3758c2ecf20Sopenharmony_ci			*size = offset;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci		if (*size > max_mw_size)
3788c2ecf20Sopenharmony_ci			*size = max_mw_size;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	return 0;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cistatic int switchtec_ntb_lut_get_addr(struct switchtec_ntb *sndev,
3858c2ecf20Sopenharmony_ci				      int idx, phys_addr_t *base,
3868c2ecf20Sopenharmony_ci				      resource_size_t *size)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	int bar = sndev->direct_mw_to_bar[0];
3898c2ecf20Sopenharmony_ci	int offset;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	offset = LUT_SIZE * lut_index(sndev, idx);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	if (base)
3948c2ecf20Sopenharmony_ci		*base = pci_resource_start(sndev->ntb.pdev, bar) + offset;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (size)
3978c2ecf20Sopenharmony_ci		*size = LUT_SIZE;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	return 0;
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic int switchtec_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
4038c2ecf20Sopenharmony_ci					  phys_addr_t *base,
4048c2ecf20Sopenharmony_ci					  resource_size_t *size)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	if (idx < sndev->nr_direct_mw)
4098c2ecf20Sopenharmony_ci		return switchtec_ntb_direct_get_addr(sndev, idx, base, size);
4108c2ecf20Sopenharmony_ci	else if (idx < switchtec_ntb_peer_mw_count(ntb))
4118c2ecf20Sopenharmony_ci		return switchtec_ntb_lut_get_addr(sndev, idx, base, size);
4128c2ecf20Sopenharmony_ci	else
4138c2ecf20Sopenharmony_ci		return -EINVAL;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev,
4178c2ecf20Sopenharmony_ci					  int partition,
4188c2ecf20Sopenharmony_ci					  enum ntb_speed *speed,
4198c2ecf20Sopenharmony_ci					  enum ntb_width *width)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	struct switchtec_dev *stdev = sndev->stdev;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	u32 pff = ioread32(&stdev->mmio_part_cfg[partition].vep_pff_inst_id);
4248c2ecf20Sopenharmony_ci	u32 linksta = ioread32(&stdev->mmio_pff_csr[pff].pci_cap_region[13]);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	if (speed)
4278c2ecf20Sopenharmony_ci		*speed = (linksta >> 16) & 0xF;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	if (width)
4308c2ecf20Sopenharmony_ci		*width = (linksta >> 20) & 0x3F;
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic void switchtec_ntb_set_link_speed(struct switchtec_ntb *sndev)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	enum ntb_speed self_speed, peer_speed;
4368c2ecf20Sopenharmony_ci	enum ntb_width self_width, peer_width;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	if (!sndev->link_is_up) {
4398c2ecf20Sopenharmony_ci		sndev->link_speed = NTB_SPEED_NONE;
4408c2ecf20Sopenharmony_ci		sndev->link_width = NTB_WIDTH_NONE;
4418c2ecf20Sopenharmony_ci		return;
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	switchtec_ntb_part_link_speed(sndev, sndev->self_partition,
4458c2ecf20Sopenharmony_ci				      &self_speed, &self_width);
4468c2ecf20Sopenharmony_ci	switchtec_ntb_part_link_speed(sndev, sndev->peer_partition,
4478c2ecf20Sopenharmony_ci				      &peer_speed, &peer_width);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	sndev->link_speed = min(self_speed, peer_speed);
4508c2ecf20Sopenharmony_ci	sndev->link_width = min(self_width, peer_width);
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic int crosslink_is_enabled(struct switchtec_ntb *sndev)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	struct ntb_info_regs __iomem *inf = sndev->mmio_ntb;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	return ioread8(&inf->ntp_info[sndev->peer_partition].xlink_enabled);
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic void crosslink_init_dbmsgs(struct switchtec_ntb *sndev)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	int i;
4638c2ecf20Sopenharmony_ci	u32 msg_map = 0;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	if (!crosslink_is_enabled(sndev))
4668c2ecf20Sopenharmony_ci		return;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sndev->mmio_peer_dbmsg->imsg); i++) {
4698c2ecf20Sopenharmony_ci		int m = i | sndev->self_partition << 2;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci		msg_map |= m << i * 8;
4728c2ecf20Sopenharmony_ci	}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	iowrite32(msg_map, &sndev->mmio_peer_dbmsg->msg_map);
4758c2ecf20Sopenharmony_ci	iowrite64(sndev->db_valid_mask << sndev->db_peer_shift,
4768c2ecf20Sopenharmony_ci		  &sndev->mmio_peer_dbmsg->odb_mask);
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_cienum switchtec_msg {
4808c2ecf20Sopenharmony_ci	LINK_MESSAGE = 0,
4818c2ecf20Sopenharmony_ci	MSG_LINK_UP = 1,
4828c2ecf20Sopenharmony_ci	MSG_LINK_DOWN = 2,
4838c2ecf20Sopenharmony_ci	MSG_CHECK_LINK = 3,
4848c2ecf20Sopenharmony_ci	MSG_LINK_FORCE_DOWN = 4,
4858c2ecf20Sopenharmony_ci};
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_cistatic void switchtec_ntb_link_status_update(struct switchtec_ntb *sndev)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	int link_sta;
4928c2ecf20Sopenharmony_ci	int old = sndev->link_is_up;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	link_sta = sndev->self_shared->link_sta;
4958c2ecf20Sopenharmony_ci	if (link_sta) {
4968c2ecf20Sopenharmony_ci		u64 peer = ioread64(&sndev->peer_shared->magic);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci		if ((peer & 0xFFFFFFFF) == SWITCHTEC_NTB_MAGIC)
4998c2ecf20Sopenharmony_ci			link_sta = peer >> 32;
5008c2ecf20Sopenharmony_ci		else
5018c2ecf20Sopenharmony_ci			link_sta = 0;
5028c2ecf20Sopenharmony_ci	}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	sndev->link_is_up = link_sta;
5058c2ecf20Sopenharmony_ci	switchtec_ntb_set_link_speed(sndev);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	if (link_sta != old) {
5088c2ecf20Sopenharmony_ci		switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_CHECK_LINK);
5098c2ecf20Sopenharmony_ci		ntb_link_event(&sndev->ntb);
5108c2ecf20Sopenharmony_ci		dev_info(&sndev->stdev->dev, "ntb link %s\n",
5118c2ecf20Sopenharmony_ci			 link_sta ? "up" : "down");
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		if (link_sta)
5148c2ecf20Sopenharmony_ci			crosslink_init_dbmsgs(sndev);
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic void check_link_status_work(struct work_struct *work)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	sndev = container_of(work, struct switchtec_ntb,
5238c2ecf20Sopenharmony_ci			     check_link_status_work);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	if (sndev->link_force_down) {
5268c2ecf20Sopenharmony_ci		sndev->link_force_down = false;
5278c2ecf20Sopenharmony_ci		switchtec_ntb_reinit_peer(sndev);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci		if (sndev->link_is_up) {
5308c2ecf20Sopenharmony_ci			sndev->link_is_up = 0;
5318c2ecf20Sopenharmony_ci			ntb_link_event(&sndev->ntb);
5328c2ecf20Sopenharmony_ci			dev_info(&sndev->stdev->dev, "ntb link forced down\n");
5338c2ecf20Sopenharmony_ci		}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci		return;
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	switchtec_ntb_link_status_update(sndev);
5398c2ecf20Sopenharmony_ci}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_cistatic void switchtec_ntb_check_link(struct switchtec_ntb *sndev,
5428c2ecf20Sopenharmony_ci				      enum switchtec_msg msg)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	if (msg == MSG_LINK_FORCE_DOWN)
5458c2ecf20Sopenharmony_ci		sndev->link_force_down = true;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	schedule_work(&sndev->check_link_status_work);
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_cistatic void switchtec_ntb_link_notification(struct switchtec_dev *stdev)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = stdev->sndev;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	switchtec_ntb_check_link(sndev, MSG_CHECK_LINK);
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistatic u64 switchtec_ntb_link_is_up(struct ntb_dev *ntb,
5588c2ecf20Sopenharmony_ci				    enum ntb_speed *speed,
5598c2ecf20Sopenharmony_ci				    enum ntb_width *width)
5608c2ecf20Sopenharmony_ci{
5618c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	if (speed)
5648c2ecf20Sopenharmony_ci		*speed = sndev->link_speed;
5658c2ecf20Sopenharmony_ci	if (width)
5668c2ecf20Sopenharmony_ci		*width = sndev->link_width;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	return sndev->link_is_up;
5698c2ecf20Sopenharmony_ci}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_cistatic int switchtec_ntb_link_enable(struct ntb_dev *ntb,
5728c2ecf20Sopenharmony_ci				     enum ntb_speed max_speed,
5738c2ecf20Sopenharmony_ci				     enum ntb_width max_width)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	dev_dbg(&sndev->stdev->dev, "enabling link\n");
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	sndev->self_shared->link_sta = 1;
5808c2ecf20Sopenharmony_ci	switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	switchtec_ntb_link_status_update(sndev);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	return 0;
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_cistatic int switchtec_ntb_link_disable(struct ntb_dev *ntb)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	dev_dbg(&sndev->stdev->dev, "disabling link\n");
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	sndev->self_shared->link_sta = 0;
5948c2ecf20Sopenharmony_ci	switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_DOWN);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	switchtec_ntb_link_status_update(sndev);
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	return 0;
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic u64 switchtec_ntb_db_valid_mask(struct ntb_dev *ntb)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	return sndev->db_valid_mask;
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic int switchtec_ntb_db_vector_count(struct ntb_dev *ntb)
6098c2ecf20Sopenharmony_ci{
6108c2ecf20Sopenharmony_ci	return 1;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic u64 switchtec_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector)
6148c2ecf20Sopenharmony_ci{
6158c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	if (db_vector < 0 || db_vector > 1)
6188c2ecf20Sopenharmony_ci		return 0;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	return sndev->db_valid_mask;
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_cistatic u64 switchtec_ntb_db_read(struct ntb_dev *ntb)
6248c2ecf20Sopenharmony_ci{
6258c2ecf20Sopenharmony_ci	u64 ret;
6268c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	ret = ioread64(&sndev->mmio_self_dbmsg->idb) >> sndev->db_shift;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	return ret & sndev->db_valid_mask;
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cistatic int switchtec_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	iowrite64(db_bits << sndev->db_shift, &sndev->mmio_self_dbmsg->idb);
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	return 0;
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic int switchtec_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	unsigned long irqflags;
6458c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	if (db_bits & ~sndev->db_valid_mask)
6488c2ecf20Sopenharmony_ci		return -EINVAL;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sndev->db_mask_lock, irqflags);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	sndev->db_mask |= db_bits << sndev->db_shift;
6538c2ecf20Sopenharmony_ci	iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags);
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	return 0;
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic int switchtec_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
6618c2ecf20Sopenharmony_ci{
6628c2ecf20Sopenharmony_ci	unsigned long irqflags;
6638c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	if (db_bits & ~sndev->db_valid_mask)
6668c2ecf20Sopenharmony_ci		return -EINVAL;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sndev->db_mask_lock, irqflags);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	sndev->db_mask &= ~(db_bits << sndev->db_shift);
6718c2ecf20Sopenharmony_ci	iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	return 0;
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_cistatic u64 switchtec_ntb_db_read_mask(struct ntb_dev *ntb)
6798c2ecf20Sopenharmony_ci{
6808c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	return (sndev->db_mask >> sndev->db_shift) & sndev->db_valid_mask;
6838c2ecf20Sopenharmony_ci}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_cistatic int switchtec_ntb_peer_db_addr(struct ntb_dev *ntb,
6868c2ecf20Sopenharmony_ci				      phys_addr_t *db_addr,
6878c2ecf20Sopenharmony_ci				      resource_size_t *db_size,
6888c2ecf20Sopenharmony_ci				      u64 *db_data,
6898c2ecf20Sopenharmony_ci				      int db_bit)
6908c2ecf20Sopenharmony_ci{
6918c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
6928c2ecf20Sopenharmony_ci	unsigned long offset;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	if (unlikely(db_bit >= BITS_PER_LONG_LONG))
6958c2ecf20Sopenharmony_ci		return -EINVAL;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	offset = (unsigned long)sndev->mmio_peer_dbmsg->odb -
6988c2ecf20Sopenharmony_ci		(unsigned long)sndev->stdev->mmio;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	offset += sndev->db_shift / 8;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	if (db_addr)
7038c2ecf20Sopenharmony_ci		*db_addr = pci_resource_start(ntb->pdev, 0) + offset;
7048c2ecf20Sopenharmony_ci	if (db_size)
7058c2ecf20Sopenharmony_ci		*db_size = sizeof(u32);
7068c2ecf20Sopenharmony_ci	if (db_data)
7078c2ecf20Sopenharmony_ci		*db_data = BIT_ULL(db_bit) << sndev->db_peer_shift;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	return 0;
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic int switchtec_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
7138c2ecf20Sopenharmony_ci{
7148c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	iowrite64(db_bits << sndev->db_peer_shift,
7178c2ecf20Sopenharmony_ci		  &sndev->mmio_peer_dbmsg->odb);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	return 0;
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_cistatic int switchtec_ntb_spad_count(struct ntb_dev *ntb)
7238c2ecf20Sopenharmony_ci{
7248c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	return ARRAY_SIZE(sndev->self_shared->spad);
7278c2ecf20Sopenharmony_ci}
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_cistatic u32 switchtec_ntb_spad_read(struct ntb_dev *ntb, int idx)
7308c2ecf20Sopenharmony_ci{
7318c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad))
7348c2ecf20Sopenharmony_ci		return 0;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	if (!sndev->self_shared)
7378c2ecf20Sopenharmony_ci		return 0;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	return sndev->self_shared->spad[idx];
7408c2ecf20Sopenharmony_ci}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_cistatic int switchtec_ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
7438c2ecf20Sopenharmony_ci{
7448c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad))
7478c2ecf20Sopenharmony_ci		return -EINVAL;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	if (!sndev->self_shared)
7508c2ecf20Sopenharmony_ci		return -EIO;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	sndev->self_shared->spad[idx] = val;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	return 0;
7558c2ecf20Sopenharmony_ci}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_cistatic u32 switchtec_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx,
7588c2ecf20Sopenharmony_ci					int sidx)
7598c2ecf20Sopenharmony_ci{
7608c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	if (pidx != NTB_DEF_PEER_IDX)
7638c2ecf20Sopenharmony_ci		return -EINVAL;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad))
7668c2ecf20Sopenharmony_ci		return 0;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	if (!sndev->peer_shared)
7698c2ecf20Sopenharmony_ci		return 0;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	return ioread32(&sndev->peer_shared->spad[sidx]);
7728c2ecf20Sopenharmony_ci}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_cistatic int switchtec_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
7758c2ecf20Sopenharmony_ci					 int sidx, u32 val)
7768c2ecf20Sopenharmony_ci{
7778c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	if (pidx != NTB_DEF_PEER_IDX)
7808c2ecf20Sopenharmony_ci		return -EINVAL;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad))
7838c2ecf20Sopenharmony_ci		return -EINVAL;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	if (!sndev->peer_shared)
7868c2ecf20Sopenharmony_ci		return -EIO;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	iowrite32(val, &sndev->peer_shared->spad[sidx]);
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	return 0;
7918c2ecf20Sopenharmony_ci}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_cistatic int switchtec_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx,
7948c2ecf20Sopenharmony_ci					int sidx, phys_addr_t *spad_addr)
7958c2ecf20Sopenharmony_ci{
7968c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = ntb_sndev(ntb);
7978c2ecf20Sopenharmony_ci	unsigned long offset;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	if (pidx != NTB_DEF_PEER_IDX)
8008c2ecf20Sopenharmony_ci		return -EINVAL;
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	offset = (unsigned long)&sndev->peer_shared->spad[sidx] -
8038c2ecf20Sopenharmony_ci		(unsigned long)sndev->stdev->mmio;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	if (spad_addr)
8068c2ecf20Sopenharmony_ci		*spad_addr = pci_resource_start(ntb->pdev, 0) + offset;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	return 0;
8098c2ecf20Sopenharmony_ci}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_cistatic const struct ntb_dev_ops switchtec_ntb_ops = {
8128c2ecf20Sopenharmony_ci	.mw_count		= switchtec_ntb_mw_count,
8138c2ecf20Sopenharmony_ci	.mw_get_align		= switchtec_ntb_mw_get_align,
8148c2ecf20Sopenharmony_ci	.mw_set_trans		= switchtec_ntb_mw_set_trans,
8158c2ecf20Sopenharmony_ci	.peer_mw_count		= switchtec_ntb_peer_mw_count,
8168c2ecf20Sopenharmony_ci	.peer_mw_get_addr	= switchtec_ntb_peer_mw_get_addr,
8178c2ecf20Sopenharmony_ci	.link_is_up		= switchtec_ntb_link_is_up,
8188c2ecf20Sopenharmony_ci	.link_enable		= switchtec_ntb_link_enable,
8198c2ecf20Sopenharmony_ci	.link_disable		= switchtec_ntb_link_disable,
8208c2ecf20Sopenharmony_ci	.db_valid_mask		= switchtec_ntb_db_valid_mask,
8218c2ecf20Sopenharmony_ci	.db_vector_count	= switchtec_ntb_db_vector_count,
8228c2ecf20Sopenharmony_ci	.db_vector_mask		= switchtec_ntb_db_vector_mask,
8238c2ecf20Sopenharmony_ci	.db_read		= switchtec_ntb_db_read,
8248c2ecf20Sopenharmony_ci	.db_clear		= switchtec_ntb_db_clear,
8258c2ecf20Sopenharmony_ci	.db_set_mask		= switchtec_ntb_db_set_mask,
8268c2ecf20Sopenharmony_ci	.db_clear_mask		= switchtec_ntb_db_clear_mask,
8278c2ecf20Sopenharmony_ci	.db_read_mask		= switchtec_ntb_db_read_mask,
8288c2ecf20Sopenharmony_ci	.peer_db_addr		= switchtec_ntb_peer_db_addr,
8298c2ecf20Sopenharmony_ci	.peer_db_set		= switchtec_ntb_peer_db_set,
8308c2ecf20Sopenharmony_ci	.spad_count		= switchtec_ntb_spad_count,
8318c2ecf20Sopenharmony_ci	.spad_read		= switchtec_ntb_spad_read,
8328c2ecf20Sopenharmony_ci	.spad_write		= switchtec_ntb_spad_write,
8338c2ecf20Sopenharmony_ci	.peer_spad_read		= switchtec_ntb_peer_spad_read,
8348c2ecf20Sopenharmony_ci	.peer_spad_write	= switchtec_ntb_peer_spad_write,
8358c2ecf20Sopenharmony_ci	.peer_spad_addr		= switchtec_ntb_peer_spad_addr,
8368c2ecf20Sopenharmony_ci};
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_cistatic int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev)
8398c2ecf20Sopenharmony_ci{
8408c2ecf20Sopenharmony_ci	u64 tpart_vec;
8418c2ecf20Sopenharmony_ci	int self;
8428c2ecf20Sopenharmony_ci	u64 part_map;
8438c2ecf20Sopenharmony_ci	int bit;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	sndev->ntb.pdev = sndev->stdev->pdev;
8468c2ecf20Sopenharmony_ci	sndev->ntb.topo = NTB_TOPO_SWITCH;
8478c2ecf20Sopenharmony_ci	sndev->ntb.ops = &switchtec_ntb_ops;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	INIT_WORK(&sndev->check_link_status_work, check_link_status_work);
8508c2ecf20Sopenharmony_ci	sndev->link_force_down = false;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	sndev->self_partition = sndev->stdev->partition;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	sndev->mmio_ntb = sndev->stdev->mmio_ntb;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	self = sndev->self_partition;
8578c2ecf20Sopenharmony_ci	tpart_vec = ioread32(&sndev->mmio_ntb->ntp_info[self].target_part_high);
8588c2ecf20Sopenharmony_ci	tpart_vec <<= 32;
8598c2ecf20Sopenharmony_ci	tpart_vec |= ioread32(&sndev->mmio_ntb->ntp_info[self].target_part_low);
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	part_map = ioread64(&sndev->mmio_ntb->ep_map);
8628c2ecf20Sopenharmony_ci	part_map &= ~(1 << sndev->self_partition);
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	if (!ffs(tpart_vec)) {
8658c2ecf20Sopenharmony_ci		if (sndev->stdev->partition_count != 2) {
8668c2ecf20Sopenharmony_ci			dev_err(&sndev->stdev->dev,
8678c2ecf20Sopenharmony_ci				"ntb target partition not defined\n");
8688c2ecf20Sopenharmony_ci			return -ENODEV;
8698c2ecf20Sopenharmony_ci		}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci		bit = ffs(part_map);
8728c2ecf20Sopenharmony_ci		if (!bit) {
8738c2ecf20Sopenharmony_ci			dev_err(&sndev->stdev->dev,
8748c2ecf20Sopenharmony_ci				"peer partition is not NT partition\n");
8758c2ecf20Sopenharmony_ci			return -ENODEV;
8768c2ecf20Sopenharmony_ci		}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci		sndev->peer_partition = bit - 1;
8798c2ecf20Sopenharmony_ci	} else {
8808c2ecf20Sopenharmony_ci		if (ffs(tpart_vec) != fls(tpart_vec)) {
8818c2ecf20Sopenharmony_ci			dev_err(&sndev->stdev->dev,
8828c2ecf20Sopenharmony_ci				"ntb driver only supports 1 pair of 1-1 ntb mapping\n");
8838c2ecf20Sopenharmony_ci			return -ENODEV;
8848c2ecf20Sopenharmony_ci		}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci		sndev->peer_partition = ffs(tpart_vec) - 1;
8878c2ecf20Sopenharmony_ci		if (!(part_map & (1ULL << sndev->peer_partition))) {
8888c2ecf20Sopenharmony_ci			dev_err(&sndev->stdev->dev,
8898c2ecf20Sopenharmony_ci				"ntb target partition is not NT partition\n");
8908c2ecf20Sopenharmony_ci			return -ENODEV;
8918c2ecf20Sopenharmony_ci		}
8928c2ecf20Sopenharmony_ci	}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d\n",
8958c2ecf20Sopenharmony_ci		sndev->self_partition, sndev->stdev->partition_count);
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	sndev->mmio_ctrl = (void * __iomem)sndev->mmio_ntb +
8988c2ecf20Sopenharmony_ci		SWITCHTEC_NTB_REG_CTRL_OFFSET;
8998c2ecf20Sopenharmony_ci	sndev->mmio_dbmsg = (void * __iomem)sndev->mmio_ntb +
9008c2ecf20Sopenharmony_ci		SWITCHTEC_NTB_REG_DBMSG_OFFSET;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	sndev->mmio_self_ctrl = &sndev->mmio_ctrl[sndev->self_partition];
9038c2ecf20Sopenharmony_ci	sndev->mmio_peer_ctrl = &sndev->mmio_ctrl[sndev->peer_partition];
9048c2ecf20Sopenharmony_ci	sndev->mmio_self_dbmsg = &sndev->mmio_dbmsg[sndev->self_partition];
9058c2ecf20Sopenharmony_ci	sndev->mmio_peer_dbmsg = sndev->mmio_self_dbmsg;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	return 0;
9088c2ecf20Sopenharmony_ci}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_cistatic int config_rsvd_lut_win(struct switchtec_ntb *sndev,
9118c2ecf20Sopenharmony_ci			       struct ntb_ctrl_regs __iomem *ctl,
9128c2ecf20Sopenharmony_ci			       int lut_idx, int partition, u64 addr)
9138c2ecf20Sopenharmony_ci{
9148c2ecf20Sopenharmony_ci	int peer_bar = sndev->peer_direct_mw_to_bar[0];
9158c2ecf20Sopenharmony_ci	u32 ctl_val;
9168c2ecf20Sopenharmony_ci	int rc;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK,
9198c2ecf20Sopenharmony_ci				   NTB_CTRL_PART_STATUS_LOCKED);
9208c2ecf20Sopenharmony_ci	if (rc)
9218c2ecf20Sopenharmony_ci		return rc;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	ctl_val = ioread32(&ctl->bar_entry[peer_bar].ctl);
9248c2ecf20Sopenharmony_ci	ctl_val &= 0xFF;
9258c2ecf20Sopenharmony_ci	ctl_val |= NTB_CTRL_BAR_LUT_WIN_EN;
9268c2ecf20Sopenharmony_ci	ctl_val |= ilog2(LUT_SIZE) << 8;
9278c2ecf20Sopenharmony_ci	ctl_val |= (sndev->nr_lut_mw - 1) << 14;
9288c2ecf20Sopenharmony_ci	iowrite32(ctl_val, &ctl->bar_entry[peer_bar].ctl);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	iowrite64((NTB_CTRL_LUT_EN | (partition << 1) | addr),
9318c2ecf20Sopenharmony_ci		  &ctl->lut_entry[lut_idx]);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG,
9348c2ecf20Sopenharmony_ci				   NTB_CTRL_PART_STATUS_NORMAL);
9358c2ecf20Sopenharmony_ci	if (rc) {
9368c2ecf20Sopenharmony_ci		u32 bar_error, lut_error;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci		bar_error = ioread32(&ctl->bar_error);
9398c2ecf20Sopenharmony_ci		lut_error = ioread32(&ctl->lut_error);
9408c2ecf20Sopenharmony_ci		dev_err(&sndev->stdev->dev,
9418c2ecf20Sopenharmony_ci			"Error setting up reserved lut window: %08x / %08x\n",
9428c2ecf20Sopenharmony_ci			bar_error, lut_error);
9438c2ecf20Sopenharmony_ci		return rc;
9448c2ecf20Sopenharmony_ci	}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	return 0;
9478c2ecf20Sopenharmony_ci}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_cistatic int config_req_id_table(struct switchtec_ntb *sndev,
9508c2ecf20Sopenharmony_ci			       struct ntb_ctrl_regs __iomem *mmio_ctrl,
9518c2ecf20Sopenharmony_ci			       int *req_ids, int count)
9528c2ecf20Sopenharmony_ci{
9538c2ecf20Sopenharmony_ci	int i, rc = 0;
9548c2ecf20Sopenharmony_ci	u32 error;
9558c2ecf20Sopenharmony_ci	u32 proxy_id;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	if (ioread32(&mmio_ctrl->req_id_table_size) < count) {
9588c2ecf20Sopenharmony_ci		dev_err(&sndev->stdev->dev,
9598c2ecf20Sopenharmony_ci			"Not enough requester IDs available.\n");
9608c2ecf20Sopenharmony_ci		return -EFAULT;
9618c2ecf20Sopenharmony_ci	}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	rc = switchtec_ntb_part_op(sndev, mmio_ctrl,
9648c2ecf20Sopenharmony_ci				   NTB_CTRL_PART_OP_LOCK,
9658c2ecf20Sopenharmony_ci				   NTB_CTRL_PART_STATUS_LOCKED);
9668c2ecf20Sopenharmony_ci	if (rc)
9678c2ecf20Sopenharmony_ci		return rc;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	iowrite32(NTB_PART_CTRL_ID_PROT_DIS,
9708c2ecf20Sopenharmony_ci		  &mmio_ctrl->partition_ctrl);
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
9738c2ecf20Sopenharmony_ci		iowrite32(req_ids[i] << 16 | NTB_CTRL_REQ_ID_EN,
9748c2ecf20Sopenharmony_ci			  &mmio_ctrl->req_id_table[i]);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci		proxy_id = ioread32(&mmio_ctrl->req_id_table[i]);
9778c2ecf20Sopenharmony_ci		dev_dbg(&sndev->stdev->dev,
9788c2ecf20Sopenharmony_ci			"Requester ID %02X:%02X.%X -> BB:%02X.%X\n",
9798c2ecf20Sopenharmony_ci			req_ids[i] >> 8, (req_ids[i] >> 3) & 0x1F,
9808c2ecf20Sopenharmony_ci			req_ids[i] & 0x7, (proxy_id >> 4) & 0x1F,
9818c2ecf20Sopenharmony_ci			(proxy_id >> 1) & 0x7);
9828c2ecf20Sopenharmony_ci	}
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	rc = switchtec_ntb_part_op(sndev, mmio_ctrl,
9858c2ecf20Sopenharmony_ci				   NTB_CTRL_PART_OP_CFG,
9868c2ecf20Sopenharmony_ci				   NTB_CTRL_PART_STATUS_NORMAL);
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	if (rc == -EIO) {
9898c2ecf20Sopenharmony_ci		error = ioread32(&mmio_ctrl->req_id_error);
9908c2ecf20Sopenharmony_ci		dev_err(&sndev->stdev->dev,
9918c2ecf20Sopenharmony_ci			"Error setting up the requester ID table: %08x\n",
9928c2ecf20Sopenharmony_ci			error);
9938c2ecf20Sopenharmony_ci	}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	return 0;
9968c2ecf20Sopenharmony_ci}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic int crosslink_setup_mws(struct switchtec_ntb *sndev, int ntb_lut_idx,
9998c2ecf20Sopenharmony_ci			       u64 *mw_addrs, int mw_count)
10008c2ecf20Sopenharmony_ci{
10018c2ecf20Sopenharmony_ci	int rc, i;
10028c2ecf20Sopenharmony_ci	struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_self_ctrl;
10038c2ecf20Sopenharmony_ci	u64 addr;
10048c2ecf20Sopenharmony_ci	size_t size, offset;
10058c2ecf20Sopenharmony_ci	int bar;
10068c2ecf20Sopenharmony_ci	int xlate_pos;
10078c2ecf20Sopenharmony_ci	u32 ctl_val;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK,
10108c2ecf20Sopenharmony_ci				   NTB_CTRL_PART_STATUS_LOCKED);
10118c2ecf20Sopenharmony_ci	if (rc)
10128c2ecf20Sopenharmony_ci		return rc;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	for (i = 0; i < sndev->nr_lut_mw; i++) {
10158c2ecf20Sopenharmony_ci		if (i == ntb_lut_idx)
10168c2ecf20Sopenharmony_ci			continue;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci		addr = mw_addrs[0] + LUT_SIZE * i;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci		iowrite64((NTB_CTRL_LUT_EN | (sndev->peer_partition << 1) |
10218c2ecf20Sopenharmony_ci			   addr),
10228c2ecf20Sopenharmony_ci			  &ctl->lut_entry[i]);
10238c2ecf20Sopenharmony_ci	}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	sndev->nr_direct_mw = min_t(int, sndev->nr_direct_mw, mw_count);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	for (i = 0; i < sndev->nr_direct_mw; i++) {
10288c2ecf20Sopenharmony_ci		bar = sndev->direct_mw_to_bar[i];
10298c2ecf20Sopenharmony_ci		offset = (i == 0) ? LUT_SIZE * sndev->nr_lut_mw : 0;
10308c2ecf20Sopenharmony_ci		addr = mw_addrs[i] + offset;
10318c2ecf20Sopenharmony_ci		size = pci_resource_len(sndev->ntb.pdev, bar) - offset;
10328c2ecf20Sopenharmony_ci		xlate_pos = ilog2(size);
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci		if (offset && size > offset)
10358c2ecf20Sopenharmony_ci			size = offset;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci		ctl_val = ioread32(&ctl->bar_entry[bar].ctl);
10388c2ecf20Sopenharmony_ci		ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci		iowrite32(ctl_val, &ctl->bar_entry[bar].ctl);
10418c2ecf20Sopenharmony_ci		iowrite32(xlate_pos | (lower_32_bits(size) & 0xFFFFF000),
10428c2ecf20Sopenharmony_ci			  &ctl->bar_entry[bar].win_size);
10438c2ecf20Sopenharmony_ci		iowrite32(upper_32_bits(size), &ctl->bar_ext_entry[bar].win_size);
10448c2ecf20Sopenharmony_ci		iowrite64(sndev->peer_partition | addr,
10458c2ecf20Sopenharmony_ci			  &ctl->bar_entry[bar].xlate_addr);
10468c2ecf20Sopenharmony_ci	}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG,
10498c2ecf20Sopenharmony_ci				   NTB_CTRL_PART_STATUS_NORMAL);
10508c2ecf20Sopenharmony_ci	if (rc) {
10518c2ecf20Sopenharmony_ci		u32 bar_error, lut_error;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci		bar_error = ioread32(&ctl->bar_error);
10548c2ecf20Sopenharmony_ci		lut_error = ioread32(&ctl->lut_error);
10558c2ecf20Sopenharmony_ci		dev_err(&sndev->stdev->dev,
10568c2ecf20Sopenharmony_ci			"Error setting up cross link windows: %08x / %08x\n",
10578c2ecf20Sopenharmony_ci			bar_error, lut_error);
10588c2ecf20Sopenharmony_ci		return rc;
10598c2ecf20Sopenharmony_ci	}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	return 0;
10628c2ecf20Sopenharmony_ci}
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_cistatic int crosslink_setup_req_ids(struct switchtec_ntb *sndev,
10658c2ecf20Sopenharmony_ci	struct ntb_ctrl_regs __iomem *mmio_ctrl)
10668c2ecf20Sopenharmony_ci{
10678c2ecf20Sopenharmony_ci	int req_ids[16];
10688c2ecf20Sopenharmony_ci	int i;
10698c2ecf20Sopenharmony_ci	u32 proxy_id;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(req_ids); i++) {
10728c2ecf20Sopenharmony_ci		proxy_id = ioread32(&sndev->mmio_self_ctrl->req_id_table[i]);
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci		if (!(proxy_id & NTB_CTRL_REQ_ID_EN))
10758c2ecf20Sopenharmony_ci			break;
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci		req_ids[i] = ((proxy_id >> 1) & 0xFF);
10788c2ecf20Sopenharmony_ci	}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	return config_req_id_table(sndev, mmio_ctrl, req_ids, i);
10818c2ecf20Sopenharmony_ci}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci/*
10848c2ecf20Sopenharmony_ci * In crosslink configuration there is a virtual partition in the
10858c2ecf20Sopenharmony_ci * middle of the two switches. The BARs in this partition have to be
10868c2ecf20Sopenharmony_ci * enumerated and assigned addresses.
10878c2ecf20Sopenharmony_ci */
10888c2ecf20Sopenharmony_cistatic int crosslink_enum_partition(struct switchtec_ntb *sndev,
10898c2ecf20Sopenharmony_ci				    u64 *bar_addrs)
10908c2ecf20Sopenharmony_ci{
10918c2ecf20Sopenharmony_ci	struct part_cfg_regs __iomem *part_cfg =
10928c2ecf20Sopenharmony_ci		&sndev->stdev->mmio_part_cfg_all[sndev->peer_partition];
10938c2ecf20Sopenharmony_ci	u32 pff = ioread32(&part_cfg->vep_pff_inst_id);
10948c2ecf20Sopenharmony_ci	struct pff_csr_regs __iomem *mmio_pff =
10958c2ecf20Sopenharmony_ci		&sndev->stdev->mmio_pff_csr[pff];
10968c2ecf20Sopenharmony_ci	const u64 bar_space = 0x1000000000LL;
10978c2ecf20Sopenharmony_ci	u64 bar_addr;
10988c2ecf20Sopenharmony_ci	int bar_cnt = 0;
10998c2ecf20Sopenharmony_ci	int i;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	iowrite16(0x6, &mmio_pff->pcicmd);
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mmio_pff->pci_bar64); i++) {
11048c2ecf20Sopenharmony_ci		iowrite64(bar_space * i, &mmio_pff->pci_bar64[i]);
11058c2ecf20Sopenharmony_ci		bar_addr = ioread64(&mmio_pff->pci_bar64[i]);
11068c2ecf20Sopenharmony_ci		bar_addr &= ~0xf;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci		dev_dbg(&sndev->stdev->dev,
11098c2ecf20Sopenharmony_ci			"Crosslink BAR%d addr: %llx\n",
11108c2ecf20Sopenharmony_ci			i*2, bar_addr);
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci		if (bar_addr != bar_space * i)
11138c2ecf20Sopenharmony_ci			continue;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci		bar_addrs[bar_cnt++] = bar_addr;
11168c2ecf20Sopenharmony_ci	}
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	return bar_cnt;
11198c2ecf20Sopenharmony_ci}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_cistatic int switchtec_ntb_init_crosslink(struct switchtec_ntb *sndev)
11228c2ecf20Sopenharmony_ci{
11238c2ecf20Sopenharmony_ci	int rc;
11248c2ecf20Sopenharmony_ci	int bar = sndev->direct_mw_to_bar[0];
11258c2ecf20Sopenharmony_ci	const int ntb_lut_idx = 1;
11268c2ecf20Sopenharmony_ci	u64 bar_addrs[6];
11278c2ecf20Sopenharmony_ci	u64 addr;
11288c2ecf20Sopenharmony_ci	int offset;
11298c2ecf20Sopenharmony_ci	int bar_cnt;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	if (!crosslink_is_enabled(sndev))
11328c2ecf20Sopenharmony_ci		return 0;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	dev_info(&sndev->stdev->dev, "Using crosslink configuration\n");
11358c2ecf20Sopenharmony_ci	sndev->ntb.topo = NTB_TOPO_CROSSLINK;
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	bar_cnt = crosslink_enum_partition(sndev, bar_addrs);
11388c2ecf20Sopenharmony_ci	if (bar_cnt < sndev->nr_direct_mw + 1) {
11398c2ecf20Sopenharmony_ci		dev_err(&sndev->stdev->dev,
11408c2ecf20Sopenharmony_ci			"Error enumerating crosslink partition\n");
11418c2ecf20Sopenharmony_ci		return -EINVAL;
11428c2ecf20Sopenharmony_ci	}
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	addr = (bar_addrs[0] + SWITCHTEC_GAS_NTB_OFFSET +
11458c2ecf20Sopenharmony_ci		SWITCHTEC_NTB_REG_DBMSG_OFFSET +
11468c2ecf20Sopenharmony_ci		sizeof(struct ntb_dbmsg_regs) * sndev->peer_partition);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	offset = addr & (LUT_SIZE - 1);
11498c2ecf20Sopenharmony_ci	addr -= offset;
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	rc = config_rsvd_lut_win(sndev, sndev->mmio_self_ctrl, ntb_lut_idx,
11528c2ecf20Sopenharmony_ci				 sndev->peer_partition, addr);
11538c2ecf20Sopenharmony_ci	if (rc)
11548c2ecf20Sopenharmony_ci		return rc;
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	rc = crosslink_setup_mws(sndev, ntb_lut_idx, &bar_addrs[1],
11578c2ecf20Sopenharmony_ci				 bar_cnt - 1);
11588c2ecf20Sopenharmony_ci	if (rc)
11598c2ecf20Sopenharmony_ci		return rc;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	rc = crosslink_setup_req_ids(sndev, sndev->mmio_peer_ctrl);
11628c2ecf20Sopenharmony_ci	if (rc)
11638c2ecf20Sopenharmony_ci		return rc;
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	sndev->mmio_xlink_win = pci_iomap_range(sndev->stdev->pdev, bar,
11668c2ecf20Sopenharmony_ci						LUT_SIZE, LUT_SIZE);
11678c2ecf20Sopenharmony_ci	if (!sndev->mmio_xlink_win) {
11688c2ecf20Sopenharmony_ci		rc = -ENOMEM;
11698c2ecf20Sopenharmony_ci		return rc;
11708c2ecf20Sopenharmony_ci	}
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	sndev->mmio_peer_dbmsg = sndev->mmio_xlink_win + offset;
11738c2ecf20Sopenharmony_ci	sndev->nr_rsvd_luts++;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	crosslink_init_dbmsgs(sndev);
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	return 0;
11788c2ecf20Sopenharmony_ci}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_cistatic void switchtec_ntb_deinit_crosslink(struct switchtec_ntb *sndev)
11818c2ecf20Sopenharmony_ci{
11828c2ecf20Sopenharmony_ci	if (sndev->mmio_xlink_win)
11838c2ecf20Sopenharmony_ci		pci_iounmap(sndev->stdev->pdev, sndev->mmio_xlink_win);
11848c2ecf20Sopenharmony_ci}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_cistatic int map_bars(int *map, struct ntb_ctrl_regs __iomem *ctrl)
11878c2ecf20Sopenharmony_ci{
11888c2ecf20Sopenharmony_ci	int i;
11898c2ecf20Sopenharmony_ci	int cnt = 0;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ctrl->bar_entry); i++) {
11928c2ecf20Sopenharmony_ci		u32 r = ioread32(&ctrl->bar_entry[i].ctl);
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci		if (r & NTB_CTRL_BAR_VALID)
11958c2ecf20Sopenharmony_ci			map[cnt++] = i;
11968c2ecf20Sopenharmony_ci	}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	return cnt;
11998c2ecf20Sopenharmony_ci}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_cistatic void switchtec_ntb_init_mw(struct switchtec_ntb *sndev)
12028c2ecf20Sopenharmony_ci{
12038c2ecf20Sopenharmony_ci	sndev->nr_direct_mw = map_bars(sndev->direct_mw_to_bar,
12048c2ecf20Sopenharmony_ci				       sndev->mmio_self_ctrl);
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	sndev->nr_lut_mw = ioread16(&sndev->mmio_self_ctrl->lut_table_entries);
12078c2ecf20Sopenharmony_ci	sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw);
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	dev_dbg(&sndev->stdev->dev, "MWs: %d direct, %d lut\n",
12108c2ecf20Sopenharmony_ci		sndev->nr_direct_mw, sndev->nr_lut_mw);
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	sndev->peer_nr_direct_mw = map_bars(sndev->peer_direct_mw_to_bar,
12138c2ecf20Sopenharmony_ci					    sndev->mmio_peer_ctrl);
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	sndev->peer_nr_lut_mw =
12168c2ecf20Sopenharmony_ci		ioread16(&sndev->mmio_peer_ctrl->lut_table_entries);
12178c2ecf20Sopenharmony_ci	sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	dev_dbg(&sndev->stdev->dev, "Peer MWs: %d direct, %d lut\n",
12208c2ecf20Sopenharmony_ci		sndev->peer_nr_direct_mw, sndev->peer_nr_lut_mw);
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci/*
12258c2ecf20Sopenharmony_ci * There are 64 doorbells in the switch hardware but this is
12268c2ecf20Sopenharmony_ci * shared among all partitions. So we must split them in half
12278c2ecf20Sopenharmony_ci * (32 for each partition). However, the message interrupts are
12288c2ecf20Sopenharmony_ci * also shared with the top 4 doorbells so we just limit this to
12298c2ecf20Sopenharmony_ci * 28 doorbells per partition.
12308c2ecf20Sopenharmony_ci *
12318c2ecf20Sopenharmony_ci * In crosslink mode, each side has it's own dbmsg register so
12328c2ecf20Sopenharmony_ci * they can each use all 60 of the available doorbells.
12338c2ecf20Sopenharmony_ci */
12348c2ecf20Sopenharmony_cistatic void switchtec_ntb_init_db(struct switchtec_ntb *sndev)
12358c2ecf20Sopenharmony_ci{
12368c2ecf20Sopenharmony_ci	sndev->db_mask = 0x0FFFFFFFFFFFFFFFULL;
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	if (sndev->mmio_peer_dbmsg != sndev->mmio_self_dbmsg) {
12398c2ecf20Sopenharmony_ci		sndev->db_shift = 0;
12408c2ecf20Sopenharmony_ci		sndev->db_peer_shift = 0;
12418c2ecf20Sopenharmony_ci		sndev->db_valid_mask = sndev->db_mask;
12428c2ecf20Sopenharmony_ci	} else if (sndev->self_partition < sndev->peer_partition) {
12438c2ecf20Sopenharmony_ci		sndev->db_shift = 0;
12448c2ecf20Sopenharmony_ci		sndev->db_peer_shift = 32;
12458c2ecf20Sopenharmony_ci		sndev->db_valid_mask = 0x0FFFFFFF;
12468c2ecf20Sopenharmony_ci	} else {
12478c2ecf20Sopenharmony_ci		sndev->db_shift = 32;
12488c2ecf20Sopenharmony_ci		sndev->db_peer_shift = 0;
12498c2ecf20Sopenharmony_ci		sndev->db_valid_mask = 0x0FFFFFFF;
12508c2ecf20Sopenharmony_ci	}
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask);
12538c2ecf20Sopenharmony_ci	iowrite64(sndev->db_valid_mask << sndev->db_peer_shift,
12548c2ecf20Sopenharmony_ci		  &sndev->mmio_peer_dbmsg->odb_mask);
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	dev_dbg(&sndev->stdev->dev, "dbs: shift %d/%d, mask %016llx\n",
12578c2ecf20Sopenharmony_ci		sndev->db_shift, sndev->db_peer_shift, sndev->db_valid_mask);
12588c2ecf20Sopenharmony_ci}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_cistatic void switchtec_ntb_init_msgs(struct switchtec_ntb *sndev)
12618c2ecf20Sopenharmony_ci{
12628c2ecf20Sopenharmony_ci	int i;
12638c2ecf20Sopenharmony_ci	u32 msg_map = 0;
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) {
12668c2ecf20Sopenharmony_ci		int m = i | sndev->peer_partition << 2;
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci		msg_map |= m << i * 8;
12698c2ecf20Sopenharmony_ci	}
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	iowrite32(msg_map, &sndev->mmio_self_dbmsg->msg_map);
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++)
12748c2ecf20Sopenharmony_ci		iowrite64(NTB_DBMSG_IMSG_STATUS | NTB_DBMSG_IMSG_MASK,
12758c2ecf20Sopenharmony_ci			  &sndev->mmio_self_dbmsg->imsg[i]);
12768c2ecf20Sopenharmony_ci}
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_cistatic int
12798c2ecf20Sopenharmony_ciswitchtec_ntb_init_req_id_table(struct switchtec_ntb *sndev)
12808c2ecf20Sopenharmony_ci{
12818c2ecf20Sopenharmony_ci	int req_ids[2];
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	/*
12848c2ecf20Sopenharmony_ci	 * Root Complex Requester ID (which is 0:00.0)
12858c2ecf20Sopenharmony_ci	 */
12868c2ecf20Sopenharmony_ci	req_ids[0] = 0;
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	/*
12898c2ecf20Sopenharmony_ci	 * Host Bridge Requester ID (as read from the mmap address)
12908c2ecf20Sopenharmony_ci	 */
12918c2ecf20Sopenharmony_ci	req_ids[1] = ioread16(&sndev->mmio_ntb->requester_id);
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	return config_req_id_table(sndev, sndev->mmio_self_ctrl, req_ids,
12948c2ecf20Sopenharmony_ci				   ARRAY_SIZE(req_ids));
12958c2ecf20Sopenharmony_ci}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_cistatic void switchtec_ntb_init_shared(struct switchtec_ntb *sndev)
12988c2ecf20Sopenharmony_ci{
12998c2ecf20Sopenharmony_ci	int i;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	memset(sndev->self_shared, 0, LUT_SIZE);
13028c2ecf20Sopenharmony_ci	sndev->self_shared->magic = SWITCHTEC_NTB_MAGIC;
13038c2ecf20Sopenharmony_ci	sndev->self_shared->partition_id = sndev->stdev->partition;
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	for (i = 0; i < sndev->nr_direct_mw; i++) {
13068c2ecf20Sopenharmony_ci		int bar = sndev->direct_mw_to_bar[i];
13078c2ecf20Sopenharmony_ci		resource_size_t sz = pci_resource_len(sndev->stdev->pdev, bar);
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci		if (i == 0)
13108c2ecf20Sopenharmony_ci			sz = min_t(resource_size_t, sz,
13118c2ecf20Sopenharmony_ci				   LUT_SIZE * sndev->nr_lut_mw);
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci		sndev->self_shared->mw_sizes[i] = sz;
13148c2ecf20Sopenharmony_ci	}
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	for (i = 0; i < sndev->nr_lut_mw; i++) {
13178c2ecf20Sopenharmony_ci		int idx = sndev->nr_direct_mw + i;
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci		sndev->self_shared->mw_sizes[idx] = LUT_SIZE;
13208c2ecf20Sopenharmony_ci	}
13218c2ecf20Sopenharmony_ci}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_cistatic int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev)
13248c2ecf20Sopenharmony_ci{
13258c2ecf20Sopenharmony_ci	int self_bar = sndev->direct_mw_to_bar[0];
13268c2ecf20Sopenharmony_ci	int rc;
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	sndev->nr_rsvd_luts++;
13298c2ecf20Sopenharmony_ci	sndev->self_shared = dma_alloc_coherent(&sndev->stdev->pdev->dev,
13308c2ecf20Sopenharmony_ci						LUT_SIZE,
13318c2ecf20Sopenharmony_ci						&sndev->self_shared_dma,
13328c2ecf20Sopenharmony_ci						GFP_KERNEL);
13338c2ecf20Sopenharmony_ci	if (!sndev->self_shared) {
13348c2ecf20Sopenharmony_ci		dev_err(&sndev->stdev->dev,
13358c2ecf20Sopenharmony_ci			"unable to allocate memory for shared mw\n");
13368c2ecf20Sopenharmony_ci		return -ENOMEM;
13378c2ecf20Sopenharmony_ci	}
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	switchtec_ntb_init_shared(sndev);
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	rc = config_rsvd_lut_win(sndev, sndev->mmio_peer_ctrl, 0,
13428c2ecf20Sopenharmony_ci				 sndev->self_partition,
13438c2ecf20Sopenharmony_ci				 sndev->self_shared_dma);
13448c2ecf20Sopenharmony_ci	if (rc)
13458c2ecf20Sopenharmony_ci		goto unalloc_and_exit;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	sndev->peer_shared = pci_iomap(sndev->stdev->pdev, self_bar, LUT_SIZE);
13488c2ecf20Sopenharmony_ci	if (!sndev->peer_shared) {
13498c2ecf20Sopenharmony_ci		rc = -ENOMEM;
13508c2ecf20Sopenharmony_ci		goto unalloc_and_exit;
13518c2ecf20Sopenharmony_ci	}
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	dev_dbg(&sndev->stdev->dev, "Shared MW Ready\n");
13548c2ecf20Sopenharmony_ci	return 0;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ciunalloc_and_exit:
13578c2ecf20Sopenharmony_ci	dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE,
13588c2ecf20Sopenharmony_ci			  sndev->self_shared, sndev->self_shared_dma);
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	return rc;
13618c2ecf20Sopenharmony_ci}
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_cistatic void switchtec_ntb_deinit_shared_mw(struct switchtec_ntb *sndev)
13648c2ecf20Sopenharmony_ci{
13658c2ecf20Sopenharmony_ci	if (sndev->peer_shared)
13668c2ecf20Sopenharmony_ci		pci_iounmap(sndev->stdev->pdev, sndev->peer_shared);
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	if (sndev->self_shared)
13698c2ecf20Sopenharmony_ci		dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE,
13708c2ecf20Sopenharmony_ci				  sndev->self_shared,
13718c2ecf20Sopenharmony_ci				  sndev->self_shared_dma);
13728c2ecf20Sopenharmony_ci	sndev->nr_rsvd_luts--;
13738c2ecf20Sopenharmony_ci}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_cistatic irqreturn_t switchtec_ntb_doorbell_isr(int irq, void *dev)
13768c2ecf20Sopenharmony_ci{
13778c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = dev;
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	dev_dbg(&sndev->stdev->dev, "doorbell\n");
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	ntb_db_event(&sndev->ntb, 0);
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
13848c2ecf20Sopenharmony_ci}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_cistatic irqreturn_t switchtec_ntb_message_isr(int irq, void *dev)
13878c2ecf20Sopenharmony_ci{
13888c2ecf20Sopenharmony_ci	int i;
13898c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = dev;
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) {
13928c2ecf20Sopenharmony_ci		u64 msg = ioread64(&sndev->mmio_self_dbmsg->imsg[i]);
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci		if (msg & NTB_DBMSG_IMSG_STATUS) {
13958c2ecf20Sopenharmony_ci			dev_dbg(&sndev->stdev->dev, "message: %d %08x\n",
13968c2ecf20Sopenharmony_ci				i, (u32)msg);
13978c2ecf20Sopenharmony_ci			iowrite8(1, &sndev->mmio_self_dbmsg->imsg[i].status);
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci			if (i == LINK_MESSAGE)
14008c2ecf20Sopenharmony_ci				switchtec_ntb_check_link(sndev, msg);
14018c2ecf20Sopenharmony_ci		}
14028c2ecf20Sopenharmony_ci	}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
14058c2ecf20Sopenharmony_ci}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_cistatic int switchtec_ntb_init_db_msg_irq(struct switchtec_ntb *sndev)
14088c2ecf20Sopenharmony_ci{
14098c2ecf20Sopenharmony_ci	int i;
14108c2ecf20Sopenharmony_ci	int rc;
14118c2ecf20Sopenharmony_ci	int doorbell_irq = 0;
14128c2ecf20Sopenharmony_ci	int message_irq = 0;
14138c2ecf20Sopenharmony_ci	int event_irq;
14148c2ecf20Sopenharmony_ci	int idb_vecs = sizeof(sndev->mmio_self_dbmsg->idb_vec_map);
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	event_irq = ioread32(&sndev->stdev->mmio_part_cfg->vep_vector_number);
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	while (doorbell_irq == event_irq)
14198c2ecf20Sopenharmony_ci		doorbell_irq++;
14208c2ecf20Sopenharmony_ci	while (message_irq == doorbell_irq ||
14218c2ecf20Sopenharmony_ci	       message_irq == event_irq)
14228c2ecf20Sopenharmony_ci		message_irq++;
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	dev_dbg(&sndev->stdev->dev, "irqs - event: %d, db: %d, msgs: %d\n",
14258c2ecf20Sopenharmony_ci		event_irq, doorbell_irq, message_irq);
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	for (i = 0; i < idb_vecs - 4; i++)
14288c2ecf20Sopenharmony_ci		iowrite8(doorbell_irq,
14298c2ecf20Sopenharmony_ci			 &sndev->mmio_self_dbmsg->idb_vec_map[i]);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	for (; i < idb_vecs; i++)
14328c2ecf20Sopenharmony_ci		iowrite8(message_irq,
14338c2ecf20Sopenharmony_ci			 &sndev->mmio_self_dbmsg->idb_vec_map[i]);
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	sndev->doorbell_irq = pci_irq_vector(sndev->stdev->pdev, doorbell_irq);
14368c2ecf20Sopenharmony_ci	sndev->message_irq = pci_irq_vector(sndev->stdev->pdev, message_irq);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	rc = request_irq(sndev->doorbell_irq,
14398c2ecf20Sopenharmony_ci			 switchtec_ntb_doorbell_isr, 0,
14408c2ecf20Sopenharmony_ci			 "switchtec_ntb_doorbell", sndev);
14418c2ecf20Sopenharmony_ci	if (rc)
14428c2ecf20Sopenharmony_ci		return rc;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	rc = request_irq(sndev->message_irq,
14458c2ecf20Sopenharmony_ci			 switchtec_ntb_message_isr, 0,
14468c2ecf20Sopenharmony_ci			 "switchtec_ntb_message", sndev);
14478c2ecf20Sopenharmony_ci	if (rc) {
14488c2ecf20Sopenharmony_ci		free_irq(sndev->doorbell_irq, sndev);
14498c2ecf20Sopenharmony_ci		return rc;
14508c2ecf20Sopenharmony_ci	}
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	return 0;
14538c2ecf20Sopenharmony_ci}
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_cistatic void switchtec_ntb_deinit_db_msg_irq(struct switchtec_ntb *sndev)
14568c2ecf20Sopenharmony_ci{
14578c2ecf20Sopenharmony_ci	free_irq(sndev->doorbell_irq, sndev);
14588c2ecf20Sopenharmony_ci	free_irq(sndev->message_irq, sndev);
14598c2ecf20Sopenharmony_ci}
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_cistatic int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev)
14628c2ecf20Sopenharmony_ci{
14638c2ecf20Sopenharmony_ci	int rc;
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	if (crosslink_is_enabled(sndev))
14668c2ecf20Sopenharmony_ci		return 0;
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	dev_info(&sndev->stdev->dev, "reinitialize shared memory window\n");
14698c2ecf20Sopenharmony_ci	rc = config_rsvd_lut_win(sndev, sndev->mmio_peer_ctrl, 0,
14708c2ecf20Sopenharmony_ci				 sndev->self_partition,
14718c2ecf20Sopenharmony_ci				 sndev->self_shared_dma);
14728c2ecf20Sopenharmony_ci	return rc;
14738c2ecf20Sopenharmony_ci}
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_cistatic int switchtec_ntb_add(struct device *dev,
14768c2ecf20Sopenharmony_ci			     struct class_interface *class_intf)
14778c2ecf20Sopenharmony_ci{
14788c2ecf20Sopenharmony_ci	struct switchtec_dev *stdev = to_stdev(dev);
14798c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev;
14808c2ecf20Sopenharmony_ci	int rc;
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	stdev->sndev = NULL;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	if (stdev->pdev->class != (PCI_CLASS_BRIDGE_OTHER << 8))
14858c2ecf20Sopenharmony_ci		return -ENODEV;
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev));
14888c2ecf20Sopenharmony_ci	if (!sndev)
14898c2ecf20Sopenharmony_ci		return -ENOMEM;
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	sndev->stdev = stdev;
14928c2ecf20Sopenharmony_ci	rc = switchtec_ntb_init_sndev(sndev);
14938c2ecf20Sopenharmony_ci	if (rc)
14948c2ecf20Sopenharmony_ci		goto free_and_exit;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	switchtec_ntb_init_mw(sndev);
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	rc = switchtec_ntb_init_req_id_table(sndev);
14998c2ecf20Sopenharmony_ci	if (rc)
15008c2ecf20Sopenharmony_ci		goto free_and_exit;
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	rc = switchtec_ntb_init_crosslink(sndev);
15038c2ecf20Sopenharmony_ci	if (rc)
15048c2ecf20Sopenharmony_ci		goto free_and_exit;
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	switchtec_ntb_init_db(sndev);
15078c2ecf20Sopenharmony_ci	switchtec_ntb_init_msgs(sndev);
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	rc = switchtec_ntb_init_shared_mw(sndev);
15108c2ecf20Sopenharmony_ci	if (rc)
15118c2ecf20Sopenharmony_ci		goto deinit_crosslink;
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	rc = switchtec_ntb_init_db_msg_irq(sndev);
15148c2ecf20Sopenharmony_ci	if (rc)
15158c2ecf20Sopenharmony_ci		goto deinit_shared_and_exit;
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	/*
15188c2ecf20Sopenharmony_ci	 * If this host crashed, the other host may think the link is
15198c2ecf20Sopenharmony_ci	 * still up. Tell them to force it down (it will go back up
15208c2ecf20Sopenharmony_ci	 * once we register the ntb device).
15218c2ecf20Sopenharmony_ci	 */
15228c2ecf20Sopenharmony_ci	switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_FORCE_DOWN);
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	rc = ntb_register_device(&sndev->ntb);
15258c2ecf20Sopenharmony_ci	if (rc)
15268c2ecf20Sopenharmony_ci		goto deinit_and_exit;
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	stdev->sndev = sndev;
15298c2ecf20Sopenharmony_ci	stdev->link_notifier = switchtec_ntb_link_notification;
15308c2ecf20Sopenharmony_ci	dev_info(dev, "NTB device registered\n");
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	return 0;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_cideinit_and_exit:
15358c2ecf20Sopenharmony_ci	switchtec_ntb_deinit_db_msg_irq(sndev);
15368c2ecf20Sopenharmony_cideinit_shared_and_exit:
15378c2ecf20Sopenharmony_ci	switchtec_ntb_deinit_shared_mw(sndev);
15388c2ecf20Sopenharmony_cideinit_crosslink:
15398c2ecf20Sopenharmony_ci	switchtec_ntb_deinit_crosslink(sndev);
15408c2ecf20Sopenharmony_cifree_and_exit:
15418c2ecf20Sopenharmony_ci	kfree(sndev);
15428c2ecf20Sopenharmony_ci	dev_err(dev, "failed to register ntb device: %d\n", rc);
15438c2ecf20Sopenharmony_ci	return rc;
15448c2ecf20Sopenharmony_ci}
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_cistatic void switchtec_ntb_remove(struct device *dev,
15478c2ecf20Sopenharmony_ci				 struct class_interface *class_intf)
15488c2ecf20Sopenharmony_ci{
15498c2ecf20Sopenharmony_ci	struct switchtec_dev *stdev = to_stdev(dev);
15508c2ecf20Sopenharmony_ci	struct switchtec_ntb *sndev = stdev->sndev;
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	if (!sndev)
15538c2ecf20Sopenharmony_ci		return;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	stdev->link_notifier = NULL;
15568c2ecf20Sopenharmony_ci	stdev->sndev = NULL;
15578c2ecf20Sopenharmony_ci	ntb_unregister_device(&sndev->ntb);
15588c2ecf20Sopenharmony_ci	switchtec_ntb_deinit_db_msg_irq(sndev);
15598c2ecf20Sopenharmony_ci	switchtec_ntb_deinit_shared_mw(sndev);
15608c2ecf20Sopenharmony_ci	switchtec_ntb_deinit_crosslink(sndev);
15618c2ecf20Sopenharmony_ci	kfree(sndev);
15628c2ecf20Sopenharmony_ci	dev_info(dev, "ntb device unregistered\n");
15638c2ecf20Sopenharmony_ci}
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_cistatic struct class_interface switchtec_interface  = {
15668c2ecf20Sopenharmony_ci	.add_dev = switchtec_ntb_add,
15678c2ecf20Sopenharmony_ci	.remove_dev = switchtec_ntb_remove,
15688c2ecf20Sopenharmony_ci};
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_cistatic int __init switchtec_ntb_init(void)
15718c2ecf20Sopenharmony_ci{
15728c2ecf20Sopenharmony_ci	switchtec_interface.class = switchtec_class;
15738c2ecf20Sopenharmony_ci	return class_interface_register(&switchtec_interface);
15748c2ecf20Sopenharmony_ci}
15758c2ecf20Sopenharmony_cimodule_init(switchtec_ntb_init);
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_cistatic void __exit switchtec_ntb_exit(void)
15788c2ecf20Sopenharmony_ci{
15798c2ecf20Sopenharmony_ci	class_interface_unregister(&switchtec_interface);
15808c2ecf20Sopenharmony_ci}
15818c2ecf20Sopenharmony_cimodule_exit(switchtec_ntb_exit);
1582