14ad7e9b0SAdrian Chadd /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
36e778a7eSPedro F. Giffuni *
489294a78SLandon J. Fuller * Copyright (c) 2015-2017 Landon Fuller <landonf@landonf.org>
589294a78SLandon J. Fuller * Copyright (c) 2017 The FreeBSD Foundation
64ad7e9b0SAdrian Chadd * All rights reserved.
74ad7e9b0SAdrian Chadd *
889294a78SLandon J. Fuller * Portions of this software were developed by Landon Fuller
989294a78SLandon J. Fuller * under sponsorship from the FreeBSD Foundation.
1089294a78SLandon J. Fuller *
114ad7e9b0SAdrian Chadd * Redistribution and use in source and binary forms, with or without
124ad7e9b0SAdrian Chadd * modification, are permitted provided that the following conditions
134ad7e9b0SAdrian Chadd * are met:
144ad7e9b0SAdrian Chadd * 1. Redistributions of source code must retain the above copyright
154ad7e9b0SAdrian Chadd * notice, this list of conditions and the following disclaimer,
164ad7e9b0SAdrian Chadd * without modification.
174ad7e9b0SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer
184ad7e9b0SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
194ad7e9b0SAdrian Chadd * redistribution must be conditioned upon including a substantially
204ad7e9b0SAdrian Chadd * similar Disclaimer requirement for further binary redistribution.
214ad7e9b0SAdrian Chadd *
224ad7e9b0SAdrian Chadd * NO WARRANTY
234ad7e9b0SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
244ad7e9b0SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
254ad7e9b0SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
264ad7e9b0SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
274ad7e9b0SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
284ad7e9b0SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
294ad7e9b0SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
304ad7e9b0SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
314ad7e9b0SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
324ad7e9b0SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
334ad7e9b0SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES.
344ad7e9b0SAdrian Chadd */
354ad7e9b0SAdrian Chadd
364ad7e9b0SAdrian Chadd #include <sys/param.h>
374ad7e9b0SAdrian Chadd #include <sys/bus.h>
384ad7e9b0SAdrian Chadd #include <sys/kernel.h>
394ad7e9b0SAdrian Chadd #include <sys/limits.h>
404ad7e9b0SAdrian Chadd #include <sys/systm.h>
414ad7e9b0SAdrian Chadd
424ad7e9b0SAdrian Chadd #include <machine/bus.h>
434ad7e9b0SAdrian Chadd #include <machine/resource.h>
444ad7e9b0SAdrian Chadd
45f3524ec8SLandon J. Fuller #include <dev/bhnd/bhnd_eromvar.h>
46664a7497SLandon J. Fuller
474ad7e9b0SAdrian Chadd #include "bcma_eromreg.h"
484ad7e9b0SAdrian Chadd #include "bcma_eromvar.h"
494ad7e9b0SAdrian Chadd
504ad7e9b0SAdrian Chadd /*
514ad7e9b0SAdrian Chadd * BCMA Enumeration ROM (EROM) Table
524ad7e9b0SAdrian Chadd *
534ad7e9b0SAdrian Chadd * Provides auto-discovery of BCMA cores on Broadcom's HND SoC.
544ad7e9b0SAdrian Chadd *
554ad7e9b0SAdrian Chadd * The EROM core address can be found at BCMA_CC_EROM_ADDR within the
564ad7e9b0SAdrian Chadd * ChipCommon registers. The table itself is comprised of 32-bit
574ad7e9b0SAdrian Chadd * type-tagged entries, organized into an array of variable-length
584ad7e9b0SAdrian Chadd * core descriptor records.
594ad7e9b0SAdrian Chadd *
604ad7e9b0SAdrian Chadd * The final core descriptor is followed by a 32-bit BCMA_EROM_TABLE_EOF (0xF)
614ad7e9b0SAdrian Chadd * marker.
624ad7e9b0SAdrian Chadd */
634ad7e9b0SAdrian Chadd
64664a7497SLandon J. Fuller static const char *bcma_erom_entry_type_name (uint8_t entry);
65111d7cb2SLandon J. Fuller
66664a7497SLandon J. Fuller static int bcma_erom_read32(struct bcma_erom *erom,
67664a7497SLandon J. Fuller uint32_t *entry);
68664a7497SLandon J. Fuller static int bcma_erom_skip32(struct bcma_erom *erom);
694ad7e9b0SAdrian Chadd
70664a7497SLandon J. Fuller static int bcma_erom_skip_core(struct bcma_erom *erom);
71664a7497SLandon J. Fuller static int bcma_erom_skip_mport(struct bcma_erom *erom);
72664a7497SLandon J. Fuller static int bcma_erom_skip_sport_region(struct bcma_erom *erom);
734ad7e9b0SAdrian Chadd
74664a7497SLandon J. Fuller static int bcma_erom_seek_next(struct bcma_erom *erom,
75664a7497SLandon J. Fuller uint8_t etype);
76664a7497SLandon J. Fuller static int bcma_erom_region_to_port_type(struct bcma_erom *erom,
77cb4abe62SLandon J. Fuller uint8_t region_type, bhnd_port_type *port_type);
784ad7e9b0SAdrian Chadd
79664a7497SLandon J. Fuller static int bcma_erom_peek32(struct bcma_erom *erom,
80664a7497SLandon J. Fuller uint32_t *entry);
81111d7cb2SLandon J. Fuller
82664a7497SLandon J. Fuller static bus_size_t bcma_erom_tell(struct bcma_erom *erom);
83664a7497SLandon J. Fuller static void bcma_erom_seek(struct bcma_erom *erom,
84664a7497SLandon J. Fuller bus_size_t offset);
85664a7497SLandon J. Fuller static void bcma_erom_reset(struct bcma_erom *erom);
86664a7497SLandon J. Fuller
87664a7497SLandon J. Fuller static int bcma_erom_seek_matching_core(struct bcma_erom *sc,
88664a7497SLandon J. Fuller const struct bhnd_core_match *desc,
89664a7497SLandon J. Fuller struct bhnd_core_info *core);
90664a7497SLandon J. Fuller
91664a7497SLandon J. Fuller static int bcma_erom_parse_core(struct bcma_erom *erom,
92664a7497SLandon J. Fuller struct bcma_erom_core *core);
93664a7497SLandon J. Fuller
94664a7497SLandon J. Fuller static int bcma_erom_parse_mport(struct bcma_erom *erom,
95664a7497SLandon J. Fuller struct bcma_erom_mport *mport);
96664a7497SLandon J. Fuller
97664a7497SLandon J. Fuller static int bcma_erom_parse_sport_region(struct bcma_erom *erom,
98664a7497SLandon J. Fuller struct bcma_erom_sport_region *region);
99664a7497SLandon J. Fuller
100664a7497SLandon J. Fuller static void bcma_erom_to_core_info(const struct bcma_erom_core *core,
101664a7497SLandon J. Fuller u_int core_idx, int core_unit,
102664a7497SLandon J. Fuller struct bhnd_core_info *info);
103664a7497SLandon J. Fuller
104111d7cb2SLandon J. Fuller /**
105111d7cb2SLandon J. Fuller * BCMA EROM per-instance state.
106111d7cb2SLandon J. Fuller */
107111d7cb2SLandon J. Fuller struct bcma_erom {
108111d7cb2SLandon J. Fuller struct bhnd_erom obj;
109111d7cb2SLandon J. Fuller device_t dev; /**< parent device, or NULL if none. */
11089294a78SLandon J. Fuller struct bhnd_erom_io *eio; /**< bus I/O callbacks */
11189294a78SLandon J. Fuller bhnd_size_t offset; /**< current read offset */
112111d7cb2SLandon J. Fuller };
113111d7cb2SLandon J. Fuller
114cb4abe62SLandon J. Fuller #define EROM_LOG(erom, fmt, ...) do { \
11589294a78SLandon J. Fuller printf("%s erom[0x%llx]: " fmt, __FUNCTION__, \
116cb4abe62SLandon J. Fuller (unsigned long long)(erom->offset), ##__VA_ARGS__); \
117cb4abe62SLandon J. Fuller } while(0)
1184ad7e9b0SAdrian Chadd
1194ad7e9b0SAdrian Chadd /** Return the type name for an EROM entry */
1204ad7e9b0SAdrian Chadd static const char *
bcma_erom_entry_type_name(uint8_t entry)121664a7497SLandon J. Fuller bcma_erom_entry_type_name (uint8_t entry)
1224ad7e9b0SAdrian Chadd {
1234ad7e9b0SAdrian Chadd switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) {
1244ad7e9b0SAdrian Chadd case BCMA_EROM_ENTRY_TYPE_CORE:
1254ad7e9b0SAdrian Chadd return "core";
1264ad7e9b0SAdrian Chadd case BCMA_EROM_ENTRY_TYPE_MPORT:
1274ad7e9b0SAdrian Chadd return "mport";
1284ad7e9b0SAdrian Chadd case BCMA_EROM_ENTRY_TYPE_REGION:
1294ad7e9b0SAdrian Chadd return "region";
1304ad7e9b0SAdrian Chadd default:
1314ad7e9b0SAdrian Chadd return "unknown";
1324ad7e9b0SAdrian Chadd }
1334ad7e9b0SAdrian Chadd }
1344ad7e9b0SAdrian Chadd
135111d7cb2SLandon J. Fuller /* BCMA implementation of BHND_EROM_INIT() */
136111d7cb2SLandon J. Fuller static int
bcma_erom_init(bhnd_erom_t * erom,const struct bhnd_chipid * cid,struct bhnd_erom_io * eio)137111d7cb2SLandon J. Fuller bcma_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid,
13889294a78SLandon J. Fuller struct bhnd_erom_io *eio)
139111d7cb2SLandon J. Fuller {
140111d7cb2SLandon J. Fuller struct bcma_erom *sc;
14189294a78SLandon J. Fuller bhnd_addr_t table_addr;
14289294a78SLandon J. Fuller int error;
143111d7cb2SLandon J. Fuller
144111d7cb2SLandon J. Fuller sc = (struct bcma_erom *)erom;
14589294a78SLandon J. Fuller sc->eio = eio;
146111d7cb2SLandon J. Fuller sc->offset = 0;
1474ad7e9b0SAdrian Chadd
14889294a78SLandon J. Fuller /* Determine erom table address */
14989294a78SLandon J. Fuller if (BHND_ADDR_MAX - BCMA_EROM_TABLE_START < cid->enum_addr)
15089294a78SLandon J. Fuller return (ENXIO); /* would overflow */
151111d7cb2SLandon J. Fuller
15289294a78SLandon J. Fuller table_addr = cid->enum_addr + BCMA_EROM_TABLE_START;
1534ad7e9b0SAdrian Chadd
15489294a78SLandon J. Fuller /* Try to map the erom table */
15589294a78SLandon J. Fuller error = bhnd_erom_io_map(sc->eio, table_addr, BCMA_EROM_TABLE_SIZE);
15689294a78SLandon J. Fuller if (error)
15789294a78SLandon J. Fuller return (error);
158664a7497SLandon J. Fuller
1594ad7e9b0SAdrian Chadd return (0);
1604ad7e9b0SAdrian Chadd }
1614ad7e9b0SAdrian Chadd
16289294a78SLandon J. Fuller /* BCMA implementation of BHND_EROM_PROBE() */
1634ad7e9b0SAdrian Chadd static int
bcma_erom_probe(bhnd_erom_class_t * cls,struct bhnd_erom_io * eio,const struct bhnd_chipid * hint,struct bhnd_chipid * cid)16489294a78SLandon J. Fuller bcma_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio,
16589294a78SLandon J. Fuller const struct bhnd_chipid *hint, struct bhnd_chipid *cid)
166111d7cb2SLandon J. Fuller {
167f3524ec8SLandon J. Fuller int error;
168111d7cb2SLandon J. Fuller
169111d7cb2SLandon J. Fuller /* Hints aren't supported; all BCMA devices have a ChipCommon
170111d7cb2SLandon J. Fuller * core */
171111d7cb2SLandon J. Fuller if (hint != NULL)
172111d7cb2SLandon J. Fuller return (EINVAL);
173111d7cb2SLandon J. Fuller
174f3524ec8SLandon J. Fuller /* Read and parse chip identification */
175f3524ec8SLandon J. Fuller if ((error = bhnd_erom_read_chipid(eio, cid)))
176f3524ec8SLandon J. Fuller return (error);
1774ad7e9b0SAdrian Chadd
178664a7497SLandon J. Fuller /* Verify chip type */
179111d7cb2SLandon J. Fuller switch (cid->chip_type) {
180664a7497SLandon J. Fuller case BHND_CHIPTYPE_BCMA:
181664a7497SLandon J. Fuller return (BUS_PROBE_DEFAULT);
1824ad7e9b0SAdrian Chadd
183664a7497SLandon J. Fuller case BHND_CHIPTYPE_BCMA_ALT:
184664a7497SLandon J. Fuller case BHND_CHIPTYPE_UBUS:
185664a7497SLandon J. Fuller return (BUS_PROBE_GENERIC);
1864ad7e9b0SAdrian Chadd
1874ad7e9b0SAdrian Chadd default:
188664a7497SLandon J. Fuller return (ENXIO);
1894ad7e9b0SAdrian Chadd }
1904ad7e9b0SAdrian Chadd }
1914ad7e9b0SAdrian Chadd
192664a7497SLandon J. Fuller static void
bcma_erom_fini(bhnd_erom_t * erom)193664a7497SLandon J. Fuller bcma_erom_fini(bhnd_erom_t *erom)
1944ad7e9b0SAdrian Chadd {
195664a7497SLandon J. Fuller struct bcma_erom *sc = (struct bcma_erom *)erom;
1964ad7e9b0SAdrian Chadd
19789294a78SLandon J. Fuller bhnd_erom_io_fini(sc->eio);
1984ad7e9b0SAdrian Chadd }
1994ad7e9b0SAdrian Chadd
200664a7497SLandon J. Fuller static int
bcma_erom_lookup_core(bhnd_erom_t * erom,const struct bhnd_core_match * desc,struct bhnd_core_info * core)201664a7497SLandon J. Fuller bcma_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
202664a7497SLandon J. Fuller struct bhnd_core_info *core)
203cb4abe62SLandon J. Fuller {
204664a7497SLandon J. Fuller struct bcma_erom *sc = (struct bcma_erom *)erom;
205664a7497SLandon J. Fuller
206664a7497SLandon J. Fuller /* Search for the first matching core */
207664a7497SLandon J. Fuller return (bcma_erom_seek_matching_core(sc, desc, core));
208664a7497SLandon J. Fuller }
209664a7497SLandon J. Fuller
210664a7497SLandon J. Fuller static int
bcma_erom_lookup_core_addr(bhnd_erom_t * erom,const struct bhnd_core_match * desc,bhnd_port_type port_type,u_int port_num,u_int region_num,struct bhnd_core_info * core,bhnd_addr_t * addr,bhnd_size_t * size)211664a7497SLandon J. Fuller bcma_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
212664a7497SLandon J. Fuller bhnd_port_type port_type, u_int port_num, u_int region_num,
213664a7497SLandon J. Fuller struct bhnd_core_info *core, bhnd_addr_t *addr, bhnd_size_t *size)
214664a7497SLandon J. Fuller {
215664a7497SLandon J. Fuller struct bcma_erom *sc;
216664a7497SLandon J. Fuller struct bcma_erom_core ec;
217cb4abe62SLandon J. Fuller uint32_t entry;
218cb4abe62SLandon J. Fuller uint8_t region_port, region_type;
219cb4abe62SLandon J. Fuller bool found;
220cb4abe62SLandon J. Fuller int error;
221cb4abe62SLandon J. Fuller
222664a7497SLandon J. Fuller sc = (struct bcma_erom *)erom;
223664a7497SLandon J. Fuller
224664a7497SLandon J. Fuller /* Seek to the first matching core and provide the core info
225664a7497SLandon J. Fuller * to the caller */
226664a7497SLandon J. Fuller if ((error = bcma_erom_seek_matching_core(sc, desc, core)))
227cb4abe62SLandon J. Fuller return (error);
228cb4abe62SLandon J. Fuller
229664a7497SLandon J. Fuller if ((error = bcma_erom_parse_core(sc, &ec)))
230cb4abe62SLandon J. Fuller return (error);
231cb4abe62SLandon J. Fuller
232cb4abe62SLandon J. Fuller /* Skip master ports */
233664a7497SLandon J. Fuller for (u_long i = 0; i < ec.num_mport; i++) {
234664a7497SLandon J. Fuller if ((error = bcma_erom_skip_mport(sc)))
235cb4abe62SLandon J. Fuller return (error);
236cb4abe62SLandon J. Fuller }
237cb4abe62SLandon J. Fuller
238cb4abe62SLandon J. Fuller /* Seek to the region block for the given port type */
239cb4abe62SLandon J. Fuller found = false;
240cb4abe62SLandon J. Fuller while (1) {
241cb4abe62SLandon J. Fuller bhnd_port_type p_type;
242cb4abe62SLandon J. Fuller uint8_t r_type;
243cb4abe62SLandon J. Fuller
244664a7497SLandon J. Fuller if ((error = bcma_erom_peek32(sc, &entry)))
245cb4abe62SLandon J. Fuller return (error);
246cb4abe62SLandon J. Fuller
247cb4abe62SLandon J. Fuller if (!BCMA_EROM_ENTRY_IS(entry, REGION))
248cb4abe62SLandon J. Fuller return (ENOENT);
249cb4abe62SLandon J. Fuller
250cb4abe62SLandon J. Fuller /* Expected region type? */
251cb4abe62SLandon J. Fuller r_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
252664a7497SLandon J. Fuller error = bcma_erom_region_to_port_type(sc, r_type, &p_type);
253664a7497SLandon J. Fuller if (error)
254cb4abe62SLandon J. Fuller return (error);
255cb4abe62SLandon J. Fuller
256cb4abe62SLandon J. Fuller if (p_type == port_type) {
257cb4abe62SLandon J. Fuller found = true;
258cb4abe62SLandon J. Fuller break;
259cb4abe62SLandon J. Fuller }
260cb4abe62SLandon J. Fuller
261cb4abe62SLandon J. Fuller /* Skip to next entry */
262664a7497SLandon J. Fuller if ((error = bcma_erom_skip_sport_region(sc)))
263cb4abe62SLandon J. Fuller return (error);
264cb4abe62SLandon J. Fuller }
265cb4abe62SLandon J. Fuller
266cb4abe62SLandon J. Fuller if (!found)
267cb4abe62SLandon J. Fuller return (ENOENT);
268cb4abe62SLandon J. Fuller
269cb4abe62SLandon J. Fuller /* Found the appropriate port type block; now find the region records
270cb4abe62SLandon J. Fuller * for the given port number */
271cb4abe62SLandon J. Fuller found = false;
272cb4abe62SLandon J. Fuller for (u_int i = 0; i <= port_num; i++) {
273cb4abe62SLandon J. Fuller bhnd_port_type p_type;
274cb4abe62SLandon J. Fuller
275664a7497SLandon J. Fuller if ((error = bcma_erom_peek32(sc, &entry)))
276cb4abe62SLandon J. Fuller return (error);
277cb4abe62SLandon J. Fuller
278cb4abe62SLandon J. Fuller if (!BCMA_EROM_ENTRY_IS(entry, REGION))
279cb4abe62SLandon J. Fuller return (ENOENT);
280cb4abe62SLandon J. Fuller
281cb4abe62SLandon J. Fuller /* Fetch the type/port of the first region entry */
282cb4abe62SLandon J. Fuller region_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
283cb4abe62SLandon J. Fuller region_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
284cb4abe62SLandon J. Fuller
285cb4abe62SLandon J. Fuller /* Have we found the region entries for the desired port? */
286cb4abe62SLandon J. Fuller if (i == port_num) {
287664a7497SLandon J. Fuller error = bcma_erom_region_to_port_type(sc, region_type,
288cb4abe62SLandon J. Fuller &p_type);
289cb4abe62SLandon J. Fuller if (error)
290cb4abe62SLandon J. Fuller return (error);
291cb4abe62SLandon J. Fuller
292cb4abe62SLandon J. Fuller if (p_type == port_type)
293cb4abe62SLandon J. Fuller found = true;
294cb4abe62SLandon J. Fuller
295cb4abe62SLandon J. Fuller break;
296cb4abe62SLandon J. Fuller }
297cb4abe62SLandon J. Fuller
298cb4abe62SLandon J. Fuller /* Otherwise, seek to next block of region records */
299cb4abe62SLandon J. Fuller while (1) {
300cb4abe62SLandon J. Fuller uint8_t next_type, next_port;
301cb4abe62SLandon J. Fuller
302664a7497SLandon J. Fuller if ((error = bcma_erom_skip_sport_region(sc)))
303cb4abe62SLandon J. Fuller return (error);
304cb4abe62SLandon J. Fuller
305664a7497SLandon J. Fuller if ((error = bcma_erom_peek32(sc, &entry)))
306cb4abe62SLandon J. Fuller return (error);
307cb4abe62SLandon J. Fuller
308cb4abe62SLandon J. Fuller if (!BCMA_EROM_ENTRY_IS(entry, REGION))
309cb4abe62SLandon J. Fuller return (ENOENT);
310cb4abe62SLandon J. Fuller
311cb4abe62SLandon J. Fuller next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
312cb4abe62SLandon J. Fuller next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
313cb4abe62SLandon J. Fuller
314cb4abe62SLandon J. Fuller if (next_type != region_type ||
315cb4abe62SLandon J. Fuller next_port != region_port)
316cb4abe62SLandon J. Fuller break;
317cb4abe62SLandon J. Fuller }
318cb4abe62SLandon J. Fuller }
319cb4abe62SLandon J. Fuller
320cb4abe62SLandon J. Fuller if (!found)
321cb4abe62SLandon J. Fuller return (ENOENT);
322cb4abe62SLandon J. Fuller
323cb4abe62SLandon J. Fuller /* Finally, search for the requested region number */
324cb4abe62SLandon J. Fuller for (u_int i = 0; i <= region_num; i++) {
325664a7497SLandon J. Fuller struct bcma_erom_sport_region region;
326cb4abe62SLandon J. Fuller uint8_t next_port, next_type;
327cb4abe62SLandon J. Fuller
328664a7497SLandon J. Fuller if ((error = bcma_erom_peek32(sc, &entry)))
329cb4abe62SLandon J. Fuller return (error);
330cb4abe62SLandon J. Fuller
331cb4abe62SLandon J. Fuller if (!BCMA_EROM_ENTRY_IS(entry, REGION))
332cb4abe62SLandon J. Fuller return (ENOENT);
333cb4abe62SLandon J. Fuller
334cb4abe62SLandon J. Fuller /* Check for the end of the region block */
335cb4abe62SLandon J. Fuller next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
336cb4abe62SLandon J. Fuller next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
337cb4abe62SLandon J. Fuller
338cb4abe62SLandon J. Fuller if (next_type != region_type ||
339cb4abe62SLandon J. Fuller next_port != region_port)
340cb4abe62SLandon J. Fuller break;
341cb4abe62SLandon J. Fuller
342664a7497SLandon J. Fuller /* Parse the region */
343664a7497SLandon J. Fuller if ((error = bcma_erom_parse_sport_region(sc, ®ion)))
344cb4abe62SLandon J. Fuller return (error);
345664a7497SLandon J. Fuller
346664a7497SLandon J. Fuller /* Is this our target region_num? */
347664a7497SLandon J. Fuller if (i == region_num) {
348664a7497SLandon J. Fuller /* Found */
349664a7497SLandon J. Fuller *addr = region.base_addr;
350664a7497SLandon J. Fuller *size = region.size;
351664a7497SLandon J. Fuller return (0);
352664a7497SLandon J. Fuller }
353cb4abe62SLandon J. Fuller }
354cb4abe62SLandon J. Fuller
355cb4abe62SLandon J. Fuller /* Not found */
356cb4abe62SLandon J. Fuller return (ENOENT);
357664a7497SLandon J. Fuller };
358cb4abe62SLandon J. Fuller
359664a7497SLandon J. Fuller static int
bcma_erom_get_core_table(bhnd_erom_t * erom,struct bhnd_core_info ** cores,u_int * num_cores)360664a7497SLandon J. Fuller bcma_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
3614ad7e9b0SAdrian Chadd u_int *num_cores)
3624ad7e9b0SAdrian Chadd {
363664a7497SLandon J. Fuller struct bcma_erom *sc;
3644ad7e9b0SAdrian Chadd struct bhnd_core_info *buffer;
3654ad7e9b0SAdrian Chadd bus_size_t initial_offset;
3664ad7e9b0SAdrian Chadd u_int count;
3674ad7e9b0SAdrian Chadd int error;
3684ad7e9b0SAdrian Chadd
369664a7497SLandon J. Fuller sc = (struct bcma_erom *)erom;
370664a7497SLandon J. Fuller
3714ad7e9b0SAdrian Chadd buffer = NULL;
372664a7497SLandon J. Fuller initial_offset = bcma_erom_tell(sc);
3734ad7e9b0SAdrian Chadd
3744ad7e9b0SAdrian Chadd /* Determine the core count */
375664a7497SLandon J. Fuller bcma_erom_reset(sc);
3764ad7e9b0SAdrian Chadd for (count = 0, error = 0; !error; count++) {
3774ad7e9b0SAdrian Chadd struct bcma_erom_core core;
3784ad7e9b0SAdrian Chadd
3794ad7e9b0SAdrian Chadd /* Seek to the first readable core entry */
380664a7497SLandon J. Fuller error = bcma_erom_seek_next(sc, BCMA_EROM_ENTRY_TYPE_CORE);
3814ad7e9b0SAdrian Chadd if (error == ENOENT)
3824ad7e9b0SAdrian Chadd break;
3834ad7e9b0SAdrian Chadd else if (error)
3844ad7e9b0SAdrian Chadd goto cleanup;
3854ad7e9b0SAdrian Chadd
3864ad7e9b0SAdrian Chadd /* Read past the core descriptor */
387664a7497SLandon J. Fuller if ((error = bcma_erom_parse_core(sc, &core)))
3884ad7e9b0SAdrian Chadd goto cleanup;
3894ad7e9b0SAdrian Chadd }
3904ad7e9b0SAdrian Chadd
3914ad7e9b0SAdrian Chadd /* Allocate our output buffer */
39292e1020aSPedro F. Giffuni buffer = mallocarray(count, sizeof(struct bhnd_core_info), M_BHND,
3934ad7e9b0SAdrian Chadd M_NOWAIT);
3944ad7e9b0SAdrian Chadd if (buffer == NULL) {
3954ad7e9b0SAdrian Chadd error = ENOMEM;
3964ad7e9b0SAdrian Chadd goto cleanup;
3974ad7e9b0SAdrian Chadd }
3984ad7e9b0SAdrian Chadd
3994ad7e9b0SAdrian Chadd /* Parse all core descriptors */
400664a7497SLandon J. Fuller bcma_erom_reset(sc);
4014ad7e9b0SAdrian Chadd for (u_int i = 0; i < count; i++) {
4024ad7e9b0SAdrian Chadd struct bcma_erom_core core;
403cb4abe62SLandon J. Fuller int unit;
4044ad7e9b0SAdrian Chadd
4054ad7e9b0SAdrian Chadd /* Parse the core */
406664a7497SLandon J. Fuller error = bcma_erom_seek_next(sc, BCMA_EROM_ENTRY_TYPE_CORE);
4074ad7e9b0SAdrian Chadd if (error)
4084ad7e9b0SAdrian Chadd goto cleanup;
4094ad7e9b0SAdrian Chadd
410664a7497SLandon J. Fuller error = bcma_erom_parse_core(sc, &core);
4114ad7e9b0SAdrian Chadd if (error)
4124ad7e9b0SAdrian Chadd goto cleanup;
4134ad7e9b0SAdrian Chadd
4144ad7e9b0SAdrian Chadd /* Determine the unit number */
415cb4abe62SLandon J. Fuller unit = 0;
4164ad7e9b0SAdrian Chadd for (u_int j = 0; j < i; j++) {
4174ad7e9b0SAdrian Chadd if (buffer[i].vendor == buffer[j].vendor &&
4184ad7e9b0SAdrian Chadd buffer[i].device == buffer[j].device)
419cb4abe62SLandon J. Fuller unit++;
4204ad7e9b0SAdrian Chadd }
421cb4abe62SLandon J. Fuller
422cb4abe62SLandon J. Fuller /* Convert to a bhnd info record */
423cb4abe62SLandon J. Fuller bcma_erom_to_core_info(&core, i, unit, &buffer[i]);
4244ad7e9b0SAdrian Chadd }
4254ad7e9b0SAdrian Chadd
4264ad7e9b0SAdrian Chadd cleanup:
4274ad7e9b0SAdrian Chadd if (!error) {
4284ad7e9b0SAdrian Chadd *cores = buffer;
4294ad7e9b0SAdrian Chadd *num_cores = count;
4304ad7e9b0SAdrian Chadd } else {
4314ad7e9b0SAdrian Chadd if (buffer != NULL)
4324ad7e9b0SAdrian Chadd free(buffer, M_BHND);
4334ad7e9b0SAdrian Chadd }
4344ad7e9b0SAdrian Chadd
4354ad7e9b0SAdrian Chadd /* Restore the initial position */
436664a7497SLandon J. Fuller bcma_erom_seek(sc, initial_offset);
4374ad7e9b0SAdrian Chadd return (error);
4384ad7e9b0SAdrian Chadd }
4394ad7e9b0SAdrian Chadd
440664a7497SLandon J. Fuller static void
bcma_erom_free_core_table(bhnd_erom_t * erom,struct bhnd_core_info * cores)441664a7497SLandon J. Fuller bcma_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
442664a7497SLandon J. Fuller {
443664a7497SLandon J. Fuller free(cores, M_BHND);
444664a7497SLandon J. Fuller }
445664a7497SLandon J. Fuller
446664a7497SLandon J. Fuller /**
447664a7497SLandon J. Fuller * Return the current read position.
448664a7497SLandon J. Fuller */
449664a7497SLandon J. Fuller static bus_size_t
bcma_erom_tell(struct bcma_erom * erom)450664a7497SLandon J. Fuller bcma_erom_tell(struct bcma_erom *erom)
451664a7497SLandon J. Fuller {
452664a7497SLandon J. Fuller return (erom->offset);
453664a7497SLandon J. Fuller }
454664a7497SLandon J. Fuller
455664a7497SLandon J. Fuller /**
456664a7497SLandon J. Fuller * Seek to an absolute read position.
457664a7497SLandon J. Fuller */
458664a7497SLandon J. Fuller static void
bcma_erom_seek(struct bcma_erom * erom,bus_size_t offset)459664a7497SLandon J. Fuller bcma_erom_seek(struct bcma_erom *erom, bus_size_t offset)
460664a7497SLandon J. Fuller {
461664a7497SLandon J. Fuller erom->offset = offset;
462664a7497SLandon J. Fuller }
463664a7497SLandon J. Fuller
464664a7497SLandon J. Fuller /**
465664a7497SLandon J. Fuller * Read a 32-bit entry value from the EROM table without advancing the
466664a7497SLandon J. Fuller * read position.
467664a7497SLandon J. Fuller *
468664a7497SLandon J. Fuller * @param erom EROM read state.
469664a7497SLandon J. Fuller * @param entry Will contain the read result on success.
470664a7497SLandon J. Fuller * @retval 0 success
471664a7497SLandon J. Fuller * @retval ENOENT The end of the EROM table was reached.
472664a7497SLandon J. Fuller * @retval non-zero The read could not be completed.
473664a7497SLandon J. Fuller */
474664a7497SLandon J. Fuller static int
bcma_erom_peek32(struct bcma_erom * erom,uint32_t * entry)475664a7497SLandon J. Fuller bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry)
476664a7497SLandon J. Fuller {
477111d7cb2SLandon J. Fuller if (erom->offset >= (BCMA_EROM_TABLE_SIZE - sizeof(uint32_t))) {
478664a7497SLandon J. Fuller EROM_LOG(erom, "BCMA EROM table missing terminating EOF\n");
479664a7497SLandon J. Fuller return (EINVAL);
480664a7497SLandon J. Fuller }
481664a7497SLandon J. Fuller
48289294a78SLandon J. Fuller *entry = bhnd_erom_io_read(erom->eio, erom->offset, 4);
483664a7497SLandon J. Fuller return (0);
484664a7497SLandon J. Fuller }
485664a7497SLandon J. Fuller
486664a7497SLandon J. Fuller /**
487664a7497SLandon J. Fuller * Read a 32-bit entry value from the EROM table.
488664a7497SLandon J. Fuller *
489664a7497SLandon J. Fuller * @param erom EROM read state.
490664a7497SLandon J. Fuller * @param entry Will contain the read result on success.
491664a7497SLandon J. Fuller * @retval 0 success
492664a7497SLandon J. Fuller * @retval ENOENT The end of the EROM table was reached.
493664a7497SLandon J. Fuller * @retval non-zero The read could not be completed.
494664a7497SLandon J. Fuller */
495664a7497SLandon J. Fuller static int
bcma_erom_read32(struct bcma_erom * erom,uint32_t * entry)496664a7497SLandon J. Fuller bcma_erom_read32(struct bcma_erom *erom, uint32_t *entry)
497664a7497SLandon J. Fuller {
498664a7497SLandon J. Fuller int error;
499664a7497SLandon J. Fuller
500664a7497SLandon J. Fuller if ((error = bcma_erom_peek32(erom, entry)) == 0)
501664a7497SLandon J. Fuller erom->offset += 4;
502664a7497SLandon J. Fuller
503664a7497SLandon J. Fuller return (error);
504664a7497SLandon J. Fuller }
505664a7497SLandon J. Fuller
506664a7497SLandon J. Fuller /**
507664a7497SLandon J. Fuller * Read and discard 32-bit entry value from the EROM table.
508664a7497SLandon J. Fuller *
509664a7497SLandon J. Fuller * @param erom EROM read state.
510664a7497SLandon J. Fuller * @retval 0 success
511664a7497SLandon J. Fuller * @retval ENOENT The end of the EROM table was reached.
512664a7497SLandon J. Fuller * @retval non-zero The read could not be completed.
513664a7497SLandon J. Fuller */
514664a7497SLandon J. Fuller static int
bcma_erom_skip32(struct bcma_erom * erom)515664a7497SLandon J. Fuller bcma_erom_skip32(struct bcma_erom *erom)
516664a7497SLandon J. Fuller {
517664a7497SLandon J. Fuller uint32_t entry;
518664a7497SLandon J. Fuller
519664a7497SLandon J. Fuller return bcma_erom_read32(erom, &entry);
520664a7497SLandon J. Fuller }
521664a7497SLandon J. Fuller
522664a7497SLandon J. Fuller /**
523664a7497SLandon J. Fuller * Read and discard a core descriptor from the EROM table.
524664a7497SLandon J. Fuller *
525664a7497SLandon J. Fuller * @param erom EROM read state.
526664a7497SLandon J. Fuller * @retval 0 success
527664a7497SLandon J. Fuller * @retval ENOENT The end of the EROM table was reached.
528664a7497SLandon J. Fuller * @retval non-zero The read could not be completed.
529664a7497SLandon J. Fuller */
530664a7497SLandon J. Fuller static int
bcma_erom_skip_core(struct bcma_erom * erom)531664a7497SLandon J. Fuller bcma_erom_skip_core(struct bcma_erom *erom)
532664a7497SLandon J. Fuller {
533664a7497SLandon J. Fuller struct bcma_erom_core core;
534664a7497SLandon J. Fuller return (bcma_erom_parse_core(erom, &core));
535664a7497SLandon J. Fuller }
536664a7497SLandon J. Fuller
537664a7497SLandon J. Fuller /**
538664a7497SLandon J. Fuller * Read and discard a master port descriptor from the EROM table.
539664a7497SLandon J. Fuller *
540664a7497SLandon J. Fuller * @param erom EROM read state.
541664a7497SLandon J. Fuller * @retval 0 success
542664a7497SLandon J. Fuller * @retval ENOENT The end of the EROM table was reached.
543664a7497SLandon J. Fuller * @retval non-zero The read could not be completed.
544664a7497SLandon J. Fuller */
545664a7497SLandon J. Fuller static int
bcma_erom_skip_mport(struct bcma_erom * erom)546664a7497SLandon J. Fuller bcma_erom_skip_mport(struct bcma_erom *erom)
547664a7497SLandon J. Fuller {
548664a7497SLandon J. Fuller struct bcma_erom_mport mp;
549664a7497SLandon J. Fuller return (bcma_erom_parse_mport(erom, &mp));
550664a7497SLandon J. Fuller }
551664a7497SLandon J. Fuller
552664a7497SLandon J. Fuller /**
553664a7497SLandon J. Fuller * Read and discard a port region descriptor from the EROM table.
554664a7497SLandon J. Fuller *
555664a7497SLandon J. Fuller * @param erom EROM read state.
556664a7497SLandon J. Fuller * @retval 0 success
557664a7497SLandon J. Fuller * @retval ENOENT The end of the EROM table was reached.
558664a7497SLandon J. Fuller * @retval non-zero The read could not be completed.
559664a7497SLandon J. Fuller */
560664a7497SLandon J. Fuller static int
bcma_erom_skip_sport_region(struct bcma_erom * erom)561664a7497SLandon J. Fuller bcma_erom_skip_sport_region(struct bcma_erom *erom)
562664a7497SLandon J. Fuller {
563664a7497SLandon J. Fuller struct bcma_erom_sport_region r;
564664a7497SLandon J. Fuller return (bcma_erom_parse_sport_region(erom, &r));
565664a7497SLandon J. Fuller }
566664a7497SLandon J. Fuller
567664a7497SLandon J. Fuller /**
568664a7497SLandon J. Fuller * Seek to the next entry matching the given EROM entry type.
569664a7497SLandon J. Fuller *
570664a7497SLandon J. Fuller * @param erom EROM read state.
571664a7497SLandon J. Fuller * @param etype One of BCMA_EROM_ENTRY_TYPE_CORE,
572664a7497SLandon J. Fuller * BCMA_EROM_ENTRY_TYPE_MPORT, or BCMA_EROM_ENTRY_TYPE_REGION.
573664a7497SLandon J. Fuller * @retval 0 success
574664a7497SLandon J. Fuller * @retval ENOENT The end of the EROM table was reached.
575664a7497SLandon J. Fuller * @retval non-zero Reading or parsing the descriptor failed.
576664a7497SLandon J. Fuller */
577664a7497SLandon J. Fuller static int
bcma_erom_seek_next(struct bcma_erom * erom,uint8_t etype)578664a7497SLandon J. Fuller bcma_erom_seek_next(struct bcma_erom *erom, uint8_t etype)
579664a7497SLandon J. Fuller {
580664a7497SLandon J. Fuller uint32_t entry;
581664a7497SLandon J. Fuller int error;
582664a7497SLandon J. Fuller
583664a7497SLandon J. Fuller /* Iterate until we hit an entry matching the requested type. */
584664a7497SLandon J. Fuller while (!(error = bcma_erom_peek32(erom, &entry))) {
585664a7497SLandon J. Fuller /* Handle EOF */
586664a7497SLandon J. Fuller if (entry == BCMA_EROM_TABLE_EOF)
587664a7497SLandon J. Fuller return (ENOENT);
588664a7497SLandon J. Fuller
589664a7497SLandon J. Fuller /* Invalid entry */
590664a7497SLandon J. Fuller if (!BCMA_EROM_GET_ATTR(entry, ENTRY_ISVALID))
591664a7497SLandon J. Fuller return (EINVAL);
592664a7497SLandon J. Fuller
593664a7497SLandon J. Fuller /* Entry type matches? */
594664a7497SLandon J. Fuller if (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE) == etype)
595664a7497SLandon J. Fuller return (0);
596664a7497SLandon J. Fuller
597664a7497SLandon J. Fuller /* Skip non-matching entry types. */
598664a7497SLandon J. Fuller switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) {
599664a7497SLandon J. Fuller case BCMA_EROM_ENTRY_TYPE_CORE:
600664a7497SLandon J. Fuller if ((error = bcma_erom_skip_core(erom)))
601664a7497SLandon J. Fuller return (error);
602664a7497SLandon J. Fuller
603664a7497SLandon J. Fuller break;
604664a7497SLandon J. Fuller
605664a7497SLandon J. Fuller case BCMA_EROM_ENTRY_TYPE_MPORT:
606664a7497SLandon J. Fuller if ((error = bcma_erom_skip_mport(erom)))
607664a7497SLandon J. Fuller return (error);
608664a7497SLandon J. Fuller
609664a7497SLandon J. Fuller break;
610664a7497SLandon J. Fuller
611664a7497SLandon J. Fuller case BCMA_EROM_ENTRY_TYPE_REGION:
612664a7497SLandon J. Fuller if ((error = bcma_erom_skip_sport_region(erom)))
613664a7497SLandon J. Fuller return (error);
614664a7497SLandon J. Fuller break;
615664a7497SLandon J. Fuller
616664a7497SLandon J. Fuller default:
617664a7497SLandon J. Fuller /* Unknown entry type! */
618664a7497SLandon J. Fuller return (EINVAL);
619664a7497SLandon J. Fuller }
620664a7497SLandon J. Fuller }
621664a7497SLandon J. Fuller
622664a7497SLandon J. Fuller return (error);
623664a7497SLandon J. Fuller }
624664a7497SLandon J. Fuller
625664a7497SLandon J. Fuller /**
626664a7497SLandon J. Fuller * Return the read position to the start of the EROM table.
627664a7497SLandon J. Fuller *
628664a7497SLandon J. Fuller * @param erom EROM read state.
629664a7497SLandon J. Fuller */
630664a7497SLandon J. Fuller static void
bcma_erom_reset(struct bcma_erom * erom)631664a7497SLandon J. Fuller bcma_erom_reset(struct bcma_erom *erom)
632664a7497SLandon J. Fuller {
633664a7497SLandon J. Fuller erom->offset = 0;
634664a7497SLandon J. Fuller }
635664a7497SLandon J. Fuller
636664a7497SLandon J. Fuller /**
637664a7497SLandon J. Fuller * Seek to the first core entry matching @p desc.
638664a7497SLandon J. Fuller *
639664a7497SLandon J. Fuller * @param erom EROM read state.
640664a7497SLandon J. Fuller * @param desc The core match descriptor.
641664a7497SLandon J. Fuller * @param[out] core On success, the matching core info. If the core info
642664a7497SLandon J. Fuller * is not desired, a NULL pointer may be provided.
643664a7497SLandon J. Fuller * @retval 0 success
644664a7497SLandon J. Fuller * @retval ENOENT The end of the EROM table was reached before @p index was
645664a7497SLandon J. Fuller * found.
646664a7497SLandon J. Fuller * @retval non-zero Reading or parsing failed.
647664a7497SLandon J. Fuller */
648664a7497SLandon J. Fuller static int
bcma_erom_seek_matching_core(struct bcma_erom * sc,const struct bhnd_core_match * desc,struct bhnd_core_info * core)649664a7497SLandon J. Fuller bcma_erom_seek_matching_core(struct bcma_erom *sc,
650664a7497SLandon J. Fuller const struct bhnd_core_match *desc, struct bhnd_core_info *core)
651664a7497SLandon J. Fuller {
652664a7497SLandon J. Fuller struct bhnd_core_match imatch;
653664a7497SLandon J. Fuller bus_size_t core_offset, next_offset;
654664a7497SLandon J. Fuller int error;
655664a7497SLandon J. Fuller
656664a7497SLandon J. Fuller /* Seek to table start. */
657664a7497SLandon J. Fuller bcma_erom_reset(sc);
658664a7497SLandon J. Fuller
659664a7497SLandon J. Fuller /* We can't determine a core's unit number during the initial scan. */
660664a7497SLandon J. Fuller imatch = *desc;
661664a7497SLandon J. Fuller imatch.m.match.core_unit = 0;
662664a7497SLandon J. Fuller
663664a7497SLandon J. Fuller /* Locate the first matching core */
664664a7497SLandon J. Fuller for (u_int i = 0; i < UINT_MAX; i++) {
665664a7497SLandon J. Fuller struct bcma_erom_core ec;
666664a7497SLandon J. Fuller struct bhnd_core_info ci;
667664a7497SLandon J. Fuller
668664a7497SLandon J. Fuller /* Seek to the next core */
669664a7497SLandon J. Fuller error = bcma_erom_seek_next(sc, BCMA_EROM_ENTRY_TYPE_CORE);
670664a7497SLandon J. Fuller if (error)
671664a7497SLandon J. Fuller return (error);
672664a7497SLandon J. Fuller
673664a7497SLandon J. Fuller /* Save the core offset */
674664a7497SLandon J. Fuller core_offset = bcma_erom_tell(sc);
675664a7497SLandon J. Fuller
676664a7497SLandon J. Fuller /* Parse the core */
677664a7497SLandon J. Fuller if ((error = bcma_erom_parse_core(sc, &ec)))
678664a7497SLandon J. Fuller return (error);
679664a7497SLandon J. Fuller
680664a7497SLandon J. Fuller bcma_erom_to_core_info(&ec, i, 0, &ci);
681664a7497SLandon J. Fuller
682664a7497SLandon J. Fuller /* Check for initial match */
683664a7497SLandon J. Fuller if (!bhnd_core_matches(&ci, &imatch))
684664a7497SLandon J. Fuller continue;
685664a7497SLandon J. Fuller
686664a7497SLandon J. Fuller /* Re-scan preceding cores to determine the unit number. */
687664a7497SLandon J. Fuller next_offset = bcma_erom_tell(sc);
688664a7497SLandon J. Fuller bcma_erom_reset(sc);
689664a7497SLandon J. Fuller for (u_int j = 0; j < i; j++) {
690664a7497SLandon J. Fuller /* Parse the core */
691664a7497SLandon J. Fuller error = bcma_erom_seek_next(sc,
692664a7497SLandon J. Fuller BCMA_EROM_ENTRY_TYPE_CORE);
693664a7497SLandon J. Fuller if (error)
694664a7497SLandon J. Fuller return (error);
695664a7497SLandon J. Fuller
696664a7497SLandon J. Fuller if ((error = bcma_erom_parse_core(sc, &ec)))
697664a7497SLandon J. Fuller return (error);
698664a7497SLandon J. Fuller
699664a7497SLandon J. Fuller /* Bump the unit number? */
700664a7497SLandon J. Fuller if (ec.vendor == ci.vendor && ec.device == ci.device)
701664a7497SLandon J. Fuller ci.unit++;
702664a7497SLandon J. Fuller }
703664a7497SLandon J. Fuller
704664a7497SLandon J. Fuller /* Check for full match against now-valid unit number */
705664a7497SLandon J. Fuller if (!bhnd_core_matches(&ci, desc)) {
706664a7497SLandon J. Fuller /* Reposition to allow reading the next core */
707664a7497SLandon J. Fuller bcma_erom_seek(sc, next_offset);
708664a7497SLandon J. Fuller continue;
709664a7497SLandon J. Fuller }
710664a7497SLandon J. Fuller
711664a7497SLandon J. Fuller /* Found; seek to the core's initial offset and provide
712664a7497SLandon J. Fuller * the core info to the caller */
713664a7497SLandon J. Fuller bcma_erom_seek(sc, core_offset);
714664a7497SLandon J. Fuller if (core != NULL)
715664a7497SLandon J. Fuller *core = ci;
716664a7497SLandon J. Fuller
717664a7497SLandon J. Fuller return (0);
718664a7497SLandon J. Fuller }
719664a7497SLandon J. Fuller
72088cdf609SGordon Bergling /* Not found, or a parse error occurred */
721664a7497SLandon J. Fuller return (error);
722664a7497SLandon J. Fuller }
723664a7497SLandon J. Fuller
724664a7497SLandon J. Fuller /**
725664a7497SLandon J. Fuller * Read the next core descriptor from the EROM table.
726664a7497SLandon J. Fuller *
727664a7497SLandon J. Fuller * @param erom EROM read state.
728664a7497SLandon J. Fuller * @param[out] core On success, will be populated with the parsed core
729664a7497SLandon J. Fuller * descriptor data.
730664a7497SLandon J. Fuller * @retval 0 success
731664a7497SLandon J. Fuller * @retval ENOENT The end of the EROM table was reached.
732664a7497SLandon J. Fuller * @retval non-zero Reading or parsing the core descriptor failed.
733664a7497SLandon J. Fuller */
734664a7497SLandon J. Fuller static int
bcma_erom_parse_core(struct bcma_erom * erom,struct bcma_erom_core * core)735664a7497SLandon J. Fuller bcma_erom_parse_core(struct bcma_erom *erom, struct bcma_erom_core *core)
736664a7497SLandon J. Fuller {
737664a7497SLandon J. Fuller uint32_t entry;
738664a7497SLandon J. Fuller int error;
739664a7497SLandon J. Fuller
740664a7497SLandon J. Fuller /* Parse CoreDescA */
741664a7497SLandon J. Fuller if ((error = bcma_erom_read32(erom, &entry)))
742664a7497SLandon J. Fuller return (error);
743664a7497SLandon J. Fuller
744664a7497SLandon J. Fuller /* Handle EOF */
745664a7497SLandon J. Fuller if (entry == BCMA_EROM_TABLE_EOF)
746664a7497SLandon J. Fuller return (ENOENT);
747664a7497SLandon J. Fuller
748664a7497SLandon J. Fuller if (!BCMA_EROM_ENTRY_IS(entry, CORE)) {
749664a7497SLandon J. Fuller EROM_LOG(erom, "Unexpected EROM entry 0x%x (type=%s)\n",
750664a7497SLandon J. Fuller entry, bcma_erom_entry_type_name(entry));
751664a7497SLandon J. Fuller
752664a7497SLandon J. Fuller return (EINVAL);
753664a7497SLandon J. Fuller }
754664a7497SLandon J. Fuller
755664a7497SLandon J. Fuller core->vendor = BCMA_EROM_GET_ATTR(entry, COREA_DESIGNER);
756664a7497SLandon J. Fuller core->device = BCMA_EROM_GET_ATTR(entry, COREA_ID);
757664a7497SLandon J. Fuller
758664a7497SLandon J. Fuller /* Parse CoreDescB */
759664a7497SLandon J. Fuller if ((error = bcma_erom_read32(erom, &entry)))
760664a7497SLandon J. Fuller return (error);
761664a7497SLandon J. Fuller
762664a7497SLandon J. Fuller if (!BCMA_EROM_ENTRY_IS(entry, CORE)) {
763664a7497SLandon J. Fuller return (EINVAL);
764664a7497SLandon J. Fuller }
765664a7497SLandon J. Fuller
766664a7497SLandon J. Fuller core->rev = BCMA_EROM_GET_ATTR(entry, COREB_REV);
767664a7497SLandon J. Fuller core->num_mport = BCMA_EROM_GET_ATTR(entry, COREB_NUM_MP);
768664a7497SLandon J. Fuller core->num_dport = BCMA_EROM_GET_ATTR(entry, COREB_NUM_DP);
769664a7497SLandon J. Fuller core->num_mwrap = BCMA_EROM_GET_ATTR(entry, COREB_NUM_WMP);
770664a7497SLandon J. Fuller core->num_swrap = BCMA_EROM_GET_ATTR(entry, COREB_NUM_WSP);
771664a7497SLandon J. Fuller
772664a7497SLandon J. Fuller return (0);
773664a7497SLandon J. Fuller }
774664a7497SLandon J. Fuller
775664a7497SLandon J. Fuller /**
776664a7497SLandon J. Fuller * Read the next master port descriptor from the EROM table.
777664a7497SLandon J. Fuller *
778664a7497SLandon J. Fuller * @param erom EROM read state.
779664a7497SLandon J. Fuller * @param[out] mport On success, will be populated with the parsed
780664a7497SLandon J. Fuller * descriptor data.
781664a7497SLandon J. Fuller * @retval 0 success
782664a7497SLandon J. Fuller * @retval non-zero Reading or parsing the descriptor failed.
783664a7497SLandon J. Fuller */
784664a7497SLandon J. Fuller static int
bcma_erom_parse_mport(struct bcma_erom * erom,struct bcma_erom_mport * mport)785664a7497SLandon J. Fuller bcma_erom_parse_mport(struct bcma_erom *erom, struct bcma_erom_mport *mport)
786664a7497SLandon J. Fuller {
787664a7497SLandon J. Fuller uint32_t entry;
788664a7497SLandon J. Fuller int error;
789664a7497SLandon J. Fuller
790664a7497SLandon J. Fuller /* Parse the master port descriptor */
791664a7497SLandon J. Fuller if ((error = bcma_erom_read32(erom, &entry)))
792664a7497SLandon J. Fuller return (error);
793664a7497SLandon J. Fuller
794664a7497SLandon J. Fuller if (!BCMA_EROM_ENTRY_IS(entry, MPORT))
795664a7497SLandon J. Fuller return (EINVAL);
796664a7497SLandon J. Fuller
797664a7497SLandon J. Fuller mport->port_vid = BCMA_EROM_GET_ATTR(entry, MPORT_ID);
798664a7497SLandon J. Fuller mport->port_num = BCMA_EROM_GET_ATTR(entry, MPORT_NUM);
799664a7497SLandon J. Fuller
800664a7497SLandon J. Fuller return (0);
801664a7497SLandon J. Fuller }
802664a7497SLandon J. Fuller
803664a7497SLandon J. Fuller /**
804664a7497SLandon J. Fuller * Read the next slave port region descriptor from the EROM table.
805664a7497SLandon J. Fuller *
806664a7497SLandon J. Fuller * @param erom EROM read state.
807664a7497SLandon J. Fuller * @param[out] mport On success, will be populated with the parsed
808664a7497SLandon J. Fuller * descriptor data.
809664a7497SLandon J. Fuller * @retval 0 success
810664a7497SLandon J. Fuller * @retval ENOENT The end of the region descriptor table was reached.
811664a7497SLandon J. Fuller * @retval non-zero Reading or parsing the descriptor failed.
812664a7497SLandon J. Fuller */
813664a7497SLandon J. Fuller static int
bcma_erom_parse_sport_region(struct bcma_erom * erom,struct bcma_erom_sport_region * region)814664a7497SLandon J. Fuller bcma_erom_parse_sport_region(struct bcma_erom *erom,
815664a7497SLandon J. Fuller struct bcma_erom_sport_region *region)
816664a7497SLandon J. Fuller {
817664a7497SLandon J. Fuller uint32_t entry;
818664a7497SLandon J. Fuller uint8_t size_type;
819664a7497SLandon J. Fuller int error;
820664a7497SLandon J. Fuller
821664a7497SLandon J. Fuller /* Peek at the region descriptor */
822664a7497SLandon J. Fuller if (bcma_erom_peek32(erom, &entry))
823664a7497SLandon J. Fuller return (EINVAL);
824664a7497SLandon J. Fuller
825664a7497SLandon J. Fuller /* A non-region entry signals the end of the region table */
826664a7497SLandon J. Fuller if (!BCMA_EROM_ENTRY_IS(entry, REGION)) {
827664a7497SLandon J. Fuller return (ENOENT);
828664a7497SLandon J. Fuller } else {
829664a7497SLandon J. Fuller bcma_erom_skip32(erom);
830664a7497SLandon J. Fuller }
831664a7497SLandon J. Fuller
832664a7497SLandon J. Fuller region->base_addr = BCMA_EROM_GET_ATTR(entry, REGION_BASE);
833664a7497SLandon J. Fuller region->region_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
834664a7497SLandon J. Fuller region->region_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
835664a7497SLandon J. Fuller size_type = BCMA_EROM_GET_ATTR(entry, REGION_SIZE);
836664a7497SLandon J. Fuller
837664a7497SLandon J. Fuller /* If region address is 64-bit, fetch the high bits. */
838664a7497SLandon J. Fuller if (BCMA_EROM_GET_ATTR(entry, REGION_64BIT)) {
839664a7497SLandon J. Fuller if ((error = bcma_erom_read32(erom, &entry)))
840664a7497SLandon J. Fuller return (error);
841664a7497SLandon J. Fuller
842664a7497SLandon J. Fuller region->base_addr |= ((bhnd_addr_t) entry << 32);
843664a7497SLandon J. Fuller }
844664a7497SLandon J. Fuller
845664a7497SLandon J. Fuller /* Parse the region size; it's either encoded as the binary logarithm
846664a7497SLandon J. Fuller * of the number of 4K pages (i.e. log2 n), or its encoded as a
847664a7497SLandon J. Fuller * 32-bit/64-bit literal value directly following the current entry. */
848664a7497SLandon J. Fuller if (size_type == BCMA_EROM_REGION_SIZE_OTHER) {
849664a7497SLandon J. Fuller if ((error = bcma_erom_read32(erom, &entry)))
850664a7497SLandon J. Fuller return (error);
851664a7497SLandon J. Fuller
852664a7497SLandon J. Fuller region->size = BCMA_EROM_GET_ATTR(entry, RSIZE_VAL);
853664a7497SLandon J. Fuller
854664a7497SLandon J. Fuller if (BCMA_EROM_GET_ATTR(entry, RSIZE_64BIT)) {
855664a7497SLandon J. Fuller if ((error = bcma_erom_read32(erom, &entry)))
856664a7497SLandon J. Fuller return (error);
857664a7497SLandon J. Fuller region->size |= ((bhnd_size_t) entry << 32);
858664a7497SLandon J. Fuller }
859664a7497SLandon J. Fuller } else {
860664a7497SLandon J. Fuller region->size = BCMA_EROM_REGION_SIZE_BASE << size_type;
861664a7497SLandon J. Fuller }
862664a7497SLandon J. Fuller
863664a7497SLandon J. Fuller /* Verify that addr+size does not overflow. */
864664a7497SLandon J. Fuller if (region->size != 0 &&
865664a7497SLandon J. Fuller BHND_ADDR_MAX - (region->size - 1) < region->base_addr)
866664a7497SLandon J. Fuller {
867664a7497SLandon J. Fuller EROM_LOG(erom, "%s%u: invalid address map %llx:%llx\n",
868664a7497SLandon J. Fuller bcma_erom_entry_type_name(region->region_type),
869664a7497SLandon J. Fuller region->region_port,
870664a7497SLandon J. Fuller (unsigned long long) region->base_addr,
871664a7497SLandon J. Fuller (unsigned long long) region->size);
872664a7497SLandon J. Fuller
873664a7497SLandon J. Fuller return (EINVAL);
874664a7497SLandon J. Fuller }
875664a7497SLandon J. Fuller
876664a7497SLandon J. Fuller return (0);
877664a7497SLandon J. Fuller }
878664a7497SLandon J. Fuller
879664a7497SLandon J. Fuller /**
880664a7497SLandon J. Fuller * Convert a bcma_erom_core record to its bhnd_core_info representation.
881664a7497SLandon J. Fuller *
882664a7497SLandon J. Fuller * @param core EROM core record to convert.
883664a7497SLandon J. Fuller * @param core_idx The core index of @p core.
884664a7497SLandon J. Fuller * @param core_unit The core unit of @p core.
885664a7497SLandon J. Fuller * @param[out] info The populated bhnd_core_info representation.
886664a7497SLandon J. Fuller */
887664a7497SLandon J. Fuller static void
bcma_erom_to_core_info(const struct bcma_erom_core * core,u_int core_idx,int core_unit,struct bhnd_core_info * info)888664a7497SLandon J. Fuller bcma_erom_to_core_info(const struct bcma_erom_core *core, u_int core_idx,
889664a7497SLandon J. Fuller int core_unit, struct bhnd_core_info *info)
890664a7497SLandon J. Fuller {
891664a7497SLandon J. Fuller info->vendor = core->vendor;
892664a7497SLandon J. Fuller info->device = core->device;
893664a7497SLandon J. Fuller info->hwrev = core->rev;
894664a7497SLandon J. Fuller info->core_idx = core_idx;
895664a7497SLandon J. Fuller info->unit = core_unit;
896664a7497SLandon J. Fuller }
897664a7497SLandon J. Fuller
898cb4abe62SLandon J. Fuller /**
899cb4abe62SLandon J. Fuller * Map an EROM region type to its corresponding port type.
900cb4abe62SLandon J. Fuller *
901cb4abe62SLandon J. Fuller * @param region_type Region type value.
902cb4abe62SLandon J. Fuller * @param[out] port_type On success, the corresponding port type.
903cb4abe62SLandon J. Fuller */
904cb4abe62SLandon J. Fuller static int
bcma_erom_region_to_port_type(struct bcma_erom * erom,uint8_t region_type,bhnd_port_type * port_type)905664a7497SLandon J. Fuller bcma_erom_region_to_port_type(struct bcma_erom *erom, uint8_t region_type,
906cb4abe62SLandon J. Fuller bhnd_port_type *port_type)
907cb4abe62SLandon J. Fuller {
908cb4abe62SLandon J. Fuller switch (region_type) {
909cb4abe62SLandon J. Fuller case BCMA_EROM_REGION_TYPE_DEVICE:
910cb4abe62SLandon J. Fuller *port_type = BHND_PORT_DEVICE;
911cb4abe62SLandon J. Fuller return (0);
912cb4abe62SLandon J. Fuller case BCMA_EROM_REGION_TYPE_BRIDGE:
913cb4abe62SLandon J. Fuller *port_type = BHND_PORT_BRIDGE;
914cb4abe62SLandon J. Fuller return (0);
915cb4abe62SLandon J. Fuller case BCMA_EROM_REGION_TYPE_MWRAP:
916cb4abe62SLandon J. Fuller case BCMA_EROM_REGION_TYPE_SWRAP:
917cb4abe62SLandon J. Fuller *port_type = BHND_PORT_AGENT;
918cb4abe62SLandon J. Fuller return (0);
919cb4abe62SLandon J. Fuller default:
920cb4abe62SLandon J. Fuller EROM_LOG(erom, "unsupported region type %hhx\n",
921cb4abe62SLandon J. Fuller region_type);
922cb4abe62SLandon J. Fuller return (EINVAL);
923cb4abe62SLandon J. Fuller }
924cb4abe62SLandon J. Fuller }
9254ad7e9b0SAdrian Chadd
9264ad7e9b0SAdrian Chadd /**
9274ad7e9b0SAdrian Chadd * Register all MMIO region descriptors for the given slave port.
9284ad7e9b0SAdrian Chadd *
9294ad7e9b0SAdrian Chadd * @param erom EROM read state.
9304ad7e9b0SAdrian Chadd * @param corecfg Core info to be populated with the scanned port regions.
9314ad7e9b0SAdrian Chadd * @param port_num Port index for which regions will be parsed.
9324ad7e9b0SAdrian Chadd * @param region_type The region type to be parsed.
9334ad7e9b0SAdrian Chadd * @param[out] offset The offset at which to perform parsing. On success, this
9344ad7e9b0SAdrian Chadd * will be updated to point to the next EROM table entry.
9354ad7e9b0SAdrian Chadd */
9364ad7e9b0SAdrian Chadd static int
bcma_erom_corecfg_fill_port_regions(struct bcma_erom * erom,struct bcma_corecfg * corecfg,bcma_pid_t port_num,uint8_t region_type)937664a7497SLandon J. Fuller bcma_erom_corecfg_fill_port_regions(struct bcma_erom *erom,
9384ad7e9b0SAdrian Chadd struct bcma_corecfg *corecfg, bcma_pid_t port_num,
9394ad7e9b0SAdrian Chadd uint8_t region_type)
9404ad7e9b0SAdrian Chadd {
9414ad7e9b0SAdrian Chadd struct bcma_sport *sport;
9424ad7e9b0SAdrian Chadd struct bcma_sport_list *sports;
9434ad7e9b0SAdrian Chadd bus_size_t entry_offset;
9444ad7e9b0SAdrian Chadd int error;
9454ad7e9b0SAdrian Chadd bhnd_port_type port_type;
9464ad7e9b0SAdrian Chadd
9474ad7e9b0SAdrian Chadd error = 0;
9484ad7e9b0SAdrian Chadd
9494ad7e9b0SAdrian Chadd /* Determine the port type for this region type. */
950664a7497SLandon J. Fuller error = bcma_erom_region_to_port_type(erom, region_type, &port_type);
951664a7497SLandon J. Fuller if (error)
952cb4abe62SLandon J. Fuller return (error);
9534ad7e9b0SAdrian Chadd
9544ad7e9b0SAdrian Chadd /* Fetch the list to be populated */
9554ad7e9b0SAdrian Chadd sports = bcma_corecfg_get_port_list(corecfg, port_type);
9564ad7e9b0SAdrian Chadd
9574ad7e9b0SAdrian Chadd /* Allocate a new port descriptor */
9584ad7e9b0SAdrian Chadd sport = bcma_alloc_sport(port_num, port_type);
9594ad7e9b0SAdrian Chadd if (sport == NULL)
9604ad7e9b0SAdrian Chadd return (ENOMEM);
9614ad7e9b0SAdrian Chadd
9624ad7e9b0SAdrian Chadd /* Read all address regions defined for this port */
9634ad7e9b0SAdrian Chadd for (bcma_rmid_t region_num = 0;; region_num++) {
9644ad7e9b0SAdrian Chadd struct bcma_map *map;
9654ad7e9b0SAdrian Chadd struct bcma_erom_sport_region spr;
9664ad7e9b0SAdrian Chadd
9674ad7e9b0SAdrian Chadd /* No valid port definition should come anywhere near
9684ad7e9b0SAdrian Chadd * BCMA_RMID_MAX. */
9694ad7e9b0SAdrian Chadd if (region_num == BCMA_RMID_MAX) {
9704ad7e9b0SAdrian Chadd EROM_LOG(erom, "core%u %s%u: region count reached "
9714ad7e9b0SAdrian Chadd "upper limit of %u\n",
9724ad7e9b0SAdrian Chadd corecfg->core_info.core_idx,
9734ad7e9b0SAdrian Chadd bhnd_port_type_name(port_type),
9744ad7e9b0SAdrian Chadd port_num, BCMA_RMID_MAX);
9754ad7e9b0SAdrian Chadd
9764ad7e9b0SAdrian Chadd error = EINVAL;
9774ad7e9b0SAdrian Chadd goto cleanup;
9784ad7e9b0SAdrian Chadd }
9794ad7e9b0SAdrian Chadd
9804ad7e9b0SAdrian Chadd /* Parse the next region entry. */
9814ad7e9b0SAdrian Chadd entry_offset = bcma_erom_tell(erom);
9824ad7e9b0SAdrian Chadd error = bcma_erom_parse_sport_region(erom, &spr);
9834ad7e9b0SAdrian Chadd if (error && error != ENOENT) {
9844ad7e9b0SAdrian Chadd EROM_LOG(erom, "core%u %s%u.%u: invalid slave port "
9854ad7e9b0SAdrian Chadd "address region\n",
9864ad7e9b0SAdrian Chadd corecfg->core_info.core_idx,
9874ad7e9b0SAdrian Chadd bhnd_port_type_name(port_type),
9884ad7e9b0SAdrian Chadd port_num, region_num);
9894ad7e9b0SAdrian Chadd goto cleanup;
9904ad7e9b0SAdrian Chadd }
9914ad7e9b0SAdrian Chadd
9924ad7e9b0SAdrian Chadd /* ENOENT signals no further region entries */
9934ad7e9b0SAdrian Chadd if (error == ENOENT) {
9944ad7e9b0SAdrian Chadd /* No further entries */
9954ad7e9b0SAdrian Chadd error = 0;
9964ad7e9b0SAdrian Chadd break;
9974ad7e9b0SAdrian Chadd }
9984ad7e9b0SAdrian Chadd
9994ad7e9b0SAdrian Chadd /* A region or type mismatch also signals no further region
10004ad7e9b0SAdrian Chadd * entries */
10014ad7e9b0SAdrian Chadd if (spr.region_port != port_num ||
10024ad7e9b0SAdrian Chadd spr.region_type != region_type)
10034ad7e9b0SAdrian Chadd {
10044ad7e9b0SAdrian Chadd /* We don't want to consume this entry */
10054ad7e9b0SAdrian Chadd bcma_erom_seek(erom, entry_offset);
10064ad7e9b0SAdrian Chadd
10074ad7e9b0SAdrian Chadd error = 0;
10084ad7e9b0SAdrian Chadd goto cleanup;
10094ad7e9b0SAdrian Chadd }
10104ad7e9b0SAdrian Chadd
10114ad7e9b0SAdrian Chadd /*
10124ad7e9b0SAdrian Chadd * Create the map entry.
10134ad7e9b0SAdrian Chadd */
10144ad7e9b0SAdrian Chadd map = malloc(sizeof(struct bcma_map), M_BHND, M_NOWAIT);
10154ad7e9b0SAdrian Chadd if (map == NULL) {
10164ad7e9b0SAdrian Chadd error = ENOMEM;
10174ad7e9b0SAdrian Chadd goto cleanup;
10184ad7e9b0SAdrian Chadd }
10194ad7e9b0SAdrian Chadd
10204ad7e9b0SAdrian Chadd map->m_region_num = region_num;
10214ad7e9b0SAdrian Chadd map->m_base = spr.base_addr;
10224ad7e9b0SAdrian Chadd map->m_size = spr.size;
10234ad7e9b0SAdrian Chadd map->m_rid = -1;
10244ad7e9b0SAdrian Chadd
10254ad7e9b0SAdrian Chadd /* Add the region map to the port */
10264ad7e9b0SAdrian Chadd STAILQ_INSERT_TAIL(&sport->sp_maps, map, m_link);
10274ad7e9b0SAdrian Chadd sport->sp_num_maps++;
10284ad7e9b0SAdrian Chadd }
10294ad7e9b0SAdrian Chadd
10304ad7e9b0SAdrian Chadd cleanup:
10314ad7e9b0SAdrian Chadd /* Append the new port descriptor on success, or deallocate the
10324ad7e9b0SAdrian Chadd * partially parsed descriptor on failure. */
10334ad7e9b0SAdrian Chadd if (error == 0) {
10344ad7e9b0SAdrian Chadd STAILQ_INSERT_TAIL(sports, sport, sp_link);
10354ad7e9b0SAdrian Chadd } else if (sport != NULL) {
10364ad7e9b0SAdrian Chadd bcma_free_sport(sport);
10374ad7e9b0SAdrian Chadd }
10384ad7e9b0SAdrian Chadd
10394ad7e9b0SAdrian Chadd return error;
10404ad7e9b0SAdrian Chadd }
10414ad7e9b0SAdrian Chadd
10424ad7e9b0SAdrian Chadd /**
10434ad7e9b0SAdrian Chadd * Parse the next core entry from the EROM table and produce a bcma_corecfg
10444ad7e9b0SAdrian Chadd * to be owned by the caller.
10454ad7e9b0SAdrian Chadd *
1046664a7497SLandon J. Fuller * @param erom A bcma EROM instance.
10474ad7e9b0SAdrian Chadd * @param[out] result On success, the core's device info. The caller inherits
10484ad7e9b0SAdrian Chadd * ownership of this allocation.
10494ad7e9b0SAdrian Chadd *
10504ad7e9b0SAdrian Chadd * @return If successful, returns 0. If the end of the EROM table is hit,
10514ad7e9b0SAdrian Chadd * ENOENT will be returned. On error, returns a non-zero error value.
10524ad7e9b0SAdrian Chadd */
10534ad7e9b0SAdrian Chadd int
bcma_erom_next_corecfg(struct bcma_erom * erom,struct bcma_corecfg ** result)1054664a7497SLandon J. Fuller bcma_erom_next_corecfg(struct bcma_erom *erom, struct bcma_corecfg **result)
10554ad7e9b0SAdrian Chadd {
10564ad7e9b0SAdrian Chadd struct bcma_corecfg *cfg;
10574ad7e9b0SAdrian Chadd struct bcma_erom_core core;
10584ad7e9b0SAdrian Chadd uint8_t first_region_type;
10594ad7e9b0SAdrian Chadd bus_size_t initial_offset;
10604ad7e9b0SAdrian Chadd u_int core_index;
10614ad7e9b0SAdrian Chadd int core_unit;
10624ad7e9b0SAdrian Chadd int error;
10634ad7e9b0SAdrian Chadd
10644ad7e9b0SAdrian Chadd cfg = NULL;
10654ad7e9b0SAdrian Chadd initial_offset = bcma_erom_tell(erom);
10664ad7e9b0SAdrian Chadd
10674ad7e9b0SAdrian Chadd /* Parse the next core entry */
10684ad7e9b0SAdrian Chadd if ((error = bcma_erom_parse_core(erom, &core)))
10694ad7e9b0SAdrian Chadd return (error);
10704ad7e9b0SAdrian Chadd
10714ad7e9b0SAdrian Chadd /* Determine the core's index and unit numbers */
10724ad7e9b0SAdrian Chadd bcma_erom_reset(erom);
10734ad7e9b0SAdrian Chadd core_unit = 0;
10744ad7e9b0SAdrian Chadd core_index = 0;
10754ad7e9b0SAdrian Chadd for (; bcma_erom_tell(erom) != initial_offset; core_index++) {
10764ad7e9b0SAdrian Chadd struct bcma_erom_core prev_core;
10774ad7e9b0SAdrian Chadd
10784ad7e9b0SAdrian Chadd /* Parse next core */
1079664a7497SLandon J. Fuller error = bcma_erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE);
1080664a7497SLandon J. Fuller if (error)
10814ad7e9b0SAdrian Chadd return (error);
10824ad7e9b0SAdrian Chadd
10834ad7e9b0SAdrian Chadd if ((error = bcma_erom_parse_core(erom, &prev_core)))
10844ad7e9b0SAdrian Chadd return (error);
10854ad7e9b0SAdrian Chadd
10864ad7e9b0SAdrian Chadd /* Is earlier unit? */
10874ad7e9b0SAdrian Chadd if (core.vendor == prev_core.vendor &&
10884ad7e9b0SAdrian Chadd core.device == prev_core.device)
10894ad7e9b0SAdrian Chadd {
10904ad7e9b0SAdrian Chadd core_unit++;
10914ad7e9b0SAdrian Chadd }
10924ad7e9b0SAdrian Chadd
10934ad7e9b0SAdrian Chadd /* Seek to next core */
1094664a7497SLandon J. Fuller error = bcma_erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE);
1095664a7497SLandon J. Fuller if (error)
10964ad7e9b0SAdrian Chadd return (error);
10974ad7e9b0SAdrian Chadd }
10984ad7e9b0SAdrian Chadd
10994ad7e9b0SAdrian Chadd /* We already parsed the core descriptor */
1100664a7497SLandon J. Fuller if ((error = bcma_erom_skip_core(erom)))
11014ad7e9b0SAdrian Chadd return (error);
11024ad7e9b0SAdrian Chadd
11034ad7e9b0SAdrian Chadd /* Allocate our corecfg */
11044ad7e9b0SAdrian Chadd cfg = bcma_alloc_corecfg(core_index, core_unit, core.vendor,
11054ad7e9b0SAdrian Chadd core.device, core.rev);
11064ad7e9b0SAdrian Chadd if (cfg == NULL)
11074ad7e9b0SAdrian Chadd return (ENOMEM);
11084ad7e9b0SAdrian Chadd
11094ad7e9b0SAdrian Chadd /* These are 5-bit values in the EROM table, and should never be able
11104ad7e9b0SAdrian Chadd * to overflow BCMA_PID_MAX. */
11114ad7e9b0SAdrian Chadd KASSERT(core.num_mport <= BCMA_PID_MAX, ("unsupported mport count"));
11124ad7e9b0SAdrian Chadd KASSERT(core.num_dport <= BCMA_PID_MAX, ("unsupported dport count"));
11134ad7e9b0SAdrian Chadd KASSERT(core.num_mwrap + core.num_swrap <= BCMA_PID_MAX,
11144ad7e9b0SAdrian Chadd ("unsupported wport count"));
11154ad7e9b0SAdrian Chadd
11164ad7e9b0SAdrian Chadd if (bootverbose) {
11174ad7e9b0SAdrian Chadd EROM_LOG(erom,
11184ad7e9b0SAdrian Chadd "core%u: %s %s (cid=%hx, rev=%hu, unit=%d)\n",
11194ad7e9b0SAdrian Chadd core_index,
11204ad7e9b0SAdrian Chadd bhnd_vendor_name(core.vendor),
11214ad7e9b0SAdrian Chadd bhnd_find_core_name(core.vendor, core.device),
11224ad7e9b0SAdrian Chadd core.device, core.rev, core_unit);
11234ad7e9b0SAdrian Chadd }
11244ad7e9b0SAdrian Chadd
11254ad7e9b0SAdrian Chadd cfg->num_master_ports = core.num_mport;
11264ad7e9b0SAdrian Chadd cfg->num_dev_ports = 0; /* determined below */
11274ad7e9b0SAdrian Chadd cfg->num_bridge_ports = 0; /* determined blow */
11284ad7e9b0SAdrian Chadd cfg->num_wrapper_ports = core.num_mwrap + core.num_swrap;
11294ad7e9b0SAdrian Chadd
11304ad7e9b0SAdrian Chadd /* Parse Master Port Descriptors */
11314ad7e9b0SAdrian Chadd for (uint8_t i = 0; i < core.num_mport; i++) {
11324ad7e9b0SAdrian Chadd struct bcma_mport *mport;
11334ad7e9b0SAdrian Chadd struct bcma_erom_mport mpd;
11344ad7e9b0SAdrian Chadd
11354ad7e9b0SAdrian Chadd /* Parse the master port descriptor */
11364ad7e9b0SAdrian Chadd error = bcma_erom_parse_mport(erom, &mpd);
11374ad7e9b0SAdrian Chadd if (error)
11384ad7e9b0SAdrian Chadd goto failed;
11394ad7e9b0SAdrian Chadd
11404ad7e9b0SAdrian Chadd /* Initialize a new bus mport structure */
11414ad7e9b0SAdrian Chadd mport = malloc(sizeof(struct bcma_mport), M_BHND, M_NOWAIT);
11424ad7e9b0SAdrian Chadd if (mport == NULL) {
11434ad7e9b0SAdrian Chadd error = ENOMEM;
11444ad7e9b0SAdrian Chadd goto failed;
11454ad7e9b0SAdrian Chadd }
11464ad7e9b0SAdrian Chadd
11474ad7e9b0SAdrian Chadd mport->mp_vid = mpd.port_vid;
11484ad7e9b0SAdrian Chadd mport->mp_num = mpd.port_num;
11494ad7e9b0SAdrian Chadd
11504ad7e9b0SAdrian Chadd /* Update dinfo */
11514ad7e9b0SAdrian Chadd STAILQ_INSERT_TAIL(&cfg->master_ports, mport, mp_link);
11524ad7e9b0SAdrian Chadd }
11534ad7e9b0SAdrian Chadd
11544ad7e9b0SAdrian Chadd /*
11554ad7e9b0SAdrian Chadd * Determine whether this is a bridge device; if so, we can
11564ad7e9b0SAdrian Chadd * expect the first sequence of address region descriptors to
11574ad7e9b0SAdrian Chadd * be of EROM_REGION_TYPE_BRIDGE instead of
11584ad7e9b0SAdrian Chadd * BCMA_EROM_REGION_TYPE_DEVICE.
11594ad7e9b0SAdrian Chadd *
11604ad7e9b0SAdrian Chadd * It's unclear whether this is the correct mechanism by which we
11614ad7e9b0SAdrian Chadd * should detect/handle bridge devices, but this approach matches
11624ad7e9b0SAdrian Chadd * that of (some of) Broadcom's published drivers.
11634ad7e9b0SAdrian Chadd */
11644ad7e9b0SAdrian Chadd if (core.num_dport > 0) {
11654ad7e9b0SAdrian Chadd uint32_t entry;
11664ad7e9b0SAdrian Chadd
11674ad7e9b0SAdrian Chadd if ((error = bcma_erom_peek32(erom, &entry)))
11684ad7e9b0SAdrian Chadd goto failed;
11694ad7e9b0SAdrian Chadd
11704ad7e9b0SAdrian Chadd if (BCMA_EROM_ENTRY_IS(entry, REGION) &&
11714ad7e9b0SAdrian Chadd BCMA_EROM_GET_ATTR(entry, REGION_TYPE) == BCMA_EROM_REGION_TYPE_BRIDGE)
11724ad7e9b0SAdrian Chadd {
11734ad7e9b0SAdrian Chadd first_region_type = BCMA_EROM_REGION_TYPE_BRIDGE;
11744ad7e9b0SAdrian Chadd cfg->num_dev_ports = 0;
11754ad7e9b0SAdrian Chadd cfg->num_bridge_ports = core.num_dport;
11764ad7e9b0SAdrian Chadd } else {
11774ad7e9b0SAdrian Chadd first_region_type = BCMA_EROM_REGION_TYPE_DEVICE;
11784ad7e9b0SAdrian Chadd cfg->num_dev_ports = core.num_dport;
11794ad7e9b0SAdrian Chadd cfg->num_bridge_ports = 0;
11804ad7e9b0SAdrian Chadd }
11814ad7e9b0SAdrian Chadd }
11824ad7e9b0SAdrian Chadd
11834ad7e9b0SAdrian Chadd /* Device/bridge port descriptors */
11844ad7e9b0SAdrian Chadd for (uint8_t sp_num = 0; sp_num < core.num_dport; sp_num++) {
1185664a7497SLandon J. Fuller error = bcma_erom_corecfg_fill_port_regions(erom, cfg, sp_num,
11864ad7e9b0SAdrian Chadd first_region_type);
11874ad7e9b0SAdrian Chadd
11884ad7e9b0SAdrian Chadd if (error)
11894ad7e9b0SAdrian Chadd goto failed;
11904ad7e9b0SAdrian Chadd }
11914ad7e9b0SAdrian Chadd
11924ad7e9b0SAdrian Chadd /* Wrapper (aka device management) descriptors (for master ports). */
11934ad7e9b0SAdrian Chadd for (uint8_t sp_num = 0; sp_num < core.num_mwrap; sp_num++) {
1194664a7497SLandon J. Fuller error = bcma_erom_corecfg_fill_port_regions(erom, cfg, sp_num,
11954ad7e9b0SAdrian Chadd BCMA_EROM_REGION_TYPE_MWRAP);
11964ad7e9b0SAdrian Chadd
11974ad7e9b0SAdrian Chadd if (error)
11984ad7e9b0SAdrian Chadd goto failed;
11994ad7e9b0SAdrian Chadd }
12004ad7e9b0SAdrian Chadd
12014ad7e9b0SAdrian Chadd /* Wrapper (aka device management) descriptors (for slave ports). */
12024ad7e9b0SAdrian Chadd for (uint8_t i = 0; i < core.num_swrap; i++) {
12034ad7e9b0SAdrian Chadd /* Slave wrapper ports are not numbered distinctly from master
12044ad7e9b0SAdrian Chadd * wrapper ports. */
120505992f9eSAdrian Chadd
120605992f9eSAdrian Chadd /*
120705992f9eSAdrian Chadd * Broadcom DDR1/DDR2 Memory Controller
120805992f9eSAdrian Chadd * (cid=82e, rev=1, unit=0, d/mw/sw = 2/0/1 ) ->
120905992f9eSAdrian Chadd * bhnd0: erom[0xdc]: core6 agent0.0: mismatch got: 0x1 (0x2)
121005992f9eSAdrian Chadd *
121105992f9eSAdrian Chadd * ARM BP135 AMBA3 AXI to APB Bridge
121205992f9eSAdrian Chadd * (cid=135, rev=0, unit=0, d/mw/sw = 1/0/1 ) ->
121305992f9eSAdrian Chadd * bhnd0: erom[0x124]: core9 agent1.0: mismatch got: 0x0 (0x2)
121405992f9eSAdrian Chadd *
121505992f9eSAdrian Chadd * core.num_mwrap
121605992f9eSAdrian Chadd * ===>
121705992f9eSAdrian Chadd * (core.num_mwrap > 0) ?
121805992f9eSAdrian Chadd * core.num_mwrap :
121905992f9eSAdrian Chadd * ((core.vendor == BHND_MFGID_BCM) ? 1 : 0)
122005992f9eSAdrian Chadd */
122105992f9eSAdrian Chadd uint8_t sp_num;
122205992f9eSAdrian Chadd sp_num = (core.num_mwrap > 0) ?
122305992f9eSAdrian Chadd core.num_mwrap :
122405992f9eSAdrian Chadd ((core.vendor == BHND_MFGID_BCM) ? 1 : 0) + i;
1225664a7497SLandon J. Fuller error = bcma_erom_corecfg_fill_port_regions(erom, cfg, sp_num,
12264ad7e9b0SAdrian Chadd BCMA_EROM_REGION_TYPE_SWRAP);
12274ad7e9b0SAdrian Chadd
12284ad7e9b0SAdrian Chadd if (error)
12294ad7e9b0SAdrian Chadd goto failed;
12304ad7e9b0SAdrian Chadd }
12314ad7e9b0SAdrian Chadd
12325658bc0aSLandon J. Fuller /*
12335658bc0aSLandon J. Fuller * Seek to the next core entry (if any), skipping any dangling/invalid
12345658bc0aSLandon J. Fuller * region entries.
12355658bc0aSLandon J. Fuller *
12365658bc0aSLandon J. Fuller * On the BCM4706, the EROM entry for the memory controller core
12375658bc0aSLandon J. Fuller * (0x4bf/0x52E) contains a dangling/unused slave wrapper port region
12385658bc0aSLandon J. Fuller * descriptor.
12395658bc0aSLandon J. Fuller */
12405658bc0aSLandon J. Fuller if ((error = bcma_erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE))) {
12415658bc0aSLandon J. Fuller if (error != ENOENT)
12425658bc0aSLandon J. Fuller goto failed;
12435658bc0aSLandon J. Fuller }
12445658bc0aSLandon J. Fuller
12454ad7e9b0SAdrian Chadd *result = cfg;
12464ad7e9b0SAdrian Chadd return (0);
12474ad7e9b0SAdrian Chadd
12484ad7e9b0SAdrian Chadd failed:
12494ad7e9b0SAdrian Chadd if (cfg != NULL)
12504ad7e9b0SAdrian Chadd bcma_free_corecfg(cfg);
12514ad7e9b0SAdrian Chadd
12524ad7e9b0SAdrian Chadd return error;
12534ad7e9b0SAdrian Chadd }
1254664a7497SLandon J. Fuller
1255eb23aa80SLandon J. Fuller static int
bcma_erom_dump(bhnd_erom_t * erom)1256eb23aa80SLandon J. Fuller bcma_erom_dump(bhnd_erom_t *erom)
1257eb23aa80SLandon J. Fuller {
1258eb23aa80SLandon J. Fuller struct bcma_erom *sc;
1259eb23aa80SLandon J. Fuller uint32_t entry;
1260eb23aa80SLandon J. Fuller int error;
1261eb23aa80SLandon J. Fuller
1262eb23aa80SLandon J. Fuller sc = (struct bcma_erom *)erom;
1263eb23aa80SLandon J. Fuller
1264eb23aa80SLandon J. Fuller bcma_erom_reset(sc);
1265eb23aa80SLandon J. Fuller
1266eb23aa80SLandon J. Fuller while (!(error = bcma_erom_read32(sc, &entry))) {
1267eb23aa80SLandon J. Fuller /* Handle EOF */
1268eb23aa80SLandon J. Fuller if (entry == BCMA_EROM_TABLE_EOF) {
1269eb23aa80SLandon J. Fuller EROM_LOG(sc, "EOF\n");
1270eb23aa80SLandon J. Fuller return (0);
1271eb23aa80SLandon J. Fuller }
1272eb23aa80SLandon J. Fuller
1273eb23aa80SLandon J. Fuller /* Invalid entry */
1274eb23aa80SLandon J. Fuller if (!BCMA_EROM_GET_ATTR(entry, ENTRY_ISVALID)) {
1275eb23aa80SLandon J. Fuller EROM_LOG(sc, "invalid EROM entry %#x\n", entry);
1276eb23aa80SLandon J. Fuller return (EINVAL);
1277eb23aa80SLandon J. Fuller }
1278eb23aa80SLandon J. Fuller
1279eb23aa80SLandon J. Fuller switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) {
1280eb23aa80SLandon J. Fuller case BCMA_EROM_ENTRY_TYPE_CORE: {
1281eb23aa80SLandon J. Fuller /* CoreDescA */
1282eb23aa80SLandon J. Fuller EROM_LOG(sc, "coreA (0x%x)\n", entry);
1283eb23aa80SLandon J. Fuller EROM_LOG(sc, "\tdesigner:\t0x%x\n",
1284eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, COREA_DESIGNER));
1285eb23aa80SLandon J. Fuller EROM_LOG(sc, "\tid:\t\t0x%x\n",
1286eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, COREA_ID));
1287eb23aa80SLandon J. Fuller EROM_LOG(sc, "\tclass:\t\t0x%x\n",
1288eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, COREA_CLASS));
1289eb23aa80SLandon J. Fuller
1290eb23aa80SLandon J. Fuller /* CoreDescB */
1291eb23aa80SLandon J. Fuller if ((error = bcma_erom_read32(sc, &entry))) {
1292eb23aa80SLandon J. Fuller EROM_LOG(sc, "error reading CoreDescB: %d\n",
1293eb23aa80SLandon J. Fuller error);
1294eb23aa80SLandon J. Fuller return (error);
1295eb23aa80SLandon J. Fuller }
1296eb23aa80SLandon J. Fuller
1297eb23aa80SLandon J. Fuller if (!BCMA_EROM_ENTRY_IS(entry, CORE)) {
1298eb23aa80SLandon J. Fuller EROM_LOG(sc, "invalid core descriptor; found "
1299eb23aa80SLandon J. Fuller "unexpected entry %#x (type=%s)\n",
1300eb23aa80SLandon J. Fuller entry, bcma_erom_entry_type_name(entry));
1301eb23aa80SLandon J. Fuller return (EINVAL);
1302eb23aa80SLandon J. Fuller }
1303eb23aa80SLandon J. Fuller
1304eb23aa80SLandon J. Fuller EROM_LOG(sc, "coreB (0x%x)\n", entry);
1305eb23aa80SLandon J. Fuller EROM_LOG(sc, "\trev:\t0x%x\n",
1306eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, COREB_REV));
1307eb23aa80SLandon J. Fuller EROM_LOG(sc, "\tnummp:\t0x%x\n",
1308eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, COREB_NUM_MP));
1309eb23aa80SLandon J. Fuller EROM_LOG(sc, "\tnumdp:\t0x%x\n",
1310eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, COREB_NUM_DP));
1311eb23aa80SLandon J. Fuller EROM_LOG(sc, "\tnumwmp:\t0x%x\n",
1312eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, COREB_NUM_WMP));
1313eb23aa80SLandon J. Fuller EROM_LOG(sc, "\tnumwsp:\t0x%x\n",
1314eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, COREB_NUM_WMP));
1315eb23aa80SLandon J. Fuller
1316eb23aa80SLandon J. Fuller break;
1317eb23aa80SLandon J. Fuller }
1318eb23aa80SLandon J. Fuller case BCMA_EROM_ENTRY_TYPE_MPORT:
1319eb23aa80SLandon J. Fuller EROM_LOG(sc, "\tmport 0x%x\n", entry);
1320eb23aa80SLandon J. Fuller EROM_LOG(sc, "\t\tport:\t0x%x\n",
1321eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, MPORT_NUM));
1322eb23aa80SLandon J. Fuller EROM_LOG(sc, "\t\tid:\t\t0x%x\n",
1323eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, MPORT_ID));
1324eb23aa80SLandon J. Fuller break;
1325eb23aa80SLandon J. Fuller
1326eb23aa80SLandon J. Fuller case BCMA_EROM_ENTRY_TYPE_REGION: {
1327eb23aa80SLandon J. Fuller bool addr64;
1328eb23aa80SLandon J. Fuller uint8_t size_type;
1329eb23aa80SLandon J. Fuller
1330eb23aa80SLandon J. Fuller addr64 = (BCMA_EROM_GET_ATTR(entry, REGION_64BIT) != 0);
1331eb23aa80SLandon J. Fuller size_type = BCMA_EROM_GET_ATTR(entry, REGION_SIZE);
1332eb23aa80SLandon J. Fuller
1333eb23aa80SLandon J. Fuller EROM_LOG(sc, "\tregion 0x%x:\n", entry);
1334eb23aa80SLandon J. Fuller EROM_LOG(sc, "\t\t%s:\t0x%x\n",
1335eb23aa80SLandon J. Fuller addr64 ? "baselo" : "base",
1336eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, REGION_BASE));
1337eb23aa80SLandon J. Fuller EROM_LOG(sc, "\t\tport:\t0x%x\n",
1338eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, REGION_PORT));
1339eb23aa80SLandon J. Fuller EROM_LOG(sc, "\t\ttype:\t0x%x\n",
1340eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, REGION_TYPE));
1341eb23aa80SLandon J. Fuller EROM_LOG(sc, "\t\tsztype:\t0x%hhx\n", size_type);
1342eb23aa80SLandon J. Fuller
1343eb23aa80SLandon J. Fuller /* Read the base address high bits */
1344eb23aa80SLandon J. Fuller if (addr64) {
1345eb23aa80SLandon J. Fuller if ((error = bcma_erom_read32(sc, &entry))) {
1346eb23aa80SLandon J. Fuller EROM_LOG(sc, "error reading region "
1347eb23aa80SLandon J. Fuller "base address high bits %d\n",
1348eb23aa80SLandon J. Fuller error);
1349eb23aa80SLandon J. Fuller return (error);
1350eb23aa80SLandon J. Fuller }
1351eb23aa80SLandon J. Fuller
1352eb23aa80SLandon J. Fuller EROM_LOG(sc, "\t\tbasehi:\t0x%x\n", entry);
1353eb23aa80SLandon J. Fuller }
1354eb23aa80SLandon J. Fuller
1355eb23aa80SLandon J. Fuller /* Read extended size descriptor */
1356eb23aa80SLandon J. Fuller if (size_type == BCMA_EROM_REGION_SIZE_OTHER) {
1357eb23aa80SLandon J. Fuller bool size64;
1358eb23aa80SLandon J. Fuller
1359eb23aa80SLandon J. Fuller if ((error = bcma_erom_read32(sc, &entry))) {
1360eb23aa80SLandon J. Fuller EROM_LOG(sc, "error reading region "
1361eb23aa80SLandon J. Fuller "size descriptor %d\n",
1362eb23aa80SLandon J. Fuller error);
1363eb23aa80SLandon J. Fuller return (error);
1364eb23aa80SLandon J. Fuller }
1365eb23aa80SLandon J. Fuller
1366eb23aa80SLandon J. Fuller if (BCMA_EROM_GET_ATTR(entry, RSIZE_64BIT))
1367eb23aa80SLandon J. Fuller size64 = true;
1368eb23aa80SLandon J. Fuller else
1369eb23aa80SLandon J. Fuller size64 = false;
1370eb23aa80SLandon J. Fuller
1371eb23aa80SLandon J. Fuller EROM_LOG(sc, "\t\t%s:\t0x%x\n",
1372eb23aa80SLandon J. Fuller size64 ? "sizelo" : "size",
1373eb23aa80SLandon J. Fuller BCMA_EROM_GET_ATTR(entry, RSIZE_VAL));
1374eb23aa80SLandon J. Fuller
1375eb23aa80SLandon J. Fuller if (size64) {
1376eb23aa80SLandon J. Fuller error = bcma_erom_read32(sc, &entry);
1377eb23aa80SLandon J. Fuller if (error) {
1378eb23aa80SLandon J. Fuller EROM_LOG(sc, "error reading "
1379eb23aa80SLandon J. Fuller "region size high bits: "
1380eb23aa80SLandon J. Fuller "%d\n", error);
1381eb23aa80SLandon J. Fuller return (error);
1382eb23aa80SLandon J. Fuller }
1383eb23aa80SLandon J. Fuller
1384eb23aa80SLandon J. Fuller EROM_LOG(sc, "\t\tsizehi:\t0x%x\n",
1385eb23aa80SLandon J. Fuller entry);
1386eb23aa80SLandon J. Fuller }
1387eb23aa80SLandon J. Fuller }
1388eb23aa80SLandon J. Fuller break;
1389eb23aa80SLandon J. Fuller }
1390eb23aa80SLandon J. Fuller
1391eb23aa80SLandon J. Fuller default:
1392eb23aa80SLandon J. Fuller EROM_LOG(sc, "unknown EROM entry 0x%x (type=%s)\n",
1393eb23aa80SLandon J. Fuller entry, bcma_erom_entry_type_name(entry));
1394eb23aa80SLandon J. Fuller return (EINVAL);
1395eb23aa80SLandon J. Fuller }
1396eb23aa80SLandon J. Fuller }
1397eb23aa80SLandon J. Fuller
1398eb23aa80SLandon J. Fuller if (error == ENOENT)
1399eb23aa80SLandon J. Fuller EROM_LOG(sc, "BCMA EROM table missing terminating EOF\n");
1400eb23aa80SLandon J. Fuller else if (error)
1401eb23aa80SLandon J. Fuller EROM_LOG(sc, "EROM read failed: %d\n", error);
1402eb23aa80SLandon J. Fuller
1403eb23aa80SLandon J. Fuller return (error);
1404eb23aa80SLandon J. Fuller }
1405eb23aa80SLandon J. Fuller
1406664a7497SLandon J. Fuller static kobj_method_t bcma_erom_methods[] = {
1407111d7cb2SLandon J. Fuller KOBJMETHOD(bhnd_erom_probe, bcma_erom_probe),
1408664a7497SLandon J. Fuller KOBJMETHOD(bhnd_erom_init, bcma_erom_init),
1409664a7497SLandon J. Fuller KOBJMETHOD(bhnd_erom_fini, bcma_erom_fini),
1410664a7497SLandon J. Fuller KOBJMETHOD(bhnd_erom_get_core_table, bcma_erom_get_core_table),
1411664a7497SLandon J. Fuller KOBJMETHOD(bhnd_erom_free_core_table, bcma_erom_free_core_table),
1412664a7497SLandon J. Fuller KOBJMETHOD(bhnd_erom_lookup_core, bcma_erom_lookup_core),
1413664a7497SLandon J. Fuller KOBJMETHOD(bhnd_erom_lookup_core_addr, bcma_erom_lookup_core_addr),
1414eb23aa80SLandon J. Fuller KOBJMETHOD(bhnd_erom_dump, bcma_erom_dump),
1415664a7497SLandon J. Fuller
1416664a7497SLandon J. Fuller KOBJMETHOD_END
1417664a7497SLandon J. Fuller };
1418664a7497SLandon J. Fuller
1419664a7497SLandon J. Fuller BHND_EROM_DEFINE_CLASS(bcma_erom, bcma_erom_parser, bcma_erom_methods, sizeof(struct bcma_erom));
1420