ntb_hw_plx.c revision 324407
1323032Smav/*-
2323032Smav * Copyright (c) 2017 Alexander Motin <mav@FreeBSD.org>
3323032Smav * All rights reserved.
4323032Smav *
5323032Smav * Redistribution and use in source and binary forms, with or without
6323032Smav * modification, are permitted provided that the following conditions
7323032Smav * are met:
8323032Smav * 1. Redistributions of source code must retain the above copyright
9323032Smav *    notice, this list of conditions and the following disclaimer.
10323032Smav * 2. Redistributions in binary form must reproduce the above copyright
11323032Smav *    notice, this list of conditions and the following disclaimer in the
12323032Smav *    documentation and/or other materials provided with the distribution.
13323032Smav *
14323032Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15323032Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16323032Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17323032Smav * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18323032Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19323032Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20323032Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21323032Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22323032Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23323032Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24323032Smav * SUCH DAMAGE.
25323032Smav */
26323032Smav
27323032Smav/*
28323032Smav * The Non-Transparent Bridge (NTB) is a device that allows you to connect
29323032Smav * two or more systems using a PCI-e links, providing remote memory access.
30323032Smav *
31323032Smav * This module contains a driver for NTBs in PLX/Avago/Broadcom PCIe bridges.
32323032Smav */
33323032Smav
34323032Smav#include <sys/cdefs.h>
35323032Smav__FBSDID("$FreeBSD: stable/11/sys/dev/ntb/ntb_hw/ntb_hw_plx.c 324407 2017-10-08 07:19:59Z mav $");
36323032Smav
37323032Smav#include <sys/param.h>
38323032Smav#include <sys/kernel.h>
39323032Smav#include <sys/systm.h>
40323032Smav#include <sys/bus.h>
41323032Smav#include <sys/interrupt.h>
42323032Smav#include <sys/module.h>
43323032Smav#include <sys/rman.h>
44323032Smav#include <sys/sysctl.h>
45323032Smav#include <vm/vm.h>
46323032Smav#include <vm/pmap.h>
47323032Smav#include <machine/bus.h>
48323032Smav#include <machine/intr_machdep.h>
49323032Smav#include <machine/resource.h>
50323032Smav#include <dev/pci/pcireg.h>
51323032Smav#include <dev/pci/pcivar.h>
52323032Smav
53323032Smav#include "../ntb.h"
54323032Smav
55323032Smav#define PLX_MAX_BARS		4	/* There are at most 4 data BARs. */
56323032Smav#define PLX_NUM_SPAD		8	/* There are 8 scratchpads. */
57323032Smav#define PLX_NUM_SPAD_PATT	4	/* Use test pattern as 4 more. */
58323032Smav#define PLX_NUM_DB		16	/* There are 16 doorbells. */
59323032Smav
60323032Smavstruct ntb_plx_mw_info {
61323032Smav	int			 mw_bar;
62323032Smav	int			 mw_64bit;
63323032Smav	int			 mw_rid;
64323032Smav	struct resource		*mw_res;
65323032Smav	vm_paddr_t		 mw_pbase;
66323032Smav	caddr_t			 mw_vbase;
67323032Smav	vm_size_t		 mw_size;
68323032Smav	vm_memattr_t		 mw_map_mode;
69323032Smav	bus_addr_t		 mw_xlat_addr;
70323032Smav	size_t			 mw_xlat_size;
71323032Smav};
72323032Smav
73323032Smavstruct ntb_plx_softc {
74323032Smav	/* ntb.c context. Do not move! Must go first! */
75323032Smav	void			*ntb_store;
76323032Smav
77323032Smav	device_t		 dev;
78323032Smav	struct resource		*conf_res;
79323032Smav	int			 conf_rid;
80323032Smav	u_int			 ntx;		/* NTx number within chip. */
81323032Smav	u_int			 link;		/* Link v/s Virtual side. */
82323032Smav	u_int			 port;		/* Port number within chip. */
83324407Smav	u_int			 alut;		/* A-LUT is enabled for NTx */
84323032Smav
85323032Smav	int			 int_rid;
86323032Smav	struct resource		*int_res;
87323032Smav	void			*int_tag;
88323032Smav
89323032Smav	struct ntb_plx_mw_info	 mw_info[PLX_MAX_BARS];
90323032Smav	int			 mw_count;	/* Number of memory windows. */
91323032Smav
92323032Smav	int			 spad_count1;	/* Number of standard spads. */
93323032Smav	int			 spad_count2;	/* Number of extra spads. */
94323032Smav	uint32_t		 spad_off1;	/* Offset of our spads. */
95323032Smav	uint32_t		 spad_off2;	/* Offset of our extra spads. */
96323032Smav	uint32_t		 spad_offp1;	/* Offset of peer spads. */
97323032Smav	uint32_t		 spad_offp2;	/* Offset of peer extra spads. */
98323032Smav
99323032Smav	/* Parameters of window shared with peer config access in B2B mode. */
100323032Smav	int			 b2b_mw;	/* Shared window number. */
101323032Smav	uint64_t		 b2b_off;	/* Offset in shared window. */
102323032Smav};
103323032Smav
104323032Smav#define	PLX_NT0_BASE		0x3E000
105323032Smav#define	PLX_NT1_BASE		0x3C000
106323032Smav#define	PLX_NTX_BASE(sc)	((sc)->ntx ? PLX_NT1_BASE : PLX_NT0_BASE)
107323032Smav#define	PLX_NTX_LINK_OFFSET	0x01000
108323032Smav
109323032Smav/* Bases of NTx our/peer interface registers */
110323453Smav#define	PLX_NTX_OUR_BASE(sc)				\
111323032Smav    (PLX_NTX_BASE(sc) + ((sc)->link ? PLX_NTX_LINK_OFFSET : 0))
112323453Smav#define	PLX_NTX_PEER_BASE(sc)				\
113323032Smav    (PLX_NTX_BASE(sc) + ((sc)->link ? 0 : PLX_NTX_LINK_OFFSET))
114323032Smav
115323032Smav/* Read/write NTx our interface registers */
116323453Smav#define	NTX_READ(sc, reg)				\
117323453Smav    bus_read_4((sc)->conf_res, PLX_NTX_OUR_BASE(sc) + (reg))
118323453Smav#define	NTX_WRITE(sc, reg, val)				\
119323453Smav    bus_write_4((sc)->conf_res, PLX_NTX_OUR_BASE(sc) + (reg), (val))
120323032Smav
121323032Smav/* Read/write NTx peer interface registers */
122323453Smav#define	PNTX_READ(sc, reg)				\
123323453Smav    bus_read_4((sc)->conf_res, PLX_NTX_PEER_BASE(sc) + (reg))
124323453Smav#define	PNTX_WRITE(sc, reg, val)			\
125323453Smav    bus_write_4((sc)->conf_res, PLX_NTX_PEER_BASE(sc) + (reg), (val))
126323032Smav
127323032Smav/* Read/write B2B NTx registers */
128323453Smav#define	BNTX_READ(sc, reg)				\
129323032Smav    bus_read_4((sc)->mw_info[(sc)->b2b_mw].mw_res,	\
130323032Smav    PLX_NTX_BASE(sc) + (reg))
131323453Smav#define	BNTX_WRITE(sc, reg, val)			\
132323032Smav    bus_write_4((sc)->mw_info[(sc)->b2b_mw].mw_res,	\
133323032Smav    PLX_NTX_BASE(sc) + (reg), (val))
134323032Smav
135323453Smav#define	PLX_PORT_BASE(p)		((p) << 12)
136323453Smav#define	PLX_STATION_PORT_BASE(sc)	PLX_PORT_BASE((sc)->port & ~7)
137323453Smav
138323453Smav#define	PLX_PORT_CONTROL(sc)		(PLX_STATION_PORT_BASE(sc) + 0x208)
139323453Smav
140323032Smavstatic int ntb_plx_init(device_t dev);
141323032Smavstatic int ntb_plx_detach(device_t dev);
142323032Smavstatic int ntb_plx_mw_set_trans_internal(device_t dev, unsigned mw_idx);
143323032Smav
144323032Smavstatic int
145323032Smavntb_plx_probe(device_t dev)
146323032Smav{
147323032Smav
148323032Smav	switch (pci_get_devid(dev)) {
149323032Smav	case 0x87a010b5:
150323032Smav		device_set_desc(dev, "PLX Non-Transparent Bridge NT0 Link");
151323032Smav		return (BUS_PROBE_DEFAULT);
152323032Smav	case 0x87a110b5:
153323032Smav		device_set_desc(dev, "PLX Non-Transparent Bridge NT1 Link");
154323032Smav		return (BUS_PROBE_DEFAULT);
155323032Smav	case 0x87b010b5:
156323032Smav		device_set_desc(dev, "PLX Non-Transparent Bridge NT0 Virtual");
157323032Smav		return (BUS_PROBE_DEFAULT);
158323032Smav	case 0x87b110b5:
159323032Smav		device_set_desc(dev, "PLX Non-Transparent Bridge NT1 Virtual");
160323032Smav		return (BUS_PROBE_DEFAULT);
161323032Smav	}
162323032Smav	return (ENXIO);
163323032Smav}
164323032Smav
165323032Smavstatic int
166323032Smavntb_plx_init(device_t dev)
167323032Smav{
168323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
169323032Smav	struct ntb_plx_mw_info *mw;
170323032Smav	uint64_t val64;
171323032Smav	int i;
172323032Smav	uint32_t val;
173323032Smav
174323032Smav	if (sc->b2b_mw >= 0) {
175323032Smav		/* Set peer BAR0/1 size and address for B2B NTx access. */
176323032Smav		mw = &sc->mw_info[sc->b2b_mw];
177323032Smav		if (mw->mw_64bit) {
178323032Smav			PNTX_WRITE(sc, 0xe4, 0x3);	/* 64-bit */
179323032Smav			val64 = 0x2000000000000000 * mw->mw_bar | 0x4;
180323032Smav			PNTX_WRITE(sc, PCIR_BAR(0), val64);
181323032Smav			PNTX_WRITE(sc, PCIR_BAR(0) + 4, val64 >> 32);
182323032Smav		} else {
183323032Smav			PNTX_WRITE(sc, 0xe4, 0x2);	/* 32-bit */
184323032Smav			val = 0x20000000 * mw->mw_bar;
185323032Smav			PNTX_WRITE(sc, PCIR_BAR(0), val);
186323032Smav		}
187323032Smav
188323032Smav		/* Set Virtual to Link address translation for B2B. */
189323032Smav		for (i = 0; i < sc->mw_count; i++) {
190323032Smav			mw = &sc->mw_info[i];
191323032Smav			if (mw->mw_64bit) {
192323032Smav				val64 = 0x2000000000000000 * mw->mw_bar;
193323032Smav				NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, val64);
194323032Smav				NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4 + 4, val64 >> 32);
195323032Smav			} else {
196323032Smav				val = 0x20000000 * mw->mw_bar;
197323032Smav				NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, val);
198323032Smav			}
199323032Smav		}
200323032Smav
201324407Smav		/* Make sure Virtual to Link A-LUT is disabled. */
202324407Smav		if (sc->alut)
203324407Smav			PNTX_WRITE(sc, 0xc94, 0);
204324407Smav
205323844Smav		/* Enable Link Interface LUT entries 0/1 for peer 0/1. */
206323844Smav		PNTX_WRITE(sc, 0xdb4, 0x00090001);
207323032Smav	}
208323032Smav
209323032Smav	/*
210323032Smav	 * Enable Virtual Interface LUT entry 0 for 0:0.0 and
211323032Smav	 * entry 1 for our Requester ID reported by chip.
212323032Smav	 */
213323032Smav	val = (NTX_READ(sc, 0xc90) << 16) | 0x00010001;
214323032Smav	NTX_WRITE(sc, sc->link ? 0xdb4 : 0xd94, val);
215323032Smav
216323032Smav	/* Set Link to Virtual address translation. */
217323032Smav	for (i = 0; i < sc->mw_count; i++) {
218323032Smav		mw = &sc->mw_info[i];
219323032Smav		if (mw->mw_xlat_size != 0)
220323032Smav			ntb_plx_mw_set_trans_internal(dev, i);
221323032Smav	}
222323032Smav
223323032Smav	pci_enable_busmaster(dev);
224323032Smav	if (sc->b2b_mw >= 0)
225323032Smav		PNTX_WRITE(sc, PCIR_COMMAND, PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
226323032Smav
227323032Smav	return (0);
228323032Smav}
229323032Smav
230323032Smavstatic void
231323032Smavntb_plx_isr(void *arg)
232323032Smav{
233323032Smav	device_t dev = arg;
234323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
235323032Smav	uint32_t val;
236323032Smav
237323032Smav	ntb_db_event((device_t)arg, 0);
238323032Smav
239323453Smav	if (sc->link)	/* Link Interface has no Link Error registers. */
240323453Smav		return;
241323453Smav
242323032Smav	val = NTX_READ(sc, 0xfe0);
243323032Smav	if (val == 0)
244323032Smav		return;
245323032Smav	NTX_WRITE(sc, 0xfe0, val);
246323032Smav	if (val & 1)
247323032Smav		device_printf(dev, "Correctable Error\n");
248323032Smav	if (val & 2)
249323032Smav		device_printf(dev, "Uncorrectable Error\n");
250323032Smav	if (val & 4) {
251323032Smav		/* DL_Down resets link side registers, have to reinit. */
252323032Smav		ntb_plx_init(dev);
253323032Smav		ntb_link_event(dev);
254323032Smav	}
255323032Smav	if (val & 8)
256323032Smav		device_printf(dev, "Uncorrectable Error Message Drop\n");
257323032Smav}
258323032Smav
259323032Smavstatic int
260323032Smavntb_plx_setup_intr(device_t dev)
261323032Smav{
262323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
263323032Smav	int error;
264323032Smav
265323032Smav	/*
266323032Smav	 * XXX: This hardware supports MSI, but I found it unusable.
267323032Smav	 * It generates new MSI only when doorbell register goes from
268323032Smav	 * zero, but does not generate it when another bit is set or on
269323032Smav	 * partial clear.  It makes operation very racy and unreliable.
270323032Smav	 * The data book mentions some mask juggling magic to workaround
271323032Smav	 * that, but I failed to make it work.
272323032Smav	 */
273323032Smav	sc->int_rid = 0;
274323032Smav	sc->int_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
275323032Smav	    &sc->int_rid, RF_SHAREABLE|RF_ACTIVE);
276323032Smav	if (sc->int_res == NULL) {
277323032Smav		device_printf(dev, "bus_alloc_resource failed\n");
278323032Smav		return (ENOMEM);
279323032Smav	}
280323032Smav	error = bus_setup_intr(dev, sc->int_res, INTR_MPSAFE | INTR_TYPE_MISC,
281323032Smav	    NULL, ntb_plx_isr, dev, &sc->int_tag);
282323032Smav	if (error != 0) {
283323032Smav		device_printf(dev, "bus_setup_intr failed: %d\n", error);
284323032Smav		return (error);
285323032Smav	}
286323453Smav
287323453Smav	if (!sc->link) { /* Link Interface has no Link Error registers. */
288323453Smav		NTX_WRITE(sc, 0xfe0, 0xf);	/* Clear link interrupts. */
289323453Smav		NTX_WRITE(sc, 0xfe4, 0x0);	/* Unmask link interrupts. */
290323453Smav	}
291323032Smav	return (0);
292323032Smav}
293323032Smav
294323032Smavstatic void
295323032Smavntb_plx_teardown_intr(device_t dev)
296323032Smav{
297323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
298323032Smav
299323453Smav	if (!sc->link)	/* Link Interface has no Link Error registers. */
300323453Smav		NTX_WRITE(sc, 0xfe4, 0xf);	/* Mask link interrupts. */
301323453Smav
302323032Smav	if (sc->int_res) {
303323032Smav		bus_teardown_intr(dev, sc->int_res, sc->int_tag);
304323032Smav		bus_release_resource(dev, SYS_RES_IRQ, sc->int_rid,
305323032Smav		    sc->int_res);
306323032Smav	}
307323032Smav}
308323032Smav
309323032Smavstatic int
310323032Smavntb_plx_attach(device_t dev)
311323032Smav{
312323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
313323032Smav	struct ntb_plx_mw_info *mw;
314323032Smav	int error = 0, i;
315323032Smav	uint32_t val;
316323032Smav	char buf[32];
317323032Smav
318323032Smav	/* Identify what we are (what side of what NTx). */
319323032Smav	sc->dev = dev;
320323032Smav	val = pci_read_config(dev, 0xc8c, 4);
321323032Smav	sc->ntx = (val & 1) != 0;
322323032Smav	sc->link = (val & 0x80000000) != 0;
323323032Smav
324323032Smav	/* Get access to whole 256KB of chip configuration space via BAR0/1. */
325323032Smav	sc->conf_rid = PCIR_BAR(0);
326323032Smav	sc->conf_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
327323032Smav	    &sc->conf_rid, RF_ACTIVE);
328323032Smav	if (sc->conf_res == NULL) {
329323032Smav		device_printf(dev, "Can't allocate configuration BAR.\n");
330323032Smav		return (ENXIO);
331323032Smav	}
332323032Smav
333323032Smav	/* Identify chip port we are connected to. */
334323032Smav	val = bus_read_4(sc->conf_res, 0x360);
335323032Smav	sc->port = (val >> ((sc->ntx == 0) ? 8 : 16)) & 0x1f;
336323032Smav
337324407Smav	/* Detect A-LUT enable and size. */
338324407Smav	val >>= 30;
339324407Smav	sc->alut = (val == 0x3) ? 1 : ((val & (1 << sc->ntx)) ? 2 : 0);
340324407Smav	if (sc->alut)
341324407Smav		device_printf(dev, "%u A-LUT entries\n", 128 * sc->alut);
342324407Smav
343323032Smav	/* Find configured memory windows at BAR2-5. */
344323032Smav	sc->mw_count = 0;
345323032Smav	for (i = 2; i <= 5; i++) {
346323032Smav		mw = &sc->mw_info[sc->mw_count];
347323032Smav		mw->mw_bar = i;
348323032Smav		mw->mw_rid = PCIR_BAR(mw->mw_bar);
349323032Smav		mw->mw_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
350323032Smav		    &mw->mw_rid, RF_ACTIVE);
351323032Smav		if (mw->mw_res == NULL)
352323032Smav			continue;
353323032Smav		mw->mw_pbase = rman_get_start(mw->mw_res);
354323032Smav		mw->mw_size = rman_get_size(mw->mw_res);
355323032Smav		mw->mw_vbase = rman_get_virtual(mw->mw_res);
356323032Smav		mw->mw_map_mode = VM_MEMATTR_UNCACHEABLE;
357323032Smav		sc->mw_count++;
358323032Smav
359323032Smav		/* Skip over adjacent BAR for 64-bit BARs. */
360323032Smav		val = pci_read_config(dev, PCIR_BAR(mw->mw_bar), 4);
361323032Smav		if ((val & PCIM_BAR_MEM_TYPE) == PCIM_BAR_MEM_64) {
362323032Smav			mw->mw_64bit = 1;
363323032Smav			i++;
364323032Smav		}
365323032Smav	}
366323032Smav
367323032Smav	/* Try to identify B2B mode. */
368323032Smav	i = 1;
369323032Smav	snprintf(buf, sizeof(buf), "hint.%s.%d.b2b", device_get_name(dev),
370323032Smav	    device_get_unit(dev));
371323032Smav	TUNABLE_INT_FETCH(buf, &i);
372323032Smav	if (sc->link) {
373323032Smav		device_printf(dev, "NTB-to-Root Port mode (Link Interface)\n");
374323032Smav		sc->b2b_mw = -1;
375323032Smav	} else if (i == 0) {
376323032Smav		device_printf(dev, "NTB-to-Root Port mode (Virtual Interface)\n");
377323032Smav		sc->b2b_mw = -1;
378323032Smav	} else {
379323032Smav		device_printf(dev, "NTB-to-NTB (back-to-back) mode\n");
380323032Smav
381323032Smav		/* We need at least one memory window for B2B peer access. */
382323032Smav		if (sc->mw_count == 0) {
383323032Smav			device_printf(dev, "No memory window BARs enabled.\n");
384323032Smav			error = ENXIO;
385323032Smav			goto out;
386323032Smav		}
387323032Smav		sc->b2b_mw = sc->mw_count - 1;
388323032Smav
389323032Smav		/* Use half of the window for B2B, but no less then 1MB. */
390323032Smav		mw = &sc->mw_info[sc->b2b_mw];
391323032Smav		if (mw->mw_size >= 2 * 1024 * 1024)
392323032Smav			sc->b2b_off = mw->mw_size / 2;
393323032Smav		else
394323032Smav			sc->b2b_off = 0;
395323032Smav	}
396323032Smav
397323032Smav	/*
398323032Smav	 * Use Physical Layer User Test Pattern as additional scratchpad.
399323032Smav	 * Make sure they are present and enabled by writing to them.
400323032Smav	 * XXX: Its a hack, but standard 8 registers are not enough.
401323032Smav	 */
402323453Smav	sc->spad_offp1 = sc->spad_off1 = PLX_NTX_OUR_BASE(sc) + 0xc6c;
403323453Smav	sc->spad_offp2 = sc->spad_off2 = PLX_PORT_BASE(sc->ntx * 8) + 0x20c;
404323032Smav	if (sc->b2b_mw >= 0) {
405323453Smav		/* In NTB-to-NTB mode each side has own scratchpads. */
406323032Smav		sc->spad_count1 = PLX_NUM_SPAD;
407323032Smav		bus_write_4(sc->conf_res, sc->spad_off2, 0x12345678);
408323032Smav		if (bus_read_4(sc->conf_res, sc->spad_off2) == 0x12345678)
409323032Smav			sc->spad_count2 = PLX_NUM_SPAD_PATT;
410323032Smav	} else {
411323453Smav		/* Otherwise we have share scratchpads with the peer. */
412323032Smav		if (sc->link) {
413323032Smav			sc->spad_off1 += PLX_NUM_SPAD / 2 * 4;
414323032Smav			sc->spad_off2 += PLX_NUM_SPAD_PATT / 2 * 4;
415323032Smav		} else {
416323032Smav			sc->spad_offp1 += PLX_NUM_SPAD / 2 * 4;
417323032Smav			sc->spad_offp2 += PLX_NUM_SPAD_PATT / 2 * 4;
418323032Smav		}
419323453Smav		sc->spad_count1 = PLX_NUM_SPAD / 2;
420323032Smav		bus_write_4(sc->conf_res, sc->spad_off2, 0x12345678);
421323032Smav		if (bus_read_4(sc->conf_res, sc->spad_off2) == 0x12345678)
422323032Smav			sc->spad_count2 = PLX_NUM_SPAD_PATT / 2;
423323032Smav	}
424323032Smav
425323032Smav	/* Apply static part of NTB configuration. */
426323032Smav	ntb_plx_init(dev);
427323032Smav
428323032Smav	/* Allocate and setup interrupts. */
429323032Smav	error = ntb_plx_setup_intr(dev);
430323032Smav	if (error)
431323032Smav		goto out;
432323032Smav
433323032Smav	/* Attach children to this controller */
434323032Smav	error = ntb_register_device(dev);
435323032Smav
436323032Smavout:
437323032Smav	if (error != 0)
438323032Smav		ntb_plx_detach(dev);
439323032Smav	return (error);
440323032Smav}
441323032Smav
442323032Smavstatic int
443323032Smavntb_plx_detach(device_t dev)
444323032Smav{
445323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
446323032Smav	struct ntb_plx_mw_info *mw;
447323032Smav	int i;
448323032Smav
449323032Smav	/* Detach & delete all children */
450323032Smav	ntb_unregister_device(dev);
451323032Smav
452323032Smav	/* Disable and free interrupts. */
453323032Smav	ntb_plx_teardown_intr(dev);
454323032Smav
455323032Smav	/* Free memory resources. */
456323032Smav	for (i = 0; i < sc->mw_count; i++) {
457323032Smav		mw = &sc->mw_info[i];
458323032Smav		bus_release_resource(dev, SYS_RES_MEMORY, mw->mw_rid,
459323032Smav		    mw->mw_res);
460323032Smav	}
461323032Smav	bus_release_resource(dev, SYS_RES_MEMORY, sc->conf_rid, sc->conf_res);
462323032Smav	return (0);
463323032Smav}
464323032Smav
465323032Smav
466323032Smavstatic bool
467323032Smavntb_plx_link_is_up(device_t dev, enum ntb_speed *speed, enum ntb_width *width)
468323032Smav{
469323032Smav	uint16_t link;
470323032Smav
471323032Smav	link = pcie_read_config(dev, PCIER_LINK_STA, 2);
472323032Smav	if (speed != NULL)
473323032Smav		*speed = (link & PCIEM_LINK_STA_SPEED);
474323032Smav	if (width != NULL)
475323032Smav		*width = (link & PCIEM_LINK_STA_WIDTH) >> 4;
476323032Smav	return ((link & PCIEM_LINK_STA_WIDTH) != 0);
477323032Smav}
478323032Smav
479323032Smavstatic int
480323032Smavntb_plx_link_enable(device_t dev, enum ntb_speed speed __unused,
481323032Smav    enum ntb_width width __unused)
482323032Smav{
483323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
484323032Smav	uint32_t reg, val;
485323032Smav
486323032Smav	/* The fact that we see the Link Interface means link is enabled. */
487323032Smav	if (sc->link) {
488323032Smav		ntb_link_event(dev);
489323032Smav		return (0);
490323032Smav	}
491323032Smav
492323453Smav	reg = PLX_PORT_CONTROL(sc);
493323032Smav	val = bus_read_4(sc->conf_res, reg);
494323032Smav	if ((val & (1 << (sc->port & 7))) == 0) {
495323032Smav		/* If already enabled, generate fake link event and exit. */
496323032Smav		ntb_link_event(dev);
497323032Smav		return (0);
498323032Smav	}
499323032Smav	val &= ~(1 << (sc->port & 7));
500323032Smav	bus_write_4(sc->conf_res, reg, val);
501323032Smav	return (0);
502323032Smav}
503323032Smav
504323032Smavstatic int
505323032Smavntb_plx_link_disable(device_t dev)
506323032Smav{
507323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
508323032Smav	uint32_t reg, val;
509323032Smav
510323032Smav	/* Link disable for Link Interface would be suicidal. */
511323032Smav	if (sc->link)
512323032Smav		return (0);
513323032Smav
514323453Smav	reg = PLX_PORT_CONTROL(sc);
515323032Smav	val = bus_read_4(sc->conf_res, reg);
516323032Smav	val |= (1 << (sc->port & 7));
517323032Smav	bus_write_4(sc->conf_res, reg, val);
518323032Smav	return (0);
519323032Smav}
520323032Smav
521323032Smavstatic bool
522323032Smavntb_plx_link_enabled(device_t dev)
523323032Smav{
524323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
525323032Smav	uint32_t reg, val;
526323032Smav
527323032Smav	/* The fact that we see the Link Interface means link is enabled. */
528323032Smav	if (sc->link)
529323032Smav		return (TRUE);
530323032Smav
531323453Smav	reg = PLX_PORT_CONTROL(sc);
532323032Smav	val = bus_read_4(sc->conf_res, reg);
533323032Smav	return ((val & (1 << (sc->port & 7))) == 0);
534323032Smav}
535323032Smav
536323032Smavstatic uint8_t
537323032Smavntb_plx_mw_count(device_t dev)
538323032Smav{
539323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
540323032Smav
541323032Smav	if (sc->b2b_mw >= 0 && sc->b2b_off == 0)
542323032Smav		return (sc->mw_count - 1); /* B2B consumed whole window. */
543323032Smav	return (sc->mw_count);
544323032Smav}
545323032Smav
546323032Smavstatic int
547323032Smavntb_plx_mw_get_range(device_t dev, unsigned mw_idx, vm_paddr_t *base,
548323032Smav    caddr_t *vbase, size_t *size, size_t *align, size_t *align_size,
549323032Smav    bus_addr_t *plimit)
550323032Smav{
551323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
552323032Smav	struct ntb_plx_mw_info *mw;
553323032Smav	size_t off;
554323032Smav
555323032Smav	if (mw_idx >= sc->mw_count)
556323032Smav		return (EINVAL);
557323032Smav	off = 0;
558323032Smav	if (mw_idx == sc->b2b_mw) {
559323032Smav		KASSERT(sc->b2b_off != 0,
560323032Smav		    ("user shouldn't get non-shared b2b mw"));
561323032Smav		off = sc->b2b_off;
562323032Smav	}
563323032Smav	mw = &sc->mw_info[mw_idx];
564323032Smav
565323032Smav	/* Local to remote memory window parameters. */
566323032Smav	if (base != NULL)
567323032Smav		*base = mw->mw_pbase + off;
568323032Smav	if (vbase != NULL)
569323032Smav		*vbase = mw->mw_vbase + off;
570323032Smav	if (size != NULL)
571323032Smav		*size = mw->mw_size - off;
572323032Smav
573323032Smav	/*
574323032Smav	 * Remote to local memory window translation address alignment.
575324407Smav	 * Translation address has to be aligned to the BAR size, but A-LUT
576324407Smav	 * entries re-map addresses can be aligned to 1/128 or 1/256 of it.
577324407Smav	 * XXX: In B2B mode we can change BAR size (and so alignmet) live,
578324407Smav	 * but there is no way to report it here, so report safe value.
579323032Smav	 */
580324407Smav	if (align != NULL) {
581324407Smav		if (sc->alut && mw->mw_bar == 2)
582324407Smav			*align = (mw->mw_size - off) / 128 / sc->alut;
583324407Smav		else
584324407Smav			*align = mw->mw_size - off;
585324407Smav	}
586323032Smav
587323032Smav	/*
588323032Smav	 * Remote to local memory window size alignment.
589324407Smav	 * The chip has no limit registers, but A-LUT, when available, allows
590324407Smav	 * access control with granularity of 1/128 or 1/256 of the BAR size.
591324407Smav	 * XXX: In B2B case we can change BAR size live, but there is no way
592324407Smav	 * to report it, so report half of the BAR size, that should be safe.
593324407Smav	 * In non-B2B case there is no control at all, so report the BAR size.
594323032Smav	 */
595323032Smav	if (align_size != NULL) {
596324407Smav		if (sc->alut && mw->mw_bar == 2)
597324407Smav			*align_size = (mw->mw_size - off) / 128 / sc->alut;
598324407Smav		else if (sc->b2b_mw >= 0)
599324407Smav			*align_size = (mw->mw_size - off) / 2;
600323032Smav		else
601323032Smav			*align_size = mw->mw_size - off;
602323032Smav	}
603323032Smav
604323032Smav	/* Remote to local memory window translation address upper limit. */
605323032Smav	if (plimit != NULL)
606323032Smav		*plimit = mw->mw_64bit ? BUS_SPACE_MAXADDR :
607323032Smav		    BUS_SPACE_MAXADDR_32BIT;
608323032Smav	return (0);
609323032Smav}
610323032Smav
611323032Smavstatic int
612323032Smavntb_plx_mw_set_trans_internal(device_t dev, unsigned mw_idx)
613323032Smav{
614323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
615323032Smav	struct ntb_plx_mw_info *mw;
616324407Smav	uint64_t addr, eaddr, off, size, bsize, esize, val64;
617323032Smav	uint32_t val;
618324407Smav	int i;
619323032Smav
620323032Smav	mw = &sc->mw_info[mw_idx];
621323032Smav	addr = mw->mw_xlat_addr;
622323032Smav	size = mw->mw_xlat_size;
623323032Smav	off = 0;
624323032Smav	if (mw_idx == sc->b2b_mw) {
625323032Smav		off = sc->b2b_off;
626323032Smav		KASSERT(off != 0, ("user shouldn't get non-shared b2b mw"));
627323032Smav
628323032Smav		/*
629323032Smav		 * While generally we can set any BAR size on link side,
630323032Smav		 * for B2B shared window we can't go above preconfigured
631323032Smav		 * size due to BAR address alignment requirements.
632323032Smav		 */
633323032Smav		if (size > mw->mw_size - off)
634323032Smav			return (EINVAL);
635323032Smav	}
636323032Smav
637323032Smav	if (size > 0) {
638323032Smav		/* Round BAR size to next power of 2 or at least 1MB. */
639324407Smav		bsize = size;
640324407Smav		if (!powerof2(bsize))
641324407Smav			bsize = 1LL << flsll(bsize);
642324407Smav		if (bsize < 1024 * 1024)
643324407Smav			bsize = 1024 * 1024;
644323032Smav
645324407Smav		/* A-LUT has 128 or 256 times better granularity. */
646324407Smav		esize = bsize;
647324407Smav		if (sc->alut && mw->mw_bar == 2)
648324407Smav			esize /= 128 * sc->alut;
649324407Smav
650324407Smav		/* addr should be aligned to BAR or A-LUT element size. */
651324407Smav		if ((addr & (esize - 1)) != 0)
652323032Smav			return (EINVAL);
653324407Smav	} else
654324407Smav		esize = bsize = 0;
655323032Smav
656323032Smav	if (mw->mw_64bit) {
657323032Smav		if (sc->b2b_mw >= 0) {
658323032Smav			/* Set Link Interface BAR size and enable/disable it. */
659323032Smav			val64 = 0;
660324407Smav			if (bsize > 0)
661324407Smav				val64 = (~(bsize - 1) & ~0xfffff);
662323844Smav			val64 |= 0xc;
663323032Smav			PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4, val64);
664323032Smav			PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4 + 4, val64 >> 32);
665323032Smav
666323032Smav			/* Set Link Interface BAR address. */
667323032Smav			val64 = 0x2000000000000000 * mw->mw_bar + off;
668323032Smav			PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar), val64);
669323032Smav			PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar) + 4, val64 >> 32);
670323032Smav		}
671323032Smav
672323032Smav		/* Set Virtual Interface BARs address translation */
673323032Smav		PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, addr);
674323032Smav		PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4 + 4, addr >> 32);
675323032Smav	} else {
676323032Smav		/* Make sure we fit into 32-bit address space. */
677323032Smav		if ((addr & UINT32_MAX) != addr)
678323032Smav			return (ERANGE);
679324407Smav		if (((addr + bsize) & UINT32_MAX) != (addr + bsize))
680323032Smav			return (ERANGE);
681323032Smav
682323032Smav		if (sc->b2b_mw >= 0) {
683323032Smav			/* Set Link Interface BAR size and enable/disable it. */
684323032Smav			val = 0;
685324407Smav			if (bsize > 0)
686324407Smav				val = (~(bsize - 1) & ~0xfffff);
687323032Smav			PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4, val);
688323032Smav
689323032Smav			/* Set Link Interface BAR address. */
690323032Smav			val64 = 0x20000000 * mw->mw_bar + off;
691323032Smav			PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar), val64);
692323032Smav		}
693323032Smav
694323032Smav		/* Set Virtual Interface BARs address translation */
695323032Smav		PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, addr);
696323032Smav	}
697324407Smav
698324407Smav	/* Configure and enable Link to Virtual A-LUT if we need it. */
699324407Smav	if (sc->alut && mw->mw_bar == 2 &&
700324407Smav	    ((addr & (bsize - 1)) != 0 || size != bsize)) {
701324407Smav		eaddr = addr;
702324407Smav		for (i = 0; i < 128 * sc->alut; i++) {
703324407Smav			val = sc->link ? 0 : 1;
704324407Smav			if (sc->alut == 1)
705324407Smav				val += 2 * sc->ntx;
706324407Smav			val *= 0x1000 * sc->alut;
707324407Smav			val += 0x38000 + i * 4 + (i >= 128 ? 0x0e00 : 0);
708324407Smav			bus_write_4(sc->conf_res, val, eaddr);
709324407Smav			bus_write_4(sc->conf_res, val + 0x400, eaddr >> 32);
710324407Smav			bus_write_4(sc->conf_res, val + 0x800,
711324407Smav			    (eaddr < addr + size) ? 0x3 : 0);
712324407Smav			eaddr += esize;
713324407Smav		}
714324407Smav		NTX_WRITE(sc, 0xc94, 0x10000000);
715324407Smav	} else if (sc->alut && mw->mw_bar == 2)
716324407Smav		NTX_WRITE(sc, 0xc94, 0);
717324407Smav
718323032Smav	return (0);
719323032Smav}
720323032Smav
721323032Smavstatic int
722323032Smavntb_plx_mw_set_trans(device_t dev, unsigned mw_idx, bus_addr_t addr, size_t size)
723323032Smav{
724323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
725323032Smav	struct ntb_plx_mw_info *mw;
726323032Smav
727323032Smav	if (mw_idx >= sc->mw_count)
728323032Smav		return (EINVAL);
729323032Smav	mw = &sc->mw_info[mw_idx];
730323032Smav	mw->mw_xlat_addr = addr;
731323032Smav	mw->mw_xlat_size = size;
732323032Smav	return (ntb_plx_mw_set_trans_internal(dev, mw_idx));
733323032Smav}
734323032Smav
735323032Smavstatic int
736323032Smavntb_plx_mw_clear_trans(device_t dev, unsigned mw_idx)
737323032Smav{
738323032Smav
739323032Smav	return (ntb_plx_mw_set_trans(dev, mw_idx, 0, 0));
740323032Smav}
741323032Smav
742323032Smavstatic int
743323032Smavntb_plx_mw_get_wc(device_t dev, unsigned idx, vm_memattr_t *mode)
744323032Smav{
745323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
746323032Smav	struct ntb_plx_mw_info *mw;
747323032Smav
748323032Smav	if (idx >= sc->mw_count)
749323032Smav		return (EINVAL);
750323032Smav	mw = &sc->mw_info[idx];
751323032Smav	*mode = mw->mw_map_mode;
752323032Smav	return (0);
753323032Smav}
754323032Smav
755323032Smavstatic int
756323032Smavntb_plx_mw_set_wc(device_t dev, unsigned idx, vm_memattr_t mode)
757323032Smav{
758323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
759323032Smav	struct ntb_plx_mw_info *mw;
760323032Smav	uint64_t off;
761323032Smav	int rc;
762323032Smav
763323032Smav	if (idx >= sc->mw_count)
764323032Smav		return (EINVAL);
765323032Smav	mw = &sc->mw_info[idx];
766323032Smav	if (mw->mw_map_mode == mode)
767323032Smav		return (0);
768323032Smav
769323032Smav	off = 0;
770323032Smav	if (idx == sc->b2b_mw) {
771323032Smav		KASSERT(sc->b2b_off != 0,
772323032Smav		    ("user shouldn't get non-shared b2b mw"));
773323032Smav		off = sc->b2b_off;
774323032Smav	}
775323032Smav
776323032Smav	rc = pmap_change_attr((vm_offset_t)mw->mw_vbase + off,
777323032Smav	    mw->mw_size - off, mode);
778323032Smav	if (rc == 0)
779323032Smav		mw->mw_map_mode = mode;
780323032Smav	return (rc);
781323032Smav}
782323032Smav
783323032Smavstatic uint8_t
784323032Smavntb_plx_spad_count(device_t dev)
785323032Smav{
786323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
787323032Smav
788323032Smav	return (sc->spad_count1 + sc->spad_count2);
789323032Smav}
790323032Smav
791323032Smavstatic int
792323032Smavntb_plx_spad_write(device_t dev, unsigned int idx, uint32_t val)
793323032Smav{
794323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
795323032Smav	u_int off;
796323032Smav
797323032Smav	if (idx >= sc->spad_count1 + sc->spad_count2)
798323032Smav		return (EINVAL);
799323032Smav
800323032Smav	if (idx < sc->spad_count1)
801323032Smav		off = sc->spad_off1 + idx * 4;
802323032Smav	else
803323032Smav		off = sc->spad_off2 + (idx - sc->spad_count1) * 4;
804323032Smav	bus_write_4(sc->conf_res, off, val);
805323032Smav	return (0);
806323032Smav}
807323032Smav
808323032Smavstatic void
809323032Smavntb_plx_spad_clear(device_t dev)
810323032Smav{
811323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
812323032Smav	int i;
813323032Smav
814323032Smav	for (i = 0; i < sc->spad_count1 + sc->spad_count2; i++)
815323032Smav		ntb_plx_spad_write(dev, i, 0);
816323032Smav}
817323032Smav
818323032Smavstatic int
819323032Smavntb_plx_spad_read(device_t dev, unsigned int idx, uint32_t *val)
820323032Smav{
821323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
822323032Smav	u_int off;
823323032Smav
824323032Smav	if (idx >= sc->spad_count1 + sc->spad_count2)
825323032Smav		return (EINVAL);
826323032Smav
827323032Smav	if (idx < sc->spad_count1)
828323032Smav		off = sc->spad_off1 + idx * 4;
829323032Smav	else
830323032Smav		off = sc->spad_off2 + (idx - sc->spad_count1) * 4;
831323032Smav	*val = bus_read_4(sc->conf_res, off);
832323032Smav	return (0);
833323032Smav}
834323032Smav
835323032Smavstatic int
836323032Smavntb_plx_peer_spad_write(device_t dev, unsigned int idx, uint32_t val)
837323032Smav{
838323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
839323032Smav	u_int off;
840323032Smav
841323032Smav	if (idx >= sc->spad_count1 + sc->spad_count2)
842323032Smav		return (EINVAL);
843323032Smav
844323032Smav	if (idx < sc->spad_count1)
845323032Smav		off = sc->spad_offp1 + idx * 4;
846323032Smav	else
847323032Smav		off = sc->spad_offp2 + (idx - sc->spad_count1) * 4;
848323032Smav	if (sc->b2b_mw >= 0)
849323032Smav		bus_write_4(sc->mw_info[sc->b2b_mw].mw_res, off, val);
850323032Smav	else
851323032Smav		bus_write_4(sc->conf_res, off, val);
852323032Smav	return (0);
853323032Smav}
854323032Smav
855323032Smavstatic int
856323032Smavntb_plx_peer_spad_read(device_t dev, unsigned int idx, uint32_t *val)
857323032Smav{
858323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
859323032Smav	u_int off;
860323032Smav
861323032Smav	if (idx >= sc->spad_count1 + sc->spad_count2)
862323032Smav		return (EINVAL);
863323032Smav
864323032Smav	if (idx < sc->spad_count1)
865323032Smav		off = sc->spad_offp1 + idx * 4;
866323032Smav	else
867323032Smav		off = sc->spad_offp2 + (idx - sc->spad_count1) * 4;
868323032Smav	if (sc->b2b_mw >= 0)
869323032Smav		*val = bus_read_4(sc->mw_info[sc->b2b_mw].mw_res, off);
870323032Smav	else
871323032Smav		*val = bus_read_4(sc->conf_res, off);
872323032Smav	return (0);
873323032Smav}
874323032Smav
875323032Smavstatic uint64_t
876323032Smavntb_plx_db_valid_mask(device_t dev)
877323032Smav{
878323032Smav
879323032Smav	return ((1LL << PLX_NUM_DB) - 1);
880323032Smav}
881323032Smav
882323032Smavstatic int
883323032Smavntb_plx_db_vector_count(device_t dev)
884323032Smav{
885323032Smav
886323032Smav	return (1);
887323032Smav}
888323032Smav
889323032Smavstatic uint64_t
890323032Smavntb_plx_db_vector_mask(device_t dev, uint32_t vector)
891323032Smav{
892323032Smav
893323032Smav	if (vector > 0)
894323032Smav		return (0);
895323032Smav	return ((1LL << PLX_NUM_DB) - 1);
896323032Smav}
897323032Smav
898323032Smavstatic void
899323032Smavntb_plx_db_clear(device_t dev, uint64_t bits)
900323032Smav{
901323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
902323032Smav
903323032Smav	NTX_WRITE(sc, sc->link ? 0xc60 : 0xc50, bits);
904323032Smav}
905323032Smav
906323032Smavstatic void
907323032Smavntb_plx_db_clear_mask(device_t dev, uint64_t bits)
908323032Smav{
909323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
910323032Smav
911323032Smav	NTX_WRITE(sc, sc->link ? 0xc68 : 0xc58, bits);
912323032Smav}
913323032Smav
914323032Smavstatic uint64_t
915323032Smavntb_plx_db_read(device_t dev)
916323032Smav{
917323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
918323032Smav
919323032Smav	return (NTX_READ(sc, sc->link ? 0xc5c : 0xc4c));
920323032Smav}
921323032Smav
922323032Smavstatic void
923323032Smavntb_plx_db_set_mask(device_t dev, uint64_t bits)
924323032Smav{
925323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
926323032Smav
927323032Smav	NTX_WRITE(sc, sc->link ? 0xc64 : 0xc54, bits);
928323032Smav}
929323032Smav
930323032Smavstatic int
931323032Smavntb_plx_peer_db_addr(device_t dev, bus_addr_t *db_addr, vm_size_t *db_size)
932323032Smav{
933323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
934323032Smav	struct ntb_plx_mw_info *mw;
935323032Smav
936323032Smav	KASSERT((db_addr != NULL && db_size != NULL), ("must be non-NULL"));
937323032Smav
938323032Smav	if (sc->b2b_mw >= 0) {
939323032Smav		mw = &sc->mw_info[sc->b2b_mw];
940323032Smav		*db_addr = (uint64_t)mw->mw_pbase + PLX_NTX_BASE(sc) + 0xc4c;
941323032Smav	} else {
942323032Smav		*db_addr = rman_get_start(sc->conf_res) + PLX_NTX_BASE(sc);
943323032Smav		*db_addr += sc->link ? 0xc4c : 0xc5c;
944323032Smav	}
945323032Smav	*db_size = 4;
946323032Smav	return (0);
947323032Smav}
948323032Smav
949323032Smavstatic void
950323032Smavntb_plx_peer_db_set(device_t dev, uint64_t bit)
951323032Smav{
952323032Smav	struct ntb_plx_softc *sc = device_get_softc(dev);
953323032Smav
954323032Smav	if (sc->b2b_mw >= 0)
955323032Smav		BNTX_WRITE(sc, 0xc4c, bit);
956323032Smav	else
957323032Smav		NTX_WRITE(sc, sc->link ? 0xc4c : 0xc5c, bit);
958323032Smav}
959323032Smav
960323032Smavstatic device_method_t ntb_plx_methods[] = {
961323032Smav	/* Device interface */
962323032Smav	DEVMETHOD(device_probe,		ntb_plx_probe),
963323032Smav	DEVMETHOD(device_attach,	ntb_plx_attach),
964323032Smav	DEVMETHOD(device_detach,	ntb_plx_detach),
965323455Smav	/* Bus interface */
966323455Smav	DEVMETHOD(bus_child_location_str, ntb_child_location_str),
967323455Smav	DEVMETHOD(bus_print_child,	ntb_print_child),
968323032Smav	/* NTB interface */
969323032Smav	DEVMETHOD(ntb_link_is_up,	ntb_plx_link_is_up),
970323032Smav	DEVMETHOD(ntb_link_enable,	ntb_plx_link_enable),
971323032Smav	DEVMETHOD(ntb_link_disable,	ntb_plx_link_disable),
972323032Smav	DEVMETHOD(ntb_link_enabled,	ntb_plx_link_enabled),
973323032Smav	DEVMETHOD(ntb_mw_count,		ntb_plx_mw_count),
974323032Smav	DEVMETHOD(ntb_mw_get_range,	ntb_plx_mw_get_range),
975323032Smav	DEVMETHOD(ntb_mw_set_trans,	ntb_plx_mw_set_trans),
976323032Smav	DEVMETHOD(ntb_mw_clear_trans,	ntb_plx_mw_clear_trans),
977323032Smav	DEVMETHOD(ntb_mw_get_wc,	ntb_plx_mw_get_wc),
978323032Smav	DEVMETHOD(ntb_mw_set_wc,	ntb_plx_mw_set_wc),
979323032Smav	DEVMETHOD(ntb_spad_count,	ntb_plx_spad_count),
980323032Smav	DEVMETHOD(ntb_spad_clear,	ntb_plx_spad_clear),
981323032Smav	DEVMETHOD(ntb_spad_write,	ntb_plx_spad_write),
982323032Smav	DEVMETHOD(ntb_spad_read,	ntb_plx_spad_read),
983323032Smav	DEVMETHOD(ntb_peer_spad_write,	ntb_plx_peer_spad_write),
984323032Smav	DEVMETHOD(ntb_peer_spad_read,	ntb_plx_peer_spad_read),
985323032Smav	DEVMETHOD(ntb_db_valid_mask,	ntb_plx_db_valid_mask),
986323032Smav	DEVMETHOD(ntb_db_vector_count,	ntb_plx_db_vector_count),
987323032Smav	DEVMETHOD(ntb_db_vector_mask,	ntb_plx_db_vector_mask),
988323032Smav	DEVMETHOD(ntb_db_clear,		ntb_plx_db_clear),
989323032Smav	DEVMETHOD(ntb_db_clear_mask,	ntb_plx_db_clear_mask),
990323032Smav	DEVMETHOD(ntb_db_read,		ntb_plx_db_read),
991323032Smav	DEVMETHOD(ntb_db_set_mask,	ntb_plx_db_set_mask),
992323032Smav	DEVMETHOD(ntb_peer_db_addr,	ntb_plx_peer_db_addr),
993323032Smav	DEVMETHOD(ntb_peer_db_set,	ntb_plx_peer_db_set),
994323032Smav	DEVMETHOD_END
995323032Smav};
996323032Smav
997323032Smavstatic DEFINE_CLASS_0(ntb_hw, ntb_plx_driver, ntb_plx_methods,
998323032Smav    sizeof(struct ntb_plx_softc));
999323032SmavDRIVER_MODULE(ntb_hw_plx, pci, ntb_plx_driver, ntb_hw_devclass, NULL, NULL);
1000323032SmavMODULE_DEPEND(ntb_hw_plx, ntb, 1, 1, 1);
1001323032SmavMODULE_VERSION(ntb_hw_plx, 1);
1002