1ed9652daSAlexander Motin /*-
27aafa7c3SAlexander Motin * Copyright (c) 2017-2019 Alexander Motin <mav@FreeBSD.org>
3ed9652daSAlexander Motin * All rights reserved.
4ed9652daSAlexander Motin *
5ed9652daSAlexander Motin * Redistribution and use in source and binary forms, with or without
6ed9652daSAlexander Motin * modification, are permitted provided that the following conditions
7ed9652daSAlexander Motin * are met:
8ed9652daSAlexander Motin * 1. Redistributions of source code must retain the above copyright
9ed9652daSAlexander Motin * notice, this list of conditions and the following disclaimer.
10ed9652daSAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright
11ed9652daSAlexander Motin * notice, this list of conditions and the following disclaimer in the
12ed9652daSAlexander Motin * documentation and/or other materials provided with the distribution.
13ed9652daSAlexander Motin *
14ed9652daSAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15ed9652daSAlexander Motin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16ed9652daSAlexander Motin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ed9652daSAlexander Motin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18ed9652daSAlexander Motin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19ed9652daSAlexander Motin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20ed9652daSAlexander Motin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21ed9652daSAlexander Motin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22ed9652daSAlexander Motin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23ed9652daSAlexander Motin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24ed9652daSAlexander Motin * SUCH DAMAGE.
25ed9652daSAlexander Motin */
26ed9652daSAlexander Motin
27ed9652daSAlexander Motin /*
28ed9652daSAlexander Motin * The Non-Transparent Bridge (NTB) is a device that allows you to connect
29ed9652daSAlexander Motin * two or more systems using a PCI-e links, providing remote memory access.
30ed9652daSAlexander Motin *
31ed9652daSAlexander Motin * This module contains a driver for NTBs in PLX/Avago/Broadcom PCIe bridges.
32ed9652daSAlexander Motin */
33ed9652daSAlexander Motin
34ed9652daSAlexander Motin #include <sys/param.h>
35ed9652daSAlexander Motin #include <sys/kernel.h>
36ed9652daSAlexander Motin #include <sys/systm.h>
37ed9652daSAlexander Motin #include <sys/bus.h>
38ed9652daSAlexander Motin #include <sys/interrupt.h>
39ed9652daSAlexander Motin #include <sys/module.h>
40ed9652daSAlexander Motin #include <sys/rman.h>
41ed9652daSAlexander Motin #include <sys/sysctl.h>
42c8597a1fSRuslan Bukin #include <sys/taskqueue.h>
43c8597a1fSRuslan Bukin #include <sys/tree.h>
44ed9652daSAlexander Motin #include <vm/vm.h>
45ed9652daSAlexander Motin #include <vm/pmap.h>
46ed9652daSAlexander Motin #include <machine/bus.h>
47ed9652daSAlexander Motin #include <machine/intr_machdep.h>
48ed9652daSAlexander Motin #include <machine/resource.h>
49ed9652daSAlexander Motin #include <dev/pci/pcireg.h>
50ed9652daSAlexander Motin #include <dev/pci/pcivar.h>
519abb9265SRuslan Bukin #include <dev/iommu/iommu.h>
52ed9652daSAlexander Motin
53ed9652daSAlexander Motin #include "../ntb.h"
54ed9652daSAlexander Motin
55ed9652daSAlexander Motin #define PLX_MAX_BARS 4 /* There are at most 4 data BARs. */
56ed9652daSAlexander Motin #define PLX_NUM_SPAD 8 /* There are 8 scratchpads. */
57ed9652daSAlexander Motin #define PLX_NUM_SPAD_PATT 4 /* Use test pattern as 4 more. */
58ed9652daSAlexander Motin #define PLX_NUM_DB 16 /* There are 16 doorbells. */
597aafa7c3SAlexander Motin #define PLX_MAX_SPLIT 128 /* Allow are at most 128 splits. */
60ed9652daSAlexander Motin
61ed9652daSAlexander Motin struct ntb_plx_mw_info {
62ed9652daSAlexander Motin int mw_bar;
63ed9652daSAlexander Motin int mw_64bit;
64ed9652daSAlexander Motin int mw_rid;
65ed9652daSAlexander Motin struct resource *mw_res;
66ed9652daSAlexander Motin vm_paddr_t mw_pbase;
67ed9652daSAlexander Motin caddr_t mw_vbase;
68ed9652daSAlexander Motin vm_size_t mw_size;
697aafa7c3SAlexander Motin struct {
70ed9652daSAlexander Motin vm_memattr_t mw_map_mode;
71ed9652daSAlexander Motin bus_addr_t mw_xlat_addr;
727aafa7c3SAlexander Motin bus_size_t mw_xlat_size;
737aafa7c3SAlexander Motin } splits[PLX_MAX_SPLIT];
74ed9652daSAlexander Motin };
75ed9652daSAlexander Motin
76ed9652daSAlexander Motin struct ntb_plx_softc {
77ed9652daSAlexander Motin /* ntb.c context. Do not move! Must go first! */
78ed9652daSAlexander Motin void *ntb_store;
79ed9652daSAlexander Motin
80ed9652daSAlexander Motin device_t dev;
81ed9652daSAlexander Motin struct resource *conf_res;
82ed9652daSAlexander Motin int conf_rid;
83ed9652daSAlexander Motin u_int ntx; /* NTx number within chip. */
84ed9652daSAlexander Motin u_int link; /* Link v/s Virtual side. */
85ed9652daSAlexander Motin u_int port; /* Port number within chip. */
8621811c24SAlexander Motin u_int alut; /* A-LUT is enabled for NTx */
877aafa7c3SAlexander Motin u_int split; /* split BAR2 into 2^x parts */
88ed9652daSAlexander Motin
89ed9652daSAlexander Motin int int_rid;
90ed9652daSAlexander Motin struct resource *int_res;
91ed9652daSAlexander Motin void *int_tag;
92ed9652daSAlexander Motin
93ed9652daSAlexander Motin struct ntb_plx_mw_info mw_info[PLX_MAX_BARS];
94ed9652daSAlexander Motin int mw_count; /* Number of memory windows. */
95ed9652daSAlexander Motin
96ed9652daSAlexander Motin int spad_count1; /* Number of standard spads. */
97ed9652daSAlexander Motin int spad_count2; /* Number of extra spads. */
98ed9652daSAlexander Motin uint32_t spad_off1; /* Offset of our spads. */
99ed9652daSAlexander Motin uint32_t spad_off2; /* Offset of our extra spads. */
100ed9652daSAlexander Motin uint32_t spad_offp1; /* Offset of peer spads. */
101ed9652daSAlexander Motin uint32_t spad_offp2; /* Offset of peer extra spads. */
102ed9652daSAlexander Motin
103ed9652daSAlexander Motin /* Parameters of window shared with peer config access in B2B mode. */
104ed9652daSAlexander Motin int b2b_mw; /* Shared window number. */
105ed9652daSAlexander Motin uint64_t b2b_off; /* Offset in shared window. */
106ed9652daSAlexander Motin };
107ed9652daSAlexander Motin
108ed9652daSAlexander Motin #define PLX_NT0_BASE 0x3E000
109ed9652daSAlexander Motin #define PLX_NT1_BASE 0x3C000
110ed9652daSAlexander Motin #define PLX_NTX_BASE(sc) ((sc)->ntx ? PLX_NT1_BASE : PLX_NT0_BASE)
111ed9652daSAlexander Motin #define PLX_NTX_LINK_OFFSET 0x01000
112ed9652daSAlexander Motin
113ed9652daSAlexander Motin /* Bases of NTx our/peer interface registers */
1140faf5914SAlexander Motin #define PLX_NTX_OUR_BASE(sc) \
115ed9652daSAlexander Motin (PLX_NTX_BASE(sc) + ((sc)->link ? PLX_NTX_LINK_OFFSET : 0))
1160faf5914SAlexander Motin #define PLX_NTX_PEER_BASE(sc) \
117ed9652daSAlexander Motin (PLX_NTX_BASE(sc) + ((sc)->link ? 0 : PLX_NTX_LINK_OFFSET))
118ed9652daSAlexander Motin
119ed9652daSAlexander Motin /* Read/write NTx our interface registers */
120ed9652daSAlexander Motin #define NTX_READ(sc, reg) \
1210faf5914SAlexander Motin bus_read_4((sc)->conf_res, PLX_NTX_OUR_BASE(sc) + (reg))
122ed9652daSAlexander Motin #define NTX_WRITE(sc, reg, val) \
1230faf5914SAlexander Motin bus_write_4((sc)->conf_res, PLX_NTX_OUR_BASE(sc) + (reg), (val))
124ed9652daSAlexander Motin
125ed9652daSAlexander Motin /* Read/write NTx peer interface registers */
126ed9652daSAlexander Motin #define PNTX_READ(sc, reg) \
1270faf5914SAlexander Motin bus_read_4((sc)->conf_res, PLX_NTX_PEER_BASE(sc) + (reg))
128ed9652daSAlexander Motin #define PNTX_WRITE(sc, reg, val) \
1290faf5914SAlexander Motin bus_write_4((sc)->conf_res, PLX_NTX_PEER_BASE(sc) + (reg), (val))
130ed9652daSAlexander Motin
131ed9652daSAlexander Motin /* Read/write B2B NTx registers */
132ed9652daSAlexander Motin #define BNTX_READ(sc, reg) \
133ed9652daSAlexander Motin bus_read_4((sc)->mw_info[(sc)->b2b_mw].mw_res, \
134ed9652daSAlexander Motin PLX_NTX_BASE(sc) + (reg))
135ed9652daSAlexander Motin #define BNTX_WRITE(sc, reg, val) \
136ed9652daSAlexander Motin bus_write_4((sc)->mw_info[(sc)->b2b_mw].mw_res, \
137ed9652daSAlexander Motin PLX_NTX_BASE(sc) + (reg), (val))
138ed9652daSAlexander Motin
1390faf5914SAlexander Motin #define PLX_PORT_BASE(p) ((p) << 12)
1400faf5914SAlexander Motin #define PLX_STATION_PORT_BASE(sc) PLX_PORT_BASE((sc)->port & ~7)
1410faf5914SAlexander Motin
1420faf5914SAlexander Motin #define PLX_PORT_CONTROL(sc) (PLX_STATION_PORT_BASE(sc) + 0x208)
1430faf5914SAlexander Motin
144ed9652daSAlexander Motin static int ntb_plx_init(device_t dev);
145ed9652daSAlexander Motin static int ntb_plx_detach(device_t dev);
146ed9652daSAlexander Motin static int ntb_plx_mw_set_trans_internal(device_t dev, unsigned mw_idx);
147ed9652daSAlexander Motin
148ed9652daSAlexander Motin static int
ntb_plx_probe(device_t dev)149ed9652daSAlexander Motin ntb_plx_probe(device_t dev)
150ed9652daSAlexander Motin {
151ed9652daSAlexander Motin
152ed9652daSAlexander Motin switch (pci_get_devid(dev)) {
153ed9652daSAlexander Motin case 0x87a010b5:
154ed9652daSAlexander Motin device_set_desc(dev, "PLX Non-Transparent Bridge NT0 Link");
155ed9652daSAlexander Motin return (BUS_PROBE_DEFAULT);
156ed9652daSAlexander Motin case 0x87a110b5:
157ed9652daSAlexander Motin device_set_desc(dev, "PLX Non-Transparent Bridge NT1 Link");
158ed9652daSAlexander Motin return (BUS_PROBE_DEFAULT);
159ed9652daSAlexander Motin case 0x87b010b5:
160ed9652daSAlexander Motin device_set_desc(dev, "PLX Non-Transparent Bridge NT0 Virtual");
161ed9652daSAlexander Motin return (BUS_PROBE_DEFAULT);
162ed9652daSAlexander Motin case 0x87b110b5:
163ed9652daSAlexander Motin device_set_desc(dev, "PLX Non-Transparent Bridge NT1 Virtual");
164ed9652daSAlexander Motin return (BUS_PROBE_DEFAULT);
165ed9652daSAlexander Motin }
166ed9652daSAlexander Motin return (ENXIO);
167ed9652daSAlexander Motin }
168ed9652daSAlexander Motin
169ed9652daSAlexander Motin static int
ntb_plx_init(device_t dev)170ed9652daSAlexander Motin ntb_plx_init(device_t dev)
171ed9652daSAlexander Motin {
172ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
173ed9652daSAlexander Motin struct ntb_plx_mw_info *mw;
174ed9652daSAlexander Motin uint64_t val64;
175ed9652daSAlexander Motin int i;
176ed9652daSAlexander Motin uint32_t val;
177ed9652daSAlexander Motin
178ed9652daSAlexander Motin if (sc->b2b_mw >= 0) {
179ed9652daSAlexander Motin /* Set peer BAR0/1 size and address for B2B NTx access. */
180ed9652daSAlexander Motin mw = &sc->mw_info[sc->b2b_mw];
181ed9652daSAlexander Motin if (mw->mw_64bit) {
182ed9652daSAlexander Motin PNTX_WRITE(sc, 0xe4, 0x3); /* 64-bit */
183ed9652daSAlexander Motin val64 = 0x2000000000000000 * mw->mw_bar | 0x4;
184ed9652daSAlexander Motin PNTX_WRITE(sc, PCIR_BAR(0), val64);
185ed9652daSAlexander Motin PNTX_WRITE(sc, PCIR_BAR(0) + 4, val64 >> 32);
186ed9652daSAlexander Motin } else {
187ed9652daSAlexander Motin PNTX_WRITE(sc, 0xe4, 0x2); /* 32-bit */
188ed9652daSAlexander Motin val = 0x20000000 * mw->mw_bar;
189ed9652daSAlexander Motin PNTX_WRITE(sc, PCIR_BAR(0), val);
190ed9652daSAlexander Motin }
191ed9652daSAlexander Motin
192ed9652daSAlexander Motin /* Set Virtual to Link address translation for B2B. */
193ed9652daSAlexander Motin for (i = 0; i < sc->mw_count; i++) {
194ed9652daSAlexander Motin mw = &sc->mw_info[i];
195ed9652daSAlexander Motin if (mw->mw_64bit) {
196ed9652daSAlexander Motin val64 = 0x2000000000000000 * mw->mw_bar;
197ed9652daSAlexander Motin NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, val64);
198ed9652daSAlexander Motin NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4 + 4, val64 >> 32);
199ed9652daSAlexander Motin } else {
200ed9652daSAlexander Motin val = 0x20000000 * mw->mw_bar;
201ed9652daSAlexander Motin NTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, val);
202ed9652daSAlexander Motin }
203ed9652daSAlexander Motin }
204ed9652daSAlexander Motin
20521811c24SAlexander Motin /* Make sure Virtual to Link A-LUT is disabled. */
20621811c24SAlexander Motin if (sc->alut)
20721811c24SAlexander Motin PNTX_WRITE(sc, 0xc94, 0);
20821811c24SAlexander Motin
209a8bc5594SAlexander Motin /* Enable all Link Interface LUT entries for peer. */
210a8bc5594SAlexander Motin for (i = 0; i < 32; i += 2) {
211a8bc5594SAlexander Motin PNTX_WRITE(sc, 0xdb4 + i * 2,
212a8bc5594SAlexander Motin 0x00010001 | ((i + 1) << 19) | (i << 3));
213a8bc5594SAlexander Motin }
214ed9652daSAlexander Motin }
215ed9652daSAlexander Motin
216ed9652daSAlexander Motin /*
217a8bc5594SAlexander Motin * Enable Virtual Interface LUT entry 0 for 0:0.*.
218a8bc5594SAlexander Motin * entry 1 for our Requester ID reported by the chip,
219a8bc5594SAlexander Motin * entries 2-5 for 0/64/128/192:4.* of I/OAT DMA engines.
220a8bc5594SAlexander Motin * XXX: Its a hack, we can't know all DMA engines, but this covers all
221a8bc5594SAlexander Motin * I/OAT of Xeon E5/E7 at least from Sandy Bridge till Skylake I saw.
222ed9652daSAlexander Motin */
223ed9652daSAlexander Motin val = (NTX_READ(sc, 0xc90) << 16) | 0x00010001;
224ed9652daSAlexander Motin NTX_WRITE(sc, sc->link ? 0xdb4 : 0xd94, val);
225a8bc5594SAlexander Motin NTX_WRITE(sc, sc->link ? 0xdb8 : 0xd98, 0x40210021);
226a8bc5594SAlexander Motin NTX_WRITE(sc, sc->link ? 0xdbc : 0xd9c, 0xc0218021);
227ed9652daSAlexander Motin
228ed9652daSAlexander Motin /* Set Link to Virtual address translation. */
2297aafa7c3SAlexander Motin for (i = 0; i < sc->mw_count; i++)
230ed9652daSAlexander Motin ntb_plx_mw_set_trans_internal(dev, i);
231ed9652daSAlexander Motin
232ed9652daSAlexander Motin pci_enable_busmaster(dev);
233ed9652daSAlexander Motin if (sc->b2b_mw >= 0)
234ed9652daSAlexander Motin PNTX_WRITE(sc, PCIR_COMMAND, PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
235ed9652daSAlexander Motin
236ed9652daSAlexander Motin return (0);
237ed9652daSAlexander Motin }
238ed9652daSAlexander Motin
239ed9652daSAlexander Motin static void
ntb_plx_isr(void * arg)240ed9652daSAlexander Motin ntb_plx_isr(void *arg)
241ed9652daSAlexander Motin {
242ed9652daSAlexander Motin device_t dev = arg;
243ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
244ed9652daSAlexander Motin uint32_t val;
245ed9652daSAlexander Motin
246ed9652daSAlexander Motin ntb_db_event((device_t)arg, 0);
247ed9652daSAlexander Motin
24808dc7816SAlexander Motin if (sc->link) /* Link Interface has no Link Error registers. */
24908dc7816SAlexander Motin return;
25008dc7816SAlexander Motin
251ed9652daSAlexander Motin val = NTX_READ(sc, 0xfe0);
252ed9652daSAlexander Motin if (val == 0)
253ed9652daSAlexander Motin return;
254ed9652daSAlexander Motin NTX_WRITE(sc, 0xfe0, val);
255ed9652daSAlexander Motin if (val & 1)
256ed9652daSAlexander Motin device_printf(dev, "Correctable Error\n");
257ed9652daSAlexander Motin if (val & 2)
258ed9652daSAlexander Motin device_printf(dev, "Uncorrectable Error\n");
259ed9652daSAlexander Motin if (val & 4) {
260ed9652daSAlexander Motin /* DL_Down resets link side registers, have to reinit. */
261ed9652daSAlexander Motin ntb_plx_init(dev);
262ed9652daSAlexander Motin ntb_link_event(dev);
263ed9652daSAlexander Motin }
264ed9652daSAlexander Motin if (val & 8)
265ed9652daSAlexander Motin device_printf(dev, "Uncorrectable Error Message Drop\n");
266ed9652daSAlexander Motin }
267ed9652daSAlexander Motin
268ed9652daSAlexander Motin static int
ntb_plx_setup_intr(device_t dev)269ed9652daSAlexander Motin ntb_plx_setup_intr(device_t dev)
270ed9652daSAlexander Motin {
271ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
272ed9652daSAlexander Motin int error;
273ed9652daSAlexander Motin
274ed9652daSAlexander Motin /*
275ed9652daSAlexander Motin * XXX: This hardware supports MSI, but I found it unusable.
276ed9652daSAlexander Motin * It generates new MSI only when doorbell register goes from
277ed9652daSAlexander Motin * zero, but does not generate it when another bit is set or on
278ed9652daSAlexander Motin * partial clear. It makes operation very racy and unreliable.
279ed9652daSAlexander Motin * The data book mentions some mask juggling magic to workaround
280ed9652daSAlexander Motin * that, but I failed to make it work.
281ed9652daSAlexander Motin */
282ed9652daSAlexander Motin sc->int_rid = 0;
283ed9652daSAlexander Motin sc->int_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
284ed9652daSAlexander Motin &sc->int_rid, RF_SHAREABLE|RF_ACTIVE);
285ed9652daSAlexander Motin if (sc->int_res == NULL) {
286ed9652daSAlexander Motin device_printf(dev, "bus_alloc_resource failed\n");
287ed9652daSAlexander Motin return (ENOMEM);
288ed9652daSAlexander Motin }
289ed9652daSAlexander Motin error = bus_setup_intr(dev, sc->int_res, INTR_MPSAFE | INTR_TYPE_MISC,
290ed9652daSAlexander Motin NULL, ntb_plx_isr, dev, &sc->int_tag);
291ed9652daSAlexander Motin if (error != 0) {
292ed9652daSAlexander Motin device_printf(dev, "bus_setup_intr failed: %d\n", error);
293ed9652daSAlexander Motin return (error);
294ed9652daSAlexander Motin }
29508dc7816SAlexander Motin
29608dc7816SAlexander Motin if (!sc->link) { /* Link Interface has no Link Error registers. */
297ed9652daSAlexander Motin NTX_WRITE(sc, 0xfe0, 0xf); /* Clear link interrupts. */
298ed9652daSAlexander Motin NTX_WRITE(sc, 0xfe4, 0x0); /* Unmask link interrupts. */
29908dc7816SAlexander Motin }
300ed9652daSAlexander Motin return (0);
301ed9652daSAlexander Motin }
302ed9652daSAlexander Motin
303ed9652daSAlexander Motin static void
ntb_plx_teardown_intr(device_t dev)304ed9652daSAlexander Motin ntb_plx_teardown_intr(device_t dev)
305ed9652daSAlexander Motin {
306ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
307ed9652daSAlexander Motin
30808dc7816SAlexander Motin if (!sc->link) /* Link Interface has no Link Error registers. */
309ed9652daSAlexander Motin NTX_WRITE(sc, 0xfe4, 0xf); /* Mask link interrupts. */
31008dc7816SAlexander Motin
311ed9652daSAlexander Motin if (sc->int_res) {
312ed9652daSAlexander Motin bus_teardown_intr(dev, sc->int_res, sc->int_tag);
313ed9652daSAlexander Motin bus_release_resource(dev, SYS_RES_IRQ, sc->int_rid,
314ed9652daSAlexander Motin sc->int_res);
315ed9652daSAlexander Motin }
316ed9652daSAlexander Motin }
317ed9652daSAlexander Motin
318ed9652daSAlexander Motin static int
ntb_plx_attach(device_t dev)319ed9652daSAlexander Motin ntb_plx_attach(device_t dev)
320ed9652daSAlexander Motin {
321ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
322ed9652daSAlexander Motin struct ntb_plx_mw_info *mw;
3237aafa7c3SAlexander Motin int error = 0, i, j;
324ed9652daSAlexander Motin uint32_t val;
325ed9652daSAlexander Motin char buf[32];
326ed9652daSAlexander Motin
327ed9652daSAlexander Motin /* Identify what we are (what side of what NTx). */
328ed9652daSAlexander Motin sc->dev = dev;
329ed9652daSAlexander Motin val = pci_read_config(dev, 0xc8c, 4);
330ed9652daSAlexander Motin sc->ntx = (val & 1) != 0;
331ed9652daSAlexander Motin sc->link = (val & 0x80000000) != 0;
332ed9652daSAlexander Motin
333ed9652daSAlexander Motin /* Get access to whole 256KB of chip configuration space via BAR0/1. */
334ed9652daSAlexander Motin sc->conf_rid = PCIR_BAR(0);
335ed9652daSAlexander Motin sc->conf_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
336ed9652daSAlexander Motin &sc->conf_rid, RF_ACTIVE);
337ed9652daSAlexander Motin if (sc->conf_res == NULL) {
338ed9652daSAlexander Motin device_printf(dev, "Can't allocate configuration BAR.\n");
339ed9652daSAlexander Motin return (ENXIO);
340ed9652daSAlexander Motin }
341ed9652daSAlexander Motin
342f0dd6a17SAlexander Motin /*
343f0dd6a17SAlexander Motin * The device occupies whole bus. In translated TLP slot field
344f0dd6a17SAlexander Motin * keeps LUT index (original bus/slot), function is passed through.
345f0dd6a17SAlexander Motin */
346ea4c0115SRuslan Bukin bus_dma_iommu_set_buswide(dev);
347f0dd6a17SAlexander Motin
348ed9652daSAlexander Motin /* Identify chip port we are connected to. */
349ed9652daSAlexander Motin val = bus_read_4(sc->conf_res, 0x360);
350ed9652daSAlexander Motin sc->port = (val >> ((sc->ntx == 0) ? 8 : 16)) & 0x1f;
351ed9652daSAlexander Motin
35221811c24SAlexander Motin /* Detect A-LUT enable and size. */
35321811c24SAlexander Motin val >>= 30;
35421811c24SAlexander Motin sc->alut = (val == 0x3) ? 1 : ((val & (1 << sc->ntx)) ? 2 : 0);
35521811c24SAlexander Motin if (sc->alut)
35621811c24SAlexander Motin device_printf(dev, "%u A-LUT entries\n", 128 * sc->alut);
35721811c24SAlexander Motin
358ed9652daSAlexander Motin /* Find configured memory windows at BAR2-5. */
359ed9652daSAlexander Motin sc->mw_count = 0;
360ed9652daSAlexander Motin for (i = 2; i <= 5; i++) {
361ed9652daSAlexander Motin mw = &sc->mw_info[sc->mw_count];
362ed9652daSAlexander Motin mw->mw_bar = i;
363ed9652daSAlexander Motin mw->mw_rid = PCIR_BAR(mw->mw_bar);
364ed9652daSAlexander Motin mw->mw_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
365ed9652daSAlexander Motin &mw->mw_rid, RF_ACTIVE);
366ed9652daSAlexander Motin if (mw->mw_res == NULL)
367ed9652daSAlexander Motin continue;
368ed9652daSAlexander Motin mw->mw_pbase = rman_get_start(mw->mw_res);
369ed9652daSAlexander Motin mw->mw_size = rman_get_size(mw->mw_res);
370ed9652daSAlexander Motin mw->mw_vbase = rman_get_virtual(mw->mw_res);
3717aafa7c3SAlexander Motin for (j = 0; j < PLX_MAX_SPLIT; j++)
3727aafa7c3SAlexander Motin mw->splits[j].mw_map_mode = VM_MEMATTR_UNCACHEABLE;
373ed9652daSAlexander Motin sc->mw_count++;
374ed9652daSAlexander Motin
375ed9652daSAlexander Motin /* Skip over adjacent BAR for 64-bit BARs. */
376ed9652daSAlexander Motin val = pci_read_config(dev, PCIR_BAR(mw->mw_bar), 4);
377ed9652daSAlexander Motin if ((val & PCIM_BAR_MEM_TYPE) == PCIM_BAR_MEM_64) {
378ed9652daSAlexander Motin mw->mw_64bit = 1;
379ed9652daSAlexander Motin i++;
380ed9652daSAlexander Motin }
381ed9652daSAlexander Motin }
382ed9652daSAlexander Motin
383ed9652daSAlexander Motin /* Try to identify B2B mode. */
384ed9652daSAlexander Motin i = 1;
385ed9652daSAlexander Motin snprintf(buf, sizeof(buf), "hint.%s.%d.b2b", device_get_name(dev),
386ed9652daSAlexander Motin device_get_unit(dev));
387ed9652daSAlexander Motin TUNABLE_INT_FETCH(buf, &i);
388ed9652daSAlexander Motin if (sc->link) {
389ed9652daSAlexander Motin device_printf(dev, "NTB-to-Root Port mode (Link Interface)\n");
390ed9652daSAlexander Motin sc->b2b_mw = -1;
391ed9652daSAlexander Motin } else if (i == 0) {
392ed9652daSAlexander Motin device_printf(dev, "NTB-to-Root Port mode (Virtual Interface)\n");
393ed9652daSAlexander Motin sc->b2b_mw = -1;
394ed9652daSAlexander Motin } else {
395ed9652daSAlexander Motin device_printf(dev, "NTB-to-NTB (back-to-back) mode\n");
396ed9652daSAlexander Motin
397ed9652daSAlexander Motin /* We need at least one memory window for B2B peer access. */
398ed9652daSAlexander Motin if (sc->mw_count == 0) {
399ed9652daSAlexander Motin device_printf(dev, "No memory window BARs enabled.\n");
400ed9652daSAlexander Motin error = ENXIO;
401ed9652daSAlexander Motin goto out;
402ed9652daSAlexander Motin }
403ed9652daSAlexander Motin sc->b2b_mw = sc->mw_count - 1;
404ed9652daSAlexander Motin
405ed9652daSAlexander Motin /* Use half of the window for B2B, but no less then 1MB. */
406ed9652daSAlexander Motin mw = &sc->mw_info[sc->b2b_mw];
407ed9652daSAlexander Motin if (mw->mw_size >= 2 * 1024 * 1024)
408ed9652daSAlexander Motin sc->b2b_off = mw->mw_size / 2;
409ed9652daSAlexander Motin else
410ed9652daSAlexander Motin sc->b2b_off = 0;
411ed9652daSAlexander Motin }
412ed9652daSAlexander Motin
4137aafa7c3SAlexander Motin snprintf(buf, sizeof(buf), "hint.%s.%d.split", device_get_name(dev),
4147aafa7c3SAlexander Motin device_get_unit(dev));
4157aafa7c3SAlexander Motin TUNABLE_INT_FETCH(buf, &sc->split);
4167aafa7c3SAlexander Motin if (sc->split > 7) {
4177aafa7c3SAlexander Motin device_printf(dev, "Split value is too high (%u)\n", sc->split);
4187aafa7c3SAlexander Motin sc->split = 0;
4197aafa7c3SAlexander Motin } else if (sc->split > 0 && sc->alut == 0) {
4207aafa7c3SAlexander Motin device_printf(dev, "Can't split with disabled A-LUT\n");
4217aafa7c3SAlexander Motin sc->split = 0;
4227aafa7c3SAlexander Motin } else if (sc->split > 0 && (sc->mw_count == 0 || sc->mw_info[0].mw_bar != 2)) {
4237aafa7c3SAlexander Motin device_printf(dev, "Can't split disabled BAR2\n");
4247aafa7c3SAlexander Motin sc->split = 0;
4257aafa7c3SAlexander Motin } else if (sc->split > 0 && (sc->b2b_mw == 0 && sc->b2b_off == 0)) {
4267aafa7c3SAlexander Motin device_printf(dev, "Can't split BAR2 consumed by B2B\n");
4277aafa7c3SAlexander Motin sc->split = 0;
4287aafa7c3SAlexander Motin } else if (sc->split > 0) {
4297aafa7c3SAlexander Motin device_printf(dev, "Splitting BAR2 into %d memory windows\n",
4307aafa7c3SAlexander Motin 1 << sc->split);
4317aafa7c3SAlexander Motin }
4327aafa7c3SAlexander Motin
433ed9652daSAlexander Motin /*
434ed9652daSAlexander Motin * Use Physical Layer User Test Pattern as additional scratchpad.
435ed9652daSAlexander Motin * Make sure they are present and enabled by writing to them.
436ed9652daSAlexander Motin * XXX: Its a hack, but standard 8 registers are not enough.
437ed9652daSAlexander Motin */
4380faf5914SAlexander Motin sc->spad_offp1 = sc->spad_off1 = PLX_NTX_OUR_BASE(sc) + 0xc6c;
4390faf5914SAlexander Motin sc->spad_offp2 = sc->spad_off2 = PLX_PORT_BASE(sc->ntx * 8) + 0x20c;
440ed9652daSAlexander Motin if (sc->b2b_mw >= 0) {
4410faf5914SAlexander Motin /* In NTB-to-NTB mode each side has own scratchpads. */
442ed9652daSAlexander Motin sc->spad_count1 = PLX_NUM_SPAD;
443ed9652daSAlexander Motin bus_write_4(sc->conf_res, sc->spad_off2, 0x12345678);
444ed9652daSAlexander Motin if (bus_read_4(sc->conf_res, sc->spad_off2) == 0x12345678)
445ed9652daSAlexander Motin sc->spad_count2 = PLX_NUM_SPAD_PATT;
446ed9652daSAlexander Motin } else {
4470faf5914SAlexander Motin /* Otherwise we have share scratchpads with the peer. */
448ed9652daSAlexander Motin if (sc->link) {
449ed9652daSAlexander Motin sc->spad_off1 += PLX_NUM_SPAD / 2 * 4;
450ed9652daSAlexander Motin sc->spad_off2 += PLX_NUM_SPAD_PATT / 2 * 4;
451ed9652daSAlexander Motin } else {
452ed9652daSAlexander Motin sc->spad_offp1 += PLX_NUM_SPAD / 2 * 4;
453ed9652daSAlexander Motin sc->spad_offp2 += PLX_NUM_SPAD_PATT / 2 * 4;
454ed9652daSAlexander Motin }
4550faf5914SAlexander Motin sc->spad_count1 = PLX_NUM_SPAD / 2;
456ed9652daSAlexander Motin bus_write_4(sc->conf_res, sc->spad_off2, 0x12345678);
457ed9652daSAlexander Motin if (bus_read_4(sc->conf_res, sc->spad_off2) == 0x12345678)
458ed9652daSAlexander Motin sc->spad_count2 = PLX_NUM_SPAD_PATT / 2;
459ed9652daSAlexander Motin }
460ed9652daSAlexander Motin
461ed9652daSAlexander Motin /* Apply static part of NTB configuration. */
462ed9652daSAlexander Motin ntb_plx_init(dev);
463ed9652daSAlexander Motin
464ed9652daSAlexander Motin /* Allocate and setup interrupts. */
465ed9652daSAlexander Motin error = ntb_plx_setup_intr(dev);
466ed9652daSAlexander Motin if (error)
467ed9652daSAlexander Motin goto out;
468ed9652daSAlexander Motin
469ed9652daSAlexander Motin /* Attach children to this controller */
470ed9652daSAlexander Motin error = ntb_register_device(dev);
471ed9652daSAlexander Motin
472ed9652daSAlexander Motin out:
473ed9652daSAlexander Motin if (error != 0)
474ed9652daSAlexander Motin ntb_plx_detach(dev);
475ed9652daSAlexander Motin return (error);
476ed9652daSAlexander Motin }
477ed9652daSAlexander Motin
478ed9652daSAlexander Motin static int
ntb_plx_detach(device_t dev)479ed9652daSAlexander Motin ntb_plx_detach(device_t dev)
480ed9652daSAlexander Motin {
481ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
482ed9652daSAlexander Motin struct ntb_plx_mw_info *mw;
483ed9652daSAlexander Motin int i;
484ed9652daSAlexander Motin
485ed9652daSAlexander Motin /* Detach & delete all children */
486ed9652daSAlexander Motin ntb_unregister_device(dev);
487ed9652daSAlexander Motin
488ed9652daSAlexander Motin /* Disable and free interrupts. */
489ed9652daSAlexander Motin ntb_plx_teardown_intr(dev);
490ed9652daSAlexander Motin
491ed9652daSAlexander Motin /* Free memory resources. */
492ed9652daSAlexander Motin for (i = 0; i < sc->mw_count; i++) {
493ed9652daSAlexander Motin mw = &sc->mw_info[i];
494ed9652daSAlexander Motin bus_release_resource(dev, SYS_RES_MEMORY, mw->mw_rid,
495ed9652daSAlexander Motin mw->mw_res);
496ed9652daSAlexander Motin }
497ed9652daSAlexander Motin bus_release_resource(dev, SYS_RES_MEMORY, sc->conf_rid, sc->conf_res);
498ed9652daSAlexander Motin return (0);
499ed9652daSAlexander Motin }
500ed9652daSAlexander Motin
5016ddecf2bSAlexander Motin static int
ntb_plx_port_number(device_t dev)5026ddecf2bSAlexander Motin ntb_plx_port_number(device_t dev)
5036ddecf2bSAlexander Motin {
5046ddecf2bSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
5056ddecf2bSAlexander Motin
5066ddecf2bSAlexander Motin return (sc->link ? 1 : 0);
5076ddecf2bSAlexander Motin }
5086ddecf2bSAlexander Motin
5096ddecf2bSAlexander Motin static int
ntb_plx_peer_port_count(device_t dev)5106ddecf2bSAlexander Motin ntb_plx_peer_port_count(device_t dev)
5116ddecf2bSAlexander Motin {
5126ddecf2bSAlexander Motin
5136ddecf2bSAlexander Motin return (1);
5146ddecf2bSAlexander Motin }
5156ddecf2bSAlexander Motin
5166ddecf2bSAlexander Motin static int
ntb_plx_peer_port_number(device_t dev,int pidx)5176ddecf2bSAlexander Motin ntb_plx_peer_port_number(device_t dev, int pidx)
5186ddecf2bSAlexander Motin {
5196ddecf2bSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
5206ddecf2bSAlexander Motin
5216ddecf2bSAlexander Motin if (pidx != 0)
5226ddecf2bSAlexander Motin return (-EINVAL);
5236ddecf2bSAlexander Motin
5246ddecf2bSAlexander Motin return (sc->link ? 0 : 1);
5256ddecf2bSAlexander Motin }
5266ddecf2bSAlexander Motin
5276ddecf2bSAlexander Motin static int
ntb_plx_peer_port_idx(device_t dev,int port)5286ddecf2bSAlexander Motin ntb_plx_peer_port_idx(device_t dev, int port)
5296ddecf2bSAlexander Motin {
5306ddecf2bSAlexander Motin int peer_port;
5316ddecf2bSAlexander Motin
5326ddecf2bSAlexander Motin peer_port = ntb_plx_peer_port_number(dev, 0);
5336ddecf2bSAlexander Motin if (peer_port == -EINVAL || port != peer_port)
5346ddecf2bSAlexander Motin return (-EINVAL);
5356ddecf2bSAlexander Motin
5366ddecf2bSAlexander Motin return (0);
5376ddecf2bSAlexander Motin }
538ed9652daSAlexander Motin
539ed9652daSAlexander Motin static bool
ntb_plx_link_is_up(device_t dev,enum ntb_speed * speed,enum ntb_width * width)540ed9652daSAlexander Motin ntb_plx_link_is_up(device_t dev, enum ntb_speed *speed, enum ntb_width *width)
541ed9652daSAlexander Motin {
542ed9652daSAlexander Motin uint16_t link;
543ed9652daSAlexander Motin
544ed9652daSAlexander Motin link = pcie_read_config(dev, PCIER_LINK_STA, 2);
545ed9652daSAlexander Motin if (speed != NULL)
546ed9652daSAlexander Motin *speed = (link & PCIEM_LINK_STA_SPEED);
547ed9652daSAlexander Motin if (width != NULL)
548ed9652daSAlexander Motin *width = (link & PCIEM_LINK_STA_WIDTH) >> 4;
549ed9652daSAlexander Motin return ((link & PCIEM_LINK_STA_WIDTH) != 0);
550ed9652daSAlexander Motin }
551ed9652daSAlexander Motin
552ed9652daSAlexander Motin static int
ntb_plx_link_enable(device_t dev,enum ntb_speed speed __unused,enum ntb_width width __unused)553ed9652daSAlexander Motin ntb_plx_link_enable(device_t dev, enum ntb_speed speed __unused,
554ed9652daSAlexander Motin enum ntb_width width __unused)
555ed9652daSAlexander Motin {
556ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
557ed9652daSAlexander Motin uint32_t reg, val;
558ed9652daSAlexander Motin
559ed9652daSAlexander Motin /* The fact that we see the Link Interface means link is enabled. */
560ed9652daSAlexander Motin if (sc->link) {
561ed9652daSAlexander Motin ntb_link_event(dev);
562ed9652daSAlexander Motin return (0);
563ed9652daSAlexander Motin }
564ed9652daSAlexander Motin
5650faf5914SAlexander Motin reg = PLX_PORT_CONTROL(sc);
566ed9652daSAlexander Motin val = bus_read_4(sc->conf_res, reg);
567ed9652daSAlexander Motin if ((val & (1 << (sc->port & 7))) == 0) {
568ed9652daSAlexander Motin /* If already enabled, generate fake link event and exit. */
569ed9652daSAlexander Motin ntb_link_event(dev);
570ed9652daSAlexander Motin return (0);
571ed9652daSAlexander Motin }
572ed9652daSAlexander Motin val &= ~(1 << (sc->port & 7));
573ed9652daSAlexander Motin bus_write_4(sc->conf_res, reg, val);
574ed9652daSAlexander Motin return (0);
575ed9652daSAlexander Motin }
576ed9652daSAlexander Motin
577ed9652daSAlexander Motin static int
ntb_plx_link_disable(device_t dev)578ed9652daSAlexander Motin ntb_plx_link_disable(device_t dev)
579ed9652daSAlexander Motin {
580ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
581ed9652daSAlexander Motin uint32_t reg, val;
582ed9652daSAlexander Motin
583ed9652daSAlexander Motin /* Link disable for Link Interface would be suicidal. */
584ed9652daSAlexander Motin if (sc->link)
585ed9652daSAlexander Motin return (0);
586ed9652daSAlexander Motin
5870faf5914SAlexander Motin reg = PLX_PORT_CONTROL(sc);
588ed9652daSAlexander Motin val = bus_read_4(sc->conf_res, reg);
589ed9652daSAlexander Motin val |= (1 << (sc->port & 7));
590ed9652daSAlexander Motin bus_write_4(sc->conf_res, reg, val);
591ed9652daSAlexander Motin return (0);
592ed9652daSAlexander Motin }
593ed9652daSAlexander Motin
594ed9652daSAlexander Motin static bool
ntb_plx_link_enabled(device_t dev)595ed9652daSAlexander Motin ntb_plx_link_enabled(device_t dev)
596ed9652daSAlexander Motin {
597ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
598ed9652daSAlexander Motin uint32_t reg, val;
599ed9652daSAlexander Motin
600ed9652daSAlexander Motin /* The fact that we see the Link Interface means link is enabled. */
601ed9652daSAlexander Motin if (sc->link)
602ed9652daSAlexander Motin return (TRUE);
603ed9652daSAlexander Motin
6040faf5914SAlexander Motin reg = PLX_PORT_CONTROL(sc);
605ed9652daSAlexander Motin val = bus_read_4(sc->conf_res, reg);
606ed9652daSAlexander Motin return ((val & (1 << (sc->port & 7))) == 0);
607ed9652daSAlexander Motin }
608ed9652daSAlexander Motin
609ed9652daSAlexander Motin static uint8_t
ntb_plx_mw_count(device_t dev)610ed9652daSAlexander Motin ntb_plx_mw_count(device_t dev)
611ed9652daSAlexander Motin {
612ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
6137aafa7c3SAlexander Motin uint8_t res;
614ed9652daSAlexander Motin
6157aafa7c3SAlexander Motin res = sc->mw_count;
6167aafa7c3SAlexander Motin res += (1 << sc->split) - 1;
617ed9652daSAlexander Motin if (sc->b2b_mw >= 0 && sc->b2b_off == 0)
6187aafa7c3SAlexander Motin res--; /* B2B consumed whole window. */
6197aafa7c3SAlexander Motin return (res);
6207aafa7c3SAlexander Motin }
6217aafa7c3SAlexander Motin
6227aafa7c3SAlexander Motin static unsigned
ntb_plx_user_mw_to_idx(struct ntb_plx_softc * sc,unsigned uidx,unsigned * sp)6237aafa7c3SAlexander Motin ntb_plx_user_mw_to_idx(struct ntb_plx_softc *sc, unsigned uidx, unsigned *sp)
6247aafa7c3SAlexander Motin {
6257aafa7c3SAlexander Motin unsigned t;
6267aafa7c3SAlexander Motin
6277aafa7c3SAlexander Motin t = 1 << sc->split;
6287aafa7c3SAlexander Motin if (uidx < t) {
6297aafa7c3SAlexander Motin *sp = uidx;
6307aafa7c3SAlexander Motin return (0);
6317aafa7c3SAlexander Motin }
6327aafa7c3SAlexander Motin *sp = 0;
6337aafa7c3SAlexander Motin return (uidx - (t - 1));
634ed9652daSAlexander Motin }
635ed9652daSAlexander Motin
636ed9652daSAlexander Motin static int
ntb_plx_mw_get_range(device_t dev,unsigned mw_idx,vm_paddr_t * base,caddr_t * vbase,size_t * size,size_t * align,size_t * align_size,bus_addr_t * plimit)637ed9652daSAlexander Motin ntb_plx_mw_get_range(device_t dev, unsigned mw_idx, vm_paddr_t *base,
638ed9652daSAlexander Motin caddr_t *vbase, size_t *size, size_t *align, size_t *align_size,
639ed9652daSAlexander Motin bus_addr_t *plimit)
640ed9652daSAlexander Motin {
641ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
642ed9652daSAlexander Motin struct ntb_plx_mw_info *mw;
6437aafa7c3SAlexander Motin size_t off, ss;
6447aafa7c3SAlexander Motin unsigned sp, split;
645ed9652daSAlexander Motin
6467aafa7c3SAlexander Motin mw_idx = ntb_plx_user_mw_to_idx(sc, mw_idx, &sp);
647ed9652daSAlexander Motin if (mw_idx >= sc->mw_count)
648ed9652daSAlexander Motin return (EINVAL);
649ed9652daSAlexander Motin off = 0;
650ed9652daSAlexander Motin if (mw_idx == sc->b2b_mw) {
651ed9652daSAlexander Motin KASSERT(sc->b2b_off != 0,
652ed9652daSAlexander Motin ("user shouldn't get non-shared b2b mw"));
653ed9652daSAlexander Motin off = sc->b2b_off;
654ed9652daSAlexander Motin }
655ed9652daSAlexander Motin mw = &sc->mw_info[mw_idx];
6567aafa7c3SAlexander Motin split = (mw->mw_bar == 2) ? sc->split : 0;
6577aafa7c3SAlexander Motin ss = (mw->mw_size - off) >> split;
658ed9652daSAlexander Motin
659ed9652daSAlexander Motin /* Local to remote memory window parameters. */
660ed9652daSAlexander Motin if (base != NULL)
6617aafa7c3SAlexander Motin *base = mw->mw_pbase + off + ss * sp;
662ed9652daSAlexander Motin if (vbase != NULL)
6637aafa7c3SAlexander Motin *vbase = mw->mw_vbase + off + ss * sp;
664ed9652daSAlexander Motin if (size != NULL)
6657aafa7c3SAlexander Motin *size = ss;
666ed9652daSAlexander Motin
667ed9652daSAlexander Motin /*
668ed9652daSAlexander Motin * Remote to local memory window translation address alignment.
66921811c24SAlexander Motin * Translation address has to be aligned to the BAR size, but A-LUT
67021811c24SAlexander Motin * entries re-map addresses can be aligned to 1/128 or 1/256 of it.
67121811c24SAlexander Motin * XXX: In B2B mode we can change BAR size (and so alignmet) live,
67221811c24SAlexander Motin * but there is no way to report it here, so report safe value.
673ed9652daSAlexander Motin */
67421811c24SAlexander Motin if (align != NULL) {
67521811c24SAlexander Motin if (sc->alut && mw->mw_bar == 2)
67621811c24SAlexander Motin *align = (mw->mw_size - off) / 128 / sc->alut;
67721811c24SAlexander Motin else
678ed9652daSAlexander Motin *align = mw->mw_size - off;
67921811c24SAlexander Motin }
680ed9652daSAlexander Motin
681ed9652daSAlexander Motin /*
682ed9652daSAlexander Motin * Remote to local memory window size alignment.
68321811c24SAlexander Motin * The chip has no limit registers, but A-LUT, when available, allows
68421811c24SAlexander Motin * access control with granularity of 1/128 or 1/256 of the BAR size.
68521811c24SAlexander Motin * XXX: In B2B case we can change BAR size live, but there is no way
68621811c24SAlexander Motin * to report it, so report half of the BAR size, that should be safe.
68721811c24SAlexander Motin * In non-B2B case there is no control at all, so report the BAR size.
688ed9652daSAlexander Motin */
689ed9652daSAlexander Motin if (align_size != NULL) {
69021811c24SAlexander Motin if (sc->alut && mw->mw_bar == 2)
69121811c24SAlexander Motin *align_size = (mw->mw_size - off) / 128 / sc->alut;
69221811c24SAlexander Motin else if (sc->b2b_mw >= 0)
69321811c24SAlexander Motin *align_size = (mw->mw_size - off) / 2;
694ed9652daSAlexander Motin else
695ed9652daSAlexander Motin *align_size = mw->mw_size - off;
696ed9652daSAlexander Motin }
697ed9652daSAlexander Motin
698ed9652daSAlexander Motin /* Remote to local memory window translation address upper limit. */
699ed9652daSAlexander Motin if (plimit != NULL)
700ed9652daSAlexander Motin *plimit = mw->mw_64bit ? BUS_SPACE_MAXADDR :
701ed9652daSAlexander Motin BUS_SPACE_MAXADDR_32BIT;
702ed9652daSAlexander Motin return (0);
703ed9652daSAlexander Motin }
704ed9652daSAlexander Motin
705ed9652daSAlexander Motin static int
ntb_plx_mw_set_trans_internal(device_t dev,unsigned mw_idx)706ed9652daSAlexander Motin ntb_plx_mw_set_trans_internal(device_t dev, unsigned mw_idx)
707ed9652daSAlexander Motin {
708ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
709ed9652daSAlexander Motin struct ntb_plx_mw_info *mw;
71021811c24SAlexander Motin uint64_t addr, eaddr, off, size, bsize, esize, val64;
711ed9652daSAlexander Motin uint32_t val;
7127aafa7c3SAlexander Motin unsigned i, sp, split;
713ed9652daSAlexander Motin
714ed9652daSAlexander Motin mw = &sc->mw_info[mw_idx];
7157aafa7c3SAlexander Motin off = (mw_idx == sc->b2b_mw) ? sc->b2b_off : 0;
7167aafa7c3SAlexander Motin split = (mw->mw_bar == 2) ? sc->split : 0;
717ed9652daSAlexander Motin
7187aafa7c3SAlexander Motin /* Get BAR size. In case of split or B2RP we can't change it. */
7197aafa7c3SAlexander Motin if (split || sc->b2b_mw < 0) {
7207aafa7c3SAlexander Motin bsize = mw->mw_size - off;
7217aafa7c3SAlexander Motin } else {
7227aafa7c3SAlexander Motin bsize = mw->splits[0].mw_xlat_size;
72321811c24SAlexander Motin if (!powerof2(bsize))
72421811c24SAlexander Motin bsize = 1LL << flsll(bsize);
7257aafa7c3SAlexander Motin if (bsize > 0 && bsize < 1024 * 1024)
72621811c24SAlexander Motin bsize = 1024 * 1024;
7277aafa7c3SAlexander Motin }
728ed9652daSAlexander Motin
7297aafa7c3SAlexander Motin /*
7307aafa7c3SAlexander Motin * While for B2B we can set any BAR size on a link side, for shared
7317aafa7c3SAlexander Motin * window we can't go above preconfigured size due to BAR address
7327aafa7c3SAlexander Motin * alignment requirements.
7337aafa7c3SAlexander Motin */
7347aafa7c3SAlexander Motin if ((off & (bsize - 1)) != 0)
735ed9652daSAlexander Motin return (EINVAL);
736ed9652daSAlexander Motin
7377aafa7c3SAlexander Motin /* In B2B mode set Link Interface BAR size/address. */
7387aafa7c3SAlexander Motin if (sc->b2b_mw >= 0 && mw->mw_64bit) {
739ed9652daSAlexander Motin val64 = 0;
74021811c24SAlexander Motin if (bsize > 0)
74121811c24SAlexander Motin val64 = (~(bsize - 1) & ~0xfffff);
74283feae78SAlexander Motin val64 |= 0xc;
743ed9652daSAlexander Motin PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4, val64);
744ed9652daSAlexander Motin PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4 + 4, val64 >> 32);
745ed9652daSAlexander Motin
746ed9652daSAlexander Motin val64 = 0x2000000000000000 * mw->mw_bar + off;
747ed9652daSAlexander Motin PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar), val64);
748ed9652daSAlexander Motin PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar) + 4, val64 >> 32);
7497aafa7c3SAlexander Motin } else if (sc->b2b_mw >= 0) {
750ed9652daSAlexander Motin val = 0;
75121811c24SAlexander Motin if (bsize > 0)
75221811c24SAlexander Motin val = (~(bsize - 1) & ~0xfffff);
753ed9652daSAlexander Motin PNTX_WRITE(sc, 0xe8 + (mw->mw_bar - 2) * 4, val);
754ed9652daSAlexander Motin
755ed9652daSAlexander Motin val64 = 0x20000000 * mw->mw_bar + off;
756ed9652daSAlexander Motin PNTX_WRITE(sc, PCIR_BAR(mw->mw_bar), val64);
757ed9652daSAlexander Motin }
758ed9652daSAlexander Motin
7597aafa7c3SAlexander Motin /* Set BARs address translation */
7607aafa7c3SAlexander Motin addr = split ? UINT64_MAX : mw->splits[0].mw_xlat_addr;
7617aafa7c3SAlexander Motin if (mw->mw_64bit) {
7627aafa7c3SAlexander Motin PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, addr);
7637aafa7c3SAlexander Motin PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4 + 4, addr >> 32);
7647aafa7c3SAlexander Motin } else {
765ed9652daSAlexander Motin PNTX_WRITE(sc, 0xc3c + (mw->mw_bar - 2) * 4, addr);
766ed9652daSAlexander Motin }
76721811c24SAlexander Motin
7687aafa7c3SAlexander Motin /* Configure and enable A-LUT if we need it. */
7697aafa7c3SAlexander Motin size = split ? 0 : mw->splits[0].mw_xlat_size;
7707aafa7c3SAlexander Motin if (sc->alut && mw->mw_bar == 2 && (sc->split > 0 ||
7717aafa7c3SAlexander Motin ((addr & (bsize - 1)) != 0 || size != bsize))) {
7727aafa7c3SAlexander Motin esize = bsize / (128 * sc->alut);
7737aafa7c3SAlexander Motin for (i = sp = 0; i < 128 * sc->alut; i++) {
7747aafa7c3SAlexander Motin if (i % (128 * sc->alut >> sc->split) == 0) {
7757aafa7c3SAlexander Motin eaddr = addr = mw->splits[sp].mw_xlat_addr;
7767aafa7c3SAlexander Motin size = mw->splits[sp++].mw_xlat_size;
7777aafa7c3SAlexander Motin }
77821811c24SAlexander Motin val = sc->link ? 0 : 1;
77921811c24SAlexander Motin if (sc->alut == 1)
78021811c24SAlexander Motin val += 2 * sc->ntx;
78121811c24SAlexander Motin val *= 0x1000 * sc->alut;
78221811c24SAlexander Motin val += 0x38000 + i * 4 + (i >= 128 ? 0x0e00 : 0);
78321811c24SAlexander Motin bus_write_4(sc->conf_res, val, eaddr);
78421811c24SAlexander Motin bus_write_4(sc->conf_res, val + 0x400, eaddr >> 32);
78521811c24SAlexander Motin bus_write_4(sc->conf_res, val + 0x800,
78621811c24SAlexander Motin (eaddr < addr + size) ? 0x3 : 0);
78721811c24SAlexander Motin eaddr += esize;
78821811c24SAlexander Motin }
78921811c24SAlexander Motin NTX_WRITE(sc, 0xc94, 0x10000000);
79021811c24SAlexander Motin } else if (sc->alut && mw->mw_bar == 2)
79121811c24SAlexander Motin NTX_WRITE(sc, 0xc94, 0);
79221811c24SAlexander Motin
793ed9652daSAlexander Motin return (0);
794ed9652daSAlexander Motin }
795ed9652daSAlexander Motin
796ed9652daSAlexander Motin static int
ntb_plx_mw_set_trans(device_t dev,unsigned mw_idx,bus_addr_t addr,size_t size)797ed9652daSAlexander Motin ntb_plx_mw_set_trans(device_t dev, unsigned mw_idx, bus_addr_t addr, size_t size)
798ed9652daSAlexander Motin {
799ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
800ed9652daSAlexander Motin struct ntb_plx_mw_info *mw;
8017aafa7c3SAlexander Motin unsigned sp;
802ed9652daSAlexander Motin
8037aafa7c3SAlexander Motin mw_idx = ntb_plx_user_mw_to_idx(sc, mw_idx, &sp);
804ed9652daSAlexander Motin if (mw_idx >= sc->mw_count)
805ed9652daSAlexander Motin return (EINVAL);
806ed9652daSAlexander Motin mw = &sc->mw_info[mw_idx];
8077aafa7c3SAlexander Motin if (!mw->mw_64bit &&
8087aafa7c3SAlexander Motin ((addr & UINT32_MAX) != addr ||
8097aafa7c3SAlexander Motin ((addr + size) & UINT32_MAX) != (addr + size)))
8107aafa7c3SAlexander Motin return (ERANGE);
8117aafa7c3SAlexander Motin mw->splits[sp].mw_xlat_addr = addr;
8127aafa7c3SAlexander Motin mw->splits[sp].mw_xlat_size = size;
813ed9652daSAlexander Motin return (ntb_plx_mw_set_trans_internal(dev, mw_idx));
814ed9652daSAlexander Motin }
815ed9652daSAlexander Motin
816ed9652daSAlexander Motin static int
ntb_plx_mw_clear_trans(device_t dev,unsigned mw_idx)817ed9652daSAlexander Motin ntb_plx_mw_clear_trans(device_t dev, unsigned mw_idx)
818ed9652daSAlexander Motin {
819ed9652daSAlexander Motin
820ed9652daSAlexander Motin return (ntb_plx_mw_set_trans(dev, mw_idx, 0, 0));
821ed9652daSAlexander Motin }
822ed9652daSAlexander Motin
823ed9652daSAlexander Motin static int
ntb_plx_mw_get_wc(device_t dev,unsigned mw_idx,vm_memattr_t * mode)8247aafa7c3SAlexander Motin ntb_plx_mw_get_wc(device_t dev, unsigned mw_idx, vm_memattr_t *mode)
825ed9652daSAlexander Motin {
826ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
827ed9652daSAlexander Motin struct ntb_plx_mw_info *mw;
8287aafa7c3SAlexander Motin unsigned sp;
829ed9652daSAlexander Motin
8307aafa7c3SAlexander Motin mw_idx = ntb_plx_user_mw_to_idx(sc, mw_idx, &sp);
8317aafa7c3SAlexander Motin if (mw_idx >= sc->mw_count)
832ed9652daSAlexander Motin return (EINVAL);
8337aafa7c3SAlexander Motin mw = &sc->mw_info[mw_idx];
8347aafa7c3SAlexander Motin *mode = mw->splits[sp].mw_map_mode;
835ed9652daSAlexander Motin return (0);
836ed9652daSAlexander Motin }
837ed9652daSAlexander Motin
838ed9652daSAlexander Motin static int
ntb_plx_mw_set_wc(device_t dev,unsigned mw_idx,vm_memattr_t mode)8397aafa7c3SAlexander Motin ntb_plx_mw_set_wc(device_t dev, unsigned mw_idx, vm_memattr_t mode)
840ed9652daSAlexander Motin {
841ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
842ed9652daSAlexander Motin struct ntb_plx_mw_info *mw;
8437aafa7c3SAlexander Motin uint64_t off, ss;
844ed9652daSAlexander Motin int rc;
8457aafa7c3SAlexander Motin unsigned sp, split;
846ed9652daSAlexander Motin
8477aafa7c3SAlexander Motin mw_idx = ntb_plx_user_mw_to_idx(sc, mw_idx, &sp);
8487aafa7c3SAlexander Motin if (mw_idx >= sc->mw_count)
849ed9652daSAlexander Motin return (EINVAL);
8507aafa7c3SAlexander Motin mw = &sc->mw_info[mw_idx];
8517aafa7c3SAlexander Motin if (mw->splits[sp].mw_map_mode == mode)
852ed9652daSAlexander Motin return (0);
853ed9652daSAlexander Motin
854ed9652daSAlexander Motin off = 0;
8557aafa7c3SAlexander Motin if (mw_idx == sc->b2b_mw) {
856ed9652daSAlexander Motin KASSERT(sc->b2b_off != 0,
857ed9652daSAlexander Motin ("user shouldn't get non-shared b2b mw"));
858ed9652daSAlexander Motin off = sc->b2b_off;
859ed9652daSAlexander Motin }
860ed9652daSAlexander Motin
8617aafa7c3SAlexander Motin split = (mw->mw_bar == 2) ? sc->split : 0;
8627aafa7c3SAlexander Motin ss = (mw->mw_size - off) >> split;
8637aafa7c3SAlexander Motin rc = pmap_change_attr((vm_offset_t)mw->mw_vbase + off + ss * sp,
8647aafa7c3SAlexander Motin ss, mode);
865ed9652daSAlexander Motin if (rc == 0)
8667aafa7c3SAlexander Motin mw->splits[sp].mw_map_mode = mode;
867ed9652daSAlexander Motin return (rc);
868ed9652daSAlexander Motin }
869ed9652daSAlexander Motin
870ed9652daSAlexander Motin static uint8_t
ntb_plx_spad_count(device_t dev)871ed9652daSAlexander Motin ntb_plx_spad_count(device_t dev)
872ed9652daSAlexander Motin {
873ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
874ed9652daSAlexander Motin
875ed9652daSAlexander Motin return (sc->spad_count1 + sc->spad_count2);
876ed9652daSAlexander Motin }
877ed9652daSAlexander Motin
878ed9652daSAlexander Motin static int
ntb_plx_spad_write(device_t dev,unsigned int idx,uint32_t val)879ed9652daSAlexander Motin ntb_plx_spad_write(device_t dev, unsigned int idx, uint32_t val)
880ed9652daSAlexander Motin {
881ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
882*3883c6fbSAlexander Motin u_int off, t;
883ed9652daSAlexander Motin
884ed9652daSAlexander Motin if (idx >= sc->spad_count1 + sc->spad_count2)
885ed9652daSAlexander Motin return (EINVAL);
886ed9652daSAlexander Motin
887*3883c6fbSAlexander Motin if (idx < sc->spad_count1) {
888ed9652daSAlexander Motin off = sc->spad_off1 + idx * 4;
889ed9652daSAlexander Motin bus_write_4(sc->conf_res, off, val);
890ed9652daSAlexander Motin return (0);
891*3883c6fbSAlexander Motin } else {
892*3883c6fbSAlexander Motin off = sc->spad_off2 + (idx - sc->spad_count1) * 4;
893*3883c6fbSAlexander Motin /*
894*3883c6fbSAlexander Motin * For some reason when link goes down Test Pattern registers
895*3883c6fbSAlexander Motin * we use as additional scratchpad become read-only for about
896*3883c6fbSAlexander Motin * 100us. I see no explanation in specs, so just wait a bit.
897*3883c6fbSAlexander Motin */
898*3883c6fbSAlexander Motin for (t = 0; t <= 1000; t++) {
899*3883c6fbSAlexander Motin bus_write_4(sc->conf_res, off, val);
900*3883c6fbSAlexander Motin if (bus_read_4(sc->conf_res, off) == val)
901*3883c6fbSAlexander Motin return (0);
902*3883c6fbSAlexander Motin DELAY(1);
903*3883c6fbSAlexander Motin }
904*3883c6fbSAlexander Motin device_printf(dev,
905*3883c6fbSAlexander Motin "Can't write Physical Layer User Test Pattern (0x%x)\n",
906*3883c6fbSAlexander Motin off);
907*3883c6fbSAlexander Motin return (EIO);
908*3883c6fbSAlexander Motin }
909ed9652daSAlexander Motin }
910ed9652daSAlexander Motin
911ed9652daSAlexander Motin static void
ntb_plx_spad_clear(device_t dev)912ed9652daSAlexander Motin ntb_plx_spad_clear(device_t dev)
913ed9652daSAlexander Motin {
914ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
915ed9652daSAlexander Motin int i;
916ed9652daSAlexander Motin
917ed9652daSAlexander Motin for (i = 0; i < sc->spad_count1 + sc->spad_count2; i++)
918ed9652daSAlexander Motin ntb_plx_spad_write(dev, i, 0);
919ed9652daSAlexander Motin }
920ed9652daSAlexander Motin
921ed9652daSAlexander Motin static int
ntb_plx_spad_read(device_t dev,unsigned int idx,uint32_t * val)922ed9652daSAlexander Motin ntb_plx_spad_read(device_t dev, unsigned int idx, uint32_t *val)
923ed9652daSAlexander Motin {
924ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
925ed9652daSAlexander Motin u_int off;
926ed9652daSAlexander Motin
927ed9652daSAlexander Motin if (idx >= sc->spad_count1 + sc->spad_count2)
928ed9652daSAlexander Motin return (EINVAL);
929ed9652daSAlexander Motin
930ed9652daSAlexander Motin if (idx < sc->spad_count1)
931ed9652daSAlexander Motin off = sc->spad_off1 + idx * 4;
932ed9652daSAlexander Motin else
933ed9652daSAlexander Motin off = sc->spad_off2 + (idx - sc->spad_count1) * 4;
934ed9652daSAlexander Motin *val = bus_read_4(sc->conf_res, off);
935ed9652daSAlexander Motin return (0);
936ed9652daSAlexander Motin }
937ed9652daSAlexander Motin
938ed9652daSAlexander Motin static int
ntb_plx_peer_spad_write(device_t dev,unsigned int idx,uint32_t val)939ed9652daSAlexander Motin ntb_plx_peer_spad_write(device_t dev, unsigned int idx, uint32_t val)
940ed9652daSAlexander Motin {
941ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
942ed9652daSAlexander Motin u_int off;
943ed9652daSAlexander Motin
944ed9652daSAlexander Motin if (idx >= sc->spad_count1 + sc->spad_count2)
945ed9652daSAlexander Motin return (EINVAL);
946ed9652daSAlexander Motin
947ed9652daSAlexander Motin if (idx < sc->spad_count1)
948ed9652daSAlexander Motin off = sc->spad_offp1 + idx * 4;
949ed9652daSAlexander Motin else
950ed9652daSAlexander Motin off = sc->spad_offp2 + (idx - sc->spad_count1) * 4;
951ed9652daSAlexander Motin if (sc->b2b_mw >= 0)
952ed9652daSAlexander Motin bus_write_4(sc->mw_info[sc->b2b_mw].mw_res, off, val);
953ed9652daSAlexander Motin else
954ed9652daSAlexander Motin bus_write_4(sc->conf_res, off, val);
955ed9652daSAlexander Motin return (0);
956ed9652daSAlexander Motin }
957ed9652daSAlexander Motin
958ed9652daSAlexander Motin static int
ntb_plx_peer_spad_read(device_t dev,unsigned int idx,uint32_t * val)959ed9652daSAlexander Motin ntb_plx_peer_spad_read(device_t dev, unsigned int idx, uint32_t *val)
960ed9652daSAlexander Motin {
961ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
962ed9652daSAlexander Motin u_int off;
963ed9652daSAlexander Motin
964ed9652daSAlexander Motin if (idx >= sc->spad_count1 + sc->spad_count2)
965ed9652daSAlexander Motin return (EINVAL);
966ed9652daSAlexander Motin
967ed9652daSAlexander Motin if (idx < sc->spad_count1)
968ed9652daSAlexander Motin off = sc->spad_offp1 + idx * 4;
969ed9652daSAlexander Motin else
970ed9652daSAlexander Motin off = sc->spad_offp2 + (idx - sc->spad_count1) * 4;
971ed9652daSAlexander Motin if (sc->b2b_mw >= 0)
972ed9652daSAlexander Motin *val = bus_read_4(sc->mw_info[sc->b2b_mw].mw_res, off);
973ed9652daSAlexander Motin else
974ed9652daSAlexander Motin *val = bus_read_4(sc->conf_res, off);
975ed9652daSAlexander Motin return (0);
976ed9652daSAlexander Motin }
977ed9652daSAlexander Motin
978ed9652daSAlexander Motin static uint64_t
ntb_plx_db_valid_mask(device_t dev)979ed9652daSAlexander Motin ntb_plx_db_valid_mask(device_t dev)
980ed9652daSAlexander Motin {
981ed9652daSAlexander Motin
982ed9652daSAlexander Motin return ((1LL << PLX_NUM_DB) - 1);
983ed9652daSAlexander Motin }
984ed9652daSAlexander Motin
985ed9652daSAlexander Motin static int
ntb_plx_db_vector_count(device_t dev)986ed9652daSAlexander Motin ntb_plx_db_vector_count(device_t dev)
987ed9652daSAlexander Motin {
988ed9652daSAlexander Motin
989ed9652daSAlexander Motin return (1);
990ed9652daSAlexander Motin }
991ed9652daSAlexander Motin
992ed9652daSAlexander Motin static uint64_t
ntb_plx_db_vector_mask(device_t dev,uint32_t vector)993ed9652daSAlexander Motin ntb_plx_db_vector_mask(device_t dev, uint32_t vector)
994ed9652daSAlexander Motin {
995ed9652daSAlexander Motin
996ed9652daSAlexander Motin if (vector > 0)
997ed9652daSAlexander Motin return (0);
998ed9652daSAlexander Motin return ((1LL << PLX_NUM_DB) - 1);
999ed9652daSAlexander Motin }
1000ed9652daSAlexander Motin
1001ed9652daSAlexander Motin static void
ntb_plx_db_clear(device_t dev,uint64_t bits)1002ed9652daSAlexander Motin ntb_plx_db_clear(device_t dev, uint64_t bits)
1003ed9652daSAlexander Motin {
1004ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
1005ed9652daSAlexander Motin
1006ed9652daSAlexander Motin NTX_WRITE(sc, sc->link ? 0xc60 : 0xc50, bits);
1007ed9652daSAlexander Motin }
1008ed9652daSAlexander Motin
1009ed9652daSAlexander Motin static void
ntb_plx_db_clear_mask(device_t dev,uint64_t bits)1010ed9652daSAlexander Motin ntb_plx_db_clear_mask(device_t dev, uint64_t bits)
1011ed9652daSAlexander Motin {
1012ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
1013ed9652daSAlexander Motin
1014ed9652daSAlexander Motin NTX_WRITE(sc, sc->link ? 0xc68 : 0xc58, bits);
1015ed9652daSAlexander Motin }
1016ed9652daSAlexander Motin
1017ed9652daSAlexander Motin static uint64_t
ntb_plx_db_read(device_t dev)1018ed9652daSAlexander Motin ntb_plx_db_read(device_t dev)
1019ed9652daSAlexander Motin {
1020ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
1021ed9652daSAlexander Motin
1022ed9652daSAlexander Motin return (NTX_READ(sc, sc->link ? 0xc5c : 0xc4c));
1023ed9652daSAlexander Motin }
1024ed9652daSAlexander Motin
1025ed9652daSAlexander Motin static void
ntb_plx_db_set_mask(device_t dev,uint64_t bits)1026ed9652daSAlexander Motin ntb_plx_db_set_mask(device_t dev, uint64_t bits)
1027ed9652daSAlexander Motin {
1028ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
1029ed9652daSAlexander Motin
1030ed9652daSAlexander Motin NTX_WRITE(sc, sc->link ? 0xc64 : 0xc54, bits);
1031ed9652daSAlexander Motin }
1032ed9652daSAlexander Motin
1033ed9652daSAlexander Motin static int
ntb_plx_peer_db_addr(device_t dev,bus_addr_t * db_addr,vm_size_t * db_size)1034ed9652daSAlexander Motin ntb_plx_peer_db_addr(device_t dev, bus_addr_t *db_addr, vm_size_t *db_size)
1035ed9652daSAlexander Motin {
1036ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
1037ed9652daSAlexander Motin struct ntb_plx_mw_info *mw;
1038ed9652daSAlexander Motin
1039ed9652daSAlexander Motin KASSERT((db_addr != NULL && db_size != NULL), ("must be non-NULL"));
1040ed9652daSAlexander Motin
1041ed9652daSAlexander Motin if (sc->b2b_mw >= 0) {
1042ed9652daSAlexander Motin mw = &sc->mw_info[sc->b2b_mw];
1043ed9652daSAlexander Motin *db_addr = (uint64_t)mw->mw_pbase + PLX_NTX_BASE(sc) + 0xc4c;
1044ed9652daSAlexander Motin } else {
1045ed9652daSAlexander Motin *db_addr = rman_get_start(sc->conf_res) + PLX_NTX_BASE(sc);
1046ed9652daSAlexander Motin *db_addr += sc->link ? 0xc4c : 0xc5c;
1047ed9652daSAlexander Motin }
1048ed9652daSAlexander Motin *db_size = 4;
1049ed9652daSAlexander Motin return (0);
1050ed9652daSAlexander Motin }
1051ed9652daSAlexander Motin
1052ed9652daSAlexander Motin static void
ntb_plx_peer_db_set(device_t dev,uint64_t bit)1053ed9652daSAlexander Motin ntb_plx_peer_db_set(device_t dev, uint64_t bit)
1054ed9652daSAlexander Motin {
1055ed9652daSAlexander Motin struct ntb_plx_softc *sc = device_get_softc(dev);
1056ed9652daSAlexander Motin
1057ed9652daSAlexander Motin if (sc->b2b_mw >= 0)
1058ed9652daSAlexander Motin BNTX_WRITE(sc, 0xc4c, bit);
1059ed9652daSAlexander Motin else
1060ed9652daSAlexander Motin NTX_WRITE(sc, sc->link ? 0xc4c : 0xc5c, bit);
1061ed9652daSAlexander Motin }
1062ed9652daSAlexander Motin
1063ed9652daSAlexander Motin static device_method_t ntb_plx_methods[] = {
1064ed9652daSAlexander Motin /* Device interface */
1065ed9652daSAlexander Motin DEVMETHOD(device_probe, ntb_plx_probe),
1066ed9652daSAlexander Motin DEVMETHOD(device_attach, ntb_plx_attach),
1067ed9652daSAlexander Motin DEVMETHOD(device_detach, ntb_plx_detach),
1068b7dd3fbeSAlexander Motin /* Bus interface */
1069ddfc9c4cSWarner Losh DEVMETHOD(bus_child_location, ntb_child_location),
1070b7dd3fbeSAlexander Motin DEVMETHOD(bus_print_child, ntb_print_child),
10717f215e07SAlexander Motin DEVMETHOD(bus_get_dma_tag, ntb_get_dma_tag),
1072ed9652daSAlexander Motin /* NTB interface */
10736ddecf2bSAlexander Motin DEVMETHOD(ntb_port_number, ntb_plx_port_number),
10746ddecf2bSAlexander Motin DEVMETHOD(ntb_peer_port_count, ntb_plx_peer_port_count),
10756ddecf2bSAlexander Motin DEVMETHOD(ntb_peer_port_number, ntb_plx_peer_port_number),
10766ddecf2bSAlexander Motin DEVMETHOD(ntb_peer_port_idx, ntb_plx_peer_port_idx),
1077ed9652daSAlexander Motin DEVMETHOD(ntb_link_is_up, ntb_plx_link_is_up),
1078ed9652daSAlexander Motin DEVMETHOD(ntb_link_enable, ntb_plx_link_enable),
1079ed9652daSAlexander Motin DEVMETHOD(ntb_link_disable, ntb_plx_link_disable),
1080ed9652daSAlexander Motin DEVMETHOD(ntb_link_enabled, ntb_plx_link_enabled),
1081ed9652daSAlexander Motin DEVMETHOD(ntb_mw_count, ntb_plx_mw_count),
1082ed9652daSAlexander Motin DEVMETHOD(ntb_mw_get_range, ntb_plx_mw_get_range),
1083ed9652daSAlexander Motin DEVMETHOD(ntb_mw_set_trans, ntb_plx_mw_set_trans),
1084ed9652daSAlexander Motin DEVMETHOD(ntb_mw_clear_trans, ntb_plx_mw_clear_trans),
1085ed9652daSAlexander Motin DEVMETHOD(ntb_mw_get_wc, ntb_plx_mw_get_wc),
1086ed9652daSAlexander Motin DEVMETHOD(ntb_mw_set_wc, ntb_plx_mw_set_wc),
1087ed9652daSAlexander Motin DEVMETHOD(ntb_spad_count, ntb_plx_spad_count),
1088ed9652daSAlexander Motin DEVMETHOD(ntb_spad_clear, ntb_plx_spad_clear),
1089ed9652daSAlexander Motin DEVMETHOD(ntb_spad_write, ntb_plx_spad_write),
1090ed9652daSAlexander Motin DEVMETHOD(ntb_spad_read, ntb_plx_spad_read),
1091ed9652daSAlexander Motin DEVMETHOD(ntb_peer_spad_write, ntb_plx_peer_spad_write),
1092ed9652daSAlexander Motin DEVMETHOD(ntb_peer_spad_read, ntb_plx_peer_spad_read),
1093ed9652daSAlexander Motin DEVMETHOD(ntb_db_valid_mask, ntb_plx_db_valid_mask),
1094ed9652daSAlexander Motin DEVMETHOD(ntb_db_vector_count, ntb_plx_db_vector_count),
1095ed9652daSAlexander Motin DEVMETHOD(ntb_db_vector_mask, ntb_plx_db_vector_mask),
1096ed9652daSAlexander Motin DEVMETHOD(ntb_db_clear, ntb_plx_db_clear),
1097ed9652daSAlexander Motin DEVMETHOD(ntb_db_clear_mask, ntb_plx_db_clear_mask),
1098ed9652daSAlexander Motin DEVMETHOD(ntb_db_read, ntb_plx_db_read),
1099ed9652daSAlexander Motin DEVMETHOD(ntb_db_set_mask, ntb_plx_db_set_mask),
1100ed9652daSAlexander Motin DEVMETHOD(ntb_peer_db_addr, ntb_plx_peer_db_addr),
1101ed9652daSAlexander Motin DEVMETHOD(ntb_peer_db_set, ntb_plx_peer_db_set),
1102ed9652daSAlexander Motin DEVMETHOD_END
1103ed9652daSAlexander Motin };
1104ed9652daSAlexander Motin
1105ed9652daSAlexander Motin static DEFINE_CLASS_0(ntb_hw, ntb_plx_driver, ntb_plx_methods,
1106ed9652daSAlexander Motin sizeof(struct ntb_plx_softc));
11079940f7a7SJohn Baldwin DRIVER_MODULE(ntb_hw_plx, pci, ntb_plx_driver, NULL, NULL);
1108ed9652daSAlexander Motin MODULE_DEPEND(ntb_hw_plx, ntb, 1, 1, 1);
1109ed9652daSAlexander Motin MODULE_VERSION(ntb_hw_plx, 1);
1110