ntb_hw_intel.c revision 289232
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 289232 2015-10-13 17:20:47Z 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
65250079Scarl#define NTB_MAX_BARS	3
66250079Scarl#define NTB_MW_TO_BAR(mw) ((mw) + 1)
67250079Scarl
68250079Scarl#define MAX_MSIX_INTERRUPTS MAX(XEON_MAX_DB_BITS, SOC_MAX_DB_BITS)
69250079Scarl
70250079Scarl#define NTB_HB_TIMEOUT	1 /* second */
71250079Scarl#define SOC_LINK_RECOVERY_TIME	500
72250079Scarl
73250079Scarl#define DEVICE2SOFTC(dev) ((struct ntb_softc *) device_get_softc(dev))
74250079Scarl
75250079Scarlenum ntb_device_type {
76250079Scarl	NTB_XEON,
77250079Scarl	NTB_SOC
78250079Scarl};
79250079Scarl
80255274Scarl/* Device features and workarounds */
81255274Scarl#define HAS_FEATURE(feature)	\
82255274Scarl	((ntb->features & (feature)) != 0)
83255274Scarl
84250079Scarlstruct ntb_hw_info {
85250079Scarl	uint32_t		device_id;
86255274Scarl	const char		*desc;
87250079Scarl	enum ntb_device_type	type;
88255274Scarl	uint64_t		features;
89250079Scarl};
90250079Scarl
91250079Scarlstruct ntb_pci_bar_info {
92250079Scarl	bus_space_tag_t		pci_bus_tag;
93250079Scarl	bus_space_handle_t	pci_bus_handle;
94250079Scarl	int			pci_resource_id;
95250079Scarl	struct resource		*pci_resource;
96250079Scarl	vm_paddr_t		pbase;
97250079Scarl	void			*vbase;
98250079Scarl	u_long			size;
99250079Scarl};
100250079Scarl
101250079Scarlstruct ntb_int_info {
102250079Scarl	struct resource	*res;
103250079Scarl	int		rid;
104250079Scarl	void		*tag;
105250079Scarl};
106250079Scarl
107250079Scarlstruct ntb_db_cb {
108250079Scarl	ntb_db_callback		callback;
109250079Scarl	unsigned int		db_num;
110250079Scarl	void			*data;
111250079Scarl	struct ntb_softc	*ntb;
112250079Scarl};
113250079Scarl
114250079Scarlstruct ntb_softc {
115250079Scarl	device_t		device;
116250079Scarl	enum ntb_device_type	type;
117255274Scarl	uint64_t		features;
118250079Scarl
119250079Scarl	struct ntb_pci_bar_info	bar_info[NTB_MAX_BARS];
120250079Scarl	struct ntb_int_info	int_info[MAX_MSIX_INTERRUPTS];
121250079Scarl	uint32_t		allocated_interrupts;
122250079Scarl
123250079Scarl	struct callout		heartbeat_timer;
124250079Scarl	struct callout		lr_timer;
125250079Scarl
126250079Scarl	void			*ntb_transport;
127250079Scarl	ntb_event_callback	event_cb;
128250079Scarl	struct ntb_db_cb 	*db_cb;
129250079Scarl
130250079Scarl	struct {
131289208Scem		uint8_t max_spads;
132289208Scem		uint8_t max_db_bits;
133289208Scem		uint8_t msix_cnt;
134250079Scarl	} limits;
135250079Scarl	struct {
136250079Scarl		uint32_t pdb;
137250079Scarl		uint32_t pdb_mask;
138250079Scarl		uint32_t sdb;
139250079Scarl		uint32_t sbar2_xlat;
140250079Scarl		uint32_t sbar4_xlat;
141250079Scarl		uint32_t spad_remote;
142250079Scarl		uint32_t spad_local;
143250079Scarl		uint32_t lnk_cntl;
144250079Scarl		uint32_t lnk_stat;
145250079Scarl		uint32_t spci_cmd;
146250079Scarl	} reg_ofs;
147250079Scarl	uint8_t conn_type;
148250079Scarl	uint8_t dev_type;
149250079Scarl	uint8_t bits_per_vector;
150250079Scarl	uint8_t link_status;
151250079Scarl	uint8_t link_width;
152250079Scarl	uint8_t link_speed;
153250079Scarl};
154250079Scarl
155255279Scarl#define ntb_bar_read(SIZE, bar, offset) \
156255279Scarl	    bus_space_read_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \
157255279Scarl	    ntb->bar_info[(bar)].pci_bus_handle, (offset))
158255279Scarl#define ntb_bar_write(SIZE, bar, offset, val) \
159255279Scarl	    bus_space_write_ ## SIZE (ntb->bar_info[(bar)].pci_bus_tag, \
160255279Scarl	    ntb->bar_info[(bar)].pci_bus_handle, (offset), (val))
161255279Scarl#define ntb_reg_read(SIZE, offset) ntb_bar_read(SIZE, NTB_CONFIG_BAR, offset)
162250079Scarl#define ntb_reg_write(SIZE, offset, val) \
163255279Scarl	    ntb_bar_write(SIZE, NTB_CONFIG_BAR, offset, val)
164255279Scarl#define ntb_mw_read(SIZE, offset) ntb_bar_read(SIZE, NTB_B2B_BAR_2, offset)
165255279Scarl#define ntb_mw_write(SIZE, offset, val) \
166255279Scarl	    ntb_bar_write(SIZE, NTB_B2B_BAR_2, offset, val)
167250079Scarl
168255272Scarltypedef int (*bar_map_strategy)(struct ntb_softc *ntb,
169255272Scarl    struct ntb_pci_bar_info *bar);
170255272Scarl
171250079Scarlstatic int ntb_probe(device_t device);
172250079Scarlstatic int ntb_attach(device_t device);
173250079Scarlstatic int ntb_detach(device_t device);
174255272Scarlstatic int ntb_map_pci_bars(struct ntb_softc *ntb);
175255272Scarlstatic int map_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy,
176255272Scarl    struct ntb_pci_bar_info *bar);
177255272Scarlstatic int map_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar);
178255272Scarlstatic int map_memory_window_bar(struct ntb_softc *ntb,
179255272Scarl    struct ntb_pci_bar_info *bar);
180250079Scarlstatic void ntb_unmap_pci_bar(struct ntb_softc *ntb);
181250079Scarlstatic int ntb_setup_interrupts(struct ntb_softc *ntb);
182250079Scarlstatic void ntb_teardown_interrupts(struct ntb_softc *ntb);
183250079Scarlstatic void handle_soc_irq(void *arg);
184250079Scarlstatic void handle_xeon_irq(void *arg);
185250079Scarlstatic void handle_xeon_event_irq(void *arg);
186250079Scarlstatic void ntb_handle_legacy_interrupt(void *arg);
187250079Scarlstatic int ntb_create_callbacks(struct ntb_softc *ntb, int num_vectors);
188250079Scarlstatic void ntb_free_callbacks(struct ntb_softc *ntb);
189250079Scarlstatic struct ntb_hw_info *ntb_get_device_info(uint32_t device_id);
190250079Scarlstatic int ntb_initialize_hw(struct ntb_softc *ntb);
191250079Scarlstatic int ntb_setup_xeon(struct ntb_softc *ntb);
192250079Scarlstatic int ntb_setup_soc(struct ntb_softc *ntb);
193255279Scarlstatic void configure_soc_secondary_side_bars(struct ntb_softc *ntb);
194255279Scarlstatic void configure_xeon_secondary_side_bars(struct ntb_softc *ntb);
195250079Scarlstatic void ntb_handle_heartbeat(void *arg);
196250079Scarlstatic void ntb_handle_link_event(struct ntb_softc *ntb, int link_state);
197250079Scarlstatic void recover_soc_link(void *arg);
198250079Scarlstatic int ntb_check_link_status(struct ntb_softc *ntb);
199255274Scarlstatic void save_bar_parameters(struct ntb_pci_bar_info *bar);
200250079Scarl
201250079Scarlstatic struct ntb_hw_info pci_ids[] = {
202255274Scarl	{ 0x3C0D8086, "Xeon E5/Core i7 Non-Transparent Bridge B2B", NTB_XEON,
203255274Scarl	    NTB_REGS_THRU_MW },
204255274Scarl	{ 0x0C4E8086, "Atom Processor S1200 NTB Primary B2B", NTB_SOC, 0 },
205255274Scarl	{ 0x0E0D8086, "Xeon E5 V2 Non-Transparent Bridge B2B", NTB_XEON,
206255274Scarl	    NTB_REGS_THRU_MW | NTB_BAR_SIZE_4K },
207255274Scarl	{ 0x00000000, NULL, NTB_SOC, 0 }
208250079Scarl};
209250079Scarl
210250079Scarl/*
211250079Scarl * OS <-> Driver interface structures
212250079Scarl */
213250079ScarlMALLOC_DEFINE(M_NTB, "ntb_hw", "ntb_hw driver memory allocations");
214250079Scarl
215250079Scarlstatic device_method_t ntb_pci_methods[] = {
216250079Scarl	/* Device interface */
217250079Scarl	DEVMETHOD(device_probe,     ntb_probe),
218250079Scarl	DEVMETHOD(device_attach,    ntb_attach),
219250079Scarl	DEVMETHOD(device_detach,    ntb_detach),
220250079Scarl	DEVMETHOD_END
221250079Scarl};
222250079Scarl
223250079Scarlstatic driver_t ntb_pci_driver = {
224250079Scarl	"ntb_hw",
225250079Scarl	ntb_pci_methods,
226250079Scarl	sizeof(struct ntb_softc),
227250079Scarl};
228250079Scarl
229250079Scarlstatic devclass_t ntb_devclass;
230250079ScarlDRIVER_MODULE(ntb_hw, pci, ntb_pci_driver, ntb_devclass, NULL, NULL);
231250079ScarlMODULE_VERSION(ntb_hw, 1);
232250079Scarl
233289207ScemSYSCTL_NODE(_hw, OID_AUTO, ntb, CTLFLAG_RW, 0, "NTB sysctls");
234289207Scem
235250079Scarl/*
236250079Scarl * OS <-> Driver linkage functions
237250079Scarl */
238250079Scarlstatic int
239250079Scarlntb_probe(device_t device)
240250079Scarl{
241289209Scem	struct ntb_hw_info *p;
242250079Scarl
243289209Scem	p = ntb_get_device_info(pci_get_devid(device));
244289209Scem	if (p == NULL)
245250079Scarl		return (ENXIO);
246289209Scem
247289209Scem	device_set_desc(device, p->desc);
248289209Scem	return (0);
249250079Scarl}
250250079Scarl
251250079Scarlstatic int
252250079Scarlntb_attach(device_t device)
253250079Scarl{
254289209Scem	struct ntb_softc *ntb;
255289209Scem	struct ntb_hw_info *p;
256250079Scarl	int error;
257250079Scarl
258289209Scem	ntb = DEVICE2SOFTC(device);
259289209Scem	p = ntb_get_device_info(pci_get_devid(device));
260289209Scem
261250079Scarl	ntb->device = device;
262250079Scarl	ntb->type = p->type;
263255274Scarl	ntb->features = p->features;
264250079Scarl
265250079Scarl	/* Heartbeat timer for NTB_SOC since there is no link interrupt */
266283291Sjkim	callout_init(&ntb->heartbeat_timer, 1);
267283291Sjkim	callout_init(&ntb->lr_timer, 1);
268250079Scarl
269289209Scem	error = ntb_map_pci_bars(ntb);
270289209Scem	if (error)
271289209Scem		goto out;
272289209Scem	error = ntb_initialize_hw(ntb);
273289209Scem	if (error)
274289209Scem		goto out;
275289209Scem	error = ntb_setup_interrupts(ntb);
276289209Scem	if (error)
277289209Scem		goto out;
278250079Scarl
279250079Scarl	pci_enable_busmaster(ntb->device);
280250079Scarl
281289209Scemout:
282289209Scem	if (error != 0)
283289209Scem		ntb_detach(device);
284250079Scarl	return (error);
285250079Scarl}
286250079Scarl
287250079Scarlstatic int
288250079Scarlntb_detach(device_t device)
289250079Scarl{
290289209Scem	struct ntb_softc *ntb;
291250079Scarl
292289209Scem	ntb = DEVICE2SOFTC(device);
293250079Scarl	callout_drain(&ntb->heartbeat_timer);
294250079Scarl	callout_drain(&ntb->lr_timer);
295250079Scarl	ntb_teardown_interrupts(ntb);
296250079Scarl	ntb_unmap_pci_bar(ntb);
297250079Scarl
298250079Scarl	return (0);
299250079Scarl}
300250079Scarl
301250079Scarlstatic int
302255272Scarlntb_map_pci_bars(struct ntb_softc *ntb)
303250079Scarl{
304255272Scarl	int rc;
305250079Scarl
306250079Scarl	ntb->bar_info[NTB_CONFIG_BAR].pci_resource_id = PCIR_BAR(0);
307255272Scarl	rc = map_pci_bar(ntb, map_mmr_bar, &ntb->bar_info[NTB_CONFIG_BAR]);
308255272Scarl	if (rc != 0)
309289209Scem		return (rc);
310255272Scarl
311289209Scem	ntb->bar_info[NTB_B2B_BAR_1].pci_resource_id = PCIR_BAR(2);
312255272Scarl	rc = map_pci_bar(ntb, map_memory_window_bar,
313255272Scarl	    &ntb->bar_info[NTB_B2B_BAR_1]);
314255272Scarl	if (rc != 0)
315289209Scem		return (rc);
316255272Scarl
317289209Scem	ntb->bar_info[NTB_B2B_BAR_2].pci_resource_id = PCIR_BAR(4);
318255279Scarl	if (HAS_FEATURE(NTB_REGS_THRU_MW))
319255279Scarl		rc = map_pci_bar(ntb, map_mmr_bar,
320255279Scarl		    &ntb->bar_info[NTB_B2B_BAR_2]);
321255279Scarl	else
322255279Scarl		rc = map_pci_bar(ntb, map_memory_window_bar,
323255279Scarl		    &ntb->bar_info[NTB_B2B_BAR_2]);
324289209Scem	return (rc);
325255272Scarl}
326250079Scarl
327255272Scarlstatic int
328255272Scarlmap_pci_bar(struct ntb_softc *ntb, bar_map_strategy strategy,
329255272Scarl    struct ntb_pci_bar_info *bar)
330255272Scarl{
331255272Scarl	int rc;
332255272Scarl
333255272Scarl	rc = strategy(ntb, bar);
334289209Scem	if (rc != 0)
335255272Scarl		device_printf(ntb->device,
336255272Scarl		    "unable to allocate pci resource\n");
337289209Scem	else
338255279Scarl		device_printf(ntb->device,
339255272Scarl		    "Bar size = %lx, v %p, p %p\n",
340289209Scem		    bar->size, bar->vbase, (void *)(bar->pbase));
341255272Scarl	return (rc);
342255272Scarl}
343255272Scarl
344255272Scarlstatic int
345255272Scarlmap_mmr_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar)
346255272Scarl{
347255272Scarl
348255275Scarl	bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY,
349289209Scem	    &bar->pci_resource_id, RF_ACTIVE);
350255272Scarl	if (bar->pci_resource == NULL)
351255272Scarl		return (ENXIO);
352289209Scem
353289209Scem	save_bar_parameters(bar);
354289209Scem	return (0);
355255272Scarl}
356255272Scarl
357255272Scarlstatic int
358255272Scarlmap_memory_window_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar)
359255272Scarl{
360255272Scarl	int rc;
361255276Scarl	uint8_t bar_size_bits = 0;
362255272Scarl
363289209Scem	bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY,
364289209Scem	    &bar->pci_resource_id, RF_ACTIVE);
365250079Scarl
366255272Scarl	if (bar->pci_resource == NULL)
367255272Scarl		return (ENXIO);
368255276Scarl
369289209Scem	save_bar_parameters(bar);
370289209Scem	/*
371289209Scem	 * Ivytown NTB BAR sizes are misreported by the hardware due to a
372289209Scem	 * hardware issue. To work around this, query the size it should be
373289209Scem	 * configured to by the device and modify the resource to correspond to
374289209Scem	 * this new size. The BIOS on systems with this problem is required to
375289209Scem	 * provide enough address space to allow the driver to make this change
376289209Scem	 * safely.
377289209Scem	 *
378289209Scem	 * Ideally I could have just specified the size when I allocated the
379289209Scem	 * resource like:
380289209Scem	 *  bus_alloc_resource(ntb->device,
381289209Scem	 *	SYS_RES_MEMORY, &bar->pci_resource_id, 0ul, ~0ul,
382289209Scem	 *	1ul << bar_size_bits, RF_ACTIVE);
383289209Scem	 * but the PCI driver does not honor the size in this call, so we have
384289209Scem	 * to modify it after the fact.
385289209Scem	 */
386289209Scem	if (HAS_FEATURE(NTB_BAR_SIZE_4K)) {
387289209Scem		if (bar->pci_resource_id == PCIR_BAR(2))
388289209Scem			bar_size_bits = pci_read_config(ntb->device,
389289209Scem			    XEON_PBAR23SZ_OFFSET, 1);
390289209Scem		else
391289209Scem			bar_size_bits = pci_read_config(ntb->device,
392289209Scem			    XEON_PBAR45SZ_OFFSET, 1);
393289209Scem
394289209Scem		rc = bus_adjust_resource(ntb->device, SYS_RES_MEMORY,
395289209Scem		    bar->pci_resource, bar->pbase,
396289209Scem		    bar->pbase + (1ul << bar_size_bits) - 1);
397255272Scarl		if (rc != 0) {
398289209Scem			device_printf(ntb->device,
399289209Scem			    "unable to resize bar\n");
400255272Scarl			return (rc);
401250079Scarl		}
402289209Scem
403289209Scem		save_bar_parameters(bar);
404250079Scarl	}
405289209Scem
406289209Scem	/* Mark bar region as write combining to improve performance. */
407289209Scem	rc = pmap_change_attr((vm_offset_t)bar->vbase, bar->size,
408289209Scem	    VM_MEMATTR_WRITE_COMBINING);
409289209Scem	if (rc != 0) {
410289209Scem		device_printf(ntb->device,
411289209Scem		    "unable to mark bar as WRITE_COMBINING\n");
412289209Scem		return (rc);
413289209Scem	}
414250079Scarl	return (0);
415250079Scarl}
416250079Scarl
417250079Scarlstatic void
418250079Scarlntb_unmap_pci_bar(struct ntb_softc *ntb)
419250079Scarl{
420250079Scarl	struct ntb_pci_bar_info *current_bar;
421250079Scarl	int i;
422250079Scarl
423250079Scarl	for (i = 0; i< NTB_MAX_BARS; i++) {
424250079Scarl		current_bar = &ntb->bar_info[i];
425250079Scarl		if (current_bar->pci_resource != NULL)
426250079Scarl			bus_release_resource(ntb->device, SYS_RES_MEMORY,
427250079Scarl			    current_bar->pci_resource_id,
428250079Scarl			    current_bar->pci_resource);
429250079Scarl	}
430250079Scarl}
431250079Scarl
432250079Scarlstatic int
433250079Scarlntb_setup_interrupts(struct ntb_softc *ntb)
434250079Scarl{
435250079Scarl	void (*interrupt_handler)(void *);
436250079Scarl	void *int_arg;
437289209Scem	bool use_msix = false;
438250079Scarl	uint32_t num_vectors;
439250079Scarl	int i;
440250079Scarl
441250079Scarl	ntb->allocated_interrupts = 0;
442250079Scarl	/*
443250079Scarl	 * On SOC, disable all interrupts.  On XEON, disable all but Link
444250079Scarl	 * Interrupt.  The rest will be unmasked as callbacks are registered.
445250079Scarl	 */
446250079Scarl	if (ntb->type == NTB_SOC)
447255278Scarl		ntb_reg_write(8, ntb->reg_ofs.pdb_mask, ~0);
448250079Scarl	else
449255278Scarl		ntb_reg_write(2, ntb->reg_ofs.pdb_mask,
450250079Scarl		    ~(1 << ntb->limits.max_db_bits));
451250079Scarl
452250079Scarl	num_vectors = MIN(pci_msix_count(ntb->device),
453250079Scarl	    ntb->limits.max_db_bits);
454250079Scarl	if (num_vectors >= 1) {
455250079Scarl		pci_alloc_msix(ntb->device, &num_vectors);
456250079Scarl		if (num_vectors >= 4)
457289209Scem			use_msix = true;
458250079Scarl	}
459250079Scarl
460250079Scarl	ntb_create_callbacks(ntb, num_vectors);
461289209Scem	if (use_msix == true) {
462250079Scarl		for (i = 0; i < num_vectors; i++) {
463250079Scarl			ntb->int_info[i].rid = i + 1;
464250079Scarl			ntb->int_info[i].res = bus_alloc_resource_any(
465250079Scarl			    ntb->device, SYS_RES_IRQ, &ntb->int_info[i].rid,
466250079Scarl			    RF_ACTIVE);
467250079Scarl			if (ntb->int_info[i].res == NULL) {
468250079Scarl				device_printf(ntb->device,
469250079Scarl				    "bus_alloc_resource failed\n");
470289209Scem				return (ENOMEM);
471250079Scarl			}
472250079Scarl			ntb->int_info[i].tag = NULL;
473250079Scarl			ntb->allocated_interrupts++;
474250079Scarl			if (ntb->type == NTB_SOC) {
475250079Scarl				interrupt_handler = handle_soc_irq;
476250079Scarl				int_arg = &ntb->db_cb[i];
477250079Scarl			} else {
478250079Scarl				if (i == num_vectors - 1) {
479255279Scarl					interrupt_handler =
480255279Scarl					    handle_xeon_event_irq;
481250079Scarl					int_arg = ntb;
482250079Scarl				} else {
483250079Scarl					interrupt_handler =
484250079Scarl					    handle_xeon_irq;
485250079Scarl					int_arg = &ntb->db_cb[i];
486250079Scarl				}
487250079Scarl			}
488250079Scarl			if (bus_setup_intr(ntb->device, ntb->int_info[i].res,
489250079Scarl			    INTR_MPSAFE | INTR_TYPE_MISC, NULL,
490250079Scarl			    interrupt_handler, int_arg,
491250079Scarl			    &ntb->int_info[i].tag) != 0) {
492250079Scarl				device_printf(ntb->device,
493250079Scarl				    "bus_setup_intr failed\n");
494250079Scarl				return (ENXIO);
495250079Scarl			}
496250079Scarl		}
497289209Scem	} else {
498250079Scarl		ntb->int_info[0].rid = 0;
499255279Scarl		ntb->int_info[0].res = bus_alloc_resource_any(ntb->device,
500255279Scarl		    SYS_RES_IRQ, &ntb->int_info[0].rid, RF_SHAREABLE|RF_ACTIVE);
501250079Scarl		interrupt_handler = ntb_handle_legacy_interrupt;
502250079Scarl		if (ntb->int_info[0].res == NULL) {
503250079Scarl			device_printf(ntb->device,
504250079Scarl			    "bus_alloc_resource failed\n");
505289209Scem			return (ENOMEM);
506250079Scarl		}
507250079Scarl		ntb->int_info[0].tag = NULL;
508250079Scarl		ntb->allocated_interrupts = 1;
509250079Scarl
510250079Scarl		if (bus_setup_intr(ntb->device, ntb->int_info[0].res,
511250079Scarl			INTR_MPSAFE | INTR_TYPE_MISC, NULL,
512250079Scarl			interrupt_handler, ntb, &ntb->int_info[0].tag) != 0) {
513250079Scarl
514250079Scarl			device_printf(ntb->device, "bus_setup_intr failed\n");
515250079Scarl			return (ENXIO);
516250079Scarl		}
517250079Scarl	}
518250079Scarl
519250079Scarl	return (0);
520250079Scarl}
521250079Scarl
522250079Scarlstatic void
523250079Scarlntb_teardown_interrupts(struct ntb_softc *ntb)
524250079Scarl{
525250079Scarl	struct ntb_int_info *current_int;
526250079Scarl	int i;
527250079Scarl
528289209Scem	for (i = 0; i < ntb->allocated_interrupts; i++) {
529250079Scarl		current_int = &ntb->int_info[i];
530250079Scarl		if (current_int->tag != NULL)
531250079Scarl			bus_teardown_intr(ntb->device, current_int->res,
532250079Scarl			    current_int->tag);
533250079Scarl
534250079Scarl		if (current_int->res != NULL)
535250079Scarl			bus_release_resource(ntb->device, SYS_RES_IRQ,
536250079Scarl			    rman_get_rid(current_int->res), current_int->res);
537250079Scarl	}
538250079Scarl
539250079Scarl	ntb_free_callbacks(ntb);
540250079Scarl	pci_release_msi(ntb->device);
541250079Scarl}
542250079Scarl
543250079Scarlstatic void
544250079Scarlhandle_soc_irq(void *arg)
545250079Scarl{
546250079Scarl	struct ntb_db_cb *db_cb = arg;
547250079Scarl	struct ntb_softc *ntb = db_cb->ntb;
548250079Scarl
549255278Scarl	ntb_reg_write(8, ntb->reg_ofs.pdb, (uint64_t) 1 << db_cb->db_num);
550250079Scarl
551250079Scarl	if (db_cb->callback != NULL)
552250079Scarl		db_cb->callback(db_cb->data, db_cb->db_num);
553250079Scarl}
554250079Scarl
555250079Scarlstatic void
556250079Scarlhandle_xeon_irq(void *arg)
557250079Scarl{
558250079Scarl	struct ntb_db_cb *db_cb = arg;
559250079Scarl	struct ntb_softc *ntb = db_cb->ntb;
560250079Scarl
561250079Scarl	/*
562250079Scarl	 * On Xeon, there are 16 bits in the interrupt register
563250079Scarl	 * but only 4 vectors.  So, 5 bits are assigned to the first 3
564250079Scarl	 * vectors, with the 4th having a single bit for link
565250079Scarl	 * interrupts.
566250079Scarl	 */
567255278Scarl	ntb_reg_write(2, ntb->reg_ofs.pdb,
568250079Scarl	    ((1 << ntb->bits_per_vector) - 1) <<
569250079Scarl	    (db_cb->db_num * ntb->bits_per_vector));
570250079Scarl
571250079Scarl	if (db_cb->callback != NULL)
572250079Scarl		db_cb->callback(db_cb->data, db_cb->db_num);
573250079Scarl}
574250079Scarl
575250079Scarl/* Since we do not have a HW doorbell in SOC, this is only used in JF/JT */
576250079Scarlstatic void
577250079Scarlhandle_xeon_event_irq(void *arg)
578250079Scarl{
579250079Scarl	struct ntb_softc *ntb = arg;
580250079Scarl	int rc;
581250079Scarl
582250079Scarl	rc = ntb_check_link_status(ntb);
583250079Scarl	if (rc != 0)
584250079Scarl		device_printf(ntb->device, "Error determining link status\n");
585250079Scarl
586250079Scarl	/* bit 15 is always the link bit */
587255278Scarl	ntb_reg_write(2, ntb->reg_ofs.pdb, 1 << ntb->limits.max_db_bits);
588250079Scarl}
589250079Scarl
590250079Scarlstatic void
591250079Scarlntb_handle_legacy_interrupt(void *arg)
592250079Scarl{
593250079Scarl	struct ntb_softc *ntb = arg;
594250079Scarl	unsigned int i = 0;
595250079Scarl	uint64_t pdb64;
596250079Scarl	uint16_t pdb16;
597250079Scarl
598250079Scarl	if (ntb->type == NTB_SOC) {
599255278Scarl		pdb64 = ntb_reg_read(8, ntb->reg_ofs.pdb);
600250079Scarl
601250079Scarl		while (pdb64) {
602250079Scarl			i = ffs(pdb64);
603250079Scarl			pdb64 &= pdb64 - 1;
604250079Scarl			handle_soc_irq(&ntb->db_cb[i]);
605250079Scarl		}
606250079Scarl	} else {
607255278Scarl		pdb16 = ntb_reg_read(2, ntb->reg_ofs.pdb);
608250079Scarl
609250079Scarl		if ((pdb16 & XEON_DB_HW_LINK) != 0) {
610250079Scarl			handle_xeon_event_irq(ntb);
611250079Scarl			pdb16 &= ~XEON_DB_HW_LINK;
612250079Scarl		}
613250079Scarl
614250079Scarl		while (pdb16 != 0) {
615250079Scarl			i = ffs(pdb16);
616250079Scarl			pdb16 &= pdb16 - 1;
617250079Scarl			handle_xeon_irq(&ntb->db_cb[i]);
618250079Scarl		}
619250079Scarl	}
620250079Scarl
621250079Scarl}
622250079Scarl
623250079Scarlstatic int
624250079Scarlntb_create_callbacks(struct ntb_softc *ntb, int num_vectors)
625250079Scarl{
626250079Scarl	int i;
627250079Scarl
628289209Scem	ntb->db_cb = malloc(num_vectors * sizeof(*ntb->db_cb), M_NTB,
629250079Scarl	    M_ZERO | M_WAITOK);
630250079Scarl	for (i = 0; i < num_vectors; i++) {
631250079Scarl		ntb->db_cb[i].db_num = i;
632250079Scarl		ntb->db_cb[i].ntb = ntb;
633250079Scarl	}
634250079Scarl
635250079Scarl	return (0);
636250079Scarl}
637250079Scarl
638250079Scarlstatic void
639250079Scarlntb_free_callbacks(struct ntb_softc *ntb)
640250079Scarl{
641250079Scarl	int i;
642250079Scarl
643250079Scarl	for (i = 0; i < ntb->limits.max_db_bits; i++)
644250079Scarl		ntb_unregister_db_callback(ntb, i);
645250079Scarl
646250079Scarl	free(ntb->db_cb, M_NTB);
647250079Scarl}
648250079Scarl
649250079Scarlstatic struct ntb_hw_info *
650250079Scarlntb_get_device_info(uint32_t device_id)
651250079Scarl{
652250079Scarl	struct ntb_hw_info *ep = pci_ids;
653250079Scarl
654250079Scarl	while (ep->device_id) {
655250079Scarl		if (ep->device_id == device_id)
656250079Scarl			return (ep);
657250079Scarl		++ep;
658250079Scarl	}
659250079Scarl	return (NULL);
660250079Scarl}
661250079Scarl
662250079Scarlstatic int
663250079Scarlntb_initialize_hw(struct ntb_softc *ntb)
664250079Scarl{
665250079Scarl
666250079Scarl	if (ntb->type == NTB_SOC)
667250079Scarl		return (ntb_setup_soc(ntb));
668250079Scarl	else
669250079Scarl		return (ntb_setup_xeon(ntb));
670250079Scarl}
671250079Scarl
672250079Scarlstatic int
673250079Scarlntb_setup_xeon(struct ntb_softc *ntb)
674250079Scarl{
675250079Scarl	uint8_t val, connection_type;
676250079Scarl
677250079Scarl	val = pci_read_config(ntb->device, NTB_PPD_OFFSET, 1);
678250079Scarl
679250079Scarl	connection_type = val & XEON_PPD_CONN_TYPE;
680250079Scarl	switch (connection_type) {
681250079Scarl	case NTB_CONN_B2B:
682250079Scarl		ntb->conn_type = NTB_CONN_B2B;
683250079Scarl		break;
684250079Scarl	case NTB_CONN_CLASSIC:
685250079Scarl	case NTB_CONN_RP:
686250079Scarl	default:
687250079Scarl		device_printf(ntb->device, "Connection type %d not supported\n",
688250079Scarl		    connection_type);
689250079Scarl		return (ENXIO);
690250079Scarl	}
691250079Scarl
692250079Scarl	if ((val & XEON_PPD_DEV_TYPE) != 0)
693289206Scem		ntb->dev_type = NTB_DEV_USD;
694289206Scem	else
695250079Scarl		ntb->dev_type = NTB_DEV_DSD;
696250079Scarl
697250079Scarl	ntb->reg_ofs.pdb	= XEON_PDOORBELL_OFFSET;
698250079Scarl	ntb->reg_ofs.pdb_mask	= XEON_PDBMSK_OFFSET;
699250079Scarl	ntb->reg_ofs.sbar2_xlat = XEON_SBAR2XLAT_OFFSET;
700250079Scarl	ntb->reg_ofs.sbar4_xlat = XEON_SBAR4XLAT_OFFSET;
701250079Scarl	ntb->reg_ofs.lnk_cntl	= XEON_NTBCNTL_OFFSET;
702250079Scarl	ntb->reg_ofs.lnk_stat	= XEON_LINK_STATUS_OFFSET;
703250079Scarl	ntb->reg_ofs.spad_local	= XEON_SPAD_OFFSET;
704250079Scarl	ntb->reg_ofs.spci_cmd	= XEON_PCICMD_OFFSET;
705250079Scarl
706289208Scem	/*
707289208Scem	 * There is a Xeon hardware errata related to writes to SDOORBELL or
708289208Scem	 * B2BDOORBELL in conjunction with inbound access to NTB MMIO space,
709289208Scem	 * which may hang the system.  To workaround this use the second memory
710289208Scem	 * window to access the interrupt and scratch pad registers on the
711289208Scem	 * remote system.
712289208Scem	 */
713289208Scem	if (HAS_FEATURE(NTB_REGS_THRU_MW))
714289208Scem		/*
715289208Scem		 * Set the Limit register to 4k, the minimum size, to prevent
716289208Scem		 * an illegal access.
717289208Scem		 */
718289208Scem		ntb_reg_write(8, XEON_PBAR4LMT_OFFSET,
719289208Scem		    ntb_get_mw_size(ntb, 1) + 0x1000);
720289208Scem	else
721289208Scem		/*
722289208Scem		 * Disable the limit register, just in case it is set to
723289208Scem		 * something silly.
724289208Scem		 */
725289208Scem		ntb_reg_write(8, XEON_PBAR4LMT_OFFSET, 0);
726289208Scem
727289208Scem
728250079Scarl	if (ntb->conn_type == NTB_CONN_B2B) {
729250079Scarl		ntb->reg_ofs.sdb	 = XEON_B2B_DOORBELL_OFFSET;
730250079Scarl		ntb->reg_ofs.spad_remote = XEON_B2B_SPAD_OFFSET;
731250079Scarl		ntb->limits.max_spads	 = XEON_MAX_SPADS;
732250079Scarl	} else {
733250079Scarl		ntb->reg_ofs.sdb	 = XEON_SDOORBELL_OFFSET;
734250079Scarl		ntb->reg_ofs.spad_remote = XEON_SPAD_OFFSET;
735250079Scarl		ntb->limits.max_spads	 = XEON_MAX_COMPAT_SPADS;
736250079Scarl	}
737250079Scarl
738250079Scarl	ntb->limits.max_db_bits  = XEON_MAX_DB_BITS;
739250079Scarl	ntb->limits.msix_cnt	 = XEON_MSIX_CNT;
740250079Scarl	ntb->bits_per_vector	 = XEON_DB_BITS_PER_VEC;
741250079Scarl
742255279Scarl	configure_xeon_secondary_side_bars(ntb);
743289209Scem
744250079Scarl	/* Enable Bus Master and Memory Space on the secondary side */
745255278Scarl	ntb_reg_write(2, ntb->reg_ofs.spci_cmd,
746250079Scarl	    PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
747255279Scarl
748255269Scarl	/* Enable link training */
749255278Scarl	ntb_reg_write(4, ntb->reg_ofs.lnk_cntl,
750255269Scarl	    NTB_CNTL_BAR23_SNOOP | NTB_CNTL_BAR45_SNOOP);
751250079Scarl
752250079Scarl	return (0);
753250079Scarl}
754250079Scarl
755250079Scarlstatic int
756250079Scarlntb_setup_soc(struct ntb_softc *ntb)
757250079Scarl{
758250079Scarl	uint32_t val, connection_type;
759250079Scarl
760250079Scarl	val = pci_read_config(ntb->device, NTB_PPD_OFFSET, 4);
761250079Scarl
762250079Scarl	connection_type = (val & SOC_PPD_CONN_TYPE) >> 8;
763250079Scarl	switch (connection_type) {
764250079Scarl	case NTB_CONN_B2B:
765250079Scarl		ntb->conn_type = NTB_CONN_B2B;
766250079Scarl		break;
767250079Scarl	case NTB_CONN_RP:
768250079Scarl	default:
769250079Scarl		device_printf(ntb->device, "Connection type %d not supported\n",
770250079Scarl		    connection_type);
771250079Scarl		return (ENXIO);
772250079Scarl	}
773250079Scarl
774250079Scarl	if ((val & SOC_PPD_DEV_TYPE) != 0)
775250079Scarl		ntb->dev_type = NTB_DEV_DSD;
776250079Scarl	else
777250079Scarl		ntb->dev_type = NTB_DEV_USD;
778250079Scarl
779250079Scarl	/* Initiate PCI-E link training */
780250079Scarl	pci_write_config(ntb->device, NTB_PPD_OFFSET, val | SOC_PPD_INIT_LINK,
781250079Scarl	    4);
782250079Scarl
783250079Scarl	ntb->reg_ofs.pdb	 = SOC_PDOORBELL_OFFSET;
784250079Scarl	ntb->reg_ofs.pdb_mask	 = SOC_PDBMSK_OFFSET;
785250079Scarl	ntb->reg_ofs.sbar2_xlat  = SOC_SBAR2XLAT_OFFSET;
786250079Scarl	ntb->reg_ofs.sbar4_xlat  = SOC_SBAR4XLAT_OFFSET;
787250079Scarl	ntb->reg_ofs.lnk_cntl	 = SOC_NTBCNTL_OFFSET;
788250079Scarl	ntb->reg_ofs.lnk_stat	 = SOC_LINK_STATUS_OFFSET;
789250079Scarl	ntb->reg_ofs.spad_local	 = SOC_SPAD_OFFSET;
790250079Scarl	ntb->reg_ofs.spci_cmd	 = SOC_PCICMD_OFFSET;
791250079Scarl
792250079Scarl	if (ntb->conn_type == NTB_CONN_B2B) {
793250079Scarl		ntb->reg_ofs.sdb	 = SOC_B2B_DOORBELL_OFFSET;
794250079Scarl		ntb->reg_ofs.spad_remote = SOC_B2B_SPAD_OFFSET;
795250079Scarl		ntb->limits.max_spads	 = SOC_MAX_SPADS;
796250079Scarl	} else {
797250079Scarl		ntb->reg_ofs.sdb	 = SOC_PDOORBELL_OFFSET;
798250079Scarl		ntb->reg_ofs.spad_remote = SOC_SPAD_OFFSET;
799250079Scarl		ntb->limits.max_spads	 = SOC_MAX_COMPAT_SPADS;
800250079Scarl	}
801250079Scarl
802250079Scarl	ntb->limits.max_db_bits  = SOC_MAX_DB_BITS;
803250079Scarl	ntb->limits.msix_cnt	 = SOC_MSIX_CNT;
804250079Scarl	ntb->bits_per_vector	 = SOC_DB_BITS_PER_VEC;
805250079Scarl
806250079Scarl	/*
807250079Scarl	 * FIXME - MSI-X bug on early SOC HW, remove once internal issue is
808250079Scarl	 * resolved.  Mask transaction layer internal parity errors.
809250079Scarl	 */
810250079Scarl	pci_write_config(ntb->device, 0xFC, 0x4, 4);
811250079Scarl
812255279Scarl	configure_soc_secondary_side_bars(ntb);
813250079Scarl
814250079Scarl	/* Enable Bus Master and Memory Space on the secondary side */
815255278Scarl	ntb_reg_write(2, ntb->reg_ofs.spci_cmd,
816250079Scarl	    PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
817289209Scem
818250079Scarl	callout_reset(&ntb->heartbeat_timer, 0, ntb_handle_heartbeat, ntb);
819250079Scarl
820250079Scarl	return (0);
821250079Scarl}
822250079Scarl
823255279Scarlstatic void
824255279Scarlconfigure_soc_secondary_side_bars(struct ntb_softc *ntb)
825255279Scarl{
826255279Scarl
827255279Scarl	if (ntb->dev_type == NTB_DEV_USD) {
828255279Scarl		ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET, PBAR2XLAT_USD_ADDR);
829255279Scarl		ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, PBAR4XLAT_USD_ADDR);
830255279Scarl		ntb_reg_write(8, SOC_MBAR23_OFFSET, MBAR23_USD_ADDR);
831255279Scarl		ntb_reg_write(8, SOC_MBAR45_OFFSET, MBAR45_USD_ADDR);
832255279Scarl	} else {
833255279Scarl		ntb_reg_write(8, SOC_PBAR2XLAT_OFFSET, PBAR2XLAT_DSD_ADDR);
834255279Scarl		ntb_reg_write(8, SOC_PBAR4XLAT_OFFSET, PBAR4XLAT_DSD_ADDR);
835255279Scarl		ntb_reg_write(8, SOC_MBAR23_OFFSET, MBAR23_DSD_ADDR);
836255279Scarl		ntb_reg_write(8, SOC_MBAR45_OFFSET, MBAR45_DSD_ADDR);
837255279Scarl	}
838255279Scarl}
839255279Scarl
840255279Scarlstatic void
841255279Scarlconfigure_xeon_secondary_side_bars(struct ntb_softc *ntb)
842255279Scarl{
843255279Scarl
844255279Scarl	if (ntb->dev_type == NTB_DEV_USD) {
845255279Scarl		ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, PBAR2XLAT_USD_ADDR);
846255279Scarl		if (HAS_FEATURE(NTB_REGS_THRU_MW))
847255279Scarl			ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
848255279Scarl			    MBAR01_DSD_ADDR);
849289208Scem		else {
850255279Scarl			ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
851255279Scarl			    PBAR4XLAT_USD_ADDR);
852289208Scem			/*
853289208Scem			 * B2B_XLAT_OFFSET is a 64-bit register but can only be
854289208Scem			 * written 32 bits at a time.
855289208Scem			 */
856289208Scem			ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL,
857289208Scem			    MBAR01_DSD_ADDR & 0xffffffff);
858289208Scem			ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU,
859289208Scem			    MBAR01_DSD_ADDR >> 32);
860289208Scem		}
861255279Scarl		ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, MBAR01_USD_ADDR);
862255279Scarl		ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, MBAR23_USD_ADDR);
863255279Scarl		ntb_reg_write(8, XEON_SBAR4BASE_OFFSET, MBAR45_USD_ADDR);
864255279Scarl	} else {
865255279Scarl		ntb_reg_write(8, XEON_PBAR2XLAT_OFFSET, PBAR2XLAT_DSD_ADDR);
866255279Scarl		if (HAS_FEATURE(NTB_REGS_THRU_MW))
867255279Scarl			ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
868255279Scarl			    MBAR01_USD_ADDR);
869289208Scem		else {
870255279Scarl			ntb_reg_write(8, XEON_PBAR4XLAT_OFFSET,
871255279Scarl			    PBAR4XLAT_DSD_ADDR);
872289208Scem			/*
873289208Scem			 * B2B_XLAT_OFFSET is a 64-bit register but can only be
874289208Scem			 * written 32 bits at a time.
875289208Scem			 */
876289208Scem			ntb_reg_write(4, XEON_B2B_XLAT_OFFSETL,
877289208Scem			    MBAR01_USD_ADDR & 0xffffffff);
878289208Scem			ntb_reg_write(4, XEON_B2B_XLAT_OFFSETU,
879289208Scem			    MBAR01_USD_ADDR >> 32);
880289208Scem		}
881255279Scarl		ntb_reg_write(8, XEON_SBAR0BASE_OFFSET, MBAR01_DSD_ADDR);
882255279Scarl		ntb_reg_write(8, XEON_SBAR2BASE_OFFSET, MBAR23_DSD_ADDR);
883255279Scarl		ntb_reg_write(8, XEON_SBAR4BASE_OFFSET, MBAR45_DSD_ADDR);
884255279Scarl	}
885255279Scarl}
886255279Scarl
887255281Scarl/* SOC does not have link status interrupt, poll on that platform */
888250079Scarlstatic void
889250079Scarlntb_handle_heartbeat(void *arg)
890250079Scarl{
891250079Scarl	struct ntb_softc *ntb = arg;
892250079Scarl	uint32_t status32;
893289209Scem	int rc;
894250079Scarl
895289209Scem	rc = ntb_check_link_status(ntb);
896250079Scarl	if (rc != 0)
897250079Scarl		device_printf(ntb->device,
898250079Scarl		    "Error determining link status\n");
899289232Scem
900250079Scarl	/* Check to see if a link error is the cause of the link down */
901250079Scarl	if (ntb->link_status == NTB_LINK_DOWN) {
902255278Scarl		status32 = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET);
903250079Scarl		if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0) {
904250079Scarl			callout_reset(&ntb->lr_timer, 0, recover_soc_link,
905250079Scarl			    ntb);
906250079Scarl			return;
907250079Scarl		}
908250079Scarl	}
909250079Scarl
910250079Scarl	callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz,
911250079Scarl	    ntb_handle_heartbeat, ntb);
912250079Scarl}
913250079Scarl
914250079Scarlstatic void
915250079Scarlsoc_perform_link_restart(struct ntb_softc *ntb)
916250079Scarl{
917250079Scarl	uint32_t status;
918250079Scarl
919250079Scarl	/* Driver resets the NTB ModPhy lanes - magic! */
920255278Scarl	ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0xe0);
921255278Scarl	ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x40);
922255278Scarl	ntb_reg_write(1, SOC_MODPHY_PCSREG4, 0x60);
923255278Scarl	ntb_reg_write(1, SOC_MODPHY_PCSREG6, 0x60);
924250079Scarl
925250079Scarl	/* Driver waits 100ms to allow the NTB ModPhy to settle */
926250079Scarl	pause("ModPhy", hz / 10);
927250079Scarl
928250079Scarl	/* Clear AER Errors, write to clear */
929255278Scarl	status = ntb_reg_read(4, SOC_ERRCORSTS_OFFSET);
930250079Scarl	status &= PCIM_AER_COR_REPLAY_ROLLOVER;
931255278Scarl	ntb_reg_write(4, SOC_ERRCORSTS_OFFSET, status);
932250079Scarl
933250079Scarl	/* Clear unexpected electrical idle event in LTSSM, write to clear */
934255278Scarl	status = ntb_reg_read(4, SOC_LTSSMERRSTS0_OFFSET);
935250079Scarl	status |= SOC_LTSSMERRSTS0_UNEXPECTEDEI;
936255278Scarl	ntb_reg_write(4, SOC_LTSSMERRSTS0_OFFSET, status);
937250079Scarl
938250079Scarl	/* Clear DeSkew Buffer error, write to clear */
939255278Scarl	status = ntb_reg_read(4, SOC_DESKEWSTS_OFFSET);
940250079Scarl	status |= SOC_DESKEWSTS_DBERR;
941255278Scarl	ntb_reg_write(4, SOC_DESKEWSTS_OFFSET, status);
942250079Scarl
943255278Scarl	status = ntb_reg_read(4, SOC_IBSTERRRCRVSTS0_OFFSET);
944250079Scarl	status &= SOC_IBIST_ERR_OFLOW;
945255278Scarl	ntb_reg_write(4, SOC_IBSTERRRCRVSTS0_OFFSET, status);
946250079Scarl
947250079Scarl	/* Releases the NTB state machine to allow the link to retrain */
948255278Scarl	status = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET);
949250079Scarl	status &= ~SOC_LTSSMSTATEJMP_FORCEDETECT;
950255278Scarl	ntb_reg_write(4, SOC_LTSSMSTATEJMP_OFFSET, status);
951250079Scarl}
952250079Scarl
953250079Scarlstatic void
954250079Scarlntb_handle_link_event(struct ntb_softc *ntb, int link_state)
955250079Scarl{
956250079Scarl	enum ntb_hw_event event;
957250079Scarl	uint16_t status;
958250079Scarl
959250079Scarl	if (ntb->link_status == link_state)
960250079Scarl		return;
961250079Scarl
962250079Scarl	if (link_state == NTB_LINK_UP) {
963250079Scarl		device_printf(ntb->device, "Link Up\n");
964250079Scarl		ntb->link_status = NTB_LINK_UP;
965250079Scarl		event = NTB_EVENT_HW_LINK_UP;
966250079Scarl
967250079Scarl		if (ntb->type == NTB_SOC)
968255278Scarl			status = ntb_reg_read(2, ntb->reg_ofs.lnk_stat);
969250079Scarl		else
970250079Scarl			status = pci_read_config(ntb->device,
971250079Scarl			    XEON_LINK_STATUS_OFFSET, 2);
972250079Scarl		ntb->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4;
973250079Scarl		ntb->link_speed = (status & NTB_LINK_SPEED_MASK);
974250079Scarl		device_printf(ntb->device, "Link Width %d, Link Speed %d\n",
975250079Scarl		    ntb->link_width, ntb->link_speed);
976250079Scarl		callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz,
977250079Scarl		    ntb_handle_heartbeat, ntb);
978250079Scarl	} else {
979250079Scarl		device_printf(ntb->device, "Link Down\n");
980250079Scarl		ntb->link_status = NTB_LINK_DOWN;
981250079Scarl		event = NTB_EVENT_HW_LINK_DOWN;
982255281Scarl		/* Do not modify link width/speed, we need it in link recovery */
983250079Scarl	}
984250079Scarl
985250079Scarl	/* notify the upper layer if we have an event change */
986250079Scarl	if (ntb->event_cb != NULL)
987250079Scarl		ntb->event_cb(ntb->ntb_transport, event);
988250079Scarl}
989250079Scarl
990250079Scarlstatic void
991250079Scarlrecover_soc_link(void *arg)
992250079Scarl{
993250079Scarl	struct ntb_softc *ntb = arg;
994250079Scarl	uint8_t speed, width;
995250079Scarl	uint32_t status32;
996250079Scarl	uint16_t status16;
997250079Scarl
998250079Scarl	soc_perform_link_restart(ntb);
999250079Scarl
1000289232Scem	/*
1001289232Scem	 * There is a potential race between the 2 NTB devices recovering at
1002289232Scem	 * the same time.  If the times are the same, the link will not recover
1003289232Scem	 * and the driver will be stuck in this loop forever.  Add a random
1004289232Scem	 * interval to the recovery time to prevent this race.
1005289232Scem	 */
1006289232Scem	status32 = arc4random() % SOC_LINK_RECOVERY_TIME;
1007289232Scem	pause("Link", (SOC_LINK_RECOVERY_TIME + status32) * hz / 1000);
1008289232Scem
1009255278Scarl	status32 = ntb_reg_read(4, SOC_LTSSMSTATEJMP_OFFSET);
1010250079Scarl	if ((status32 & SOC_LTSSMSTATEJMP_FORCEDETECT) != 0)
1011250079Scarl		goto retry;
1012250079Scarl
1013255278Scarl	status32 = ntb_reg_read(4, SOC_IBSTERRRCRVSTS0_OFFSET);
1014250079Scarl	if ((status32 & SOC_IBIST_ERR_OFLOW) != 0)
1015250079Scarl		goto retry;
1016250079Scarl
1017289232Scem	status32 = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl);
1018289232Scem	if ((status32 & SOC_CNTL_LINK_DOWN) != 0)
1019289232Scem		goto out;
1020289232Scem
1021255278Scarl	status16 = ntb_reg_read(2, ntb->reg_ofs.lnk_stat);
1022250079Scarl	width = (status16 & NTB_LINK_WIDTH_MASK) >> 4;
1023250079Scarl	speed = (status16 & NTB_LINK_SPEED_MASK);
1024250079Scarl	if (ntb->link_width != width || ntb->link_speed != speed)
1025250079Scarl		goto retry;
1026250079Scarl
1027289232Scemout:
1028250079Scarl	callout_reset(&ntb->heartbeat_timer, NTB_HB_TIMEOUT * hz,
1029250079Scarl	    ntb_handle_heartbeat, ntb);
1030250079Scarl	return;
1031250079Scarl
1032250079Scarlretry:
1033250079Scarl	callout_reset(&ntb->lr_timer, NTB_HB_TIMEOUT * hz, recover_soc_link,
1034250079Scarl	    ntb);
1035250079Scarl}
1036250079Scarl
1037250079Scarlstatic int
1038250079Scarlntb_check_link_status(struct ntb_softc *ntb)
1039250079Scarl{
1040250079Scarl	int link_state;
1041250079Scarl	uint32_t ntb_cntl;
1042250079Scarl	uint16_t status;
1043250079Scarl
1044250079Scarl	if (ntb->type == NTB_SOC) {
1045255278Scarl		ntb_cntl = ntb_reg_read(4, ntb->reg_ofs.lnk_cntl);
1046250079Scarl		if ((ntb_cntl & SOC_CNTL_LINK_DOWN) != 0)
1047250079Scarl			link_state = NTB_LINK_DOWN;
1048250079Scarl		else
1049250079Scarl			link_state = NTB_LINK_UP;
1050250079Scarl	} else {
1051250079Scarl		status = pci_read_config(ntb->device, XEON_LINK_STATUS_OFFSET,
1052250079Scarl		    2);
1053250079Scarl
1054250079Scarl		if ((status & NTB_LINK_STATUS_ACTIVE) != 0)
1055250079Scarl			link_state = NTB_LINK_UP;
1056250079Scarl		else
1057250079Scarl			link_state = NTB_LINK_DOWN;
1058250079Scarl	}
1059250079Scarl
1060250079Scarl	ntb_handle_link_event(ntb, link_state);
1061250079Scarl
1062250079Scarl	return (0);
1063250079Scarl}
1064250079Scarl
1065250079Scarl/**
1066250079Scarl * ntb_register_event_callback() - register event callback
1067250079Scarl * @ntb: pointer to ntb_softc instance
1068250079Scarl * @func: callback function to register
1069250079Scarl *
1070250079Scarl * This function registers a callback for any HW driver events such as link
1071250079Scarl * up/down, power management notices and etc.
1072250079Scarl *
1073289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success.
1074250079Scarl */
1075250079Scarlint
1076250079Scarlntb_register_event_callback(struct ntb_softc *ntb, ntb_event_callback func)
1077250079Scarl{
1078250079Scarl
1079250079Scarl	if (ntb->event_cb != NULL)
1080250079Scarl		return (EINVAL);
1081250079Scarl
1082250079Scarl	ntb->event_cb = func;
1083250079Scarl
1084250079Scarl	return (0);
1085250079Scarl}
1086250079Scarl
1087250079Scarl/**
1088250079Scarl * ntb_unregister_event_callback() - unregisters the event callback
1089250079Scarl * @ntb: pointer to ntb_softc instance
1090250079Scarl *
1091250079Scarl * This function unregisters the existing callback from transport
1092250079Scarl */
1093250079Scarlvoid
1094250079Scarlntb_unregister_event_callback(struct ntb_softc *ntb)
1095250079Scarl{
1096250079Scarl
1097250079Scarl	ntb->event_cb = NULL;
1098250079Scarl}
1099250079Scarl
1100250079Scarl/**
1101250079Scarl * ntb_register_db_callback() - register a callback for doorbell interrupt
1102250079Scarl * @ntb: pointer to ntb_softc instance
1103250079Scarl * @idx: doorbell index to register callback, zero based
1104250079Scarl * @func: callback function to register
1105250079Scarl *
1106250079Scarl * This function registers a callback function for the doorbell interrupt
1107250079Scarl * on the primary side. The function will unmask the doorbell as well to
1108250079Scarl * allow interrupt.
1109250079Scarl *
1110289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success.
1111250079Scarl */
1112250079Scarlint
1113250079Scarlntb_register_db_callback(struct ntb_softc *ntb, unsigned int idx, void *data,
1114250079Scarl    ntb_db_callback func)
1115250079Scarl{
1116250079Scarl	uint16_t mask;
1117250079Scarl
1118250079Scarl	if (idx >= ntb->allocated_interrupts || ntb->db_cb[idx].callback) {
1119250079Scarl		device_printf(ntb->device, "Invalid Index.\n");
1120250079Scarl		return (EINVAL);
1121250079Scarl	}
1122250079Scarl
1123250079Scarl	ntb->db_cb[idx].callback = func;
1124250079Scarl	ntb->db_cb[idx].data = data;
1125250079Scarl
1126250079Scarl	/* unmask interrupt */
1127255278Scarl	mask = ntb_reg_read(2, ntb->reg_ofs.pdb_mask);
1128250079Scarl	mask &= ~(1 << (idx * ntb->bits_per_vector));
1129255278Scarl	ntb_reg_write(2, ntb->reg_ofs.pdb_mask, mask);
1130250079Scarl
1131250079Scarl	return (0);
1132250079Scarl}
1133250079Scarl
1134250079Scarl/**
1135250079Scarl * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt
1136250079Scarl * @ntb: pointer to ntb_softc instance
1137250079Scarl * @idx: doorbell index to register callback, zero based
1138250079Scarl *
1139250079Scarl * This function unregisters a callback function for the doorbell interrupt
1140250079Scarl * on the primary side. The function will also mask the said doorbell.
1141250079Scarl */
1142250079Scarlvoid
1143250079Scarlntb_unregister_db_callback(struct ntb_softc *ntb, unsigned int idx)
1144250079Scarl{
1145250079Scarl	unsigned long mask;
1146250079Scarl
1147250079Scarl	if (idx >= ntb->allocated_interrupts || !ntb->db_cb[idx].callback)
1148250079Scarl		return;
1149250079Scarl
1150255278Scarl	mask = ntb_reg_read(2, ntb->reg_ofs.pdb_mask);
1151250079Scarl	mask |= 1 << (idx * ntb->bits_per_vector);
1152255278Scarl	ntb_reg_write(2, ntb->reg_ofs.pdb_mask, mask);
1153250079Scarl
1154250079Scarl	ntb->db_cb[idx].callback = NULL;
1155250079Scarl}
1156250079Scarl
1157250079Scarl/**
1158250079Scarl * ntb_find_transport() - find the transport pointer
1159250079Scarl * @transport: pointer to pci device
1160250079Scarl *
1161250079Scarl * Given the pci device pointer, return the transport pointer passed in when
1162250079Scarl * the transport attached when it was inited.
1163250079Scarl *
1164250079Scarl * RETURNS: pointer to transport.
1165250079Scarl */
1166250079Scarlvoid *
1167250079Scarlntb_find_transport(struct ntb_softc *ntb)
1168250079Scarl{
1169250079Scarl
1170250079Scarl	return (ntb->ntb_transport);
1171250079Scarl}
1172250079Scarl
1173250079Scarl/**
1174250079Scarl * ntb_register_transport() - Register NTB transport with NTB HW driver
1175250079Scarl * @transport: transport identifier
1176250079Scarl *
1177250079Scarl * This function allows a transport to reserve the hardware driver for
1178250079Scarl * NTB usage.
1179250079Scarl *
1180250079Scarl * RETURNS: pointer to ntb_softc, NULL on error.
1181250079Scarl */
1182250079Scarlstruct ntb_softc *
1183250079Scarlntb_register_transport(struct ntb_softc *ntb, void *transport)
1184250079Scarl{
1185250079Scarl
1186250079Scarl	/*
1187250079Scarl	 * TODO: when we have more than one transport, we will need to rewrite
1188250079Scarl	 * this to prevent race conditions
1189250079Scarl	 */
1190250079Scarl	if (ntb->ntb_transport != NULL)
1191250079Scarl		return (NULL);
1192250079Scarl
1193250079Scarl	ntb->ntb_transport = transport;
1194250079Scarl	return (ntb);
1195250079Scarl}
1196250079Scarl
1197250079Scarl/**
1198250079Scarl * ntb_unregister_transport() - Unregister the transport with the NTB HW driver
1199250079Scarl * @ntb - ntb_softc of the transport to be freed
1200250079Scarl *
1201250079Scarl * This function unregisters the transport from the HW driver and performs any
1202250079Scarl * necessary cleanups.
1203250079Scarl */
1204250079Scarlvoid
1205250079Scarlntb_unregister_transport(struct ntb_softc *ntb)
1206250079Scarl{
1207250079Scarl	int i;
1208250079Scarl
1209250079Scarl	if (ntb->ntb_transport == NULL)
1210250079Scarl		return;
1211250079Scarl
1212250079Scarl	for (i = 0; i < ntb->allocated_interrupts; i++)
1213250079Scarl		ntb_unregister_db_callback(ntb, i);
1214250079Scarl
1215250079Scarl	ntb_unregister_event_callback(ntb);
1216250079Scarl	ntb->ntb_transport = NULL;
1217250079Scarl}
1218250079Scarl
1219250079Scarl/**
1220250079Scarl * ntb_get_max_spads() - get the total scratch regs usable
1221250079Scarl * @ntb: pointer to ntb_softc instance
1222250079Scarl *
1223250079Scarl * This function returns the max 32bit scratchpad registers usable by the
1224250079Scarl * upper layer.
1225250079Scarl *
1226250079Scarl * RETURNS: total number of scratch pad registers available
1227250079Scarl */
1228289208Scemuint8_t
1229250079Scarlntb_get_max_spads(struct ntb_softc *ntb)
1230250079Scarl{
1231250079Scarl
1232250079Scarl	return (ntb->limits.max_spads);
1233250079Scarl}
1234250079Scarl
1235250079Scarl/**
1236250079Scarl * ntb_write_local_spad() - write to the secondary scratchpad register
1237250079Scarl * @ntb: pointer to ntb_softc instance
1238250079Scarl * @idx: index to the scratchpad register, 0 based
1239250079Scarl * @val: the data value to put into the register
1240250079Scarl *
1241250079Scarl * This function allows writing of a 32bit value to the indexed scratchpad
1242250079Scarl * register. The register resides on the secondary (external) side.
1243250079Scarl *
1244289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success.
1245250079Scarl */
1246250079Scarlint
1247250079Scarlntb_write_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val)
1248250079Scarl{
1249250079Scarl
1250250079Scarl	if (idx >= ntb->limits.max_spads)
1251250079Scarl		return (EINVAL);
1252250079Scarl
1253255278Scarl	ntb_reg_write(4, ntb->reg_ofs.spad_local + idx * 4, val);
1254250079Scarl
1255250079Scarl	return (0);
1256250079Scarl}
1257250079Scarl
1258250079Scarl/**
1259250079Scarl * ntb_read_local_spad() - read from the primary scratchpad register
1260250079Scarl * @ntb: pointer to ntb_softc instance
1261250079Scarl * @idx: index to scratchpad register, 0 based
1262250079Scarl * @val: pointer to 32bit integer for storing the register value
1263250079Scarl *
1264250079Scarl * This function allows reading of the 32bit scratchpad register on
1265250079Scarl * the primary (internal) side.
1266250079Scarl *
1267289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success.
1268250079Scarl */
1269250079Scarlint
1270250079Scarlntb_read_local_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val)
1271250079Scarl{
1272250079Scarl
1273250079Scarl	if (idx >= ntb->limits.max_spads)
1274250079Scarl		return (EINVAL);
1275250079Scarl
1276255278Scarl	*val = ntb_reg_read(4, ntb->reg_ofs.spad_local + idx * 4);
1277250079Scarl
1278250079Scarl	return (0);
1279250079Scarl}
1280250079Scarl
1281250079Scarl/**
1282250079Scarl * ntb_write_remote_spad() - write to the secondary scratchpad register
1283250079Scarl * @ntb: pointer to ntb_softc instance
1284250079Scarl * @idx: index to the scratchpad register, 0 based
1285250079Scarl * @val: the data value to put into the register
1286250079Scarl *
1287250079Scarl * This function allows writing of a 32bit value to the indexed scratchpad
1288250079Scarl * register. The register resides on the secondary (external) side.
1289250079Scarl *
1290289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success.
1291250079Scarl */
1292250079Scarlint
1293250079Scarlntb_write_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t val)
1294250079Scarl{
1295250079Scarl
1296250079Scarl	if (idx >= ntb->limits.max_spads)
1297250079Scarl		return (EINVAL);
1298250079Scarl
1299255279Scarl	if (HAS_FEATURE(NTB_REGS_THRU_MW))
1300255279Scarl		ntb_mw_write(4, XEON_SHADOW_SPAD_OFFSET + idx * 4, val);
1301255279Scarl	else
1302255279Scarl		ntb_reg_write(4, ntb->reg_ofs.spad_remote + idx * 4, val);
1303250079Scarl
1304250079Scarl	return (0);
1305250079Scarl}
1306250079Scarl
1307250079Scarl/**
1308250079Scarl * ntb_read_remote_spad() - read from the primary scratchpad register
1309250079Scarl * @ntb: pointer to ntb_softc instance
1310250079Scarl * @idx: index to scratchpad register, 0 based
1311250079Scarl * @val: pointer to 32bit integer for storing the register value
1312250079Scarl *
1313250079Scarl * This function allows reading of the 32bit scratchpad register on
1314250079Scarl * the primary (internal) side.
1315250079Scarl *
1316289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success.
1317250079Scarl */
1318250079Scarlint
1319250079Scarlntb_read_remote_spad(struct ntb_softc *ntb, unsigned int idx, uint32_t *val)
1320250079Scarl{
1321250079Scarl
1322250079Scarl	if (idx >= ntb->limits.max_spads)
1323250079Scarl		return (EINVAL);
1324250079Scarl
1325255279Scarl	if (HAS_FEATURE(NTB_REGS_THRU_MW))
1326255279Scarl		*val = ntb_mw_read(4, XEON_SHADOW_SPAD_OFFSET + idx * 4);
1327255279Scarl	else
1328255279Scarl		*val = ntb_reg_read(4, ntb->reg_ofs.spad_remote + idx * 4);
1329250079Scarl
1330250079Scarl	return (0);
1331250079Scarl}
1332250079Scarl
1333250079Scarl/**
1334250079Scarl * ntb_get_mw_vbase() - get virtual addr for the NTB memory window
1335250079Scarl * @ntb: pointer to ntb_softc instance
1336250079Scarl * @mw: memory window number
1337250079Scarl *
1338250079Scarl * This function provides the base virtual address of the memory window
1339250079Scarl * specified.
1340250079Scarl *
1341250079Scarl * RETURNS: pointer to virtual address, or NULL on error.
1342250079Scarl */
1343250079Scarlvoid *
1344250079Scarlntb_get_mw_vbase(struct ntb_softc *ntb, unsigned int mw)
1345250079Scarl{
1346250079Scarl
1347250079Scarl	if (mw >= NTB_NUM_MW)
1348250079Scarl		return (NULL);
1349250079Scarl
1350250079Scarl	return (ntb->bar_info[NTB_MW_TO_BAR(mw)].vbase);
1351250079Scarl}
1352250079Scarl
1353250079Scarlvm_paddr_t
1354250079Scarlntb_get_mw_pbase(struct ntb_softc *ntb, unsigned int mw)
1355250079Scarl{
1356250079Scarl
1357250079Scarl	if (mw >= NTB_NUM_MW)
1358250079Scarl		return (0);
1359250079Scarl
1360250079Scarl	return (ntb->bar_info[NTB_MW_TO_BAR(mw)].pbase);
1361250079Scarl}
1362250079Scarl
1363250079Scarl/**
1364250079Scarl * ntb_get_mw_size() - return size of NTB memory window
1365250079Scarl * @ntb: pointer to ntb_softc instance
1366250079Scarl * @mw: memory window number
1367250079Scarl *
1368250079Scarl * This function provides the physical size of the memory window specified
1369250079Scarl *
1370250079Scarl * RETURNS: the size of the memory window or zero on error
1371250079Scarl */
1372250079Scarlu_long
1373250079Scarlntb_get_mw_size(struct ntb_softc *ntb, unsigned int mw)
1374250079Scarl{
1375250079Scarl
1376250079Scarl	if (mw >= NTB_NUM_MW)
1377250079Scarl		return (0);
1378250079Scarl
1379250079Scarl	return (ntb->bar_info[NTB_MW_TO_BAR(mw)].size);
1380250079Scarl}
1381250079Scarl
1382250079Scarl/**
1383250079Scarl * ntb_set_mw_addr - set the memory window address
1384250079Scarl * @ntb: pointer to ntb_softc instance
1385250079Scarl * @mw: memory window number
1386250079Scarl * @addr: base address for data
1387250079Scarl *
1388250079Scarl * This function sets the base physical address of the memory window.  This
1389250079Scarl * memory address is where data from the remote system will be transfered into
1390250079Scarl * or out of depending on how the transport is configured.
1391250079Scarl */
1392250079Scarlvoid
1393250079Scarlntb_set_mw_addr(struct ntb_softc *ntb, unsigned int mw, uint64_t addr)
1394250079Scarl{
1395250079Scarl
1396250079Scarl	if (mw >= NTB_NUM_MW)
1397250079Scarl		return;
1398250079Scarl
1399250079Scarl	switch (NTB_MW_TO_BAR(mw)) {
1400250079Scarl	case NTB_B2B_BAR_1:
1401255278Scarl		ntb_reg_write(8, ntb->reg_ofs.sbar2_xlat, addr);
1402250079Scarl		break;
1403250079Scarl	case NTB_B2B_BAR_2:
1404255278Scarl		ntb_reg_write(8, ntb->reg_ofs.sbar4_xlat, addr);
1405250079Scarl		break;
1406250079Scarl	}
1407250079Scarl}
1408250079Scarl
1409250079Scarl/**
1410250079Scarl * ntb_ring_sdb() - Set the doorbell on the secondary/external side
1411250079Scarl * @ntb: pointer to ntb_softc instance
1412250079Scarl * @db: doorbell to ring
1413250079Scarl *
1414250079Scarl * This function allows triggering of a doorbell on the secondary/external
1415250079Scarl * side that will initiate an interrupt on the remote host
1416250079Scarl *
1417289209Scem * RETURNS: An appropriate ERRNO error value on error, or zero for success.
1418250079Scarl */
1419250079Scarlvoid
1420250079Scarlntb_ring_sdb(struct ntb_softc *ntb, unsigned int db)
1421250079Scarl{
1422250079Scarl
1423250079Scarl	if (ntb->type == NTB_SOC)
1424255278Scarl		ntb_reg_write(8, ntb->reg_ofs.sdb, (uint64_t) 1 << db);
1425289209Scem	else {
1426255279Scarl		if (HAS_FEATURE(NTB_REGS_THRU_MW))
1427255279Scarl			ntb_mw_write(2, XEON_SHADOW_PDOORBELL_OFFSET,
1428255279Scarl			    ((1 << ntb->bits_per_vector) - 1) <<
1429255279Scarl			    (db * ntb->bits_per_vector));
1430255279Scarl		else
1431255279Scarl			ntb_reg_write(2, ntb->reg_ofs.sdb,
1432255279Scarl			    ((1 << ntb->bits_per_vector) - 1) <<
1433255279Scarl			    (db * ntb->bits_per_vector));
1434289209Scem	}
1435250079Scarl}
1436250079Scarl
1437250079Scarl/**
1438250079Scarl * ntb_query_link_status() - return the hardware link status
1439250079Scarl * @ndev: pointer to ntb_device instance
1440250079Scarl *
1441250079Scarl * Returns true if the hardware is connected to the remote system
1442250079Scarl *
1443250079Scarl * RETURNS: true or false based on the hardware link state
1444250079Scarl */
1445250079Scarlbool
1446250079Scarlntb_query_link_status(struct ntb_softc *ntb)
1447250079Scarl{
1448250079Scarl
1449250079Scarl	return (ntb->link_status == NTB_LINK_UP);
1450250079Scarl}
1451250079Scarl
1452255272Scarlstatic void
1453255272Scarlsave_bar_parameters(struct ntb_pci_bar_info *bar)
1454250079Scarl{
1455255272Scarl
1456289209Scem	bar->pci_bus_tag = rman_get_bustag(bar->pci_resource);
1457289209Scem	bar->pci_bus_handle = rman_get_bushandle(bar->pci_resource);
1458289209Scem	bar->pbase = rman_get_start(bar->pci_resource);
1459289209Scem	bar->size = rman_get_size(bar->pci_resource);
1460289209Scem	bar->vbase = rman_get_virtual(bar->pci_resource);
1461250079Scarl}
1462255268Scarl
1463289209Scemdevice_t
1464289209Scemntb_get_device(struct ntb_softc *ntb)
1465255268Scarl{
1466255268Scarl
1467255268Scarl	return (ntb->device);
1468255268Scarl}
1469289208Scem
1470289208Scem/* Export HW-specific errata information. */
1471289208Scembool
1472289208Scemntb_has_feature(struct ntb_softc *ntb, uint64_t feature)
1473289208Scem{
1474289208Scem
1475289208Scem	return (HAS_FEATURE(feature));
1476289208Scem}
1477