12306b72aSZbigniew Bodek /*-
22306b72aSZbigniew Bodek * Copyright (c) 2015 The FreeBSD Foundation
32306b72aSZbigniew Bodek *
42306b72aSZbigniew Bodek * This software was developed by Semihalf under
52306b72aSZbigniew Bodek * the sponsorship of the FreeBSD Foundation.
62306b72aSZbigniew Bodek *
72306b72aSZbigniew Bodek * Redistribution and use in source and binary forms, with or without
82306b72aSZbigniew Bodek * modification, are permitted provided that the following conditions
92306b72aSZbigniew Bodek * are met:
102306b72aSZbigniew Bodek * 1. Redistributions of source code must retain the above copyright
112306b72aSZbigniew Bodek * notice, this list of conditions and the following disclaimer.
122306b72aSZbigniew Bodek * 2. Redistributions in binary form must reproduce the above copyright
132306b72aSZbigniew Bodek * notice, this list of conditions and the following disclaimer in the
142306b72aSZbigniew Bodek * documentation and/or other materials provided with the distribution.
152306b72aSZbigniew Bodek *
162306b72aSZbigniew Bodek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
172306b72aSZbigniew Bodek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182306b72aSZbigniew Bodek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192306b72aSZbigniew Bodek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
202306b72aSZbigniew Bodek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212306b72aSZbigniew Bodek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222306b72aSZbigniew Bodek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232306b72aSZbigniew Bodek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242306b72aSZbigniew Bodek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252306b72aSZbigniew Bodek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262306b72aSZbigniew Bodek * SUCH DAMAGE.
272306b72aSZbigniew Bodek */
282306b72aSZbigniew Bodek
292306b72aSZbigniew Bodek #include <sys/param.h>
302306b72aSZbigniew Bodek #include <sys/systm.h>
312306b72aSZbigniew Bodek #include <sys/bitset.h>
322306b72aSZbigniew Bodek #include <sys/bitstring.h>
332306b72aSZbigniew Bodek #include <sys/bus.h>
34*6074a3c0SMark Johnston #include <sys/ctype.h>
352306b72aSZbigniew Bodek #include <sys/endian.h>
362306b72aSZbigniew Bodek #include <sys/kernel.h>
372306b72aSZbigniew Bodek #include <sys/malloc.h>
382306b72aSZbigniew Bodek #include <sys/module.h>
392306b72aSZbigniew Bodek #include <sys/rman.h>
402306b72aSZbigniew Bodek #include <sys/pciio.h>
412306b72aSZbigniew Bodek #include <sys/pcpu.h>
422306b72aSZbigniew Bodek #include <sys/proc.h>
432306b72aSZbigniew Bodek #include <sys/socket.h>
442306b72aSZbigniew Bodek #include <sys/cpuset.h>
452306b72aSZbigniew Bodek #include <sys/lock.h>
462306b72aSZbigniew Bodek #include <sys/mutex.h>
472306b72aSZbigniew Bodek
482306b72aSZbigniew Bodek #include <net/ethernet.h>
492306b72aSZbigniew Bodek #include <net/if.h>
502306b72aSZbigniew Bodek #include <net/if_media.h>
512306b72aSZbigniew Bodek
522306b72aSZbigniew Bodek #include <dev/ofw/openfirm.h>
53be624ad4SZbigniew Bodek #include <dev/ofw/ofw_bus.h>
542306b72aSZbigniew Bodek #include <dev/mii/miivar.h>
552306b72aSZbigniew Bodek
562306b72aSZbigniew Bodek #include "thunder_bgx.h"
572306b72aSZbigniew Bodek #include "thunder_bgx_var.h"
582306b72aSZbigniew Bodek
592306b72aSZbigniew Bodek #define CONN_TYPE_MAXLEN 16
602306b72aSZbigniew Bodek #define CONN_TYPE_OFFSET 2
612306b72aSZbigniew Bodek
62be624ad4SZbigniew Bodek #define BGX_NODE_NAME "bgx"
63be624ad4SZbigniew Bodek #define BGX_MAXID 9
6419fbe8bdSZbigniew Bodek /* BGX func. 0, i.e.: reg = <0x8000 0 0 0 0>; DEVFN = 0x80 */
6519fbe8bdSZbigniew Bodek #define BGX_DEVFN_0 0x80
66be624ad4SZbigniew Bodek
67be624ad4SZbigniew Bodek #define FDT_NAME_MAXLEN 31
68be624ad4SZbigniew Bodek
692306b72aSZbigniew Bodek int bgx_fdt_init_phy(struct bgx *);
702306b72aSZbigniew Bodek
712306b72aSZbigniew Bodek static void
bgx_fdt_get_macaddr(phandle_t phy,uint8_t * hwaddr)722306b72aSZbigniew Bodek bgx_fdt_get_macaddr(phandle_t phy, uint8_t *hwaddr)
732306b72aSZbigniew Bodek {
742306b72aSZbigniew Bodek uint8_t addr[ETHER_ADDR_LEN];
752306b72aSZbigniew Bodek
762306b72aSZbigniew Bodek if (OF_getprop(phy, "local-mac-address", addr, ETHER_ADDR_LEN) == -1) {
772306b72aSZbigniew Bodek /* Missing MAC address should be marked by clearing it */
782306b72aSZbigniew Bodek memset(hwaddr, 0, ETHER_ADDR_LEN);
792306b72aSZbigniew Bodek } else
802306b72aSZbigniew Bodek memcpy(hwaddr, addr, ETHER_ADDR_LEN);
812306b72aSZbigniew Bodek }
822306b72aSZbigniew Bodek
832306b72aSZbigniew Bodek static boolean_t
bgx_fdt_phy_mode_match(struct bgx * bgx,char * qlm_mode,ssize_t size)8419fbe8bdSZbigniew Bodek bgx_fdt_phy_mode_match(struct bgx *bgx, char *qlm_mode, ssize_t size)
852306b72aSZbigniew Bodek {
8619fbe8bdSZbigniew Bodek const char *type;
8719fbe8bdSZbigniew Bodek ssize_t sz;
8819fbe8bdSZbigniew Bodek ssize_t offset;
892306b72aSZbigniew Bodek
902306b72aSZbigniew Bodek switch (bgx->qlm_mode) {
912306b72aSZbigniew Bodek case QLM_MODE_SGMII:
9219fbe8bdSZbigniew Bodek type = "sgmii";
93c11862c0SAndrew Turner sz = sizeof("sgmii");
9419fbe8bdSZbigniew Bodek offset = size - sz;
952306b72aSZbigniew Bodek break;
962306b72aSZbigniew Bodek case QLM_MODE_XAUI_1X4:
9719fbe8bdSZbigniew Bodek type = "xaui";
98c11862c0SAndrew Turner sz = sizeof("xaui");
9919fbe8bdSZbigniew Bodek offset = size - sz;
10019fbe8bdSZbigniew Bodek if (offset < 0)
10119fbe8bdSZbigniew Bodek return (FALSE);
10219fbe8bdSZbigniew Bodek if (strncmp(&qlm_mode[offset], type, sz) == 0)
1032306b72aSZbigniew Bodek return (TRUE);
10419fbe8bdSZbigniew Bodek type = "dxaui";
105c11862c0SAndrew Turner sz = sizeof("dxaui");
10619fbe8bdSZbigniew Bodek offset = size - sz;
1072306b72aSZbigniew Bodek break;
1082306b72aSZbigniew Bodek case QLM_MODE_RXAUI_2X2:
10919fbe8bdSZbigniew Bodek type = "raui";
110c11862c0SAndrew Turner sz = sizeof("raui");
11119fbe8bdSZbigniew Bodek offset = size - sz;
1122306b72aSZbigniew Bodek break;
1132306b72aSZbigniew Bodek case QLM_MODE_XFI_4X1:
11419fbe8bdSZbigniew Bodek type = "xfi";
115c11862c0SAndrew Turner sz = sizeof("xfi");
11619fbe8bdSZbigniew Bodek offset = size - sz;
1172306b72aSZbigniew Bodek break;
1182306b72aSZbigniew Bodek case QLM_MODE_XLAUI_1X4:
11919fbe8bdSZbigniew Bodek type = "xlaui";
120c11862c0SAndrew Turner sz = sizeof("xlaui");
12119fbe8bdSZbigniew Bodek offset = size - sz;
1222306b72aSZbigniew Bodek break;
1232306b72aSZbigniew Bodek case QLM_MODE_10G_KR_4X1:
12419fbe8bdSZbigniew Bodek type = "xfi-10g-kr";
125c11862c0SAndrew Turner sz = sizeof("xfi-10g-kr");
12619fbe8bdSZbigniew Bodek offset = size - sz;
1272306b72aSZbigniew Bodek break;
1282306b72aSZbigniew Bodek case QLM_MODE_40G_KR4_1X4:
12919fbe8bdSZbigniew Bodek type = "xlaui-40g-kr";
130c11862c0SAndrew Turner sz = sizeof("xlaui-40g-kr");
13119fbe8bdSZbigniew Bodek offset = size - sz;
1322306b72aSZbigniew Bodek break;
1332306b72aSZbigniew Bodek default:
1342306b72aSZbigniew Bodek return (FALSE);
1352306b72aSZbigniew Bodek }
1362306b72aSZbigniew Bodek
13719fbe8bdSZbigniew Bodek if (offset < 0)
13819fbe8bdSZbigniew Bodek return (FALSE);
13919fbe8bdSZbigniew Bodek
14019fbe8bdSZbigniew Bodek if (strncmp(&qlm_mode[offset], type, sz) == 0)
14119fbe8bdSZbigniew Bodek return (TRUE);
14219fbe8bdSZbigniew Bodek
14319fbe8bdSZbigniew Bodek return (FALSE);
14419fbe8bdSZbigniew Bodek }
14519fbe8bdSZbigniew Bodek
14619fbe8bdSZbigniew Bodek static boolean_t
bgx_fdt_phy_name_match(struct bgx * bgx,char * phy_name,ssize_t size)14719fbe8bdSZbigniew Bodek bgx_fdt_phy_name_match(struct bgx *bgx, char *phy_name, ssize_t size)
14819fbe8bdSZbigniew Bodek {
14919fbe8bdSZbigniew Bodek const char *type;
15019fbe8bdSZbigniew Bodek ssize_t sz;
151*6074a3c0SMark Johnston char last;
15219fbe8bdSZbigniew Bodek
15319fbe8bdSZbigniew Bodek switch (bgx->qlm_mode) {
15419fbe8bdSZbigniew Bodek case QLM_MODE_SGMII:
15519fbe8bdSZbigniew Bodek type = "sgmii";
156c11862c0SAndrew Turner sz = sizeof("sgmii");
15719fbe8bdSZbigniew Bodek break;
15819fbe8bdSZbigniew Bodek case QLM_MODE_XAUI_1X4:
15919fbe8bdSZbigniew Bodek type = "xaui";
160c11862c0SAndrew Turner sz = sizeof("xaui");
16119fbe8bdSZbigniew Bodek if (sz < size)
16219fbe8bdSZbigniew Bodek return (FALSE);
16319fbe8bdSZbigniew Bodek if (strncmp(phy_name, type, sz) == 0)
16419fbe8bdSZbigniew Bodek return (TRUE);
16519fbe8bdSZbigniew Bodek type = "dxaui";
166c11862c0SAndrew Turner sz = sizeof("dxaui");
16719fbe8bdSZbigniew Bodek break;
16819fbe8bdSZbigniew Bodek case QLM_MODE_RXAUI_2X2:
16919fbe8bdSZbigniew Bodek type = "raui";
170c11862c0SAndrew Turner sz = sizeof("raui");
17119fbe8bdSZbigniew Bodek break;
17219fbe8bdSZbigniew Bodek case QLM_MODE_XFI_4X1:
17319fbe8bdSZbigniew Bodek type = "xfi";
174c11862c0SAndrew Turner sz = sizeof("xfi");
17519fbe8bdSZbigniew Bodek break;
17619fbe8bdSZbigniew Bodek case QLM_MODE_XLAUI_1X4:
17719fbe8bdSZbigniew Bodek type = "xlaui";
178c11862c0SAndrew Turner sz = sizeof("xlaui");
17919fbe8bdSZbigniew Bodek break;
18019fbe8bdSZbigniew Bodek case QLM_MODE_10G_KR_4X1:
18119fbe8bdSZbigniew Bodek type = "xfi-10g-kr";
182c11862c0SAndrew Turner sz = sizeof("xfi-10g-kr");
18319fbe8bdSZbigniew Bodek break;
18419fbe8bdSZbigniew Bodek case QLM_MODE_40G_KR4_1X4:
18519fbe8bdSZbigniew Bodek type = "xlaui-40g-kr";
186c11862c0SAndrew Turner sz = sizeof("xlaui-40g-kr");
18719fbe8bdSZbigniew Bodek break;
18819fbe8bdSZbigniew Bodek default:
18919fbe8bdSZbigniew Bodek return (FALSE);
19019fbe8bdSZbigniew Bodek }
19119fbe8bdSZbigniew Bodek
19219fbe8bdSZbigniew Bodek if (sz > size)
19319fbe8bdSZbigniew Bodek return (FALSE);
194*6074a3c0SMark Johnston if (strncmp(phy_name, type, sz - 1) == 0) {
195*6074a3c0SMark Johnston last = phy_name[sz - 1];
196*6074a3c0SMark Johnston if (last == '\0' || last == '@' || isdigit(last))
19719fbe8bdSZbigniew Bodek return (TRUE);
198*6074a3c0SMark Johnston }
1992306b72aSZbigniew Bodek return (FALSE);
2002306b72aSZbigniew Bodek }
2012306b72aSZbigniew Bodek
202be624ad4SZbigniew Bodek static phandle_t
bgx_fdt_traverse_nodes(uint8_t unit,phandle_t start,char * name,size_t len)20319fbe8bdSZbigniew Bodek bgx_fdt_traverse_nodes(uint8_t unit, phandle_t start, char *name,
20419fbe8bdSZbigniew Bodek size_t len)
205be624ad4SZbigniew Bodek {
206be624ad4SZbigniew Bodek phandle_t node, ret;
20719fbe8bdSZbigniew Bodek uint32_t *reg;
208be624ad4SZbigniew Bodek size_t buf_size;
20919fbe8bdSZbigniew Bodek ssize_t proplen;
210be624ad4SZbigniew Bodek char *node_name;
211be624ad4SZbigniew Bodek int err;
212be624ad4SZbigniew Bodek
21319fbe8bdSZbigniew Bodek /*
21419fbe8bdSZbigniew Bodek * Traverse all subordinate nodes of 'start' to find BGX instance.
21519fbe8bdSZbigniew Bodek * This supports both old (by name) and new (by reg) methods.
21619fbe8bdSZbigniew Bodek */
217be624ad4SZbigniew Bodek buf_size = sizeof(*node_name) * FDT_NAME_MAXLEN;
218be624ad4SZbigniew Bodek if (len > buf_size) {
219be624ad4SZbigniew Bodek /*
220be624ad4SZbigniew Bodek * This is an erroneous situation since the string
221be624ad4SZbigniew Bodek * to compare cannot be longer than FDT_NAME_MAXLEN.
222be624ad4SZbigniew Bodek */
223be624ad4SZbigniew Bodek return (0);
224be624ad4SZbigniew Bodek }
225be624ad4SZbigniew Bodek
226be624ad4SZbigniew Bodek node_name = malloc(buf_size, M_BGX, M_WAITOK);
227be624ad4SZbigniew Bodek for (node = OF_child(start); node != 0; node = OF_peer(node)) {
228be624ad4SZbigniew Bodek /* Clean-up the buffer */
229be624ad4SZbigniew Bodek memset(node_name, 0, buf_size);
230be624ad4SZbigniew Bodek /* Recurse to children */
231be624ad4SZbigniew Bodek if (OF_child(node) != 0) {
23219fbe8bdSZbigniew Bodek ret = bgx_fdt_traverse_nodes(unit, node, name, len);
233be624ad4SZbigniew Bodek if (ret != 0) {
234be624ad4SZbigniew Bodek free(node_name, M_BGX);
235be624ad4SZbigniew Bodek return (ret);
236be624ad4SZbigniew Bodek }
237be624ad4SZbigniew Bodek }
23819fbe8bdSZbigniew Bodek /*
23919fbe8bdSZbigniew Bodek * Old way - by name
24019fbe8bdSZbigniew Bodek */
24119fbe8bdSZbigniew Bodek proplen = OF_getproplen(node, "name");
24219fbe8bdSZbigniew Bodek if ((proplen <= 0) || (proplen < len))
24319fbe8bdSZbigniew Bodek continue;
24419fbe8bdSZbigniew Bodek
24519fbe8bdSZbigniew Bodek err = OF_getprop(node, "name", node_name, proplen);
24619fbe8bdSZbigniew Bodek if (err <= 0)
24719fbe8bdSZbigniew Bodek continue;
24819fbe8bdSZbigniew Bodek
24919fbe8bdSZbigniew Bodek if (strncmp(node_name, name, len) == 0) {
250be624ad4SZbigniew Bodek free(node_name, M_BGX);
251be624ad4SZbigniew Bodek return (node);
252be624ad4SZbigniew Bodek }
25319fbe8bdSZbigniew Bodek /*
25419fbe8bdSZbigniew Bodek * New way - by reg
25519fbe8bdSZbigniew Bodek */
25619fbe8bdSZbigniew Bodek /* Check if even BGX */
25719fbe8bdSZbigniew Bodek if (strncmp(node_name,
25819fbe8bdSZbigniew Bodek BGX_NODE_NAME, sizeof(BGX_NODE_NAME) - 1) != 0)
25919fbe8bdSZbigniew Bodek continue;
26019fbe8bdSZbigniew Bodek /* Get reg */
261f7604b1bSOleksandr Tymoshenko err = OF_getencprop_alloc_multi(node, "reg", sizeof(*reg),
26219fbe8bdSZbigniew Bodek (void **)®);
26319fbe8bdSZbigniew Bodek if (err == -1) {
26419fbe8bdSZbigniew Bodek free(reg, M_OFWPROP);
26519fbe8bdSZbigniew Bodek continue;
26619fbe8bdSZbigniew Bodek }
26719fbe8bdSZbigniew Bodek
26819fbe8bdSZbigniew Bodek /* Match BGX device function */
26919fbe8bdSZbigniew Bodek if ((BGX_DEVFN_0 + unit) == (reg[0] >> 8)) {
27019fbe8bdSZbigniew Bodek free(reg, M_OFWPROP);
27119fbe8bdSZbigniew Bodek free(node_name, M_BGX);
27219fbe8bdSZbigniew Bodek return (node);
27319fbe8bdSZbigniew Bodek }
27419fbe8bdSZbigniew Bodek free(reg, M_OFWPROP);
275be624ad4SZbigniew Bodek }
276be624ad4SZbigniew Bodek free(node_name, M_BGX);
277be624ad4SZbigniew Bodek
278be624ad4SZbigniew Bodek return (0);
279be624ad4SZbigniew Bodek }
280be624ad4SZbigniew Bodek
281be624ad4SZbigniew Bodek /*
282be624ad4SZbigniew Bodek * Similar functionality to pci_find_pcie_root_port()
283be624ad4SZbigniew Bodek * but this one works for ThunderX.
284be624ad4SZbigniew Bodek */
285be624ad4SZbigniew Bodek static device_t
bgx_find_root_pcib(device_t dev)286be624ad4SZbigniew Bodek bgx_find_root_pcib(device_t dev)
287be624ad4SZbigniew Bodek {
288be624ad4SZbigniew Bodek devclass_t pci_class;
289be624ad4SZbigniew Bodek device_t pcib, bus;
290be624ad4SZbigniew Bodek
291be624ad4SZbigniew Bodek pci_class = devclass_find("pci");
292be624ad4SZbigniew Bodek KASSERT(device_get_devclass(device_get_parent(dev)) == pci_class,
293be624ad4SZbigniew Bodek ("%s: non-pci device %s", __func__, device_get_nameunit(dev)));
294be624ad4SZbigniew Bodek
295be624ad4SZbigniew Bodek /* Walk the bridge hierarchy until we find a non-PCI device */
296be624ad4SZbigniew Bodek for (;;) {
297be624ad4SZbigniew Bodek bus = device_get_parent(dev);
298be624ad4SZbigniew Bodek KASSERT(bus != NULL, ("%s: null parent of %s", __func__,
299be624ad4SZbigniew Bodek device_get_nameunit(dev)));
300be624ad4SZbigniew Bodek
301be624ad4SZbigniew Bodek if (device_get_devclass(bus) != pci_class)
302be624ad4SZbigniew Bodek return (NULL);
303be624ad4SZbigniew Bodek
304be624ad4SZbigniew Bodek pcib = device_get_parent(bus);
305be624ad4SZbigniew Bodek KASSERT(pcib != NULL, ("%s: null bridge of %s", __func__,
306be624ad4SZbigniew Bodek device_get_nameunit(bus)));
307be624ad4SZbigniew Bodek
308be624ad4SZbigniew Bodek /*
309be624ad4SZbigniew Bodek * If the parent of this PCIB is not PCI
310be624ad4SZbigniew Bodek * then we found our root PCIB.
311be624ad4SZbigniew Bodek */
312be624ad4SZbigniew Bodek if (device_get_devclass(device_get_parent(pcib)) != pci_class)
313be624ad4SZbigniew Bodek return (pcib);
314be624ad4SZbigniew Bodek
315be624ad4SZbigniew Bodek dev = pcib;
316be624ad4SZbigniew Bodek }
317be624ad4SZbigniew Bodek }
318be624ad4SZbigniew Bodek
319be624ad4SZbigniew Bodek static __inline phandle_t
bgx_fdt_find_node(struct bgx * bgx)320be624ad4SZbigniew Bodek bgx_fdt_find_node(struct bgx *bgx)
321be624ad4SZbigniew Bodek {
322be624ad4SZbigniew Bodek device_t root_pcib;
323be624ad4SZbigniew Bodek phandle_t node;
324be624ad4SZbigniew Bodek char *bgx_sel;
325be624ad4SZbigniew Bodek size_t len;
326be624ad4SZbigniew Bodek
327be624ad4SZbigniew Bodek KASSERT(bgx->bgx_id <= BGX_MAXID,
328be624ad4SZbigniew Bodek ("Invalid BGX ID: %d, max: %d", bgx->bgx_id, BGX_MAXID));
329be624ad4SZbigniew Bodek
330be624ad4SZbigniew Bodek len = sizeof(BGX_NODE_NAME) + 1; /* <bgx_name>+<digit>+<\0> */
331be624ad4SZbigniew Bodek /* Allocate memory for BGX node name + "/" character */
332be624ad4SZbigniew Bodek bgx_sel = malloc(sizeof(*bgx_sel) * (len + 1), M_BGX,
333be624ad4SZbigniew Bodek M_ZERO | M_WAITOK);
334be624ad4SZbigniew Bodek
335be624ad4SZbigniew Bodek /* Prepare node's name */
336be624ad4SZbigniew Bodek snprintf(bgx_sel, len + 1, "/"BGX_NODE_NAME"%d", bgx->bgx_id);
337be624ad4SZbigniew Bodek /* First try the root node */
338be624ad4SZbigniew Bodek node = OF_finddevice(bgx_sel);
339108117ccSOleksandr Tymoshenko if (node != -1) {
340be624ad4SZbigniew Bodek /* Found relevant node */
341be624ad4SZbigniew Bodek goto out;
342be624ad4SZbigniew Bodek }
343be624ad4SZbigniew Bodek /*
344be624ad4SZbigniew Bodek * Clean-up and try to find BGX in DT
345be624ad4SZbigniew Bodek * starting from the parent PCI bridge node.
346be624ad4SZbigniew Bodek */
347be624ad4SZbigniew Bodek memset(bgx_sel, 0, sizeof(*bgx_sel) * (len + 1));
348be624ad4SZbigniew Bodek snprintf(bgx_sel, len, BGX_NODE_NAME"%d", bgx->bgx_id);
349be624ad4SZbigniew Bodek
350be624ad4SZbigniew Bodek /* Find PCI bridge that we are connected to */
351be624ad4SZbigniew Bodek
352be624ad4SZbigniew Bodek root_pcib = bgx_find_root_pcib(bgx->dev);
353be624ad4SZbigniew Bodek if (root_pcib == NULL) {
354be624ad4SZbigniew Bodek device_printf(bgx->dev, "Unable to find BGX root bridge\n");
355be624ad4SZbigniew Bodek node = 0;
356be624ad4SZbigniew Bodek goto out;
357be624ad4SZbigniew Bodek }
358be624ad4SZbigniew Bodek
359be624ad4SZbigniew Bodek node = ofw_bus_get_node(root_pcib);
360db7cfc19SZbigniew Bodek if ((int)node <= 0) {
361be624ad4SZbigniew Bodek device_printf(bgx->dev, "No parent FDT node for BGX\n");
362be624ad4SZbigniew Bodek goto out;
363be624ad4SZbigniew Bodek }
364be624ad4SZbigniew Bodek
36519fbe8bdSZbigniew Bodek node = bgx_fdt_traverse_nodes(bgx->bgx_id, node, bgx_sel, len);
366be624ad4SZbigniew Bodek out:
367be624ad4SZbigniew Bodek free(bgx_sel, M_BGX);
368be624ad4SZbigniew Bodek return (node);
369be624ad4SZbigniew Bodek }
370be624ad4SZbigniew Bodek
3712306b72aSZbigniew Bodek int
bgx_fdt_init_phy(struct bgx * bgx)3722306b72aSZbigniew Bodek bgx_fdt_init_phy(struct bgx *bgx)
3732306b72aSZbigniew Bodek {
37419fbe8bdSZbigniew Bodek char *node_name;
3752306b72aSZbigniew Bodek phandle_t node, child;
3762306b72aSZbigniew Bodek phandle_t phy, mdio;
37719fbe8bdSZbigniew Bodek ssize_t len;
3782306b72aSZbigniew Bodek uint8_t lmac;
3792306b72aSZbigniew Bodek char qlm_mode[CONN_TYPE_MAXLEN];
3802306b72aSZbigniew Bodek
381be624ad4SZbigniew Bodek node = bgx_fdt_find_node(bgx);
382be624ad4SZbigniew Bodek if (node == 0) {
3832306b72aSZbigniew Bodek device_printf(bgx->dev,
384be624ad4SZbigniew Bodek "Could not find bgx%d node in FDT\n", bgx->bgx_id);
3852306b72aSZbigniew Bodek return (ENXIO);
3862306b72aSZbigniew Bodek }
3872306b72aSZbigniew Bodek
388be624ad4SZbigniew Bodek lmac = 0;
3892306b72aSZbigniew Bodek for (child = OF_child(node); child > 0; child = OF_peer(child)) {
39019fbe8bdSZbigniew Bodek len = OF_getprop(child, "qlm-mode", qlm_mode, sizeof(qlm_mode));
39119fbe8bdSZbigniew Bodek if (len > 0) {
39219fbe8bdSZbigniew Bodek if (!bgx_fdt_phy_mode_match(bgx, qlm_mode, len)) {
3932306b72aSZbigniew Bodek /*
3942306b72aSZbigniew Bodek * Connection type not match with BGX mode.
3952306b72aSZbigniew Bodek */
3962306b72aSZbigniew Bodek continue;
3972306b72aSZbigniew Bodek }
39819fbe8bdSZbigniew Bodek } else {
399217d17bcSOleksandr Tymoshenko len = OF_getprop_alloc(child, "name",
40019fbe8bdSZbigniew Bodek (void **)&node_name);
40119fbe8bdSZbigniew Bodek if (len <= 0) {
40219fbe8bdSZbigniew Bodek continue;
40319fbe8bdSZbigniew Bodek }
4042306b72aSZbigniew Bodek
40519fbe8bdSZbigniew Bodek if (!bgx_fdt_phy_name_match(bgx, node_name, len)) {
40619fbe8bdSZbigniew Bodek free(node_name, M_OFWPROP);
40719fbe8bdSZbigniew Bodek continue;
40819fbe8bdSZbigniew Bodek }
40919fbe8bdSZbigniew Bodek free(node_name, M_OFWPROP);
41019fbe8bdSZbigniew Bodek }
4112306b72aSZbigniew Bodek
4122306b72aSZbigniew Bodek /* Acquire PHY address */
413316e15b4SZbigniew Bodek if (OF_getencprop(child, "reg", &bgx->lmac[lmac].phyaddr,
4142306b72aSZbigniew Bodek sizeof(bgx->lmac[lmac].phyaddr)) <= 0) {
4152306b72aSZbigniew Bodek if (bootverbose) {
4162306b72aSZbigniew Bodek device_printf(bgx->dev,
4172306b72aSZbigniew Bodek "Could not retrieve PHY address\n");
4182306b72aSZbigniew Bodek }
4192306b72aSZbigniew Bodek bgx->lmac[lmac].phyaddr = MII_PHY_ANY;
4202306b72aSZbigniew Bodek }
4212306b72aSZbigniew Bodek
422316e15b4SZbigniew Bodek if (OF_getencprop(child, "phy-handle", &phy,
423316e15b4SZbigniew Bodek sizeof(phy)) <= 0) {
424316e15b4SZbigniew Bodek if (bootverbose) {
425316e15b4SZbigniew Bodek device_printf(bgx->dev,
426316e15b4SZbigniew Bodek "No phy-handle in PHY node. Skipping...\n");
427316e15b4SZbigniew Bodek }
428316e15b4SZbigniew Bodek continue;
429316e15b4SZbigniew Bodek }
430316e15b4SZbigniew Bodek phy = OF_instance_to_package(phy);
4312306b72aSZbigniew Bodek /*
4322306b72aSZbigniew Bodek * Get PHY interface (MDIO bus) device.
4332306b72aSZbigniew Bodek * Driver must be already attached.
4342306b72aSZbigniew Bodek */
4352306b72aSZbigniew Bodek mdio = OF_parent(phy);
4362306b72aSZbigniew Bodek bgx->lmac[lmac].phy_if_dev =
4372306b72aSZbigniew Bodek OF_device_from_xref(OF_xref_from_node(mdio));
4382306b72aSZbigniew Bodek if (bgx->lmac[lmac].phy_if_dev == NULL) {
4392306b72aSZbigniew Bodek if (bootverbose) {
4402306b72aSZbigniew Bodek device_printf(bgx->dev,
4412306b72aSZbigniew Bodek "Could not find interface to PHY\n");
4422306b72aSZbigniew Bodek }
4432306b72aSZbigniew Bodek continue;
4442306b72aSZbigniew Bodek }
4452306b72aSZbigniew Bodek
4462306b72aSZbigniew Bodek /* Get mac address from FDT */
447316e15b4SZbigniew Bodek bgx_fdt_get_macaddr(child, bgx->lmac[lmac].mac);
4482306b72aSZbigniew Bodek
4492306b72aSZbigniew Bodek bgx->lmac[lmac].lmacid = lmac;
4502306b72aSZbigniew Bodek lmac++;
4512306b72aSZbigniew Bodek if (lmac == MAX_LMAC_PER_BGX)
4522306b72aSZbigniew Bodek break;
4532306b72aSZbigniew Bodek }
4542306b72aSZbigniew Bodek if (lmac == 0) {
4552306b72aSZbigniew Bodek device_printf(bgx->dev, "Could not find matching PHY\n");
4562306b72aSZbigniew Bodek return (ENXIO);
4572306b72aSZbigniew Bodek }
4582306b72aSZbigniew Bodek
4592306b72aSZbigniew Bodek return (0);
4602306b72aSZbigniew Bodek }
461