133dea5aaSLogan Gunthorpe /*
233dea5aaSLogan Gunthorpe  * Microsemi Switchtec(tm) PCIe Management Driver
333dea5aaSLogan Gunthorpe  * Copyright (c) 2017, Microsemi Corporation
433dea5aaSLogan Gunthorpe  *
533dea5aaSLogan Gunthorpe  * This program is free software; you can redistribute it and/or modify it
633dea5aaSLogan Gunthorpe  * under the terms and conditions of the GNU General Public License,
733dea5aaSLogan Gunthorpe  * version 2, as published by the Free Software Foundation.
833dea5aaSLogan Gunthorpe  *
933dea5aaSLogan Gunthorpe  * This program is distributed in the hope it will be useful, but WITHOUT
1033dea5aaSLogan Gunthorpe  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1133dea5aaSLogan Gunthorpe  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
1233dea5aaSLogan Gunthorpe  * more details.
1333dea5aaSLogan Gunthorpe  *
1433dea5aaSLogan Gunthorpe  */
1533dea5aaSLogan Gunthorpe 
1633dea5aaSLogan Gunthorpe #include <linux/switchtec.h>
1733dea5aaSLogan Gunthorpe #include <linux/module.h>
18ec0467ccSLogan Gunthorpe #include <linux/delay.h>
19ec0467ccSLogan Gunthorpe #include <linux/kthread.h>
203dd4db47SLogan Gunthorpe #include <linux/interrupt.h>
21e099b45bSLogan Gunthorpe #include <linux/ntb.h>
2233dea5aaSLogan Gunthorpe 
2333dea5aaSLogan Gunthorpe MODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver");
2433dea5aaSLogan Gunthorpe MODULE_VERSION("0.1");
2533dea5aaSLogan Gunthorpe MODULE_LICENSE("GPL");
2633dea5aaSLogan Gunthorpe MODULE_AUTHOR("Microsemi Corporation");
2733dea5aaSLogan Gunthorpe 
28ec0467ccSLogan Gunthorpe static bool use_lut_mws;
29ec0467ccSLogan Gunthorpe module_param(use_lut_mws, bool, 0644);
30ec0467ccSLogan Gunthorpe MODULE_PARM_DESC(use_lut_mws,
31ec0467ccSLogan Gunthorpe 		 "Enable the use of the LUT based memory windows");
32ec0467ccSLogan Gunthorpe 
33ec0467ccSLogan Gunthorpe #ifndef ioread64
34ec0467ccSLogan Gunthorpe #ifdef readq
35ec0467ccSLogan Gunthorpe #define ioread64 readq
36ec0467ccSLogan Gunthorpe #else
37ec0467ccSLogan Gunthorpe #define ioread64 _ioread64
38ec0467ccSLogan Gunthorpe static inline u64 _ioread64(void __iomem *mmio)
39ec0467ccSLogan Gunthorpe {
40ec0467ccSLogan Gunthorpe 	u64 low, high;
41ec0467ccSLogan Gunthorpe 
42ec0467ccSLogan Gunthorpe 	low = ioread32(mmio);
43ec0467ccSLogan Gunthorpe 	high = ioread32(mmio + sizeof(u32));
44ec0467ccSLogan Gunthorpe 	return low | (high << 32);
45ec0467ccSLogan Gunthorpe }
46ec0467ccSLogan Gunthorpe #endif
47ec0467ccSLogan Gunthorpe #endif
48ec0467ccSLogan Gunthorpe 
49ec0467ccSLogan Gunthorpe #ifndef iowrite64
50ec0467ccSLogan Gunthorpe #ifdef writeq
51ec0467ccSLogan Gunthorpe #define iowrite64 writeq
52ec0467ccSLogan Gunthorpe #else
53ec0467ccSLogan Gunthorpe #define iowrite64 _iowrite64
54ec0467ccSLogan Gunthorpe static inline void _iowrite64(u64 val, void __iomem *mmio)
55ec0467ccSLogan Gunthorpe {
56ec0467ccSLogan Gunthorpe 	iowrite32(val, mmio);
57ec0467ccSLogan Gunthorpe 	iowrite32(val >> 32, mmio + sizeof(u32));
58ec0467ccSLogan Gunthorpe }
59ec0467ccSLogan Gunthorpe #endif
60ec0467ccSLogan Gunthorpe #endif
61ec0467ccSLogan Gunthorpe 
62ec0467ccSLogan Gunthorpe #define SWITCHTEC_NTB_MAGIC 0x45CC0001
63ec0467ccSLogan Gunthorpe #define MAX_MWS     128
64ec0467ccSLogan Gunthorpe 
65ec0467ccSLogan Gunthorpe struct shared_mw {
66ec0467ccSLogan Gunthorpe 	u32 magic;
670ee28f26SLogan Gunthorpe 	u32 link_sta;
68ec0467ccSLogan Gunthorpe 	u32 partition_id;
69ec0467ccSLogan Gunthorpe 	u64 mw_sizes[MAX_MWS];
70*b9a4acacSLogan Gunthorpe 	u32 spad[128];
71ec0467ccSLogan Gunthorpe };
72ec0467ccSLogan Gunthorpe 
73ec0467ccSLogan Gunthorpe #define MAX_DIRECT_MW ARRAY_SIZE(((struct ntb_ctrl_regs *)(0))->bar_entry)
74ec0467ccSLogan Gunthorpe #define LUT_SIZE SZ_64K
75ec0467ccSLogan Gunthorpe 
7633dea5aaSLogan Gunthorpe struct switchtec_ntb {
77e099b45bSLogan Gunthorpe 	struct ntb_dev ntb;
7833dea5aaSLogan Gunthorpe 	struct switchtec_dev *stdev;
79ec0467ccSLogan Gunthorpe 
80ec0467ccSLogan Gunthorpe 	int self_partition;
81ec0467ccSLogan Gunthorpe 	int peer_partition;
82ec0467ccSLogan Gunthorpe 
833dd4db47SLogan Gunthorpe 	int doorbell_irq;
843dd4db47SLogan Gunthorpe 	int message_irq;
853dd4db47SLogan Gunthorpe 
86ec0467ccSLogan Gunthorpe 	struct ntb_info_regs __iomem *mmio_ntb;
87ec0467ccSLogan Gunthorpe 	struct ntb_ctrl_regs __iomem *mmio_ctrl;
88ec0467ccSLogan Gunthorpe 	struct ntb_dbmsg_regs __iomem *mmio_dbmsg;
89ec0467ccSLogan Gunthorpe 	struct ntb_ctrl_regs __iomem *mmio_self_ctrl;
90ec0467ccSLogan Gunthorpe 	struct ntb_ctrl_regs __iomem *mmio_peer_ctrl;
91ec0467ccSLogan Gunthorpe 	struct ntb_dbmsg_regs __iomem *mmio_self_dbmsg;
92ec0467ccSLogan Gunthorpe 
93ec0467ccSLogan Gunthorpe 	struct shared_mw *self_shared;
94ec0467ccSLogan Gunthorpe 	struct shared_mw __iomem *peer_shared;
95ec0467ccSLogan Gunthorpe 	dma_addr_t self_shared_dma;
96ec0467ccSLogan Gunthorpe 
973dd4db47SLogan Gunthorpe 	u64 db_mask;
983dd4db47SLogan Gunthorpe 	u64 db_valid_mask;
993dd4db47SLogan Gunthorpe 	int db_shift;
1003dd4db47SLogan Gunthorpe 	int db_peer_shift;
1013dd4db47SLogan Gunthorpe 
1026619bf95SLogan Gunthorpe 	/* synchronize rmw access of db_mask and hw reg */
1036619bf95SLogan Gunthorpe 	spinlock_t db_mask_lock;
1046619bf95SLogan Gunthorpe 
105ec0467ccSLogan Gunthorpe 	int nr_direct_mw;
106ec0467ccSLogan Gunthorpe 	int nr_lut_mw;
107ec0467ccSLogan Gunthorpe 	int direct_mw_to_bar[MAX_DIRECT_MW];
108ec0467ccSLogan Gunthorpe 
109ec0467ccSLogan Gunthorpe 	int peer_nr_direct_mw;
110ec0467ccSLogan Gunthorpe 	int peer_nr_lut_mw;
111ec0467ccSLogan Gunthorpe 	int peer_direct_mw_to_bar[MAX_DIRECT_MW];
1120ee28f26SLogan Gunthorpe 
1130ee28f26SLogan Gunthorpe 	bool link_is_up;
1140ee28f26SLogan Gunthorpe 	enum ntb_speed link_speed;
1150ee28f26SLogan Gunthorpe 	enum ntb_width link_width;
11633dea5aaSLogan Gunthorpe };
11733dea5aaSLogan Gunthorpe 
1180ee28f26SLogan Gunthorpe static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb)
1190ee28f26SLogan Gunthorpe {
1200ee28f26SLogan Gunthorpe 	return container_of(ntb, struct switchtec_ntb, ntb);
1210ee28f26SLogan Gunthorpe }
1220ee28f26SLogan Gunthorpe 
123ec0467ccSLogan Gunthorpe static int switchtec_ntb_part_op(struct switchtec_ntb *sndev,
124ec0467ccSLogan Gunthorpe 				 struct ntb_ctrl_regs __iomem *ctl,
125ec0467ccSLogan Gunthorpe 				 u32 op, int wait_status)
126ec0467ccSLogan Gunthorpe {
127ec0467ccSLogan Gunthorpe 	static const char * const op_text[] = {
128ec0467ccSLogan Gunthorpe 		[NTB_CTRL_PART_OP_LOCK] = "lock",
129ec0467ccSLogan Gunthorpe 		[NTB_CTRL_PART_OP_CFG] = "configure",
130ec0467ccSLogan Gunthorpe 		[NTB_CTRL_PART_OP_RESET] = "reset",
131ec0467ccSLogan Gunthorpe 	};
132ec0467ccSLogan Gunthorpe 
133ec0467ccSLogan Gunthorpe 	int i;
134ec0467ccSLogan Gunthorpe 	u32 ps;
135ec0467ccSLogan Gunthorpe 	int status;
136ec0467ccSLogan Gunthorpe 
137ec0467ccSLogan Gunthorpe 	switch (op) {
138ec0467ccSLogan Gunthorpe 	case NTB_CTRL_PART_OP_LOCK:
139ec0467ccSLogan Gunthorpe 		status = NTB_CTRL_PART_STATUS_LOCKING;
140ec0467ccSLogan Gunthorpe 		break;
141ec0467ccSLogan Gunthorpe 	case NTB_CTRL_PART_OP_CFG:
142ec0467ccSLogan Gunthorpe 		status = NTB_CTRL_PART_STATUS_CONFIGURING;
143ec0467ccSLogan Gunthorpe 		break;
144ec0467ccSLogan Gunthorpe 	case NTB_CTRL_PART_OP_RESET:
145ec0467ccSLogan Gunthorpe 		status = NTB_CTRL_PART_STATUS_RESETTING;
146ec0467ccSLogan Gunthorpe 		break;
147ec0467ccSLogan Gunthorpe 	default:
148ec0467ccSLogan Gunthorpe 		return -EINVAL;
149ec0467ccSLogan Gunthorpe 	}
150ec0467ccSLogan Gunthorpe 
151ec0467ccSLogan Gunthorpe 	iowrite32(op, &ctl->partition_op);
152ec0467ccSLogan Gunthorpe 
153ec0467ccSLogan Gunthorpe 	for (i = 0; i < 1000; i++) {
154ec0467ccSLogan Gunthorpe 		if (msleep_interruptible(50) != 0) {
155ec0467ccSLogan Gunthorpe 			iowrite32(NTB_CTRL_PART_OP_RESET, &ctl->partition_op);
156ec0467ccSLogan Gunthorpe 			return -EINTR;
157ec0467ccSLogan Gunthorpe 		}
158ec0467ccSLogan Gunthorpe 
159ec0467ccSLogan Gunthorpe 		ps = ioread32(&ctl->partition_status) & 0xFFFF;
160ec0467ccSLogan Gunthorpe 
161ec0467ccSLogan Gunthorpe 		if (ps != status)
162ec0467ccSLogan Gunthorpe 			break;
163ec0467ccSLogan Gunthorpe 	}
164ec0467ccSLogan Gunthorpe 
165ec0467ccSLogan Gunthorpe 	if (ps == wait_status)
166ec0467ccSLogan Gunthorpe 		return 0;
167ec0467ccSLogan Gunthorpe 
168ec0467ccSLogan Gunthorpe 	if (ps == status) {
169ec0467ccSLogan Gunthorpe 		dev_err(&sndev->stdev->dev,
170ec0467ccSLogan Gunthorpe 			"Timed out while peforming %s (%d). (%08x)",
171ec0467ccSLogan Gunthorpe 			op_text[op], op,
172ec0467ccSLogan Gunthorpe 			ioread32(&ctl->partition_status));
173ec0467ccSLogan Gunthorpe 
174ec0467ccSLogan Gunthorpe 		return -ETIMEDOUT;
175ec0467ccSLogan Gunthorpe 	}
176ec0467ccSLogan Gunthorpe 
177ec0467ccSLogan Gunthorpe 	return -EIO;
178ec0467ccSLogan Gunthorpe }
179ec0467ccSLogan Gunthorpe 
1800ee28f26SLogan Gunthorpe static int switchtec_ntb_send_msg(struct switchtec_ntb *sndev, int idx,
1810ee28f26SLogan Gunthorpe 				  u32 val)
1820ee28f26SLogan Gunthorpe {
1830ee28f26SLogan Gunthorpe 	if (idx < 0 || idx >= ARRAY_SIZE(sndev->mmio_self_dbmsg->omsg))
1840ee28f26SLogan Gunthorpe 		return -EINVAL;
1850ee28f26SLogan Gunthorpe 
1860ee28f26SLogan Gunthorpe 	iowrite32(val, &sndev->mmio_self_dbmsg->omsg[idx].msg);
1870ee28f26SLogan Gunthorpe 
1880ee28f26SLogan Gunthorpe 	return 0;
1890ee28f26SLogan Gunthorpe }
1900ee28f26SLogan Gunthorpe 
191e099b45bSLogan Gunthorpe static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx)
192e099b45bSLogan Gunthorpe {
193e099b45bSLogan Gunthorpe 	return 0;
194e099b45bSLogan Gunthorpe }
195e099b45bSLogan Gunthorpe 
196e099b45bSLogan Gunthorpe static int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx,
197e099b45bSLogan Gunthorpe 				      int widx, resource_size_t *addr_align,
198e099b45bSLogan Gunthorpe 				      resource_size_t *size_align,
199e099b45bSLogan Gunthorpe 				      resource_size_t *size_max)
200e099b45bSLogan Gunthorpe {
201e099b45bSLogan Gunthorpe 	return 0;
202e099b45bSLogan Gunthorpe }
203e099b45bSLogan Gunthorpe 
204e099b45bSLogan Gunthorpe static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
205e099b45bSLogan Gunthorpe 				      dma_addr_t addr, resource_size_t size)
206e099b45bSLogan Gunthorpe {
207e099b45bSLogan Gunthorpe 	return 0;
208e099b45bSLogan Gunthorpe }
209e099b45bSLogan Gunthorpe 
210e099b45bSLogan Gunthorpe static int switchtec_ntb_peer_mw_count(struct ntb_dev *ntb)
211e099b45bSLogan Gunthorpe {
212e099b45bSLogan Gunthorpe 	return 0;
213e099b45bSLogan Gunthorpe }
214e099b45bSLogan Gunthorpe 
215e099b45bSLogan Gunthorpe static int switchtec_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
216e099b45bSLogan Gunthorpe 					  phys_addr_t *base,
217e099b45bSLogan Gunthorpe 					  resource_size_t *size)
218e099b45bSLogan Gunthorpe {
219e099b45bSLogan Gunthorpe 	return 0;
220e099b45bSLogan Gunthorpe }
221e099b45bSLogan Gunthorpe 
2220ee28f26SLogan Gunthorpe static void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev,
2230ee28f26SLogan Gunthorpe 					  int partition,
2240ee28f26SLogan Gunthorpe 					  enum ntb_speed *speed,
2250ee28f26SLogan Gunthorpe 					  enum ntb_width *width)
2260ee28f26SLogan Gunthorpe {
2270ee28f26SLogan Gunthorpe 	struct switchtec_dev *stdev = sndev->stdev;
2280ee28f26SLogan Gunthorpe 
2290ee28f26SLogan Gunthorpe 	u32 pff = ioread32(&stdev->mmio_part_cfg[partition].vep_pff_inst_id);
2300ee28f26SLogan Gunthorpe 	u32 linksta = ioread32(&stdev->mmio_pff_csr[pff].pci_cap_region[13]);
2310ee28f26SLogan Gunthorpe 
2320ee28f26SLogan Gunthorpe 	if (speed)
2330ee28f26SLogan Gunthorpe 		*speed = (linksta >> 16) & 0xF;
2340ee28f26SLogan Gunthorpe 
2350ee28f26SLogan Gunthorpe 	if (width)
2360ee28f26SLogan Gunthorpe 		*width = (linksta >> 20) & 0x3F;
2370ee28f26SLogan Gunthorpe }
2380ee28f26SLogan Gunthorpe 
2390ee28f26SLogan Gunthorpe static void switchtec_ntb_set_link_speed(struct switchtec_ntb *sndev)
2400ee28f26SLogan Gunthorpe {
2410ee28f26SLogan Gunthorpe 	enum ntb_speed self_speed, peer_speed;
2420ee28f26SLogan Gunthorpe 	enum ntb_width self_width, peer_width;
2430ee28f26SLogan Gunthorpe 
2440ee28f26SLogan Gunthorpe 	if (!sndev->link_is_up) {
2450ee28f26SLogan Gunthorpe 		sndev->link_speed = NTB_SPEED_NONE;
2460ee28f26SLogan Gunthorpe 		sndev->link_width = NTB_WIDTH_NONE;
2470ee28f26SLogan Gunthorpe 		return;
2480ee28f26SLogan Gunthorpe 	}
2490ee28f26SLogan Gunthorpe 
2500ee28f26SLogan Gunthorpe 	switchtec_ntb_part_link_speed(sndev, sndev->self_partition,
2510ee28f26SLogan Gunthorpe 				      &self_speed, &self_width);
2520ee28f26SLogan Gunthorpe 	switchtec_ntb_part_link_speed(sndev, sndev->peer_partition,
2530ee28f26SLogan Gunthorpe 				      &peer_speed, &peer_width);
2540ee28f26SLogan Gunthorpe 
2550ee28f26SLogan Gunthorpe 	sndev->link_speed = min(self_speed, peer_speed);
2560ee28f26SLogan Gunthorpe 	sndev->link_width = min(self_width, peer_width);
2570ee28f26SLogan Gunthorpe }
2580ee28f26SLogan Gunthorpe 
2590ee28f26SLogan Gunthorpe enum {
2600ee28f26SLogan Gunthorpe 	LINK_MESSAGE = 0,
2610ee28f26SLogan Gunthorpe 	MSG_LINK_UP = 1,
2620ee28f26SLogan Gunthorpe 	MSG_LINK_DOWN = 2,
2630ee28f26SLogan Gunthorpe 	MSG_CHECK_LINK = 3,
2640ee28f26SLogan Gunthorpe };
2650ee28f26SLogan Gunthorpe 
2660ee28f26SLogan Gunthorpe static void switchtec_ntb_check_link(struct switchtec_ntb *sndev)
2670ee28f26SLogan Gunthorpe {
2680ee28f26SLogan Gunthorpe 	int link_sta;
2690ee28f26SLogan Gunthorpe 	int old = sndev->link_is_up;
2700ee28f26SLogan Gunthorpe 
2710ee28f26SLogan Gunthorpe 	link_sta = sndev->self_shared->link_sta;
2720ee28f26SLogan Gunthorpe 	if (link_sta) {
2730ee28f26SLogan Gunthorpe 		u64 peer = ioread64(&sndev->peer_shared->magic);
2740ee28f26SLogan Gunthorpe 
2750ee28f26SLogan Gunthorpe 		if ((peer & 0xFFFFFFFF) == SWITCHTEC_NTB_MAGIC)
2760ee28f26SLogan Gunthorpe 			link_sta = peer >> 32;
2770ee28f26SLogan Gunthorpe 		else
2780ee28f26SLogan Gunthorpe 			link_sta = 0;
2790ee28f26SLogan Gunthorpe 	}
2800ee28f26SLogan Gunthorpe 
2810ee28f26SLogan Gunthorpe 	sndev->link_is_up = link_sta;
2820ee28f26SLogan Gunthorpe 	switchtec_ntb_set_link_speed(sndev);
2830ee28f26SLogan Gunthorpe 
2840ee28f26SLogan Gunthorpe 	if (link_sta != old) {
2850ee28f26SLogan Gunthorpe 		switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_CHECK_LINK);
2860ee28f26SLogan Gunthorpe 		ntb_link_event(&sndev->ntb);
2870ee28f26SLogan Gunthorpe 		dev_info(&sndev->stdev->dev, "ntb link %s",
2880ee28f26SLogan Gunthorpe 			 link_sta ? "up" : "down");
2890ee28f26SLogan Gunthorpe 	}
2900ee28f26SLogan Gunthorpe }
2910ee28f26SLogan Gunthorpe 
2920ee28f26SLogan Gunthorpe static void switchtec_ntb_link_notification(struct switchtec_dev *stdev)
2930ee28f26SLogan Gunthorpe {
2940ee28f26SLogan Gunthorpe 	struct switchtec_ntb *sndev = stdev->sndev;
2950ee28f26SLogan Gunthorpe 
2960ee28f26SLogan Gunthorpe 	switchtec_ntb_check_link(sndev);
2970ee28f26SLogan Gunthorpe }
2980ee28f26SLogan Gunthorpe 
299e099b45bSLogan Gunthorpe static u64 switchtec_ntb_link_is_up(struct ntb_dev *ntb,
300e099b45bSLogan Gunthorpe 				    enum ntb_speed *speed,
301e099b45bSLogan Gunthorpe 				    enum ntb_width *width)
302e099b45bSLogan Gunthorpe {
3030ee28f26SLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
3040ee28f26SLogan Gunthorpe 
3050ee28f26SLogan Gunthorpe 	if (speed)
3060ee28f26SLogan Gunthorpe 		*speed = sndev->link_speed;
3070ee28f26SLogan Gunthorpe 	if (width)
3080ee28f26SLogan Gunthorpe 		*width = sndev->link_width;
3090ee28f26SLogan Gunthorpe 
3100ee28f26SLogan Gunthorpe 	return sndev->link_is_up;
311e099b45bSLogan Gunthorpe }
312e099b45bSLogan Gunthorpe 
313e099b45bSLogan Gunthorpe static int switchtec_ntb_link_enable(struct ntb_dev *ntb,
314e099b45bSLogan Gunthorpe 				     enum ntb_speed max_speed,
315e099b45bSLogan Gunthorpe 				     enum ntb_width max_width)
316e099b45bSLogan Gunthorpe {
3170ee28f26SLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
3180ee28f26SLogan Gunthorpe 
3190ee28f26SLogan Gunthorpe 	dev_dbg(&sndev->stdev->dev, "enabling link");
3200ee28f26SLogan Gunthorpe 
3210ee28f26SLogan Gunthorpe 	sndev->self_shared->link_sta = 1;
3220ee28f26SLogan Gunthorpe 	switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP);
3230ee28f26SLogan Gunthorpe 
3240ee28f26SLogan Gunthorpe 	switchtec_ntb_check_link(sndev);
3250ee28f26SLogan Gunthorpe 
326e099b45bSLogan Gunthorpe 	return 0;
327e099b45bSLogan Gunthorpe }
328e099b45bSLogan Gunthorpe 
329e099b45bSLogan Gunthorpe static int switchtec_ntb_link_disable(struct ntb_dev *ntb)
330e099b45bSLogan Gunthorpe {
3310ee28f26SLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
3320ee28f26SLogan Gunthorpe 
3330ee28f26SLogan Gunthorpe 	dev_dbg(&sndev->stdev->dev, "disabling link");
3340ee28f26SLogan Gunthorpe 
3350ee28f26SLogan Gunthorpe 	sndev->self_shared->link_sta = 0;
3360ee28f26SLogan Gunthorpe 	switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP);
3370ee28f26SLogan Gunthorpe 
3380ee28f26SLogan Gunthorpe 	switchtec_ntb_check_link(sndev);
3390ee28f26SLogan Gunthorpe 
340e099b45bSLogan Gunthorpe 	return 0;
341e099b45bSLogan Gunthorpe }
342e099b45bSLogan Gunthorpe 
343e099b45bSLogan Gunthorpe static u64 switchtec_ntb_db_valid_mask(struct ntb_dev *ntb)
344e099b45bSLogan Gunthorpe {
3456619bf95SLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
3466619bf95SLogan Gunthorpe 
3476619bf95SLogan Gunthorpe 	return sndev->db_valid_mask;
348e099b45bSLogan Gunthorpe }
349e099b45bSLogan Gunthorpe 
350e099b45bSLogan Gunthorpe static int switchtec_ntb_db_vector_count(struct ntb_dev *ntb)
351e099b45bSLogan Gunthorpe {
3526619bf95SLogan Gunthorpe 	return 1;
353e099b45bSLogan Gunthorpe }
354e099b45bSLogan Gunthorpe 
355e099b45bSLogan Gunthorpe static u64 switchtec_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector)
356e099b45bSLogan Gunthorpe {
3576619bf95SLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
3586619bf95SLogan Gunthorpe 
3596619bf95SLogan Gunthorpe 	if (db_vector < 0 || db_vector > 1)
360e099b45bSLogan Gunthorpe 		return 0;
3616619bf95SLogan Gunthorpe 
3626619bf95SLogan Gunthorpe 	return sndev->db_valid_mask;
363e099b45bSLogan Gunthorpe }
364e099b45bSLogan Gunthorpe 
365e099b45bSLogan Gunthorpe static u64 switchtec_ntb_db_read(struct ntb_dev *ntb)
366e099b45bSLogan Gunthorpe {
3676619bf95SLogan Gunthorpe 	u64 ret;
3686619bf95SLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
3696619bf95SLogan Gunthorpe 
3706619bf95SLogan Gunthorpe 	ret = ioread64(&sndev->mmio_self_dbmsg->idb) >> sndev->db_shift;
3716619bf95SLogan Gunthorpe 
3726619bf95SLogan Gunthorpe 	return ret & sndev->db_valid_mask;
373e099b45bSLogan Gunthorpe }
374e099b45bSLogan Gunthorpe 
375e099b45bSLogan Gunthorpe static int switchtec_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits)
376e099b45bSLogan Gunthorpe {
3776619bf95SLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
3786619bf95SLogan Gunthorpe 
3796619bf95SLogan Gunthorpe 	iowrite64(db_bits << sndev->db_shift, &sndev->mmio_self_dbmsg->idb);
3806619bf95SLogan Gunthorpe 
381e099b45bSLogan Gunthorpe 	return 0;
382e099b45bSLogan Gunthorpe }
383e099b45bSLogan Gunthorpe 
384e099b45bSLogan Gunthorpe static int switchtec_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
385e099b45bSLogan Gunthorpe {
3866619bf95SLogan Gunthorpe 	unsigned long irqflags;
3876619bf95SLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
3886619bf95SLogan Gunthorpe 
3896619bf95SLogan Gunthorpe 	if (db_bits & ~sndev->db_valid_mask)
3906619bf95SLogan Gunthorpe 		return -EINVAL;
3916619bf95SLogan Gunthorpe 
3926619bf95SLogan Gunthorpe 	spin_lock_irqsave(&sndev->db_mask_lock, irqflags);
3936619bf95SLogan Gunthorpe 
3946619bf95SLogan Gunthorpe 	sndev->db_mask |= db_bits << sndev->db_shift;
3956619bf95SLogan Gunthorpe 	iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask);
3966619bf95SLogan Gunthorpe 
3976619bf95SLogan Gunthorpe 	spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags);
3986619bf95SLogan Gunthorpe 
399e099b45bSLogan Gunthorpe 	return 0;
400e099b45bSLogan Gunthorpe }
401e099b45bSLogan Gunthorpe 
402e099b45bSLogan Gunthorpe static int switchtec_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
403e099b45bSLogan Gunthorpe {
4046619bf95SLogan Gunthorpe 	unsigned long irqflags;
4056619bf95SLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
4066619bf95SLogan Gunthorpe 
4076619bf95SLogan Gunthorpe 	if (db_bits & ~sndev->db_valid_mask)
4086619bf95SLogan Gunthorpe 		return -EINVAL;
4096619bf95SLogan Gunthorpe 
4106619bf95SLogan Gunthorpe 	spin_lock_irqsave(&sndev->db_mask_lock, irqflags);
4116619bf95SLogan Gunthorpe 
4126619bf95SLogan Gunthorpe 	sndev->db_mask &= ~(db_bits << sndev->db_shift);
4136619bf95SLogan Gunthorpe 	iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask);
4146619bf95SLogan Gunthorpe 
4156619bf95SLogan Gunthorpe 	spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags);
4166619bf95SLogan Gunthorpe 
4176619bf95SLogan Gunthorpe 	return 0;
4186619bf95SLogan Gunthorpe }
4196619bf95SLogan Gunthorpe 
4206619bf95SLogan Gunthorpe static u64 switchtec_ntb_db_read_mask(struct ntb_dev *ntb)
4216619bf95SLogan Gunthorpe {
4226619bf95SLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
4236619bf95SLogan Gunthorpe 
4246619bf95SLogan Gunthorpe 	return (sndev->db_mask >> sndev->db_shift) & sndev->db_valid_mask;
4256619bf95SLogan Gunthorpe }
4266619bf95SLogan Gunthorpe 
4276619bf95SLogan Gunthorpe static int switchtec_ntb_peer_db_addr(struct ntb_dev *ntb,
4286619bf95SLogan Gunthorpe 				      phys_addr_t *db_addr,
4296619bf95SLogan Gunthorpe 				      resource_size_t *db_size)
4306619bf95SLogan Gunthorpe {
4316619bf95SLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
4326619bf95SLogan Gunthorpe 	unsigned long offset;
4336619bf95SLogan Gunthorpe 
4346619bf95SLogan Gunthorpe 	offset = (unsigned long)sndev->mmio_self_dbmsg->odb -
4356619bf95SLogan Gunthorpe 		(unsigned long)sndev->stdev->mmio;
4366619bf95SLogan Gunthorpe 
4376619bf95SLogan Gunthorpe 	offset += sndev->db_shift / 8;
4386619bf95SLogan Gunthorpe 
4396619bf95SLogan Gunthorpe 	if (db_addr)
4406619bf95SLogan Gunthorpe 		*db_addr = pci_resource_start(ntb->pdev, 0) + offset;
4416619bf95SLogan Gunthorpe 	if (db_size)
4426619bf95SLogan Gunthorpe 		*db_size = sizeof(u32);
4436619bf95SLogan Gunthorpe 
444e099b45bSLogan Gunthorpe 	return 0;
445e099b45bSLogan Gunthorpe }
446e099b45bSLogan Gunthorpe 
447e099b45bSLogan Gunthorpe static int switchtec_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
448e099b45bSLogan Gunthorpe {
4496619bf95SLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
4506619bf95SLogan Gunthorpe 
4516619bf95SLogan Gunthorpe 	iowrite64(db_bits << sndev->db_peer_shift,
4526619bf95SLogan Gunthorpe 		  &sndev->mmio_self_dbmsg->odb);
4536619bf95SLogan Gunthorpe 
454e099b45bSLogan Gunthorpe 	return 0;
455e099b45bSLogan Gunthorpe }
456e099b45bSLogan Gunthorpe 
457e099b45bSLogan Gunthorpe static int switchtec_ntb_spad_count(struct ntb_dev *ntb)
458e099b45bSLogan Gunthorpe {
459*b9a4acacSLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
460*b9a4acacSLogan Gunthorpe 
461*b9a4acacSLogan Gunthorpe 	return ARRAY_SIZE(sndev->self_shared->spad);
462e099b45bSLogan Gunthorpe }
463e099b45bSLogan Gunthorpe 
464e099b45bSLogan Gunthorpe static u32 switchtec_ntb_spad_read(struct ntb_dev *ntb, int idx)
465e099b45bSLogan Gunthorpe {
466*b9a4acacSLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
467*b9a4acacSLogan Gunthorpe 
468*b9a4acacSLogan Gunthorpe 	if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad))
469e099b45bSLogan Gunthorpe 		return 0;
470*b9a4acacSLogan Gunthorpe 
471*b9a4acacSLogan Gunthorpe 	if (!sndev->self_shared)
472*b9a4acacSLogan Gunthorpe 		return 0;
473*b9a4acacSLogan Gunthorpe 
474*b9a4acacSLogan Gunthorpe 	return sndev->self_shared->spad[idx];
475e099b45bSLogan Gunthorpe }
476e099b45bSLogan Gunthorpe 
477e099b45bSLogan Gunthorpe static int switchtec_ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
478e099b45bSLogan Gunthorpe {
479*b9a4acacSLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
480*b9a4acacSLogan Gunthorpe 
481*b9a4acacSLogan Gunthorpe 	if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad))
482*b9a4acacSLogan Gunthorpe 		return -EINVAL;
483*b9a4acacSLogan Gunthorpe 
484*b9a4acacSLogan Gunthorpe 	if (!sndev->self_shared)
485*b9a4acacSLogan Gunthorpe 		return -EIO;
486*b9a4acacSLogan Gunthorpe 
487*b9a4acacSLogan Gunthorpe 	sndev->self_shared->spad[idx] = val;
488*b9a4acacSLogan Gunthorpe 
489e099b45bSLogan Gunthorpe 	return 0;
490e099b45bSLogan Gunthorpe }
491e099b45bSLogan Gunthorpe 
492*b9a4acacSLogan Gunthorpe static u32 switchtec_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx,
493*b9a4acacSLogan Gunthorpe 					int sidx)
494*b9a4acacSLogan Gunthorpe {
495*b9a4acacSLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
496*b9a4acacSLogan Gunthorpe 
497*b9a4acacSLogan Gunthorpe 	if (pidx != NTB_DEF_PEER_IDX)
498*b9a4acacSLogan Gunthorpe 		return -EINVAL;
499*b9a4acacSLogan Gunthorpe 
500*b9a4acacSLogan Gunthorpe 	if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad))
501*b9a4acacSLogan Gunthorpe 		return 0;
502*b9a4acacSLogan Gunthorpe 
503*b9a4acacSLogan Gunthorpe 	if (!sndev->peer_shared)
504*b9a4acacSLogan Gunthorpe 		return 0;
505*b9a4acacSLogan Gunthorpe 
506*b9a4acacSLogan Gunthorpe 	return ioread32(&sndev->peer_shared->spad[sidx]);
507*b9a4acacSLogan Gunthorpe }
508*b9a4acacSLogan Gunthorpe 
509e099b45bSLogan Gunthorpe static int switchtec_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx,
510e099b45bSLogan Gunthorpe 					 int sidx, u32 val)
511e099b45bSLogan Gunthorpe {
512*b9a4acacSLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
513*b9a4acacSLogan Gunthorpe 
514*b9a4acacSLogan Gunthorpe 	if (pidx != NTB_DEF_PEER_IDX)
515*b9a4acacSLogan Gunthorpe 		return -EINVAL;
516*b9a4acacSLogan Gunthorpe 
517*b9a4acacSLogan Gunthorpe 	if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad))
518*b9a4acacSLogan Gunthorpe 		return -EINVAL;
519*b9a4acacSLogan Gunthorpe 
520*b9a4acacSLogan Gunthorpe 	if (!sndev->peer_shared)
521*b9a4acacSLogan Gunthorpe 		return -EIO;
522*b9a4acacSLogan Gunthorpe 
523*b9a4acacSLogan Gunthorpe 	iowrite32(val, &sndev->peer_shared->spad[sidx]);
524*b9a4acacSLogan Gunthorpe 
525*b9a4acacSLogan Gunthorpe 	return 0;
526*b9a4acacSLogan Gunthorpe }
527*b9a4acacSLogan Gunthorpe 
528*b9a4acacSLogan Gunthorpe static int switchtec_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx,
529*b9a4acacSLogan Gunthorpe 					int sidx, phys_addr_t *spad_addr)
530*b9a4acacSLogan Gunthorpe {
531*b9a4acacSLogan Gunthorpe 	struct switchtec_ntb *sndev = ntb_sndev(ntb);
532*b9a4acacSLogan Gunthorpe 	unsigned long offset;
533*b9a4acacSLogan Gunthorpe 
534*b9a4acacSLogan Gunthorpe 	if (pidx != NTB_DEF_PEER_IDX)
535*b9a4acacSLogan Gunthorpe 		return -EINVAL;
536*b9a4acacSLogan Gunthorpe 
537*b9a4acacSLogan Gunthorpe 	offset = (unsigned long)&sndev->peer_shared->spad[sidx] -
538*b9a4acacSLogan Gunthorpe 		(unsigned long)sndev->stdev->mmio;
539*b9a4acacSLogan Gunthorpe 
540*b9a4acacSLogan Gunthorpe 	if (spad_addr)
541*b9a4acacSLogan Gunthorpe 		*spad_addr = pci_resource_start(ntb->pdev, 0) + offset;
542*b9a4acacSLogan Gunthorpe 
543e099b45bSLogan Gunthorpe 	return 0;
544e099b45bSLogan Gunthorpe }
545e099b45bSLogan Gunthorpe 
546e099b45bSLogan Gunthorpe static const struct ntb_dev_ops switchtec_ntb_ops = {
547e099b45bSLogan Gunthorpe 	.mw_count		= switchtec_ntb_mw_count,
548e099b45bSLogan Gunthorpe 	.mw_get_align		= switchtec_ntb_mw_get_align,
549e099b45bSLogan Gunthorpe 	.mw_set_trans		= switchtec_ntb_mw_set_trans,
550e099b45bSLogan Gunthorpe 	.peer_mw_count		= switchtec_ntb_peer_mw_count,
551e099b45bSLogan Gunthorpe 	.peer_mw_get_addr	= switchtec_ntb_peer_mw_get_addr,
552e099b45bSLogan Gunthorpe 	.link_is_up		= switchtec_ntb_link_is_up,
553e099b45bSLogan Gunthorpe 	.link_enable		= switchtec_ntb_link_enable,
554e099b45bSLogan Gunthorpe 	.link_disable		= switchtec_ntb_link_disable,
555e099b45bSLogan Gunthorpe 	.db_valid_mask		= switchtec_ntb_db_valid_mask,
556e099b45bSLogan Gunthorpe 	.db_vector_count	= switchtec_ntb_db_vector_count,
557e099b45bSLogan Gunthorpe 	.db_vector_mask		= switchtec_ntb_db_vector_mask,
558e099b45bSLogan Gunthorpe 	.db_read		= switchtec_ntb_db_read,
559e099b45bSLogan Gunthorpe 	.db_clear		= switchtec_ntb_db_clear,
560e099b45bSLogan Gunthorpe 	.db_set_mask		= switchtec_ntb_db_set_mask,
561e099b45bSLogan Gunthorpe 	.db_clear_mask		= switchtec_ntb_db_clear_mask,
5626619bf95SLogan Gunthorpe 	.db_read_mask		= switchtec_ntb_db_read_mask,
5636619bf95SLogan Gunthorpe 	.peer_db_addr		= switchtec_ntb_peer_db_addr,
564e099b45bSLogan Gunthorpe 	.peer_db_set		= switchtec_ntb_peer_db_set,
565e099b45bSLogan Gunthorpe 	.spad_count		= switchtec_ntb_spad_count,
566e099b45bSLogan Gunthorpe 	.spad_read		= switchtec_ntb_spad_read,
567e099b45bSLogan Gunthorpe 	.spad_write		= switchtec_ntb_spad_write,
568*b9a4acacSLogan Gunthorpe 	.peer_spad_read		= switchtec_ntb_peer_spad_read,
569e099b45bSLogan Gunthorpe 	.peer_spad_write	= switchtec_ntb_peer_spad_write,
570*b9a4acacSLogan Gunthorpe 	.peer_spad_addr		= switchtec_ntb_peer_spad_addr,
571e099b45bSLogan Gunthorpe };
572e099b45bSLogan Gunthorpe 
573ec0467ccSLogan Gunthorpe static void switchtec_ntb_init_sndev(struct switchtec_ntb *sndev)
574ec0467ccSLogan Gunthorpe {
575ec0467ccSLogan Gunthorpe 	u64 part_map;
576ec0467ccSLogan Gunthorpe 
577e099b45bSLogan Gunthorpe 	sndev->ntb.pdev = sndev->stdev->pdev;
578e099b45bSLogan Gunthorpe 	sndev->ntb.topo = NTB_TOPO_SWITCH;
579e099b45bSLogan Gunthorpe 	sndev->ntb.ops = &switchtec_ntb_ops;
580e099b45bSLogan Gunthorpe 
581ec0467ccSLogan Gunthorpe 	sndev->self_partition = sndev->stdev->partition;
582ec0467ccSLogan Gunthorpe 
583ec0467ccSLogan Gunthorpe 	sndev->mmio_ntb = sndev->stdev->mmio_ntb;
584ec0467ccSLogan Gunthorpe 	part_map = ioread64(&sndev->mmio_ntb->ep_map);
585ec0467ccSLogan Gunthorpe 	part_map &= ~(1 << sndev->self_partition);
586ec0467ccSLogan Gunthorpe 	sndev->peer_partition = ffs(part_map) - 1;
587ec0467ccSLogan Gunthorpe 
588ec0467ccSLogan Gunthorpe 	dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d (%llx)",
589ec0467ccSLogan Gunthorpe 		sndev->self_partition, sndev->stdev->partition_count,
590ec0467ccSLogan Gunthorpe 		part_map);
591ec0467ccSLogan Gunthorpe 
592ec0467ccSLogan Gunthorpe 	sndev->mmio_ctrl = (void * __iomem)sndev->mmio_ntb +
593ec0467ccSLogan Gunthorpe 		SWITCHTEC_NTB_REG_CTRL_OFFSET;
594ec0467ccSLogan Gunthorpe 	sndev->mmio_dbmsg = (void * __iomem)sndev->mmio_ntb +
595ec0467ccSLogan Gunthorpe 		SWITCHTEC_NTB_REG_DBMSG_OFFSET;
596ec0467ccSLogan Gunthorpe 
597ec0467ccSLogan Gunthorpe 	sndev->mmio_self_ctrl = &sndev->mmio_ctrl[sndev->self_partition];
598ec0467ccSLogan Gunthorpe 	sndev->mmio_peer_ctrl = &sndev->mmio_ctrl[sndev->peer_partition];
599ec0467ccSLogan Gunthorpe 	sndev->mmio_self_dbmsg = &sndev->mmio_dbmsg[sndev->self_partition];
600ec0467ccSLogan Gunthorpe }
601ec0467ccSLogan Gunthorpe 
602ec0467ccSLogan Gunthorpe static int map_bars(int *map, struct ntb_ctrl_regs __iomem *ctrl)
603ec0467ccSLogan Gunthorpe {
604ec0467ccSLogan Gunthorpe 	int i;
605ec0467ccSLogan Gunthorpe 	int cnt = 0;
606ec0467ccSLogan Gunthorpe 
607ec0467ccSLogan Gunthorpe 	for (i = 0; i < ARRAY_SIZE(ctrl->bar_entry); i++) {
608ec0467ccSLogan Gunthorpe 		u32 r = ioread32(&ctrl->bar_entry[i].ctl);
609ec0467ccSLogan Gunthorpe 
610ec0467ccSLogan Gunthorpe 		if (r & NTB_CTRL_BAR_VALID)
611ec0467ccSLogan Gunthorpe 			map[cnt++] = i;
612ec0467ccSLogan Gunthorpe 	}
613ec0467ccSLogan Gunthorpe 
614ec0467ccSLogan Gunthorpe 	return cnt;
615ec0467ccSLogan Gunthorpe }
616ec0467ccSLogan Gunthorpe 
617ec0467ccSLogan Gunthorpe static void switchtec_ntb_init_mw(struct switchtec_ntb *sndev)
618ec0467ccSLogan Gunthorpe {
619ec0467ccSLogan Gunthorpe 	sndev->nr_direct_mw = map_bars(sndev->direct_mw_to_bar,
620ec0467ccSLogan Gunthorpe 				       sndev->mmio_self_ctrl);
621ec0467ccSLogan Gunthorpe 
622ec0467ccSLogan Gunthorpe 	sndev->nr_lut_mw = ioread16(&sndev->mmio_self_ctrl->lut_table_entries);
623ec0467ccSLogan Gunthorpe 	sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw);
624ec0467ccSLogan Gunthorpe 
625ec0467ccSLogan Gunthorpe 	dev_dbg(&sndev->stdev->dev, "MWs: %d direct, %d lut",
626ec0467ccSLogan Gunthorpe 		sndev->nr_direct_mw, sndev->nr_lut_mw);
627ec0467ccSLogan Gunthorpe 
628ec0467ccSLogan Gunthorpe 	sndev->peer_nr_direct_mw = map_bars(sndev->peer_direct_mw_to_bar,
629ec0467ccSLogan Gunthorpe 					    sndev->mmio_peer_ctrl);
630ec0467ccSLogan Gunthorpe 
631ec0467ccSLogan Gunthorpe 	sndev->peer_nr_lut_mw =
632ec0467ccSLogan Gunthorpe 		ioread16(&sndev->mmio_peer_ctrl->lut_table_entries);
633ec0467ccSLogan Gunthorpe 	sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw);
634ec0467ccSLogan Gunthorpe 
635ec0467ccSLogan Gunthorpe 	dev_dbg(&sndev->stdev->dev, "Peer MWs: %d direct, %d lut",
636ec0467ccSLogan Gunthorpe 		sndev->peer_nr_direct_mw, sndev->peer_nr_lut_mw);
637ec0467ccSLogan Gunthorpe 
638ec0467ccSLogan Gunthorpe }
639ec0467ccSLogan Gunthorpe 
6403dd4db47SLogan Gunthorpe /*
6413dd4db47SLogan Gunthorpe  * There are 64 doorbells in the switch hardware but this is
6423dd4db47SLogan Gunthorpe  * shared among all partitions. So we must split them in half
6433dd4db47SLogan Gunthorpe  * (32 for each partition). However, the message interrupts are
6443dd4db47SLogan Gunthorpe  * also shared with the top 4 doorbells so we just limit this to
6453dd4db47SLogan Gunthorpe  * 28 doorbells per partition
6463dd4db47SLogan Gunthorpe  */
6473dd4db47SLogan Gunthorpe static void switchtec_ntb_init_db(struct switchtec_ntb *sndev)
6483dd4db47SLogan Gunthorpe {
6493dd4db47SLogan Gunthorpe 	sndev->db_valid_mask = 0x0FFFFFFF;
6503dd4db47SLogan Gunthorpe 
6513dd4db47SLogan Gunthorpe 	if (sndev->self_partition < sndev->peer_partition) {
6523dd4db47SLogan Gunthorpe 		sndev->db_shift = 0;
6533dd4db47SLogan Gunthorpe 		sndev->db_peer_shift = 32;
6543dd4db47SLogan Gunthorpe 	} else {
6553dd4db47SLogan Gunthorpe 		sndev->db_shift = 32;
6563dd4db47SLogan Gunthorpe 		sndev->db_peer_shift = 0;
6573dd4db47SLogan Gunthorpe 	}
6583dd4db47SLogan Gunthorpe 
6593dd4db47SLogan Gunthorpe 	sndev->db_mask = 0x0FFFFFFFFFFFFFFFULL;
6603dd4db47SLogan Gunthorpe 	iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask);
6613dd4db47SLogan Gunthorpe 	iowrite64(sndev->db_valid_mask << sndev->db_peer_shift,
6623dd4db47SLogan Gunthorpe 		  &sndev->mmio_self_dbmsg->odb_mask);
6633dd4db47SLogan Gunthorpe }
6643dd4db47SLogan Gunthorpe 
6653dd4db47SLogan Gunthorpe static void switchtec_ntb_init_msgs(struct switchtec_ntb *sndev)
6663dd4db47SLogan Gunthorpe {
6673dd4db47SLogan Gunthorpe 	int i;
6683dd4db47SLogan Gunthorpe 	u32 msg_map = 0;
6693dd4db47SLogan Gunthorpe 
6703dd4db47SLogan Gunthorpe 	for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) {
6713dd4db47SLogan Gunthorpe 		int m = i | sndev->peer_partition << 2;
6723dd4db47SLogan Gunthorpe 
6733dd4db47SLogan Gunthorpe 		msg_map |= m << i * 8;
6743dd4db47SLogan Gunthorpe 	}
6753dd4db47SLogan Gunthorpe 
6763dd4db47SLogan Gunthorpe 	iowrite32(msg_map, &sndev->mmio_self_dbmsg->msg_map);
6773dd4db47SLogan Gunthorpe 
6783dd4db47SLogan Gunthorpe 	for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++)
6793dd4db47SLogan Gunthorpe 		iowrite64(NTB_DBMSG_IMSG_STATUS | NTB_DBMSG_IMSG_MASK,
6803dd4db47SLogan Gunthorpe 			  &sndev->mmio_self_dbmsg->imsg[i]);
6813dd4db47SLogan Gunthorpe }
6823dd4db47SLogan Gunthorpe 
683ec0467ccSLogan Gunthorpe static int switchtec_ntb_init_req_id_table(struct switchtec_ntb *sndev)
684ec0467ccSLogan Gunthorpe {
685ec0467ccSLogan Gunthorpe 	int rc = 0;
686ec0467ccSLogan Gunthorpe 	u16 req_id;
687ec0467ccSLogan Gunthorpe 	u32 error;
688ec0467ccSLogan Gunthorpe 
689ec0467ccSLogan Gunthorpe 	req_id = ioread16(&sndev->mmio_ntb->requester_id);
690ec0467ccSLogan Gunthorpe 
691ec0467ccSLogan Gunthorpe 	if (ioread32(&sndev->mmio_self_ctrl->req_id_table_size) < 2) {
692ec0467ccSLogan Gunthorpe 		dev_err(&sndev->stdev->dev,
693ec0467ccSLogan Gunthorpe 			"Not enough requester IDs available.");
694ec0467ccSLogan Gunthorpe 		return -EFAULT;
695ec0467ccSLogan Gunthorpe 	}
696ec0467ccSLogan Gunthorpe 
697ec0467ccSLogan Gunthorpe 	rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl,
698ec0467ccSLogan Gunthorpe 				   NTB_CTRL_PART_OP_LOCK,
699ec0467ccSLogan Gunthorpe 				   NTB_CTRL_PART_STATUS_LOCKED);
700ec0467ccSLogan Gunthorpe 	if (rc)
701ec0467ccSLogan Gunthorpe 		return rc;
702ec0467ccSLogan Gunthorpe 
703ec0467ccSLogan Gunthorpe 	iowrite32(NTB_PART_CTRL_ID_PROT_DIS,
704ec0467ccSLogan Gunthorpe 		  &sndev->mmio_self_ctrl->partition_ctrl);
705ec0467ccSLogan Gunthorpe 
706ec0467ccSLogan Gunthorpe 	/*
707ec0467ccSLogan Gunthorpe 	 * Root Complex Requester ID (which is 0:00.0)
708ec0467ccSLogan Gunthorpe 	 */
709ec0467ccSLogan Gunthorpe 	iowrite32(0 << 16 | NTB_CTRL_REQ_ID_EN,
710ec0467ccSLogan Gunthorpe 		  &sndev->mmio_self_ctrl->req_id_table[0]);
711ec0467ccSLogan Gunthorpe 
712ec0467ccSLogan Gunthorpe 	/*
713ec0467ccSLogan Gunthorpe 	 * Host Bridge Requester ID (as read from the mmap address)
714ec0467ccSLogan Gunthorpe 	 */
715ec0467ccSLogan Gunthorpe 	iowrite32(req_id << 16 | NTB_CTRL_REQ_ID_EN,
716ec0467ccSLogan Gunthorpe 		  &sndev->mmio_self_ctrl->req_id_table[1]);
717ec0467ccSLogan Gunthorpe 
718ec0467ccSLogan Gunthorpe 	rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl,
719ec0467ccSLogan Gunthorpe 				   NTB_CTRL_PART_OP_CFG,
720ec0467ccSLogan Gunthorpe 				   NTB_CTRL_PART_STATUS_NORMAL);
721ec0467ccSLogan Gunthorpe 	if (rc == -EIO) {
722ec0467ccSLogan Gunthorpe 		error = ioread32(&sndev->mmio_self_ctrl->req_id_error);
723ec0467ccSLogan Gunthorpe 		dev_err(&sndev->stdev->dev,
724ec0467ccSLogan Gunthorpe 			"Error setting up the requester ID table: %08x",
725ec0467ccSLogan Gunthorpe 			error);
726ec0467ccSLogan Gunthorpe 	}
727ec0467ccSLogan Gunthorpe 
728ec0467ccSLogan Gunthorpe 	return rc;
729ec0467ccSLogan Gunthorpe }
730ec0467ccSLogan Gunthorpe 
731ec0467ccSLogan Gunthorpe static void switchtec_ntb_init_shared(struct switchtec_ntb *sndev)
732ec0467ccSLogan Gunthorpe {
733ec0467ccSLogan Gunthorpe 	int i;
734ec0467ccSLogan Gunthorpe 
735ec0467ccSLogan Gunthorpe 	memset(sndev->self_shared, 0, LUT_SIZE);
736ec0467ccSLogan Gunthorpe 	sndev->self_shared->magic = SWITCHTEC_NTB_MAGIC;
737ec0467ccSLogan Gunthorpe 	sndev->self_shared->partition_id = sndev->stdev->partition;
738ec0467ccSLogan Gunthorpe 
739ec0467ccSLogan Gunthorpe 	for (i = 0; i < sndev->nr_direct_mw; i++) {
740ec0467ccSLogan Gunthorpe 		int bar = sndev->direct_mw_to_bar[i];
741ec0467ccSLogan Gunthorpe 		resource_size_t sz = pci_resource_len(sndev->stdev->pdev, bar);
742ec0467ccSLogan Gunthorpe 
743ec0467ccSLogan Gunthorpe 		if (i == 0)
744ec0467ccSLogan Gunthorpe 			sz = min_t(resource_size_t, sz,
745ec0467ccSLogan Gunthorpe 				   LUT_SIZE * sndev->nr_lut_mw);
746ec0467ccSLogan Gunthorpe 
747ec0467ccSLogan Gunthorpe 		sndev->self_shared->mw_sizes[i] = sz;
748ec0467ccSLogan Gunthorpe 	}
749ec0467ccSLogan Gunthorpe 
750ec0467ccSLogan Gunthorpe 	for (i = 0; i < sndev->nr_lut_mw; i++) {
751ec0467ccSLogan Gunthorpe 		int idx = sndev->nr_direct_mw + i;
752ec0467ccSLogan Gunthorpe 
753ec0467ccSLogan Gunthorpe 		sndev->self_shared->mw_sizes[idx] = LUT_SIZE;
754ec0467ccSLogan Gunthorpe 	}
755ec0467ccSLogan Gunthorpe }
756ec0467ccSLogan Gunthorpe 
757ec0467ccSLogan Gunthorpe static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev)
758ec0467ccSLogan Gunthorpe {
759ec0467ccSLogan Gunthorpe 	struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl;
760ec0467ccSLogan Gunthorpe 	int bar = sndev->direct_mw_to_bar[0];
761ec0467ccSLogan Gunthorpe 	u32 ctl_val;
762ec0467ccSLogan Gunthorpe 	int rc;
763ec0467ccSLogan Gunthorpe 
764ec0467ccSLogan Gunthorpe 	sndev->self_shared = dma_zalloc_coherent(&sndev->stdev->pdev->dev,
765ec0467ccSLogan Gunthorpe 						 LUT_SIZE,
766ec0467ccSLogan Gunthorpe 						 &sndev->self_shared_dma,
767ec0467ccSLogan Gunthorpe 						 GFP_KERNEL);
768ec0467ccSLogan Gunthorpe 	if (!sndev->self_shared) {
769ec0467ccSLogan Gunthorpe 		dev_err(&sndev->stdev->dev,
770ec0467ccSLogan Gunthorpe 			"unable to allocate memory for shared mw");
771ec0467ccSLogan Gunthorpe 		return -ENOMEM;
772ec0467ccSLogan Gunthorpe 	}
773ec0467ccSLogan Gunthorpe 
774ec0467ccSLogan Gunthorpe 	switchtec_ntb_init_shared(sndev);
775ec0467ccSLogan Gunthorpe 
776ec0467ccSLogan Gunthorpe 	rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK,
777ec0467ccSLogan Gunthorpe 				   NTB_CTRL_PART_STATUS_LOCKED);
778ec0467ccSLogan Gunthorpe 	if (rc)
779ec0467ccSLogan Gunthorpe 		goto unalloc_and_exit;
780ec0467ccSLogan Gunthorpe 
781ec0467ccSLogan Gunthorpe 	ctl_val = ioread32(&ctl->bar_entry[bar].ctl);
782ec0467ccSLogan Gunthorpe 	ctl_val &= 0xFF;
783ec0467ccSLogan Gunthorpe 	ctl_val |= NTB_CTRL_BAR_LUT_WIN_EN;
784ec0467ccSLogan Gunthorpe 	ctl_val |= ilog2(LUT_SIZE) << 8;
785ec0467ccSLogan Gunthorpe 	ctl_val |= (sndev->nr_lut_mw - 1) << 14;
786ec0467ccSLogan Gunthorpe 	iowrite32(ctl_val, &ctl->bar_entry[bar].ctl);
787ec0467ccSLogan Gunthorpe 
788ec0467ccSLogan Gunthorpe 	iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) |
789ec0467ccSLogan Gunthorpe 		   sndev->self_shared_dma),
790ec0467ccSLogan Gunthorpe 		  &ctl->lut_entry[0]);
791ec0467ccSLogan Gunthorpe 
792ec0467ccSLogan Gunthorpe 	rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG,
793ec0467ccSLogan Gunthorpe 				   NTB_CTRL_PART_STATUS_NORMAL);
794ec0467ccSLogan Gunthorpe 	if (rc) {
795ec0467ccSLogan Gunthorpe 		u32 bar_error, lut_error;
796ec0467ccSLogan Gunthorpe 
797ec0467ccSLogan Gunthorpe 		bar_error = ioread32(&ctl->bar_error);
798ec0467ccSLogan Gunthorpe 		lut_error = ioread32(&ctl->lut_error);
799ec0467ccSLogan Gunthorpe 		dev_err(&sndev->stdev->dev,
800ec0467ccSLogan Gunthorpe 			"Error setting up shared MW: %08x / %08x",
801ec0467ccSLogan Gunthorpe 			bar_error, lut_error);
802ec0467ccSLogan Gunthorpe 		goto unalloc_and_exit;
803ec0467ccSLogan Gunthorpe 	}
804ec0467ccSLogan Gunthorpe 
805ec0467ccSLogan Gunthorpe 	sndev->peer_shared = pci_iomap(sndev->stdev->pdev, bar, LUT_SIZE);
806ec0467ccSLogan Gunthorpe 	if (!sndev->peer_shared) {
807ec0467ccSLogan Gunthorpe 		rc = -ENOMEM;
808ec0467ccSLogan Gunthorpe 		goto unalloc_and_exit;
809ec0467ccSLogan Gunthorpe 	}
810ec0467ccSLogan Gunthorpe 
811ec0467ccSLogan Gunthorpe 	dev_dbg(&sndev->stdev->dev, "Shared MW Ready");
812ec0467ccSLogan Gunthorpe 	return 0;
813ec0467ccSLogan Gunthorpe 
814ec0467ccSLogan Gunthorpe unalloc_and_exit:
815ec0467ccSLogan Gunthorpe 	dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE,
816ec0467ccSLogan Gunthorpe 			  sndev->self_shared, sndev->self_shared_dma);
817ec0467ccSLogan Gunthorpe 
818ec0467ccSLogan Gunthorpe 	return rc;
819ec0467ccSLogan Gunthorpe }
820ec0467ccSLogan Gunthorpe 
821ec0467ccSLogan Gunthorpe static void switchtec_ntb_deinit_shared_mw(struct switchtec_ntb *sndev)
822ec0467ccSLogan Gunthorpe {
823ec0467ccSLogan Gunthorpe 	if (sndev->peer_shared)
824ec0467ccSLogan Gunthorpe 		pci_iounmap(sndev->stdev->pdev, sndev->peer_shared);
825ec0467ccSLogan Gunthorpe 
826ec0467ccSLogan Gunthorpe 	if (sndev->self_shared)
827ec0467ccSLogan Gunthorpe 		dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE,
828ec0467ccSLogan Gunthorpe 				  sndev->self_shared,
829ec0467ccSLogan Gunthorpe 				  sndev->self_shared_dma);
830ec0467ccSLogan Gunthorpe }
831ec0467ccSLogan Gunthorpe 
8323dd4db47SLogan Gunthorpe static irqreturn_t switchtec_ntb_doorbell_isr(int irq, void *dev)
8333dd4db47SLogan Gunthorpe {
8343dd4db47SLogan Gunthorpe 	struct switchtec_ntb *sndev = dev;
8353dd4db47SLogan Gunthorpe 
8363dd4db47SLogan Gunthorpe 	dev_dbg(&sndev->stdev->dev, "doorbell\n");
8373dd4db47SLogan Gunthorpe 
8386619bf95SLogan Gunthorpe 	ntb_db_event(&sndev->ntb, 0);
8396619bf95SLogan Gunthorpe 
8403dd4db47SLogan Gunthorpe 	return IRQ_HANDLED;
8413dd4db47SLogan Gunthorpe }
8423dd4db47SLogan Gunthorpe 
8433dd4db47SLogan Gunthorpe static irqreturn_t switchtec_ntb_message_isr(int irq, void *dev)
8443dd4db47SLogan Gunthorpe {
8453dd4db47SLogan Gunthorpe 	int i;
8463dd4db47SLogan Gunthorpe 	struct switchtec_ntb *sndev = dev;
8473dd4db47SLogan Gunthorpe 
8483dd4db47SLogan Gunthorpe 	for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) {
8493dd4db47SLogan Gunthorpe 		u64 msg = ioread64(&sndev->mmio_self_dbmsg->imsg[i]);
8503dd4db47SLogan Gunthorpe 
8513dd4db47SLogan Gunthorpe 		if (msg & NTB_DBMSG_IMSG_STATUS) {
8523dd4db47SLogan Gunthorpe 			dev_dbg(&sndev->stdev->dev, "message: %d %08x\n", i,
8533dd4db47SLogan Gunthorpe 				(u32)msg);
8543dd4db47SLogan Gunthorpe 			iowrite8(1, &sndev->mmio_self_dbmsg->imsg[i].status);
8550ee28f26SLogan Gunthorpe 
8560ee28f26SLogan Gunthorpe 			if (i == LINK_MESSAGE)
8570ee28f26SLogan Gunthorpe 				switchtec_ntb_check_link(sndev);
8583dd4db47SLogan Gunthorpe 		}
8593dd4db47SLogan Gunthorpe 	}
8603dd4db47SLogan Gunthorpe 
8613dd4db47SLogan Gunthorpe 	return IRQ_HANDLED;
8623dd4db47SLogan Gunthorpe }
8633dd4db47SLogan Gunthorpe 
8643dd4db47SLogan Gunthorpe static int switchtec_ntb_init_db_msg_irq(struct switchtec_ntb *sndev)
8653dd4db47SLogan Gunthorpe {
8663dd4db47SLogan Gunthorpe 	int i;
8673dd4db47SLogan Gunthorpe 	int rc;
8683dd4db47SLogan Gunthorpe 	int doorbell_irq = 0;
8693dd4db47SLogan Gunthorpe 	int message_irq = 0;
8703dd4db47SLogan Gunthorpe 	int event_irq;
8713dd4db47SLogan Gunthorpe 	int idb_vecs = sizeof(sndev->mmio_self_dbmsg->idb_vec_map);
8723dd4db47SLogan Gunthorpe 
8733dd4db47SLogan Gunthorpe 	event_irq = ioread32(&sndev->stdev->mmio_part_cfg->vep_vector_number);
8743dd4db47SLogan Gunthorpe 
8753dd4db47SLogan Gunthorpe 	while (doorbell_irq == event_irq)
8763dd4db47SLogan Gunthorpe 		doorbell_irq++;
8773dd4db47SLogan Gunthorpe 	while (message_irq == doorbell_irq ||
8783dd4db47SLogan Gunthorpe 	       message_irq == event_irq)
8793dd4db47SLogan Gunthorpe 		message_irq++;
8803dd4db47SLogan Gunthorpe 
8813dd4db47SLogan Gunthorpe 	dev_dbg(&sndev->stdev->dev, "irqs - event: %d, db: %d, msgs: %d",
8823dd4db47SLogan Gunthorpe 		event_irq, doorbell_irq, message_irq);
8833dd4db47SLogan Gunthorpe 
8843dd4db47SLogan Gunthorpe 	for (i = 0; i < idb_vecs - 4; i++)
8853dd4db47SLogan Gunthorpe 		iowrite8(doorbell_irq,
8863dd4db47SLogan Gunthorpe 			 &sndev->mmio_self_dbmsg->idb_vec_map[i]);
8873dd4db47SLogan Gunthorpe 
8883dd4db47SLogan Gunthorpe 	for (; i < idb_vecs; i++)
8893dd4db47SLogan Gunthorpe 		iowrite8(message_irq,
8903dd4db47SLogan Gunthorpe 			 &sndev->mmio_self_dbmsg->idb_vec_map[i]);
8913dd4db47SLogan Gunthorpe 
8923dd4db47SLogan Gunthorpe 	sndev->doorbell_irq = pci_irq_vector(sndev->stdev->pdev, doorbell_irq);
8933dd4db47SLogan Gunthorpe 	sndev->message_irq = pci_irq_vector(sndev->stdev->pdev, message_irq);
8943dd4db47SLogan Gunthorpe 
8953dd4db47SLogan Gunthorpe 	rc = request_irq(sndev->doorbell_irq,
8963dd4db47SLogan Gunthorpe 			 switchtec_ntb_doorbell_isr, 0,
8973dd4db47SLogan Gunthorpe 			 "switchtec_ntb_doorbell", sndev);
8983dd4db47SLogan Gunthorpe 	if (rc)
8993dd4db47SLogan Gunthorpe 		return rc;
9003dd4db47SLogan Gunthorpe 
9013dd4db47SLogan Gunthorpe 	rc = request_irq(sndev->message_irq,
9023dd4db47SLogan Gunthorpe 			 switchtec_ntb_message_isr, 0,
9033dd4db47SLogan Gunthorpe 			 "switchtec_ntb_message", sndev);
9043dd4db47SLogan Gunthorpe 	if (rc) {
9053dd4db47SLogan Gunthorpe 		free_irq(sndev->doorbell_irq, sndev);
9063dd4db47SLogan Gunthorpe 		return rc;
9073dd4db47SLogan Gunthorpe 	}
9083dd4db47SLogan Gunthorpe 
9093dd4db47SLogan Gunthorpe 	return 0;
9103dd4db47SLogan Gunthorpe }
9113dd4db47SLogan Gunthorpe 
9123dd4db47SLogan Gunthorpe static void switchtec_ntb_deinit_db_msg_irq(struct switchtec_ntb *sndev)
9133dd4db47SLogan Gunthorpe {
9143dd4db47SLogan Gunthorpe 	free_irq(sndev->doorbell_irq, sndev);
9153dd4db47SLogan Gunthorpe 	free_irq(sndev->message_irq, sndev);
9163dd4db47SLogan Gunthorpe }
9173dd4db47SLogan Gunthorpe 
91833dea5aaSLogan Gunthorpe static int switchtec_ntb_add(struct device *dev,
91933dea5aaSLogan Gunthorpe 			     struct class_interface *class_intf)
92033dea5aaSLogan Gunthorpe {
92133dea5aaSLogan Gunthorpe 	struct switchtec_dev *stdev = to_stdev(dev);
92233dea5aaSLogan Gunthorpe 	struct switchtec_ntb *sndev;
923ec0467ccSLogan Gunthorpe 	int rc;
92433dea5aaSLogan Gunthorpe 
92533dea5aaSLogan Gunthorpe 	stdev->sndev = NULL;
92633dea5aaSLogan Gunthorpe 
92733dea5aaSLogan Gunthorpe 	if (stdev->pdev->class != MICROSEMI_NTB_CLASSCODE)
92833dea5aaSLogan Gunthorpe 		return -ENODEV;
92933dea5aaSLogan Gunthorpe 
930ec0467ccSLogan Gunthorpe 	if (stdev->partition_count != 2)
931ec0467ccSLogan Gunthorpe 		dev_warn(dev, "ntb driver only supports 2 partitions");
932ec0467ccSLogan Gunthorpe 
93333dea5aaSLogan Gunthorpe 	sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev));
93433dea5aaSLogan Gunthorpe 	if (!sndev)
93533dea5aaSLogan Gunthorpe 		return -ENOMEM;
93633dea5aaSLogan Gunthorpe 
93733dea5aaSLogan Gunthorpe 	sndev->stdev = stdev;
938ec0467ccSLogan Gunthorpe 	switchtec_ntb_init_sndev(sndev);
939ec0467ccSLogan Gunthorpe 	switchtec_ntb_init_mw(sndev);
9403dd4db47SLogan Gunthorpe 	switchtec_ntb_init_db(sndev);
9413dd4db47SLogan Gunthorpe 	switchtec_ntb_init_msgs(sndev);
942ec0467ccSLogan Gunthorpe 
943ec0467ccSLogan Gunthorpe 	rc = switchtec_ntb_init_req_id_table(sndev);
944ec0467ccSLogan Gunthorpe 	if (rc)
945ec0467ccSLogan Gunthorpe 		goto free_and_exit;
946ec0467ccSLogan Gunthorpe 
947ec0467ccSLogan Gunthorpe 	rc = switchtec_ntb_init_shared_mw(sndev);
948ec0467ccSLogan Gunthorpe 	if (rc)
949ec0467ccSLogan Gunthorpe 		goto free_and_exit;
950ec0467ccSLogan Gunthorpe 
9513dd4db47SLogan Gunthorpe 	rc = switchtec_ntb_init_db_msg_irq(sndev);
9523dd4db47SLogan Gunthorpe 	if (rc)
9533dd4db47SLogan Gunthorpe 		goto deinit_shared_and_exit;
9543dd4db47SLogan Gunthorpe 
955e099b45bSLogan Gunthorpe 	rc = ntb_register_device(&sndev->ntb);
956e099b45bSLogan Gunthorpe 	if (rc)
957e099b45bSLogan Gunthorpe 		goto deinit_and_exit;
958e099b45bSLogan Gunthorpe 
95933dea5aaSLogan Gunthorpe 	stdev->sndev = sndev;
9600ee28f26SLogan Gunthorpe 	stdev->link_notifier = switchtec_ntb_link_notification;
96133dea5aaSLogan Gunthorpe 	dev_info(dev, "NTB device registered");
96233dea5aaSLogan Gunthorpe 
96333dea5aaSLogan Gunthorpe 	return 0;
964ec0467ccSLogan Gunthorpe 
965e099b45bSLogan Gunthorpe deinit_and_exit:
966e099b45bSLogan Gunthorpe 	switchtec_ntb_deinit_db_msg_irq(sndev);
9673dd4db47SLogan Gunthorpe deinit_shared_and_exit:
9683dd4db47SLogan Gunthorpe 	switchtec_ntb_deinit_shared_mw(sndev);
969ec0467ccSLogan Gunthorpe free_and_exit:
970ec0467ccSLogan Gunthorpe 	kfree(sndev);
971ec0467ccSLogan Gunthorpe 	dev_err(dev, "failed to register ntb device: %d", rc);
972ec0467ccSLogan Gunthorpe 	return rc;
97333dea5aaSLogan Gunthorpe }
97433dea5aaSLogan Gunthorpe 
97533dea5aaSLogan Gunthorpe void switchtec_ntb_remove(struct device *dev,
97633dea5aaSLogan Gunthorpe 			  struct class_interface *class_intf)
97733dea5aaSLogan Gunthorpe {
97833dea5aaSLogan Gunthorpe 	struct switchtec_dev *stdev = to_stdev(dev);
97933dea5aaSLogan Gunthorpe 	struct switchtec_ntb *sndev = stdev->sndev;
98033dea5aaSLogan Gunthorpe 
98133dea5aaSLogan Gunthorpe 	if (!sndev)
98233dea5aaSLogan Gunthorpe 		return;
98333dea5aaSLogan Gunthorpe 
9840ee28f26SLogan Gunthorpe 	stdev->link_notifier = NULL;
98533dea5aaSLogan Gunthorpe 	stdev->sndev = NULL;
986e099b45bSLogan Gunthorpe 	ntb_unregister_device(&sndev->ntb);
9873dd4db47SLogan Gunthorpe 	switchtec_ntb_deinit_db_msg_irq(sndev);
988ec0467ccSLogan Gunthorpe 	switchtec_ntb_deinit_shared_mw(sndev);
98933dea5aaSLogan Gunthorpe 	kfree(sndev);
99033dea5aaSLogan Gunthorpe 	dev_info(dev, "ntb device unregistered");
99133dea5aaSLogan Gunthorpe }
99233dea5aaSLogan Gunthorpe 
99333dea5aaSLogan Gunthorpe static struct class_interface switchtec_interface  = {
99433dea5aaSLogan Gunthorpe 	.add_dev = switchtec_ntb_add,
99533dea5aaSLogan Gunthorpe 	.remove_dev = switchtec_ntb_remove,
99633dea5aaSLogan Gunthorpe };
99733dea5aaSLogan Gunthorpe 
99833dea5aaSLogan Gunthorpe static int __init switchtec_ntb_init(void)
99933dea5aaSLogan Gunthorpe {
100033dea5aaSLogan Gunthorpe 	switchtec_interface.class = switchtec_class;
100133dea5aaSLogan Gunthorpe 	return class_interface_register(&switchtec_interface);
100233dea5aaSLogan Gunthorpe }
100333dea5aaSLogan Gunthorpe module_init(switchtec_ntb_init);
100433dea5aaSLogan Gunthorpe 
100533dea5aaSLogan Gunthorpe static void __exit switchtec_ntb_exit(void)
100633dea5aaSLogan Gunthorpe {
100733dea5aaSLogan Gunthorpe 	class_interface_unregister(&switchtec_interface);
100833dea5aaSLogan Gunthorpe }
100933dea5aaSLogan Gunthorpe module_exit(switchtec_ntb_exit);
1010