ntb_hw_intel.c revision 289538
1250079Scarl/*-
2250079Scarl * Copyright (C) 2013 Intel Corporation
3250079Scarl * All rights reserved.
4250079Scarl *
5250079Scarl * Redistribution and use in source and binary forms, with or without
6250079Scarl * modification, are permitted provided that the following conditions
7250079Scarl * are met:
8250079Scarl * 1. Redistributions of source code must retain the above copyright
9250079Scarl *    notice, this list of conditions and the following disclaimer.
10250079Scarl * 2. Redistributions in binary form must reproduce the above copyright
11250079Scarl *    notice, this list of conditions and the following disclaimer in the
12250079Scarl *    documentation and/or other materials provided with the distribution.
13250079Scarl *
14250079Scarl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15250079Scarl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16250079Scarl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17250079Scarl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18250079Scarl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19250079Scarl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20250079Scarl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21250079Scarl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22250079Scarl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23250079Scarl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24250079Scarl * SUCH DAMAGE.
25250079Scarl */
26250079Scarl
27250079Scarl#include <sys/cdefs.h>
28250079Scarl__FBSDID("$FreeBSD: head/sys/dev/ntb/ntb_hw/ntb_hw.c 289538 2015-10-18 20:19:44Z cem $");
29250079Scarl
30250079Scarl#include <sys/param.h>
31250079Scarl#include <sys/kernel.h>
32250079Scarl#include <sys/systm.h>
33250079Scarl#include <sys/bus.h>
34250079Scarl#include <sys/malloc.h>
35250079Scarl#include <sys/module.h>
36250079Scarl#include <sys/queue.h>
37250079Scarl#include <sys/rman.h>
38289207Scem#include <sys/sysctl.h>
39250079Scarl#include <vm/vm.h>
40250079Scarl#include <vm/pmap.h>
41250079Scarl#include <machine/bus.h>
42250079Scarl#include <machine/pmap.h>
43250079Scarl#include <machine/resource.h>
44250079Scarl#include <dev/pci/pcireg.h>
45250079Scarl#include <dev/pci/pcivar.h>
46250079Scarl
47250079Scarl#include "ntb_regs.h"
48250079Scarl#include "ntb_hw.h"
49250079Scarl
50250079Scarl/*
51250079Scarl * The Non-Transparent Bridge (NTB) is a device on some Intel processors that
52250079Scarl * allows you to connect two systems using a PCI-e link.
53250079Scarl *
54250079Scarl * This module contains the hardware abstraction layer for the NTB. It allows
55250079Scarl * you to send and recieve interrupts, map the memory windows and send and
56250079Scarl * receive messages in the scratch-pad registers.
57250079Scarl *
58250079Scarl * NOTE: Much of the code in this module is shared with Linux. Any patches may
59250079Scarl * be picked up and redistributed in Linux with a dual GPL/BSD license.
60250079Scarl */
61250079Scarl
62250079Scarl#define NTB_CONFIG_BAR	0
63250079Scarl#define NTB_B2B_BAR_1	1
64250079Scarl#define NTB_B2B_BAR_2	2
65289397Scem#define NTB_B2B_BAR_3	3
66289397Scem#define NTB_MAX_BARS	4
67250079Scarl#define NTB_MW_TO_BAR(mw) ((mw) + 1)
68250079Scarl
69289538Scem#define MAX_MSIX_INTERRUPTS MAX(XEON_DB_COUNT, SOC_DB_COUNT)
70250079Scarl
71250079Scarl#define NTB_HB_TIMEOUT	1 /* second */
72250079Scarl#define SOC_LINK_RECOVERY_TIME	500
73250079Scarl
74250079Scarl#define DEVICE2SOFTC(dev) ((struct ntb_softc *) device_get_softc(dev))
75250079Scarl
76250079Scarlenum ntb_device_type {
77250079Scarl	NTB_XEON,
78250079Scarl	NTB_SOC
79250079Scarl};
80250079Scarl
81255274Scarl/* Device features and workarounds */
82255274Scarl#define HAS_FEATURE(feature)	\
83255274Scarl	((ntb->features & (feature)) != 0)
84255274Scarl
85250079Scarlstruct ntb_hw_info {
86250079Scarl	uint32_t		device_id;
87255274Scarl	const char		*desc;
88250079Scarl	enum ntb_device_type	type;
89289397Scem	uint32_t		features;
90250079Scarl};
91250079Scarl
92250079Scarlstruct ntb_pci_bar_info {
93250079Scarl	bus_space_tag_t		pci_bus_tag;
94250079Scarl	bus_space_handle_t	pci_bus_handle;
95250079Scarl	int			pci_resource_id;
96250079Scarl	struct resource		*pci_resource;
97250079Scarl	vm_paddr_t		pbase;
98250079Scarl	void			*vbase;
99250079Scarl	u_long			size;
100250079Scarl};
101250079Scarl
102250079Scarlstruct ntb_int_info {
103250079Scarl	struct resource	*res;
104250079Scarl	int		rid;
105250079Scarl	void		*tag;
106250079Scarl};
107250079Scarl
108250079Scarlstruct ntb_db_cb {
109250079Scarl	ntb_db_callback		callback;
110250079Scarl	unsigned int		db_num;
111250079Scarl	void			*data;
112250079Scarl	struct ntb_softc	*ntb;
113289281Scem	struct callout		irq_work;
114289343Scem	bool			reserved;
115250079Scarl};
116250079Scarl
117250079Scarlstruct ntb_softc {
118250079Scarl	device_t		device;
119250079Scarl	enum ntb_device_type	type;
120255274Scarl	uint64_t		features;
121250079Scarl
122250079Scarl	struct ntb_pci_bar_info	bar_info[NTB_MAX_BARS];
123250079Scarl	struct ntb_int_info	int_info[MAX_MSIX_INTERRUPTS];
124250079Scarl	uint32_t		allocated_interrupts;
125250079Scarl
126250079Scarl	struct callout		heartbeat_timer;
127250079Scarl	struct callout		lr_timer;
128250079Scarl
129250079Scarl	void			*ntb_transport;
130250079Scarl	ntb_event_callback	event_cb;
131289396Scem	struct ntb_db_cb	*db_cb;
132289396Scem	uint8_t			max_cbs;
133250079Scarl
134250079Scarl	struct {
135289396Scem		uint8_t max_mw;
136289208Scem		uint8_t max_spads;
137289208Scem		uint8_t max_db_bits;
138289208Scem		uint8_t msix_cnt;
139250079Scarl	} limits;
140250079Scarl	struct {
141289255Scem		uint32_t ldb;
142289255Scem		uint32_t ldb_mask;
143289255Scem		uint32_t rdb;
144289255Scem		uint32_t bar2_xlat;
145289255Scem		uint32_t bar4_xlat;
146289397Scem		uint32_t bar5_xlat;
147250079Scarl		uint32_t spad_remote;
148250079Scarl		uint32_t spad_local;
149250079Scarl		uint32_t lnk_cntl;
150250079Scarl		uint32_t lnk_stat;
151250079Scarl		uint32_t spci_cmd;
152250079Scarl	} reg_ofs;
153289348Scem	uint32_t ppd;
154250079Scarl	uint8_t conn_type;
155250079Scarl	uint8_t dev_type;
156250079Scarl	uint8_t bits_per_vector;
157250079Scarl	uint8_t link_status;
158250079Scarl	uint8_t link_width;
159250079Scarl	uint8_t link_speed;
160250079Scarl};
161250079Scarl
162289234Scem#ifdef __i386__
163289234Scemstatic __inline uint64_t
164289234Scembus_space_read_8(bus_space_tag_t tag, bus_space_handle_t handle,
165289234Scem    bus_size_t offset)
166289234Scem{
167289234Scem
168289234Scem	return (bus_space_read_4(tag, handle, offset) |
169289234Scem	    ((uint64_t)bus_space_read_4(tag, handle, offset + 4)) << 32);
170289234Scem}
171289234Scem
172289234Scemstatic __inline void
173289234Scembus_space_write_8(bus_space_tag_t tag, bus_space_handle_t handle,
174289234Scem    bus_size_t offset, uint64_t val)
175289234Scem{
176289234Scem
177289234Scem	bus_space_write_4(tag, handle, offset, val);
178289234Scem	bus_space_write_4(tag, handle, offset + 4, val >> 32);
179289234Scem}
180289234Scem#endif
181289234Scem
182255279Scarl#define ntb_bar_read(SIZE, bar, offset) \
183255279Scarl	    bus_space_read_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \
184255279Scarl	    ntb->bar_info[(bar)].pci_bus_handle, (offset))
185255279Scarl#define ntb_bar_write(SIZE, bar, offset, val) \
186255279Scarl	    bus_space_write_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \
187255279Scarl	    ntb->bar_info[(bar)].pci_bus_handle, (offset), (val))
188255279Scarl#define ntb_reg_read(SIZE, offset) ntb_bar_read(SIZE, NTB_CONFIG_BAR, offset)
189250079Scarl#define ntb_reg_write(SIZE, offset, val) \
190255279Scarl	    ntb_bar_write(SIZE, NTB_CONFIG_BAR, offset, val)
191289397Scem#define ntb_mw_read(SIZE, offset) \
192289397Scem	    ntb_bar_read(SIZE, NTB_MW_TO_BAR(ntb->limits.max_mw), offset)
193255279Scarl#define ntb_mw_write(SIZE, offset, val) \
194289397Scem	    ntb_bar_write(SIZE, NTB_MW_TO_BAR(ntb->limits.max_mw), \
195289397Scem		offset, val)
196250079Scarl
197255272Scarltypedef int (*bar_map_strategy)(struct ntb_softc *ntb,
198255272Scarl    struct ntb_pci_bar_info *bar);
199255272Scarl
200250079Scarlstatic int ntb_probe(device_t device);
201250079Scarlstatic int ntb_attach(device_t device);
202250079Scarlstatic int ntb_detach(device_t device);
203255272Scarlstatic int ntb_map_pci_bars(struct ntb_softc *ntb);
204255272Scarlstatic int map_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy,
205255272Scarl    struct ntb_pci_bar_info *bar);
206255272Scarlstatic int map_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar);
207255272Scarlstatic int map_memory_window_bar(struct ntb_softc *ntb,
208255272Scarl    struct ntb_pci_bar_info *bar);
209250079Scarlstatic void ntb_unmap_pci_bar(struct ntb_softc *ntb);
210289344Scemstatic int ntb_remap_msix(device_t, uint32_t desired, uint32_t avail);
211250079Scarlstatic int ntb_setup_interrupts(struct ntb_softc *ntb);
212289342Scemstatic int ntb_setup_legacy_interrupt(struct ntb_softc *ntb);
213289342Scemstatic int ntb_setup_xeon_msix(struct ntb_softc *ntb, uint32_t num_vectors);
214289342Scemstatic int ntb_setup_soc_msix(struct ntb_softc *ntb, uint32_t num_vectors);
215250079Scarlstatic void ntb_teardown_interrupts(struct ntb_softc *ntb);
216250079Scarlstatic void handle_soc_irq(void *arg);
217250079Scarlstatic void handle_xeon_irq(void *arg);
218250079Scarlstatic void handle_xeon_event_irq(void *arg);
219250079Scarlstatic void ntb_handle_legacy_interrupt(void *arg);
220289281Scemstatic void ntb_irq_work(void *arg);
221289347Scemstatic uint64_t db_ioread(struct ntb_softc *, uint32_t regoff);
222289347Scemstatic void db_iowrite(struct ntb_softc *, uint32_t regoff, uint64_t val);
223289281Scemstatic void mask_ldb_interrupt(struct ntb_softc *ntb, unsigned int idx);
224289281Scemstatic void unmask_ldb_interrupt(struct ntb_softc *ntb, unsigned int idx);
225289342Scemstatic int ntb_create_callbacks(struct ntb_softc *ntb, uint32_t num_vectors);
226250079Scarlstatic void ntb_free_callbacks(struct ntb_softc *ntb);
227250079Scarlstatic struct ntb_hw_info *ntb_get_device_info(uint32_t device_id);
228289397Scemstatic void ntb_detect_max_mw(struct ntb_softc *ntb);
229289348Scemstatic int ntb_detect_xeon(struct ntb_softc *ntb);
230289348Scemstatic int ntb_detect_soc(struct ntb_softc *ntb);
231250079Scarlstatic int ntb_setup_xeon(struct ntb_softc *ntb);
232250079Scarlstatic int ntb_setup_soc(struct ntb_softc *ntb);
233289272Scemstatic void ntb_teardown_xeon(struct ntb_softc *ntb);
234255279Scarlstatic void configure_soc_secondary_side_bars(struct ntb_softc *ntb);
235255279Scarlstatic void configure_xeon_secondary_side_bars(struct ntb_softc *ntb);
236250079Scarlstatic void ntb_handle_heartbeat(void *arg);
237250079Scarlstatic void ntb_handle_link_event(struct ntb_softc *ntb, int link_state);
238289272Scemstatic void ntb_hw_link_down(struct ntb_softc *ntb);
239289272Scemstatic void ntb_hw_link_up(struct ntb_softc *ntb);
240250079Scarlstatic void recover_soc_link(void *arg);
241250079Scarlstatic int ntb_check_link_status(struct ntb_softc *ntb);
242255274Scarlstatic void save_bar_parameters(struct ntb_pci_bar_info *bar);
243250079Scarl
244250079Scarlstatic struct ntb_hw_info pci_ids[] = {
245255274Scarl	{ 0x0C4E8086, "Atom Processor S1200 NTB Primary B2B", NTB_SOC, 0 },
246289233Scem
247289233Scem	/* XXX: PS/SS IDs left out until they are supported. */
248289233Scem	{ 0x37258086, "JSF Xeon C35xx/C55xx Non-Transparent Bridge B2B",
249289538Scem		NTB_XEON, NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 },
250289233Scem	{ 0x3C0D8086, "SNB Xeon E5/Core i7 Non-Transparent Bridge B2B",
251289538Scem		NTB_XEON, NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 },
252289233Scem	{ 0x0E0D8086, "IVT Xeon E5 V2 Non-Transparent Bridge B2B", NTB_XEON,
253289538Scem		NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 |
254289538Scem		    NTB_SB01BASE_LOCKUP | NTB_BAR_SIZE_4K },
255289233Scem	{ 0x2F0D8086, "HSX Xeon E5 V3 Non-Transparent Bridge B2B", NTB_XEON,
256289538Scem		NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 |
257289538Scem		    NTB_SB01BASE_LOCKUP },
258289233Scem	{ 0x6F0D8086, "BDX Xeon E5 V4 Non-Transparent Bridge B2B", NTB_XEON,
259289538Scem		NTB_SDOORBELL_LOCKUP | NTB_B2BDOORBELL_BIT14 |
260289538Scem		    NTB_SB01BASE_LOCKUP },
261289233Scem
262255274Scarl	{ 0x00000000, NULL, NTB_SOC, 0 }
263250079Scarl};
264250079Scarl
265250079Scarl/*
266250079Scarl * OS <-> Driver interface structures
267250079Scarl */
268250079ScarlMALLOC_DEFINE(M_NTB, "ntb_hw", "ntb_hw driver memory allocations");
269250079Scarl
270250079Scarlstatic device_method_t ntb_pci_methods[] = {
271250079Scarl	/* Device interface */
272250079Scarl	DEVMETHOD(device_probe,     ntb_probe),
273250079Scarl	DEVMETHOD(device_attach,    ntb_attach),
274250079Scarl	DEVMETHOD(device_detach,    ntb_detach),
275250079Scarl	DEVMETHOD_END
276250079Scarl};
277250079Scarl
278250079Scarlstatic driver_t ntb_pci_driver = {
279250079Scarl	"ntb_hw",
280250079Scarl	ntb_pci_methods,
281250079Scarl	sizeof(struct ntb_softc),
282250079Scarl};
283250079Scarl
284250079Scarlstatic devclass_t ntb_devclass;
285250079ScarlDRIVER_MODULE(ntb_hw, pci, ntb_pci_driver, ntb_devclass, NULL, NULL);
286250079ScarlMODULE_VERSION(ntb_hw, 1);
287250079Scarl
288289207ScemSYSCTL_NODE(_hw, OID_AUTO, ntb, CTLFLAG_RW, 0, "NTB sysctls");
289289207Scem
290250079Scarl/*
291250079Scarl * OS <-> Driver linkage functions
292250079Scarl */
293250079Scarlstatic int
294250079Scarlntb_probe(device_t device)
295250079Scarl{
296289209Scem	struct ntb_hw_info *p;
297250079Scarl
298289209Scem	p = ntb_get_device_info(pci_get_devid(device));
299289209Scem	if (p == NULL)
300250079Scarl		return (ENXIO);
301289209Scem
302289209Scem	device_set_desc(device, p->desc);
303289209Scem	return (0);
304250079Scarl}
305250079Scarl
306250079Scarlstatic int
307250079Scarlntb_attach(device_t device)
308250079Scarl{
309289209Scem	struct ntb_softc *ntb;
310289209Scem	struct ntb_hw_info *p;
311250079Scarl	int error;
312250079Scarl
313289209Scem	ntb = DEVICE2SOFTC(device);
314289209Scem	p = ntb_get_device_info(pci_get_devid(device));
315289209Scem
316250079Scarl	ntb->device = device;
317250079Scarl	ntb->type = p->type;
318255274Scarl	ntb->features = p->features;
319250079Scarl
320250079Scarl	/* Heartbeat timer for NTB_SOC since there is no link interrupt */
321283291Sjkim	callout_init(&ntb->heartbeat_timer, 1);
322283291Sjkim	callout_init(&ntb->lr_timer, 1);
323250079Scarl
324289348Scem	if (ntb->type == NTB_SOC)
325289348Scem		error = ntb_detect_soc(ntb);
326289348Scem	else
327289348Scem		error = ntb_detect_xeon(ntb);
328289348Scem	if (error)
329289348Scem		goto out;
330289348Scem
331289397Scem	ntb_detect_max_mw(ntb);
332289396Scem
333289209Scem	error = ntb_map_pci_bars(ntb);
334289209Scem	if (error)
335289209Scem		goto out;
336289272Scem	if (ntb->type == NTB_SOC)
337289272Scem		error = ntb_setup_soc(ntb);
338289272Scem	else
339289272Scem		error = ntb_setup_xeon(ntb);
340289209Scem	if (error)
341289209Scem		goto out;
342289209Scem	error = ntb_setup_interrupts(ntb);
343289209Scem	if (error)
344289209Scem		goto out;
345250079Scarl
346250079Scarl	pci_enable_busmaster(ntb->device);
347250079Scarl
348289209Scemout:
349289209Scem	if (error != 0)
350289209Scem		ntb_detach(device);
351250079Scarl	return (error);
352250079Scarl}
353250079Scarl
354250079Scarlstatic int
355250079Scarlntb_detach(device_t device)
356250079Scarl{
357289209Scem	struct ntb_softc *ntb;
358250079Scarl
359289209Scem	ntb = DEVICE2SOFTC(device);
360250079Scarl	callout_drain(&ntb->heartbeat_timer);
361250079Scarl	callout_drain(&ntb->lr_timer);
362289272Scem	if (ntb->type == NTB_XEON)
363289272Scem		ntb_teardown_xeon(ntb);
364250079Scarl	ntb_teardown_interrupts(ntb);
365289397Scem
366289397Scem	/*
367289397Scem	 * Redetect total MWs so we unmap properly -- in case we lowered the
368289397Scem	 * maximum to work around Xeon errata.
369289397Scem	 */
370289397Scem	ntb_detect_max_mw(ntb);
371250079Scarl	ntb_unmap_pci_bar(ntb);
372250079Scarl
373250079Scarl	return (0);
374250079Scarl}
375250079Scarl
376250079Scarlstatic int
377255272Scarlntb_map_pci_bars(struct ntb_softc *ntb)
378250079Scarl{
379255272Scarl	int rc;
380250079Scarl
381250079Scarl	ntb->bar_info[NTB_CONFIG_BAR].pci_resource_id = PCIR_BAR(0);
382255272Scarl	rc = map_pci_bar(ntb, map_mmr_bar, &ntb->bar_info[NTB_CONFIG_BAR]);
383255272Scarl	if (rc != 0)
384289209Scem		return (rc);
385255272Scarl
386289209Scem	ntb->bar_info[NTB_B2B_BAR_1].pci_resource_id = PCIR_BAR(2);
387255272Scarl	rc = map_pci_bar(ntb, map_memory_window_bar,
388255272Scarl	    &ntb->bar_info[NTB_B2B_BAR_1]);
389255272Scarl	if (rc != 0)
390289209Scem		return (rc);
391255272Scarl
392289209Scem	ntb->bar_info[NTB_B2B_BAR_2].pci_resource_id = PCIR_BAR(4);
393289538Scem	if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP) && !HAS_FEATURE(NTB_SPLIT_BAR))
394255279Scarl		rc = map_pci_bar(ntb, map_mmr_bar,
395255279Scarl		    &ntb->bar_info[NTB_B2B_BAR_2]);
396255279Scarl	else
397255279Scarl		rc = map_pci_bar(ntb, map_memory_window_bar,
398255279Scarl		    &ntb->bar_info[NTB_B2B_BAR_2]);
399289397Scem	if (!HAS_FEATURE(NTB_SPLIT_BAR))
400289397Scem		return (rc);
401289397Scem
402289397Scem	ntb->bar_info[NTB_B2B_BAR_3].pci_resource_id = PCIR_BAR(5);
403289538Scem	if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP))
404289397Scem		rc = map_pci_bar(ntb, map_mmr_bar,
405289397Scem		    &ntb->bar_info[NTB_B2B_BAR_3]);
406289397Scem	else
407289397Scem		rc = map_pci_bar(ntb, map_memory_window_bar,
408289397Scem		    &ntb->bar_info[NTB_B2B_BAR_3]);
409289209Scem	return (rc);
410255272Scarl}
411250079Scarl
412255272Scarlstatic int
413255272Scarlmap_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy,
414255272Scarl    struct ntb_pci_bar_info *bar)
415255272Scarl{
416255272Scarl	int rc;
417255272Scarl
418255272Scarl	rc = strategy(ntb, bar);
419289209Scem	if (rc != 0)
420255272Scarl		device_printf(ntb->device,
421255272Scarl		    "unable to allocate pci resource\n");
422289209Scem	else
423255279Scarl		device_printf(ntb->device,
424255272Scarl		    "Bar size = %lx, v %p, p %p\n",
425289209Scem		    bar->size, bar->vbase, (void *)(bar->pbase));
426255272Scarl	return (rc);
427255272Scarl}
428255272Scarl
429255272Scarlstatic int
430255272Scarlmap_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar)
431255272Scarl{
432255272Scarl
433255275Scarl	bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY,
434289209Scem	    &bar->pci_resource_id, RF_ACTIVE);
435255272Scarl	if (bar->pci_resource == NULL)
436255272Scarl		return (ENXIO);
437289209Scem
438289209Scem	save_bar_parameters(bar);
439289209Scem	return (0);
440255272Scarl}
441255272Scarl
442255272Scarlstatic int
443255272Scarlmap_memory_window_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar)
444255272Scarl{
445255272Scarl	int rc;
446255276Scarl	uint8_t bar_size_bits = 0;
447255272Scarl
448289209Scem	bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY,
449289209Scem	    &bar->pci_resource_id, RF_ACTIVE);
450250079Scarl
451255272Scarl	if (bar->pci_resource == NULL)
452255272Scarl		return (ENXIO);
453255276Scarl
454289209Scem	save_bar_parameters(bar);
455289209Scem	/*
456289209Scem	 * Ivytown NTB BAR sizes are misreported by the hardware due to a
457289209Scem	 * hardware issue. To work around this, query the size it should be
458289209Scem	 * configured to by the device and modify the resource to correspond to
459289209Scem	 * this new size. The BIOS on systems with this problem is required to
460289209Scem	 * provide enough address space to allow the driver to make this change
461289209Scem	 * safely.
462289209Scem	 *
463289209Scem	 * Ideally I could have just specified the size when I allocated the
464289209Scem	 * resource like:
465289209Scem	 *  bus_alloc_resource(ntb->device,
466289209Scem	 *	SYS_RES_MEMORY, &bar->pci_resource_id, 0ul, ~0ul,
467289209Scem	 *	1ul << bar_size_bits, RF_ACTIVE);
468289209Scem	 * but the PCI driver does not honor the size in this call, so we have
469289209Scem	 * to modify it after the fact.
470289209Scem	 */
471289209Scem	if (HAS_FEATURE(NTB_BAR_SIZE_4K)) {
472289209Scem		if (bar->pci_resource_id == PCIR_BAR(2))
473289209Scem			bar_size_bits = pci_read_config(ntb->device,
474289209Scem			    XEON_PBAR23SZ_OFFSET, 1);
475289209Scem		else
476289209Scem			bar_size_bits = pci_read_config(ntb->device,
477289209Scem			    XEON_PBAR45SZ_OFFSET, 1);
478289209Scem
479289209Scem		rc = bus_adjust_resource(ntb->device, SYS_RES_MEMORY,
480289209Scem		    bar->pci_resource, bar->pbase,
481289209Scem		    bar->pbase + (1ul << bar_size_bits) - 1);
482255272Scarl		if (rc != 0) {
483289209Scem			device_printf(ntb->device,
484289209Scem			    "unable to resize bar\n");
485255272Scarl			return (rc);
486250079Scarl		}
487289209Scem
488289209Scem		save_bar_parameters(bar);
489250079Scarl	}
490289209Scem
491289209Scem	/* Mark bar region as write combining to improve performance. */
492289209Scem	rc = pmap_change_attr((vm_offset_t)bar->vbase, bar->size,
493289209Scem	    VM_MEMATTR_WRITE_COMBINING);
494289209Scem	if (rc != 0) {
495289209Scem		device_printf(ntb->device,
496289209Scem		    "unable to mark bar as WRITE_COMBINING\n");
497289209Scem		return (rc);
498289209Scem	}
499250079Scarl	return (0);
500250079Scarl}
501250079Scarl
502250079Scarlstatic void
503250079Scarlntb_unmap_pci_bar(struct ntb_softc *ntb)
504250079Scarl{
505250079Scarl	struct ntb_pci_bar_info *current_bar;
506250079Scarl	int i;
507250079Scarl
508289397Scem	for (i = 0; i < NTB_MAX_BARS; i++) {
509250079Scarl		current_bar = &ntb->bar_info[i];
510250079Scarl		if (current_bar->pci_resource != NULL)
511250079Scarl			bus_release_resource(ntb->device, SYS_RES_MEMORY,
512250079Scarl			    current_bar->pci_resource_id,
513250079Scarl			    current_bar->pci_resource);
514250079Scarl	}
515250079Scarl}
516250079Scarl
517250079Scarlstatic int
518289342Scemntb_setup_xeon_msix(struct ntb_softc *ntb, uint32_t num_vectors)
519250079Scarl{
520250079Scarl	void (*interrupt_handler)(void *);
521250079Scarl	void *int_arg;
522289342Scem	uint32_t i;
523289342Scem	int rc;
524289342Scem
525289342Scem	if (num_vectors < 4)
526289342Scem		return (ENOSPC);
527289342Scem
528289342Scem	for (i = 0; i < num_vectors; i++) {
529289342Scem		ntb->int_info[i].rid = i + 1;
530289342Scem		ntb->int_info[i].res = bus_alloc_resource_any(ntb->device,
531289342Scem		    SYS_RES_IRQ, &ntb->int_info[i].rid, RF_ACTIVE);
532289342Scem		if (ntb->int_info[i].res == NULL) {
533289342Scem			device_printf(ntb->device,
534289342Scem			    "bus_alloc_resource failed\n");
535289342Scem			return (ENOMEM);
536289342Scem		}
537289342Scem		ntb->int_info[i].tag = NULL;
538289342Scem		ntb->allocated_interrupts++;
539289342Scem		if (i == num_vectors - 1) {
540289342Scem			interrupt_handler = handle_xeon_event_irq;
541289342Scem			int_arg = ntb;
542289342Scem		} else {
543289342Scem			interrupt_handler = handle_xeon_irq;
544289342Scem			int_arg = &ntb->db_cb[i];
545289342Scem		}
546289342Scem		rc = bus_setup_intr(ntb->device, ntb->int_info[i].res,
547289342Scem		    INTR_MPSAFE | INTR_TYPE_MISC, NULL, interrupt_handler,
548289342Scem		    int_arg, &ntb->int_info[i].tag);
549289342Scem		if (rc != 0) {
550289342Scem			device_printf(ntb->device,
551289342Scem			    "bus_setup_intr failed\n");
552289342Scem			return (ENXIO);
553289342Scem		}
554289342Scem	}
555289343Scem
556289343Scem	/*
557289343Scem	 * Prevent consumers from registering callbacks on the link event irq
558289343Scem	 * slot, from which they will never be called back.
559289343Scem	 */
560289343Scem	ntb->db_cb[num_vectors - 1].reserved = true;
561289396Scem	ntb->max_cbs--;
562289342Scem	return (0);
563289342Scem}
564289342Scem
565289342Scemstatic int
566289342Scemntb_setup_soc_msix(struct ntb_softc *ntb, uint32_t num_vectors)
567289342Scem{
568289342Scem	uint32_t i;
569289342Scem	int rc;
570289342Scem
571289342Scem	for (i = 0; i < num_vectors; i++) {
572289342Scem		ntb->int_info[i].rid = i + 1;
573289342Scem		ntb->int_info[i].res = bus_alloc_resource_any(ntb->device,
574289342Scem		    SYS_RES_IRQ, &ntb->int_info[i].rid, RF_ACTIVE);
575289342Scem		if (ntb->int_info[i].res == NULL) {
576289342Scem			device_printf(ntb->device,
577289342Scem			    "bus_alloc_resource failed\n");
578289342Scem			return (ENOMEM);
579289342Scem		}
580289342Scem		ntb->int_info[i].tag = NULL;
581289342Scem		ntb->allocated_interrupts++;
582289342Scem		rc = bus_setup_intr(ntb->device, ntb->int_info[i].res,
583289342Scem		    INTR_MPSAFE | INTR_TYPE_MISC, NULL, handle_soc_irq,
584289342Scem		    &ntb->db_cb[i], &ntb->int_info[i].tag);
585289342Scem		if (rc != 0) {
586289342Scem			device_printf(ntb->device, "bus_setup_intr failed\n");
587289342Scem			return (ENXIO);
588289342Scem		}
589289342Scem	}
590289342Scem	return (0);
591289342Scem}
592289342Scem
593289344Scem/*
594289344Scem * The Linux NTB driver drops from MSI-X to legacy INTx if a unique vector
595289344Scem * cannot be allocated for each MSI-X message.  JHB seems to think remapping
596289344Scem * should be okay.  This tunable should enable us to test that hypothesis
597289344Scem * when someone gets their hands on some Xeon hardware.
598289344Scem */
599289344Scemstatic int ntb_force_remap_mode;
600289344ScemSYSCTL_INT(_hw_ntb, OID_AUTO, force_remap_mode, CTLFLAG_RDTUN,
601289344Scem    &ntb_force_remap_mode, 0, "If enabled, force MSI-X messages to be remapped"
602289344Scem    " to a smaller number of ithreads, even if the desired number are "
603289344Scem    "available");
604289344Scem
605289344Scem/*
606289344Scem * In case it is NOT ok, give consumers an abort button.
607289344Scem */
608289344Scemstatic int ntb_prefer_intx;
609289344ScemSYSCTL_INT(_hw_ntb, OID_AUTO, prefer_intx_to_remap, CTLFLAG_RDTUN,
610289344Scem    &ntb_prefer_intx, 0, "If enabled, prefer to use legacy INTx mode rather "
611289344Scem    "than remapping MSI-X messages over available slots (match Linux driver "
612289344Scem    "behavior)");
613289344Scem
614289344Scem/*
615289344Scem * Remap the desired number of MSI-X messages to available ithreads in a simple
616289344Scem * round-robin fashion.
617289344Scem */
618289342Scemstatic int
619289344Scemntb_remap_msix(device_t dev, uint32_t desired, uint32_t avail)
620289344Scem{
621289344Scem	u_int *vectors;
622289344Scem	uint32_t i;
623289344Scem	int rc;
624289344Scem
625289344Scem	if (ntb_prefer_intx != 0)
626289344Scem		return (ENXIO);
627289344Scem
628289344Scem	vectors = malloc(desired * sizeof(*vectors), M_NTB, M_ZERO | M_WAITOK);
629289344Scem
630289344Scem	for (i = 0; i < desired; i++)
631289344Scem		vectors[i] = (i % avail) + 1;
632289344Scem
633289344Scem	rc = pci_remap_msix(dev, desired, vectors);
634289344Scem	free(vectors, M_NTB);
635289344Scem	return (rc);
636289344Scem}
637289344Scem
638289344Scemstatic int
639289342Scemntb_setup_interrupts(struct ntb_softc *ntb)
640289342Scem{
641289344Scem	uint32_t desired_vectors, num_vectors;
642289347Scem	uint64_t mask;
643289342Scem	int rc;
644250079Scarl
645250079Scarl	ntb->allocated_interrupts = 0;
646289347Scem
647250079Scarl	/*
648250079Scarl	 * On SOC, disable all interrupts.  On XEON, disable all but Link
649250079Scarl	 * Interrupt.  The rest will be unmasked as callbacks are registered.
650250079Scarl	 */
651289347Scem	mask = 0;
652289347Scem	if (ntb->type == NTB_XEON)
653289538Scem		mask = (1 << XEON_DB_LINK);
654289347Scem	db_iowrite(ntb, ntb->reg_ofs.ldb_mask, ~mask);
655250079Scarl
656289344Scem	num_vectors = desired_vectors = MIN(pci_msix_count(ntb->device),
657250079Scarl	    ntb->limits.max_db_bits);
658289344Scem	if (desired_vectors >= 1) {
659289344Scem		rc = pci_alloc_msix(ntb->device, &num_vectors);
660250079Scarl
661289344Scem		if (ntb_force_remap_mode != 0 && rc == 0 &&
662289344Scem		    num_vectors == desired_vectors)
663289344Scem			num_vectors--;
664289344Scem
665289344Scem		if (rc == 0 && num_vectors < desired_vectors) {
666289344Scem			rc = ntb_remap_msix(ntb->device, desired_vectors,
667289344Scem			    num_vectors);
668289344Scem			if (rc == 0)
669289344Scem				num_vectors = desired_vectors;
670289344Scem			else
671289344Scem				pci_release_msi(ntb->device);
672289344Scem		}
673289344Scem		if (rc != 0)
674289344Scem			num_vectors = 1;
675289344Scem	} else
676289344Scem		num_vectors = 1;
677289344Scem
678289396Scem	/*
679289396Scem	 * If allocating MSI-X interrupts succeeds, limit callbacks to the
680289396Scem	 * number of MSI-X slots available.
681289396Scem	 */
682250079Scarl	ntb_create_callbacks(ntb, num_vectors);
683250079Scarl
684289342Scem	if (ntb->type == NTB_XEON)
685289342Scem		rc = ntb_setup_xeon_msix(ntb, num_vectors);
686289342Scem	else
687289342Scem		rc = ntb_setup_soc_msix(ntb, num_vectors);
688289396Scem	if (rc != 0) {
689289342Scem		device_printf(ntb->device,
690289342Scem		    "Error allocating MSI-X interrupts: %d\n", rc);
691250079Scarl
692289396Scem		/*
693289396Scem		 * If allocating MSI-X interrupts failed and we're forced to
694289396Scem		 * use legacy INTx anyway, the only limit on individual
695289396Scem		 * callbacks is the number of doorbell bits.
696289396Scem		 *
697289396Scem		 * CEM: This seems odd to me but matches the behavior of the
698289396Scem		 * Linux driver ca. September 2013
699289396Scem		 */
700289396Scem		ntb_free_callbacks(ntb);
701289396Scem		ntb_create_callbacks(ntb, ntb->limits.max_db_bits);
702289396Scem	}
703289396Scem
704289342Scem	if (ntb->type == NTB_XEON && rc == ENOSPC)
705289342Scem		rc = ntb_setup_legacy_interrupt(ntb);
706289342Scem
707289342Scem	return (rc);
708289342Scem}
709289342Scem
710289342Scemstatic int
711289342Scemntb_setup_legacy_interrupt(struct ntb_softc *ntb)
712289342Scem{
713289342Scem	int rc;
714289342Scem
715289342Scem	ntb->int_info[0].rid = 0;
716289342Scem	ntb->int_info[0].res = bus_alloc_resource_any(ntb->device, SYS_RES_IRQ,
717289342Scem	    &ntb->int_info[0].rid, RF_SHAREABLE|RF_ACTIVE);
718289342Scem	if (ntb->int_info[0].res == NULL) {
719289342Scem		device_printf(ntb->device, "bus_alloc_resource failed\n");
720289342Scem		return (ENOMEM);
721250079Scarl	}
722250079Scarl
723289342Scem	ntb->int_info[0].tag = NULL;
724289342Scem	ntb->allocated_interrupts = 1;
725289342Scem
726289342Scem	rc = bus_setup_intr(ntb->device, ntb->int_info[0].res,
727289342Scem	    INTR_MPSAFE | INTR_TYPE_MISC, NULL, ntb_handle_legacy_interrupt,
728289342Scem	    ntb, &ntb->int_info[0].tag);
729289342Scem	if (rc != 0) {
730289342Scem		device_printf(ntb->device, "bus_setup_intr failed\n");
731289342Scem		return (ENXIO);
732289342Scem	}
733289342Scem
734250079Scarl	return (0);
735250079Scarl}
736250079Scarl
737250079Scarlstatic void
738250079Scarlntb_teardown_interrupts(struct ntb_softc *ntb)
739250079Scarl{
740250079Scarl	struct ntb_int_info *current_int;
741250079Scarl	int i;
742250079Scarl
743289209Scem	for (i = 0; i < ntb->allocated_interrupts; i++) {
744250079Scarl		current_int = &ntb->int_info[i];
745250079Scarl		if (current_int->tag != NULL)
746250079Scarl			bus_teardown_intr(ntb->device, current_int->res,
747250079Scarl			    current_int->tag);
748250079Scarl
749250079Scarl		if (current_int->res != NULL)
750250079Scarl			bus_release_resource(ntb->device, SYS_RES_IRQ,
751250079Scarl			    rman_get_rid(current_int->res), current_int->res);
752250079Scarl	}
753250079Scarl
754250079Scarl	ntb_free_callbacks(ntb);
755250079Scarl	pci_release_msi(ntb->device);
756250079Scarl}
757250079Scarl
758289347Scem/*
759289347Scem * Doorbell register and mask are 64-bit on SoC, 16-bit on Xeon.  Abstract it
760289347Scem * out to make code clearer.
761289347Scem */
762289347Scemstatic uint64_t
763289347Scemdb_ioread(struct ntb_softc *ntb, uint32_t regoff)
764289347Scem{
765289347Scem
766289347Scem	if (ntb->type == NTB_SOC)
767289347Scem		return (ntb_reg_read(8, regoff));
768289347Scem
769289347Scem	KASSERT(ntb->type == NTB_XEON, ("bad ntb type"));
770289347Scem
771289347Scem	return (ntb_reg_read(2, regoff));
772289347Scem}
773289347Scem
774250079Scarlstatic void
775289347Scemdb_iowrite(struct ntb_softc *ntb, uint32_t regoff, uint64_t val)
776289347Scem{
777289347Scem
778289347Scem	if (ntb->type == NTB_SOC) {
779289347Scem		ntb_reg_write(8, regoff, val);
780289347Scem		return;
781289347Scem	}
782289347Scem
783289347Scem	KASSERT(ntb->type == NTB_XEON, ("bad ntb type"));
784289347Scem	ntb_reg_write(2, regoff, (uint16_t)val);
785289347Scem}
786289347Scem
787289347Scemstatic void
788289281Scemmask_ldb_interrupt(struct ntb_softc *ntb, unsigned int idx)
789289281Scem{
790289347Scem	uint64_t mask;
791289281Scem
792289347Scem	mask = db_ioread(ntb, ntb->reg_ofs.ldb_mask);
793289281Scem	mask |= 1 << (idx * ntb->bits_per_vector);
794289347Scem	db_iowrite(ntb, ntb->reg_ofs.ldb_mask, mask);
795289281Scem}
796289281Scem
797289281Scemstatic void
798289281Scemunmask_ldb_interrupt(struct ntb_softc *ntb, unsigned int idx)
799289281Scem{
800289347Scem	uint64_t mask;
801289281Scem
802289347Scem	mask = db_ioread(ntb, ntb->reg_ofs.ldb_mask);
803289281Scem	mask &= ~(1 << (idx * ntb->bits_per_vector));
804289347Scem	db_iowrite(ntb, ntb->reg_ofs.ldb_mask, mask);
805289281Scem}
806289281Scem
807289281Scemstatic void
808250079Scarlhandle_soc_irq(void *arg)
809250079Scarl{
810250079Scarl	struct ntb_db_cb *db_cb = arg;
811250079Scarl	struct ntb_softc *ntb = db_cb->ntb;
812250079Scarl
813289347Scem	db_iowrite(ntb, ntb->reg_ofs.ldb, (uint64_t) 1 << db_cb->db_num);
814250079Scarl
815289281Scem	if (db_cb->callback != NULL) {
816289281Scem		mask_ldb_interrupt(ntb, db_cb->db_num);
817289281Scem		callout_reset(&db_cb->irq_work, 0, ntb_irq_work, db_cb);
818289281Scem	}
819250079Scarl}
820250079Scarl
821250079Scarlstatic void
822250079Scarlhandle_xeon_irq(void *arg)
823250079Scarl{
824250079Scarl	struct ntb_db_cb *db_cb = arg;
825250079Scarl	struct ntb_softc *ntb = db_cb->ntb;
826250079Scarl
827250079Scarl	/*
828250079Scarl	 * On Xeon, there are 16 bits in the interrupt register
829250079Scarl	 * but only 4 vectors.  So, 5 bits are assigned to the first 3
830250079Scarl	 * vectors, with the 4th having a single bit for link
831250079Scarl	 * interrupts.
832250079Scarl	 */
833289347Scem	db_iowrite(ntb, ntb->reg_ofs.ldb,
834250079Scarl	    ((1 << ntb->bits_per_vector) - 1) <<
835250079Scarl	    (db_cb->db_num * ntb->bits_per_vector));
836250079Scarl
837289281Scem	if (db_cb->callback != NULL) {
838289281Scem		mask_ldb_interrupt(ntb, db_cb->db_num);
839289281Scem		callout_reset(&db_cb->irq_work, 0, ntb_irq_work, db_cb);
840289281Scem	}
841250079Scarl}
842250079Scarl
843250079Scarl/* Since we do not have a HW doorbell in SOC, this is only used in JF/JT */
844250079Scarlstatic void
845250079Scarlhandle_xeon_event_irq(void *arg)
846250079Scarl{
847250079Scarl	struct ntb_softc *ntb = arg;
848250079Scarl	int rc;
849250079Scarl
850250079Scarl	rc = ntb_check_link_status(ntb);
851250079Scarl	if (rc != 0)
852250079Scarl		device_printf(ntb->device, "Error determining link status\n");
853250079Scarl
854250079Scarl	/* bit 15 is always the link bit */
855289538Scem	db_iowrite(ntb, ntb->reg_ofs.ldb, 1 << XEON_DB_LINK);
856250079Scarl}
857250079Scarl
858250079Scarlstatic void
859250079Scarlntb_handle_legacy_interrupt(void *arg)
860250079Scarl{
861250079Scarl	struct ntb_softc *ntb = arg;
862289347Scem	unsigned int i;
863289347Scem	uint64_t ldb;
864250079Scarl
865289347Scem	ldb = db_ioread(ntb, ntb->reg_ofs.ldb);
866250079Scarl
867289538Scem	if (ntb->type == NTB_XEON && (ldb & XEON_DB_LINK_BIT) != 0) {
868289347Scem		handle_xeon_event_irq(ntb);
869289538Scem		ldb &= ~XEON_DB_LINK_BIT;
870289347Scem	}
871289347Scem
872289347Scem	while (ldb != 0) {
873289347Scem		i = ffs(ldb);
874289347Scem		ldb &= ldb - 1;
875289347Scem		if (ntb->type == NTB_SOC)
876250079Scarl			handle_soc_irq(&ntb->db_cb[i]);
877289347Scem		else
878250079Scarl			handle_xeon_irq(&ntb->db_cb[i]);
879250079Scarl	}
880250079Scarl}
881250079Scarl
882250079Scarlstatic int
883289342Scemntb_create_callbacks(struct ntb_softc *ntb, uint32_t num_vectors)
884250079Scarl{
885289342Scem	uint32_t i;
886250079Scarl
887289396Scem	ntb->max_cbs = num_vectors;
888289209Scem	ntb->db_cb = malloc(num_vectors * sizeof(*ntb->db_cb), M_NTB,
889250079Scarl	    M_ZERO | M_WAITOK);
890250079Scarl	for (i = 0; i < num_vectors; i++) {
891250079Scarl		ntb->db_cb[i].db_num = i;
892250079Scarl		ntb->db_cb[i].ntb = ntb;
893250079Scarl	}
894250079Scarl
895250079Scarl	return (0);
896250079Scarl}
897250079Scarl
898250079Scarlstatic void
899250079Scarlntb_free_callbacks(struct ntb_softc *ntb)
900250079Scarl{
901289342Scem	uint8_t i;
902250079Scarl
903289396Scem	for (i = 0; i < ntb->max_cbs; i++)
904250079Scarl		ntb_unregister_db_callback(ntb, i);
905250079Scarl
906250079Scarl	free(ntb->db_cb, M_NTB);
907289396Scem	ntb->max_cbs = 0;
908250079Scarl}
909250079Scarl
910250079Scarlstatic struct ntb_hw_info *
911250079Scarlntb_get_device_info(uint32_t device_id)
912250079Scarl{
913250079Scarl	struct ntb_hw_info *ep = pci_ids;
914250079Scarl
915250079Scarl	while (ep->device_id) {
916250079Scarl		if (ep->device_id == device_id)
917250079Scarl			return (ep);
918250079Scarl		++ep;
919250079Scarl	}
920250079Scarl	return (NULL);
921250079Scarl}
922250079Scarl
923289272Scemstatic void
924289272Scemntb_teardown_xeon(struct ntb_softc *ntb)
925250079Scarl{
926250079Scarl
927289272Scem	ntb_hw_link_down(ntb);
928250079Scarl}
929250079Scarl
930289397Scemstatic void
931289397Scemntb_detect_max_mw(struct ntb_softc *ntb)
932289397Scem{
933289397Scem
934289397Scem	if (ntb->type == NTB_SOC) {
935289397Scem		ntb->limits.max_mw = SOC_MAX_MW;
936289397Scem		return;
937289397Scem	}
938289397Scem
939289397Scem	if (HAS_FEATURE(NTB_SPLIT_BAR))
940289397Scem		ntb->limits.max_mw = XEON_HSXSPLIT_MAX_MW;
941289397Scem	else
942289397Scem		ntb->limits.max_mw = XEON_SNB_MAX_MW;
943289397Scem}
944289397Scem
945250079Scarlstatic int
946289348Scemntb_detect_xeon(struct ntb_softc *ntb)
947250079Scarl{
948289348Scem	uint8_t ppd, conn_type;
949250079Scarl
950289348Scem	ppd = pci_read_config(ntb->device, NTB_PPD_OFFSET, 1);
951289348Scem	ntb->ppd = ppd;
952250079Scarl
953289348Scem	if ((ppd & XEON_PPD_DEV_TYPE) != 0)
954289257Scem		ntb->dev_type = NTB_DEV_USD;
955289257Scem	else
956289257Scem		ntb->dev_type = NTB_DEV_DSD;
957289257Scem
958289397Scem	if ((ppd & XEON_PPD_SPLIT_BAR) != 0)
959289397Scem		ntb->features |= NTB_SPLIT_BAR;
960289397Scem
961289348Scem	conn_type = ppd & XEON_PPD_CONN_TYPE;
962289348Scem	switch (conn_type) {
963289348Scem	case NTB_CONN_B2B:
964289348Scem		ntb->conn_type = conn_type;
965289348Scem		break;
966289348Scem	case NTB_CONN_RP:
967289348Scem	case NTB_CONN_TRANSPARENT:
968289348Scem	default:
969289348Scem		device_printf(ntb->device, "Unsupported connection type: %u\n",
970289348Scem		    (unsigned)conn_type);
971289348Scem		return (ENXIO);
972289348Scem	}
973289348Scem	return (0);
974289348Scem}
975289348Scem
976289348Scemstatic int
977289348Scemntb_detect_soc(struct ntb_softc *ntb)
978289348Scem{
979289348Scem	uint32_t ppd, conn_type;
980289348Scem
981289348Scem	ppd = pci_read_config(ntb->device, NTB_PPD_OFFSET, 4);
982289348Scem	ntb->ppd = ppd;
983289348Scem
984289348Scem	if ((ppd & SOC_PPD_DEV_TYPE) != 0)
985289348Scem		ntb->dev_type = NTB_DEV_DSD;
986289348Scem	else
987289348Scem		ntb->dev_type = NTB_DEV_USD;
988289348Scem
989289348Scem	conn_type = (ppd & SOC_PPD_CONN_TYPE) >> 8;
990289348Scem	switch (conn_type) {
991289348Scem	case NTB_CONN_B2B:
992289348Scem		ntb->conn_type = conn_type;
993289348Scem		break;
994289348Scem	default:
995289348Scem		device_printf(ntb->device, "Unsupported NTB configuration\n");
996289348Scem		return (ENXIO);
997289348Scem	}
998289348Scem	return (0);
999289348Scem}
1000289348Scem
1001289348Scemstatic int
1002289348Scemntb_setup_xeon(struct ntb_softc *ntb)
1003289348Scem{
1004289348Scem
1005289257Scem	ntb->reg_ofs.ldb	= XEON_PDOORBELL_OFFSET;
1006289257Scem	ntb->reg_ofs.ldb_mask	= XEON_PDBMSK_OFFSET;
1007289257Scem	ntb->reg_ofs.spad_local	= XEON_SPAD_OFFSET;
1008289257Scem	ntb->reg_ofs.bar2_xlat	= XEON_SBAR2XLAT_OFFSET;
1009289257Scem	ntb->reg_ofs.bar4_xlat	= XEON_SBAR4XLAT_OFFSET;
1010289397Scem	if (HAS_FEATURE(NTB_SPLIT_BAR))
1011289397Scem		ntb->reg_ofs.bar5_xlat = XEON_SBAR5XLAT_OFFSET;
1012289257Scem
1013289348Scem	switch (ntb->conn_type) {
1014250079Scarl	case NTB_CONN_B2B:
1015289257Scem		/*
1016289257Scem		 * reg_ofs.rdb and reg_ofs.spad_remote are effectively ignored
1017289538Scem		 * with the NTB_SDOORBELL_LOCKUP errata mode enabled.  (See
1018289257Scem		 * ntb_ring_doorbell() and ntb_read/write_remote_spad().)
1019289257Scem		 */
1020289257Scem		ntb->reg_ofs.rdb	 = XEON_B2B_DOORBELL_OFFSET;
1021289257Scem		ntb->reg_ofs.spad_remote = XEON_B2B_SPAD_OFFSET;
1022289257Scem
1023289538Scem		ntb->limits.max_spads	 = XEON_SPAD_COUNT;
1024250079Scarl		break;
1025289257Scem
1026250079Scarl	case NTB_CONN_RP:
1027289257Scem		/*
1028289538Scem		 * Every Xeon today needs NTB_SDOORBELL_LOCKUP, so punt on RP for
1029289257Scem		 * now.
1030289257Scem		 */
1031289538Scem		KASSERT(HAS_FEATURE(NTB_SDOORBELL_LOCKUP),
1032289257Scem		    ("Xeon without MW errata unimplemented"));
1033289257Scem		device_printf(ntb->device,
1034289257Scem		    "NTB-RP disabled to due hardware errata.\n");
1035289257Scem		return (ENXIO);
1036289257Scem
1037289257Scem	case NTB_CONN_TRANSPARENT:
1038250079Scarl	default:
1039250079Scarl		device_printf(ntb->device, "Connection type %d not supported\n",
1040289348Scem		    ntb->conn_type);
1041250079Scarl		return (ENXIO);
1042250079Scarl	}
1043250079Scarl
1044289208Scem	/*
1045289208Scem	 * There is a Xeon hardware errata related to writes to SDOORBELL or
1046289208Scem	 * B2BDOORBELL in conjunction with inbound access to NTB MMIO space,
1047289208Scem	 * which may hang the system.  To workaround this use the second memory
1048289208Scem	 * window to access the interrupt and scratch pad registers on the
1049289208Scem	 * remote system.
1050289274Scem	 *
1051289274Scem	 * There is another HW errata on the limit registers -- they can only
1052289274Scem	 * be written when the base register is (?)4GB aligned and < 32-bit.
1053289274Scem	 * This should already be the case based on the driver defaults, but
1054289274Scem	 * write the limit registers first just in case.
1055289208Scem	 */
1056289538Scem	if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP)) {
1057289208Scem		/*
1058289208Scem		 * Set the Limit register to 4k, the minimum size, to prevent
1059289208Scem		 * an illegal access.
1060289397Scem		 *
1061289397Scem		 * XXX: Should this be PBAR5LMT / get_mw_size(, max_mw - 1)?
1062289208Scem		 */
1063289208Scem		ntb_reg_write(8, XEON_PBAR4LMT_OFFSET,
1064289208Scem		    ntb_get_mw_size(ntb, 1) + 0x1000);
1065289397Scem		/* Reserve the last MW for mapping remote spad */
1066289397Scem		ntb->limits.max_mw--;
1067289396Scem	} else
1068289208Scem		/*
1069289208Scem		 * Disable the limit register, just in case it is set to
1070289397Scem		 * something silly.  A 64-bit write will also clear PBAR5LMT in
1071289397Scem		 * split-bar mode, and this is desired.
1072289208Scem		 */
1073289208Scem		ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, 0);
1074289208Scem
1075289257Scem	ntb->reg_ofs.lnk_cntl	 = XEON_NTBCNTL_OFFSET;
1076289257Scem	ntb->reg_ofs.lnk_stat	 = XEON_LINK_STATUS_OFFSET;
1077289257Scem	ntb->reg_ofs.spci_cmd	 = XEON_PCICMD_OFFSET;
1078250079Scarl
1079289538Scem	ntb->limits.max_db_bits	 = XEON_DB_COUNT;
1080289538Scem	ntb->limits.msix_cnt	 = XEON_DB_MSIX_VECTOR_COUNT;
1081289538Scem	ntb->bits_per_vector	 = XEON_DB_MSIX_VECTOR_SHIFT;
1082250079Scarl
1083289271Scem	/*
1084289271Scem	 * HW Errata on bit 14 of b2bdoorbell register.  Writes will not be
1085289271Scem	 * mirrored to the remote system.  Shrink the number of bits by one,
1086289271Scem	 * since bit 14 is the last bit.
1087289271Scem	 *
1088289271Scem	 * On REGS_THRU_MW errata mode, we don't use the b2bdoorbell register
1089289271Scem	 * anyway.  Nor for non-B2B connection types.
1090289271Scem	 */
1091289271Scem	if (HAS_FEATURE(NTB_B2BDOORBELL_BIT14) &&
1092289538Scem	    !HAS_FEATURE(NTB_SDOORBELL_LOCKUP) &&
1093289348Scem	    ntb->conn_type == NTB_CONN_B2B)
1094289538Scem		ntb->limits.max_db_bits = XEON_DB_COUNT - 1;
1095289271Scem
1096255279Scarl	configure_xeon_secondary_side_bars(ntb);
1097289209Scem
1098250079Scarl	/* Enable Bus Master and Memory Space on the secondary side */
1099289257Scem	if (ntb->conn_type == NTB_CONN_B2B)
1100289257Scem		ntb_reg_write(2, ntb->reg_ofs.spci_cmd,
1101289257Scem		    PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
1102255279Scarl
1103255269Scarl	/* Enable link training */
1104289272Scem	ntb_hw_link_up(ntb);
1105250079Scarl
1106250079Scarl	return (0);
1107250079Scarl}
1108250079Scarl
1109250079Scarlstatic int
1110250079Scarlntb_setup_soc(struct ntb_softc *ntb)
1111250079Scarl{
1112250079Scarl
1113289348Scem	KASSERT(ntb->conn_type == NTB_CONN_B2B,
1114289348Scem	    ("Unsupported NTB configuration (%d)\n", ntb->conn_type));
1115250079Scarl
1116250079Scarl	/* Initiate PCI-E link training */
1117289348Scem	pci_write_config(ntb->device, NTB_PPD_OFFSET,
1118289348Scem	    ntb->ppd | SOC_PPD_INIT_LINK, 4);
1119250079Scarl
1120289255Scem	ntb->reg_ofs.ldb	 = SOC_PDOORBELL_OFFSET;
1121289255Scem	ntb->reg_ofs.ldb_mask	 = SOC_PDBMSK_OFFSET;
1122289265Scem	ntb->reg_ofs.rdb	 = SOC_B2B_DOORBELL_OFFSET;
1123289255Scem	ntb->reg_ofs.bar2_xlat	 = SOC_SBAR2XLAT_OFFSET;
1124289255Scem	ntb->reg_ofs.bar4_xlat	 = SOC_SBAR4XLAT_OFFSET;
1125250079Scarl	ntb->reg_ofs.lnk_cntl	 = SOC_NTBCNTL_OFFSET;
1126250079Scarl	ntb->reg_ofs.lnk_stat	 = SOC_LINK_STATUS_OFFSET;
1127250079Scarl	ntb->reg_ofs.spad_local	 = SOC_SPAD_OFFSET;
1128289265Scem	ntb->reg_ofs.spad_remote = SOC_B2B_SPAD_OFFSET;
1129250079Scarl	ntb->reg_ofs.spci_cmd	 = SOC_PCICMD_OFFSET;
1130250079Scarl
1131289538Scem	ntb->limits.max_spads	 = SOC_SPAD_COUNT;
1132289538Scem	ntb->limits.max_db_bits	 = SOC_DB_COUNT;
1133289538Scem	ntb->limits.msix_cnt	 = SOC_DB_MSIX_VECTOR_COUNT;
1134289538Scem	ntb->bits_per_vector	 = SOC_DB_MSIX_VECTOR_SHIFT;
1135250079Scarl
1136250079Scarl	/*
1137250079Scarl	 * FIXME - MSI-X bug on early SOC HW, remove once internal issue is
1138250079Scarl	 * resolved.  Mask transaction layer internal parity errors.
1139250079Scarl	 */
1140250079Scarl	pci_write_config(ntb->device, 0xFC, 0x4, 4);
1141250079Scarl
1142255279Scarl	configure_soc_secondary_side_bars(ntb);
1143250079Scarl
1144250079Scarl	/* Enable Bus Master and Memory Space on the secondary side */
1145255278Scarl	ntb_reg_write(2, ntb->reg_ofs.spci_cmd,
1146250079Scarl	    PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
1147289209Scem
1148250079Scarl	callout_reset(&ntb->heartbeat_timer, 0, ntb_handle_heartbeat, ntb);
1149250079Scarl
1150250079Scarl	return (0);
1151250079Scarl}
1152250079Scarl
1153255279Scarlstatic void
1154255279Scarlconfigure_soc_secondary_side_bars(struct ntb_softc *ntb)
1155255279Scarl{
1156255279Scarl
1157255279Scarl	if (ntb->dev_type == NTB_DEV_USD) {
1158289538Scem		ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET,
1159289538Scem		    XEON_B2B_BAR2_DSD_ADDR);
1160289538Scem		ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, XEON_B2B_BAR4_DSD_ADDR);
1161289538Scem		ntb_reg_write(8, SOC_MBAR23_OFFSET, XEON_B2B_BAR2_USD_ADDR);
1162289538Scem		ntb_reg_write(8, SOC_MBAR45_OFFSET, XEON_B2B_BAR4_USD_ADDR);
1163255279Scarl	} else {
1164289538Scem		ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET,
1165289538Scem		    XEON_B2B_BAR2_USD_ADDR);
1166289538Scem		ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, XEON_B2B_BAR4_USD_ADDR);
1167289538Scem		ntb_reg_write(8, SOC_MBAR23_OFFSET, XEON_B2B_BAR2_DSD_ADDR);
1168289538Scem		ntb_reg_write(8, SOC_MBAR45_OFFSET, XEON_B2B_BAR4_DSD_ADDR);
1169255279Scarl	}
1170255279Scarl}
1171255279Scarl
1172255279Scarlstatic void
1173255279Scarlconfigure_xeon_secondary_side_bars(struct ntb_softc *ntb)
1174255279Scarl{
1175255279Scarl
1176255279Scarl	if (ntb->dev_type == NTB_DEV_USD) {
1177289538Scem		ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET,
1178289538Scem		    XEON_B2B_BAR2_DSD_ADDR);
1179289538Scem		if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP))
1180255279Scarl			ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
1181289538Scem			    XEON_B2B_BAR0_DSD_ADDR);
1182289208Scem		else {
1183289397Scem			if (HAS_FEATURE(NTB_SPLIT_BAR)) {
1184289397Scem				ntb_reg_write(4, XEON_PBAR4XLAT_OFFSET,
1185289538Scem				    XEON_B2B_BAR4_DSD_ADDR);
1186289397Scem				ntb_reg_write(4, XEON_PBAR5XLAT_OFFSET,
1187289538Scem				    XEON_B2B_BAR5_DSD_ADDR);
1188289397Scem			} else
1189289397Scem				ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
1190289538Scem				    XEON_B2B_BAR4_DSD_ADDR);
1191289208Scem			/*
1192289208Scem			 * B2B_XLAT_OFFSET is a 64-bit register but can only be
1193289208Scem			 * written 32 bits at a time.
1194289208Scem			 */
1195289208Scem			ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL,
1196289538Scem			    XEON_B2B_BAR0_DSD_ADDR & 0xffffffff);
1197289208Scem			ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU,
1198289538Scem			    XEON_B2B_BAR0_DSD_ADDR >> 32);
1199289208Scem		}
1200289538Scem		ntb_reg_write(8, XEON_SBAR0BASE_OFFSET,
1201289538Scem		    XEON_B2B_BAR0_USD_ADDR);
1202289538Scem		ntb_reg_write(8, XEON_SBAR2BASE_OFFSET,
1203289538Scem		    XEON_B2B_BAR2_USD_ADDR);
1204289397Scem		if (HAS_FEATURE(NTB_SPLIT_BAR)) {
1205289538Scem			ntb_reg_write(4, XEON_SBAR4BASE_OFFSET,
1206289538Scem			    XEON_B2B_BAR4_USD_ADDR);
1207289538Scem			ntb_reg_write(4, XEON_SBAR5BASE_OFFSET,
1208289538Scem			    XEON_B2B_BAR5_USD_ADDR);
1209289397Scem		} else
1210289538Scem			ntb_reg_write(8, XEON_SBAR4BASE_OFFSET,
1211289538Scem			    XEON_B2B_BAR4_USD_ADDR);
1212255279Scarl	} else {
1213289538Scem		ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET,
1214289538Scem		    XEON_B2B_BAR2_USD_ADDR);
1215289538Scem		if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP))
1216255279Scarl			ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
1217289538Scem			    XEON_B2B_BAR0_USD_ADDR);
1218289208Scem		else {
1219289397Scem			if (HAS_FEATURE(NTB_SPLIT_BAR)) {
1220289397Scem				ntb_reg_write(4, XEON_PBAR4XLAT_OFFSET,
1221289538Scem				    XEON_B2B_BAR4_USD_ADDR);
1222289397Scem				ntb_reg_write(4, XEON_PBAR5XLAT_OFFSET,
1223289538Scem				    XEON_B2B_BAR5_USD_ADDR);
1224289397Scem			} else
1225289397Scem				ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
1226289538Scem				    XEON_B2B_BAR4_USD_ADDR);
1227289208Scem			/*
1228289208Scem			 * B2B_XLAT_OFFSET is a 64-bit register but can only be
1229289208Scem			 * written 32 bits at a time.
1230289208Scem			 */
1231289208Scem			ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL,
1232289538Scem			    XEON_B2B_BAR0_USD_ADDR & 0xffffffff);
1233289208Scem			ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU,
1234289538Scem			    XEON_B2B_BAR0_USD_ADDR >> 32);
1235289208Scem		}
1236289538Scem		ntb_reg_write(8, XEON_SBAR0BASE_OFFSET,
1237289538Scem		    XEON_B2B_BAR0_DSD_ADDR);
1238289538Scem		ntb_reg_write(8, XEON_SBAR2BASE_OFFSET,
1239289538Scem		    XEON_B2B_BAR2_DSD_ADDR);
1240289397Scem		if (HAS_FEATURE(NTB_SPLIT_BAR)) {
1241289397Scem			ntb_reg_write(4, XEON_SBAR4BASE_OFFSET,
1242289538Scem			    XEON_B2B_BAR4_DSD_ADDR);
1243289397Scem			ntb_reg_write(4, XEON_SBAR5BASE_OFFSET,
1244289538Scem			    XEON_B2B_BAR5_DSD_ADDR);
1245289397Scem		} else
1246289397Scem			ntb_reg_write(8, XEON_SBAR4BASE_OFFSET,
1247289538Scem			    XEON_B2B_BAR4_DSD_ADDR);
1248255279Scarl	}
1249255279Scarl}
1250255279Scarl
1251255281Scarl/* SOC does not have link status interrupt, poll on that platform */
1252250079Scarlstatic void
1253250079Scarlntb_handle_heartbeat(void *arg)
1254250079Scarl{
1255250079Scarl	struct ntb_softc *ntb = arg;
1256250079Scarl	uint32_t status32;
1257289209Scem	int rc;
1258250079Scarl
1259289209Scem	rc = ntb_check_link_status(ntb);
1260250079Scarl	if (rc != 0)
1261250079Scarl		device_printf(ntb->device,
1262250079Scarl		    "Error determining link status\n");
1263289232Scem
1264250079Scarl	/* Check to see if a link error is the cause of the link down */
1265250079Scarl	if (ntb->link_status == NTB_LINK_DOWN) {
1266255278Scarl		status32 = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET);
1267250079Scarl		if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0) {
1268250079Scarl			callout_reset(&ntb->lr_timer, 0, recover_soc_link,
1269250079Scarl			    ntb);
1270250079Scarl			return;
1271250079Scarl		}
1272250079Scarl	}
1273250079Scarl
1274250079Scarl	callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz,
1275250079Scarl	    ntb_handle_heartbeat, ntb);
1276250079Scarl}
1277250079Scarl
1278250079Scarlstatic void
1279250079Scarlsoc_perform_link_restart(struct ntb_softc *ntb)
1280250079Scarl{
1281250079Scarl	uint32_t status;
1282250079Scarl
1283250079Scarl	/* Driver resets the NTB ModPhy lanes - magic! */
1284255278Scarl	ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0xe0);
1285255278Scarl	ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x40);
1286255278Scarl	ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x60);
1287255278Scarl	ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0x60);
1288250079Scarl
1289250079Scarl	/* Driver waits 100ms to allow the NTB ModPhy to settle */
1290250079Scarl	pause("ModPhy", hz / 10);
1291250079Scarl
1292250079Scarl	/* Clear AER Errors, write to clear */
1293255278Scarl	status = ntb_reg_read(4, SOC_ERRCORSTS_OFFSET);
1294250079Scarl	status &= PCIM_AER_COR_REPLAY_ROLLOVER;
1295255278Scarl	ntb_reg_write(4, SOC_ERRCORSTS_OFFSET, status);
1296250079Scarl
1297250079Scarl	/* Clear unexpected electrical idle event in LTSSM, write to clear */
1298255278Scarl	status = ntb_reg_read(4, SOC_LTSSMERRSTS0_OFFSET);
1299250079Scarl	status |= SOC_LTSSMERRSTS0_UNEXPECTEDEI;
1300255278Scarl	ntb_reg_write(4, SOC_LTSSMERRSTS0_OFFSET, status);
1301250079Scarl
1302250079Scarl	/* Clear DeSkew Buffer error, write to clear */
1303255278Scarl	status = ntb_reg_read(4, SOC_DESKEWSTS_OFFSET);
1304250079Scarl	status |= SOC_DESKEWSTS_DBERR;
1305255278Scarl	ntb_reg_write(4, SOC_DESKEWSTS_OFFSET, status);
1306250079Scarl
1307255278Scarl	status = ntb_reg_read(4, SOC_IBSTERRRCRVSTS0_OFFSET);
1308250079Scarl	status &= SOC_IBIST_ERR_OFLOW;
1309255278Scarl	ntb_reg_write(4, SOC_IBSTERRRCRVSTS0_OFFSET, status);
1310250079Scarl
1311250079Scarl	/* Releases the NTB state machine to allow the link to retrain */
1312255278Scarl	status = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET);
1313250079Scarl	status &= ~SOC_LTSSMSTATEJMP_FORCEDETECT;
1314255278Scarl	ntb_reg_write(4, SOC_LTSSMSTATEJMP_OFFSET, status);
1315250079Scarl}
1316250079Scarl
1317250079Scarlstatic void
1318250079Scarlntb_handle_link_event(struct ntb_softc *ntb, int link_state)
1319250079Scarl{
1320250079Scarl	enum ntb_hw_event event;
1321250079Scarl	uint16_t status;
1322250079Scarl
1323250079Scarl	if (ntb->link_status == link_state)
1324250079Scarl		return;
1325250079Scarl
1326250079Scarl	if (link_state == NTB_LINK_UP) {
1327250079Scarl		device_printf(ntb->device, "Link Up\n");
1328250079Scarl		ntb->link_status = NTB_LINK_UP;
1329250079Scarl		event = NTB_EVENT_HW_LINK_UP;
1330250079Scarl
1331289257Scem		if (ntb->type == NTB_SOC ||
1332289257Scem		    ntb->conn_type == NTB_CONN_TRANSPARENT)
1333255278Scarl			status = ntb_reg_read(2, ntb->reg_ofs.lnk_stat);
1334250079Scarl		else
1335250079Scarl			status = pci_read_config(ntb->device,
1336250079Scarl			    XEON_LINK_STATUS_OFFSET, 2);
1337250079Scarl		ntb->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4;
1338250079Scarl		ntb->link_speed = (status & NTB_LINK_SPEED_MASK);
1339250079Scarl		device_printf(ntb->device, "Link Width %d, Link Speed %d\n",
1340250079Scarl		    ntb->link_width, ntb->link_speed);
1341250079Scarl		callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz,
1342250079Scarl		    ntb_handle_heartbeat, ntb);
1343250079Scarl	} else {
1344250079Scarl		device_printf(ntb->device, "Link Down\n");
1345250079Scarl		ntb->link_status = NTB_LINK_DOWN;
1346250079Scarl		event = NTB_EVENT_HW_LINK_DOWN;
1347255281Scarl		/* Do not modify link width/speed, we need it in link recovery */
1348250079Scarl	}
1349250079Scarl
1350250079Scarl	/* notify the upper layer if we have an event change */
1351250079Scarl	if (ntb->event_cb != NULL)
1352250079Scarl		ntb->event_cb(ntb->ntb_transport, event);
1353250079Scarl}
1354250079Scarl
1355250079Scarlstatic void
1356289272Scemntb_hw_link_up(struct ntb_softc *ntb)
1357289272Scem{
1358289280Scem	uint32_t cntl;
1359289272Scem
1360289280Scem	if (ntb->conn_type == NTB_CONN_TRANSPARENT) {
1361289272Scem		ntb_handle_link_event(ntb, NTB_LINK_UP);
1362289280Scem		return;
1363289280Scem	}
1364289280Scem
1365289280Scem	cntl = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl);
1366289280Scem	cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK);
1367289280Scem	cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP;
1368289397Scem	cntl |= NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP;
1369289397Scem	if (HAS_FEATURE(NTB_SPLIT_BAR))
1370289397Scem		cntl |= NTB_CNTL_P2S_BAR5_SNOOP | NTB_CNTL_S2P_BAR5_SNOOP;
1371289280Scem	ntb_reg_write(4, ntb->reg_ofs.lnk_cntl, cntl);
1372289272Scem}
1373289272Scem
1374289272Scemstatic void
1375289272Scemntb_hw_link_down(struct ntb_softc *ntb)
1376289272Scem{
1377289272Scem	uint32_t cntl;
1378289272Scem
1379289272Scem	if (ntb->conn_type == NTB_CONN_TRANSPARENT) {
1380289272Scem		ntb_handle_link_event(ntb, NTB_LINK_DOWN);
1381289272Scem		return;
1382289272Scem	}
1383289272Scem
1384289272Scem	cntl = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl);
1385289280Scem	cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP);
1386289397Scem	cntl &= ~(NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP);
1387289397Scem	if (HAS_FEATURE(NTB_SPLIT_BAR))
1388289397Scem		cntl &= ~(NTB_CNTL_P2S_BAR5_SNOOP | NTB_CNTL_S2P_BAR5_SNOOP);
1389289280Scem	cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK;
1390289272Scem	ntb_reg_write(4, ntb->reg_ofs.lnk_cntl, cntl);
1391289272Scem}
1392289272Scem
1393289272Scemstatic void
1394250079Scarlrecover_soc_link(void *arg)
1395250079Scarl{
1396250079Scarl	struct ntb_softc *ntb = arg;
1397250079Scarl	uint8_t speed, width;
1398250079Scarl	uint32_t status32;
1399250079Scarl	uint16_t status16;
1400250079Scarl
1401250079Scarl	soc_perform_link_restart(ntb);
1402250079Scarl
1403289232Scem	/*
1404289232Scem	 * There is a potential race between the 2 NTB devices recovering at
1405289232Scem	 * the same time.  If the times are the same, the link will not recover
1406289232Scem	 * and the driver will be stuck in this loop forever.  Add a random
1407289232Scem	 * interval to the recovery time to prevent this race.
1408289232Scem	 */
1409289232Scem	status32 = arc4random() % SOC_LINK_RECOVERY_TIME;
1410289232Scem	pause("Link", (SOC_LINK_RECOVERY_TIME + status32) * hz / 1000);
1411289232Scem
1412255278Scarl	status32 = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET);
1413250079Scarl	if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0)
1414250079Scarl		goto retry;
1415250079Scarl
1416255278Scarl	status32 = ntb_reg_read(4, SOC_IBSTERRRCRVSTS0_OFFSET);
1417250079Scarl	if ((status32 & SOC_IBIST_ERR_OFLOW) != 0)
1418250079Scarl		goto retry;
1419250079Scarl
1420289232Scem	status32 = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl);
1421289232Scem	if ((status32 & SOC_CNTL_LINK_DOWN) != 0)
1422289232Scem		goto out;
1423289232Scem
1424255278Scarl	status16 = ntb_reg_read(2, ntb->reg_ofs.lnk_stat);
1425250079Scarl	width = (status16 & NTB_LINK_WIDTH_MASK) >> 4;
1426250079Scarl	speed = (status16 & NTB_LINK_SPEED_MASK);
1427250079Scarl	if (ntb->link_width != width || ntb->link_speed != speed)
1428250079Scarl		goto retry;
1429250079Scarl
1430289232Scemout:
1431250079Scarl	callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz,
1432250079Scarl	    ntb_handle_heartbeat, ntb);
1433250079Scarl	return;
1434250079Scarl
1435250079Scarlretry:
1436250079Scarl	callout_reset(&ntb->lr_timer, NTB_HB_TIMEOUT * hz, recover_soc_link,
1437250079Scarl	    ntb);
1438250079Scarl}
1439250079Scarl
1440250079Scarlstatic int
1441250079Scarlntb_check_link_status(struct ntb_softc *ntb)
1442250079Scarl{
1443250079Scarl	int link_state;
1444250079Scarl	uint32_t ntb_cntl;
1445250079Scarl	uint16_t status;
1446250079Scarl
1447250079Scarl	if (ntb->type == NTB_SOC) {
1448255278Scarl		ntb_cntl = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl);
1449250079Scarl		if ((ntb_cntl & SOC_CNTL_LINK_DOWN) != 0)
1450250079Scarl			link_state = NTB_LINK_DOWN;
1451250079Scarl		else
1452250079Scarl			link_state = NTB_LINK_UP;
1453250079Scarl	} else {
1454250079Scarl		status = pci_read_config(ntb->device, XEON_LINK_STATUS_OFFSET,
1455250079Scarl		    2);
1456250079Scarl
1457250079Scarl		if ((status & NTB_LINK_STATUS_ACTIVE) != 0)
1458250079Scarl			link_state = NTB_LINK_UP;
1459250079Scarl		else
1460250079Scarl			link_state = NTB_LINK_DOWN;
1461250079Scarl	}
1462250079Scarl
1463250079Scarl	ntb_handle_link_event(ntb, link_state);
1464250079Scarl
1465250079Scarl	return (0);
1466250079Scarl}
1467250079Scarl
1468250079Scarl/**
1469250079Scarl * ntb_register_event_callback() - register event callback
1470250079Scarl * @ntb: pointer to ntb_softc instance
1471250079Scarl * @func: callback function to register
1472250079Scarl *
1473250079Scarl * This function registers a callback for any HW driver events such as link
1474250079Scarl * up/down, power management notices and etc.
1475250079Scarl *
1476289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success.
1477250079Scarl */
1478250079Scarlint
1479250079Scarlntb_register_event_callback(struct ntb_softc *ntb, ntb_event_callback func)
1480250079Scarl{
1481250079Scarl
1482250079Scarl	if (ntb->event_cb != NULL)
1483250079Scarl		return (EINVAL);
1484250079Scarl
1485250079Scarl	ntb->event_cb = func;
1486250079Scarl
1487250079Scarl	return (0);
1488250079Scarl}
1489250079Scarl
1490250079Scarl/**
1491250079Scarl * ntb_unregister_event_callback() - unregisters the event callback
1492250079Scarl * @ntb: pointer to ntb_softc instance
1493250079Scarl *
1494250079Scarl * This function unregisters the existing callback from transport
1495250079Scarl */
1496250079Scarlvoid
1497250079Scarlntb_unregister_event_callback(struct ntb_softc *ntb)
1498250079Scarl{
1499250079Scarl
1500250079Scarl	ntb->event_cb = NULL;
1501250079Scarl}
1502250079Scarl
1503289281Scemstatic void
1504289281Scemntb_irq_work(void *arg)
1505289281Scem{
1506289281Scem	struct ntb_db_cb *db_cb = arg;
1507289281Scem	struct ntb_softc *ntb;
1508289281Scem	int rc;
1509289281Scem
1510289281Scem	rc = db_cb->callback(db_cb->data, db_cb->db_num);
1511289281Scem	/* Poll if forward progress was made. */
1512289281Scem	if (rc != 0) {
1513289281Scem		callout_reset(&db_cb->irq_work, 0, ntb_irq_work, db_cb);
1514289281Scem		return;
1515289281Scem	}
1516289281Scem
1517289281Scem	/* Unmask interrupt if no progress was made. */
1518289281Scem	ntb = db_cb->ntb;
1519289281Scem	unmask_ldb_interrupt(ntb, db_cb->db_num);
1520289281Scem}
1521289281Scem
1522250079Scarl/**
1523250079Scarl * ntb_register_db_callback() - register a callback for doorbell interrupt
1524250079Scarl * @ntb: pointer to ntb_softc instance
1525250079Scarl * @idx: doorbell index to register callback, zero based
1526289266Scem * @data: pointer to be returned to caller with every callback
1527250079Scarl * @func: callback function to register
1528250079Scarl *
1529250079Scarl * This function registers a callback function for the doorbell interrupt
1530250079Scarl * on the primary side. The function will unmask the doorbell as well to
1531250079Scarl * allow interrupt.
1532250079Scarl *
1533289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success.
1534250079Scarl */
1535250079Scarlint
1536250079Scarlntb_register_db_callback(struct ntb_softc *ntb, unsigned int idx, void *data,
1537250079Scarl    ntb_db_callback func)
1538250079Scarl{
1539289343Scem	struct ntb_db_cb *db_cb = &ntb->db_cb[idx];
1540250079Scarl
1541289396Scem	if (idx >= ntb->max_cbs || db_cb->callback != NULL || db_cb->reserved) {
1542250079Scarl		device_printf(ntb->device, "Invalid Index.\n");
1543250079Scarl		return (EINVAL);
1544250079Scarl	}
1545250079Scarl
1546289343Scem	db_cb->callback = func;
1547289343Scem	db_cb->data = data;
1548289343Scem	callout_init(&db_cb->irq_work, 1);
1549250079Scarl
1550289281Scem	unmask_ldb_interrupt(ntb, idx);
1551250079Scarl
1552250079Scarl	return (0);
1553250079Scarl}
1554250079Scarl
1555250079Scarl/**
1556250079Scarl * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt
1557250079Scarl * @ntb: pointer to ntb_softc instance
1558250079Scarl * @idx: doorbell index to register callback, zero based
1559250079Scarl *
1560250079Scarl * This function unregisters a callback function for the doorbell interrupt
1561250079Scarl * on the primary side. The function will also mask the said doorbell.
1562250079Scarl */
1563250079Scarlvoid
1564250079Scarlntb_unregister_db_callback(struct ntb_softc *ntb, unsigned int idx)
1565250079Scarl{
1566250079Scarl
1567289396Scem	if (idx >= ntb->max_cbs || ntb->db_cb[idx].callback == NULL)
1568250079Scarl		return;
1569250079Scarl
1570289281Scem	mask_ldb_interrupt(ntb, idx);
1571250079Scarl
1572289281Scem	callout_drain(&ntb->db_cb[idx].irq_work);
1573250079Scarl	ntb->db_cb[idx].callback = NULL;
1574250079Scarl}
1575250079Scarl
1576250079Scarl/**
1577250079Scarl * ntb_find_transport() - find the transport pointer
1578250079Scarl * @transport: pointer to pci device
1579250079Scarl *
1580250079Scarl * Given the pci device pointer, return the transport pointer passed in when
1581250079Scarl * the transport attached when it was inited.
1582250079Scarl *
1583250079Scarl * RETURNS: pointer to transport.
1584250079Scarl */
1585250079Scarlvoid *
1586250079Scarlntb_find_transport(struct ntb_softc *ntb)
1587250079Scarl{
1588250079Scarl
1589250079Scarl	return (ntb->ntb_transport);
1590250079Scarl}
1591250079Scarl
1592250079Scarl/**
1593250079Scarl * ntb_register_transport() - Register NTB transport with NTB HW driver
1594250079Scarl * @transport: transport identifier
1595250079Scarl *
1596250079Scarl * This function allows a transport to reserve the hardware driver for
1597250079Scarl * NTB usage.
1598250079Scarl *
1599250079Scarl * RETURNS: pointer to ntb_softc, NULL on error.
1600250079Scarl */
1601250079Scarlstruct ntb_softc *
1602250079Scarlntb_register_transport(struct ntb_softc *ntb, void *transport)
1603250079Scarl{
1604250079Scarl
1605250079Scarl	/*
1606250079Scarl	 * TODO: when we have more than one transport, we will need to rewrite
1607250079Scarl	 * this to prevent race conditions
1608250079Scarl	 */
1609250079Scarl	if (ntb->ntb_transport != NULL)
1610250079Scarl		return (NULL);
1611250079Scarl
1612250079Scarl	ntb->ntb_transport = transport;
1613250079Scarl	return (ntb);
1614250079Scarl}
1615250079Scarl
1616250079Scarl/**
1617250079Scarl * ntb_unregister_transport() - Unregister the transport with the NTB HW driver
1618250079Scarl * @ntb - ntb_softc of the transport to be freed
1619250079Scarl *
1620250079Scarl * This function unregisters the transport from the HW driver and performs any
1621250079Scarl * necessary cleanups.
1622250079Scarl */
1623250079Scarlvoid
1624250079Scarlntb_unregister_transport(struct ntb_softc *ntb)
1625250079Scarl{
1626289396Scem	uint8_t i;
1627250079Scarl
1628250079Scarl	if (ntb->ntb_transport == NULL)
1629250079Scarl		return;
1630250079Scarl
1631289396Scem	for (i = 0; i < ntb->max_cbs; i++)
1632250079Scarl		ntb_unregister_db_callback(ntb, i);
1633250079Scarl
1634250079Scarl	ntb_unregister_event_callback(ntb);
1635250079Scarl	ntb->ntb_transport = NULL;
1636250079Scarl}
1637250079Scarl
1638250079Scarl/**
1639250079Scarl * ntb_get_max_spads() - get the total scratch regs usable
1640250079Scarl * @ntb: pointer to ntb_softc instance
1641250079Scarl *
1642250079Scarl * This function returns the max 32bit scratchpad registers usable by the
1643250079Scarl * upper layer.
1644250079Scarl *
1645250079Scarl * RETURNS: total number of scratch pad registers available
1646250079Scarl */
1647289208Scemuint8_t
1648250079Scarlntb_get_max_spads(struct ntb_softc *ntb)
1649250079Scarl{
1650250079Scarl
1651250079Scarl	return (ntb->limits.max_spads);
1652250079Scarl}
1653250079Scarl
1654289396Scemuint8_t
1655289396Scemntb_get_max_cbs(struct ntb_softc *ntb)
1656289396Scem{
1657289396Scem
1658289396Scem	return (ntb->max_cbs);
1659289396Scem}
1660289396Scem
1661289396Scemuint8_t
1662289396Scemntb_get_max_mw(struct ntb_softc *ntb)
1663289396Scem{
1664289396Scem
1665289396Scem	return (ntb->limits.max_mw);
1666289396Scem}
1667289396Scem
1668250079Scarl/**
1669250079Scarl * ntb_write_local_spad() - write to the secondary scratchpad register
1670250079Scarl * @ntb: pointer to ntb_softc instance
1671250079Scarl * @idx: index to the scratchpad register, 0 based
1672250079Scarl * @val: the data value to put into the register
1673250079Scarl *
1674250079Scarl * This function allows writing of a 32bit value to the indexed scratchpad
1675250079Scarl * register. The register resides on the secondary (external) side.
1676250079Scarl *
1677289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success.
1678250079Scarl */
1679250079Scarlint
1680250079Scarlntb_write_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val)
1681250079Scarl{
1682250079Scarl
1683250079Scarl	if (idx >= ntb->limits.max_spads)
1684250079Scarl		return (EINVAL);
1685250079Scarl
1686255278Scarl	ntb_reg_write(4, ntb->reg_ofs.spad_local + idx * 4, val);
1687250079Scarl
1688250079Scarl	return (0);
1689250079Scarl}
1690250079Scarl
1691250079Scarl/**
1692250079Scarl * ntb_read_local_spad() - read from the primary scratchpad register
1693250079Scarl * @ntb: pointer to ntb_softc instance
1694250079Scarl * @idx: index to scratchpad register, 0 based
1695250079Scarl * @val: pointer to 32bit integer for storing the register value
1696250079Scarl *
1697250079Scarl * This function allows reading of the 32bit scratchpad register on
1698250079Scarl * the primary (internal) side.
1699250079Scarl *
1700289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success.
1701250079Scarl */
1702250079Scarlint
1703250079Scarlntb_read_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val)
1704250079Scarl{
1705250079Scarl
1706250079Scarl	if (idx >= ntb->limits.max_spads)
1707250079Scarl		return (EINVAL);
1708250079Scarl
1709255278Scarl	*val = ntb_reg_read(4, ntb->reg_ofs.spad_local + idx * 4);
1710250079Scarl
1711250079Scarl	return (0);
1712250079Scarl}
1713250079Scarl
1714250079Scarl/**
1715250079Scarl * ntb_write_remote_spad() - write to the secondary scratchpad register
1716250079Scarl * @ntb: pointer to ntb_softc instance
1717250079Scarl * @idx: index to the scratchpad register, 0 based
1718250079Scarl * @val: the data value to put into the register
1719250079Scarl *
1720250079Scarl * This function allows writing of a 32bit value to the indexed scratchpad
1721250079Scarl * register. The register resides on the secondary (external) side.
1722250079Scarl *
1723289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success.
1724250079Scarl */
1725250079Scarlint
1726250079Scarlntb_write_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val)
1727250079Scarl{
1728250079Scarl
1729250079Scarl	if (idx >= ntb->limits.max_spads)
1730250079Scarl		return (EINVAL);
1731250079Scarl
1732289538Scem	if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP))
1733255279Scarl		ntb_mw_write(4, XEON_SHADOW_SPAD_OFFSET + idx * 4, val);
1734255279Scarl	else
1735255279Scarl		ntb_reg_write(4, ntb->reg_ofs.spad_remote + idx * 4, val);
1736250079Scarl
1737250079Scarl	return (0);
1738250079Scarl}
1739250079Scarl
1740250079Scarl/**
1741250079Scarl * ntb_read_remote_spad() - read from the primary scratchpad register
1742250079Scarl * @ntb: pointer to ntb_softc instance
1743250079Scarl * @idx: index to scratchpad register, 0 based
1744250079Scarl * @val: pointer to 32bit integer for storing the register value
1745250079Scarl *
1746250079Scarl * This function allows reading of the 32bit scratchpad register on
1747250079Scarl * the primary (internal) side.
1748250079Scarl *
1749289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success.
1750250079Scarl */
1751250079Scarlint
1752250079Scarlntb_read_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val)
1753250079Scarl{
1754250079Scarl
1755250079Scarl	if (idx >= ntb->limits.max_spads)
1756250079Scarl		return (EINVAL);
1757250079Scarl
1758289538Scem	if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP))
1759255279Scarl		*val = ntb_mw_read(4, XEON_SHADOW_SPAD_OFFSET + idx * 4);
1760255279Scarl	else
1761255279Scarl		*val = ntb_reg_read(4, ntb->reg_ofs.spad_remote + idx * 4);
1762250079Scarl
1763250079Scarl	return (0);
1764250079Scarl}
1765250079Scarl
1766250079Scarl/**
1767250079Scarl * ntb_get_mw_vbase() - get virtual addr for the NTB memory window
1768250079Scarl * @ntb: pointer to ntb_softc instance
1769250079Scarl * @mw: memory window number
1770250079Scarl *
1771250079Scarl * This function provides the base virtual address of the memory window
1772250079Scarl * specified.
1773250079Scarl *
1774250079Scarl * RETURNS: pointer to virtual address, or NULL on error.
1775250079Scarl */
1776250079Scarlvoid *
1777250079Scarlntb_get_mw_vbase(struct ntb_softc *ntb, unsigned int mw)
1778250079Scarl{
1779250079Scarl
1780289396Scem	if (mw >= ntb_get_max_mw(ntb))
1781250079Scarl		return (NULL);
1782250079Scarl
1783250079Scarl	return (ntb->bar_info[NTB_MW_TO_BAR(mw)].vbase);
1784250079Scarl}
1785250079Scarl
1786250079Scarlvm_paddr_t
1787250079Scarlntb_get_mw_pbase(struct ntb_softc *ntb, unsigned int mw)
1788250079Scarl{
1789250079Scarl
1790289396Scem	if (mw >= ntb_get_max_mw(ntb))
1791250079Scarl		return (0);
1792250079Scarl
1793250079Scarl	return (ntb->bar_info[NTB_MW_TO_BAR(mw)].pbase);
1794250079Scarl}
1795250079Scarl
1796250079Scarl/**
1797250079Scarl * ntb_get_mw_size() - return size of NTB memory window
1798250079Scarl * @ntb: pointer to ntb_softc instance
1799250079Scarl * @mw: memory window number
1800250079Scarl *
1801250079Scarl * This function provides the physical size of the memory window specified
1802250079Scarl *
1803250079Scarl * RETURNS: the size of the memory window or zero on error
1804250079Scarl */
1805250079Scarlu_long
1806250079Scarlntb_get_mw_size(struct ntb_softc *ntb, unsigned int mw)
1807250079Scarl{
1808250079Scarl
1809289396Scem	if (mw >= ntb_get_max_mw(ntb))
1810250079Scarl		return (0);
1811250079Scarl
1812250079Scarl	return (ntb->bar_info[NTB_MW_TO_BAR(mw)].size);
1813250079Scarl}
1814250079Scarl
1815250079Scarl/**
1816250079Scarl * ntb_set_mw_addr - set the memory window address
1817250079Scarl * @ntb: pointer to ntb_softc instance
1818250079Scarl * @mw: memory window number
1819250079Scarl * @addr: base address for data
1820250079Scarl *
1821250079Scarl * This function sets the base physical address of the memory window.  This
1822250079Scarl * memory address is where data from the remote system will be transfered into
1823250079Scarl * or out of depending on how the transport is configured.
1824250079Scarl */
1825250079Scarlvoid
1826250079Scarlntb_set_mw_addr(struct ntb_softc *ntb, unsigned int mw, uint64_t addr)
1827250079Scarl{
1828250079Scarl
1829289396Scem	if (mw >= ntb_get_max_mw(ntb))
1830250079Scarl		return;
1831250079Scarl
1832250079Scarl	switch (NTB_MW_TO_BAR(mw)) {
1833250079Scarl	case NTB_B2B_BAR_1:
1834289255Scem		ntb_reg_write(8, ntb->reg_ofs.bar2_xlat, addr);
1835250079Scarl		break;
1836250079Scarl	case NTB_B2B_BAR_2:
1837289397Scem		if (HAS_FEATURE(NTB_SPLIT_BAR))
1838289397Scem			ntb_reg_write(4, ntb->reg_ofs.bar4_xlat, addr);
1839289397Scem		else
1840289397Scem			ntb_reg_write(8, ntb->reg_ofs.bar4_xlat, addr);
1841250079Scarl		break;
1842289397Scem	case NTB_B2B_BAR_3:
1843289397Scem		ntb_reg_write(4, ntb->reg_ofs.bar5_xlat, addr);
1844289397Scem		break;
1845250079Scarl	}
1846250079Scarl}
1847250079Scarl
1848250079Scarl/**
1849289255Scem * ntb_ring_doorbell() - Set the doorbell on the secondary/external side
1850250079Scarl * @ntb: pointer to ntb_softc instance
1851250079Scarl * @db: doorbell to ring
1852250079Scarl *
1853250079Scarl * This function allows triggering of a doorbell on the secondary/external
1854250079Scarl * side that will initiate an interrupt on the remote host
1855250079Scarl */
1856250079Scarlvoid
1857289255Scemntb_ring_doorbell(struct ntb_softc *ntb, unsigned int db)
1858250079Scarl{
1859289347Scem	uint64_t bit;
1860250079Scarl
1861250079Scarl	if (ntb->type == NTB_SOC)
1862289347Scem		bit = 1 << db;
1863289347Scem	else
1864289347Scem		bit = ((1 << ntb->bits_per_vector) - 1) <<
1865289347Scem		    (db * ntb->bits_per_vector);
1866289347Scem
1867289538Scem	if (HAS_FEATURE(NTB_SDOORBELL_LOCKUP)) {
1868289347Scem		ntb_mw_write(2, XEON_SHADOW_PDOORBELL_OFFSET, bit);
1869289347Scem		return;
1870289209Scem	}
1871289347Scem
1872289347Scem	db_iowrite(ntb, ntb->reg_ofs.rdb, bit);
1873250079Scarl}
1874250079Scarl
1875250079Scarl/**
1876250079Scarl * ntb_query_link_status() - return the hardware link status
1877250079Scarl * @ndev: pointer to ntb_device instance
1878250079Scarl *
1879250079Scarl * Returns true if the hardware is connected to the remote system
1880250079Scarl *
1881250079Scarl * RETURNS: true or false based on the hardware link state
1882250079Scarl */
1883250079Scarlbool
1884250079Scarlntb_query_link_status(struct ntb_softc *ntb)
1885250079Scarl{
1886250079Scarl
1887250079Scarl	return (ntb->link_status == NTB_LINK_UP);
1888250079Scarl}
1889250079Scarl
1890255272Scarlstatic void
1891255272Scarlsave_bar_parameters(struct ntb_pci_bar_info *bar)
1892250079Scarl{
1893255272Scarl
1894289209Scem	bar->pci_bus_tag = rman_get_bustag(bar->pci_resource);
1895289209Scem	bar->pci_bus_handle = rman_get_bushandle(bar->pci_resource);
1896289209Scem	bar->pbase = rman_get_start(bar->pci_resource);
1897289209Scem	bar->size = rman_get_size(bar->pci_resource);
1898289209Scem	bar->vbase = rman_get_virtual(bar->pci_resource);
1899250079Scarl}
1900255268Scarl
1901289209Scemdevice_t
1902289209Scemntb_get_device(struct ntb_softc *ntb)
1903255268Scarl{
1904255268Scarl
1905255268Scarl	return (ntb->device);
1906255268Scarl}
1907289208Scem
1908289208Scem/* Export HW-specific errata information. */
1909289208Scembool
1910289208Scemntb_has_feature(struct ntb_softc *ntb, uint64_t feature)
1911289208Scem{
1912289208Scem
1913289208Scem	return (HAS_FEATURE(feature));
1914289208Scem}
1915