xref: /freebsd/sys/dev/ntb/ntb_hw/ntb_hw_intel.c (revision 70450ecd37fa4ce06bd957195b00669dc3445e04)
1ed9652daSAlexander Motin /*-
2b7dd3fbeSAlexander Motin  * Copyright (c) 2016-2017 Alexander Motin <mav@FreeBSD.org>
3ed9652daSAlexander Motin  * Copyright (C) 2013 Intel Corporation
4ed9652daSAlexander Motin  * Copyright (C) 2015 EMC Corporation
5ed9652daSAlexander Motin  * All rights reserved.
6ed9652daSAlexander Motin  *
7ed9652daSAlexander Motin  * Redistribution and use in source and binary forms, with or without
8ed9652daSAlexander Motin  * modification, are permitted provided that the following conditions
9ed9652daSAlexander Motin  * are met:
10ed9652daSAlexander Motin  * 1. Redistributions of source code must retain the above copyright
11ed9652daSAlexander Motin  *    notice, this list of conditions and the following disclaimer.
12ed9652daSAlexander Motin  * 2. Redistributions in binary form must reproduce the above copyright
13ed9652daSAlexander Motin  *    notice, this list of conditions and the following disclaimer in the
14ed9652daSAlexander Motin  *    documentation and/or other materials provided with the distribution.
15ed9652daSAlexander Motin  *
16ed9652daSAlexander Motin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17ed9652daSAlexander Motin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18ed9652daSAlexander Motin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ed9652daSAlexander Motin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20ed9652daSAlexander Motin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21ed9652daSAlexander Motin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22ed9652daSAlexander Motin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23ed9652daSAlexander Motin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24ed9652daSAlexander Motin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25ed9652daSAlexander Motin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26ed9652daSAlexander Motin  * SUCH DAMAGE.
27ed9652daSAlexander Motin  */
28ed9652daSAlexander Motin 
29ed9652daSAlexander Motin /*
30ed9652daSAlexander Motin  * The Non-Transparent Bridge (NTB) is a device that allows you to connect
31ed9652daSAlexander Motin  * two or more systems using a PCI-e links, providing remote memory access.
32ed9652daSAlexander Motin  *
33ed9652daSAlexander Motin  * This module contains a driver for NTB hardware in Intel Xeon/Atom CPUs.
34ed9652daSAlexander Motin  *
35ed9652daSAlexander Motin  * NOTE: Much of the code in this module is shared with Linux. Any patches may
36ed9652daSAlexander Motin  * be picked up and redistributed in Linux with a dual GPL/BSD license.
37ed9652daSAlexander Motin  */
38ed9652daSAlexander Motin 
39ed9652daSAlexander Motin #include <sys/param.h>
40ed9652daSAlexander Motin #include <sys/kernel.h>
41ed9652daSAlexander Motin #include <sys/systm.h>
42ed9652daSAlexander Motin #include <sys/bus.h>
43ed9652daSAlexander Motin #include <sys/endian.h>
44ed9652daSAlexander Motin #include <sys/interrupt.h>
45e2e050c8SConrad Meyer #include <sys/lock.h>
46ed9652daSAlexander Motin #include <sys/malloc.h>
47ed9652daSAlexander Motin #include <sys/module.h>
48ed9652daSAlexander Motin #include <sys/mutex.h>
49ed9652daSAlexander Motin #include <sys/pciio.h>
50c8597a1fSRuslan Bukin #include <sys/taskqueue.h>
51c8597a1fSRuslan Bukin #include <sys/tree.h>
52ed9652daSAlexander Motin #include <sys/queue.h>
53ed9652daSAlexander Motin #include <sys/rman.h>
54ed9652daSAlexander Motin #include <sys/sbuf.h>
55ed9652daSAlexander Motin #include <sys/sysctl.h>
56ed9652daSAlexander Motin #include <vm/vm.h>
57ed9652daSAlexander Motin #include <vm/pmap.h>
58ed9652daSAlexander Motin #include <machine/bus.h>
59ed9652daSAlexander Motin #include <machine/intr_machdep.h>
60ed9652daSAlexander Motin #include <machine/resource.h>
61ed9652daSAlexander Motin #include <dev/pci/pcireg.h>
62ed9652daSAlexander Motin #include <dev/pci/pcivar.h>
639abb9265SRuslan Bukin #include <dev/iommu/iommu.h>
64ed9652daSAlexander Motin 
65ed9652daSAlexander Motin #include "ntb_hw_intel.h"
66ed9652daSAlexander Motin #include "../ntb.h"
67ed9652daSAlexander Motin 
686660ef6eSMark Johnston #define MAX_MSIX_INTERRUPTS	\
696660ef6eSMark Johnston 	MAX(MAX(XEON_DB_COUNT, ATOM_DB_COUNT), XEON_GEN3_DB_COUNT)
70ed9652daSAlexander Motin 
71ed9652daSAlexander Motin #define NTB_HB_TIMEOUT		1 /* second */
72ed9652daSAlexander Motin #define ATOM_LINK_RECOVERY_TIME	500 /* ms */
73ed9652daSAlexander Motin #define BAR_HIGH_MASK		(~((1ull << 12) - 1))
74ed9652daSAlexander Motin 
75ed9652daSAlexander Motin #define	NTB_MSIX_VER_GUARD	0xaabbccdd
76ed9652daSAlexander Motin #define	NTB_MSIX_RECEIVED	0xe0f0e0f0
77ed9652daSAlexander Motin 
78ed9652daSAlexander Motin /*
79ed9652daSAlexander Motin  * PCI constants could be somewhere more generic, but aren't defined/used in
80ed9652daSAlexander Motin  * pci.c.
81ed9652daSAlexander Motin  */
82ed9652daSAlexander Motin #define	PCI_MSIX_ENTRY_SIZE		16
83ed9652daSAlexander Motin #define	PCI_MSIX_ENTRY_LOWER_ADDR	0
84ed9652daSAlexander Motin #define	PCI_MSIX_ENTRY_UPPER_ADDR	4
85ed9652daSAlexander Motin #define	PCI_MSIX_ENTRY_DATA		8
86ed9652daSAlexander Motin 
87ed9652daSAlexander Motin enum ntb_device_type {
886660ef6eSMark Johnston 	NTB_XEON_GEN1,
896660ef6eSMark Johnston 	NTB_XEON_GEN3,
90*70450ecdSAustin Zhang 	NTB_XEON_GEN4,
91ed9652daSAlexander Motin 	NTB_ATOM
92ed9652daSAlexander Motin };
93ed9652daSAlexander Motin 
94ed9652daSAlexander Motin /* ntb_conn_type are hardware numbers, cannot change. */
95ed9652daSAlexander Motin enum ntb_conn_type {
96ed9652daSAlexander Motin 	NTB_CONN_TRANSPARENT = 0,
97ed9652daSAlexander Motin 	NTB_CONN_B2B = 1,
98ed9652daSAlexander Motin 	NTB_CONN_RP = 2,
99ed9652daSAlexander Motin };
100ed9652daSAlexander Motin 
101ed9652daSAlexander Motin enum ntb_b2b_direction {
102ed9652daSAlexander Motin 	NTB_DEV_USD = 0,
103ed9652daSAlexander Motin 	NTB_DEV_DSD = 1,
104ed9652daSAlexander Motin };
105ed9652daSAlexander Motin 
106ed9652daSAlexander Motin enum ntb_bar {
107ed9652daSAlexander Motin 	NTB_CONFIG_BAR = 0,
108ed9652daSAlexander Motin 	NTB_B2B_BAR_1,
109ed9652daSAlexander Motin 	NTB_B2B_BAR_2,
110ed9652daSAlexander Motin 	NTB_B2B_BAR_3,
111ed9652daSAlexander Motin 	NTB_MAX_BARS
112ed9652daSAlexander Motin };
113ed9652daSAlexander Motin 
114ed9652daSAlexander Motin enum {
115ed9652daSAlexander Motin 	NTB_MSIX_GUARD = 0,
116ed9652daSAlexander Motin 	NTB_MSIX_DATA0,
117ed9652daSAlexander Motin 	NTB_MSIX_DATA1,
118ed9652daSAlexander Motin 	NTB_MSIX_DATA2,
119ed9652daSAlexander Motin 	NTB_MSIX_OFS0,
120ed9652daSAlexander Motin 	NTB_MSIX_OFS1,
121ed9652daSAlexander Motin 	NTB_MSIX_OFS2,
122ed9652daSAlexander Motin 	NTB_MSIX_DONE,
123ed9652daSAlexander Motin 	NTB_MAX_MSIX_SPAD
124ed9652daSAlexander Motin };
125ed9652daSAlexander Motin 
126ed9652daSAlexander Motin /* Device features and workarounds */
127ed9652daSAlexander Motin #define HAS_FEATURE(ntb, feature)	\
128ed9652daSAlexander Motin 	(((ntb)->features & (feature)) != 0)
129ed9652daSAlexander Motin 
130ed9652daSAlexander Motin struct ntb_hw_info {
131ed9652daSAlexander Motin 	uint32_t		device_id;
132ed9652daSAlexander Motin 	const char		*desc;
133ed9652daSAlexander Motin 	enum ntb_device_type	type;
134ed9652daSAlexander Motin 	uint32_t		features;
135ed9652daSAlexander Motin };
136ed9652daSAlexander Motin 
137ed9652daSAlexander Motin struct ntb_pci_bar_info {
138ed9652daSAlexander Motin 	bus_space_tag_t		pci_bus_tag;
139ed9652daSAlexander Motin 	bus_space_handle_t	pci_bus_handle;
140ed9652daSAlexander Motin 	int			pci_resource_id;
141ed9652daSAlexander Motin 	struct resource		*pci_resource;
142ed9652daSAlexander Motin 	vm_paddr_t		pbase;
143ed9652daSAlexander Motin 	caddr_t			vbase;
144ed9652daSAlexander Motin 	vm_size_t		size;
145ed9652daSAlexander Motin 	vm_memattr_t		map_mode;
146ed9652daSAlexander Motin 
147ed9652daSAlexander Motin 	/* Configuration register offsets */
148ed9652daSAlexander Motin 	uint32_t		psz_off;
149ed9652daSAlexander Motin 	uint32_t		ssz_off;
150ed9652daSAlexander Motin 	uint32_t		pbarxlat_off;
151ed9652daSAlexander Motin };
152ed9652daSAlexander Motin 
153ed9652daSAlexander Motin struct ntb_int_info {
154ed9652daSAlexander Motin 	struct resource	*res;
155ed9652daSAlexander Motin 	int		rid;
156ed9652daSAlexander Motin 	void		*tag;
157ed9652daSAlexander Motin };
158ed9652daSAlexander Motin 
159ed9652daSAlexander Motin struct ntb_vec {
160ed9652daSAlexander Motin 	struct ntb_softc	*ntb;
161ed9652daSAlexander Motin 	uint32_t		num;
162ed9652daSAlexander Motin 	unsigned		masked;
163ed9652daSAlexander Motin };
164ed9652daSAlexander Motin 
165ed9652daSAlexander Motin struct ntb_reg {
166ed9652daSAlexander Motin 	uint32_t	ntb_ctl;
167ed9652daSAlexander Motin 	uint32_t	lnk_sta;
168ed9652daSAlexander Motin 	uint8_t		db_size;
169ed9652daSAlexander Motin 	unsigned	mw_bar[NTB_MAX_BARS];
170ed9652daSAlexander Motin };
171ed9652daSAlexander Motin 
172ed9652daSAlexander Motin struct ntb_alt_reg {
173ed9652daSAlexander Motin 	uint32_t	db_bell;
174ed9652daSAlexander Motin 	uint32_t	db_mask;
175*70450ecdSAustin Zhang 	uint32_t	db_clear;
176ed9652daSAlexander Motin 	uint32_t	spad;
177ed9652daSAlexander Motin };
178ed9652daSAlexander Motin 
179ed9652daSAlexander Motin struct ntb_xlat_reg {
180ed9652daSAlexander Motin 	uint32_t	bar0_base;
181ed9652daSAlexander Motin 	uint32_t	bar2_base;
182ed9652daSAlexander Motin 	uint32_t	bar4_base;
183ed9652daSAlexander Motin 	uint32_t	bar5_base;
184ed9652daSAlexander Motin 
185ed9652daSAlexander Motin 	uint32_t	bar2_xlat;
186ed9652daSAlexander Motin 	uint32_t	bar4_xlat;
187ed9652daSAlexander Motin 	uint32_t	bar5_xlat;
188ed9652daSAlexander Motin 
189ed9652daSAlexander Motin 	uint32_t	bar2_limit;
190ed9652daSAlexander Motin 	uint32_t	bar4_limit;
191ed9652daSAlexander Motin 	uint32_t	bar5_limit;
192ed9652daSAlexander Motin };
193ed9652daSAlexander Motin 
194ed9652daSAlexander Motin struct ntb_b2b_addr {
195ed9652daSAlexander Motin 	uint64_t	bar0_addr;
196ed9652daSAlexander Motin 	uint64_t	bar2_addr64;
197ed9652daSAlexander Motin 	uint64_t	bar4_addr64;
198ed9652daSAlexander Motin 	uint64_t	bar4_addr32;
199ed9652daSAlexander Motin 	uint64_t	bar5_addr32;
200ed9652daSAlexander Motin };
201ed9652daSAlexander Motin 
202ed9652daSAlexander Motin struct ntb_msix_data {
203ed9652daSAlexander Motin 	uint32_t	nmd_ofs;
204ed9652daSAlexander Motin 	uint32_t	nmd_data;
205ed9652daSAlexander Motin };
206ed9652daSAlexander Motin 
207ed9652daSAlexander Motin struct ntb_softc {
208ed9652daSAlexander Motin 	/* ntb.c context. Do not move! Must go first! */
209ed9652daSAlexander Motin 	void			*ntb_store;
210ed9652daSAlexander Motin 
211ed9652daSAlexander Motin 	device_t		device;
212ed9652daSAlexander Motin 	enum ntb_device_type	type;
213ed9652daSAlexander Motin 	uint32_t		features;
214ed9652daSAlexander Motin 
215ed9652daSAlexander Motin 	struct ntb_pci_bar_info	bar_info[NTB_MAX_BARS];
216ed9652daSAlexander Motin 	struct ntb_int_info	int_info[MAX_MSIX_INTERRUPTS];
217ed9652daSAlexander Motin 	uint32_t		allocated_interrupts;
218ed9652daSAlexander Motin 
219ed9652daSAlexander Motin 	struct ntb_msix_data	peer_msix_data[XEON_NONLINK_DB_MSIX_BITS];
220ed9652daSAlexander Motin 	struct ntb_msix_data	msix_data[XEON_NONLINK_DB_MSIX_BITS];
221ed9652daSAlexander Motin 	bool			peer_msix_good;
222ed9652daSAlexander Motin 	bool			peer_msix_done;
223ed9652daSAlexander Motin 	struct ntb_pci_bar_info	*peer_lapic_bar;
224ed9652daSAlexander Motin 	struct callout		peer_msix_work;
225ed9652daSAlexander Motin 
22695ba48d9SAlexander Motin 	bus_dma_tag_t		bar0_dma_tag;
22795ba48d9SAlexander Motin 	bus_dmamap_t		bar0_dma_map;
22895ba48d9SAlexander Motin 
229ed9652daSAlexander Motin 	struct callout		heartbeat_timer;
230ed9652daSAlexander Motin 	struct callout		lr_timer;
231ed9652daSAlexander Motin 
232ed9652daSAlexander Motin 	struct ntb_vec		*msix_vec;
233ed9652daSAlexander Motin 
234ed9652daSAlexander Motin 	uint32_t		ppd;
235ed9652daSAlexander Motin 	enum ntb_conn_type	conn_type;
236ed9652daSAlexander Motin 	enum ntb_b2b_direction	dev_type;
237ed9652daSAlexander Motin 
238ed9652daSAlexander Motin 	/* Offset of peer bar0 in B2B BAR */
239ed9652daSAlexander Motin 	uint64_t			b2b_off;
240ed9652daSAlexander Motin 	/* Memory window used to access peer bar0 */
241ed9652daSAlexander Motin #define B2B_MW_DISABLED			UINT8_MAX
242ed9652daSAlexander Motin 	uint8_t				b2b_mw_idx;
243ed9652daSAlexander Motin 	uint32_t			msix_xlat;
244ed9652daSAlexander Motin 	uint8_t				msix_mw_idx;
245ed9652daSAlexander Motin 
246ed9652daSAlexander Motin 	uint8_t				mw_count;
247ed9652daSAlexander Motin 	uint8_t				spad_count;
248ed9652daSAlexander Motin 	uint8_t				db_count;
249ed9652daSAlexander Motin 	uint8_t				db_vec_count;
250ed9652daSAlexander Motin 	uint8_t				db_vec_shift;
251ed9652daSAlexander Motin 
252ed9652daSAlexander Motin 	/* Protects local db_mask. */
253ed9652daSAlexander Motin #define DB_MASK_LOCK(sc)	mtx_lock_spin(&(sc)->db_mask_lock)
254ed9652daSAlexander Motin #define DB_MASK_UNLOCK(sc)	mtx_unlock_spin(&(sc)->db_mask_lock)
255ed9652daSAlexander Motin #define DB_MASK_ASSERT(sc,f)	mtx_assert(&(sc)->db_mask_lock, (f))
256ed9652daSAlexander Motin 	struct mtx			db_mask_lock;
257ed9652daSAlexander Motin 
258ed9652daSAlexander Motin 	volatile uint32_t		ntb_ctl;
259ed9652daSAlexander Motin 	volatile uint32_t		lnk_sta;
260ed9652daSAlexander Motin 
261ed9652daSAlexander Motin 	uint64_t			db_valid_mask;
262ed9652daSAlexander Motin 	uint64_t			db_link_mask;
263ed9652daSAlexander Motin 	uint64_t			db_mask;
264ed9652daSAlexander Motin 	uint64_t			fake_db;	/* NTB_SB01BASE_LOCKUP*/
265ed9652daSAlexander Motin 	uint64_t			force_db;	/* NTB_SB01BASE_LOCKUP*/
266ed9652daSAlexander Motin 
267ed9652daSAlexander Motin 	int				last_ts;	/* ticks @ last irq */
268ed9652daSAlexander Motin 
269ed9652daSAlexander Motin 	const struct ntb_reg		*reg;
270ed9652daSAlexander Motin 	const struct ntb_alt_reg	*self_reg;
271ed9652daSAlexander Motin 	const struct ntb_alt_reg	*peer_reg;
272ed9652daSAlexander Motin 	const struct ntb_xlat_reg	*xlat_reg;
273ed9652daSAlexander Motin };
274ed9652daSAlexander Motin 
275ed9652daSAlexander Motin #ifdef __i386__
276ed9652daSAlexander Motin static __inline uint64_t
bus_space_read_8(bus_space_tag_t tag,bus_space_handle_t handle,bus_size_t offset)277ed9652daSAlexander Motin bus_space_read_8(bus_space_tag_t tag, bus_space_handle_t handle,
278ed9652daSAlexander Motin     bus_size_t offset)
279ed9652daSAlexander Motin {
280ed9652daSAlexander Motin 
281ed9652daSAlexander Motin 	return (bus_space_read_4(tag, handle, offset) |
282ed9652daSAlexander Motin 	    ((uint64_t)bus_space_read_4(tag, handle, offset + 4)) << 32);
283ed9652daSAlexander Motin }
284ed9652daSAlexander Motin 
285ed9652daSAlexander Motin static __inline void
bus_space_write_8(bus_space_tag_t tag,bus_space_handle_t handle,bus_size_t offset,uint64_t val)286ed9652daSAlexander Motin bus_space_write_8(bus_space_tag_t tag, bus_space_handle_t handle,
287ed9652daSAlexander Motin     bus_size_t offset, uint64_t val)
288ed9652daSAlexander Motin {
289ed9652daSAlexander Motin 
290ed9652daSAlexander Motin 	bus_space_write_4(tag, handle, offset, val);
291ed9652daSAlexander Motin 	bus_space_write_4(tag, handle, offset + 4, val >> 32);
292ed9652daSAlexander Motin }
293ed9652daSAlexander Motin #endif
294ed9652daSAlexander Motin 
295ed9652daSAlexander Motin #define intel_ntb_bar_read(SIZE, bar, offset) \
296ed9652daSAlexander Motin 	    bus_space_read_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \
297ed9652daSAlexander Motin 	    ntb->bar_info[(bar)].pci_bus_handle, (offset))
298ed9652daSAlexander Motin #define intel_ntb_bar_write(SIZE, bar, offset, val) \
299ed9652daSAlexander Motin 	    bus_space_write_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \
300ed9652daSAlexander Motin 	    ntb->bar_info[(bar)].pci_bus_handle, (offset), (val))
301ed9652daSAlexander Motin #define intel_ntb_reg_read(SIZE, offset) \
302ed9652daSAlexander Motin 	    intel_ntb_bar_read(SIZE, NTB_CONFIG_BAR, offset)
303ed9652daSAlexander Motin #define intel_ntb_reg_write(SIZE, offset, val) \
304ed9652daSAlexander Motin 	    intel_ntb_bar_write(SIZE, NTB_CONFIG_BAR, offset, val)
305ed9652daSAlexander Motin #define intel_ntb_mw_read(SIZE, offset) \
306ed9652daSAlexander Motin 	    intel_ntb_bar_read(SIZE, intel_ntb_mw_to_bar(ntb, ntb->b2b_mw_idx), \
307ed9652daSAlexander Motin 		offset)
308ed9652daSAlexander Motin #define intel_ntb_mw_write(SIZE, offset, val) \
309ed9652daSAlexander Motin 	    intel_ntb_bar_write(SIZE, intel_ntb_mw_to_bar(ntb, ntb->b2b_mw_idx), \
310ed9652daSAlexander Motin 		offset, val)
311ed9652daSAlexander Motin 
312ed9652daSAlexander Motin static int intel_ntb_probe(device_t device);
313ed9652daSAlexander Motin static int intel_ntb_attach(device_t device);
314ed9652daSAlexander Motin static int intel_ntb_detach(device_t device);
315ed9652daSAlexander Motin static uint64_t intel_ntb_db_valid_mask(device_t dev);
316ed9652daSAlexander Motin static void intel_ntb_spad_clear(device_t dev);
317ed9652daSAlexander Motin static uint64_t intel_ntb_db_vector_mask(device_t dev, uint32_t vector);
318ed9652daSAlexander Motin static bool intel_ntb_link_is_up(device_t dev, enum ntb_speed *speed,
319ed9652daSAlexander Motin     enum ntb_width *width);
320ed9652daSAlexander Motin static int intel_ntb_link_enable(device_t dev, enum ntb_speed speed,
321ed9652daSAlexander Motin     enum ntb_width width);
322ed9652daSAlexander Motin static int intel_ntb_link_disable(device_t dev);
323ed9652daSAlexander Motin static int intel_ntb_spad_read(device_t dev, unsigned int idx, uint32_t *val);
324ed9652daSAlexander Motin static int intel_ntb_peer_spad_write(device_t dev, unsigned int idx, uint32_t val);
325ed9652daSAlexander Motin 
326ed9652daSAlexander Motin static unsigned intel_ntb_user_mw_to_idx(struct ntb_softc *, unsigned uidx);
327ed9652daSAlexander Motin static inline enum ntb_bar intel_ntb_mw_to_bar(struct ntb_softc *, unsigned mw);
328ed9652daSAlexander Motin static inline bool bar_is_64bit(struct ntb_softc *, enum ntb_bar);
329ed9652daSAlexander Motin static inline void bar_get_xlat_params(struct ntb_softc *, enum ntb_bar,
330ed9652daSAlexander Motin     uint32_t *base, uint32_t *xlat, uint32_t *lmt);
331ed9652daSAlexander Motin static int intel_ntb_map_pci_bars(struct ntb_softc *ntb);
332ed9652daSAlexander Motin static int intel_ntb_mw_set_wc_internal(struct ntb_softc *, unsigned idx,
333ed9652daSAlexander Motin     vm_memattr_t);
334ed9652daSAlexander Motin static void print_map_success(struct ntb_softc *, struct ntb_pci_bar_info *,
335ed9652daSAlexander Motin     const char *);
336ed9652daSAlexander Motin static int map_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar);
337ed9652daSAlexander Motin static int map_memory_window_bar(struct ntb_softc *ntb,
338ed9652daSAlexander Motin     struct ntb_pci_bar_info *bar);
339ed9652daSAlexander Motin static void intel_ntb_unmap_pci_bar(struct ntb_softc *ntb);
340ed9652daSAlexander Motin static int intel_ntb_remap_msix(device_t, uint32_t desired, uint32_t avail);
341ed9652daSAlexander Motin static int intel_ntb_init_isr(struct ntb_softc *ntb);
3426660ef6eSMark Johnston static int intel_ntb_xeon_gen3_init_isr(struct ntb_softc *ntb);
343ed9652daSAlexander Motin static int intel_ntb_setup_legacy_interrupt(struct ntb_softc *ntb);
344ed9652daSAlexander Motin static int intel_ntb_setup_msix(struct ntb_softc *ntb, uint32_t num_vectors);
345ed9652daSAlexander Motin static void intel_ntb_teardown_interrupts(struct ntb_softc *ntb);
346ed9652daSAlexander Motin static inline uint64_t intel_ntb_vec_mask(struct ntb_softc *, uint64_t db_vector);
347ed9652daSAlexander Motin static void intel_ntb_interrupt(struct ntb_softc *, uint32_t vec);
348ed9652daSAlexander Motin static void ndev_vec_isr(void *arg);
349ed9652daSAlexander Motin static void ndev_irq_isr(void *arg);
350ed9652daSAlexander Motin static inline uint64_t db_ioread(struct ntb_softc *, uint64_t regoff);
351ed9652daSAlexander Motin static inline void db_iowrite(struct ntb_softc *, uint64_t regoff, uint64_t);
352ed9652daSAlexander Motin static inline void db_iowrite_raw(struct ntb_softc *, uint64_t regoff, uint64_t);
353ed9652daSAlexander Motin static int intel_ntb_create_msix_vec(struct ntb_softc *ntb, uint32_t num_vectors);
354ed9652daSAlexander Motin static void intel_ntb_free_msix_vec(struct ntb_softc *ntb);
355ed9652daSAlexander Motin static void intel_ntb_get_msix_info(struct ntb_softc *ntb);
356ed9652daSAlexander Motin static void intel_ntb_exchange_msix(void *);
357ed9652daSAlexander Motin static struct ntb_hw_info *intel_ntb_get_device_info(uint32_t device_id);
358ed9652daSAlexander Motin static void intel_ntb_detect_max_mw(struct ntb_softc *ntb);
359ed9652daSAlexander Motin static int intel_ntb_detect_xeon(struct ntb_softc *ntb);
3606660ef6eSMark Johnston static int intel_ntb_detect_xeon_gen3(struct ntb_softc *ntb);
361*70450ecdSAustin Zhang static int intel_ntb_detect_xeon_gen4(struct ntb_softc *ntb);
362*70450ecdSAustin Zhang static int intel_ntb_detect_xeon_gen4_cfg(struct ntb_softc *ntb);
363ed9652daSAlexander Motin static int intel_ntb_detect_atom(struct ntb_softc *ntb);
364ed9652daSAlexander Motin static int intel_ntb_xeon_init_dev(struct ntb_softc *ntb);
3656660ef6eSMark Johnston static int intel_ntb_xeon_gen3_init_dev(struct ntb_softc *ntb);
366*70450ecdSAustin Zhang static int intel_ntb_xeon_gen4_init_dev(struct ntb_softc *ntb);
367ed9652daSAlexander Motin static int intel_ntb_atom_init_dev(struct ntb_softc *ntb);
368ed9652daSAlexander Motin static void intel_ntb_teardown_xeon(struct ntb_softc *ntb);
369ed9652daSAlexander Motin static void configure_atom_secondary_side_bars(struct ntb_softc *ntb);
370ed9652daSAlexander Motin static void xeon_reset_sbar_size(struct ntb_softc *, enum ntb_bar idx,
371ed9652daSAlexander Motin     enum ntb_bar regbar);
372ed9652daSAlexander Motin static void xeon_set_sbar_base_and_limit(struct ntb_softc *,
373ed9652daSAlexander Motin     uint64_t base_addr, enum ntb_bar idx, enum ntb_bar regbar);
374ed9652daSAlexander Motin static void xeon_set_pbar_xlat(struct ntb_softc *, uint64_t base_addr,
375ed9652daSAlexander Motin     enum ntb_bar idx);
376ed9652daSAlexander Motin static int xeon_setup_b2b_mw(struct ntb_softc *,
377ed9652daSAlexander Motin     const struct ntb_b2b_addr *addr, const struct ntb_b2b_addr *peer_addr);
3786660ef6eSMark Johnston static int xeon_gen3_setup_b2b_mw(struct ntb_softc *);
379*70450ecdSAustin Zhang static int xeon_gen4_setup_b2b_mw(struct ntb_softc *);
3806660ef6eSMark Johnston static int intel_ntb_mw_set_trans(device_t dev, unsigned idx, bus_addr_t addr,
3816660ef6eSMark Johnston     size_t size);
382ed9652daSAlexander Motin static inline bool link_is_up(struct ntb_softc *ntb);
383ed9652daSAlexander Motin static inline bool _xeon_link_is_up(struct ntb_softc *ntb);
384ed9652daSAlexander Motin static inline bool atom_link_is_err(struct ntb_softc *ntb);
385ed9652daSAlexander Motin static inline enum ntb_speed intel_ntb_link_sta_speed(struct ntb_softc *);
386ed9652daSAlexander Motin static inline enum ntb_width intel_ntb_link_sta_width(struct ntb_softc *);
387ed9652daSAlexander Motin static void atom_link_hb(void *arg);
388ed9652daSAlexander Motin static void recover_atom_link(void *arg);
389ed9652daSAlexander Motin static bool intel_ntb_poll_link(struct ntb_softc *ntb);
390ed9652daSAlexander Motin static void save_bar_parameters(struct ntb_pci_bar_info *bar);
391ed9652daSAlexander Motin static void intel_ntb_sysctl_init(struct ntb_softc *);
392ed9652daSAlexander Motin static int sysctl_handle_features(SYSCTL_HANDLER_ARGS);
393ed9652daSAlexander Motin static int sysctl_handle_link_admin(SYSCTL_HANDLER_ARGS);
394ed9652daSAlexander Motin static int sysctl_handle_link_status_human(SYSCTL_HANDLER_ARGS);
395ed9652daSAlexander Motin static int sysctl_handle_link_status(SYSCTL_HANDLER_ARGS);
396ed9652daSAlexander Motin static int sysctl_handle_register(SYSCTL_HANDLER_ARGS);
397ed9652daSAlexander Motin 
398ed9652daSAlexander Motin static unsigned g_ntb_hw_debug_level;
399ed9652daSAlexander Motin SYSCTL_UINT(_hw_ntb, OID_AUTO, debug_level, CTLFLAG_RWTUN,
400ed9652daSAlexander Motin     &g_ntb_hw_debug_level, 0, "ntb_hw log level -- higher is more verbose");
401ed9652daSAlexander Motin #define intel_ntb_printf(lvl, ...) do {				\
402ed9652daSAlexander Motin 	if ((lvl) <= g_ntb_hw_debug_level) {			\
403ed9652daSAlexander Motin 		device_printf(ntb->device, __VA_ARGS__);	\
404ed9652daSAlexander Motin 	}							\
405ed9652daSAlexander Motin } while (0)
406ed9652daSAlexander Motin 
407ed9652daSAlexander Motin #define	_NTB_PAT_UC	0
408ed9652daSAlexander Motin #define	_NTB_PAT_WC	1
409ed9652daSAlexander Motin #define	_NTB_PAT_WT	4
410ed9652daSAlexander Motin #define	_NTB_PAT_WP	5
411ed9652daSAlexander Motin #define	_NTB_PAT_WB	6
412ed9652daSAlexander Motin #define	_NTB_PAT_UCM	7
413ed9652daSAlexander Motin static unsigned g_ntb_mw_pat = _NTB_PAT_UC;
414ed9652daSAlexander Motin SYSCTL_UINT(_hw_ntb, OID_AUTO, default_mw_pat, CTLFLAG_RDTUN,
415ed9652daSAlexander Motin     &g_ntb_mw_pat, 0, "Configure the default memory window cache flags (PAT): "
416ed9652daSAlexander Motin     "UC: "  __XSTRING(_NTB_PAT_UC) ", "
417ed9652daSAlexander Motin     "WC: "  __XSTRING(_NTB_PAT_WC) ", "
418ed9652daSAlexander Motin     "WT: "  __XSTRING(_NTB_PAT_WT) ", "
419ed9652daSAlexander Motin     "WP: "  __XSTRING(_NTB_PAT_WP) ", "
420ed9652daSAlexander Motin     "WB: "  __XSTRING(_NTB_PAT_WB) ", "
421ed9652daSAlexander Motin     "UC-: " __XSTRING(_NTB_PAT_UCM));
422ed9652daSAlexander Motin 
423ed9652daSAlexander Motin static inline vm_memattr_t
intel_ntb_pat_flags(void)424ed9652daSAlexander Motin intel_ntb_pat_flags(void)
425ed9652daSAlexander Motin {
426ed9652daSAlexander Motin 
427ed9652daSAlexander Motin 	switch (g_ntb_mw_pat) {
428ed9652daSAlexander Motin 	case _NTB_PAT_WC:
429ed9652daSAlexander Motin 		return (VM_MEMATTR_WRITE_COMBINING);
430ed9652daSAlexander Motin 	case _NTB_PAT_WT:
431ed9652daSAlexander Motin 		return (VM_MEMATTR_WRITE_THROUGH);
432ed9652daSAlexander Motin 	case _NTB_PAT_WP:
433ed9652daSAlexander Motin 		return (VM_MEMATTR_WRITE_PROTECTED);
434ed9652daSAlexander Motin 	case _NTB_PAT_WB:
435ed9652daSAlexander Motin 		return (VM_MEMATTR_WRITE_BACK);
436ed9652daSAlexander Motin 	case _NTB_PAT_UCM:
437ed9652daSAlexander Motin 		return (VM_MEMATTR_WEAK_UNCACHEABLE);
438ed9652daSAlexander Motin 	case _NTB_PAT_UC:
439ed9652daSAlexander Motin 		/* FALLTHROUGH */
440ed9652daSAlexander Motin 	default:
441ed9652daSAlexander Motin 		return (VM_MEMATTR_UNCACHEABLE);
442ed9652daSAlexander Motin 	}
443ed9652daSAlexander Motin }
444ed9652daSAlexander Motin 
445ed9652daSAlexander Motin /*
446ed9652daSAlexander Motin  * Well, this obviously doesn't belong here, but it doesn't seem to exist
447ed9652daSAlexander Motin  * anywhere better yet.
448ed9652daSAlexander Motin  */
449ed9652daSAlexander Motin static inline const char *
intel_ntb_vm_memattr_to_str(vm_memattr_t pat)450ed9652daSAlexander Motin intel_ntb_vm_memattr_to_str(vm_memattr_t pat)
451ed9652daSAlexander Motin {
452ed9652daSAlexander Motin 
453ed9652daSAlexander Motin 	switch (pat) {
454ed9652daSAlexander Motin 	case VM_MEMATTR_WRITE_COMBINING:
455ed9652daSAlexander Motin 		return ("WRITE_COMBINING");
456ed9652daSAlexander Motin 	case VM_MEMATTR_WRITE_THROUGH:
457ed9652daSAlexander Motin 		return ("WRITE_THROUGH");
458ed9652daSAlexander Motin 	case VM_MEMATTR_WRITE_PROTECTED:
459ed9652daSAlexander Motin 		return ("WRITE_PROTECTED");
460ed9652daSAlexander Motin 	case VM_MEMATTR_WRITE_BACK:
461ed9652daSAlexander Motin 		return ("WRITE_BACK");
462ed9652daSAlexander Motin 	case VM_MEMATTR_WEAK_UNCACHEABLE:
463ed9652daSAlexander Motin 		return ("UNCACHED");
464ed9652daSAlexander Motin 	case VM_MEMATTR_UNCACHEABLE:
465ed9652daSAlexander Motin 		return ("UNCACHEABLE");
466ed9652daSAlexander Motin 	default:
467ed9652daSAlexander Motin 		return ("UNKNOWN");
468ed9652daSAlexander Motin 	}
469ed9652daSAlexander Motin }
470ed9652daSAlexander Motin 
471ed9652daSAlexander Motin static int g_ntb_msix_idx = 1;
472ed9652daSAlexander Motin SYSCTL_INT(_hw_ntb, OID_AUTO, msix_mw_idx, CTLFLAG_RDTUN, &g_ntb_msix_idx,
473ed9652daSAlexander Motin     0, "Use this memory window to access the peer MSIX message complex on "
474ed9652daSAlexander Motin     "certain Xeon-based NTB systems, as a workaround for a hardware errata.  "
475ed9652daSAlexander Motin     "Like b2b_mw_idx, negative values index from the last available memory "
476ed9652daSAlexander Motin     "window.  (Applies on Xeon platforms with SB01BASE_LOCKUP errata.)");
477ed9652daSAlexander Motin 
478ed9652daSAlexander Motin static int g_ntb_mw_idx = -1;
479ed9652daSAlexander Motin SYSCTL_INT(_hw_ntb, OID_AUTO, b2b_mw_idx, CTLFLAG_RDTUN, &g_ntb_mw_idx,
480ed9652daSAlexander Motin     0, "Use this memory window to access the peer NTB registers.  A "
481ed9652daSAlexander Motin     "non-negative value starts from the first MW index; a negative value "
482ed9652daSAlexander Motin     "starts from the last MW index.  The default is -1, i.e., the last "
483ed9652daSAlexander Motin     "available memory window.  Both sides of the NTB MUST set the same "
484ed9652daSAlexander Motin     "value here!  (Applies on Xeon platforms with SDOORBELL_LOCKUP errata.)");
485ed9652daSAlexander Motin 
486ed9652daSAlexander Motin /* Hardware owns the low 16 bits of features. */
487ed9652daSAlexander Motin #define NTB_BAR_SIZE_4K		(1 << 0)
488ed9652daSAlexander Motin #define NTB_SDOORBELL_LOCKUP	(1 << 1)
489ed9652daSAlexander Motin #define NTB_SB01BASE_LOCKUP	(1 << 2)
490ed9652daSAlexander Motin #define NTB_B2BDOORBELL_BIT14	(1 << 3)
491*70450ecdSAustin Zhang #define NTB_BAR_ALIGN		(1 << 4)
492*70450ecdSAustin Zhang #define NTB_LTR_BAD			(1 << 5)
493ed9652daSAlexander Motin /* Software/configuration owns the top 16 bits. */
494ed9652daSAlexander Motin #define NTB_SPLIT_BAR		(1ull << 16)
4956660ef6eSMark Johnston #define NTB_ONE_MSIX		(1ull << 17)
496ed9652daSAlexander Motin 
497ed9652daSAlexander Motin #define NTB_FEATURES_STR \
498*70450ecdSAustin Zhang     "\20\21SPLIT_BAR4\06LTR_BAD\05BAR_ALIGN"  \
499*70450ecdSAustin Zhang 	"\04B2B_DOORBELL_BIT14\03SB01BASE_LOCKUP" \
500ed9652daSAlexander Motin     "\02SDOORBELL_LOCKUP\01BAR_SIZE_4K"
501ed9652daSAlexander Motin 
502ed9652daSAlexander Motin static struct ntb_hw_info pci_ids[] = {
503ed9652daSAlexander Motin 	/* XXX: PS/SS IDs left out until they are supported. */
504ed9652daSAlexander Motin 	{ 0x0C4E8086, "BWD Atom Processor S1200 Non-Transparent Bridge B2B",
505ed9652daSAlexander Motin 		NTB_ATOM, 0 },
506ed9652daSAlexander Motin 
507ed9652daSAlexander Motin 	{ 0x37258086, "JSF Xeon C35xx/C55xx Non-Transparent Bridge B2B",
5086660ef6eSMark Johnston 		NTB_XEON_GEN1, NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 },
509ed9652daSAlexander Motin 	{ 0x3C0D8086, "SNB Xeon E5/Core i7 Non-Transparent Bridge B2B",
5106660ef6eSMark Johnston 		NTB_XEON_GEN1, NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 },
5116660ef6eSMark Johnston 	{ 0x0E0D8086, "IVT Xeon E5 V2 Non-Transparent Bridge B2B",
5126660ef6eSMark Johnston 		NTB_XEON_GEN1, NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 |
513ed9652daSAlexander Motin 		    NTB_SB01BASE_LOCKUP | NTB_BAR_SIZE_4K },
5146660ef6eSMark Johnston 	{ 0x2F0D8086, "HSX Xeon E5 V3 Non-Transparent Bridge B2B",
5156660ef6eSMark Johnston 		NTB_XEON_GEN1, NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 |
516ed9652daSAlexander Motin 		    NTB_SB01BASE_LOCKUP },
5176660ef6eSMark Johnston 	{ 0x6F0D8086, "BDX Xeon E5 V4 Non-Transparent Bridge B2B",
5186660ef6eSMark Johnston 		NTB_XEON_GEN1, NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 |
519ed9652daSAlexander Motin 		    NTB_SB01BASE_LOCKUP },
5206660ef6eSMark Johnston 
5216660ef6eSMark Johnston 	{ 0x201C8086, "SKL Xeon E5 V5 Non-Transparent Bridge B2B",
5226660ef6eSMark Johnston 		NTB_XEON_GEN3, 0 },
523*70450ecdSAustin Zhang 
524*70450ecdSAustin Zhang 	{ 0x347e8086, "ICX/SPR Xeon Non-Transparent Bridge B2B",
525*70450ecdSAustin Zhang 	    NTB_XEON_GEN4, 0 },
526ed9652daSAlexander Motin };
527ed9652daSAlexander Motin 
528ed9652daSAlexander Motin static const struct ntb_reg atom_reg = {
529ed9652daSAlexander Motin 	.ntb_ctl = ATOM_NTBCNTL_OFFSET,
530ed9652daSAlexander Motin 	.lnk_sta = ATOM_LINK_STATUS_OFFSET,
531ed9652daSAlexander Motin 	.db_size = sizeof(uint64_t),
532ed9652daSAlexander Motin 	.mw_bar = { NTB_B2B_BAR_1, NTB_B2B_BAR_2 },
533ed9652daSAlexander Motin };
534ed9652daSAlexander Motin 
535ed9652daSAlexander Motin static const struct ntb_alt_reg atom_pri_reg = {
536ed9652daSAlexander Motin 	.db_bell = ATOM_PDOORBELL_OFFSET,
537ed9652daSAlexander Motin 	.db_mask = ATOM_PDBMSK_OFFSET,
538ed9652daSAlexander Motin 	.spad = ATOM_SPAD_OFFSET,
539ed9652daSAlexander Motin };
540ed9652daSAlexander Motin 
541ed9652daSAlexander Motin static const struct ntb_alt_reg atom_b2b_reg = {
542ed9652daSAlexander Motin 	.db_bell = ATOM_B2B_DOORBELL_OFFSET,
543ed9652daSAlexander Motin 	.spad = ATOM_B2B_SPAD_OFFSET,
544ed9652daSAlexander Motin };
545ed9652daSAlexander Motin 
546ed9652daSAlexander Motin static const struct ntb_xlat_reg atom_sec_xlat = {
547ed9652daSAlexander Motin #if 0
548ed9652daSAlexander Motin 	/* "FIXME" says the Linux driver. */
549ed9652daSAlexander Motin 	.bar0_base = ATOM_SBAR0BASE_OFFSET,
550ed9652daSAlexander Motin 	.bar2_base = ATOM_SBAR2BASE_OFFSET,
551ed9652daSAlexander Motin 	.bar4_base = ATOM_SBAR4BASE_OFFSET,
552ed9652daSAlexander Motin 
553ed9652daSAlexander Motin 	.bar2_limit = ATOM_SBAR2LMT_OFFSET,
554ed9652daSAlexander Motin 	.bar4_limit = ATOM_SBAR4LMT_OFFSET,
555ed9652daSAlexander Motin #endif
556ed9652daSAlexander Motin 
557ed9652daSAlexander Motin 	.bar2_xlat = ATOM_SBAR2XLAT_OFFSET,
558ed9652daSAlexander Motin 	.bar4_xlat = ATOM_SBAR4XLAT_OFFSET,
559ed9652daSAlexander Motin };
560ed9652daSAlexander Motin 
561ed9652daSAlexander Motin static const struct ntb_reg xeon_reg = {
562ed9652daSAlexander Motin 	.ntb_ctl = XEON_NTBCNTL_OFFSET,
563ed9652daSAlexander Motin 	.lnk_sta = XEON_LINK_STATUS_OFFSET,
564ed9652daSAlexander Motin 	.db_size = sizeof(uint16_t),
565ed9652daSAlexander Motin 	.mw_bar = { NTB_B2B_BAR_1, NTB_B2B_BAR_2, NTB_B2B_BAR_3 },
566ed9652daSAlexander Motin };
567ed9652daSAlexander Motin 
568ed9652daSAlexander Motin static const struct ntb_alt_reg xeon_pri_reg = {
569ed9652daSAlexander Motin 	.db_bell = XEON_PDOORBELL_OFFSET,
570ed9652daSAlexander Motin 	.db_mask = XEON_PDBMSK_OFFSET,
571ed9652daSAlexander Motin 	.spad = XEON_SPAD_OFFSET,
572ed9652daSAlexander Motin };
573ed9652daSAlexander Motin 
574ed9652daSAlexander Motin static const struct ntb_alt_reg xeon_b2b_reg = {
575ed9652daSAlexander Motin 	.db_bell = XEON_B2B_DOORBELL_OFFSET,
576ed9652daSAlexander Motin 	.spad = XEON_B2B_SPAD_OFFSET,
577ed9652daSAlexander Motin };
578ed9652daSAlexander Motin 
579ed9652daSAlexander Motin static const struct ntb_xlat_reg xeon_sec_xlat = {
580ed9652daSAlexander Motin 	.bar0_base = XEON_SBAR0BASE_OFFSET,
581ed9652daSAlexander Motin 	.bar2_base = XEON_SBAR2BASE_OFFSET,
582ed9652daSAlexander Motin 	.bar4_base = XEON_SBAR4BASE_OFFSET,
583ed9652daSAlexander Motin 	.bar5_base = XEON_SBAR5BASE_OFFSET,
584ed9652daSAlexander Motin 
585ed9652daSAlexander Motin 	.bar2_limit = XEON_SBAR2LMT_OFFSET,
586ed9652daSAlexander Motin 	.bar4_limit = XEON_SBAR4LMT_OFFSET,
587ed9652daSAlexander Motin 	.bar5_limit = XEON_SBAR5LMT_OFFSET,
588ed9652daSAlexander Motin 
589ed9652daSAlexander Motin 	.bar2_xlat = XEON_SBAR2XLAT_OFFSET,
590ed9652daSAlexander Motin 	.bar4_xlat = XEON_SBAR4XLAT_OFFSET,
591ed9652daSAlexander Motin 	.bar5_xlat = XEON_SBAR5XLAT_OFFSET,
592ed9652daSAlexander Motin };
593ed9652daSAlexander Motin 
594ed9652daSAlexander Motin static struct ntb_b2b_addr xeon_b2b_usd_addr = {
595ed9652daSAlexander Motin 	.bar0_addr = XEON_B2B_BAR0_ADDR,
596ed9652daSAlexander Motin 	.bar2_addr64 = XEON_B2B_BAR2_ADDR64,
597ed9652daSAlexander Motin 	.bar4_addr64 = XEON_B2B_BAR4_ADDR64,
598ed9652daSAlexander Motin 	.bar4_addr32 = XEON_B2B_BAR4_ADDR32,
599ed9652daSAlexander Motin 	.bar5_addr32 = XEON_B2B_BAR5_ADDR32,
600ed9652daSAlexander Motin };
601ed9652daSAlexander Motin 
602ed9652daSAlexander Motin static struct ntb_b2b_addr xeon_b2b_dsd_addr = {
603ed9652daSAlexander Motin 	.bar0_addr = XEON_B2B_BAR0_ADDR,
604ed9652daSAlexander Motin 	.bar2_addr64 = XEON_B2B_BAR2_ADDR64,
605ed9652daSAlexander Motin 	.bar4_addr64 = XEON_B2B_BAR4_ADDR64,
606ed9652daSAlexander Motin 	.bar4_addr32 = XEON_B2B_BAR4_ADDR32,
607ed9652daSAlexander Motin 	.bar5_addr32 = XEON_B2B_BAR5_ADDR32,
608ed9652daSAlexander Motin };
609ed9652daSAlexander Motin 
6106660ef6eSMark Johnston static const struct ntb_reg xeon_gen3_reg = {
6116660ef6eSMark Johnston 	.ntb_ctl = XEON_GEN3_REG_IMNTB_CTRL,
6126660ef6eSMark Johnston 	.lnk_sta = XEON_GEN3_INT_LNK_STS_OFFSET,
6136660ef6eSMark Johnston 	.db_size = sizeof(uint32_t),
6146660ef6eSMark Johnston 	.mw_bar = { NTB_B2B_BAR_1, NTB_B2B_BAR_2 },
6156660ef6eSMark Johnston };
6166660ef6eSMark Johnston 
6176660ef6eSMark Johnston static const struct ntb_alt_reg xeon_gen3_pri_reg = {
6186660ef6eSMark Johnston 	.db_bell = XEON_GEN3_REG_EMDOORBELL,
6196660ef6eSMark Johnston 	.db_mask = XEON_GEN3_REG_IMINT_DISABLE,
6206660ef6eSMark Johnston 	.spad = XEON_GEN3_REG_IMSPAD,
6216660ef6eSMark Johnston };
6226660ef6eSMark Johnston 
6236660ef6eSMark Johnston static const struct ntb_alt_reg xeon_gen3_b2b_reg = {
6246660ef6eSMark Johnston 	.db_bell = XEON_GEN3_REG_IMDOORBELL,
6256660ef6eSMark Johnston 	.db_mask = XEON_GEN3_REG_EMINT_DISABLE,
6266660ef6eSMark Johnston 	.spad = XEON_GEN3_REG_IMB2B_SSPAD,
6276660ef6eSMark Johnston };
6286660ef6eSMark Johnston 
6296660ef6eSMark Johnston static const struct ntb_xlat_reg xeon_gen3_sec_xlat = {
6306660ef6eSMark Johnston 	.bar0_base = XEON_GEN3_EXT_REG_BAR0BASE,
6316660ef6eSMark Johnston 	.bar2_base = XEON_GEN3_EXT_REG_BAR1BASE,
6326660ef6eSMark Johnston 	.bar4_base = XEON_GEN3_EXT_REG_BAR2BASE,
6336660ef6eSMark Johnston 
6346660ef6eSMark Johnston 	.bar2_limit = XEON_GEN3_REG_IMBAR1XLIMIT,
6356660ef6eSMark Johnston 	.bar4_limit = XEON_GEN3_REG_IMBAR2XLIMIT,
6366660ef6eSMark Johnston 
6376660ef6eSMark Johnston 	.bar2_xlat = XEON_GEN3_REG_IMBAR1XBASE,
6386660ef6eSMark Johnston 	.bar4_xlat = XEON_GEN3_REG_IMBAR2XBASE,
6396660ef6eSMark Johnston };
6406660ef6eSMark Johnston 
641*70450ecdSAustin Zhang static const struct ntb_reg xeon_gen4_reg = {
642*70450ecdSAustin Zhang 	.ntb_ctl = XEON_GEN4_REG_IMNTB_CTL,
643*70450ecdSAustin Zhang 	.lnk_sta = XEON_GEN4_REG_LINK_STATUS, /* mmio */
644*70450ecdSAustin Zhang 	.db_size = sizeof(uint32_t),
645*70450ecdSAustin Zhang 	.mw_bar = { NTB_B2B_BAR_1, NTB_B2B_BAR_2 },
646*70450ecdSAustin Zhang };
647*70450ecdSAustin Zhang 
648*70450ecdSAustin Zhang static const struct ntb_alt_reg xeon_gen4_pri_reg = {
649*70450ecdSAustin Zhang 	.db_clear = XEON_GEN4_REG_IMINT_STATUS,
650*70450ecdSAustin Zhang 	.db_mask = XEON_GEN4_REG_IMINT_DISABLE,
651*70450ecdSAustin Zhang 	.spad = XEON_GEN4_REG_IMSPAD,
652*70450ecdSAustin Zhang };
653*70450ecdSAustin Zhang 
654*70450ecdSAustin Zhang static const struct ntb_alt_reg xeon_gen4_b2b_reg = {
655*70450ecdSAustin Zhang 	.db_bell = XEON_GEN4_REG_IMDOORBELL,
656*70450ecdSAustin Zhang 	.spad = XEON_GEN4_REG_EMSPAD,
657*70450ecdSAustin Zhang };
658*70450ecdSAustin Zhang 
659*70450ecdSAustin Zhang static const struct ntb_xlat_reg xeon_gen4_sec_xlat = {
660*70450ecdSAustin Zhang 	.bar2_limit = XEON_GEN4_REG_IMBAR1XLIMIT,
661*70450ecdSAustin Zhang 	.bar2_xlat = XEON_GEN4_REG_IMBAR1XBASE,
662*70450ecdSAustin Zhang 
663*70450ecdSAustin Zhang 	.bar4_limit = XEON_GEN4_REG_IMBAR1XLIMIT,
664*70450ecdSAustin Zhang 	.bar4_xlat = XEON_GEN4_REG_IMBAR2XBASE,
665*70450ecdSAustin Zhang };
666*70450ecdSAustin Zhang 
6677029da5cSPawel Biernacki SYSCTL_NODE(_hw_ntb, OID_AUTO, xeon_b2b, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
668ed9652daSAlexander Motin     "B2B MW segment overrides -- MUST be the same on both sides");
669ed9652daSAlexander Motin 
670ed9652daSAlexander Motin SYSCTL_UQUAD(_hw_ntb_xeon_b2b, OID_AUTO, usd_bar2_addr64, CTLFLAG_RDTUN,
671ed9652daSAlexander Motin     &xeon_b2b_usd_addr.bar2_addr64, 0, "If using B2B topology on Xeon "
672ed9652daSAlexander Motin     "hardware, use this 64-bit address on the bus between the NTB devices for "
673ed9652daSAlexander Motin     "the window at BAR2, on the upstream side of the link.  MUST be the same "
674ed9652daSAlexander Motin     "address on both sides.");
675ed9652daSAlexander Motin SYSCTL_UQUAD(_hw_ntb_xeon_b2b, OID_AUTO, usd_bar4_addr64, CTLFLAG_RDTUN,
676ed9652daSAlexander Motin     &xeon_b2b_usd_addr.bar4_addr64, 0, "See usd_bar2_addr64, but BAR4.");
677ed9652daSAlexander Motin SYSCTL_UQUAD(_hw_ntb_xeon_b2b, OID_AUTO, usd_bar4_addr32, CTLFLAG_RDTUN,
678ed9652daSAlexander Motin     &xeon_b2b_usd_addr.bar4_addr32, 0, "See usd_bar2_addr64, but BAR4 "
679ed9652daSAlexander Motin     "(split-BAR mode).");
680ed9652daSAlexander Motin SYSCTL_UQUAD(_hw_ntb_xeon_b2b, OID_AUTO, usd_bar5_addr32, CTLFLAG_RDTUN,
681ed9652daSAlexander Motin     &xeon_b2b_usd_addr.bar5_addr32, 0, "See usd_bar2_addr64, but BAR5 "
682ed9652daSAlexander Motin     "(split-BAR mode).");
683ed9652daSAlexander Motin 
684ed9652daSAlexander Motin SYSCTL_UQUAD(_hw_ntb_xeon_b2b, OID_AUTO, dsd_bar2_addr64, CTLFLAG_RDTUN,
685ed9652daSAlexander Motin     &xeon_b2b_dsd_addr.bar2_addr64, 0, "If using B2B topology on Xeon "
686ed9652daSAlexander Motin     "hardware, use this 64-bit address on the bus between the NTB devices for "
687ed9652daSAlexander Motin     "the window at BAR2, on the downstream side of the link.  MUST be the same"
688ed9652daSAlexander Motin     " address on both sides.");
689ed9652daSAlexander Motin SYSCTL_UQUAD(_hw_ntb_xeon_b2b, OID_AUTO, dsd_bar4_addr64, CTLFLAG_RDTUN,
690ed9652daSAlexander Motin     &xeon_b2b_dsd_addr.bar4_addr64, 0, "See dsd_bar2_addr64, but BAR4.");
691ed9652daSAlexander Motin SYSCTL_UQUAD(_hw_ntb_xeon_b2b, OID_AUTO, dsd_bar4_addr32, CTLFLAG_RDTUN,
692ed9652daSAlexander Motin     &xeon_b2b_dsd_addr.bar4_addr32, 0, "See dsd_bar2_addr64, but BAR4 "
693ed9652daSAlexander Motin     "(split-BAR mode).");
694ed9652daSAlexander Motin SYSCTL_UQUAD(_hw_ntb_xeon_b2b, OID_AUTO, dsd_bar5_addr32, CTLFLAG_RDTUN,
695ed9652daSAlexander Motin     &xeon_b2b_dsd_addr.bar5_addr32, 0, "See dsd_bar2_addr64, but BAR5 "
696ed9652daSAlexander Motin     "(split-BAR mode).");
697ed9652daSAlexander Motin 
698ed9652daSAlexander Motin /*
699ed9652daSAlexander Motin  * OS <-> Driver interface structures
700ed9652daSAlexander Motin  */
701ed9652daSAlexander Motin MALLOC_DEFINE(M_NTB, "ntb_hw", "ntb_hw driver memory allocations");
702ed9652daSAlexander Motin 
703ed9652daSAlexander Motin /*
704ed9652daSAlexander Motin  * OS <-> Driver linkage functions
705ed9652daSAlexander Motin  */
706ed9652daSAlexander Motin static int
intel_ntb_probe(device_t device)707ed9652daSAlexander Motin intel_ntb_probe(device_t device)
708ed9652daSAlexander Motin {
709ed9652daSAlexander Motin 	struct ntb_hw_info *p;
710ed9652daSAlexander Motin 
711ed9652daSAlexander Motin 	p = intel_ntb_get_device_info(pci_get_devid(device));
712ed9652daSAlexander Motin 	if (p == NULL)
713ed9652daSAlexander Motin 		return (ENXIO);
714ed9652daSAlexander Motin 
715ed9652daSAlexander Motin 	device_set_desc(device, p->desc);
716ed9652daSAlexander Motin 	return (0);
717ed9652daSAlexander Motin }
718ed9652daSAlexander Motin 
719ed9652daSAlexander Motin static int
intel_ntb_attach(device_t device)720ed9652daSAlexander Motin intel_ntb_attach(device_t device)
721ed9652daSAlexander Motin {
722ed9652daSAlexander Motin 	struct ntb_softc *ntb;
723ed9652daSAlexander Motin 	struct ntb_hw_info *p;
724ed9652daSAlexander Motin 	int error;
725ed9652daSAlexander Motin 
726ed9652daSAlexander Motin 	ntb = device_get_softc(device);
727ed9652daSAlexander Motin 	p = intel_ntb_get_device_info(pci_get_devid(device));
728ed9652daSAlexander Motin 
729ed9652daSAlexander Motin 	ntb->device = device;
730ed9652daSAlexander Motin 	ntb->type = p->type;
731ed9652daSAlexander Motin 	ntb->features = p->features;
732ed9652daSAlexander Motin 	ntb->b2b_mw_idx = B2B_MW_DISABLED;
733ed9652daSAlexander Motin 	ntb->msix_mw_idx = B2B_MW_DISABLED;
734ed9652daSAlexander Motin 
735ed9652daSAlexander Motin 	/* Heartbeat timer for NTB_ATOM since there is no link interrupt */
736ed9652daSAlexander Motin 	callout_init(&ntb->heartbeat_timer, 1);
737ed9652daSAlexander Motin 	callout_init(&ntb->lr_timer, 1);
738ed9652daSAlexander Motin 	callout_init(&ntb->peer_msix_work, 1);
739ed9652daSAlexander Motin 	mtx_init(&ntb->db_mask_lock, "ntb hw bits", NULL, MTX_SPIN);
740ed9652daSAlexander Motin 
741ed9652daSAlexander Motin 	if (ntb->type == NTB_ATOM)
742ed9652daSAlexander Motin 		error = intel_ntb_detect_atom(ntb);
7436660ef6eSMark Johnston 	else if (ntb->type == NTB_XEON_GEN3)
7446660ef6eSMark Johnston 		error = intel_ntb_detect_xeon_gen3(ntb);
745*70450ecdSAustin Zhang 	else if (ntb->type == NTB_XEON_GEN4)
746*70450ecdSAustin Zhang 		error = intel_ntb_detect_xeon_gen4(ntb);
747ed9652daSAlexander Motin 	else
748ed9652daSAlexander Motin 		error = intel_ntb_detect_xeon(ntb);
749ed9652daSAlexander Motin 	if (error != 0)
750ed9652daSAlexander Motin 		goto out;
751ed9652daSAlexander Motin 
752ed9652daSAlexander Motin 	intel_ntb_detect_max_mw(ntb);
753ed9652daSAlexander Motin 
754ed9652daSAlexander Motin 	pci_enable_busmaster(ntb->device);
755ed9652daSAlexander Motin 
756ed9652daSAlexander Motin 	error = intel_ntb_map_pci_bars(ntb);
757ed9652daSAlexander Motin 	if (error != 0)
758ed9652daSAlexander Motin 		goto out;
759ed9652daSAlexander Motin 	if (ntb->type == NTB_ATOM)
760ed9652daSAlexander Motin 		error = intel_ntb_atom_init_dev(ntb);
7616660ef6eSMark Johnston 	else if (ntb->type == NTB_XEON_GEN3)
7626660ef6eSMark Johnston 		error = intel_ntb_xeon_gen3_init_dev(ntb);
763*70450ecdSAustin Zhang 	else if (ntb->type == NTB_XEON_GEN4)
764*70450ecdSAustin Zhang 		error = intel_ntb_xeon_gen4_init_dev(ntb);
765ed9652daSAlexander Motin 	else
766ed9652daSAlexander Motin 		error = intel_ntb_xeon_init_dev(ntb);
767ed9652daSAlexander Motin 	if (error != 0)
768ed9652daSAlexander Motin 		goto out;
769ed9652daSAlexander Motin 
770ed9652daSAlexander Motin 	intel_ntb_spad_clear(device);
771ed9652daSAlexander Motin 
772ed9652daSAlexander Motin 	intel_ntb_poll_link(ntb);
773ed9652daSAlexander Motin 
774ed9652daSAlexander Motin 	intel_ntb_sysctl_init(ntb);
775ed9652daSAlexander Motin 
776ed9652daSAlexander Motin 	/* Attach children to this controller */
777ed9652daSAlexander Motin 	error = ntb_register_device(device);
778ed9652daSAlexander Motin 
779ed9652daSAlexander Motin out:
780ed9652daSAlexander Motin 	if (error != 0)
781ed9652daSAlexander Motin 		intel_ntb_detach(device);
782ed9652daSAlexander Motin 	return (error);
783ed9652daSAlexander Motin }
784ed9652daSAlexander Motin 
785ed9652daSAlexander Motin static int
intel_ntb_detach(device_t device)786ed9652daSAlexander Motin intel_ntb_detach(device_t device)
787ed9652daSAlexander Motin {
788ed9652daSAlexander Motin 	struct ntb_softc *ntb;
789ed9652daSAlexander Motin 
790ed9652daSAlexander Motin 	ntb = device_get_softc(device);
791ed9652daSAlexander Motin 
792ed9652daSAlexander Motin 	/* Detach & delete all children */
793ed9652daSAlexander Motin 	ntb_unregister_device(device);
794ed9652daSAlexander Motin 
795ed9652daSAlexander Motin 	if (ntb->self_reg != NULL) {
796ed9652daSAlexander Motin 		DB_MASK_LOCK(ntb);
797ed9652daSAlexander Motin 		db_iowrite(ntb, ntb->self_reg->db_mask, ntb->db_valid_mask);
798ed9652daSAlexander Motin 		DB_MASK_UNLOCK(ntb);
799ed9652daSAlexander Motin 	}
800ed9652daSAlexander Motin 	callout_drain(&ntb->heartbeat_timer);
801ed9652daSAlexander Motin 	callout_drain(&ntb->lr_timer);
802ed9652daSAlexander Motin 	callout_drain(&ntb->peer_msix_work);
803ed9652daSAlexander Motin 	pci_disable_busmaster(ntb->device);
8046660ef6eSMark Johnston 	if (ntb->type == NTB_XEON_GEN1)
805ed9652daSAlexander Motin 		intel_ntb_teardown_xeon(ntb);
806ed9652daSAlexander Motin 	intel_ntb_teardown_interrupts(ntb);
807ed9652daSAlexander Motin 
808ed9652daSAlexander Motin 	mtx_destroy(&ntb->db_mask_lock);
809ed9652daSAlexander Motin 
810ed9652daSAlexander Motin 	intel_ntb_unmap_pci_bar(ntb);
811ed9652daSAlexander Motin 
812ed9652daSAlexander Motin 	return (0);
813ed9652daSAlexander Motin }
814ed9652daSAlexander Motin 
815ed9652daSAlexander Motin /*
816ed9652daSAlexander Motin  * Driver internal routines
817ed9652daSAlexander Motin  */
818ed9652daSAlexander Motin static inline enum ntb_bar
intel_ntb_mw_to_bar(struct ntb_softc * ntb,unsigned mw)819ed9652daSAlexander Motin intel_ntb_mw_to_bar(struct ntb_softc *ntb, unsigned mw)
820ed9652daSAlexander Motin {
821ed9652daSAlexander Motin 
822ed9652daSAlexander Motin 	KASSERT(mw < ntb->mw_count,
823ed9652daSAlexander Motin 	    ("%s: mw:%u > count:%u", __func__, mw, (unsigned)ntb->mw_count));
824ed9652daSAlexander Motin 	KASSERT(ntb->reg->mw_bar[mw] != 0, ("invalid mw"));
825ed9652daSAlexander Motin 
826ed9652daSAlexander Motin 	return (ntb->reg->mw_bar[mw]);
827ed9652daSAlexander Motin }
828ed9652daSAlexander Motin 
829ed9652daSAlexander Motin static inline bool
bar_is_64bit(struct ntb_softc * ntb,enum ntb_bar bar)830ed9652daSAlexander Motin bar_is_64bit(struct ntb_softc *ntb, enum ntb_bar bar)
831ed9652daSAlexander Motin {
832ed9652daSAlexander Motin 	/* XXX This assertion could be stronger. */
833ed9652daSAlexander Motin 	KASSERT(bar < NTB_MAX_BARS, ("bogus bar"));
834ed9652daSAlexander Motin 	return (bar < NTB_B2B_BAR_2 || !HAS_FEATURE(ntb, NTB_SPLIT_BAR));
835ed9652daSAlexander Motin }
836ed9652daSAlexander Motin 
837ed9652daSAlexander Motin static inline void
bar_get_xlat_params(struct ntb_softc * ntb,enum ntb_bar bar,uint32_t * base,uint32_t * xlat,uint32_t * lmt)838ed9652daSAlexander Motin bar_get_xlat_params(struct ntb_softc *ntb, enum ntb_bar bar, uint32_t *base,
839ed9652daSAlexander Motin     uint32_t *xlat, uint32_t *lmt)
840ed9652daSAlexander Motin {
841ed9652daSAlexander Motin 	uint32_t basev, lmtv, xlatv;
842ed9652daSAlexander Motin 
843ed9652daSAlexander Motin 	switch (bar) {
844ed9652daSAlexander Motin 	case NTB_B2B_BAR_1:
845ed9652daSAlexander Motin 		basev = ntb->xlat_reg->bar2_base;
846ed9652daSAlexander Motin 		lmtv = ntb->xlat_reg->bar2_limit;
847ed9652daSAlexander Motin 		xlatv = ntb->xlat_reg->bar2_xlat;
848ed9652daSAlexander Motin 		break;
849ed9652daSAlexander Motin 	case NTB_B2B_BAR_2:
850ed9652daSAlexander Motin 		basev = ntb->xlat_reg->bar4_base;
851ed9652daSAlexander Motin 		lmtv = ntb->xlat_reg->bar4_limit;
852ed9652daSAlexander Motin 		xlatv = ntb->xlat_reg->bar4_xlat;
853ed9652daSAlexander Motin 		break;
854ed9652daSAlexander Motin 	case NTB_B2B_BAR_3:
855ed9652daSAlexander Motin 		basev = ntb->xlat_reg->bar5_base;
856ed9652daSAlexander Motin 		lmtv = ntb->xlat_reg->bar5_limit;
857ed9652daSAlexander Motin 		xlatv = ntb->xlat_reg->bar5_xlat;
858ed9652daSAlexander Motin 		break;
859ed9652daSAlexander Motin 	default:
860ed9652daSAlexander Motin 		KASSERT(bar >= NTB_B2B_BAR_1 && bar < NTB_MAX_BARS,
861ed9652daSAlexander Motin 		    ("bad bar"));
862ed9652daSAlexander Motin 		basev = lmtv = xlatv = 0;
863ed9652daSAlexander Motin 		break;
864ed9652daSAlexander Motin 	}
865ed9652daSAlexander Motin 
866ed9652daSAlexander Motin 	if (base != NULL)
867ed9652daSAlexander Motin 		*base = basev;
868ed9652daSAlexander Motin 	if (xlat != NULL)
869ed9652daSAlexander Motin 		*xlat = xlatv;
870ed9652daSAlexander Motin 	if (lmt != NULL)
871ed9652daSAlexander Motin 		*lmt = lmtv;
872ed9652daSAlexander Motin }
873ed9652daSAlexander Motin 
874ed9652daSAlexander Motin static int
intel_ntb_map_pci_bars(struct ntb_softc * ntb)875ed9652daSAlexander Motin intel_ntb_map_pci_bars(struct ntb_softc *ntb)
876ed9652daSAlexander Motin {
877241da27eSAlexander Motin 	struct ntb_pci_bar_info *bar;
878ed9652daSAlexander Motin 	int rc;
879ed9652daSAlexander Motin 
880241da27eSAlexander Motin 	bar = &ntb->bar_info[NTB_CONFIG_BAR];
881241da27eSAlexander Motin 	bar->pci_resource_id = PCIR_BAR(0);
882241da27eSAlexander Motin 	rc = map_mmr_bar(ntb, bar);
883ed9652daSAlexander Motin 	if (rc != 0)
884ed9652daSAlexander Motin 		goto out;
885ed9652daSAlexander Motin 
88695ba48d9SAlexander Motin 	/*
88795ba48d9SAlexander Motin 	 * At least on Xeon v4 NTB device leaks to host some remote side
88895ba48d9SAlexander Motin 	 * BAR0 writes supposed to update scratchpad registers.  I am not
88995ba48d9SAlexander Motin 	 * sure why it happens, but it may be related to the fact that
89095ba48d9SAlexander Motin 	 * on a link side BAR0 is 32KB, while on a host side it is 64KB.
89195ba48d9SAlexander Motin 	 * Without this hack DMAR blocks those accesses as not allowed.
89295ba48d9SAlexander Motin 	 */
89395ba48d9SAlexander Motin 	if (bus_dma_tag_create(bus_get_dma_tag(ntb->device), 1, 0,
89495ba48d9SAlexander Motin 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
89595ba48d9SAlexander Motin 	    bar->size, 1, bar->size, 0, NULL, NULL, &ntb->bar0_dma_tag)) {
89695ba48d9SAlexander Motin 		device_printf(ntb->device, "Unable to create BAR0 tag\n");
89795ba48d9SAlexander Motin 		return (ENOMEM);
89895ba48d9SAlexander Motin 	}
89995ba48d9SAlexander Motin 	if (bus_dmamap_create(ntb->bar0_dma_tag, 0, &ntb->bar0_dma_map)) {
90095ba48d9SAlexander Motin 		device_printf(ntb->device, "Unable to create BAR0 map\n");
90195ba48d9SAlexander Motin 		return (ENOMEM);
90295ba48d9SAlexander Motin 	}
903ea4c0115SRuslan Bukin 	if (bus_dma_iommu_load_ident(ntb->bar0_dma_tag, ntb->bar0_dma_map,
90495ba48d9SAlexander Motin 	    bar->pbase, bar->size, 0)) {
90595ba48d9SAlexander Motin 		device_printf(ntb->device, "Unable to load BAR0 map\n");
90695ba48d9SAlexander Motin 		return (ENOMEM);
90795ba48d9SAlexander Motin 	}
90895ba48d9SAlexander Motin 
909241da27eSAlexander Motin 	bar = &ntb->bar_info[NTB_B2B_BAR_1];
910241da27eSAlexander Motin 	bar->pci_resource_id = PCIR_BAR(2);
911241da27eSAlexander Motin 	rc = map_memory_window_bar(ntb, bar);
912ed9652daSAlexander Motin 	if (rc != 0)
913ed9652daSAlexander Motin 		goto out;
9146660ef6eSMark Johnston 	if (ntb->type == NTB_XEON_GEN3) {
9156660ef6eSMark Johnston 		bar->psz_off = XEON_GEN3_INT_REG_IMBAR1SZ;
9166660ef6eSMark Johnston 		bar->ssz_off = XEON_GEN3_INT_REG_EMBAR1SZ;
9176660ef6eSMark Johnston 		bar->pbarxlat_off = XEON_GEN3_REG_EMBAR1XBASE;
918*70450ecdSAustin Zhang 	} else if (ntb->type == NTB_XEON_GEN4) {
919*70450ecdSAustin Zhang 		bar->psz_off = XEON_GEN4_CFG_REG_IMBAR1SZ;
920*70450ecdSAustin Zhang 		bar->ssz_off = XEON_GEN4_CFG_REG_EMBAR1SZ;
921*70450ecdSAustin Zhang 		bar->pbarxlat_off = XEON_GEN4_REG_EXT_BAR1BASE;
9226660ef6eSMark Johnston 	} else {
923241da27eSAlexander Motin 		bar->psz_off = XEON_PBAR23SZ_OFFSET;
924241da27eSAlexander Motin 		bar->ssz_off = XEON_SBAR23SZ_OFFSET;
925241da27eSAlexander Motin 		bar->pbarxlat_off = XEON_PBAR2XLAT_OFFSET;
9266660ef6eSMark Johnston 	}
927ed9652daSAlexander Motin 
928241da27eSAlexander Motin 	bar = &ntb->bar_info[NTB_B2B_BAR_2];
929241da27eSAlexander Motin 	bar->pci_resource_id = PCIR_BAR(4);
930241da27eSAlexander Motin 	rc = map_memory_window_bar(ntb, bar);
931ed9652daSAlexander Motin 	if (rc != 0)
932ed9652daSAlexander Motin 		goto out;
9336660ef6eSMark Johnston 	if (ntb->type == NTB_XEON_GEN3) {
9346660ef6eSMark Johnston 		bar->psz_off = XEON_GEN3_INT_REG_IMBAR2SZ;
9356660ef6eSMark Johnston 		bar->ssz_off = XEON_GEN3_INT_REG_EMBAR2SZ;
9366660ef6eSMark Johnston 		bar->pbarxlat_off = XEON_GEN3_REG_EMBAR2XBASE;
937*70450ecdSAustin Zhang 	} else if (ntb->type == NTB_XEON_GEN4) {
938*70450ecdSAustin Zhang 		bar->psz_off = XEON_GEN4_CFG_REG_IMBAR2SZ;
939*70450ecdSAustin Zhang 		bar->ssz_off = XEON_GEN4_CFG_REG_EMBAR2SZ;
940*70450ecdSAustin Zhang 		bar->pbarxlat_off = XEON_GEN4_REG_EXT_BAR2BASE;
9416660ef6eSMark Johnston 	} else {
942241da27eSAlexander Motin 		bar->psz_off = XEON_PBAR4SZ_OFFSET;
943241da27eSAlexander Motin 		bar->ssz_off = XEON_SBAR4SZ_OFFSET;
944241da27eSAlexander Motin 		bar->pbarxlat_off = XEON_PBAR4XLAT_OFFSET;
9456660ef6eSMark Johnston 	}
946ed9652daSAlexander Motin 
947ed9652daSAlexander Motin 	if (!HAS_FEATURE(ntb, NTB_SPLIT_BAR))
948ed9652daSAlexander Motin 		goto out;
949ed9652daSAlexander Motin 
950*70450ecdSAustin Zhang 	if (ntb->type == NTB_XEON_GEN3 ||
951*70450ecdSAustin Zhang 	    ntb->type == NTB_XEON_GEN4) {
9526660ef6eSMark Johnston 		device_printf(ntb->device, "no split bar support\n");
9536660ef6eSMark Johnston 		return (ENXIO);
9546660ef6eSMark Johnston 	}
9556660ef6eSMark Johnston 
956241da27eSAlexander Motin 	bar = &ntb->bar_info[NTB_B2B_BAR_3];
957241da27eSAlexander Motin 	bar->pci_resource_id = PCIR_BAR(5);
958241da27eSAlexander Motin 	rc = map_memory_window_bar(ntb, bar);
959241da27eSAlexander Motin 	bar->psz_off = XEON_PBAR5SZ_OFFSET;
960241da27eSAlexander Motin 	bar->ssz_off = XEON_SBAR5SZ_OFFSET;
961241da27eSAlexander Motin 	bar->pbarxlat_off = XEON_PBAR5XLAT_OFFSET;
962ed9652daSAlexander Motin 
963ed9652daSAlexander Motin out:
964ed9652daSAlexander Motin 	if (rc != 0)
965ed9652daSAlexander Motin 		device_printf(ntb->device,
966ed9652daSAlexander Motin 		    "unable to allocate pci resource\n");
967ed9652daSAlexander Motin 	return (rc);
968ed9652daSAlexander Motin }
969ed9652daSAlexander Motin 
970ed9652daSAlexander Motin static void
print_map_success(struct ntb_softc * ntb,struct ntb_pci_bar_info * bar,const char * kind)971ed9652daSAlexander Motin print_map_success(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar,
972ed9652daSAlexander Motin     const char *kind)
973ed9652daSAlexander Motin {
974ed9652daSAlexander Motin 
975ed9652daSAlexander Motin 	device_printf(ntb->device,
976124e4673SJohn Baldwin 	    "Mapped BAR%d v:[%p-%p] p:[0x%jx-0x%jx] (0x%jx bytes) (%s)\n",
977ed9652daSAlexander Motin 	    PCI_RID2BAR(bar->pci_resource_id), bar->vbase,
978ed9652daSAlexander Motin 	    (char *)bar->vbase + bar->size - 1,
979124e4673SJohn Baldwin 	    (uintmax_t)bar->pbase, (uintmax_t)(bar->pbase + bar->size - 1),
980ed9652daSAlexander Motin 	    (uintmax_t)bar->size, kind);
981ed9652daSAlexander Motin }
982ed9652daSAlexander Motin 
983ed9652daSAlexander Motin static int
map_mmr_bar(struct ntb_softc * ntb,struct ntb_pci_bar_info * bar)984ed9652daSAlexander Motin map_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar)
985ed9652daSAlexander Motin {
986ed9652daSAlexander Motin 
987ed9652daSAlexander Motin 	bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY,
988ed9652daSAlexander Motin 	    &bar->pci_resource_id, RF_ACTIVE);
989ed9652daSAlexander Motin 	if (bar->pci_resource == NULL)
990ed9652daSAlexander Motin 		return (ENXIO);
991ed9652daSAlexander Motin 
992ed9652daSAlexander Motin 	save_bar_parameters(bar);
993ed9652daSAlexander Motin 	bar->map_mode = VM_MEMATTR_UNCACHEABLE;
994ed9652daSAlexander Motin 	print_map_success(ntb, bar, "mmr");
995ed9652daSAlexander Motin 	return (0);
996ed9652daSAlexander Motin }
997ed9652daSAlexander Motin 
998ed9652daSAlexander Motin static int
map_memory_window_bar(struct ntb_softc * ntb,struct ntb_pci_bar_info * bar)999ed9652daSAlexander Motin map_memory_window_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar)
1000ed9652daSAlexander Motin {
1001ed9652daSAlexander Motin 	int rc;
1002ed9652daSAlexander Motin 	vm_memattr_t mapmode;
1003ed9652daSAlexander Motin 	uint8_t bar_size_bits = 0;
1004ed9652daSAlexander Motin 
1005ed9652daSAlexander Motin 	bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY,
1006ed9652daSAlexander Motin 	    &bar->pci_resource_id, RF_ACTIVE);
1007ed9652daSAlexander Motin 
1008ed9652daSAlexander Motin 	if (bar->pci_resource == NULL)
1009ed9652daSAlexander Motin 		return (ENXIO);
1010ed9652daSAlexander Motin 
1011ed9652daSAlexander Motin 	save_bar_parameters(bar);
1012ed9652daSAlexander Motin 	/*
1013ed9652daSAlexander Motin 	 * Ivytown NTB BAR sizes are misreported by the hardware due to a
1014ed9652daSAlexander Motin 	 * hardware issue. To work around this, query the size it should be
1015ed9652daSAlexander Motin 	 * configured to by the device and modify the resource to correspond to
1016ed9652daSAlexander Motin 	 * this new size. The BIOS on systems with this problem is required to
1017ed9652daSAlexander Motin 	 * provide enough address space to allow the driver to make this change
1018ed9652daSAlexander Motin 	 * safely.
1019ed9652daSAlexander Motin 	 *
1020ed9652daSAlexander Motin 	 * Ideally I could have just specified the size when I allocated the
1021ed9652daSAlexander Motin 	 * resource like:
1022ed9652daSAlexander Motin 	 *  bus_alloc_resource(ntb->device,
1023ed9652daSAlexander Motin 	 *	SYS_RES_MEMORY, &bar->pci_resource_id, 0ul, ~0ul,
1024ed9652daSAlexander Motin 	 *	1ul << bar_size_bits, RF_ACTIVE);
1025ed9652daSAlexander Motin 	 * but the PCI driver does not honor the size in this call, so we have
1026ed9652daSAlexander Motin 	 * to modify it after the fact.
1027ed9652daSAlexander Motin 	 */
1028ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_BAR_SIZE_4K)) {
1029ed9652daSAlexander Motin 		if (bar->pci_resource_id == PCIR_BAR(2))
1030ed9652daSAlexander Motin 			bar_size_bits = pci_read_config(ntb->device,
1031ed9652daSAlexander Motin 			    XEON_PBAR23SZ_OFFSET, 1);
1032ed9652daSAlexander Motin 		else
1033ed9652daSAlexander Motin 			bar_size_bits = pci_read_config(ntb->device,
1034ed9652daSAlexander Motin 			    XEON_PBAR45SZ_OFFSET, 1);
1035ed9652daSAlexander Motin 
1036ed9652daSAlexander Motin 		rc = bus_adjust_resource(ntb->device, SYS_RES_MEMORY,
1037ed9652daSAlexander Motin 		    bar->pci_resource, bar->pbase,
1038ed9652daSAlexander Motin 		    bar->pbase + (1ul << bar_size_bits) - 1);
1039ed9652daSAlexander Motin 		if (rc != 0) {
1040ed9652daSAlexander Motin 			device_printf(ntb->device,
1041ed9652daSAlexander Motin 			    "unable to resize bar\n");
1042ed9652daSAlexander Motin 			return (rc);
1043ed9652daSAlexander Motin 		}
1044ed9652daSAlexander Motin 
1045ed9652daSAlexander Motin 		save_bar_parameters(bar);
1046ed9652daSAlexander Motin 	}
1047ed9652daSAlexander Motin 
1048ed9652daSAlexander Motin 	bar->map_mode = VM_MEMATTR_UNCACHEABLE;
1049ed9652daSAlexander Motin 	print_map_success(ntb, bar, "mw");
1050ed9652daSAlexander Motin 
1051ed9652daSAlexander Motin 	/*
1052ed9652daSAlexander Motin 	 * Optionally, mark MW BARs as anything other than UC to improve
1053ed9652daSAlexander Motin 	 * performance.
1054ed9652daSAlexander Motin 	 */
1055ed9652daSAlexander Motin 	mapmode = intel_ntb_pat_flags();
1056ed9652daSAlexander Motin 	if (mapmode == bar->map_mode)
1057ed9652daSAlexander Motin 		return (0);
1058ed9652daSAlexander Motin 
1059ed9652daSAlexander Motin 	rc = pmap_change_attr((vm_offset_t)bar->vbase, bar->size, mapmode);
1060ed9652daSAlexander Motin 	if (rc == 0) {
1061ed9652daSAlexander Motin 		bar->map_mode = mapmode;
1062ed9652daSAlexander Motin 		device_printf(ntb->device,
1063124e4673SJohn Baldwin 		    "Marked BAR%d v:[%p-%p] p:[0x%jx-0x%jx] as "
1064ed9652daSAlexander Motin 		    "%s.\n",
1065ed9652daSAlexander Motin 		    PCI_RID2BAR(bar->pci_resource_id), bar->vbase,
1066ed9652daSAlexander Motin 		    (char *)bar->vbase + bar->size - 1,
1067124e4673SJohn Baldwin 		    (uintmax_t)bar->pbase,
1068124e4673SJohn Baldwin 		    (uintmax_t)(bar->pbase + bar->size - 1),
1069ed9652daSAlexander Motin 		    intel_ntb_vm_memattr_to_str(mapmode));
1070ed9652daSAlexander Motin 	} else
1071ed9652daSAlexander Motin 		device_printf(ntb->device,
1072124e4673SJohn Baldwin 		    "Unable to mark BAR%d v:[%p-%p] p:[0x%jx-0x%jx] as "
1073ed9652daSAlexander Motin 		    "%s: %d\n",
1074ed9652daSAlexander Motin 		    PCI_RID2BAR(bar->pci_resource_id), bar->vbase,
1075ed9652daSAlexander Motin 		    (char *)bar->vbase + bar->size - 1,
1076124e4673SJohn Baldwin 		    (uintmax_t)bar->pbase,
1077124e4673SJohn Baldwin 		    (uintmax_t)(bar->pbase + bar->size - 1),
1078ed9652daSAlexander Motin 		    intel_ntb_vm_memattr_to_str(mapmode), rc);
1079ed9652daSAlexander Motin 		/* Proceed anyway */
1080ed9652daSAlexander Motin 	return (0);
1081ed9652daSAlexander Motin }
1082ed9652daSAlexander Motin 
1083ed9652daSAlexander Motin static void
intel_ntb_unmap_pci_bar(struct ntb_softc * ntb)1084ed9652daSAlexander Motin intel_ntb_unmap_pci_bar(struct ntb_softc *ntb)
1085ed9652daSAlexander Motin {
1086241da27eSAlexander Motin 	struct ntb_pci_bar_info *bar;
1087ed9652daSAlexander Motin 	int i;
1088ed9652daSAlexander Motin 
108995ba48d9SAlexander Motin 	if (ntb->bar0_dma_map != NULL) {
109095ba48d9SAlexander Motin 		bus_dmamap_unload(ntb->bar0_dma_tag, ntb->bar0_dma_map);
109195ba48d9SAlexander Motin 		bus_dmamap_destroy(ntb->bar0_dma_tag, ntb->bar0_dma_map);
109295ba48d9SAlexander Motin 	}
109395ba48d9SAlexander Motin 	if (ntb->bar0_dma_tag != NULL)
109495ba48d9SAlexander Motin 		bus_dma_tag_destroy(ntb->bar0_dma_tag);
1095ed9652daSAlexander Motin 	for (i = 0; i < NTB_MAX_BARS; i++) {
1096241da27eSAlexander Motin 		bar = &ntb->bar_info[i];
1097241da27eSAlexander Motin 		if (bar->pci_resource != NULL)
1098ed9652daSAlexander Motin 			bus_release_resource(ntb->device, SYS_RES_MEMORY,
1099241da27eSAlexander Motin 			    bar->pci_resource_id, bar->pci_resource);
1100ed9652daSAlexander Motin 	}
1101ed9652daSAlexander Motin }
1102ed9652daSAlexander Motin 
1103ed9652daSAlexander Motin static int
intel_ntb_setup_msix(struct ntb_softc * ntb,uint32_t num_vectors)1104ed9652daSAlexander Motin intel_ntb_setup_msix(struct ntb_softc *ntb, uint32_t num_vectors)
1105ed9652daSAlexander Motin {
1106ed9652daSAlexander Motin 	uint32_t i;
1107ed9652daSAlexander Motin 	int rc;
1108ed9652daSAlexander Motin 
1109ed9652daSAlexander Motin 	for (i = 0; i < num_vectors; i++) {
1110ed9652daSAlexander Motin 		ntb->int_info[i].rid = i + 1;
1111ed9652daSAlexander Motin 		ntb->int_info[i].res = bus_alloc_resource_any(ntb->device,
1112ed9652daSAlexander Motin 		    SYS_RES_IRQ, &ntb->int_info[i].rid, RF_ACTIVE);
1113ed9652daSAlexander Motin 		if (ntb->int_info[i].res == NULL) {
1114ed9652daSAlexander Motin 			device_printf(ntb->device,
1115ed9652daSAlexander Motin 			    "bus_alloc_resource failed\n");
1116ed9652daSAlexander Motin 			return (ENOMEM);
1117ed9652daSAlexander Motin 		}
1118ed9652daSAlexander Motin 		ntb->int_info[i].tag = NULL;
1119ed9652daSAlexander Motin 		ntb->allocated_interrupts++;
1120ed9652daSAlexander Motin 		rc = bus_setup_intr(ntb->device, ntb->int_info[i].res,
1121ed9652daSAlexander Motin 		    INTR_MPSAFE | INTR_TYPE_MISC, NULL, ndev_vec_isr,
1122ed9652daSAlexander Motin 		    &ntb->msix_vec[i], &ntb->int_info[i].tag);
1123ed9652daSAlexander Motin 		if (rc != 0) {
1124ed9652daSAlexander Motin 			device_printf(ntb->device, "bus_setup_intr failed\n");
1125ed9652daSAlexander Motin 			return (ENXIO);
1126ed9652daSAlexander Motin 		}
1127ed9652daSAlexander Motin 	}
1128ed9652daSAlexander Motin 	return (0);
1129ed9652daSAlexander Motin }
1130ed9652daSAlexander Motin 
1131ed9652daSAlexander Motin /*
1132ed9652daSAlexander Motin  * The Linux NTB driver drops from MSI-X to legacy INTx if a unique vector
1133ed9652daSAlexander Motin  * cannot be allocated for each MSI-X message.  JHB seems to think remapping
1134ed9652daSAlexander Motin  * should be okay.  This tunable should enable us to test that hypothesis
1135ed9652daSAlexander Motin  * when someone gets their hands on some Xeon hardware.
1136ed9652daSAlexander Motin  */
1137ed9652daSAlexander Motin static int ntb_force_remap_mode;
1138ed9652daSAlexander Motin SYSCTL_INT(_hw_ntb, OID_AUTO, force_remap_mode, CTLFLAG_RDTUN,
1139ed9652daSAlexander Motin     &ntb_force_remap_mode, 0, "If enabled, force MSI-X messages to be remapped"
1140ed9652daSAlexander Motin     " to a smaller number of ithreads, even if the desired number are "
1141ed9652daSAlexander Motin     "available");
1142ed9652daSAlexander Motin 
1143ed9652daSAlexander Motin /*
1144ed9652daSAlexander Motin  * In case it is NOT ok, give consumers an abort button.
1145ed9652daSAlexander Motin  */
1146ed9652daSAlexander Motin static int ntb_prefer_intx;
1147ed9652daSAlexander Motin SYSCTL_INT(_hw_ntb, OID_AUTO, prefer_intx_to_remap, CTLFLAG_RDTUN,
1148ed9652daSAlexander Motin     &ntb_prefer_intx, 0, "If enabled, prefer to use legacy INTx mode rather "
1149ed9652daSAlexander Motin     "than remapping MSI-X messages over available slots (match Linux driver "
1150ed9652daSAlexander Motin     "behavior)");
1151ed9652daSAlexander Motin 
1152ed9652daSAlexander Motin /*
1153ed9652daSAlexander Motin  * Remap the desired number of MSI-X messages to available ithreads in a simple
1154ed9652daSAlexander Motin  * round-robin fashion.
1155ed9652daSAlexander Motin  */
1156ed9652daSAlexander Motin static int
intel_ntb_remap_msix(device_t dev,uint32_t desired,uint32_t avail)1157ed9652daSAlexander Motin intel_ntb_remap_msix(device_t dev, uint32_t desired, uint32_t avail)
1158ed9652daSAlexander Motin {
1159ed9652daSAlexander Motin 	u_int *vectors;
1160ed9652daSAlexander Motin 	uint32_t i;
1161ed9652daSAlexander Motin 	int rc;
1162ed9652daSAlexander Motin 
1163ed9652daSAlexander Motin 	if (ntb_prefer_intx != 0)
1164ed9652daSAlexander Motin 		return (ENXIO);
1165ed9652daSAlexander Motin 
1166ed9652daSAlexander Motin 	vectors = malloc(desired * sizeof(*vectors), M_NTB, M_ZERO | M_WAITOK);
1167ed9652daSAlexander Motin 
1168ed9652daSAlexander Motin 	for (i = 0; i < desired; i++)
1169ed9652daSAlexander Motin 		vectors[i] = (i % avail) + 1;
1170ed9652daSAlexander Motin 
1171ed9652daSAlexander Motin 	rc = pci_remap_msix(dev, desired, vectors);
1172ed9652daSAlexander Motin 	free(vectors, M_NTB);
1173ed9652daSAlexander Motin 	return (rc);
1174ed9652daSAlexander Motin }
1175ed9652daSAlexander Motin 
1176ed9652daSAlexander Motin static int
intel_ntb_xeon_gen3_init_isr(struct ntb_softc * ntb)11776660ef6eSMark Johnston intel_ntb_xeon_gen3_init_isr(struct ntb_softc *ntb)
11786660ef6eSMark Johnston {
11796660ef6eSMark Johnston 	uint64_t i, reg;
11806660ef6eSMark Johnston 	uint32_t desired_vectors, num_vectors;
11816660ef6eSMark Johnston 	int rc;
11826660ef6eSMark Johnston 
11836660ef6eSMark Johnston 	ntb->allocated_interrupts = 0;
11846660ef6eSMark Johnston 	ntb->last_ts = ticks;
11856660ef6eSMark Johnston 
11866660ef6eSMark Johnston 	/* Mask all the interrupts, including hardware interrupt */
11876660ef6eSMark Johnston 	intel_ntb_reg_write(8, XEON_GEN3_REG_IMINT_DISABLE, ~0ULL);
11886660ef6eSMark Johnston 
11896660ef6eSMark Johnston 	/* Clear Interrupt Status */
11906660ef6eSMark Johnston 	reg = intel_ntb_reg_read(8, XEON_GEN3_REG_IMINT_STATUS);
11916660ef6eSMark Johnston 	intel_ntb_reg_write(8, XEON_GEN3_REG_IMINT_STATUS, reg);
11926660ef6eSMark Johnston 
11936660ef6eSMark Johnston 	num_vectors = desired_vectors = MIN(pci_msix_count(ntb->device),
11946660ef6eSMark Johnston 	    XEON_GEN3_DB_MSIX_VECTOR_COUNT);
11956660ef6eSMark Johnston 
11966660ef6eSMark Johnston 	rc = pci_alloc_msix(ntb->device, &num_vectors);
11976660ef6eSMark Johnston 	if (rc != 0) {
11986660ef6eSMark Johnston 		device_printf(ntb->device,
11996660ef6eSMark Johnston 		    "Interrupt allocation failed %d\n", rc);
12006660ef6eSMark Johnston 		return (rc);
12016660ef6eSMark Johnston 	}
12026660ef6eSMark Johnston 	if (desired_vectors != num_vectors) {
12036660ef6eSMark Johnston 		device_printf(ntb->device, "Couldn't get %d vectors\n",
12046660ef6eSMark Johnston 		    XEON_GEN3_DB_MSIX_VECTOR_COUNT);
12056660ef6eSMark Johnston 		return (ENXIO);
12066660ef6eSMark Johnston 	}
12076660ef6eSMark Johnston 	/* 32 db + 1 hardware */
12086660ef6eSMark Johnston 	if (num_vectors == XEON_GEN3_DB_MSIX_VECTOR_COUNT) {
12096660ef6eSMark Johnston 		/* Program INTVECXX source register */
12106660ef6eSMark Johnston 		for (i = 0; i < XEON_GEN3_DB_MSIX_VECTOR_COUNT; i++) {
12116660ef6eSMark Johnston 			/* interrupt source i for vector i */
12126660ef6eSMark Johnston 			intel_ntb_reg_write(1, XEON_GEN3_REG_IMINTVEC00 + i, i);
12136660ef6eSMark Johnston 			if (i == (XEON_GEN3_DB_MSIX_VECTOR_COUNT - 1)) {
12146660ef6eSMark Johnston 				intel_ntb_reg_write(1,
12156660ef6eSMark Johnston 				    XEON_GEN3_REG_IMINTVEC00 + i,
12166660ef6eSMark Johnston 				    XEON_GEN3_LINK_VECTOR_INDEX);
12176660ef6eSMark Johnston 			}
12186660ef6eSMark Johnston 		}
12196660ef6eSMark Johnston 
12206660ef6eSMark Johnston 		intel_ntb_create_msix_vec(ntb, num_vectors);
12216660ef6eSMark Johnston 		rc = intel_ntb_setup_msix(ntb, num_vectors);
12226660ef6eSMark Johnston 
12236660ef6eSMark Johnston 		/* enable all interrupts */
12246660ef6eSMark Johnston 		intel_ntb_reg_write(8, XEON_GEN3_REG_IMINT_DISABLE, 0ULL);
12256660ef6eSMark Johnston 	} else {
12266660ef6eSMark Johnston 		device_printf(ntb->device, "need to remap interrupts, giving up.\n");
12276660ef6eSMark Johnston 		return (ENXIO);
12286660ef6eSMark Johnston 	}
12296660ef6eSMark Johnston 
1230*70450ecdSAustin Zhang 	return (rc);
1231*70450ecdSAustin Zhang }
1232*70450ecdSAustin Zhang 
1233*70450ecdSAustin Zhang static int
intel_ntb_xeon_gen4_init_isr(struct ntb_softc * ntb)1234*70450ecdSAustin Zhang intel_ntb_xeon_gen4_init_isr(struct ntb_softc *ntb)
1235*70450ecdSAustin Zhang {
1236*70450ecdSAustin Zhang 	uint64_t i, reg;
1237*70450ecdSAustin Zhang 	uint32_t desired_vectors, num_vectors;
1238*70450ecdSAustin Zhang 	int rc;
1239*70450ecdSAustin Zhang 
1240*70450ecdSAustin Zhang 	ntb->allocated_interrupts = 0;
1241*70450ecdSAustin Zhang 	ntb->last_ts = ticks;
1242*70450ecdSAustin Zhang 
1243*70450ecdSAustin Zhang 	/* Mask all the interrupts, including hardware interrupt */
1244*70450ecdSAustin Zhang 	intel_ntb_reg_write(8, XEON_GEN4_REG_IMINT_DISABLE, ~0ULL);
1245*70450ecdSAustin Zhang 
1246*70450ecdSAustin Zhang 	/* Clear Interrupt Status */
1247*70450ecdSAustin Zhang 	reg = intel_ntb_reg_read(8, XEON_GEN4_REG_IMINT_STATUS);
1248*70450ecdSAustin Zhang 	intel_ntb_reg_write(8, XEON_GEN4_REG_IMINT_STATUS, reg);
1249*70450ecdSAustin Zhang 
1250*70450ecdSAustin Zhang 	num_vectors = desired_vectors = MIN(pci_msix_count(ntb->device),
1251*70450ecdSAustin Zhang 	    XEON_GEN4_DB_MSIX_VECTOR_COUNT);
1252*70450ecdSAustin Zhang 
1253*70450ecdSAustin Zhang 	rc = pci_alloc_msix(ntb->device, &num_vectors);
1254*70450ecdSAustin Zhang 	if (rc != 0) {
1255*70450ecdSAustin Zhang 		device_printf(ntb->device,
1256*70450ecdSAustin Zhang 		    "Interrupt allocation failed %d\n", rc);
1257*70450ecdSAustin Zhang 		return (rc);
1258*70450ecdSAustin Zhang 	}
1259*70450ecdSAustin Zhang 	if (desired_vectors != num_vectors) {
1260*70450ecdSAustin Zhang 		device_printf(ntb->device, "Couldn't get %d vectors\n",
1261*70450ecdSAustin Zhang 		    XEON_GEN4_DB_MSIX_VECTOR_COUNT);
1262*70450ecdSAustin Zhang 		return (ENXIO);
1263*70450ecdSAustin Zhang 	}
1264*70450ecdSAustin Zhang 	if (num_vectors != XEON_GEN4_DB_MSIX_VECTOR_COUNT) {
1265*70450ecdSAustin Zhang 		device_printf(ntb->device,
1266*70450ecdSAustin Zhang 		    "Need to remap interrupts, giving up\n");
1267*70450ecdSAustin Zhang 		return (ENXIO);
1268*70450ecdSAustin Zhang 	}
1269*70450ecdSAustin Zhang 
1270*70450ecdSAustin Zhang 	/*
1271*70450ecdSAustin Zhang 	 * The MSIX vectors and the interrupt status bits are not lined up
1272*70450ecdSAustin Zhang 	 * on Gen3 (Skylake) and Gen4. By default the link status bit is bit
1273*70450ecdSAustin Zhang 	 * 32, however it is by default MSIX vector0. We need to fixup to
1274*70450ecdSAustin Zhang 	 * line them up. The vectors at reset is 1-32,0. We need to reprogram
1275*70450ecdSAustin Zhang 	 * to 0-32.
1276*70450ecdSAustin Zhang 	 */
1277*70450ecdSAustin Zhang 	for (i = 0; i < XEON_GEN4_DB_MSIX_VECTOR_COUNT; i++)
1278*70450ecdSAustin Zhang 		intel_ntb_reg_write(1, XEON_GEN4_REG_INTVEC + i, i);
1279*70450ecdSAustin Zhang 
1280*70450ecdSAustin Zhang 	intel_ntb_create_msix_vec(ntb, num_vectors);
1281*70450ecdSAustin Zhang 	rc = intel_ntb_setup_msix(ntb, num_vectors);
1282*70450ecdSAustin Zhang 
1283*70450ecdSAustin Zhang 	/* enable all interrupts */
1284*70450ecdSAustin Zhang 	intel_ntb_reg_write(8, XEON_GEN4_REG_IMINT_DISABLE, 0ULL);
1285*70450ecdSAustin Zhang 
1286*70450ecdSAustin Zhang 	return (rc);
12876660ef6eSMark Johnston }
12886660ef6eSMark Johnston 
12896660ef6eSMark Johnston static int
intel_ntb_init_isr(struct ntb_softc * ntb)1290ed9652daSAlexander Motin intel_ntb_init_isr(struct ntb_softc *ntb)
1291ed9652daSAlexander Motin {
1292ed9652daSAlexander Motin 	uint32_t desired_vectors, num_vectors;
1293ed9652daSAlexander Motin 	int rc;
1294ed9652daSAlexander Motin 
1295ed9652daSAlexander Motin 	ntb->allocated_interrupts = 0;
1296ed9652daSAlexander Motin 	ntb->last_ts = ticks;
1297ed9652daSAlexander Motin 
1298ed9652daSAlexander Motin 	/*
1299ed9652daSAlexander Motin 	 * Mask all doorbell interrupts.  (Except link events!)
1300ed9652daSAlexander Motin 	 */
1301ed9652daSAlexander Motin 	DB_MASK_LOCK(ntb);
1302ed9652daSAlexander Motin 	ntb->db_mask = ntb->db_valid_mask;
1303ed9652daSAlexander Motin 	db_iowrite(ntb, ntb->self_reg->db_mask, ntb->db_mask);
1304ed9652daSAlexander Motin 	DB_MASK_UNLOCK(ntb);
1305ed9652daSAlexander Motin 
1306ed9652daSAlexander Motin 	num_vectors = desired_vectors = MIN(pci_msix_count(ntb->device),
1307ed9652daSAlexander Motin 	    ntb->db_count);
1308ed9652daSAlexander Motin 	if (desired_vectors >= 1) {
1309ed9652daSAlexander Motin 		rc = pci_alloc_msix(ntb->device, &num_vectors);
1310ed9652daSAlexander Motin 
1311ed9652daSAlexander Motin 		if (ntb_force_remap_mode != 0 && rc == 0 &&
1312ed9652daSAlexander Motin 		    num_vectors == desired_vectors)
1313ed9652daSAlexander Motin 			num_vectors--;
1314ed9652daSAlexander Motin 
1315ed9652daSAlexander Motin 		if (rc == 0 && num_vectors < desired_vectors) {
1316ed9652daSAlexander Motin 			rc = intel_ntb_remap_msix(ntb->device, desired_vectors,
1317ed9652daSAlexander Motin 			    num_vectors);
1318ed9652daSAlexander Motin 			if (rc == 0)
1319ed9652daSAlexander Motin 				num_vectors = desired_vectors;
1320ed9652daSAlexander Motin 			else
1321ed9652daSAlexander Motin 				pci_release_msi(ntb->device);
1322ed9652daSAlexander Motin 		}
1323ed9652daSAlexander Motin 		if (rc != 0)
1324ed9652daSAlexander Motin 			num_vectors = 1;
1325ed9652daSAlexander Motin 	} else
1326ed9652daSAlexander Motin 		num_vectors = 1;
1327ed9652daSAlexander Motin 
13286660ef6eSMark Johnston 	if (ntb->type == NTB_XEON_GEN1 && num_vectors < ntb->db_vec_count) {
1329ed9652daSAlexander Motin 		if (HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP)) {
1330ed9652daSAlexander Motin 			device_printf(ntb->device,
1331ed9652daSAlexander Motin 			    "Errata workaround does not support MSI or INTX\n");
1332ed9652daSAlexander Motin 			return (EINVAL);
1333ed9652daSAlexander Motin 		}
1334ed9652daSAlexander Motin 
1335ed9652daSAlexander Motin 		ntb->db_vec_count = 1;
1336ed9652daSAlexander Motin 		ntb->db_vec_shift = XEON_DB_TOTAL_SHIFT;
1337ed9652daSAlexander Motin 		rc = intel_ntb_setup_legacy_interrupt(ntb);
1338ed9652daSAlexander Motin 	} else {
1339ed9652daSAlexander Motin 		if (num_vectors - 1 != XEON_NONLINK_DB_MSIX_BITS &&
1340ed9652daSAlexander Motin 		    HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP)) {
1341ed9652daSAlexander Motin 			device_printf(ntb->device,
1342ed9652daSAlexander Motin 			    "Errata workaround expects %d doorbell bits\n",
1343ed9652daSAlexander Motin 			    XEON_NONLINK_DB_MSIX_BITS);
1344ed9652daSAlexander Motin 			return (EINVAL);
1345ed9652daSAlexander Motin 		}
1346ed9652daSAlexander Motin 
1347ed9652daSAlexander Motin 		intel_ntb_create_msix_vec(ntb, num_vectors);
1348ed9652daSAlexander Motin 		rc = intel_ntb_setup_msix(ntb, num_vectors);
1349ed9652daSAlexander Motin 	}
1350ed9652daSAlexander Motin 	if (rc != 0) {
1351ed9652daSAlexander Motin 		device_printf(ntb->device,
1352ed9652daSAlexander Motin 		    "Error allocating interrupts: %d\n", rc);
1353ed9652daSAlexander Motin 		intel_ntb_free_msix_vec(ntb);
1354ed9652daSAlexander Motin 	}
1355ed9652daSAlexander Motin 
1356ed9652daSAlexander Motin 	return (rc);
1357ed9652daSAlexander Motin }
1358ed9652daSAlexander Motin 
1359ed9652daSAlexander Motin static int
intel_ntb_setup_legacy_interrupt(struct ntb_softc * ntb)1360ed9652daSAlexander Motin intel_ntb_setup_legacy_interrupt(struct ntb_softc *ntb)
1361ed9652daSAlexander Motin {
1362ed9652daSAlexander Motin 	int rc;
1363ed9652daSAlexander Motin 
1364ed9652daSAlexander Motin 	ntb->int_info[0].rid = 0;
1365ed9652daSAlexander Motin 	ntb->int_info[0].res = bus_alloc_resource_any(ntb->device, SYS_RES_IRQ,
1366ed9652daSAlexander Motin 	    &ntb->int_info[0].rid, RF_SHAREABLE|RF_ACTIVE);
1367ed9652daSAlexander Motin 	if (ntb->int_info[0].res == NULL) {
1368ed9652daSAlexander Motin 		device_printf(ntb->device, "bus_alloc_resource failed\n");
1369ed9652daSAlexander Motin 		return (ENOMEM);
1370ed9652daSAlexander Motin 	}
1371ed9652daSAlexander Motin 
1372ed9652daSAlexander Motin 	ntb->int_info[0].tag = NULL;
1373ed9652daSAlexander Motin 	ntb->allocated_interrupts = 1;
1374ed9652daSAlexander Motin 
1375ed9652daSAlexander Motin 	rc = bus_setup_intr(ntb->device, ntb->int_info[0].res,
1376ed9652daSAlexander Motin 	    INTR_MPSAFE | INTR_TYPE_MISC, NULL, ndev_irq_isr,
1377ed9652daSAlexander Motin 	    ntb, &ntb->int_info[0].tag);
1378ed9652daSAlexander Motin 	if (rc != 0) {
1379ed9652daSAlexander Motin 		device_printf(ntb->device, "bus_setup_intr failed\n");
1380ed9652daSAlexander Motin 		return (ENXIO);
1381ed9652daSAlexander Motin 	}
1382ed9652daSAlexander Motin 
1383ed9652daSAlexander Motin 	return (0);
1384ed9652daSAlexander Motin }
1385ed9652daSAlexander Motin 
1386ed9652daSAlexander Motin static void
intel_ntb_teardown_interrupts(struct ntb_softc * ntb)1387ed9652daSAlexander Motin intel_ntb_teardown_interrupts(struct ntb_softc *ntb)
1388ed9652daSAlexander Motin {
1389ed9652daSAlexander Motin 	struct ntb_int_info *current_int;
1390ed9652daSAlexander Motin 	int i;
1391ed9652daSAlexander Motin 
1392ed9652daSAlexander Motin 	for (i = 0; i < ntb->allocated_interrupts; i++) {
1393ed9652daSAlexander Motin 		current_int = &ntb->int_info[i];
1394ed9652daSAlexander Motin 		if (current_int->tag != NULL)
1395ed9652daSAlexander Motin 			bus_teardown_intr(ntb->device, current_int->res,
1396ed9652daSAlexander Motin 			    current_int->tag);
1397ed9652daSAlexander Motin 
1398ed9652daSAlexander Motin 		if (current_int->res != NULL)
1399ed9652daSAlexander Motin 			bus_release_resource(ntb->device, SYS_RES_IRQ,
1400ed9652daSAlexander Motin 			    rman_get_rid(current_int->res), current_int->res);
1401ed9652daSAlexander Motin 	}
1402ed9652daSAlexander Motin 
1403ed9652daSAlexander Motin 	intel_ntb_free_msix_vec(ntb);
1404ed9652daSAlexander Motin 	pci_release_msi(ntb->device);
1405ed9652daSAlexander Motin }
1406ed9652daSAlexander Motin 
1407ed9652daSAlexander Motin static inline uint64_t
db_ioread(struct ntb_softc * ntb,uint64_t regoff)1408ed9652daSAlexander Motin db_ioread(struct ntb_softc *ntb, uint64_t regoff)
1409ed9652daSAlexander Motin {
1410ed9652daSAlexander Motin 
14116660ef6eSMark Johnston 	switch (ntb->type) {
14126660ef6eSMark Johnston 	case NTB_ATOM:
14136660ef6eSMark Johnston 	case NTB_XEON_GEN3:
1414*70450ecdSAustin Zhang 	case NTB_XEON_GEN4:
1415ed9652daSAlexander Motin 		return (intel_ntb_reg_read(8, regoff));
14166660ef6eSMark Johnston 	case NTB_XEON_GEN1:
1417ed9652daSAlexander Motin 		return (intel_ntb_reg_read(2, regoff));
1418ed9652daSAlexander Motin 	}
1419da1c42ceSRyan Libby 	__assert_unreachable();
14206660ef6eSMark Johnston }
1421ed9652daSAlexander Motin 
1422ed9652daSAlexander Motin static inline void
db_iowrite(struct ntb_softc * ntb,uint64_t regoff,uint64_t val)1423ed9652daSAlexander Motin db_iowrite(struct ntb_softc *ntb, uint64_t regoff, uint64_t val)
1424ed9652daSAlexander Motin {
1425ed9652daSAlexander Motin 
1426ed9652daSAlexander Motin 	KASSERT((val & ~ntb->db_valid_mask) == 0,
1427ed9652daSAlexander Motin 	    ("%s: Invalid bits 0x%jx (valid: 0x%jx)", __func__,
1428ed9652daSAlexander Motin 	     (uintmax_t)(val & ~ntb->db_valid_mask),
1429ed9652daSAlexander Motin 	     (uintmax_t)ntb->db_valid_mask));
1430ed9652daSAlexander Motin 
1431ed9652daSAlexander Motin 	if (regoff == ntb->self_reg->db_mask)
1432ed9652daSAlexander Motin 		DB_MASK_ASSERT(ntb, MA_OWNED);
1433ed9652daSAlexander Motin 	db_iowrite_raw(ntb, regoff, val);
1434ed9652daSAlexander Motin }
1435ed9652daSAlexander Motin 
1436ed9652daSAlexander Motin static inline void
db_iowrite_raw(struct ntb_softc * ntb,uint64_t regoff,uint64_t val)1437ed9652daSAlexander Motin db_iowrite_raw(struct ntb_softc *ntb, uint64_t regoff, uint64_t val)
1438ed9652daSAlexander Motin {
1439ed9652daSAlexander Motin 
14406660ef6eSMark Johnston 	switch (ntb->type) {
14416660ef6eSMark Johnston 	case NTB_ATOM:
14426660ef6eSMark Johnston 	case NTB_XEON_GEN3:
1443*70450ecdSAustin Zhang 	case NTB_XEON_GEN4:
1444ed9652daSAlexander Motin 		intel_ntb_reg_write(8, regoff, val);
14456660ef6eSMark Johnston 		break;
14466660ef6eSMark Johnston 	case NTB_XEON_GEN1:
1447ed9652daSAlexander Motin 		intel_ntb_reg_write(2, regoff, (uint16_t)val);
14486660ef6eSMark Johnston 		break;
14496660ef6eSMark Johnston 	}
1450ed9652daSAlexander Motin }
1451ed9652daSAlexander Motin 
1452ed9652daSAlexander Motin static void
intel_ntb_db_set_mask(device_t dev,uint64_t bits)1453ed9652daSAlexander Motin intel_ntb_db_set_mask(device_t dev, uint64_t bits)
1454ed9652daSAlexander Motin {
1455ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
1456ed9652daSAlexander Motin 
1457ed9652daSAlexander Motin 	DB_MASK_LOCK(ntb);
1458ed9652daSAlexander Motin 	ntb->db_mask |= bits;
1459ed9652daSAlexander Motin 	if (!HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP))
1460ed9652daSAlexander Motin 		db_iowrite(ntb, ntb->self_reg->db_mask, ntb->db_mask);
1461ed9652daSAlexander Motin 	DB_MASK_UNLOCK(ntb);
1462ed9652daSAlexander Motin }
1463ed9652daSAlexander Motin 
1464ed9652daSAlexander Motin static void
intel_ntb_db_clear_mask(device_t dev,uint64_t bits)1465ed9652daSAlexander Motin intel_ntb_db_clear_mask(device_t dev, uint64_t bits)
1466ed9652daSAlexander Motin {
1467ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
1468ed9652daSAlexander Motin 	uint64_t ibits;
1469ed9652daSAlexander Motin 	int i;
1470ed9652daSAlexander Motin 
1471ed9652daSAlexander Motin 	KASSERT((bits & ~ntb->db_valid_mask) == 0,
1472ed9652daSAlexander Motin 	    ("%s: Invalid bits 0x%jx (valid: 0x%jx)", __func__,
1473ed9652daSAlexander Motin 	     (uintmax_t)(bits & ~ntb->db_valid_mask),
1474ed9652daSAlexander Motin 	     (uintmax_t)ntb->db_valid_mask));
1475ed9652daSAlexander Motin 
1476ed9652daSAlexander Motin 	DB_MASK_LOCK(ntb);
1477ed9652daSAlexander Motin 	ibits = ntb->fake_db & ntb->db_mask & bits;
1478ed9652daSAlexander Motin 	ntb->db_mask &= ~bits;
1479ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP)) {
1480ed9652daSAlexander Motin 		/* Simulate fake interrupts if unmasked DB bits are set. */
1481ed9652daSAlexander Motin 		ntb->force_db |= ibits;
1482ed9652daSAlexander Motin 		for (i = 0; i < XEON_NONLINK_DB_MSIX_BITS; i++) {
1483ed9652daSAlexander Motin 			if ((ibits & intel_ntb_db_vector_mask(dev, i)) != 0)
1484ed9652daSAlexander Motin 				swi_sched(ntb->int_info[i].tag, 0);
1485ed9652daSAlexander Motin 		}
1486ed9652daSAlexander Motin 	} else {
1487ed9652daSAlexander Motin 		db_iowrite(ntb, ntb->self_reg->db_mask, ntb->db_mask);
1488ed9652daSAlexander Motin 	}
1489ed9652daSAlexander Motin 	DB_MASK_UNLOCK(ntb);
1490ed9652daSAlexander Motin }
1491ed9652daSAlexander Motin 
1492ed9652daSAlexander Motin static uint64_t
intel_ntb_db_read(device_t dev)1493ed9652daSAlexander Motin intel_ntb_db_read(device_t dev)
1494ed9652daSAlexander Motin {
1495ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
1496ed9652daSAlexander Motin 
1497ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP))
1498ed9652daSAlexander Motin 		return (ntb->fake_db);
14996660ef6eSMark Johnston 	if (ntb->type == NTB_XEON_GEN3)
15006660ef6eSMark Johnston 		return (intel_ntb_reg_read(8, XEON_GEN3_REG_IMINT_STATUS));
15016660ef6eSMark Johnston 	else
1502ed9652daSAlexander Motin 		return (db_ioread(ntb, ntb->self_reg->db_bell));
1503ed9652daSAlexander Motin }
1504ed9652daSAlexander Motin 
1505ed9652daSAlexander Motin static void
intel_ntb_db_clear(device_t dev,uint64_t bits)1506ed9652daSAlexander Motin intel_ntb_db_clear(device_t dev, uint64_t bits)
1507ed9652daSAlexander Motin {
1508ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
1509ed9652daSAlexander Motin 
1510ed9652daSAlexander Motin 	KASSERT((bits & ~ntb->db_valid_mask) == 0,
1511ed9652daSAlexander Motin 	    ("%s: Invalid bits 0x%jx (valid: 0x%jx)", __func__,
1512ed9652daSAlexander Motin 	     (uintmax_t)(bits & ~ntb->db_valid_mask),
1513ed9652daSAlexander Motin 	     (uintmax_t)ntb->db_valid_mask));
1514ed9652daSAlexander Motin 
1515ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP)) {
1516ed9652daSAlexander Motin 		DB_MASK_LOCK(ntb);
1517ed9652daSAlexander Motin 		ntb->fake_db &= ~bits;
1518ed9652daSAlexander Motin 		DB_MASK_UNLOCK(ntb);
1519ed9652daSAlexander Motin 		return;
1520ed9652daSAlexander Motin 	}
1521ed9652daSAlexander Motin 
15226660ef6eSMark Johnston 	if (ntb->type == NTB_XEON_GEN3)
15236660ef6eSMark Johnston 		intel_ntb_reg_write(4, XEON_GEN3_REG_IMINT_STATUS,
15246660ef6eSMark Johnston 		    (uint32_t)bits);
15256660ef6eSMark Johnston 	else
1526ed9652daSAlexander Motin 		db_iowrite(ntb, ntb->self_reg->db_bell, bits);
1527ed9652daSAlexander Motin }
1528ed9652daSAlexander Motin 
1529ed9652daSAlexander Motin static inline uint64_t
intel_ntb_vec_mask(struct ntb_softc * ntb,uint64_t db_vector)1530ed9652daSAlexander Motin intel_ntb_vec_mask(struct ntb_softc *ntb, uint64_t db_vector)
1531ed9652daSAlexander Motin {
1532ed9652daSAlexander Motin 	uint64_t shift, mask;
1533ed9652daSAlexander Motin 
1534ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP)) {
1535ed9652daSAlexander Motin 		/*
1536ed9652daSAlexander Motin 		 * Remap vectors in custom way to make at least first
1537ed9652daSAlexander Motin 		 * three doorbells to not generate stray events.
1538ed9652daSAlexander Motin 		 * This breaks Linux compatibility (if one existed)
1539ed9652daSAlexander Motin 		 * when more then one DB is used (not by if_ntb).
1540ed9652daSAlexander Motin 		 */
1541ed9652daSAlexander Motin 		if (db_vector < XEON_NONLINK_DB_MSIX_BITS - 1)
1542ed9652daSAlexander Motin 			return (1 << db_vector);
1543ed9652daSAlexander Motin 		if (db_vector == XEON_NONLINK_DB_MSIX_BITS - 1)
1544ed9652daSAlexander Motin 			return (0x7ffc);
1545ed9652daSAlexander Motin 	}
1546ed9652daSAlexander Motin 
1547ed9652daSAlexander Motin 	shift = ntb->db_vec_shift;
1548ed9652daSAlexander Motin 	mask = (1ull << shift) - 1;
1549ed9652daSAlexander Motin 	return (mask << (shift * db_vector));
1550ed9652daSAlexander Motin }
1551ed9652daSAlexander Motin 
1552ed9652daSAlexander Motin static void
intel_ntb_interrupt(struct ntb_softc * ntb,uint32_t vec)1553ed9652daSAlexander Motin intel_ntb_interrupt(struct ntb_softc *ntb, uint32_t vec)
1554ed9652daSAlexander Motin {
1555ed9652daSAlexander Motin 	uint64_t vec_mask;
1556ed9652daSAlexander Motin 
1557ed9652daSAlexander Motin 	ntb->last_ts = ticks;
1558ed9652daSAlexander Motin 	vec_mask = intel_ntb_vec_mask(ntb, vec);
1559ed9652daSAlexander Motin 
1560*70450ecdSAustin Zhang 	if ((ntb->type == NTB_XEON_GEN3 || ntb->type == NTB_XEON_GEN4) &&
1561*70450ecdSAustin Zhang 	    vec == XEON_GEN3_LINK_VECTOR_INDEX)
15626660ef6eSMark Johnston 		vec_mask |= ntb->db_link_mask;
1563ed9652daSAlexander Motin 	if ((vec_mask & ntb->db_link_mask) != 0) {
1564ed9652daSAlexander Motin 		if (intel_ntb_poll_link(ntb))
1565ed9652daSAlexander Motin 			ntb_link_event(ntb->device);
15666660ef6eSMark Johnston 		if (ntb->type == NTB_XEON_GEN3)
15676660ef6eSMark Johnston 			intel_ntb_reg_write(8, XEON_GEN3_REG_IMINT_STATUS,
15686660ef6eSMark Johnston 			    intel_ntb_reg_read(8, XEON_GEN3_REG_IMINT_STATUS));
1569*70450ecdSAustin Zhang 		if (ntb->type == NTB_XEON_GEN4)
1570*70450ecdSAustin Zhang 			intel_ntb_reg_write(8, XEON_GEN4_REG_IMINT_STATUS,
1571*70450ecdSAustin Zhang 			    intel_ntb_reg_read(8, XEON_GEN4_REG_IMINT_STATUS));
1572ed9652daSAlexander Motin 	}
1573ed9652daSAlexander Motin 
1574ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP) &&
1575ed9652daSAlexander Motin 	    (vec_mask & ntb->db_link_mask) == 0) {
1576ed9652daSAlexander Motin 		DB_MASK_LOCK(ntb);
1577ed9652daSAlexander Motin 
1578ed9652daSAlexander Motin 		/*
1579ed9652daSAlexander Motin 		 * Do not report same DB events again if not cleared yet,
1580ed9652daSAlexander Motin 		 * unless the mask was just cleared for them and this
1581ed9652daSAlexander Motin 		 * interrupt handler call can be the consequence of it.
1582ed9652daSAlexander Motin 		 */
1583ed9652daSAlexander Motin 		vec_mask &= ~ntb->fake_db | ntb->force_db;
1584ed9652daSAlexander Motin 		ntb->force_db &= ~vec_mask;
1585ed9652daSAlexander Motin 
1586ed9652daSAlexander Motin 		/* Update our internal doorbell register. */
1587ed9652daSAlexander Motin 		ntb->fake_db |= vec_mask;
1588ed9652daSAlexander Motin 
1589ed9652daSAlexander Motin 		/* Do not report masked DB events. */
1590ed9652daSAlexander Motin 		vec_mask &= ~ntb->db_mask;
1591ed9652daSAlexander Motin 
1592ed9652daSAlexander Motin 		DB_MASK_UNLOCK(ntb);
1593ed9652daSAlexander Motin 	}
1594ed9652daSAlexander Motin 
1595ed9652daSAlexander Motin 	if ((vec_mask & ntb->db_valid_mask) != 0)
1596ed9652daSAlexander Motin 		ntb_db_event(ntb->device, vec);
1597ed9652daSAlexander Motin }
1598ed9652daSAlexander Motin 
1599ed9652daSAlexander Motin static void
ndev_vec_isr(void * arg)1600ed9652daSAlexander Motin ndev_vec_isr(void *arg)
1601ed9652daSAlexander Motin {
1602ed9652daSAlexander Motin 	struct ntb_vec *nvec = arg;
1603ed9652daSAlexander Motin 
1604ed9652daSAlexander Motin 	intel_ntb_interrupt(nvec->ntb, nvec->num);
1605ed9652daSAlexander Motin }
1606ed9652daSAlexander Motin 
1607ed9652daSAlexander Motin static void
ndev_irq_isr(void * arg)1608ed9652daSAlexander Motin ndev_irq_isr(void *arg)
1609ed9652daSAlexander Motin {
1610ed9652daSAlexander Motin 	/* If we couldn't set up MSI-X, we only have the one vector. */
1611ed9652daSAlexander Motin 	intel_ntb_interrupt(arg, 0);
1612ed9652daSAlexander Motin }
1613ed9652daSAlexander Motin 
1614ed9652daSAlexander Motin static int
intel_ntb_create_msix_vec(struct ntb_softc * ntb,uint32_t num_vectors)1615ed9652daSAlexander Motin intel_ntb_create_msix_vec(struct ntb_softc *ntb, uint32_t num_vectors)
1616ed9652daSAlexander Motin {
1617ed9652daSAlexander Motin 	uint32_t i;
1618ed9652daSAlexander Motin 
1619ed9652daSAlexander Motin 	ntb->msix_vec = malloc(num_vectors * sizeof(*ntb->msix_vec), M_NTB,
1620ed9652daSAlexander Motin 	    M_ZERO | M_WAITOK);
1621ed9652daSAlexander Motin 	for (i = 0; i < num_vectors; i++) {
1622ed9652daSAlexander Motin 		ntb->msix_vec[i].num = i;
1623ed9652daSAlexander Motin 		ntb->msix_vec[i].ntb = ntb;
1624ed9652daSAlexander Motin 	}
1625ed9652daSAlexander Motin 
1626ed9652daSAlexander Motin 	return (0);
1627ed9652daSAlexander Motin }
1628ed9652daSAlexander Motin 
1629ed9652daSAlexander Motin static void
intel_ntb_free_msix_vec(struct ntb_softc * ntb)1630ed9652daSAlexander Motin intel_ntb_free_msix_vec(struct ntb_softc *ntb)
1631ed9652daSAlexander Motin {
1632ed9652daSAlexander Motin 
1633ed9652daSAlexander Motin 	if (ntb->msix_vec == NULL)
1634ed9652daSAlexander Motin 		return;
1635ed9652daSAlexander Motin 
1636ed9652daSAlexander Motin 	free(ntb->msix_vec, M_NTB);
1637ed9652daSAlexander Motin 	ntb->msix_vec = NULL;
1638ed9652daSAlexander Motin }
1639ed9652daSAlexander Motin 
1640ed9652daSAlexander Motin static void
intel_ntb_get_msix_info(struct ntb_softc * ntb)1641ed9652daSAlexander Motin intel_ntb_get_msix_info(struct ntb_softc *ntb)
1642ed9652daSAlexander Motin {
1643ed9652daSAlexander Motin 	struct pci_devinfo *dinfo;
1644ed9652daSAlexander Motin 	struct pcicfg_msix *msix;
1645ed9652daSAlexander Motin 	uint32_t laddr, data, i, offset;
1646ed9652daSAlexander Motin 
1647ed9652daSAlexander Motin 	dinfo = device_get_ivars(ntb->device);
1648ed9652daSAlexander Motin 	msix = &dinfo->cfg.msix;
1649ed9652daSAlexander Motin 
1650ed9652daSAlexander Motin 	CTASSERT(XEON_NONLINK_DB_MSIX_BITS == nitems(ntb->msix_data));
1651ed9652daSAlexander Motin 
1652ed9652daSAlexander Motin 	for (i = 0; i < XEON_NONLINK_DB_MSIX_BITS; i++) {
1653ed9652daSAlexander Motin 		offset = msix->msix_table_offset + i * PCI_MSIX_ENTRY_SIZE;
1654ed9652daSAlexander Motin 
1655ed9652daSAlexander Motin 		laddr = bus_read_4(msix->msix_table_res, offset +
1656ed9652daSAlexander Motin 		    PCI_MSIX_ENTRY_LOWER_ADDR);
1657ed9652daSAlexander Motin 		intel_ntb_printf(2, "local MSIX addr(%u): 0x%x\n", i, laddr);
1658ed9652daSAlexander Motin 
1659ed9652daSAlexander Motin 		KASSERT((laddr & MSI_INTEL_ADDR_BASE) == MSI_INTEL_ADDR_BASE,
1660ed9652daSAlexander Motin 		    ("local MSIX addr 0x%x not in MSI base 0x%x", laddr,
1661ed9652daSAlexander Motin 		     MSI_INTEL_ADDR_BASE));
1662ed9652daSAlexander Motin 		ntb->msix_data[i].nmd_ofs = laddr;
1663ed9652daSAlexander Motin 
1664ed9652daSAlexander Motin 		data = bus_read_4(msix->msix_table_res, offset +
1665ed9652daSAlexander Motin 		    PCI_MSIX_ENTRY_DATA);
1666ed9652daSAlexander Motin 		intel_ntb_printf(2, "local MSIX data(%u): 0x%x\n", i, data);
1667ed9652daSAlexander Motin 
1668ed9652daSAlexander Motin 		ntb->msix_data[i].nmd_data = data;
1669ed9652daSAlexander Motin 	}
1670ed9652daSAlexander Motin }
1671ed9652daSAlexander Motin 
1672ed9652daSAlexander Motin static struct ntb_hw_info *
intel_ntb_get_device_info(uint32_t device_id)1673ed9652daSAlexander Motin intel_ntb_get_device_info(uint32_t device_id)
1674ed9652daSAlexander Motin {
1675a64bf59cSConrad Meyer 	struct ntb_hw_info *ep;
1676ed9652daSAlexander Motin 
1677a64bf59cSConrad Meyer 	for (ep = pci_ids; ep < &pci_ids[nitems(pci_ids)]; ep++) {
1678ed9652daSAlexander Motin 		if (ep->device_id == device_id)
1679ed9652daSAlexander Motin 			return (ep);
1680ed9652daSAlexander Motin 	}
1681ed9652daSAlexander Motin 	return (NULL);
1682ed9652daSAlexander Motin }
1683ed9652daSAlexander Motin 
1684ed9652daSAlexander Motin static void
intel_ntb_teardown_xeon(struct ntb_softc * ntb)1685ed9652daSAlexander Motin intel_ntb_teardown_xeon(struct ntb_softc *ntb)
1686ed9652daSAlexander Motin {
1687ed9652daSAlexander Motin 
1688ed9652daSAlexander Motin 	if (ntb->reg != NULL)
1689ed9652daSAlexander Motin 		intel_ntb_link_disable(ntb->device);
1690ed9652daSAlexander Motin }
1691ed9652daSAlexander Motin 
1692ed9652daSAlexander Motin static void
intel_ntb_detect_max_mw(struct ntb_softc * ntb)1693ed9652daSAlexander Motin intel_ntb_detect_max_mw(struct ntb_softc *ntb)
1694ed9652daSAlexander Motin {
1695ed9652daSAlexander Motin 
16966660ef6eSMark Johnston 	switch (ntb->type) {
16976660ef6eSMark Johnston 	case NTB_ATOM:
1698ed9652daSAlexander Motin 		ntb->mw_count = ATOM_MW_COUNT;
16996660ef6eSMark Johnston 		break;
17006660ef6eSMark Johnston 	case NTB_XEON_GEN1:
1701ed9652daSAlexander Motin 		if (HAS_FEATURE(ntb, NTB_SPLIT_BAR))
1702ed9652daSAlexander Motin 			ntb->mw_count = XEON_HSX_SPLIT_MW_COUNT;
1703ed9652daSAlexander Motin 		else
1704ed9652daSAlexander Motin 			ntb->mw_count = XEON_SNB_MW_COUNT;
17056660ef6eSMark Johnston 		break;
17066660ef6eSMark Johnston 	case NTB_XEON_GEN3:
1707*70450ecdSAustin Zhang 	case NTB_XEON_GEN4:
17086660ef6eSMark Johnston 		if (HAS_FEATURE(ntb, NTB_SPLIT_BAR))
17096660ef6eSMark Johnston 			ntb->mw_count = XEON_GEN3_SPLIT_MW_COUNT;
17106660ef6eSMark Johnston 		else
17116660ef6eSMark Johnston 			ntb->mw_count = XEON_GEN3_MW_COUNT;
17126660ef6eSMark Johnston 		break;
17136660ef6eSMark Johnston 	}
1714ed9652daSAlexander Motin }
1715ed9652daSAlexander Motin 
1716ed9652daSAlexander Motin static int
intel_ntb_detect_xeon(struct ntb_softc * ntb)1717ed9652daSAlexander Motin intel_ntb_detect_xeon(struct ntb_softc *ntb)
1718ed9652daSAlexander Motin {
1719ed9652daSAlexander Motin 	uint8_t ppd, conn_type;
1720ed9652daSAlexander Motin 
1721ed9652daSAlexander Motin 	ppd = pci_read_config(ntb->device, NTB_PPD_OFFSET, 1);
1722ed9652daSAlexander Motin 	ntb->ppd = ppd;
1723ed9652daSAlexander Motin 
1724ed9652daSAlexander Motin 	if ((ppd & XEON_PPD_DEV_TYPE) != 0)
1725ed9652daSAlexander Motin 		ntb->dev_type = NTB_DEV_DSD;
1726ed9652daSAlexander Motin 	else
1727ed9652daSAlexander Motin 		ntb->dev_type = NTB_DEV_USD;
1728ed9652daSAlexander Motin 
1729ed9652daSAlexander Motin 	if ((ppd & XEON_PPD_SPLIT_BAR) != 0)
1730ed9652daSAlexander Motin 		ntb->features |= NTB_SPLIT_BAR;
1731ed9652daSAlexander Motin 
1732ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP) &&
1733ed9652daSAlexander Motin 	    !HAS_FEATURE(ntb, NTB_SPLIT_BAR)) {
1734ed9652daSAlexander Motin 		device_printf(ntb->device,
1735ed9652daSAlexander Motin 		    "Can not apply SB01BASE_LOCKUP workaround "
1736ed9652daSAlexander Motin 		    "with split BARs disabled!\n");
1737ed9652daSAlexander Motin 		device_printf(ntb->device,
1738ed9652daSAlexander Motin 		    "Expect system hangs under heavy NTB traffic!\n");
1739ed9652daSAlexander Motin 		ntb->features &= ~NTB_SB01BASE_LOCKUP;
1740ed9652daSAlexander Motin 	}
1741ed9652daSAlexander Motin 
1742ed9652daSAlexander Motin 	/*
1743ed9652daSAlexander Motin 	 * SDOORBELL errata workaround gets in the way of SB01BASE_LOCKUP
1744ed9652daSAlexander Motin 	 * errata workaround; only do one at a time.
1745ed9652daSAlexander Motin 	 */
1746ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP))
1747ed9652daSAlexander Motin 		ntb->features &= ~NTB_SDOORBELL_LOCKUP;
1748ed9652daSAlexander Motin 
1749ed9652daSAlexander Motin 	conn_type = ppd & XEON_PPD_CONN_TYPE;
1750ed9652daSAlexander Motin 	switch (conn_type) {
1751ed9652daSAlexander Motin 	case NTB_CONN_B2B:
1752ed9652daSAlexander Motin 		ntb->conn_type = conn_type;
1753ed9652daSAlexander Motin 		break;
1754ed9652daSAlexander Motin 	case NTB_CONN_RP:
1755ed9652daSAlexander Motin 	case NTB_CONN_TRANSPARENT:
1756ed9652daSAlexander Motin 	default:
1757ed9652daSAlexander Motin 		device_printf(ntb->device, "Unsupported connection type: %u\n",
1758ed9652daSAlexander Motin 		    (unsigned)conn_type);
1759ed9652daSAlexander Motin 		return (ENXIO);
1760ed9652daSAlexander Motin 	}
1761ed9652daSAlexander Motin 	return (0);
1762ed9652daSAlexander Motin }
1763ed9652daSAlexander Motin 
1764ed9652daSAlexander Motin static int
intel_ntb_detect_atom(struct ntb_softc * ntb)1765ed9652daSAlexander Motin intel_ntb_detect_atom(struct ntb_softc *ntb)
1766ed9652daSAlexander Motin {
1767ed9652daSAlexander Motin 	uint32_t ppd, conn_type;
1768ed9652daSAlexander Motin 
1769ed9652daSAlexander Motin 	ppd = pci_read_config(ntb->device, NTB_PPD_OFFSET, 4);
1770ed9652daSAlexander Motin 	ntb->ppd = ppd;
1771ed9652daSAlexander Motin 
1772ed9652daSAlexander Motin 	if ((ppd & ATOM_PPD_DEV_TYPE) != 0)
1773ed9652daSAlexander Motin 		ntb->dev_type = NTB_DEV_DSD;
1774ed9652daSAlexander Motin 	else
1775ed9652daSAlexander Motin 		ntb->dev_type = NTB_DEV_USD;
1776ed9652daSAlexander Motin 
1777ed9652daSAlexander Motin 	conn_type = (ppd & ATOM_PPD_CONN_TYPE) >> 8;
1778ed9652daSAlexander Motin 	switch (conn_type) {
1779ed9652daSAlexander Motin 	case NTB_CONN_B2B:
1780ed9652daSAlexander Motin 		ntb->conn_type = conn_type;
1781ed9652daSAlexander Motin 		break;
1782ed9652daSAlexander Motin 	default:
1783ed9652daSAlexander Motin 		device_printf(ntb->device, "Unsupported NTB configuration\n");
1784ed9652daSAlexander Motin 		return (ENXIO);
1785ed9652daSAlexander Motin 	}
1786ed9652daSAlexander Motin 	return (0);
1787ed9652daSAlexander Motin }
1788ed9652daSAlexander Motin 
1789ed9652daSAlexander Motin static int
intel_ntb_detect_xeon_gen3(struct ntb_softc * ntb)17906660ef6eSMark Johnston intel_ntb_detect_xeon_gen3(struct ntb_softc *ntb)
17916660ef6eSMark Johnston {
17926660ef6eSMark Johnston 	uint8_t ppd, conn_type;
17936660ef6eSMark Johnston 
17946660ef6eSMark Johnston 	ppd = pci_read_config(ntb->device, XEON_GEN3_INT_REG_PPD, 1);
17956660ef6eSMark Johnston 	ntb->ppd = ppd;
17966660ef6eSMark Johnston 
17976660ef6eSMark Johnston 	/* check port definition */
17986660ef6eSMark Johnston 	conn_type = XEON_GEN3_REG_PPD_PORT_DEF_F(ppd);
17996660ef6eSMark Johnston 	switch (conn_type) {
18006660ef6eSMark Johnston 	case NTB_CONN_B2B:
18016660ef6eSMark Johnston 		ntb->conn_type = conn_type;
18026660ef6eSMark Johnston 		break;
18036660ef6eSMark Johnston 	default:
18046660ef6eSMark Johnston 		device_printf(ntb->device, "Unsupported connection type: %u\n",
18056660ef6eSMark Johnston 		    conn_type);
18066660ef6eSMark Johnston 		return (ENXIO);
18076660ef6eSMark Johnston 	}
18086660ef6eSMark Johnston 
18096660ef6eSMark Johnston 	/* check cross link configuration status */
18106660ef6eSMark Johnston 	if (XEON_GEN3_REG_PPD_CONF_STS_F(ppd)) {
18116660ef6eSMark Johnston 		/* NTB Port is configured as DSD/USP */
18126660ef6eSMark Johnston 		ntb->dev_type = NTB_DEV_DSD;
18136660ef6eSMark Johnston 	} else {
18146660ef6eSMark Johnston 		/* NTB Port is configured as USD/DSP */
18156660ef6eSMark Johnston 		ntb->dev_type = NTB_DEV_USD;
18166660ef6eSMark Johnston 	}
18176660ef6eSMark Johnston 
18186660ef6eSMark Johnston 	if (XEON_GEN3_REG_PPD_ONE_MSIX_F(ppd)) {
18196660ef6eSMark Johnston 		/*
18206660ef6eSMark Johnston 		 * This bit when set, causes only a single MSI-X message to be
18216660ef6eSMark Johnston 		 * generated if MSI-X is enabled.
18226660ef6eSMark Johnston 		 */
18236660ef6eSMark Johnston 		ntb->features |= NTB_ONE_MSIX;
18246660ef6eSMark Johnston 	}
18256660ef6eSMark Johnston 
18266660ef6eSMark Johnston 	if (XEON_GEN3_REG_PPD_BAR45_SPL_F(ppd)) {
18276660ef6eSMark Johnston 		/* BARs 4 and 5 are presented as two 32b non-prefetchable BARs */
18286660ef6eSMark Johnston 		ntb->features |= NTB_SPLIT_BAR;
18296660ef6eSMark Johnston 	}
18306660ef6eSMark Johnston 
18316660ef6eSMark Johnston 	device_printf(ntb->device, "conn type 0x%02x, dev type 0x%02x,"
18326660ef6eSMark Johnston 	    "features 0x%02x\n", ntb->conn_type, ntb->dev_type, ntb->features);
18336660ef6eSMark Johnston 
18346660ef6eSMark Johnston 	return (0);
18356660ef6eSMark Johnston }
18366660ef6eSMark Johnston 
18376660ef6eSMark Johnston static int
intel_ntb_is_ICX(struct ntb_softc * ntb)1838*70450ecdSAustin Zhang intel_ntb_is_ICX(struct ntb_softc *ntb)
1839*70450ecdSAustin Zhang {
1840*70450ecdSAustin Zhang 	uint8_t revision;
1841*70450ecdSAustin Zhang 
1842*70450ecdSAustin Zhang 	revision = pci_get_revid(ntb->device);
1843*70450ecdSAustin Zhang 	if (ntb->type == NTB_XEON_GEN4 &&
1844*70450ecdSAustin Zhang 	    revision >= PCI_DEV_REV_ICX_MIN &&
1845*70450ecdSAustin Zhang 	    revision <= PCI_DEV_REV_ICX_MAX)
1846*70450ecdSAustin Zhang 		return (1);
1847*70450ecdSAustin Zhang 
1848*70450ecdSAustin Zhang 	return (0);
1849*70450ecdSAustin Zhang }
1850*70450ecdSAustin Zhang 
1851*70450ecdSAustin Zhang static int
intel_ntb_is_SPR(struct ntb_softc * ntb)1852*70450ecdSAustin Zhang intel_ntb_is_SPR(struct ntb_softc *ntb)
1853*70450ecdSAustin Zhang {
1854*70450ecdSAustin Zhang 	uint8_t revision;
1855*70450ecdSAustin Zhang 
1856*70450ecdSAustin Zhang 	revision = pci_get_revid(ntb->device);
1857*70450ecdSAustin Zhang 	if (ntb->type == NTB_XEON_GEN4 &&
1858*70450ecdSAustin Zhang 	    revision > PCI_DEV_REV_ICX_MAX)
1859*70450ecdSAustin Zhang 		return (1);
1860*70450ecdSAustin Zhang 
1861*70450ecdSAustin Zhang 	return (0);
1862*70450ecdSAustin Zhang }
1863*70450ecdSAustin Zhang 
1864*70450ecdSAustin Zhang static int
intel_ntb_detect_xeon_gen4(struct ntb_softc * ntb)1865*70450ecdSAustin Zhang intel_ntb_detect_xeon_gen4(struct ntb_softc *ntb)
1866*70450ecdSAustin Zhang {
1867*70450ecdSAustin Zhang 	if (intel_ntb_is_ICX(ntb)) {
1868*70450ecdSAustin Zhang 		ntb->features |= NTB_BAR_ALIGN;
1869*70450ecdSAustin Zhang 		ntb->features |= NTB_LTR_BAD;
1870*70450ecdSAustin Zhang 	}
1871*70450ecdSAustin Zhang 	return (0);
1872*70450ecdSAustin Zhang }
1873*70450ecdSAustin Zhang 
1874*70450ecdSAustin Zhang static int
intel_ntb_detect_xeon_gen4_cfg(struct ntb_softc * ntb)1875*70450ecdSAustin Zhang intel_ntb_detect_xeon_gen4_cfg(struct ntb_softc *ntb)
1876*70450ecdSAustin Zhang {
1877*70450ecdSAustin Zhang 	uint32_t ppd1;
1878*70450ecdSAustin Zhang 
1879*70450ecdSAustin Zhang 	ppd1 = intel_ntb_reg_read(4, XEON_GEN4_REG_PPD1);
1880*70450ecdSAustin Zhang 	ntb->ppd = ppd1;
1881*70450ecdSAustin Zhang 	if (intel_ntb_is_ICX(ntb)) {
1882*70450ecdSAustin Zhang 		if ((ppd1 & GEN4_PPD_TOPO_MASK) == GEN4_PPD_TOPO_B2B_USD) {
1883*70450ecdSAustin Zhang 			/* NTB Port is configured as USD/DSP */
1884*70450ecdSAustin Zhang 			ntb->conn_type = NTB_CONN_B2B;
1885*70450ecdSAustin Zhang 			ntb->dev_type = NTB_DEV_USD;
1886*70450ecdSAustin Zhang 		} else if ((ppd1 & GEN4_PPD_TOPO_MASK) == GEN4_PPD_TOPO_B2B_DSD) {
1887*70450ecdSAustin Zhang 			/* NTB Port is configured as DSD/USP */
1888*70450ecdSAustin Zhang 			ntb->conn_type = NTB_CONN_B2B;
1889*70450ecdSAustin Zhang 			ntb->dev_type = NTB_DEV_DSD;
1890*70450ecdSAustin Zhang 		} else {
1891*70450ecdSAustin Zhang 			device_printf(ntb->device, "Unsupported connection type: %u\n",
1892*70450ecdSAustin Zhang 			    (ppd1 & GEN4_PPD_CONN_MASK));
1893*70450ecdSAustin Zhang 			return (ENXIO);
1894*70450ecdSAustin Zhang 		}
1895*70450ecdSAustin Zhang 	} else if (intel_ntb_is_SPR(ntb)) {
1896*70450ecdSAustin Zhang 		if ((ppd1 & SPR_PPD_TOPO_MASK) == SPR_PPD_TOPO_B2B_USD) {
1897*70450ecdSAustin Zhang 			/* NTB Port is configured as USD/DSP */
1898*70450ecdSAustin Zhang 			ntb->conn_type = NTB_CONN_B2B;
1899*70450ecdSAustin Zhang 			ntb->dev_type = NTB_DEV_USD;
1900*70450ecdSAustin Zhang 		} else if ((ppd1 & SPR_PPD_TOPO_MASK) == SPR_PPD_TOPO_B2B_DSD) {
1901*70450ecdSAustin Zhang 			/* NTB Port is configured as DSD/USP */
1902*70450ecdSAustin Zhang 			ntb->conn_type = NTB_CONN_B2B;
1903*70450ecdSAustin Zhang 			ntb->dev_type = NTB_DEV_DSD;
1904*70450ecdSAustin Zhang 		} else {
1905*70450ecdSAustin Zhang 			device_printf(ntb->device, "Unsupported connection type: %u\n",
1906*70450ecdSAustin Zhang 			    (ppd1 & SPR_PPD_CONN_MASK));
1907*70450ecdSAustin Zhang 			return (ENXIO);
1908*70450ecdSAustin Zhang 		}
1909*70450ecdSAustin Zhang 	}
1910*70450ecdSAustin Zhang 
1911*70450ecdSAustin Zhang 	device_printf(ntb->device, "conn type 0x%02x, dev type 0x%02x,"
1912*70450ecdSAustin Zhang 	    "features 0x%02x\n", ntb->conn_type, ntb->dev_type, ntb->features);
1913*70450ecdSAustin Zhang 
1914*70450ecdSAustin Zhang 	return (0);
1915*70450ecdSAustin Zhang }
1916*70450ecdSAustin Zhang 
1917*70450ecdSAustin Zhang static int
intel_ntb_xeon_init_dev(struct ntb_softc * ntb)1918ed9652daSAlexander Motin intel_ntb_xeon_init_dev(struct ntb_softc *ntb)
1919ed9652daSAlexander Motin {
1920ed9652daSAlexander Motin 	int rc;
1921ed9652daSAlexander Motin 
1922ed9652daSAlexander Motin 	ntb->spad_count		= XEON_SPAD_COUNT;
1923ed9652daSAlexander Motin 	ntb->db_count		= XEON_DB_COUNT;
1924ed9652daSAlexander Motin 	ntb->db_link_mask	= XEON_DB_LINK_BIT;
1925ed9652daSAlexander Motin 	ntb->db_vec_count	= XEON_DB_MSIX_VECTOR_COUNT;
1926ed9652daSAlexander Motin 	ntb->db_vec_shift	= XEON_DB_MSIX_VECTOR_SHIFT;
1927ed9652daSAlexander Motin 
1928ed9652daSAlexander Motin 	if (ntb->conn_type != NTB_CONN_B2B) {
1929ed9652daSAlexander Motin 		device_printf(ntb->device, "Connection type %d not supported\n",
1930ed9652daSAlexander Motin 		    ntb->conn_type);
1931ed9652daSAlexander Motin 		return (ENXIO);
1932ed9652daSAlexander Motin 	}
1933ed9652daSAlexander Motin 
1934ed9652daSAlexander Motin 	ntb->reg = &xeon_reg;
1935ed9652daSAlexander Motin 	ntb->self_reg = &xeon_pri_reg;
1936ed9652daSAlexander Motin 	ntb->peer_reg = &xeon_b2b_reg;
1937ed9652daSAlexander Motin 	ntb->xlat_reg = &xeon_sec_xlat;
1938ed9652daSAlexander Motin 
1939ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP)) {
1940ed9652daSAlexander Motin 		ntb->force_db = ntb->fake_db = 0;
1941ed9652daSAlexander Motin 		ntb->msix_mw_idx = (ntb->mw_count + g_ntb_msix_idx) %
1942ed9652daSAlexander Motin 		    ntb->mw_count;
1943ed9652daSAlexander Motin 		intel_ntb_printf(2, "Setting up MSIX mw idx %d means %u\n",
1944ed9652daSAlexander Motin 		    g_ntb_msix_idx, ntb->msix_mw_idx);
1945ed9652daSAlexander Motin 		rc = intel_ntb_mw_set_wc_internal(ntb, ntb->msix_mw_idx,
1946ed9652daSAlexander Motin 		    VM_MEMATTR_UNCACHEABLE);
1947ed9652daSAlexander Motin 		KASSERT(rc == 0, ("shouldn't fail"));
1948ed9652daSAlexander Motin 	} else if (HAS_FEATURE(ntb, NTB_SDOORBELL_LOCKUP)) {
1949ed9652daSAlexander Motin 		/*
1950ed9652daSAlexander Motin 		 * There is a Xeon hardware errata related to writes to SDOORBELL or
1951ed9652daSAlexander Motin 		 * B2BDOORBELL in conjunction with inbound access to NTB MMIO space,
1952ed9652daSAlexander Motin 		 * which may hang the system.  To workaround this, use a memory
1953ed9652daSAlexander Motin 		 * window to access the interrupt and scratch pad registers on the
1954ed9652daSAlexander Motin 		 * remote system.
1955ed9652daSAlexander Motin 		 */
1956ed9652daSAlexander Motin 		ntb->b2b_mw_idx = (ntb->mw_count + g_ntb_mw_idx) %
1957ed9652daSAlexander Motin 		    ntb->mw_count;
1958ed9652daSAlexander Motin 		intel_ntb_printf(2, "Setting up b2b mw idx %d means %u\n",
1959ed9652daSAlexander Motin 		    g_ntb_mw_idx, ntb->b2b_mw_idx);
1960ed9652daSAlexander Motin 		rc = intel_ntb_mw_set_wc_internal(ntb, ntb->b2b_mw_idx,
1961ed9652daSAlexander Motin 		    VM_MEMATTR_UNCACHEABLE);
1962ed9652daSAlexander Motin 		KASSERT(rc == 0, ("shouldn't fail"));
1963ed9652daSAlexander Motin 	} else if (HAS_FEATURE(ntb, NTB_B2BDOORBELL_BIT14))
1964ed9652daSAlexander Motin 		/*
1965ed9652daSAlexander Motin 		 * HW Errata on bit 14 of b2bdoorbell register.  Writes will not be
1966ed9652daSAlexander Motin 		 * mirrored to the remote system.  Shrink the number of bits by one,
1967ed9652daSAlexander Motin 		 * since bit 14 is the last bit.
1968ed9652daSAlexander Motin 		 *
1969ed9652daSAlexander Motin 		 * On REGS_THRU_MW errata mode, we don't use the b2bdoorbell register
1970ed9652daSAlexander Motin 		 * anyway.  Nor for non-B2B connection types.
1971ed9652daSAlexander Motin 		 */
1972ed9652daSAlexander Motin 		ntb->db_count = XEON_DB_COUNT - 1;
1973ed9652daSAlexander Motin 
1974ed9652daSAlexander Motin 	ntb->db_valid_mask = (1ull << ntb->db_count) - 1;
1975ed9652daSAlexander Motin 
1976ed9652daSAlexander Motin 	if (ntb->dev_type == NTB_DEV_USD)
1977ed9652daSAlexander Motin 		rc = xeon_setup_b2b_mw(ntb, &xeon_b2b_dsd_addr,
1978ed9652daSAlexander Motin 		    &xeon_b2b_usd_addr);
1979ed9652daSAlexander Motin 	else
1980ed9652daSAlexander Motin 		rc = xeon_setup_b2b_mw(ntb, &xeon_b2b_usd_addr,
1981ed9652daSAlexander Motin 		    &xeon_b2b_dsd_addr);
1982ed9652daSAlexander Motin 	if (rc != 0)
1983ed9652daSAlexander Motin 		return (rc);
1984ed9652daSAlexander Motin 
1985ed9652daSAlexander Motin 	/* Enable Bus Master and Memory Space on the secondary side */
1986ed9652daSAlexander Motin 	intel_ntb_reg_write(2, XEON_SPCICMD_OFFSET,
1987ed9652daSAlexander Motin 	    PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
1988ed9652daSAlexander Motin 
1989ed9652daSAlexander Motin 	/*
1990ed9652daSAlexander Motin 	 * Mask all doorbell interrupts.
1991ed9652daSAlexander Motin 	 */
1992ed9652daSAlexander Motin 	DB_MASK_LOCK(ntb);
1993ed9652daSAlexander Motin 	ntb->db_mask = ntb->db_valid_mask;
1994ed9652daSAlexander Motin 	db_iowrite(ntb, ntb->self_reg->db_mask, ntb->db_mask);
1995ed9652daSAlexander Motin 	DB_MASK_UNLOCK(ntb);
1996ed9652daSAlexander Motin 
1997ed9652daSAlexander Motin 	rc = intel_ntb_init_isr(ntb);
1998ed9652daSAlexander Motin 	return (rc);
1999ed9652daSAlexander Motin }
2000ed9652daSAlexander Motin 
2001ed9652daSAlexander Motin static int
intel_ntb_xeon_gen3_init_dev(struct ntb_softc * ntb)20026660ef6eSMark Johnston intel_ntb_xeon_gen3_init_dev(struct ntb_softc *ntb)
20036660ef6eSMark Johnston {
20046660ef6eSMark Johnston 	int rc;
20056660ef6eSMark Johnston 
20066660ef6eSMark Johnston 	ntb->spad_count = XEON_GEN3_SPAD_COUNT;
20076660ef6eSMark Johnston 	ntb->db_count = XEON_GEN3_DB_COUNT;
20086660ef6eSMark Johnston 	ntb->db_link_mask = XEON_GEN3_DB_LINK_BIT;
20096660ef6eSMark Johnston 	ntb->db_vec_count = XEON_GEN3_DB_MSIX_VECTOR_COUNT;
20106660ef6eSMark Johnston 	ntb->db_vec_shift = XEON_GEN3_DB_MSIX_VECTOR_SHIFT;
20116660ef6eSMark Johnston 
20126660ef6eSMark Johnston 	if (ntb->conn_type != NTB_CONN_B2B) {
20136660ef6eSMark Johnston 		device_printf(ntb->device, "Connection type %d not supported\n",
20146660ef6eSMark Johnston 		    ntb->conn_type);
20156660ef6eSMark Johnston 		return (ENXIO);
20166660ef6eSMark Johnston 	}
20176660ef6eSMark Johnston 
20186660ef6eSMark Johnston 	ntb->reg = &xeon_gen3_reg;
20196660ef6eSMark Johnston 	ntb->self_reg = &xeon_gen3_pri_reg;
20206660ef6eSMark Johnston 	ntb->peer_reg = &xeon_gen3_b2b_reg;
20216660ef6eSMark Johnston 	ntb->xlat_reg = &xeon_gen3_sec_xlat;
20226660ef6eSMark Johnston 
20236660ef6eSMark Johnston 	ntb->db_valid_mask = (1ULL << ntb->db_count) - 1;
20246660ef6eSMark Johnston 
20256660ef6eSMark Johnston 	xeon_gen3_setup_b2b_mw(ntb);
20266660ef6eSMark Johnston 
20276660ef6eSMark Johnston 	/* Enable Bus Master and Memory Space on the External Side */
20286660ef6eSMark Johnston 	intel_ntb_reg_write(2, XEON_GEN3_EXT_REG_PCI_CMD,
20296660ef6eSMark Johnston 	    PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
20306660ef6eSMark Johnston 
20316660ef6eSMark Johnston 	/* Setup Interrupt */
20326660ef6eSMark Johnston 	rc = intel_ntb_xeon_gen3_init_isr(ntb);
20336660ef6eSMark Johnston 
20346660ef6eSMark Johnston 	return (rc);
20356660ef6eSMark Johnston }
20366660ef6eSMark Johnston 
20376660ef6eSMark Johnston static int
intel_ntb_xeon_gen4_init_dev(struct ntb_softc * ntb)2038*70450ecdSAustin Zhang intel_ntb_xeon_gen4_init_dev(struct ntb_softc *ntb)
2039*70450ecdSAustin Zhang {
2040*70450ecdSAustin Zhang 	int rc;
2041*70450ecdSAustin Zhang 	uint16_t lnkctl;
2042*70450ecdSAustin Zhang 
2043*70450ecdSAustin Zhang 	ntb->spad_count = XEON_GEN4_SPAD_COUNT;
2044*70450ecdSAustin Zhang 	ntb->db_count = XEON_GEN4_DB_COUNT;
2045*70450ecdSAustin Zhang 	ntb->db_link_mask = XEON_GEN4_DB_LINK_BIT;
2046*70450ecdSAustin Zhang 	ntb->db_vec_count = XEON_GEN4_DB_MSIX_VECTOR_COUNT;
2047*70450ecdSAustin Zhang 	ntb->db_vec_shift = XEON_GEN4_DB_MSIX_VECTOR_SHIFT;
2048*70450ecdSAustin Zhang 
2049*70450ecdSAustin Zhang 	if (intel_ntb_detect_xeon_gen4_cfg(ntb) != 0)
2050*70450ecdSAustin Zhang 		return (ENXIO);
2051*70450ecdSAustin Zhang 
2052*70450ecdSAustin Zhang 	ntb->reg = &xeon_gen4_reg;
2053*70450ecdSAustin Zhang 	ntb->self_reg = &xeon_gen4_pri_reg;
2054*70450ecdSAustin Zhang 	ntb->peer_reg = &xeon_gen4_b2b_reg;
2055*70450ecdSAustin Zhang 	ntb->xlat_reg = &xeon_gen4_sec_xlat;
2056*70450ecdSAustin Zhang 
2057*70450ecdSAustin Zhang 	ntb->db_valid_mask = (1ULL << ntb->db_count) - 1;
2058*70450ecdSAustin Zhang 	xeon_gen4_setup_b2b_mw(ntb);
2059*70450ecdSAustin Zhang 
2060*70450ecdSAustin Zhang 	/* init link setup */
2061*70450ecdSAustin Zhang 	lnkctl = intel_ntb_reg_read(2, XEON_GEN4_REG_LINK_CTRL);
2062*70450ecdSAustin Zhang 	lnkctl |= GEN4_LINK_CTRL_LINK_DISABLE;
2063*70450ecdSAustin Zhang 	intel_ntb_reg_write(2, XEON_GEN4_REG_LINK_CTRL, lnkctl);
2064*70450ecdSAustin Zhang 
2065*70450ecdSAustin Zhang 	/* Setup Interrupt */
2066*70450ecdSAustin Zhang 	rc = intel_ntb_xeon_gen4_init_isr(ntb);
2067*70450ecdSAustin Zhang 	return (rc);
2068*70450ecdSAustin Zhang }
2069*70450ecdSAustin Zhang 
2070*70450ecdSAustin Zhang static int
intel_ntb_atom_init_dev(struct ntb_softc * ntb)2071ed9652daSAlexander Motin intel_ntb_atom_init_dev(struct ntb_softc *ntb)
2072ed9652daSAlexander Motin {
2073ed9652daSAlexander Motin 	int error;
2074ed9652daSAlexander Motin 
2075ed9652daSAlexander Motin 	KASSERT(ntb->conn_type == NTB_CONN_B2B,
2076ed9652daSAlexander Motin 	    ("Unsupported NTB configuration (%d)\n", ntb->conn_type));
2077ed9652daSAlexander Motin 
2078ed9652daSAlexander Motin 	ntb->spad_count		 = ATOM_SPAD_COUNT;
2079ed9652daSAlexander Motin 	ntb->db_count		 = ATOM_DB_COUNT;
2080ed9652daSAlexander Motin 	ntb->db_vec_count	 = ATOM_DB_MSIX_VECTOR_COUNT;
2081ed9652daSAlexander Motin 	ntb->db_vec_shift	 = ATOM_DB_MSIX_VECTOR_SHIFT;
2082ed9652daSAlexander Motin 	ntb->db_valid_mask	 = (1ull << ntb->db_count) - 1;
2083ed9652daSAlexander Motin 
2084ed9652daSAlexander Motin 	ntb->reg = &atom_reg;
2085ed9652daSAlexander Motin 	ntb->self_reg = &atom_pri_reg;
2086ed9652daSAlexander Motin 	ntb->peer_reg = &atom_b2b_reg;
2087ed9652daSAlexander Motin 	ntb->xlat_reg = &atom_sec_xlat;
2088ed9652daSAlexander Motin 
2089ed9652daSAlexander Motin 	/*
2090ed9652daSAlexander Motin 	 * FIXME - MSI-X bug on early Atom HW, remove once internal issue is
2091ed9652daSAlexander Motin 	 * resolved.  Mask transaction layer internal parity errors.
2092ed9652daSAlexander Motin 	 */
2093ed9652daSAlexander Motin 	pci_write_config(ntb->device, 0xFC, 0x4, 4);
2094ed9652daSAlexander Motin 
2095ed9652daSAlexander Motin 	configure_atom_secondary_side_bars(ntb);
2096ed9652daSAlexander Motin 
2097ed9652daSAlexander Motin 	/* Enable Bus Master and Memory Space on the secondary side */
2098ed9652daSAlexander Motin 	intel_ntb_reg_write(2, ATOM_SPCICMD_OFFSET,
2099ed9652daSAlexander Motin 	    PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
2100ed9652daSAlexander Motin 
2101ed9652daSAlexander Motin 	error = intel_ntb_init_isr(ntb);
2102ed9652daSAlexander Motin 	if (error != 0)
2103ed9652daSAlexander Motin 		return (error);
2104ed9652daSAlexander Motin 
2105ed9652daSAlexander Motin 	/* Initiate PCI-E link training */
2106ed9652daSAlexander Motin 	intel_ntb_link_enable(ntb->device, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
2107ed9652daSAlexander Motin 
2108ed9652daSAlexander Motin 	callout_reset(&ntb->heartbeat_timer, 0, atom_link_hb, ntb);
2109ed9652daSAlexander Motin 
2110ed9652daSAlexander Motin 	return (0);
2111ed9652daSAlexander Motin }
2112ed9652daSAlexander Motin 
2113ed9652daSAlexander Motin /* XXX: Linux driver doesn't seem to do any of this for Atom. */
2114ed9652daSAlexander Motin static void
configure_atom_secondary_side_bars(struct ntb_softc * ntb)2115ed9652daSAlexander Motin configure_atom_secondary_side_bars(struct ntb_softc *ntb)
2116ed9652daSAlexander Motin {
2117ed9652daSAlexander Motin 
2118ed9652daSAlexander Motin 	if (ntb->dev_type == NTB_DEV_USD) {
2119ed9652daSAlexander Motin 		intel_ntb_reg_write(8, ATOM_PBAR2XLAT_OFFSET,
2120ed9652daSAlexander Motin 		    XEON_B2B_BAR2_ADDR64);
2121ed9652daSAlexander Motin 		intel_ntb_reg_write(8, ATOM_PBAR4XLAT_OFFSET,
2122ed9652daSAlexander Motin 		    XEON_B2B_BAR4_ADDR64);
2123ed9652daSAlexander Motin 		intel_ntb_reg_write(8, ATOM_MBAR23_OFFSET, XEON_B2B_BAR2_ADDR64);
2124ed9652daSAlexander Motin 		intel_ntb_reg_write(8, ATOM_MBAR45_OFFSET, XEON_B2B_BAR4_ADDR64);
2125ed9652daSAlexander Motin 	} else {
2126ed9652daSAlexander Motin 		intel_ntb_reg_write(8, ATOM_PBAR2XLAT_OFFSET,
2127ed9652daSAlexander Motin 		    XEON_B2B_BAR2_ADDR64);
2128ed9652daSAlexander Motin 		intel_ntb_reg_write(8, ATOM_PBAR4XLAT_OFFSET,
2129ed9652daSAlexander Motin 		    XEON_B2B_BAR4_ADDR64);
2130ed9652daSAlexander Motin 		intel_ntb_reg_write(8, ATOM_MBAR23_OFFSET, XEON_B2B_BAR2_ADDR64);
2131ed9652daSAlexander Motin 		intel_ntb_reg_write(8, ATOM_MBAR45_OFFSET, XEON_B2B_BAR4_ADDR64);
2132ed9652daSAlexander Motin 	}
2133ed9652daSAlexander Motin }
2134ed9652daSAlexander Motin 
2135ed9652daSAlexander Motin /*
2136ed9652daSAlexander Motin  * When working around Xeon SDOORBELL errata by remapping remote registers in a
2137ed9652daSAlexander Motin  * MW, limit the B2B MW to half a MW.  By sharing a MW, half the shared MW
2138ed9652daSAlexander Motin  * remains for use by a higher layer.
2139ed9652daSAlexander Motin  *
2140ed9652daSAlexander Motin  * Will only be used if working around SDOORBELL errata and the BIOS-configured
2141ed9652daSAlexander Motin  * MW size is sufficiently large.
2142ed9652daSAlexander Motin  */
2143ed9652daSAlexander Motin static unsigned int ntb_b2b_mw_share;
2144ed9652daSAlexander Motin SYSCTL_UINT(_hw_ntb, OID_AUTO, b2b_mw_share, CTLFLAG_RDTUN, &ntb_b2b_mw_share,
2145ed9652daSAlexander Motin     0, "If enabled (non-zero), prefer to share half of the B2B peer register "
2146ed9652daSAlexander Motin     "MW with higher level consumers.  Both sides of the NTB MUST set the same "
2147ed9652daSAlexander Motin     "value here.");
2148ed9652daSAlexander Motin 
2149ed9652daSAlexander Motin static void
xeon_reset_sbar_size(struct ntb_softc * ntb,enum ntb_bar idx,enum ntb_bar regbar)2150ed9652daSAlexander Motin xeon_reset_sbar_size(struct ntb_softc *ntb, enum ntb_bar idx,
2151ed9652daSAlexander Motin     enum ntb_bar regbar)
2152ed9652daSAlexander Motin {
2153ed9652daSAlexander Motin 	struct ntb_pci_bar_info *bar;
2154ed9652daSAlexander Motin 	uint8_t bar_sz;
2155ed9652daSAlexander Motin 
2156ed9652daSAlexander Motin 	if (!HAS_FEATURE(ntb, NTB_SPLIT_BAR) && idx >= NTB_B2B_BAR_3)
2157ed9652daSAlexander Motin 		return;
2158ed9652daSAlexander Motin 
2159ed9652daSAlexander Motin 	bar = &ntb->bar_info[idx];
2160ed9652daSAlexander Motin 	bar_sz = pci_read_config(ntb->device, bar->psz_off, 1);
2161ed9652daSAlexander Motin 	if (idx == regbar) {
2162ed9652daSAlexander Motin 		if (ntb->b2b_off != 0)
2163ed9652daSAlexander Motin 			bar_sz--;
2164ed9652daSAlexander Motin 		else
2165ed9652daSAlexander Motin 			bar_sz = 0;
2166ed9652daSAlexander Motin 	}
2167ed9652daSAlexander Motin 	pci_write_config(ntb->device, bar->ssz_off, bar_sz, 1);
2168ed9652daSAlexander Motin 	bar_sz = pci_read_config(ntb->device, bar->ssz_off, 1);
2169ed9652daSAlexander Motin 	(void)bar_sz;
2170ed9652daSAlexander Motin }
2171ed9652daSAlexander Motin 
2172ed9652daSAlexander Motin static void
xeon_set_sbar_base_and_limit(struct ntb_softc * ntb,uint64_t bar_addr,enum ntb_bar idx,enum ntb_bar regbar)2173ed9652daSAlexander Motin xeon_set_sbar_base_and_limit(struct ntb_softc *ntb, uint64_t bar_addr,
2174ed9652daSAlexander Motin     enum ntb_bar idx, enum ntb_bar regbar)
2175ed9652daSAlexander Motin {
2176ed9652daSAlexander Motin 	uint64_t reg_val;
2177ed9652daSAlexander Motin 	uint32_t base_reg, lmt_reg;
2178ed9652daSAlexander Motin 
2179ed9652daSAlexander Motin 	bar_get_xlat_params(ntb, idx, &base_reg, NULL, &lmt_reg);
2180ed9652daSAlexander Motin 	if (idx == regbar) {
2181ed9652daSAlexander Motin 		if (ntb->b2b_off)
2182ed9652daSAlexander Motin 			bar_addr += ntb->b2b_off;
2183ed9652daSAlexander Motin 		else
2184ed9652daSAlexander Motin 			bar_addr = 0;
2185ed9652daSAlexander Motin 	}
2186ed9652daSAlexander Motin 
2187ed9652daSAlexander Motin 	if (!bar_is_64bit(ntb, idx)) {
2188ed9652daSAlexander Motin 		intel_ntb_reg_write(4, base_reg, bar_addr);
2189ed9652daSAlexander Motin 		reg_val = intel_ntb_reg_read(4, base_reg);
2190ed9652daSAlexander Motin 		(void)reg_val;
2191ed9652daSAlexander Motin 
2192ed9652daSAlexander Motin 		intel_ntb_reg_write(4, lmt_reg, bar_addr);
2193ed9652daSAlexander Motin 		reg_val = intel_ntb_reg_read(4, lmt_reg);
2194ed9652daSAlexander Motin 		(void)reg_val;
2195ed9652daSAlexander Motin 	} else {
2196ed9652daSAlexander Motin 		intel_ntb_reg_write(8, base_reg, bar_addr);
2197ed9652daSAlexander Motin 		reg_val = intel_ntb_reg_read(8, base_reg);
2198ed9652daSAlexander Motin 		(void)reg_val;
2199ed9652daSAlexander Motin 
2200ed9652daSAlexander Motin 		intel_ntb_reg_write(8, lmt_reg, bar_addr);
2201ed9652daSAlexander Motin 		reg_val = intel_ntb_reg_read(8, lmt_reg);
2202ed9652daSAlexander Motin 		(void)reg_val;
2203ed9652daSAlexander Motin 	}
2204ed9652daSAlexander Motin }
2205ed9652daSAlexander Motin 
2206ed9652daSAlexander Motin static void
xeon_set_pbar_xlat(struct ntb_softc * ntb,uint64_t base_addr,enum ntb_bar idx)2207ed9652daSAlexander Motin xeon_set_pbar_xlat(struct ntb_softc *ntb, uint64_t base_addr, enum ntb_bar idx)
2208ed9652daSAlexander Motin {
2209ed9652daSAlexander Motin 	struct ntb_pci_bar_info *bar;
2210ed9652daSAlexander Motin 
2211ed9652daSAlexander Motin 	bar = &ntb->bar_info[idx];
2212ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SPLIT_BAR) && idx >= NTB_B2B_BAR_2) {
2213ed9652daSAlexander Motin 		intel_ntb_reg_write(4, bar->pbarxlat_off, base_addr);
2214ed9652daSAlexander Motin 		base_addr = intel_ntb_reg_read(4, bar->pbarxlat_off);
2215ed9652daSAlexander Motin 	} else {
2216ed9652daSAlexander Motin 		intel_ntb_reg_write(8, bar->pbarxlat_off, base_addr);
2217ed9652daSAlexander Motin 		base_addr = intel_ntb_reg_read(8, bar->pbarxlat_off);
2218ed9652daSAlexander Motin 	}
2219ed9652daSAlexander Motin 	(void)base_addr;
2220ed9652daSAlexander Motin }
2221ed9652daSAlexander Motin 
2222ed9652daSAlexander Motin static int
xeon_setup_b2b_mw(struct ntb_softc * ntb,const struct ntb_b2b_addr * addr,const struct ntb_b2b_addr * peer_addr)2223ed9652daSAlexander Motin xeon_setup_b2b_mw(struct ntb_softc *ntb, const struct ntb_b2b_addr *addr,
2224ed9652daSAlexander Motin     const struct ntb_b2b_addr *peer_addr)
2225ed9652daSAlexander Motin {
2226ed9652daSAlexander Motin 	struct ntb_pci_bar_info *b2b_bar;
2227ed9652daSAlexander Motin 	vm_size_t bar_size;
2228ed9652daSAlexander Motin 	uint64_t bar_addr;
2229ed9652daSAlexander Motin 	enum ntb_bar b2b_bar_num, i;
2230ed9652daSAlexander Motin 
2231ed9652daSAlexander Motin 	if (ntb->b2b_mw_idx == B2B_MW_DISABLED) {
2232ed9652daSAlexander Motin 		b2b_bar = NULL;
2233ed9652daSAlexander Motin 		b2b_bar_num = NTB_CONFIG_BAR;
2234ed9652daSAlexander Motin 		ntb->b2b_off = 0;
2235ed9652daSAlexander Motin 	} else {
2236ed9652daSAlexander Motin 		b2b_bar_num = intel_ntb_mw_to_bar(ntb, ntb->b2b_mw_idx);
2237ed9652daSAlexander Motin 		KASSERT(b2b_bar_num > 0 && b2b_bar_num < NTB_MAX_BARS,
2238ed9652daSAlexander Motin 		    ("invalid b2b mw bar"));
2239ed9652daSAlexander Motin 
2240ed9652daSAlexander Motin 		b2b_bar = &ntb->bar_info[b2b_bar_num];
2241ed9652daSAlexander Motin 		bar_size = b2b_bar->size;
2242ed9652daSAlexander Motin 
2243ed9652daSAlexander Motin 		if (ntb_b2b_mw_share != 0 &&
2244ed9652daSAlexander Motin 		    (bar_size >> 1) >= XEON_B2B_MIN_SIZE)
2245ed9652daSAlexander Motin 			ntb->b2b_off = bar_size >> 1;
2246ed9652daSAlexander Motin 		else if (bar_size >= XEON_B2B_MIN_SIZE) {
2247ed9652daSAlexander Motin 			ntb->b2b_off = 0;
2248ed9652daSAlexander Motin 		} else {
2249ed9652daSAlexander Motin 			device_printf(ntb->device,
2250ed9652daSAlexander Motin 			    "B2B bar size is too small!\n");
2251ed9652daSAlexander Motin 			return (EIO);
2252ed9652daSAlexander Motin 		}
2253ed9652daSAlexander Motin 	}
2254ed9652daSAlexander Motin 
2255ed9652daSAlexander Motin 	/*
2256ed9652daSAlexander Motin 	 * Reset the secondary bar sizes to match the primary bar sizes.
2257ed9652daSAlexander Motin 	 * (Except, disable or halve the size of the B2B secondary bar.)
2258ed9652daSAlexander Motin 	 */
2259ed9652daSAlexander Motin 	for (i = NTB_B2B_BAR_1; i < NTB_MAX_BARS; i++)
2260ed9652daSAlexander Motin 		xeon_reset_sbar_size(ntb, i, b2b_bar_num);
2261ed9652daSAlexander Motin 
2262ed9652daSAlexander Motin 	bar_addr = 0;
2263ed9652daSAlexander Motin 	if (b2b_bar_num == NTB_CONFIG_BAR)
2264ed9652daSAlexander Motin 		bar_addr = addr->bar0_addr;
2265ed9652daSAlexander Motin 	else if (b2b_bar_num == NTB_B2B_BAR_1)
2266ed9652daSAlexander Motin 		bar_addr = addr->bar2_addr64;
2267ed9652daSAlexander Motin 	else if (b2b_bar_num == NTB_B2B_BAR_2 && !HAS_FEATURE(ntb, NTB_SPLIT_BAR))
2268ed9652daSAlexander Motin 		bar_addr = addr->bar4_addr64;
2269ed9652daSAlexander Motin 	else if (b2b_bar_num == NTB_B2B_BAR_2)
2270ed9652daSAlexander Motin 		bar_addr = addr->bar4_addr32;
2271ed9652daSAlexander Motin 	else if (b2b_bar_num == NTB_B2B_BAR_3)
2272ed9652daSAlexander Motin 		bar_addr = addr->bar5_addr32;
2273ed9652daSAlexander Motin 	else
2274ed9652daSAlexander Motin 		KASSERT(false, ("invalid bar"));
2275ed9652daSAlexander Motin 
2276ed9652daSAlexander Motin 	intel_ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, bar_addr);
2277ed9652daSAlexander Motin 
2278ed9652daSAlexander Motin 	/*
2279ed9652daSAlexander Motin 	 * Other SBARs are normally hit by the PBAR xlat, except for the b2b
2280ed9652daSAlexander Motin 	 * register BAR.  The B2B BAR is either disabled above or configured
2281ed9652daSAlexander Motin 	 * half-size.  It starts at PBAR xlat + offset.
2282ed9652daSAlexander Motin 	 *
2283ed9652daSAlexander Motin 	 * Also set up incoming BAR limits == base (zero length window).
2284ed9652daSAlexander Motin 	 */
2285ed9652daSAlexander Motin 	xeon_set_sbar_base_and_limit(ntb, addr->bar2_addr64, NTB_B2B_BAR_1,
2286ed9652daSAlexander Motin 	    b2b_bar_num);
2287ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SPLIT_BAR)) {
2288ed9652daSAlexander Motin 		xeon_set_sbar_base_and_limit(ntb, addr->bar4_addr32,
2289ed9652daSAlexander Motin 		    NTB_B2B_BAR_2, b2b_bar_num);
2290ed9652daSAlexander Motin 		xeon_set_sbar_base_and_limit(ntb, addr->bar5_addr32,
2291ed9652daSAlexander Motin 		    NTB_B2B_BAR_3, b2b_bar_num);
2292ed9652daSAlexander Motin 	} else
2293ed9652daSAlexander Motin 		xeon_set_sbar_base_and_limit(ntb, addr->bar4_addr64,
2294ed9652daSAlexander Motin 		    NTB_B2B_BAR_2, b2b_bar_num);
2295ed9652daSAlexander Motin 
2296ed9652daSAlexander Motin 	/* Zero incoming translation addrs */
2297ed9652daSAlexander Motin 	intel_ntb_reg_write(8, XEON_SBAR2XLAT_OFFSET, 0);
2298ed9652daSAlexander Motin 	intel_ntb_reg_write(8, XEON_SBAR4XLAT_OFFSET, 0);
2299ed9652daSAlexander Motin 
2300ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP)) {
2301ed9652daSAlexander Motin 		uint32_t xlat_reg, lmt_reg;
2302ed9652daSAlexander Motin 		enum ntb_bar bar_num;
2303ed9652daSAlexander Motin 
2304ed9652daSAlexander Motin 		/*
2305ed9652daSAlexander Motin 		 * We point the chosen MSIX MW BAR xlat to remote LAPIC for
2306ed9652daSAlexander Motin 		 * workaround
2307ed9652daSAlexander Motin 		 */
2308ed9652daSAlexander Motin 		bar_num = intel_ntb_mw_to_bar(ntb, ntb->msix_mw_idx);
2309ed9652daSAlexander Motin 		bar_get_xlat_params(ntb, bar_num, NULL, &xlat_reg, &lmt_reg);
2310ed9652daSAlexander Motin 		if (bar_is_64bit(ntb, bar_num)) {
2311ed9652daSAlexander Motin 			intel_ntb_reg_write(8, xlat_reg, MSI_INTEL_ADDR_BASE);
2312ed9652daSAlexander Motin 			ntb->msix_xlat = intel_ntb_reg_read(8, xlat_reg);
2313ed9652daSAlexander Motin 			intel_ntb_reg_write(8, lmt_reg, 0);
2314ed9652daSAlexander Motin 		} else {
2315ed9652daSAlexander Motin 			intel_ntb_reg_write(4, xlat_reg, MSI_INTEL_ADDR_BASE);
2316ed9652daSAlexander Motin 			ntb->msix_xlat = intel_ntb_reg_read(4, xlat_reg);
2317ed9652daSAlexander Motin 			intel_ntb_reg_write(4, lmt_reg, 0);
2318ed9652daSAlexander Motin 		}
2319ed9652daSAlexander Motin 
2320ed9652daSAlexander Motin 		ntb->peer_lapic_bar =  &ntb->bar_info[bar_num];
2321ed9652daSAlexander Motin 	}
2322ed9652daSAlexander Motin 	(void)intel_ntb_reg_read(8, XEON_SBAR2XLAT_OFFSET);
2323ed9652daSAlexander Motin 	(void)intel_ntb_reg_read(8, XEON_SBAR4XLAT_OFFSET);
2324ed9652daSAlexander Motin 
2325ed9652daSAlexander Motin 	/* Zero outgoing translation limits (whole bar size windows) */
2326ed9652daSAlexander Motin 	intel_ntb_reg_write(8, XEON_PBAR2LMT_OFFSET, 0);
2327ed9652daSAlexander Motin 	intel_ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, 0);
2328ed9652daSAlexander Motin 
2329ed9652daSAlexander Motin 	/* Set outgoing translation offsets */
2330ed9652daSAlexander Motin 	xeon_set_pbar_xlat(ntb, peer_addr->bar2_addr64, NTB_B2B_BAR_1);
2331ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SPLIT_BAR)) {
2332ed9652daSAlexander Motin 		xeon_set_pbar_xlat(ntb, peer_addr->bar4_addr32, NTB_B2B_BAR_2);
2333ed9652daSAlexander Motin 		xeon_set_pbar_xlat(ntb, peer_addr->bar5_addr32, NTB_B2B_BAR_3);
2334ed9652daSAlexander Motin 	} else
2335ed9652daSAlexander Motin 		xeon_set_pbar_xlat(ntb, peer_addr->bar4_addr64, NTB_B2B_BAR_2);
2336ed9652daSAlexander Motin 
2337ed9652daSAlexander Motin 	/* Set the translation offset for B2B registers */
2338ed9652daSAlexander Motin 	bar_addr = 0;
2339ed9652daSAlexander Motin 	if (b2b_bar_num == NTB_CONFIG_BAR)
2340ed9652daSAlexander Motin 		bar_addr = peer_addr->bar0_addr;
2341ed9652daSAlexander Motin 	else if (b2b_bar_num == NTB_B2B_BAR_1)
2342ed9652daSAlexander Motin 		bar_addr = peer_addr->bar2_addr64;
2343ed9652daSAlexander Motin 	else if (b2b_bar_num == NTB_B2B_BAR_2 && !HAS_FEATURE(ntb, NTB_SPLIT_BAR))
2344ed9652daSAlexander Motin 		bar_addr = peer_addr->bar4_addr64;
2345ed9652daSAlexander Motin 	else if (b2b_bar_num == NTB_B2B_BAR_2)
2346ed9652daSAlexander Motin 		bar_addr = peer_addr->bar4_addr32;
2347ed9652daSAlexander Motin 	else if (b2b_bar_num == NTB_B2B_BAR_3)
2348ed9652daSAlexander Motin 		bar_addr = peer_addr->bar5_addr32;
2349ed9652daSAlexander Motin 	else
2350ed9652daSAlexander Motin 		KASSERT(false, ("invalid bar"));
2351ed9652daSAlexander Motin 
2352ed9652daSAlexander Motin 	/*
2353ed9652daSAlexander Motin 	 * B2B_XLAT_OFFSET is a 64-bit register but can only be written 32 bits
2354ed9652daSAlexander Motin 	 * at a time.
2355ed9652daSAlexander Motin 	 */
2356ed9652daSAlexander Motin 	intel_ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL, bar_addr & 0xffffffff);
2357ed9652daSAlexander Motin 	intel_ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU, bar_addr >> 32);
2358ed9652daSAlexander Motin 	return (0);
2359ed9652daSAlexander Motin }
2360ed9652daSAlexander Motin 
23616660ef6eSMark Johnston static int
xeon_gen3_setup_b2b_mw(struct ntb_softc * ntb)23626660ef6eSMark Johnston xeon_gen3_setup_b2b_mw(struct ntb_softc *ntb)
23636660ef6eSMark Johnston {
23646660ef6eSMark Johnston 	uint64_t reg;
23656660ef6eSMark Johnston 	uint32_t embarsz, imbarsz;
23666660ef6eSMark Johnston 
23676660ef6eSMark Johnston 	/* IMBAR1SZ should be equal to EMBAR1SZ */
23686660ef6eSMark Johnston 	embarsz = pci_read_config(ntb->device, XEON_GEN3_INT_REG_EMBAR1SZ, 1);
23696660ef6eSMark Johnston 	imbarsz = pci_read_config(ntb->device, XEON_GEN3_INT_REG_IMBAR1SZ, 1);
23706660ef6eSMark Johnston 	if (embarsz != imbarsz) {
23716660ef6eSMark Johnston 		device_printf(ntb->device,
23726660ef6eSMark Johnston 		    "IMBAR1SZ (%u) should be equal to EMBAR1SZ (%u)\n",
23736660ef6eSMark Johnston 		    imbarsz, embarsz);
23746660ef6eSMark Johnston 		return (EIO);
23756660ef6eSMark Johnston 	}
23766660ef6eSMark Johnston 
23776660ef6eSMark Johnston 	/* IMBAR2SZ should be equal to EMBAR2SZ */
23786660ef6eSMark Johnston 	embarsz = pci_read_config(ntb->device, XEON_GEN3_INT_REG_EMBAR2SZ, 1);
23796660ef6eSMark Johnston 	imbarsz = pci_read_config(ntb->device, XEON_GEN3_INT_REG_IMBAR2SZ, 1);
23806660ef6eSMark Johnston 	if (embarsz != imbarsz) {
23816660ef6eSMark Johnston 		device_printf(ntb->device,
23826660ef6eSMark Johnston 		    "IMBAR2SZ (%u) should be equal to EMBAR2SZ (%u)\n",
23836660ef6eSMark Johnston 		    imbarsz, embarsz);
23846660ef6eSMark Johnston 		return (EIO);
23856660ef6eSMark Johnston 	}
23866660ef6eSMark Johnston 
23876660ef6eSMark Johnston 	/* Client will provide the incoming IMBAR1/2XBASE, zero it for now */
23886660ef6eSMark Johnston 	intel_ntb_reg_write(8, XEON_GEN3_REG_IMBAR1XBASE, 0);
23896660ef6eSMark Johnston 	intel_ntb_reg_write(8, XEON_GEN3_REG_IMBAR2XBASE, 0);
23906660ef6eSMark Johnston 
23916660ef6eSMark Johnston 	/*
2392e3cf7ebcSDavid Bright 	 * If the value in IMBAR1XLIMIT is set equal to the value in IMBAR1XBASE,
2393e3cf7ebcSDavid Bright 	 * the local memory window exposure from EMBAR1 is disabled.
2394e3cf7ebcSDavid Bright 	 * Note: It is needed to avoid malicious access.
23956660ef6eSMark Johnston 	 */
2396e3cf7ebcSDavid Bright 	intel_ntb_reg_write(8, XEON_GEN3_REG_IMBAR1XLIMIT, 0);
2397e3cf7ebcSDavid Bright 	intel_ntb_reg_write(8, XEON_GEN3_REG_IMBAR2XLIMIT, 0);
23986660ef6eSMark Johnston 
2399e3cf7ebcSDavid Bright 	/* Config outgoing translation limits (whole bar size windows) */
2400e3cf7ebcSDavid Bright 	reg = intel_ntb_reg_read(8, XEON_GEN3_REG_EMBAR1XBASE);
2401e3cf7ebcSDavid Bright 	reg += ntb->bar_info[NTB_B2B_BAR_1].size;
2402e3cf7ebcSDavid Bright 	intel_ntb_reg_write(8, XEON_GEN3_REG_EMBAR1XLIMIT, reg);
2403e3cf7ebcSDavid Bright 
2404e3cf7ebcSDavid Bright 	reg = intel_ntb_reg_read(8, XEON_GEN3_REG_EMBAR2XBASE);
2405e3cf7ebcSDavid Bright 	reg += ntb->bar_info[NTB_B2B_BAR_2].size;
2406e3cf7ebcSDavid Bright 	intel_ntb_reg_write(8, XEON_GEN3_REG_EMBAR2XLIMIT, reg);
24076660ef6eSMark Johnston 
24086660ef6eSMark Johnston 	return (0);
24096660ef6eSMark Johnston }
24106660ef6eSMark Johnston 
2411*70450ecdSAustin Zhang static int
xeon_gen4_setup_b2b_mw(struct ntb_softc * ntb)2412*70450ecdSAustin Zhang xeon_gen4_setup_b2b_mw(struct ntb_softc *ntb)
2413*70450ecdSAustin Zhang {
2414*70450ecdSAustin Zhang 	uint32_t embarsz, imbarsz;
2415*70450ecdSAustin Zhang 
2416*70450ecdSAustin Zhang 	/* IMBAR23SZ should be equal to EMBAR23SZ */
2417*70450ecdSAustin Zhang 	imbarsz = pci_read_config(ntb->device, XEON_GEN4_CFG_REG_IMBAR1SZ, 1);
2418*70450ecdSAustin Zhang 	embarsz = pci_read_config(ntb->device, XEON_GEN4_CFG_REG_EMBAR1SZ, 1);
2419*70450ecdSAustin Zhang 	if (embarsz != imbarsz) {
2420*70450ecdSAustin Zhang 		device_printf(ntb->device,
2421*70450ecdSAustin Zhang 		    "IMBAR23SZ (%u) should be equal to EMBAR23SZ (%u)\n",
2422*70450ecdSAustin Zhang 		    imbarsz, embarsz);
2423*70450ecdSAustin Zhang 		return (EIO);
2424*70450ecdSAustin Zhang 	}
2425*70450ecdSAustin Zhang 	/* IMBAR45SZ should be equal to EMBAR45SZ */
2426*70450ecdSAustin Zhang 	imbarsz = pci_read_config(ntb->device, XEON_GEN4_CFG_REG_IMBAR2SZ, 1);
2427*70450ecdSAustin Zhang 	embarsz = pci_read_config(ntb->device, XEON_GEN4_CFG_REG_EMBAR2SZ, 1);
2428*70450ecdSAustin Zhang 	if (embarsz != imbarsz) {
2429*70450ecdSAustin Zhang 		device_printf(ntb->device,
2430*70450ecdSAustin Zhang 		    "IMBAR45SZ (%u) should be equal to EMBAR45SZ (%u)\n",
2431*70450ecdSAustin Zhang 		    imbarsz, embarsz);
2432*70450ecdSAustin Zhang 		return (EIO);
2433*70450ecdSAustin Zhang 	}
2434*70450ecdSAustin Zhang 
2435*70450ecdSAustin Zhang 	/* Client will provide the incoming IMBARXBASE, zero it for now */
2436*70450ecdSAustin Zhang 	intel_ntb_reg_write(8, XEON_GEN4_REG_IMBAR1XBASE, 0);
2437*70450ecdSAustin Zhang 	intel_ntb_reg_write(8, XEON_GEN4_REG_IMBAR2XBASE, 0);
2438*70450ecdSAustin Zhang 
2439*70450ecdSAustin Zhang 	/*
2440*70450ecdSAustin Zhang 	 * If the value in IMBARXLIMIT is set equal to the value in IMBARXBASE,
2441*70450ecdSAustin Zhang 	 * the local memory window exposure from EMBAR is disabled.
2442*70450ecdSAustin Zhang 	 * Note: It is needed to avoid malicious access.
2443*70450ecdSAustin Zhang 	 */
2444*70450ecdSAustin Zhang 	intel_ntb_reg_write(8, XEON_GEN4_REG_IMBAR1XLIMIT, 0);
2445*70450ecdSAustin Zhang 	intel_ntb_reg_write(8, XEON_GEN4_REG_IMBAR2XLIMIT, 0);
2446*70450ecdSAustin Zhang 
2447*70450ecdSAustin Zhang 	/* EMBARXLIMIT & EMBARXBASE are gone for gen4, noop here */
2448*70450ecdSAustin Zhang 
2449*70450ecdSAustin Zhang 	return (0);
2450*70450ecdSAustin Zhang }
2451*70450ecdSAustin Zhang 
2452ed9652daSAlexander Motin static inline bool
_xeon_link_is_up(struct ntb_softc * ntb)2453ed9652daSAlexander Motin _xeon_link_is_up(struct ntb_softc *ntb)
2454ed9652daSAlexander Motin {
2455ed9652daSAlexander Motin 
2456ed9652daSAlexander Motin 	if (ntb->conn_type == NTB_CONN_TRANSPARENT)
2457ed9652daSAlexander Motin 		return (true);
2458ed9652daSAlexander Motin 	return ((ntb->lnk_sta & NTB_LINK_STATUS_ACTIVE) != 0);
2459ed9652daSAlexander Motin }
2460ed9652daSAlexander Motin 
2461ed9652daSAlexander Motin static inline bool
link_is_up(struct ntb_softc * ntb)2462ed9652daSAlexander Motin link_is_up(struct ntb_softc *ntb)
2463ed9652daSAlexander Motin {
2464ed9652daSAlexander Motin 
2465*70450ecdSAustin Zhang 	if (ntb->type == NTB_XEON_GEN1 ||
2466*70450ecdSAustin Zhang 	    ntb->type == NTB_XEON_GEN3 ||
2467*70450ecdSAustin Zhang 	    ntb->type == NTB_XEON_GEN4)
2468ed9652daSAlexander Motin 		return (_xeon_link_is_up(ntb) && (ntb->peer_msix_good ||
2469ed9652daSAlexander Motin 		    !HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP)));
2470ed9652daSAlexander Motin 
2471ed9652daSAlexander Motin 	KASSERT(ntb->type == NTB_ATOM, ("ntb type"));
2472ed9652daSAlexander Motin 	return ((ntb->ntb_ctl & ATOM_CNTL_LINK_DOWN) == 0);
2473ed9652daSAlexander Motin }
2474ed9652daSAlexander Motin 
2475ed9652daSAlexander Motin static inline bool
atom_link_is_err(struct ntb_softc * ntb)2476ed9652daSAlexander Motin atom_link_is_err(struct ntb_softc *ntb)
2477ed9652daSAlexander Motin {
2478ed9652daSAlexander Motin 	uint32_t status;
2479ed9652daSAlexander Motin 
2480ed9652daSAlexander Motin 	KASSERT(ntb->type == NTB_ATOM, ("ntb type"));
2481ed9652daSAlexander Motin 
2482ed9652daSAlexander Motin 	status = intel_ntb_reg_read(4, ATOM_LTSSMSTATEJMP_OFFSET);
2483ed9652daSAlexander Motin 	if ((status & ATOM_LTSSMSTATEJMP_FORCEDETECT) != 0)
2484ed9652daSAlexander Motin 		return (true);
2485ed9652daSAlexander Motin 
2486ed9652daSAlexander Motin 	status = intel_ntb_reg_read(4, ATOM_IBSTERRRCRVSTS0_OFFSET);
2487ed9652daSAlexander Motin 	return ((status & ATOM_IBIST_ERR_OFLOW) != 0);
2488ed9652daSAlexander Motin }
2489ed9652daSAlexander Motin 
2490ed9652daSAlexander Motin /* Atom does not have link status interrupt, poll on that platform */
2491ed9652daSAlexander Motin static void
atom_link_hb(void * arg)2492ed9652daSAlexander Motin atom_link_hb(void *arg)
2493ed9652daSAlexander Motin {
2494ed9652daSAlexander Motin 	struct ntb_softc *ntb = arg;
2495ed9652daSAlexander Motin 	sbintime_t timo, poll_ts;
2496ed9652daSAlexander Motin 
2497ed9652daSAlexander Motin 	timo = NTB_HB_TIMEOUT * hz;
2498ed9652daSAlexander Motin 	poll_ts = ntb->last_ts + timo;
2499ed9652daSAlexander Motin 
2500ed9652daSAlexander Motin 	/*
2501ed9652daSAlexander Motin 	 * Delay polling the link status if an interrupt was received, unless
2502ed9652daSAlexander Motin 	 * the cached link status says the link is down.
2503ed9652daSAlexander Motin 	 */
2504ed9652daSAlexander Motin 	if ((sbintime_t)ticks - poll_ts < 0 && link_is_up(ntb)) {
2505ed9652daSAlexander Motin 		timo = poll_ts - ticks;
2506ed9652daSAlexander Motin 		goto out;
2507ed9652daSAlexander Motin 	}
2508ed9652daSAlexander Motin 
2509ed9652daSAlexander Motin 	if (intel_ntb_poll_link(ntb))
2510ed9652daSAlexander Motin 		ntb_link_event(ntb->device);
2511ed9652daSAlexander Motin 
2512ed9652daSAlexander Motin 	if (!link_is_up(ntb) && atom_link_is_err(ntb)) {
2513ed9652daSAlexander Motin 		/* Link is down with error, proceed with recovery */
2514ed9652daSAlexander Motin 		callout_reset(&ntb->lr_timer, 0, recover_atom_link, ntb);
2515ed9652daSAlexander Motin 		return;
2516ed9652daSAlexander Motin 	}
2517ed9652daSAlexander Motin 
2518ed9652daSAlexander Motin out:
2519ed9652daSAlexander Motin 	callout_reset(&ntb->heartbeat_timer, timo, atom_link_hb, ntb);
2520ed9652daSAlexander Motin }
2521ed9652daSAlexander Motin 
2522ed9652daSAlexander Motin static void
atom_perform_link_restart(struct ntb_softc * ntb)2523ed9652daSAlexander Motin atom_perform_link_restart(struct ntb_softc *ntb)
2524ed9652daSAlexander Motin {
2525ed9652daSAlexander Motin 	uint32_t status;
2526ed9652daSAlexander Motin 
2527ed9652daSAlexander Motin 	/* Driver resets the NTB ModPhy lanes - magic! */
2528ed9652daSAlexander Motin 	intel_ntb_reg_write(1, ATOM_MODPHY_PCSREG6, 0xe0);
2529ed9652daSAlexander Motin 	intel_ntb_reg_write(1, ATOM_MODPHY_PCSREG4, 0x40);
2530ed9652daSAlexander Motin 	intel_ntb_reg_write(1, ATOM_MODPHY_PCSREG4, 0x60);
2531ed9652daSAlexander Motin 	intel_ntb_reg_write(1, ATOM_MODPHY_PCSREG6, 0x60);
2532ed9652daSAlexander Motin 
2533ed9652daSAlexander Motin 	/* Driver waits 100ms to allow the NTB ModPhy to settle */
2534ed9652daSAlexander Motin 	pause("ModPhy", hz / 10);
2535ed9652daSAlexander Motin 
2536ed9652daSAlexander Motin 	/* Clear AER Errors, write to clear */
2537ed9652daSAlexander Motin 	status = intel_ntb_reg_read(4, ATOM_ERRCORSTS_OFFSET);
2538ed9652daSAlexander Motin 	status &= PCIM_AER_COR_REPLAY_ROLLOVER;
2539ed9652daSAlexander Motin 	intel_ntb_reg_write(4, ATOM_ERRCORSTS_OFFSET, status);
2540ed9652daSAlexander Motin 
2541ed9652daSAlexander Motin 	/* Clear unexpected electrical idle event in LTSSM, write to clear */
2542ed9652daSAlexander Motin 	status = intel_ntb_reg_read(4, ATOM_LTSSMERRSTS0_OFFSET);
2543ed9652daSAlexander Motin 	status |= ATOM_LTSSMERRSTS0_UNEXPECTEDEI;
2544ed9652daSAlexander Motin 	intel_ntb_reg_write(4, ATOM_LTSSMERRSTS0_OFFSET, status);
2545ed9652daSAlexander Motin 
2546ed9652daSAlexander Motin 	/* Clear DeSkew Buffer error, write to clear */
2547ed9652daSAlexander Motin 	status = intel_ntb_reg_read(4, ATOM_DESKEWSTS_OFFSET);
2548ed9652daSAlexander Motin 	status |= ATOM_DESKEWSTS_DBERR;
2549ed9652daSAlexander Motin 	intel_ntb_reg_write(4, ATOM_DESKEWSTS_OFFSET, status);
2550ed9652daSAlexander Motin 
2551ed9652daSAlexander Motin 	status = intel_ntb_reg_read(4, ATOM_IBSTERRRCRVSTS0_OFFSET);
2552ed9652daSAlexander Motin 	status &= ATOM_IBIST_ERR_OFLOW;
2553ed9652daSAlexander Motin 	intel_ntb_reg_write(4, ATOM_IBSTERRRCRVSTS0_OFFSET, status);
2554ed9652daSAlexander Motin 
2555ed9652daSAlexander Motin 	/* Releases the NTB state machine to allow the link to retrain */
2556ed9652daSAlexander Motin 	status = intel_ntb_reg_read(4, ATOM_LTSSMSTATEJMP_OFFSET);
2557ed9652daSAlexander Motin 	status &= ~ATOM_LTSSMSTATEJMP_FORCEDETECT;
2558ed9652daSAlexander Motin 	intel_ntb_reg_write(4, ATOM_LTSSMSTATEJMP_OFFSET, status);
2559ed9652daSAlexander Motin }
2560ed9652daSAlexander Motin 
2561ed9652daSAlexander Motin static int
intel_ntb_port_number(device_t dev)25626ddecf2bSAlexander Motin intel_ntb_port_number(device_t dev)
25636ddecf2bSAlexander Motin {
25646ddecf2bSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
25656ddecf2bSAlexander Motin 
25666ddecf2bSAlexander Motin 	return (ntb->dev_type == NTB_DEV_USD ? 0 : 1);
25676ddecf2bSAlexander Motin }
25686ddecf2bSAlexander Motin 
25696ddecf2bSAlexander Motin static int
intel_ntb_peer_port_count(device_t dev)25706ddecf2bSAlexander Motin intel_ntb_peer_port_count(device_t dev)
25716ddecf2bSAlexander Motin {
25726ddecf2bSAlexander Motin 
25736ddecf2bSAlexander Motin 	return (1);
25746ddecf2bSAlexander Motin }
25756ddecf2bSAlexander Motin 
25766ddecf2bSAlexander Motin static int
intel_ntb_peer_port_number(device_t dev,int pidx)25776ddecf2bSAlexander Motin intel_ntb_peer_port_number(device_t dev, int pidx)
25786ddecf2bSAlexander Motin {
25796ddecf2bSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
25806ddecf2bSAlexander Motin 
25816ddecf2bSAlexander Motin 	if (pidx != 0)
25826ddecf2bSAlexander Motin 		return (-EINVAL);
25836ddecf2bSAlexander Motin 
25846ddecf2bSAlexander Motin 	return (ntb->dev_type == NTB_DEV_USD ? 1 : 0);
25856ddecf2bSAlexander Motin }
25866ddecf2bSAlexander Motin 
25876ddecf2bSAlexander Motin static int
intel_ntb_peer_port_idx(device_t dev,int port)25886ddecf2bSAlexander Motin intel_ntb_peer_port_idx(device_t dev, int port)
25896ddecf2bSAlexander Motin {
25906ddecf2bSAlexander Motin 	int peer_port;
25916ddecf2bSAlexander Motin 
25926ddecf2bSAlexander Motin 	peer_port = intel_ntb_peer_port_number(dev, 0);
25936ddecf2bSAlexander Motin 	if (peer_port == -EINVAL || port != peer_port)
25946ddecf2bSAlexander Motin 		return (-EINVAL);
25956ddecf2bSAlexander Motin 
25966ddecf2bSAlexander Motin 	return (0);
25976ddecf2bSAlexander Motin }
25986ddecf2bSAlexander Motin 
25996ddecf2bSAlexander Motin static int
intel_ntb4_link_enable(device_t dev,enum ntb_speed speed __unused,enum ntb_width width __unused)2600*70450ecdSAustin Zhang intel_ntb4_link_enable(device_t dev, enum ntb_speed speed __unused,
2601*70450ecdSAustin Zhang     enum ntb_width width __unused)
2602*70450ecdSAustin Zhang {
2603*70450ecdSAustin Zhang 	struct ntb_softc *ntb = device_get_softc(dev);
2604*70450ecdSAustin Zhang 	uint32_t cntl, ppd0, ltr;
2605*70450ecdSAustin Zhang 	uint16_t lnkctl;
2606*70450ecdSAustin Zhang 
2607*70450ecdSAustin Zhang 	if (!HAS_FEATURE(ntb, NTB_LTR_BAD)) {
2608*70450ecdSAustin Zhang 		/* Setup active snoop LTR values */
2609*70450ecdSAustin Zhang 		ltr = NTB_LTR_ACTIVE_REQMNT | NTB_LTR_ACTIVE_VAL | NTB_LTR_ACTIVE_LATSCALE;
2610*70450ecdSAustin Zhang 		/* Setup active non-snoop values */
2611*70450ecdSAustin Zhang 		ltr = (ltr << NTB_LTR_NS_SHIFT) | ltr;
2612*70450ecdSAustin Zhang 		intel_ntb_reg_write(4, XEON_GEN4_REG_EXT_LTR_ACTIVE, ltr);
2613*70450ecdSAustin Zhang 
2614*70450ecdSAustin Zhang 		/* Setup idle snoop LTR values */
2615*70450ecdSAustin Zhang 		ltr = NTB_LTR_IDLE_VAL | NTB_LTR_IDLE_LATSCALE | NTB_LTR_IDLE_REQMNT;
2616*70450ecdSAustin Zhang 		/* Setup idle non-snoop values */
2617*70450ecdSAustin Zhang 		ltr = (ltr << NTB_LTR_NS_SHIFT) | ltr;
2618*70450ecdSAustin Zhang 		intel_ntb_reg_write(4, XEON_GEN4_REG_EXT_LTR_IDLE, ltr);
2619*70450ecdSAustin Zhang 
2620*70450ecdSAustin Zhang 		/* setup PCIe LTR to active */
2621*70450ecdSAustin Zhang 		intel_ntb_reg_write(4, XEON_GEN4_REG_EXT_LTR_SWSEL, NTB_LTR_SWSEL_ACTIVE);
2622*70450ecdSAustin Zhang 	}
2623*70450ecdSAustin Zhang 
2624*70450ecdSAustin Zhang 	cntl = NTB_CTL_E2I_BAR23_SNOOP | NTB_CTL_I2E_BAR23_SNOOP;
2625*70450ecdSAustin Zhang 	cntl |= NTB_CTL_E2I_BAR45_SNOOP | NTB_CTL_I2E_BAR45_SNOOP;
2626*70450ecdSAustin Zhang 	intel_ntb_reg_write(4, ntb->reg->ntb_ctl, cntl);
2627*70450ecdSAustin Zhang 
2628*70450ecdSAustin Zhang 	lnkctl = intel_ntb_reg_read(2, XEON_GEN4_REG_LINK_CTRL);
2629*70450ecdSAustin Zhang 	lnkctl &= ~GEN4_LINK_CTRL_LINK_DISABLE;
2630*70450ecdSAustin Zhang 	intel_ntb_reg_write(2, XEON_GEN4_REG_LINK_CTRL, lnkctl);
2631*70450ecdSAustin Zhang 
2632*70450ecdSAustin Zhang 	/* start link training in PPD0 */
2633*70450ecdSAustin Zhang 	ppd0 = intel_ntb_reg_read(4, XEON_GEN4_REG_PPD0);
2634*70450ecdSAustin Zhang 	ppd0 |= GEN4_PPD_LINKTRN;
2635*70450ecdSAustin Zhang 	intel_ntb_reg_write(4, XEON_GEN4_REG_PPD0, ppd0);
2636*70450ecdSAustin Zhang 
2637*70450ecdSAustin Zhang 	/* make sure link training has started */
2638*70450ecdSAustin Zhang 	ppd0 = intel_ntb_reg_read(4, XEON_GEN4_REG_PPD0);
2639*70450ecdSAustin Zhang 	if (!(ppd0 & GEN4_PPD_LINKTRN))
2640*70450ecdSAustin Zhang 		intel_ntb_printf(2, "Link is not training\n");
2641*70450ecdSAustin Zhang 
2642*70450ecdSAustin Zhang 	return (0);
2643*70450ecdSAustin Zhang }
2644*70450ecdSAustin Zhang 
2645*70450ecdSAustin Zhang static int
intel_ntb_link_enable(device_t dev,enum ntb_speed speed __unused,enum ntb_width width __unused)2646ed9652daSAlexander Motin intel_ntb_link_enable(device_t dev, enum ntb_speed speed __unused,
2647ed9652daSAlexander Motin     enum ntb_width width __unused)
2648ed9652daSAlexander Motin {
2649ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
2650ed9652daSAlexander Motin 	uint32_t cntl;
2651ed9652daSAlexander Motin 
2652ed9652daSAlexander Motin 	intel_ntb_printf(2, "%s\n", __func__);
2653ed9652daSAlexander Motin 
2654*70450ecdSAustin Zhang 	if (ntb->type == NTB_XEON_GEN4)
2655*70450ecdSAustin Zhang 		return (intel_ntb4_link_enable(dev, speed, width));
2656*70450ecdSAustin Zhang 
2657ed9652daSAlexander Motin 	if (ntb->type == NTB_ATOM) {
2658ed9652daSAlexander Motin 		pci_write_config(ntb->device, NTB_PPD_OFFSET,
2659ed9652daSAlexander Motin 		    ntb->ppd | ATOM_PPD_INIT_LINK, 4);
2660ed9652daSAlexander Motin 		return (0);
2661ed9652daSAlexander Motin 	}
2662ed9652daSAlexander Motin 
2663ed9652daSAlexander Motin 	if (ntb->conn_type == NTB_CONN_TRANSPARENT) {
2664ed9652daSAlexander Motin 		ntb_link_event(dev);
2665ed9652daSAlexander Motin 		return (0);
2666ed9652daSAlexander Motin 	}
2667ed9652daSAlexander Motin 
2668ed9652daSAlexander Motin 	cntl = intel_ntb_reg_read(4, ntb->reg->ntb_ctl);
2669ed9652daSAlexander Motin 	cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK);
2670ed9652daSAlexander Motin 	cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP;
2671ed9652daSAlexander Motin 	cntl |= NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP;
2672ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SPLIT_BAR))
2673ed9652daSAlexander Motin 		cntl |= NTB_CNTL_P2S_BAR5_SNOOP | NTB_CNTL_S2P_BAR5_SNOOP;
2674ed9652daSAlexander Motin 	intel_ntb_reg_write(4, ntb->reg->ntb_ctl, cntl);
2675ed9652daSAlexander Motin 	return (0);
2676ed9652daSAlexander Motin }
2677ed9652daSAlexander Motin 
2678ed9652daSAlexander Motin static int
intel_ntb4_link_disable(device_t dev)2679*70450ecdSAustin Zhang intel_ntb4_link_disable(device_t dev)
2680*70450ecdSAustin Zhang {
2681*70450ecdSAustin Zhang 	struct ntb_softc *ntb = device_get_softc(dev);
2682*70450ecdSAustin Zhang 	uint32_t cntl;
2683*70450ecdSAustin Zhang 	uint16_t lnkctl;
2684*70450ecdSAustin Zhang 
2685*70450ecdSAustin Zhang 	/* clear the snoop bits */
2686*70450ecdSAustin Zhang 	cntl = intel_ntb_reg_read(4, ntb->reg->ntb_ctl);
2687*70450ecdSAustin Zhang 	cntl &= ~(NTB_CTL_E2I_BAR23_SNOOP | NTB_CTL_I2E_BAR23_SNOOP);
2688*70450ecdSAustin Zhang 	cntl &= ~(NTB_CTL_E2I_BAR45_SNOOP | NTB_CTL_I2E_BAR45_SNOOP);
2689*70450ecdSAustin Zhang 	intel_ntb_reg_write(4, ntb->reg->ntb_ctl, cntl);
2690*70450ecdSAustin Zhang 
2691*70450ecdSAustin Zhang 	lnkctl = intel_ntb_reg_read(2, XEON_GEN4_REG_LINK_CTRL);
2692*70450ecdSAustin Zhang 	lnkctl |= GEN4_LINK_CTRL_LINK_DISABLE;
2693*70450ecdSAustin Zhang 	intel_ntb_reg_write(2, XEON_GEN4_REG_LINK_CTRL, lnkctl);
2694*70450ecdSAustin Zhang 
2695*70450ecdSAustin Zhang 	/* set LTR to idle */
2696*70450ecdSAustin Zhang 	if (!HAS_FEATURE(ntb, NTB_LTR_BAD))
2697*70450ecdSAustin Zhang 		intel_ntb_reg_write(4, XEON_GEN4_REG_EXT_LTR_SWSEL, NTB_LTR_SWSEL_IDLE);
2698*70450ecdSAustin Zhang 
2699*70450ecdSAustin Zhang 	return (0);
2700*70450ecdSAustin Zhang }
2701*70450ecdSAustin Zhang 
2702*70450ecdSAustin Zhang static int
intel_ntb_link_disable(device_t dev)2703ed9652daSAlexander Motin intel_ntb_link_disable(device_t dev)
2704ed9652daSAlexander Motin {
2705ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
2706ed9652daSAlexander Motin 	uint32_t cntl;
2707ed9652daSAlexander Motin 
2708ed9652daSAlexander Motin 	intel_ntb_printf(2, "%s\n", __func__);
2709ed9652daSAlexander Motin 
2710*70450ecdSAustin Zhang 	if (ntb->type == NTB_XEON_GEN4)
2711*70450ecdSAustin Zhang 		return (intel_ntb4_link_disable(dev));
2712*70450ecdSAustin Zhang 
2713ed9652daSAlexander Motin 	if (ntb->conn_type == NTB_CONN_TRANSPARENT) {
2714ed9652daSAlexander Motin 		ntb_link_event(dev);
2715ed9652daSAlexander Motin 		return (0);
2716ed9652daSAlexander Motin 	}
2717ed9652daSAlexander Motin 
2718ed9652daSAlexander Motin 	cntl = intel_ntb_reg_read(4, ntb->reg->ntb_ctl);
2719ed9652daSAlexander Motin 	cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP);
2720ed9652daSAlexander Motin 	cntl &= ~(NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP);
2721ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SPLIT_BAR))
2722ed9652daSAlexander Motin 		cntl &= ~(NTB_CNTL_P2S_BAR5_SNOOP | NTB_CNTL_S2P_BAR5_SNOOP);
2723ed9652daSAlexander Motin 	cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK;
2724ed9652daSAlexander Motin 	intel_ntb_reg_write(4, ntb->reg->ntb_ctl, cntl);
2725ed9652daSAlexander Motin 	return (0);
2726ed9652daSAlexander Motin }
2727ed9652daSAlexander Motin 
2728ed9652daSAlexander Motin static bool
intel_ntb_link_enabled(device_t dev)2729ed9652daSAlexander Motin intel_ntb_link_enabled(device_t dev)
2730ed9652daSAlexander Motin {
2731ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
2732ed9652daSAlexander Motin 	uint32_t cntl;
2733ed9652daSAlexander Motin 
2734ed9652daSAlexander Motin 	if (ntb->type == NTB_ATOM) {
2735ed9652daSAlexander Motin 		cntl = pci_read_config(ntb->device, NTB_PPD_OFFSET, 4);
2736ed9652daSAlexander Motin 		return ((cntl & ATOM_PPD_INIT_LINK) != 0);
2737ed9652daSAlexander Motin 	}
2738ed9652daSAlexander Motin 
2739ed9652daSAlexander Motin 	if (ntb->conn_type == NTB_CONN_TRANSPARENT)
2740ed9652daSAlexander Motin 		return (true);
2741ed9652daSAlexander Motin 
2742*70450ecdSAustin Zhang 	if (ntb->type == NTB_XEON_GEN4) {
2743*70450ecdSAustin Zhang 		cntl = intel_ntb_reg_read(2, XEON_GEN4_REG_LINK_CTRL);
2744*70450ecdSAustin Zhang 		return ((cntl & GEN4_LINK_CTRL_LINK_DISABLE) == 0);
2745*70450ecdSAustin Zhang 	}
2746*70450ecdSAustin Zhang 
2747ed9652daSAlexander Motin 	cntl = intel_ntb_reg_read(4, ntb->reg->ntb_ctl);
2748ed9652daSAlexander Motin 	return ((cntl & NTB_CNTL_LINK_DISABLE) == 0);
2749ed9652daSAlexander Motin }
2750ed9652daSAlexander Motin 
2751ed9652daSAlexander Motin static void
recover_atom_link(void * arg)2752ed9652daSAlexander Motin recover_atom_link(void *arg)
2753ed9652daSAlexander Motin {
2754ed9652daSAlexander Motin 	struct ntb_softc *ntb = arg;
2755ed9652daSAlexander Motin 	unsigned speed, width, oldspeed, oldwidth;
2756ed9652daSAlexander Motin 	uint32_t status32;
2757ed9652daSAlexander Motin 
2758ed9652daSAlexander Motin 	atom_perform_link_restart(ntb);
2759ed9652daSAlexander Motin 
2760ed9652daSAlexander Motin 	/*
2761ed9652daSAlexander Motin 	 * There is a potential race between the 2 NTB devices recovering at
2762ed9652daSAlexander Motin 	 * the same time.  If the times are the same, the link will not recover
2763ed9652daSAlexander Motin 	 * and the driver will be stuck in this loop forever.  Add a random
2764ed9652daSAlexander Motin 	 * interval to the recovery time to prevent this race.
2765ed9652daSAlexander Motin 	 */
2766ed9652daSAlexander Motin 	status32 = arc4random() % ATOM_LINK_RECOVERY_TIME;
2767ed9652daSAlexander Motin 	pause("Link", (ATOM_LINK_RECOVERY_TIME + status32) * hz / 1000);
2768ed9652daSAlexander Motin 
2769ed9652daSAlexander Motin 	if (atom_link_is_err(ntb))
2770ed9652daSAlexander Motin 		goto retry;
2771ed9652daSAlexander Motin 
2772ed9652daSAlexander Motin 	status32 = intel_ntb_reg_read(4, ntb->reg->ntb_ctl);
2773ed9652daSAlexander Motin 	if ((status32 & ATOM_CNTL_LINK_DOWN) != 0)
2774ed9652daSAlexander Motin 		goto out;
2775ed9652daSAlexander Motin 
2776ed9652daSAlexander Motin 	status32 = intel_ntb_reg_read(4, ntb->reg->lnk_sta);
2777ed9652daSAlexander Motin 	width = NTB_LNK_STA_WIDTH(status32);
2778ed9652daSAlexander Motin 	speed = status32 & NTB_LINK_SPEED_MASK;
2779ed9652daSAlexander Motin 
2780ed9652daSAlexander Motin 	oldwidth = NTB_LNK_STA_WIDTH(ntb->lnk_sta);
2781ed9652daSAlexander Motin 	oldspeed = ntb->lnk_sta & NTB_LINK_SPEED_MASK;
2782ed9652daSAlexander Motin 	if (oldwidth != width || oldspeed != speed)
2783ed9652daSAlexander Motin 		goto retry;
2784ed9652daSAlexander Motin 
2785ed9652daSAlexander Motin out:
2786ed9652daSAlexander Motin 	callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz, atom_link_hb,
2787ed9652daSAlexander Motin 	    ntb);
2788ed9652daSAlexander Motin 	return;
2789ed9652daSAlexander Motin 
2790ed9652daSAlexander Motin retry:
2791ed9652daSAlexander Motin 	callout_reset(&ntb->lr_timer, NTB_HB_TIMEOUT * hz, recover_atom_link,
2792ed9652daSAlexander Motin 	    ntb);
2793ed9652daSAlexander Motin }
2794ed9652daSAlexander Motin 
2795ed9652daSAlexander Motin /*
2796ed9652daSAlexander Motin  * Polls the HW link status register(s); returns true if something has changed.
2797ed9652daSAlexander Motin  */
2798ed9652daSAlexander Motin static bool
intel_ntb_atom_poll_link(struct ntb_softc * ntb)2799*70450ecdSAustin Zhang intel_ntb_atom_poll_link(struct ntb_softc *ntb)
2800ed9652daSAlexander Motin {
2801ed9652daSAlexander Motin 	uint32_t ntb_cntl;
2802ed9652daSAlexander Motin 
2803ed9652daSAlexander Motin 	ntb_cntl = intel_ntb_reg_read(4, ntb->reg->ntb_ctl);
2804ed9652daSAlexander Motin 	if (ntb_cntl == ntb->ntb_ctl)
2805ed9652daSAlexander Motin 		return (false);
2806ed9652daSAlexander Motin 
2807ed9652daSAlexander Motin 	ntb->ntb_ctl = ntb_cntl;
2808ed9652daSAlexander Motin 	ntb->lnk_sta = intel_ntb_reg_read(4, ntb->reg->lnk_sta);
2809*70450ecdSAustin Zhang 	return (true);
2810*70450ecdSAustin Zhang }
2811*70450ecdSAustin Zhang 
2812*70450ecdSAustin Zhang static bool
intel_ntb_xeon_gen1_poll_link(struct ntb_softc * ntb)2813*70450ecdSAustin Zhang intel_ntb_xeon_gen1_poll_link(struct ntb_softc *ntb)
2814*70450ecdSAustin Zhang {
2815*70450ecdSAustin Zhang 	uint16_t reg_val;
2816*70450ecdSAustin Zhang 
28176660ef6eSMark Johnston 	if (ntb->type == NTB_XEON_GEN1)
28186660ef6eSMark Johnston 		db_iowrite_raw(ntb, ntb->self_reg->db_bell,
28196660ef6eSMark Johnston 			ntb->db_link_mask);
2820ed9652daSAlexander Motin 
2821ed9652daSAlexander Motin 	reg_val = pci_read_config(ntb->device, ntb->reg->lnk_sta, 2);
2822ed9652daSAlexander Motin 	if (reg_val == ntb->lnk_sta)
2823ed9652daSAlexander Motin 		return (false);
2824ed9652daSAlexander Motin 
2825ed9652daSAlexander Motin 	ntb->lnk_sta = reg_val;
2826ed9652daSAlexander Motin 
2827ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP)) {
2828ed9652daSAlexander Motin 		if (_xeon_link_is_up(ntb)) {
2829ed9652daSAlexander Motin 			if (!ntb->peer_msix_good) {
2830ed9652daSAlexander Motin 				callout_reset(&ntb->peer_msix_work, 0,
2831ed9652daSAlexander Motin 				    intel_ntb_exchange_msix, ntb);
2832ed9652daSAlexander Motin 				return (false);
2833ed9652daSAlexander Motin 			}
2834ed9652daSAlexander Motin 		} else {
2835ed9652daSAlexander Motin 			ntb->peer_msix_good = false;
2836ed9652daSAlexander Motin 			ntb->peer_msix_done = false;
2837ed9652daSAlexander Motin 		}
2838ed9652daSAlexander Motin 	}
2839ed9652daSAlexander Motin 	return (true);
2840ed9652daSAlexander Motin }
2841ed9652daSAlexander Motin 
2842*70450ecdSAustin Zhang static bool
intel_ntb_xeon_gen4_poll_link(struct ntb_softc * ntb)2843*70450ecdSAustin Zhang intel_ntb_xeon_gen4_poll_link(struct ntb_softc *ntb)
2844*70450ecdSAustin Zhang {
2845*70450ecdSAustin Zhang 	uint16_t reg_val;
2846*70450ecdSAustin Zhang 
2847*70450ecdSAustin Zhang 	/*
2848*70450ecdSAustin Zhang 	* We need to write to DLLSCS bit in the SLOTSTS before we
2849*70450ecdSAustin Zhang 	* can clear the hardware link interrupt on ICX NTB.
2850*70450ecdSAustin Zhang 	*/
2851*70450ecdSAustin Zhang 	intel_ntb_reg_write(2, XEON_GEN4_REG_SLOTSTS, GEN4_SLOTSTS_DLLSCS);
2852*70450ecdSAustin Zhang 	db_iowrite_raw(ntb, ntb->self_reg->db_clear, ntb->db_link_mask);
2853*70450ecdSAustin Zhang 
2854*70450ecdSAustin Zhang 	reg_val = intel_ntb_reg_read(2, ntb->reg->lnk_sta);
2855*70450ecdSAustin Zhang 	if (reg_val == ntb->lnk_sta)
2856*70450ecdSAustin Zhang 		return (false);
2857*70450ecdSAustin Zhang 
2858*70450ecdSAustin Zhang 	ntb->lnk_sta = reg_val;
2859*70450ecdSAustin Zhang 	return (true);
2860*70450ecdSAustin Zhang }
2861*70450ecdSAustin Zhang 
2862*70450ecdSAustin Zhang static bool
intel_ntb_poll_link(struct ntb_softc * ntb)2863*70450ecdSAustin Zhang intel_ntb_poll_link(struct ntb_softc *ntb)
2864*70450ecdSAustin Zhang {
2865*70450ecdSAustin Zhang 	bool val;
2866*70450ecdSAustin Zhang 
2867*70450ecdSAustin Zhang 	switch(ntb->type) {
2868*70450ecdSAustin Zhang 	case NTB_ATOM:
2869*70450ecdSAustin Zhang 		val = intel_ntb_atom_poll_link(ntb);
2870*70450ecdSAustin Zhang 		break;
2871*70450ecdSAustin Zhang 	case NTB_XEON_GEN4:
2872*70450ecdSAustin Zhang 		val = intel_ntb_xeon_gen4_poll_link(ntb);
2873*70450ecdSAustin Zhang 		break;
2874*70450ecdSAustin Zhang 	default:
2875*70450ecdSAustin Zhang 		val = intel_ntb_xeon_gen1_poll_link(ntb);
2876*70450ecdSAustin Zhang 		break;
2877*70450ecdSAustin Zhang 	}
2878*70450ecdSAustin Zhang 	return (val);
2879*70450ecdSAustin Zhang }
2880*70450ecdSAustin Zhang 
2881ed9652daSAlexander Motin static inline enum ntb_speed
intel_ntb_link_sta_speed(struct ntb_softc * ntb)2882ed9652daSAlexander Motin intel_ntb_link_sta_speed(struct ntb_softc *ntb)
2883ed9652daSAlexander Motin {
2884ed9652daSAlexander Motin 
2885ed9652daSAlexander Motin 	if (!link_is_up(ntb))
2886ed9652daSAlexander Motin 		return (NTB_SPEED_NONE);
2887ed9652daSAlexander Motin 	return (ntb->lnk_sta & NTB_LINK_SPEED_MASK);
2888ed9652daSAlexander Motin }
2889ed9652daSAlexander Motin 
2890ed9652daSAlexander Motin static inline enum ntb_width
intel_ntb_link_sta_width(struct ntb_softc * ntb)2891ed9652daSAlexander Motin intel_ntb_link_sta_width(struct ntb_softc *ntb)
2892ed9652daSAlexander Motin {
2893ed9652daSAlexander Motin 
2894ed9652daSAlexander Motin 	if (!link_is_up(ntb))
2895ed9652daSAlexander Motin 		return (NTB_WIDTH_NONE);
2896ed9652daSAlexander Motin 	return (NTB_LNK_STA_WIDTH(ntb->lnk_sta));
2897ed9652daSAlexander Motin }
2898ed9652daSAlexander Motin 
28997029da5cSPawel Biernacki SYSCTL_NODE(_hw_ntb, OID_AUTO, debug_info, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
2900ed9652daSAlexander Motin     "Driver state, statistics, and HW registers");
2901ed9652daSAlexander Motin 
2902ed9652daSAlexander Motin #define NTB_REGSZ_MASK	(3ul << 30)
2903ed9652daSAlexander Motin #define NTB_REG_64	(1ul << 30)
2904ed9652daSAlexander Motin #define NTB_REG_32	(2ul << 30)
2905ed9652daSAlexander Motin #define NTB_REG_16	(3ul << 30)
2906ed9652daSAlexander Motin #define NTB_REG_8	(0ul << 30)
2907ed9652daSAlexander Motin 
2908ed9652daSAlexander Motin #define NTB_DB_READ	(1ul << 29)
2909ed9652daSAlexander Motin #define NTB_PCI_REG	(1ul << 28)
2910ed9652daSAlexander Motin #define NTB_REGFLAGS_MASK	(NTB_REGSZ_MASK | NTB_DB_READ | NTB_PCI_REG)
2911ed9652daSAlexander Motin 
2912ed9652daSAlexander Motin static void
intel_ntb_sysctl_init(struct ntb_softc * ntb)2913ed9652daSAlexander Motin intel_ntb_sysctl_init(struct ntb_softc *ntb)
2914ed9652daSAlexander Motin {
2915ed9652daSAlexander Motin 	struct sysctl_oid_list *globals, *tree_par, *regpar, *statpar, *errpar;
2916ed9652daSAlexander Motin 	struct sysctl_ctx_list *ctx;
2917ed9652daSAlexander Motin 	struct sysctl_oid *tree, *tmptree;
2918ed9652daSAlexander Motin 
2919ed9652daSAlexander Motin 	ctx = device_get_sysctl_ctx(ntb->device);
2920ed9652daSAlexander Motin 	globals = SYSCTL_CHILDREN(device_get_sysctl_tree(ntb->device));
2921ed9652daSAlexander Motin 
2922ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, globals, OID_AUTO, "link_status",
292394feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_MPSAFE, ntb, 0,
2924ed9652daSAlexander Motin 	    sysctl_handle_link_status_human, "A",
2925ed9652daSAlexander Motin 	    "Link status (human readable)");
2926ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, globals, OID_AUTO, "active",
292794feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_MPSAFE, ntb, 0,
29287029da5cSPawel Biernacki 	    sysctl_handle_link_status, "IU",
29297029da5cSPawel Biernacki 	    "Link status (1=active, 0=inactive)");
2930ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, globals, OID_AUTO, "admin_up",
293194feb1f1SAlexander Motin 	    CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, ntb, 0,
29327029da5cSPawel Biernacki 	    sysctl_handle_link_admin, "IU",
29337029da5cSPawel Biernacki 	    "Set/get interface status (1=UP, 0=DOWN)");
2934ed9652daSAlexander Motin 
2935ed9652daSAlexander Motin 	tree = SYSCTL_ADD_NODE(ctx, globals, OID_AUTO, "debug_info",
29367029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
29377029da5cSPawel Biernacki 	    "Driver state, statistics, and HW registers");
2938ed9652daSAlexander Motin 	tree_par = SYSCTL_CHILDREN(tree);
2939ed9652daSAlexander Motin 
2940ed9652daSAlexander Motin 	SYSCTL_ADD_UINT(ctx, tree_par, OID_AUTO, "conn_type", CTLFLAG_RD,
2941ed9652daSAlexander Motin 	    &ntb->conn_type, 0, "0 - Transparent; 1 - B2B; 2 - Root Port");
2942ed9652daSAlexander Motin 	SYSCTL_ADD_UINT(ctx, tree_par, OID_AUTO, "dev_type", CTLFLAG_RD,
2943ed9652daSAlexander Motin 	    &ntb->dev_type, 0, "0 - USD; 1 - DSD");
2944ed9652daSAlexander Motin 	SYSCTL_ADD_UINT(ctx, tree_par, OID_AUTO, "ppd", CTLFLAG_RD,
2945ed9652daSAlexander Motin 	    &ntb->ppd, 0, "Raw PPD register (cached)");
2946ed9652daSAlexander Motin 
2947ed9652daSAlexander Motin 	if (ntb->b2b_mw_idx != B2B_MW_DISABLED) {
2948ed9652daSAlexander Motin 		SYSCTL_ADD_U8(ctx, tree_par, OID_AUTO, "b2b_idx", CTLFLAG_RD,
2949ed9652daSAlexander Motin 		    &ntb->b2b_mw_idx, 0,
2950ed9652daSAlexander Motin 		    "Index of the MW used for B2B remote register access");
2951ed9652daSAlexander Motin 		SYSCTL_ADD_UQUAD(ctx, tree_par, OID_AUTO, "b2b_off",
2952ed9652daSAlexander Motin 		    CTLFLAG_RD, &ntb->b2b_off,
2953ed9652daSAlexander Motin 		    "If non-zero, offset of B2B register region in shared MW");
2954ed9652daSAlexander Motin 	}
2955ed9652daSAlexander Motin 
2956ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, tree_par, OID_AUTO, "features",
295794feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_MPSAFE, ntb, 0,
29587029da5cSPawel Biernacki 	    sysctl_handle_features, "A", "Features/errata of this NTB device");
2959ed9652daSAlexander Motin 
2960ed9652daSAlexander Motin 	SYSCTL_ADD_UINT(ctx, tree_par, OID_AUTO, "ntb_ctl", CTLFLAG_RD,
2961ed9652daSAlexander Motin 	    __DEVOLATILE(uint32_t *, &ntb->ntb_ctl), 0,
2962ed9652daSAlexander Motin 	    "NTB CTL register (cached)");
2963ed9652daSAlexander Motin 	SYSCTL_ADD_UINT(ctx, tree_par, OID_AUTO, "lnk_sta", CTLFLAG_RD,
2964ed9652daSAlexander Motin 	    __DEVOLATILE(uint32_t *, &ntb->lnk_sta), 0,
2965ed9652daSAlexander Motin 	    "LNK STA register (cached)");
2966ed9652daSAlexander Motin 
2967ed9652daSAlexander Motin 	SYSCTL_ADD_U8(ctx, tree_par, OID_AUTO, "mw_count", CTLFLAG_RD,
2968ed9652daSAlexander Motin 	    &ntb->mw_count, 0, "MW count");
2969ed9652daSAlexander Motin 	SYSCTL_ADD_U8(ctx, tree_par, OID_AUTO, "spad_count", CTLFLAG_RD,
2970ed9652daSAlexander Motin 	    &ntb->spad_count, 0, "Scratchpad count");
2971ed9652daSAlexander Motin 	SYSCTL_ADD_U8(ctx, tree_par, OID_AUTO, "db_count", CTLFLAG_RD,
2972ed9652daSAlexander Motin 	    &ntb->db_count, 0, "Doorbell count");
2973ed9652daSAlexander Motin 	SYSCTL_ADD_U8(ctx, tree_par, OID_AUTO, "db_vec_count", CTLFLAG_RD,
2974ed9652daSAlexander Motin 	    &ntb->db_vec_count, 0, "Doorbell vector count");
2975ed9652daSAlexander Motin 	SYSCTL_ADD_U8(ctx, tree_par, OID_AUTO, "db_vec_shift", CTLFLAG_RD,
2976ed9652daSAlexander Motin 	    &ntb->db_vec_shift, 0, "Doorbell vector shift");
2977ed9652daSAlexander Motin 
2978ed9652daSAlexander Motin 	SYSCTL_ADD_UQUAD(ctx, tree_par, OID_AUTO, "db_valid_mask", CTLFLAG_RD,
2979ed9652daSAlexander Motin 	    &ntb->db_valid_mask, "Doorbell valid mask");
2980ed9652daSAlexander Motin 	SYSCTL_ADD_UQUAD(ctx, tree_par, OID_AUTO, "db_link_mask", CTLFLAG_RD,
2981ed9652daSAlexander Motin 	    &ntb->db_link_mask, "Doorbell link mask");
2982ed9652daSAlexander Motin 	SYSCTL_ADD_UQUAD(ctx, tree_par, OID_AUTO, "db_mask", CTLFLAG_RD,
2983ed9652daSAlexander Motin 	    &ntb->db_mask, "Doorbell mask (cached)");
2984ed9652daSAlexander Motin 
2985ed9652daSAlexander Motin 	tmptree = SYSCTL_ADD_NODE(ctx, tree_par, OID_AUTO, "registers",
29867029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
29877029da5cSPawel Biernacki 	    "Raw HW registers (big-endian)");
2988ed9652daSAlexander Motin 	regpar = SYSCTL_CHILDREN(tmptree);
2989ed9652daSAlexander Motin 
2990ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "ntbcntl",
299194feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
29927029da5cSPawel Biernacki 	    NTB_REG_32 | ntb->reg->ntb_ctl, sysctl_handle_register, "IU",
2993ed9652daSAlexander Motin 	    "NTB Control register");
2994ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "lnkcap",
299594feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
29967029da5cSPawel Biernacki 	    NTB_REG_32 | 0x19c, sysctl_handle_register, "IU",
2997ed9652daSAlexander Motin 	    "NTB Link Capabilities");
2998ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "lnkcon",
299994feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
30007029da5cSPawel Biernacki 	    NTB_REG_32 | 0x1a0, sysctl_handle_register, "IU",
3001ed9652daSAlexander Motin 	    "NTB Link Control register");
3002ed9652daSAlexander Motin 
3003ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "db_mask",
300494feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3005ed9652daSAlexander Motin 	    NTB_REG_64 | NTB_DB_READ | ntb->self_reg->db_mask,
3006ed9652daSAlexander Motin 	    sysctl_handle_register, "QU", "Doorbell mask register");
3007ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "db_bell",
300894feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3009ed9652daSAlexander Motin 	    NTB_REG_64 | NTB_DB_READ | ntb->self_reg->db_bell,
3010ed9652daSAlexander Motin 	    sysctl_handle_register, "QU", "Doorbell register");
3011ed9652daSAlexander Motin 
3012ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "incoming_xlat23",
301394feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3014ed9652daSAlexander Motin 	    NTB_REG_64 | ntb->xlat_reg->bar2_xlat,
3015ed9652daSAlexander Motin 	    sysctl_handle_register, "QU", "Incoming XLAT23 register");
3016ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SPLIT_BAR)) {
3017ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "incoming_xlat4",
301894feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3019ed9652daSAlexander Motin 		    NTB_REG_32 | ntb->xlat_reg->bar4_xlat,
3020ed9652daSAlexander Motin 		    sysctl_handle_register, "IU", "Incoming XLAT4 register");
3021ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "incoming_xlat5",
302294feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3023ed9652daSAlexander Motin 		    NTB_REG_32 | ntb->xlat_reg->bar5_xlat,
3024ed9652daSAlexander Motin 		    sysctl_handle_register, "IU", "Incoming XLAT5 register");
3025ed9652daSAlexander Motin 	} else {
3026ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "incoming_xlat45",
302794feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3028ed9652daSAlexander Motin 		    NTB_REG_64 | ntb->xlat_reg->bar4_xlat,
3029ed9652daSAlexander Motin 		    sysctl_handle_register, "QU", "Incoming XLAT45 register");
3030ed9652daSAlexander Motin 	}
3031ed9652daSAlexander Motin 
3032ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "incoming_lmt23",
303394feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3034ed9652daSAlexander Motin 	    NTB_REG_64 | ntb->xlat_reg->bar2_limit,
3035ed9652daSAlexander Motin 	    sysctl_handle_register, "QU", "Incoming LMT23 register");
3036ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SPLIT_BAR)) {
3037ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "incoming_lmt4",
303894feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3039ed9652daSAlexander Motin 		    NTB_REG_32 | ntb->xlat_reg->bar4_limit,
3040ed9652daSAlexander Motin 		    sysctl_handle_register, "IU", "Incoming LMT4 register");
3041ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "incoming_lmt5",
304294feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3043ed9652daSAlexander Motin 		    NTB_REG_32 | ntb->xlat_reg->bar5_limit,
3044ed9652daSAlexander Motin 		    sysctl_handle_register, "IU", "Incoming LMT5 register");
3045ed9652daSAlexander Motin 	} else {
3046ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "incoming_lmt45",
304794feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3048ed9652daSAlexander Motin 		    NTB_REG_64 | ntb->xlat_reg->bar4_limit,
3049ed9652daSAlexander Motin 		    sysctl_handle_register, "QU", "Incoming LMT45 register");
3050ed9652daSAlexander Motin 	}
3051ed9652daSAlexander Motin 
3052ed9652daSAlexander Motin 	if (ntb->type == NTB_ATOM)
3053ed9652daSAlexander Motin 		return;
3054ed9652daSAlexander Motin 
3055ed9652daSAlexander Motin 	tmptree = SYSCTL_ADD_NODE(ctx, regpar, OID_AUTO, "xeon_stats",
30567029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Xeon HW statistics");
3057ed9652daSAlexander Motin 	statpar = SYSCTL_CHILDREN(tmptree);
3058ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, statpar, OID_AUTO, "upstream_mem_miss",
305994feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3060ed9652daSAlexander Motin 	    NTB_REG_16 | XEON_USMEMMISS_OFFSET,
3061ed9652daSAlexander Motin 	    sysctl_handle_register, "SU", "Upstream Memory Miss");
3062ed9652daSAlexander Motin 
3063ed9652daSAlexander Motin 	tmptree = SYSCTL_ADD_NODE(ctx, regpar, OID_AUTO, "xeon_hw_err",
30647029da5cSPawel Biernacki 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Xeon HW errors");
3065ed9652daSAlexander Motin 	errpar = SYSCTL_CHILDREN(tmptree);
3066ed9652daSAlexander Motin 
3067ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "ppd",
306894feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3069ed9652daSAlexander Motin 	    NTB_REG_8 | NTB_PCI_REG | NTB_PPD_OFFSET,
3070ed9652daSAlexander Motin 	    sysctl_handle_register, "CU", "PPD");
3071ed9652daSAlexander Motin 
3072ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "pbar23_sz",
307394feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3074ed9652daSAlexander Motin 	    NTB_REG_8 | NTB_PCI_REG | XEON_PBAR23SZ_OFFSET,
3075ed9652daSAlexander Motin 	    sysctl_handle_register, "CU", "PBAR23 SZ (log2)");
3076ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "pbar4_sz",
307794feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3078ed9652daSAlexander Motin 	    NTB_REG_8 | NTB_PCI_REG | XEON_PBAR4SZ_OFFSET,
3079ed9652daSAlexander Motin 	    sysctl_handle_register, "CU", "PBAR4 SZ (log2)");
3080ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "pbar5_sz",
308194feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3082ed9652daSAlexander Motin 	    NTB_REG_8 | NTB_PCI_REG | XEON_PBAR5SZ_OFFSET,
3083ed9652daSAlexander Motin 	    sysctl_handle_register, "CU", "PBAR5 SZ (log2)");
3084ed9652daSAlexander Motin 
3085ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "sbar23_sz",
308694feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3087ed9652daSAlexander Motin 	    NTB_REG_8 | NTB_PCI_REG | XEON_SBAR23SZ_OFFSET,
3088ed9652daSAlexander Motin 	    sysctl_handle_register, "CU", "SBAR23 SZ (log2)");
3089ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "sbar4_sz",
309094feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3091ed9652daSAlexander Motin 	    NTB_REG_8 | NTB_PCI_REG | XEON_SBAR4SZ_OFFSET,
3092ed9652daSAlexander Motin 	    sysctl_handle_register, "CU", "SBAR4 SZ (log2)");
3093ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "sbar5_sz",
309494feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3095ed9652daSAlexander Motin 	    NTB_REG_8 | NTB_PCI_REG | XEON_SBAR5SZ_OFFSET,
3096ed9652daSAlexander Motin 	    sysctl_handle_register, "CU", "SBAR5 SZ (log2)");
3097ed9652daSAlexander Motin 
3098ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "devsts",
309994feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3100ed9652daSAlexander Motin 	    NTB_REG_16 | NTB_PCI_REG | XEON_DEVSTS_OFFSET,
3101ed9652daSAlexander Motin 	    sysctl_handle_register, "SU", "DEVSTS");
3102ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "lnksts",
310394feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3104ed9652daSAlexander Motin 	    NTB_REG_16 | NTB_PCI_REG | XEON_LINK_STATUS_OFFSET,
3105ed9652daSAlexander Motin 	    sysctl_handle_register, "SU", "LNKSTS");
3106ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "slnksts",
310794feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3108ed9652daSAlexander Motin 	    NTB_REG_16 | NTB_PCI_REG | XEON_SLINK_STATUS_OFFSET,
3109ed9652daSAlexander Motin 	    sysctl_handle_register, "SU", "SLNKSTS");
3110ed9652daSAlexander Motin 
3111ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, errpar, OID_AUTO, "uncerrsts",
311294feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3113ed9652daSAlexander Motin 	    NTB_REG_32 | NTB_PCI_REG | XEON_UNCERRSTS_OFFSET,
3114ed9652daSAlexander Motin 	    sysctl_handle_register, "IU", "UNCERRSTS");
3115ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, errpar, OID_AUTO, "corerrsts",
311694feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3117ed9652daSAlexander Motin 	    NTB_REG_32 | NTB_PCI_REG | XEON_CORERRSTS_OFFSET,
3118ed9652daSAlexander Motin 	    sysctl_handle_register, "IU", "CORERRSTS");
3119ed9652daSAlexander Motin 
3120ed9652daSAlexander Motin 	if (ntb->conn_type != NTB_CONN_B2B)
3121ed9652daSAlexander Motin 		return;
3122ed9652daSAlexander Motin 
312362ba8e84SAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "outgoing_xlat01l",
312494feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
312562ba8e84SAlexander Motin 	    NTB_REG_32 | XEON_B2B_XLAT_OFFSETL,
312662ba8e84SAlexander Motin 	    sysctl_handle_register, "IU", "Outgoing XLAT0L register");
312762ba8e84SAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "outgoing_xlat01u",
312894feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
312962ba8e84SAlexander Motin 	    NTB_REG_32 | XEON_B2B_XLAT_OFFSETU,
313062ba8e84SAlexander Motin 	    sysctl_handle_register, "IU", "Outgoing XLAT0U register");
3131ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "outgoing_xlat23",
313294feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3133ed9652daSAlexander Motin 	    NTB_REG_64 | ntb->bar_info[NTB_B2B_BAR_1].pbarxlat_off,
3134ed9652daSAlexander Motin 	    sysctl_handle_register, "QU", "Outgoing XLAT23 register");
3135ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SPLIT_BAR)) {
3136ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "outgoing_xlat4",
313794feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3138ed9652daSAlexander Motin 		    NTB_REG_32 | ntb->bar_info[NTB_B2B_BAR_2].pbarxlat_off,
3139ed9652daSAlexander Motin 		    sysctl_handle_register, "IU", "Outgoing XLAT4 register");
3140ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "outgoing_xlat5",
314194feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3142ed9652daSAlexander Motin 		    NTB_REG_32 | ntb->bar_info[NTB_B2B_BAR_3].pbarxlat_off,
3143ed9652daSAlexander Motin 		    sysctl_handle_register, "IU", "Outgoing XLAT5 register");
3144ed9652daSAlexander Motin 	} else {
3145ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "outgoing_xlat45",
314694feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3147ed9652daSAlexander Motin 		    NTB_REG_64 | ntb->bar_info[NTB_B2B_BAR_2].pbarxlat_off,
3148ed9652daSAlexander Motin 		    sysctl_handle_register, "QU", "Outgoing XLAT45 register");
3149ed9652daSAlexander Motin 	}
3150ed9652daSAlexander Motin 
3151ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "outgoing_lmt23",
315294feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3153ed9652daSAlexander Motin 	    NTB_REG_64 | XEON_PBAR2LMT_OFFSET,
3154ed9652daSAlexander Motin 	    sysctl_handle_register, "QU", "Outgoing LMT23 register");
3155ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SPLIT_BAR)) {
3156ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "outgoing_lmt4",
315794feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3158ed9652daSAlexander Motin 		    NTB_REG_32 | XEON_PBAR4LMT_OFFSET,
3159ed9652daSAlexander Motin 		    sysctl_handle_register, "IU", "Outgoing LMT4 register");
3160ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "outgoing_lmt5",
316194feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3162ed9652daSAlexander Motin 		    NTB_REG_32 | XEON_PBAR5LMT_OFFSET,
3163ed9652daSAlexander Motin 		    sysctl_handle_register, "IU", "Outgoing LMT5 register");
3164ed9652daSAlexander Motin 	} else {
3165ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "outgoing_lmt45",
316694feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3167ed9652daSAlexander Motin 		    NTB_REG_64 | XEON_PBAR4LMT_OFFSET,
3168ed9652daSAlexander Motin 		    sysctl_handle_register, "QU", "Outgoing LMT45 register");
3169ed9652daSAlexander Motin 	}
3170ed9652daSAlexander Motin 
3171ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "sbar01_base",
317294feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3173ed9652daSAlexander Motin 	    NTB_REG_64 | ntb->xlat_reg->bar0_base,
3174ed9652daSAlexander Motin 	    sysctl_handle_register, "QU", "Secondary BAR01 base register");
3175ed9652daSAlexander Motin 	SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "sbar23_base",
317694feb1f1SAlexander Motin 	    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3177ed9652daSAlexander Motin 	    NTB_REG_64 | ntb->xlat_reg->bar2_base,
3178ed9652daSAlexander Motin 	    sysctl_handle_register, "QU", "Secondary BAR23 base register");
3179ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SPLIT_BAR)) {
3180ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "sbar4_base",
318194feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3182ed9652daSAlexander Motin 		    NTB_REG_32 | ntb->xlat_reg->bar4_base,
3183ed9652daSAlexander Motin 		    sysctl_handle_register, "IU",
3184ed9652daSAlexander Motin 		    "Secondary BAR4 base register");
3185ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "sbar5_base",
318694feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3187ed9652daSAlexander Motin 		    NTB_REG_32 | ntb->xlat_reg->bar5_base,
3188ed9652daSAlexander Motin 		    sysctl_handle_register, "IU",
3189ed9652daSAlexander Motin 		    "Secondary BAR5 base register");
3190ed9652daSAlexander Motin 	} else {
3191ed9652daSAlexander Motin 		SYSCTL_ADD_PROC(ctx, regpar, OID_AUTO, "sbar45_base",
319294feb1f1SAlexander Motin 		    CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, ntb,
3193ed9652daSAlexander Motin 		    NTB_REG_64 | ntb->xlat_reg->bar4_base,
3194ed9652daSAlexander Motin 		    sysctl_handle_register, "QU",
3195ed9652daSAlexander Motin 		    "Secondary BAR45 base register");
3196ed9652daSAlexander Motin 	}
3197ed9652daSAlexander Motin }
3198ed9652daSAlexander Motin 
3199ed9652daSAlexander Motin static int
sysctl_handle_features(SYSCTL_HANDLER_ARGS)3200ed9652daSAlexander Motin sysctl_handle_features(SYSCTL_HANDLER_ARGS)
3201ed9652daSAlexander Motin {
3202ed9652daSAlexander Motin 	struct ntb_softc *ntb = arg1;
3203ed9652daSAlexander Motin 	struct sbuf sb;
3204ed9652daSAlexander Motin 	int error;
3205ed9652daSAlexander Motin 
3206ed9652daSAlexander Motin 	sbuf_new_for_sysctl(&sb, NULL, 256, req);
3207ed9652daSAlexander Motin 
3208ed9652daSAlexander Motin 	sbuf_printf(&sb, "%b", ntb->features, NTB_FEATURES_STR);
3209ed9652daSAlexander Motin 	error = sbuf_finish(&sb);
3210ed9652daSAlexander Motin 	sbuf_delete(&sb);
3211ed9652daSAlexander Motin 
3212ed9652daSAlexander Motin 	if (error || !req->newptr)
3213ed9652daSAlexander Motin 		return (error);
3214ed9652daSAlexander Motin 	return (EINVAL);
3215ed9652daSAlexander Motin }
3216ed9652daSAlexander Motin 
3217ed9652daSAlexander Motin static int
sysctl_handle_link_admin(SYSCTL_HANDLER_ARGS)3218ed9652daSAlexander Motin sysctl_handle_link_admin(SYSCTL_HANDLER_ARGS)
3219ed9652daSAlexander Motin {
3220ed9652daSAlexander Motin 	struct ntb_softc *ntb = arg1;
3221ed9652daSAlexander Motin 	unsigned old, new;
3222ed9652daSAlexander Motin 	int error;
3223ed9652daSAlexander Motin 
3224ed9652daSAlexander Motin 	old = intel_ntb_link_enabled(ntb->device);
3225ed9652daSAlexander Motin 
3226ed9652daSAlexander Motin 	error = SYSCTL_OUT(req, &old, sizeof(old));
3227ed9652daSAlexander Motin 	if (error != 0 || req->newptr == NULL)
3228ed9652daSAlexander Motin 		return (error);
3229ed9652daSAlexander Motin 
3230ed9652daSAlexander Motin 	error = SYSCTL_IN(req, &new, sizeof(new));
3231ed9652daSAlexander Motin 	if (error != 0)
3232ed9652daSAlexander Motin 		return (error);
3233ed9652daSAlexander Motin 
3234ed9652daSAlexander Motin 	intel_ntb_printf(0, "Admin set interface state to '%sabled'\n",
3235ed9652daSAlexander Motin 	    (new != 0)? "en" : "dis");
3236ed9652daSAlexander Motin 
3237ed9652daSAlexander Motin 	if (new != 0)
3238ed9652daSAlexander Motin 		error = intel_ntb_link_enable(ntb->device, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
3239ed9652daSAlexander Motin 	else
3240ed9652daSAlexander Motin 		error = intel_ntb_link_disable(ntb->device);
3241ed9652daSAlexander Motin 	return (error);
3242ed9652daSAlexander Motin }
3243ed9652daSAlexander Motin 
3244ed9652daSAlexander Motin static int
sysctl_handle_link_status_human(SYSCTL_HANDLER_ARGS)3245ed9652daSAlexander Motin sysctl_handle_link_status_human(SYSCTL_HANDLER_ARGS)
3246ed9652daSAlexander Motin {
3247ed9652daSAlexander Motin 	struct ntb_softc *ntb = arg1;
3248ed9652daSAlexander Motin 	struct sbuf sb;
3249ed9652daSAlexander Motin 	enum ntb_speed speed;
3250ed9652daSAlexander Motin 	enum ntb_width width;
3251ed9652daSAlexander Motin 	int error;
3252ed9652daSAlexander Motin 
3253ed9652daSAlexander Motin 	sbuf_new_for_sysctl(&sb, NULL, 32, req);
3254ed9652daSAlexander Motin 
3255ed9652daSAlexander Motin 	if (intel_ntb_link_is_up(ntb->device, &speed, &width))
3256ed9652daSAlexander Motin 		sbuf_printf(&sb, "up / PCIe Gen %u / Width x%u",
3257ed9652daSAlexander Motin 		    (unsigned)speed, (unsigned)width);
3258ed9652daSAlexander Motin 	else
3259ed9652daSAlexander Motin 		sbuf_printf(&sb, "down");
3260ed9652daSAlexander Motin 
3261ed9652daSAlexander Motin 	error = sbuf_finish(&sb);
3262ed9652daSAlexander Motin 	sbuf_delete(&sb);
3263ed9652daSAlexander Motin 
3264ed9652daSAlexander Motin 	if (error || !req->newptr)
3265ed9652daSAlexander Motin 		return (error);
3266ed9652daSAlexander Motin 	return (EINVAL);
3267ed9652daSAlexander Motin }
3268ed9652daSAlexander Motin 
3269ed9652daSAlexander Motin static int
sysctl_handle_link_status(SYSCTL_HANDLER_ARGS)3270ed9652daSAlexander Motin sysctl_handle_link_status(SYSCTL_HANDLER_ARGS)
3271ed9652daSAlexander Motin {
3272ed9652daSAlexander Motin 	struct ntb_softc *ntb = arg1;
3273ed9652daSAlexander Motin 	unsigned res;
3274ed9652daSAlexander Motin 	int error;
3275ed9652daSAlexander Motin 
3276ed9652daSAlexander Motin 	res = intel_ntb_link_is_up(ntb->device, NULL, NULL);
3277ed9652daSAlexander Motin 
3278ed9652daSAlexander Motin 	error = SYSCTL_OUT(req, &res, sizeof(res));
3279ed9652daSAlexander Motin 	if (error || !req->newptr)
3280ed9652daSAlexander Motin 		return (error);
3281ed9652daSAlexander Motin 	return (EINVAL);
3282ed9652daSAlexander Motin }
3283ed9652daSAlexander Motin 
3284ed9652daSAlexander Motin static int
sysctl_handle_register(SYSCTL_HANDLER_ARGS)3285ed9652daSAlexander Motin sysctl_handle_register(SYSCTL_HANDLER_ARGS)
3286ed9652daSAlexander Motin {
3287ed9652daSAlexander Motin 	struct ntb_softc *ntb;
3288ed9652daSAlexander Motin 	const void *outp;
3289ed9652daSAlexander Motin 	uintptr_t sz;
3290ed9652daSAlexander Motin 	uint64_t umv;
3291ed9652daSAlexander Motin 	char be[sizeof(umv)];
3292ed9652daSAlexander Motin 	size_t outsz;
3293ed9652daSAlexander Motin 	uint32_t reg;
3294ed9652daSAlexander Motin 	bool db, pci;
3295ed9652daSAlexander Motin 	int error;
3296ed9652daSAlexander Motin 
3297ed9652daSAlexander Motin 	ntb = arg1;
3298ed9652daSAlexander Motin 	reg = arg2 & ~NTB_REGFLAGS_MASK;
3299ed9652daSAlexander Motin 	sz = arg2 & NTB_REGSZ_MASK;
3300ed9652daSAlexander Motin 	db = (arg2 & NTB_DB_READ) != 0;
3301ed9652daSAlexander Motin 	pci = (arg2 & NTB_PCI_REG) != 0;
3302ed9652daSAlexander Motin 
3303ed9652daSAlexander Motin 	KASSERT(!(db && pci), ("bogus"));
3304ed9652daSAlexander Motin 
3305ed9652daSAlexander Motin 	if (db) {
3306ed9652daSAlexander Motin 		KASSERT(sz == NTB_REG_64, ("bogus"));
3307ed9652daSAlexander Motin 		umv = db_ioread(ntb, reg);
3308ed9652daSAlexander Motin 		outsz = sizeof(uint64_t);
3309ed9652daSAlexander Motin 	} else {
3310ed9652daSAlexander Motin 		switch (sz) {
3311ed9652daSAlexander Motin 		case NTB_REG_64:
3312ed9652daSAlexander Motin 			if (pci)
3313ed9652daSAlexander Motin 				umv = pci_read_config(ntb->device, reg, 8);
3314ed9652daSAlexander Motin 			else
3315ed9652daSAlexander Motin 				umv = intel_ntb_reg_read(8, reg);
3316ed9652daSAlexander Motin 			outsz = sizeof(uint64_t);
3317ed9652daSAlexander Motin 			break;
3318ed9652daSAlexander Motin 		case NTB_REG_32:
3319ed9652daSAlexander Motin 			if (pci)
3320ed9652daSAlexander Motin 				umv = pci_read_config(ntb->device, reg, 4);
3321ed9652daSAlexander Motin 			else
3322ed9652daSAlexander Motin 				umv = intel_ntb_reg_read(4, reg);
3323ed9652daSAlexander Motin 			outsz = sizeof(uint32_t);
3324ed9652daSAlexander Motin 			break;
3325ed9652daSAlexander Motin 		case NTB_REG_16:
3326ed9652daSAlexander Motin 			if (pci)
3327ed9652daSAlexander Motin 				umv = pci_read_config(ntb->device, reg, 2);
3328ed9652daSAlexander Motin 			else
3329ed9652daSAlexander Motin 				umv = intel_ntb_reg_read(2, reg);
3330ed9652daSAlexander Motin 			outsz = sizeof(uint16_t);
3331ed9652daSAlexander Motin 			break;
3332ed9652daSAlexander Motin 		case NTB_REG_8:
3333ed9652daSAlexander Motin 			if (pci)
3334ed9652daSAlexander Motin 				umv = pci_read_config(ntb->device, reg, 1);
3335ed9652daSAlexander Motin 			else
3336ed9652daSAlexander Motin 				umv = intel_ntb_reg_read(1, reg);
3337ed9652daSAlexander Motin 			outsz = sizeof(uint8_t);
3338ed9652daSAlexander Motin 			break;
3339ed9652daSAlexander Motin 		default:
3340ed9652daSAlexander Motin 			panic("bogus");
3341ed9652daSAlexander Motin 			break;
3342ed9652daSAlexander Motin 		}
3343ed9652daSAlexander Motin 	}
3344ed9652daSAlexander Motin 
3345ed9652daSAlexander Motin 	/* Encode bigendian so that sysctl -x is legible. */
3346ed9652daSAlexander Motin 	be64enc(be, umv);
3347ed9652daSAlexander Motin 	outp = ((char *)be) + sizeof(umv) - outsz;
3348ed9652daSAlexander Motin 
3349ed9652daSAlexander Motin 	error = SYSCTL_OUT(req, outp, outsz);
3350ed9652daSAlexander Motin 	if (error || !req->newptr)
3351ed9652daSAlexander Motin 		return (error);
3352ed9652daSAlexander Motin 	return (EINVAL);
3353ed9652daSAlexander Motin }
3354ed9652daSAlexander Motin 
3355ed9652daSAlexander Motin static unsigned
intel_ntb_user_mw_to_idx(struct ntb_softc * ntb,unsigned uidx)3356ed9652daSAlexander Motin intel_ntb_user_mw_to_idx(struct ntb_softc *ntb, unsigned uidx)
3357ed9652daSAlexander Motin {
3358ed9652daSAlexander Motin 
3359ed9652daSAlexander Motin 	if ((ntb->b2b_mw_idx != B2B_MW_DISABLED && ntb->b2b_off == 0 &&
3360ed9652daSAlexander Motin 	    uidx >= ntb->b2b_mw_idx) ||
3361ed9652daSAlexander Motin 	    (ntb->msix_mw_idx != B2B_MW_DISABLED && uidx >= ntb->msix_mw_idx))
3362ed9652daSAlexander Motin 		uidx++;
3363ed9652daSAlexander Motin 	if ((ntb->b2b_mw_idx != B2B_MW_DISABLED && ntb->b2b_off == 0 &&
3364ed9652daSAlexander Motin 	    uidx >= ntb->b2b_mw_idx) &&
3365ed9652daSAlexander Motin 	    (ntb->msix_mw_idx != B2B_MW_DISABLED && uidx >= ntb->msix_mw_idx))
3366ed9652daSAlexander Motin 		uidx++;
3367ed9652daSAlexander Motin 	return (uidx);
3368ed9652daSAlexander Motin }
3369ed9652daSAlexander Motin 
3370ed9652daSAlexander Motin #ifndef EARLY_AP_STARTUP
3371ed9652daSAlexander Motin static int msix_ready;
3372ed9652daSAlexander Motin 
3373ed9652daSAlexander Motin static void
intel_ntb_msix_ready(void * arg __unused)3374ed9652daSAlexander Motin intel_ntb_msix_ready(void *arg __unused)
3375ed9652daSAlexander Motin {
3376ed9652daSAlexander Motin 
3377ed9652daSAlexander Motin 	msix_ready = 1;
3378ed9652daSAlexander Motin }
3379ed9652daSAlexander Motin SYSINIT(intel_ntb_msix_ready, SI_SUB_SMP, SI_ORDER_ANY,
3380ed9652daSAlexander Motin     intel_ntb_msix_ready, NULL);
3381ed9652daSAlexander Motin #endif
3382ed9652daSAlexander Motin 
3383ed9652daSAlexander Motin static void
intel_ntb_exchange_msix(void * ctx)3384ed9652daSAlexander Motin intel_ntb_exchange_msix(void *ctx)
3385ed9652daSAlexander Motin {
3386ed9652daSAlexander Motin 	struct ntb_softc *ntb;
3387ed9652daSAlexander Motin 	uint32_t val;
3388ed9652daSAlexander Motin 	unsigned i;
3389ed9652daSAlexander Motin 
3390ed9652daSAlexander Motin 	ntb = ctx;
3391ed9652daSAlexander Motin 
3392ed9652daSAlexander Motin 	if (ntb->peer_msix_good)
3393ed9652daSAlexander Motin 		goto msix_good;
3394ed9652daSAlexander Motin 	if (ntb->peer_msix_done)
3395ed9652daSAlexander Motin 		goto msix_done;
3396ed9652daSAlexander Motin 
3397ed9652daSAlexander Motin #ifndef EARLY_AP_STARTUP
3398ed9652daSAlexander Motin 	/* Block MSIX negotiation until SMP started and IRQ reshuffled. */
3399ed9652daSAlexander Motin 	if (!msix_ready)
3400ed9652daSAlexander Motin 		goto reschedule;
3401ed9652daSAlexander Motin #endif
3402ed9652daSAlexander Motin 
3403ed9652daSAlexander Motin 	intel_ntb_get_msix_info(ntb);
3404ed9652daSAlexander Motin 	for (i = 0; i < XEON_NONLINK_DB_MSIX_BITS; i++) {
3405ed9652daSAlexander Motin 		intel_ntb_peer_spad_write(ntb->device, NTB_MSIX_DATA0 + i,
3406ed9652daSAlexander Motin 		    ntb->msix_data[i].nmd_data);
3407ed9652daSAlexander Motin 		intel_ntb_peer_spad_write(ntb->device, NTB_MSIX_OFS0 + i,
3408ed9652daSAlexander Motin 		    ntb->msix_data[i].nmd_ofs - ntb->msix_xlat);
3409ed9652daSAlexander Motin 	}
3410ed9652daSAlexander Motin 	intel_ntb_peer_spad_write(ntb->device, NTB_MSIX_GUARD, NTB_MSIX_VER_GUARD);
3411ed9652daSAlexander Motin 
3412ed9652daSAlexander Motin 	intel_ntb_spad_read(ntb->device, NTB_MSIX_GUARD, &val);
3413ed9652daSAlexander Motin 	if (val != NTB_MSIX_VER_GUARD)
3414ed9652daSAlexander Motin 		goto reschedule;
3415ed9652daSAlexander Motin 
3416ed9652daSAlexander Motin 	for (i = 0; i < XEON_NONLINK_DB_MSIX_BITS; i++) {
3417ed9652daSAlexander Motin 		intel_ntb_spad_read(ntb->device, NTB_MSIX_DATA0 + i, &val);
3418ed9652daSAlexander Motin 		intel_ntb_printf(2, "remote MSIX data(%u): 0x%x\n", i, val);
3419ed9652daSAlexander Motin 		ntb->peer_msix_data[i].nmd_data = val;
3420ed9652daSAlexander Motin 		intel_ntb_spad_read(ntb->device, NTB_MSIX_OFS0 + i, &val);
3421ed9652daSAlexander Motin 		intel_ntb_printf(2, "remote MSIX addr(%u): 0x%x\n", i, val);
3422ed9652daSAlexander Motin 		ntb->peer_msix_data[i].nmd_ofs = val;
3423ed9652daSAlexander Motin 	}
3424ed9652daSAlexander Motin 
3425ed9652daSAlexander Motin 	ntb->peer_msix_done = true;
3426ed9652daSAlexander Motin 
3427ed9652daSAlexander Motin msix_done:
3428ed9652daSAlexander Motin 	intel_ntb_peer_spad_write(ntb->device, NTB_MSIX_DONE, NTB_MSIX_RECEIVED);
3429ed9652daSAlexander Motin 	intel_ntb_spad_read(ntb->device, NTB_MSIX_DONE, &val);
3430ed9652daSAlexander Motin 	if (val != NTB_MSIX_RECEIVED)
3431ed9652daSAlexander Motin 		goto reschedule;
3432ed9652daSAlexander Motin 
3433ed9652daSAlexander Motin 	intel_ntb_spad_clear(ntb->device);
3434ed9652daSAlexander Motin 	ntb->peer_msix_good = true;
3435ed9652daSAlexander Motin 	/* Give peer time to see our NTB_MSIX_RECEIVED. */
3436ed9652daSAlexander Motin 	goto reschedule;
3437ed9652daSAlexander Motin 
3438ed9652daSAlexander Motin msix_good:
3439ed9652daSAlexander Motin 	intel_ntb_poll_link(ntb);
3440ed9652daSAlexander Motin 	ntb_link_event(ntb->device);
3441ed9652daSAlexander Motin 	return;
3442ed9652daSAlexander Motin 
3443ed9652daSAlexander Motin reschedule:
3444ed9652daSAlexander Motin 	ntb->lnk_sta = pci_read_config(ntb->device, ntb->reg->lnk_sta, 2);
3445ed9652daSAlexander Motin 	if (_xeon_link_is_up(ntb)) {
3446ed9652daSAlexander Motin 		callout_reset(&ntb->peer_msix_work,
34473dcd9d78SAlexander Motin 		    hz * (ntb->peer_msix_good ? 2 : 1) / 10,
3448ed9652daSAlexander Motin 		    intel_ntb_exchange_msix, ntb);
3449ed9652daSAlexander Motin 	} else
3450ed9652daSAlexander Motin 		intel_ntb_spad_clear(ntb->device);
3451ed9652daSAlexander Motin }
3452ed9652daSAlexander Motin 
3453ed9652daSAlexander Motin /*
3454ed9652daSAlexander Motin  * Public API to the rest of the OS
3455ed9652daSAlexander Motin  */
3456ed9652daSAlexander Motin 
3457ed9652daSAlexander Motin static uint8_t
intel_ntb_spad_count(device_t dev)3458ed9652daSAlexander Motin intel_ntb_spad_count(device_t dev)
3459ed9652daSAlexander Motin {
3460ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3461ed9652daSAlexander Motin 
3462ed9652daSAlexander Motin 	return (ntb->spad_count);
3463ed9652daSAlexander Motin }
3464ed9652daSAlexander Motin 
3465ed9652daSAlexander Motin static uint8_t
intel_ntb_mw_count(device_t dev)3466ed9652daSAlexander Motin intel_ntb_mw_count(device_t dev)
3467ed9652daSAlexander Motin {
3468ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3469ed9652daSAlexander Motin 	uint8_t res;
3470ed9652daSAlexander Motin 
3471ed9652daSAlexander Motin 	res = ntb->mw_count;
3472ed9652daSAlexander Motin 	if (ntb->b2b_mw_idx != B2B_MW_DISABLED && ntb->b2b_off == 0)
3473ed9652daSAlexander Motin 		res--;
3474ed9652daSAlexander Motin 	if (ntb->msix_mw_idx != B2B_MW_DISABLED)
3475ed9652daSAlexander Motin 		res--;
3476ed9652daSAlexander Motin 	return (res);
3477ed9652daSAlexander Motin }
3478ed9652daSAlexander Motin 
3479ed9652daSAlexander Motin static int
intel_ntb_spad_write(device_t dev,unsigned int idx,uint32_t val)3480ed9652daSAlexander Motin intel_ntb_spad_write(device_t dev, unsigned int idx, uint32_t val)
3481ed9652daSAlexander Motin {
3482ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3483ed9652daSAlexander Motin 
3484ed9652daSAlexander Motin 	if (idx >= ntb->spad_count)
3485ed9652daSAlexander Motin 		return (EINVAL);
3486ed9652daSAlexander Motin 
3487ed9652daSAlexander Motin 	intel_ntb_reg_write(4, ntb->self_reg->spad + idx * 4, val);
3488ed9652daSAlexander Motin 
3489ed9652daSAlexander Motin 	return (0);
3490ed9652daSAlexander Motin }
3491ed9652daSAlexander Motin 
3492ed9652daSAlexander Motin /*
3493ed9652daSAlexander Motin  * Zeros the local scratchpad.
3494ed9652daSAlexander Motin  */
3495ed9652daSAlexander Motin static void
intel_ntb_spad_clear(device_t dev)3496ed9652daSAlexander Motin intel_ntb_spad_clear(device_t dev)
3497ed9652daSAlexander Motin {
3498ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3499ed9652daSAlexander Motin 	unsigned i;
3500ed9652daSAlexander Motin 
3501ed9652daSAlexander Motin 	for (i = 0; i < ntb->spad_count; i++)
3502ed9652daSAlexander Motin 		intel_ntb_spad_write(dev, i, 0);
3503ed9652daSAlexander Motin }
3504ed9652daSAlexander Motin 
3505ed9652daSAlexander Motin static int
intel_ntb_spad_read(device_t dev,unsigned int idx,uint32_t * val)3506ed9652daSAlexander Motin intel_ntb_spad_read(device_t dev, unsigned int idx, uint32_t *val)
3507ed9652daSAlexander Motin {
3508ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3509ed9652daSAlexander Motin 
3510ed9652daSAlexander Motin 	if (idx >= ntb->spad_count)
3511ed9652daSAlexander Motin 		return (EINVAL);
3512ed9652daSAlexander Motin 
3513ed9652daSAlexander Motin 	*val = intel_ntb_reg_read(4, ntb->self_reg->spad + idx * 4);
3514ed9652daSAlexander Motin 
3515ed9652daSAlexander Motin 	return (0);
3516ed9652daSAlexander Motin }
3517ed9652daSAlexander Motin 
3518ed9652daSAlexander Motin static int
intel_ntb_peer_spad_write(device_t dev,unsigned int idx,uint32_t val)3519ed9652daSAlexander Motin intel_ntb_peer_spad_write(device_t dev, unsigned int idx, uint32_t val)
3520ed9652daSAlexander Motin {
3521ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3522ed9652daSAlexander Motin 
3523ed9652daSAlexander Motin 	if (idx >= ntb->spad_count)
3524ed9652daSAlexander Motin 		return (EINVAL);
3525ed9652daSAlexander Motin 
3526ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SDOORBELL_LOCKUP))
3527ed9652daSAlexander Motin 		intel_ntb_mw_write(4, XEON_SPAD_OFFSET + idx * 4, val);
3528ed9652daSAlexander Motin 	else
3529ed9652daSAlexander Motin 		intel_ntb_reg_write(4, ntb->peer_reg->spad + idx * 4, val);
3530ed9652daSAlexander Motin 
3531ed9652daSAlexander Motin 	return (0);
3532ed9652daSAlexander Motin }
3533ed9652daSAlexander Motin 
3534ed9652daSAlexander Motin static int
intel_ntb_peer_spad_read(device_t dev,unsigned int idx,uint32_t * val)3535ed9652daSAlexander Motin intel_ntb_peer_spad_read(device_t dev, unsigned int idx, uint32_t *val)
3536ed9652daSAlexander Motin {
3537ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3538ed9652daSAlexander Motin 
3539ed9652daSAlexander Motin 	if (idx >= ntb->spad_count)
3540ed9652daSAlexander Motin 		return (EINVAL);
3541ed9652daSAlexander Motin 
3542ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SDOORBELL_LOCKUP))
3543ed9652daSAlexander Motin 		*val = intel_ntb_mw_read(4, XEON_SPAD_OFFSET + idx * 4);
3544ed9652daSAlexander Motin 	else
3545ed9652daSAlexander Motin 		*val = intel_ntb_reg_read(4, ntb->peer_reg->spad + idx * 4);
3546ed9652daSAlexander Motin 
3547ed9652daSAlexander Motin 	return (0);
3548ed9652daSAlexander Motin }
3549ed9652daSAlexander Motin 
3550ed9652daSAlexander Motin static int
intel_ntb_mw_get_range(device_t dev,unsigned mw_idx,vm_paddr_t * base,caddr_t * vbase,size_t * size,size_t * align,size_t * align_size,bus_addr_t * plimit)3551ed9652daSAlexander Motin intel_ntb_mw_get_range(device_t dev, unsigned mw_idx, vm_paddr_t *base,
3552ed9652daSAlexander Motin     caddr_t *vbase, size_t *size, size_t *align, size_t *align_size,
3553ed9652daSAlexander Motin     bus_addr_t *plimit)
3554ed9652daSAlexander Motin {
3555ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3556ed9652daSAlexander Motin 	struct ntb_pci_bar_info *bar;
3557ed9652daSAlexander Motin 	bus_addr_t limit;
3558ed9652daSAlexander Motin 	size_t bar_b2b_off;
3559ed9652daSAlexander Motin 	enum ntb_bar bar_num;
3560ed9652daSAlexander Motin 
3561ed9652daSAlexander Motin 	if (mw_idx >= intel_ntb_mw_count(dev))
3562ed9652daSAlexander Motin 		return (EINVAL);
3563ed9652daSAlexander Motin 	mw_idx = intel_ntb_user_mw_to_idx(ntb, mw_idx);
3564ed9652daSAlexander Motin 
3565ed9652daSAlexander Motin 	bar_num = intel_ntb_mw_to_bar(ntb, mw_idx);
3566ed9652daSAlexander Motin 	bar = &ntb->bar_info[bar_num];
3567ed9652daSAlexander Motin 	bar_b2b_off = 0;
3568ed9652daSAlexander Motin 	if (mw_idx == ntb->b2b_mw_idx) {
3569ed9652daSAlexander Motin 		KASSERT(ntb->b2b_off != 0,
3570ed9652daSAlexander Motin 		    ("user shouldn't get non-shared b2b mw"));
3571ed9652daSAlexander Motin 		bar_b2b_off = ntb->b2b_off;
3572ed9652daSAlexander Motin 	}
3573ed9652daSAlexander Motin 
3574ed9652daSAlexander Motin 	if (bar_is_64bit(ntb, bar_num))
3575ed9652daSAlexander Motin 		limit = BUS_SPACE_MAXADDR;
3576ed9652daSAlexander Motin 	else
3577ed9652daSAlexander Motin 		limit = BUS_SPACE_MAXADDR_32BIT;
3578ed9652daSAlexander Motin 
3579ed9652daSAlexander Motin 	if (base != NULL)
3580ed9652daSAlexander Motin 		*base = bar->pbase + bar_b2b_off;
3581ed9652daSAlexander Motin 	if (vbase != NULL)
3582ed9652daSAlexander Motin 		*vbase = bar->vbase + bar_b2b_off;
3583ed9652daSAlexander Motin 	if (size != NULL)
3584ed9652daSAlexander Motin 		*size = bar->size - bar_b2b_off;
3585ed9652daSAlexander Motin 	if (align != NULL)
3586ed9652daSAlexander Motin 		*align = bar->size;
3587ed9652daSAlexander Motin 	if (align_size != NULL)
3588ed9652daSAlexander Motin 		*align_size = 1;
3589ed9652daSAlexander Motin 	if (plimit != NULL)
3590ed9652daSAlexander Motin 		*plimit = limit;
3591ed9652daSAlexander Motin 	return (0);
3592ed9652daSAlexander Motin }
3593ed9652daSAlexander Motin 
3594ed9652daSAlexander Motin static int
intel_ntb_mw_set_trans(device_t dev,unsigned idx,bus_addr_t addr,size_t size)3595ed9652daSAlexander Motin intel_ntb_mw_set_trans(device_t dev, unsigned idx, bus_addr_t addr, size_t size)
3596ed9652daSAlexander Motin {
3597ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3598ed9652daSAlexander Motin 	struct ntb_pci_bar_info *bar;
3599ed9652daSAlexander Motin 	uint64_t base, limit, reg_val;
3600ed9652daSAlexander Motin 	size_t bar_size, mw_size;
3601ed9652daSAlexander Motin 	uint32_t base_reg, xlat_reg, limit_reg;
3602ed9652daSAlexander Motin 	enum ntb_bar bar_num;
3603ed9652daSAlexander Motin 
3604ed9652daSAlexander Motin 	if (idx >= intel_ntb_mw_count(dev))
3605ed9652daSAlexander Motin 		return (EINVAL);
3606ed9652daSAlexander Motin 	idx = intel_ntb_user_mw_to_idx(ntb, idx);
3607ed9652daSAlexander Motin 
3608ed9652daSAlexander Motin 	bar_num = intel_ntb_mw_to_bar(ntb, idx);
3609ed9652daSAlexander Motin 	bar = &ntb->bar_info[bar_num];
3610ed9652daSAlexander Motin 
3611ed9652daSAlexander Motin 	bar_size = bar->size;
3612ed9652daSAlexander Motin 	if (idx == ntb->b2b_mw_idx)
3613ed9652daSAlexander Motin 		mw_size = bar_size - ntb->b2b_off;
3614ed9652daSAlexander Motin 	else
3615ed9652daSAlexander Motin 		mw_size = bar_size;
3616ed9652daSAlexander Motin 
3617ed9652daSAlexander Motin 	/* Hardware requires that addr is aligned to bar size */
3618ed9652daSAlexander Motin 	if ((addr & (bar_size - 1)) != 0)
3619ed9652daSAlexander Motin 		return (EINVAL);
3620ed9652daSAlexander Motin 
3621ed9652daSAlexander Motin 	if (size > mw_size)
3622ed9652daSAlexander Motin 		return (EINVAL);
3623ed9652daSAlexander Motin 
3624ed9652daSAlexander Motin 	bar_get_xlat_params(ntb, bar_num, &base_reg, &xlat_reg, &limit_reg);
3625ed9652daSAlexander Motin 
3626ed9652daSAlexander Motin 	limit = 0;
3627ed9652daSAlexander Motin 	if (bar_is_64bit(ntb, bar_num)) {
3628*70450ecdSAustin Zhang 		if (ntb->type == NTB_XEON_GEN3 || ntb->type == NTB_XEON_GEN4)
3629e3cf7ebcSDavid Bright 			base = addr;
3630e3cf7ebcSDavid Bright 		else
3631ed9652daSAlexander Motin 			base = intel_ntb_reg_read(8, base_reg) & BAR_HIGH_MASK;
3632ed9652daSAlexander Motin 
3633ed9652daSAlexander Motin 		if (limit_reg != 0 && size != mw_size)
3634ed9652daSAlexander Motin 			limit = base + size;
36356660ef6eSMark Johnston 		else
36366660ef6eSMark Johnston 			limit = base + mw_size;
3637ed9652daSAlexander Motin 
3638ed9652daSAlexander Motin 		/* Set and verify translation address */
3639ed9652daSAlexander Motin 		intel_ntb_reg_write(8, xlat_reg, addr);
3640ed9652daSAlexander Motin 		reg_val = intel_ntb_reg_read(8, xlat_reg) & BAR_HIGH_MASK;
3641ed9652daSAlexander Motin 		if (reg_val != addr) {
3642ed9652daSAlexander Motin 			intel_ntb_reg_write(8, xlat_reg, 0);
3643ed9652daSAlexander Motin 			return (EIO);
3644ed9652daSAlexander Motin 		}
3645ed9652daSAlexander Motin 
3646ed9652daSAlexander Motin 		/* Set and verify the limit */
3647ed9652daSAlexander Motin 		intel_ntb_reg_write(8, limit_reg, limit);
3648ed9652daSAlexander Motin 		reg_val = intel_ntb_reg_read(8, limit_reg) & BAR_HIGH_MASK;
3649ed9652daSAlexander Motin 		if (reg_val != limit) {
3650ed9652daSAlexander Motin 			intel_ntb_reg_write(8, limit_reg, base);
3651ed9652daSAlexander Motin 			intel_ntb_reg_write(8, xlat_reg, 0);
3652ed9652daSAlexander Motin 			return (EIO);
3653ed9652daSAlexander Motin 		}
3654ed9652daSAlexander Motin 	} else {
3655ed9652daSAlexander Motin 		/* Configure 32-bit (split) BAR MW */
3656*70450ecdSAustin Zhang 		if (ntb->type == NTB_XEON_GEN3 || ntb->type == NTB_XEON_GEN4)
36576660ef6eSMark Johnston 			return (EIO);
3658ed9652daSAlexander Motin 
3659ed9652daSAlexander Motin 		if ((addr & UINT32_MAX) != addr)
3660ed9652daSAlexander Motin 			return (ERANGE);
3661ed9652daSAlexander Motin 		if (((addr + size) & UINT32_MAX) != (addr + size))
3662ed9652daSAlexander Motin 			return (ERANGE);
3663ed9652daSAlexander Motin 
3664ed9652daSAlexander Motin 		base = intel_ntb_reg_read(4, base_reg) & BAR_HIGH_MASK;
3665ed9652daSAlexander Motin 
3666ed9652daSAlexander Motin 		if (limit_reg != 0 && size != mw_size)
3667ed9652daSAlexander Motin 			limit = base + size;
3668ed9652daSAlexander Motin 
3669ed9652daSAlexander Motin 		/* Set and verify translation address */
3670ed9652daSAlexander Motin 		intel_ntb_reg_write(4, xlat_reg, addr);
3671ed9652daSAlexander Motin 		reg_val = intel_ntb_reg_read(4, xlat_reg) & BAR_HIGH_MASK;
3672ed9652daSAlexander Motin 		if (reg_val != addr) {
3673ed9652daSAlexander Motin 			intel_ntb_reg_write(4, xlat_reg, 0);
3674ed9652daSAlexander Motin 			return (EIO);
3675ed9652daSAlexander Motin 		}
3676ed9652daSAlexander Motin 
3677ed9652daSAlexander Motin 		/* Set and verify the limit */
3678ed9652daSAlexander Motin 		intel_ntb_reg_write(4, limit_reg, limit);
3679ed9652daSAlexander Motin 		reg_val = intel_ntb_reg_read(4, limit_reg) & BAR_HIGH_MASK;
3680ed9652daSAlexander Motin 		if (reg_val != limit) {
3681ed9652daSAlexander Motin 			intel_ntb_reg_write(4, limit_reg, base);
3682ed9652daSAlexander Motin 			intel_ntb_reg_write(4, xlat_reg, 0);
3683ed9652daSAlexander Motin 			return (EIO);
3684ed9652daSAlexander Motin 		}
3685ed9652daSAlexander Motin 	}
3686ed9652daSAlexander Motin 	return (0);
3687ed9652daSAlexander Motin }
3688ed9652daSAlexander Motin 
3689ed9652daSAlexander Motin static int
intel_ntb_mw_clear_trans(device_t dev,unsigned mw_idx)3690ed9652daSAlexander Motin intel_ntb_mw_clear_trans(device_t dev, unsigned mw_idx)
3691ed9652daSAlexander Motin {
3692ed9652daSAlexander Motin 
3693ed9652daSAlexander Motin 	return (intel_ntb_mw_set_trans(dev, mw_idx, 0, 0));
3694ed9652daSAlexander Motin }
3695ed9652daSAlexander Motin 
3696ed9652daSAlexander Motin static int
intel_ntb_mw_get_wc(device_t dev,unsigned idx,vm_memattr_t * mode)3697ed9652daSAlexander Motin intel_ntb_mw_get_wc(device_t dev, unsigned idx, vm_memattr_t *mode)
3698ed9652daSAlexander Motin {
3699ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3700ed9652daSAlexander Motin 	struct ntb_pci_bar_info *bar;
3701ed9652daSAlexander Motin 
3702ed9652daSAlexander Motin 	if (idx >= intel_ntb_mw_count(dev))
3703ed9652daSAlexander Motin 		return (EINVAL);
3704ed9652daSAlexander Motin 	idx = intel_ntb_user_mw_to_idx(ntb, idx);
3705ed9652daSAlexander Motin 
3706ed9652daSAlexander Motin 	bar = &ntb->bar_info[intel_ntb_mw_to_bar(ntb, idx)];
3707ed9652daSAlexander Motin 	*mode = bar->map_mode;
3708ed9652daSAlexander Motin 	return (0);
3709ed9652daSAlexander Motin }
3710ed9652daSAlexander Motin 
3711ed9652daSAlexander Motin static int
intel_ntb_mw_set_wc(device_t dev,unsigned idx,vm_memattr_t mode)3712ed9652daSAlexander Motin intel_ntb_mw_set_wc(device_t dev, unsigned idx, vm_memattr_t mode)
3713ed9652daSAlexander Motin {
3714ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3715ed9652daSAlexander Motin 
3716ed9652daSAlexander Motin 	if (idx >= intel_ntb_mw_count(dev))
3717ed9652daSAlexander Motin 		return (EINVAL);
3718ed9652daSAlexander Motin 
3719ed9652daSAlexander Motin 	idx = intel_ntb_user_mw_to_idx(ntb, idx);
3720ed9652daSAlexander Motin 	return (intel_ntb_mw_set_wc_internal(ntb, idx, mode));
3721ed9652daSAlexander Motin }
3722ed9652daSAlexander Motin 
3723ed9652daSAlexander Motin static int
intel_ntb_mw_set_wc_internal(struct ntb_softc * ntb,unsigned idx,vm_memattr_t mode)3724ed9652daSAlexander Motin intel_ntb_mw_set_wc_internal(struct ntb_softc *ntb, unsigned idx, vm_memattr_t mode)
3725ed9652daSAlexander Motin {
3726ed9652daSAlexander Motin 	struct ntb_pci_bar_info *bar;
3727ed9652daSAlexander Motin 	int rc;
3728ed9652daSAlexander Motin 
3729ed9652daSAlexander Motin 	bar = &ntb->bar_info[intel_ntb_mw_to_bar(ntb, idx)];
3730ed9652daSAlexander Motin 	if (bar->map_mode == mode)
3731ed9652daSAlexander Motin 		return (0);
3732ed9652daSAlexander Motin 
3733ed9652daSAlexander Motin 	rc = pmap_change_attr((vm_offset_t)bar->vbase, bar->size, mode);
3734ed9652daSAlexander Motin 	if (rc == 0)
3735ed9652daSAlexander Motin 		bar->map_mode = mode;
3736ed9652daSAlexander Motin 
3737ed9652daSAlexander Motin 	return (rc);
3738ed9652daSAlexander Motin }
3739ed9652daSAlexander Motin 
3740ed9652daSAlexander Motin static void
intel_ntb_peer_db_set(device_t dev,uint64_t bits)37416660ef6eSMark Johnston intel_ntb_peer_db_set(device_t dev, uint64_t bits)
3742ed9652daSAlexander Motin {
3743ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
37446660ef6eSMark Johnston 	uint64_t db;
37456660ef6eSMark Johnston 
37466660ef6eSMark Johnston 	if ((bits & ~ntb->db_valid_mask) != 0) {
374793fb2b06SMark Johnston 		device_printf(ntb->device, "Invalid doorbell bits %#jx\n",
374893fb2b06SMark Johnston 		    (uintmax_t)bits);
37496660ef6eSMark Johnston 		return;
37506660ef6eSMark Johnston 	}
3751ed9652daSAlexander Motin 
3752ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SB01BASE_LOCKUP)) {
3753ed9652daSAlexander Motin 		struct ntb_pci_bar_info *lapic;
3754ed9652daSAlexander Motin 		unsigned i;
3755ed9652daSAlexander Motin 
3756ed9652daSAlexander Motin 		lapic = ntb->peer_lapic_bar;
3757ed9652daSAlexander Motin 
3758ed9652daSAlexander Motin 		for (i = 0; i < XEON_NONLINK_DB_MSIX_BITS; i++) {
37596660ef6eSMark Johnston 			if ((bits & intel_ntb_db_vector_mask(dev, i)) != 0)
3760ed9652daSAlexander Motin 				bus_space_write_4(lapic->pci_bus_tag,
3761ed9652daSAlexander Motin 				    lapic->pci_bus_handle,
3762ed9652daSAlexander Motin 				    ntb->peer_msix_data[i].nmd_ofs,
3763ed9652daSAlexander Motin 				    ntb->peer_msix_data[i].nmd_data);
3764ed9652daSAlexander Motin 		}
3765ed9652daSAlexander Motin 		return;
3766ed9652daSAlexander Motin 	}
3767ed9652daSAlexander Motin 
3768ed9652daSAlexander Motin 	if (HAS_FEATURE(ntb, NTB_SDOORBELL_LOCKUP)) {
37696660ef6eSMark Johnston 		intel_ntb_mw_write(2, XEON_PDOORBELL_OFFSET, bits);
3770ed9652daSAlexander Motin 		return;
3771ed9652daSAlexander Motin 	}
3772ed9652daSAlexander Motin 
3773*70450ecdSAustin Zhang 	if (ntb->type == NTB_XEON_GEN3 || ntb->type == NTB_XEON_GEN4) {
37746660ef6eSMark Johnston 		while (bits != 0) {
37756660ef6eSMark Johnston 			db = ffsll(bits);
37766660ef6eSMark Johnston 
37776660ef6eSMark Johnston 			intel_ntb_reg_write(1,
37786660ef6eSMark Johnston 			    ntb->peer_reg->db_bell + (db - 1) * 4, 0x1);
37796660ef6eSMark Johnston 
37806660ef6eSMark Johnston 			bits = bits & (bits - 1);
37816660ef6eSMark Johnston 		}
37826660ef6eSMark Johnston 	} else {
37836660ef6eSMark Johnston 		db_iowrite(ntb, ntb->peer_reg->db_bell, bits);
37846660ef6eSMark Johnston 	}
3785ed9652daSAlexander Motin }
3786ed9652daSAlexander Motin 
3787ed9652daSAlexander Motin static int
intel_ntb_peer_db_addr(device_t dev,bus_addr_t * db_addr,vm_size_t * db_size)3788ed9652daSAlexander Motin intel_ntb_peer_db_addr(device_t dev, bus_addr_t *db_addr, vm_size_t *db_size)
3789ed9652daSAlexander Motin {
3790ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3791ed9652daSAlexander Motin 	struct ntb_pci_bar_info *bar;
3792ed9652daSAlexander Motin 	uint64_t regoff;
3793ed9652daSAlexander Motin 
3794ed9652daSAlexander Motin 	KASSERT((db_addr != NULL && db_size != NULL), ("must be non-NULL"));
3795ed9652daSAlexander Motin 
3796ed9652daSAlexander Motin 	if (!HAS_FEATURE(ntb, NTB_SDOORBELL_LOCKUP)) {
3797ed9652daSAlexander Motin 		bar = &ntb->bar_info[NTB_CONFIG_BAR];
3798ed9652daSAlexander Motin 		regoff = ntb->peer_reg->db_bell;
3799ed9652daSAlexander Motin 	} else {
3800ed9652daSAlexander Motin 		KASSERT(ntb->b2b_mw_idx != B2B_MW_DISABLED,
3801ed9652daSAlexander Motin 		    ("invalid b2b idx"));
3802ed9652daSAlexander Motin 
3803ed9652daSAlexander Motin 		bar = &ntb->bar_info[intel_ntb_mw_to_bar(ntb, ntb->b2b_mw_idx)];
3804ed9652daSAlexander Motin 		regoff = XEON_PDOORBELL_OFFSET;
3805ed9652daSAlexander Motin 	}
3806ed9652daSAlexander Motin 	KASSERT(bar->pci_bus_tag != X86_BUS_SPACE_IO, ("uh oh"));
3807ed9652daSAlexander Motin 
3808ed9652daSAlexander Motin 	/* HACK: Specific to current x86 bus implementation. */
3809ed9652daSAlexander Motin 	*db_addr = ((uint64_t)bar->pci_bus_handle + regoff);
3810ed9652daSAlexander Motin 	*db_size = ntb->reg->db_size;
3811ed9652daSAlexander Motin 	return (0);
3812ed9652daSAlexander Motin }
3813ed9652daSAlexander Motin 
3814ed9652daSAlexander Motin static uint64_t
intel_ntb_db_valid_mask(device_t dev)3815ed9652daSAlexander Motin intel_ntb_db_valid_mask(device_t dev)
3816ed9652daSAlexander Motin {
3817ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3818ed9652daSAlexander Motin 
3819ed9652daSAlexander Motin 	return (ntb->db_valid_mask);
3820ed9652daSAlexander Motin }
3821ed9652daSAlexander Motin 
3822ed9652daSAlexander Motin static int
intel_ntb_db_vector_count(device_t dev)3823ed9652daSAlexander Motin intel_ntb_db_vector_count(device_t dev)
3824ed9652daSAlexander Motin {
3825ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3826ed9652daSAlexander Motin 
3827ed9652daSAlexander Motin 	return (ntb->db_vec_count);
3828ed9652daSAlexander Motin }
3829ed9652daSAlexander Motin 
3830ed9652daSAlexander Motin static uint64_t
intel_ntb_db_vector_mask(device_t dev,uint32_t vector)3831ed9652daSAlexander Motin intel_ntb_db_vector_mask(device_t dev, uint32_t vector)
3832ed9652daSAlexander Motin {
3833ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3834ed9652daSAlexander Motin 
3835ed9652daSAlexander Motin 	if (vector > ntb->db_vec_count)
3836ed9652daSAlexander Motin 		return (0);
3837ed9652daSAlexander Motin 	return (ntb->db_valid_mask & intel_ntb_vec_mask(ntb, vector));
3838ed9652daSAlexander Motin }
3839ed9652daSAlexander Motin 
3840ed9652daSAlexander Motin static bool
intel_ntb_link_is_up(device_t dev,enum ntb_speed * speed,enum ntb_width * width)3841ed9652daSAlexander Motin intel_ntb_link_is_up(device_t dev, enum ntb_speed *speed, enum ntb_width *width)
3842ed9652daSAlexander Motin {
3843ed9652daSAlexander Motin 	struct ntb_softc *ntb = device_get_softc(dev);
3844ed9652daSAlexander Motin 
3845ed9652daSAlexander Motin 	if (speed != NULL)
3846ed9652daSAlexander Motin 		*speed = intel_ntb_link_sta_speed(ntb);
3847ed9652daSAlexander Motin 	if (width != NULL)
3848ed9652daSAlexander Motin 		*width = intel_ntb_link_sta_width(ntb);
3849ed9652daSAlexander Motin 	return (link_is_up(ntb));
3850ed9652daSAlexander Motin }
3851ed9652daSAlexander Motin 
3852ed9652daSAlexander Motin static void
save_bar_parameters(struct ntb_pci_bar_info * bar)3853ed9652daSAlexander Motin save_bar_parameters(struct ntb_pci_bar_info *bar)
3854ed9652daSAlexander Motin {
3855ed9652daSAlexander Motin 
3856ed9652daSAlexander Motin 	bar->pci_bus_tag = rman_get_bustag(bar->pci_resource);
3857ed9652daSAlexander Motin 	bar->pci_bus_handle = rman_get_bushandle(bar->pci_resource);
3858ed9652daSAlexander Motin 	bar->pbase = rman_get_start(bar->pci_resource);
3859ed9652daSAlexander Motin 	bar->size = rman_get_size(bar->pci_resource);
3860ed9652daSAlexander Motin 	bar->vbase = rman_get_virtual(bar->pci_resource);
3861ed9652daSAlexander Motin }
3862ed9652daSAlexander Motin 
3863ed9652daSAlexander Motin static device_method_t ntb_intel_methods[] = {
3864ed9652daSAlexander Motin 	/* Device interface */
3865ed9652daSAlexander Motin 	DEVMETHOD(device_probe,		intel_ntb_probe),
3866ed9652daSAlexander Motin 	DEVMETHOD(device_attach,	intel_ntb_attach),
3867ed9652daSAlexander Motin 	DEVMETHOD(device_detach,	intel_ntb_detach),
3868b7dd3fbeSAlexander Motin 	/* Bus interface */
3869ddfc9c4cSWarner Losh 	DEVMETHOD(bus_child_location,	ntb_child_location),
3870b7dd3fbeSAlexander Motin 	DEVMETHOD(bus_print_child,	ntb_print_child),
38717f215e07SAlexander Motin 	DEVMETHOD(bus_get_dma_tag,	ntb_get_dma_tag),
3872ed9652daSAlexander Motin 	/* NTB interface */
38736ddecf2bSAlexander Motin 	DEVMETHOD(ntb_port_number,	intel_ntb_port_number),
38746ddecf2bSAlexander Motin 	DEVMETHOD(ntb_peer_port_count,	intel_ntb_peer_port_count),
38756ddecf2bSAlexander Motin 	DEVMETHOD(ntb_peer_port_number,	intel_ntb_peer_port_number),
38766ddecf2bSAlexander Motin 	DEVMETHOD(ntb_peer_port_idx, 	intel_ntb_peer_port_idx),
3877ed9652daSAlexander Motin 	DEVMETHOD(ntb_link_is_up,	intel_ntb_link_is_up),
3878ed9652daSAlexander Motin 	DEVMETHOD(ntb_link_enable,	intel_ntb_link_enable),
3879ed9652daSAlexander Motin 	DEVMETHOD(ntb_link_disable,	intel_ntb_link_disable),
3880ed9652daSAlexander Motin 	DEVMETHOD(ntb_link_enabled,	intel_ntb_link_enabled),
3881ed9652daSAlexander Motin 	DEVMETHOD(ntb_mw_count,		intel_ntb_mw_count),
3882ed9652daSAlexander Motin 	DEVMETHOD(ntb_mw_get_range,	intel_ntb_mw_get_range),
3883ed9652daSAlexander Motin 	DEVMETHOD(ntb_mw_set_trans,	intel_ntb_mw_set_trans),
3884ed9652daSAlexander Motin 	DEVMETHOD(ntb_mw_clear_trans,	intel_ntb_mw_clear_trans),
3885ed9652daSAlexander Motin 	DEVMETHOD(ntb_mw_get_wc,	intel_ntb_mw_get_wc),
3886ed9652daSAlexander Motin 	DEVMETHOD(ntb_mw_set_wc,	intel_ntb_mw_set_wc),
3887ed9652daSAlexander Motin 	DEVMETHOD(ntb_spad_count,	intel_ntb_spad_count),
3888ed9652daSAlexander Motin 	DEVMETHOD(ntb_spad_clear,	intel_ntb_spad_clear),
3889ed9652daSAlexander Motin 	DEVMETHOD(ntb_spad_write,	intel_ntb_spad_write),
3890ed9652daSAlexander Motin 	DEVMETHOD(ntb_spad_read,	intel_ntb_spad_read),
3891ed9652daSAlexander Motin 	DEVMETHOD(ntb_peer_spad_write,	intel_ntb_peer_spad_write),
3892ed9652daSAlexander Motin 	DEVMETHOD(ntb_peer_spad_read,	intel_ntb_peer_spad_read),
3893ed9652daSAlexander Motin 	DEVMETHOD(ntb_db_valid_mask,	intel_ntb_db_valid_mask),
3894ed9652daSAlexander Motin 	DEVMETHOD(ntb_db_vector_count,	intel_ntb_db_vector_count),
3895ed9652daSAlexander Motin 	DEVMETHOD(ntb_db_vector_mask,	intel_ntb_db_vector_mask),
3896ed9652daSAlexander Motin 	DEVMETHOD(ntb_db_clear,		intel_ntb_db_clear),
3897ed9652daSAlexander Motin 	DEVMETHOD(ntb_db_clear_mask,	intel_ntb_db_clear_mask),
3898ed9652daSAlexander Motin 	DEVMETHOD(ntb_db_read,		intel_ntb_db_read),
3899ed9652daSAlexander Motin 	DEVMETHOD(ntb_db_set_mask,	intel_ntb_db_set_mask),
3900ed9652daSAlexander Motin 	DEVMETHOD(ntb_peer_db_addr,	intel_ntb_peer_db_addr),
3901ed9652daSAlexander Motin 	DEVMETHOD(ntb_peer_db_set,	intel_ntb_peer_db_set),
3902ed9652daSAlexander Motin 	DEVMETHOD_END
3903ed9652daSAlexander Motin };
3904ed9652daSAlexander Motin 
3905ed9652daSAlexander Motin static DEFINE_CLASS_0(ntb_hw, ntb_intel_driver, ntb_intel_methods,
3906ed9652daSAlexander Motin     sizeof(struct ntb_softc));
39079940f7a7SJohn Baldwin DRIVER_MODULE(ntb_hw_intel, pci, ntb_intel_driver, NULL, NULL);
3908ed9652daSAlexander Motin MODULE_DEPEND(ntb_hw_intel, ntb, 1, 1, 1);
3909ed9652daSAlexander Motin MODULE_VERSION(ntb_hw_intel, 1);
39106efa5583SWarner Losh MODULE_PNP_INFO("W32:vendor/device;D:#", pci, ntb_hw_intel, pci_ids,
3911329e817fSWarner Losh     nitems(pci_ids));
3912