1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
5 * Copyright (c) 2017 The FreeBSD Foundation
6 * All rights reserved.
7 *
8 * Portions of this software were developed by Landon Fuller
9 * under sponsorship from the FreeBSD Foundation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
19 *    redistribution must be conditioned upon including a substantially
20 *    similar Disclaimer requirement for further binary redistribution.
21 *
22 * NO WARRANTY
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
26 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
27 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
28 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
31 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGES.
34 */
35
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD$");
38
39#include <sys/param.h>
40#include <sys/bus.h>
41#include <sys/kobj.h>
42
43#include <machine/bus.h>
44#include <sys/rman.h>
45#include <machine/resource.h>
46
47#include <dev/bhnd/bhndreg.h>
48#include <dev/bhnd/bhndvar.h>
49
50#include <dev/bhnd/bhnd_erom.h>
51#include <dev/bhnd/bhnd_eromvar.h>
52
53#include <dev/bhnd/cores/chipc/chipcreg.h>
54
55static int	bhnd_erom_iores_map(struct bhnd_erom_io *eio, bhnd_addr_t addr,
56		    bhnd_size_t size);
57static int	bhnd_erom_iores_tell(struct bhnd_erom_io *eio,
58		    bhnd_addr_t *addr, bhnd_size_t *size);
59static uint32_t	bhnd_erom_iores_read(struct bhnd_erom_io *eio,
60		    bhnd_size_t offset, u_int width);
61static void	bhnd_erom_iores_fini(struct bhnd_erom_io *eio);
62
63static int	bhnd_erom_iobus_map(struct bhnd_erom_io *eio, bhnd_addr_t addr,
64		    bhnd_size_t size);
65static int	bhnd_erom_iobus_tell(struct bhnd_erom_io *eio,
66		    bhnd_addr_t *addr, bhnd_size_t *size);
67static uint32_t	bhnd_erom_iobus_read(struct bhnd_erom_io *eio,
68		    bhnd_size_t offset, u_int width);
69
70/**
71 * An implementation of bhnd_erom_io that manages mappings via
72 * bhnd_alloc_resource() and bhnd_release_resource().
73 */
74struct bhnd_erom_iores {
75	struct bhnd_erom_io	 eio;
76	device_t		 owner;		/**< device from which we'll allocate resources */
77	int			 owner_rid;	/**< rid to use when allocating new mappings */
78	struct bhnd_resource	*mapped;	/**< current mapping, or NULL */
79	int			 mapped_rid;	/**< resource ID of current mapping, or -1 */
80};
81
82/**
83 * Fetch the device enumeration parser class from all bhnd(4)-compatible drivers
84 * registered for @p bus_devclass, probe @p eio for supporting parser classes,
85 * and return the best available supporting enumeration parser class.
86 *
87 * @param	bus_devclass	The bus device class to be queried for
88 *				bhnd(4)-compatible drivers.
89 * @param	eio		An erom bus I/O instance, configured with a
90 *				mapping of the first bus core.
91 * @param	hint		Identification hint used to identify the device.
92 *				If the chipset supports standard chip
93 *				identification registers within the first core,
94 *				this parameter should be NULL.
95 * @param[out]	cid		On success, the probed chip identifier.
96 *
97 * @retval non-NULL	on success, the best available EROM class.
98 * @retval NULL		if no erom class returned a successful probe result for
99 *			@p eio.
100 */
101bhnd_erom_class_t *
102bhnd_erom_probe_driver_classes(devclass_t bus_devclass,
103    struct bhnd_erom_io *eio, const struct bhnd_chipid *hint,
104    struct bhnd_chipid *cid)
105{
106	driver_t		**drivers;
107	int			 drv_count;
108	bhnd_erom_class_t	*erom_cls;
109	int			 error, prio, result;
110
111	erom_cls = NULL;
112	prio = 0;
113
114	/* Fetch all available drivers */
115	error = devclass_get_drivers(bus_devclass, &drivers, &drv_count);
116	if (error) {
117		printf("error fetching bhnd(4) drivers for %s: %d\n",
118		    devclass_get_name(bus_devclass), error);
119		return (NULL);
120	}
121
122	/* Enumerate the drivers looking for the best available EROM class */
123	for (int i = 0; i < drv_count; i++) {
124		struct bhnd_chipid	 pcid;
125		bhnd_erom_class_t	*cls;
126
127		/* The default implementation of BHND_BUS_GET_EROM_CLASS()
128		 * returns NULL if unimplemented; this should always be safe
129		 * to call on arbitrary drivers */
130		cls = bhnd_driver_get_erom_class(drivers[i]);
131		if (cls == NULL)
132			continue;
133
134		kobj_class_compile(cls);
135
136		/* Probe the bus */
137		result = bhnd_erom_probe(cls, eio, hint, &pcid);
138
139		/* The parser did not match if an error was returned */
140		if (result > 0)
141			continue;
142
143		/* Check for a new highest priority match */
144		if (erom_cls == NULL || result > prio) {
145			prio = result;
146
147			*cid = pcid;
148			erom_cls = cls;
149		}
150
151		/* Terminate immediately on BUS_PROBE_SPECIFIC */
152		if (result == BUS_PROBE_SPECIFIC)
153			break;
154	}
155
156	free(drivers, M_TEMP);
157	return (erom_cls);
158}
159
160/**
161 * Allocate and return a new device enumeration table parser.
162 *
163 * @param cls		The parser class for which an instance will be
164 *			allocated.
165 * @param eio		The bus I/O callbacks to use when reading the device
166 *			enumeration table.
167 * @param cid		The device's chip identifier.
168 *
169 * @retval non-NULL	success
170 * @retval NULL		if an error occured allocating or initializing the
171 *			EROM parser.
172 */
173bhnd_erom_t *
174bhnd_erom_alloc(bhnd_erom_class_t *cls, const struct bhnd_chipid *cid,
175    struct bhnd_erom_io *eio)
176{
177	bhnd_erom_t	*erom;
178	int		 error;
179
180	erom = (bhnd_erom_t *)kobj_create((kobj_class_t)cls, M_BHND,
181	    M_WAITOK|M_ZERO);
182
183	if ((error = BHND_EROM_INIT(erom, cid, eio))) {
184		printf("error initializing %s parser at %#jx: %d\n", cls->name,
185		    (uintmax_t)cid->enum_addr, error);
186
187		kobj_delete((kobj_t)erom, M_BHND);
188		return (NULL);
189	}
190
191	return (erom);
192}
193
194/**
195 * Perform static initialization of a device enumeration table parser.
196 *
197 * This may be used to initialize a caller-allocated erom instance state
198 * during early boot, prior to malloc availability.
199 *
200 * @param cls		The parser class for which an instance will be
201 *			allocated.
202 * @param erom		The erom parser instance to initialize.
203 * @param esize		The total available number of bytes allocated for
204 *			@p erom. If this is less than is required by @p cls,
205 *			ENOMEM will be returned.
206 * @param cid		The device's chip identifier.
207 * @param eio		The bus I/O callbacks to use when reading the device
208 *			enumeration table.
209 *
210 * @retval 0		success
211 * @retval ENOMEM	if @p esize is smaller than required by @p cls.
212 * @retval non-zero	if an error occurs initializing the EROM parser,
213 *			a regular unix error code will be returned.
214 */
215int
216bhnd_erom_init_static(bhnd_erom_class_t *cls, bhnd_erom_t *erom, size_t esize,
217    const struct bhnd_chipid *cid, struct bhnd_erom_io *eio)
218{
219	kobj_class_t	kcls;
220
221	kcls = (kobj_class_t)cls;
222
223	/* Verify allocation size */
224	if (kcls->size > esize)
225		return (ENOMEM);
226
227	/* Perform instance initialization */
228	kobj_init_static((kobj_t)erom, kcls);
229	return (BHND_EROM_INIT(erom, cid, eio));
230}
231
232/**
233 * Release any resources held by a @p erom parser previously
234 * initialized via bhnd_erom_init_static().
235 *
236 * @param	erom	An erom parser instance previously initialized via
237 *			bhnd_erom_init_static().
238 */
239void
240bhnd_erom_fini_static(bhnd_erom_t *erom)
241{
242	return (BHND_EROM_FINI(erom));
243}
244
245/**
246 * Release all resources held by a @p erom parser previously
247 * allocated via bhnd_erom_alloc().
248 *
249 * @param	erom	An erom parser instance previously allocated via
250 *			bhnd_erom_alloc().
251 */
252void
253bhnd_erom_free(bhnd_erom_t *erom)
254{
255	BHND_EROM_FINI(erom);
256	kobj_delete((kobj_t)erom, M_BHND);
257}
258
259/**
260 * Read the chip identification registers mapped by @p eio, popuating @p cid
261 * with the parsed result
262 *
263 * @param	eio		A bus I/O instance, configured with a mapping
264 *				of the ChipCommon core.
265 * @param[out]	cid		On success, the parsed chip identification.
266 *
267 * @warning
268 * On early siba(4) devices, the ChipCommon core does not provide
269 * a valid CHIPC_ID_NUMCORE field. On these ChipCommon revisions
270 * (see CHIPC_NCORES_MIN_HWREV()), this function will parse and return
271 * an invalid `ncores` value.
272 */
273int
274bhnd_erom_read_chipid(struct bhnd_erom_io *eio, struct bhnd_chipid *cid)
275{
276	bhnd_addr_t	cc_addr;
277	bhnd_size_t	cc_size;
278	uint32_t	idreg, cc_caps;
279	int		error;
280
281	/* Fetch ChipCommon address */
282	if ((error = bhnd_erom_io_tell(eio, &cc_addr, &cc_size)))
283		return (error);
284
285	/* Read chip identifier */
286	idreg = bhnd_erom_io_read(eio, CHIPC_ID, 4);
287
288	/* Extract the basic chip info */
289	cid->chip_id = CHIPC_GET_BITS(idreg, CHIPC_ID_CHIP);
290	cid->chip_pkg = CHIPC_GET_BITS(idreg, CHIPC_ID_PKG);
291	cid->chip_rev = CHIPC_GET_BITS(idreg, CHIPC_ID_REV);
292	cid->chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS);
293	cid->ncores = CHIPC_GET_BITS(idreg, CHIPC_ID_NUMCORE);
294
295	/* Populate EROM address */
296	if (BHND_CHIPTYPE_HAS_EROM(cid->chip_type)) {
297		cid->enum_addr = bhnd_erom_io_read(eio, CHIPC_EROMPTR, 4);
298	} else {
299		cid->enum_addr = cc_addr;
300	}
301
302	/* Populate capability flags */
303	cc_caps = bhnd_erom_io_read(eio, CHIPC_CAPABILITIES, 4);
304	cid->chip_caps = 0x0;
305
306	if (cc_caps & CHIPC_CAP_BKPLN64)
307		cid->chip_caps |= BHND_CAP_BP64;
308
309	if (cc_caps & CHIPC_CAP_PMU)
310		cid->chip_caps |= BHND_CAP_PMU;
311
312	return (0);
313}
314
315
316/**
317 * Attempt to map @p size bytes at @p addr, replacing any existing
318 * @p eio mapping.
319 *
320 * @param eio	I/O instance state.
321 * @param addr	The address to be mapped.
322 * @param size	The number of bytes to be mapped at @p addr.
323 *
324 * @retval 0		success
325 * @retval non-zero	if mapping @p addr otherwise fails, a regular
326 *			unix error code should be returned.
327 */
328int
329bhnd_erom_io_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, bhnd_size_t size)
330{
331	return (eio->map(eio, addr, size));
332}
333
334/**
335 * Return the address range mapped by @p eio, if any.
336 *
337 * @param	eio	I/O instance state.
338 * @param[out]	addr	The address mapped by @p eio.
339 * @param[out]	size	The number of bytes mapped at @p addr.
340 *
341 * @retval	0	success
342 * @retval	ENXIO	if @p eio has no mapping.
343 */
344int
345bhnd_erom_io_tell(struct bhnd_erom_io *eio, bhnd_addr_t *addr,
346    bhnd_size_t *size)
347{
348	return (eio->tell(eio, addr, size));
349}
350
351/**
352 * Read a 1, 2, or 4 byte data item from @p eio, at the given @p offset
353 * relative to @p eio's current mapping.
354 *
355 * @param eio		erom I/O callbacks
356 * @param offset	read offset.
357 * @param width		item width (1, 2, or 4 bytes).
358 */
359uint32_t
360bhnd_erom_io_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width)
361{
362	return (eio->read(eio, offset, width));
363}
364
365/**
366 * Free all resources held by @p eio.
367 */
368void
369bhnd_erom_io_fini(struct bhnd_erom_io *eio)
370{
371	if (eio->fini != NULL)
372		return (eio->fini(eio));
373}
374
375/**
376 * Allocate, initialize, and return a new I/O instance that will perform
377 * mapping by allocating SYS_RES_MEMORY resources from @p dev using @p rid.
378 *
379 * @param dev	The device to pass to bhnd_alloc_resource() and
380 *		bhnd_release_resource() functions.
381 * @param rid	The resource ID to be used when allocating memory resources.
382 */
383struct bhnd_erom_io *
384bhnd_erom_iores_new(device_t dev, int rid)
385{
386	struct bhnd_erom_iores	*iores;
387
388	iores = malloc(sizeof(*iores), M_BHND, M_WAITOK | M_ZERO);
389	iores->eio.map = bhnd_erom_iores_map;
390	iores->eio.tell = bhnd_erom_iores_tell;
391	iores->eio.read = bhnd_erom_iores_read;
392	iores->eio.fini = bhnd_erom_iores_fini;
393
394	iores->owner = dev;
395	iores->owner_rid = rid;
396	iores->mapped = NULL;
397	iores->mapped_rid = -1;
398
399	return (&iores->eio);
400}
401
402static int
403bhnd_erom_iores_map(struct bhnd_erom_io *eio, bhnd_addr_t addr,
404    bhnd_size_t size)
405{
406	struct bhnd_erom_iores *iores;
407
408	iores = (struct bhnd_erom_iores *)eio;
409
410	/* Sanity check the addr/size */
411	if (size == 0)
412		return (EINVAL);
413
414	if (BHND_ADDR_MAX - size < addr)
415		return (EINVAL);	/* would overflow */
416
417	/* Check for an existing mapping */
418	if (iores->mapped) {
419		/* If already mapped, nothing else to do */
420		if (rman_get_start(iores->mapped->res) == addr &&
421		    rman_get_size(iores->mapped->res) == size)
422		{
423			return (0);
424		}
425
426		/* Otherwise, we need to drop the existing mapping */
427		bhnd_release_resource(iores->owner, SYS_RES_MEMORY,
428		    iores->mapped_rid, iores->mapped);
429		iores->mapped = NULL;
430		iores->mapped_rid = -1;
431	}
432
433	/* Try to allocate the new mapping */
434	iores->mapped_rid = iores->owner_rid;
435	iores->mapped = bhnd_alloc_resource(iores->owner, SYS_RES_MEMORY,
436	    &iores->mapped_rid, addr, addr+size-1, size,
437	    RF_ACTIVE|RF_SHAREABLE);
438	if (iores->mapped == NULL) {
439		iores->mapped_rid = -1;
440		return (ENXIO);
441	}
442
443	return (0);
444}
445
446static int
447bhnd_erom_iores_tell(struct bhnd_erom_io *eio, bhnd_addr_t *addr,
448    bhnd_size_t *size)
449{
450	struct bhnd_erom_iores *iores = (struct bhnd_erom_iores *)eio;
451
452	if (iores->mapped == NULL)
453		return (ENXIO);
454
455	*addr = rman_get_start(iores->mapped->res);
456	*size = rman_get_size(iores->mapped->res);
457
458	return (0);
459}
460
461static uint32_t
462bhnd_erom_iores_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width)
463{
464	struct bhnd_erom_iores *iores = (struct bhnd_erom_iores *)eio;
465
466	if (iores->mapped == NULL)
467		panic("read with invalid mapping");
468
469	switch (width) {
470	case 1:
471		return (bhnd_bus_read_1(iores->mapped, offset));
472	case 2:
473		return (bhnd_bus_read_2(iores->mapped, offset));
474	case 4:
475		return (bhnd_bus_read_4(iores->mapped, offset));
476	default:
477		panic("invalid width %u", width);
478	}
479}
480
481static void
482bhnd_erom_iores_fini(struct bhnd_erom_io *eio)
483{
484	struct bhnd_erom_iores *iores = (struct bhnd_erom_iores *)eio;
485
486	/* Release any mapping */
487	if (iores->mapped) {
488		bhnd_release_resource(iores->owner, SYS_RES_MEMORY,
489		    iores->mapped_rid, iores->mapped);
490		iores->mapped = NULL;
491		iores->mapped_rid = -1;
492	}
493
494	free(eio, M_BHND);
495}
496
497/**
498 * Initialize an I/O instance that will perform mapping directly from the
499 * given bus space tag and handle.
500 *
501 * @param iobus	The I/O instance to be initialized.
502 * @param addr	The base address mapped by @p bsh.
503 * @param size	The total size mapped by @p bsh.
504 * @param bst	Bus space tag for @p bsh.
505 * @param bsh	Bus space handle mapping the full bus enumeration space.
506 *
507 * @retval 0		success
508 * @retval non-zero	if initializing @p iobus otherwise fails, a regular
509 *			unix error code will be returned.
510 */
511int
512bhnd_erom_iobus_init(struct bhnd_erom_iobus *iobus, bhnd_addr_t addr,
513    bhnd_size_t size, bus_space_tag_t bst, bus_space_handle_t bsh)
514{
515	iobus->eio.map = bhnd_erom_iobus_map;
516	iobus->eio.tell = bhnd_erom_iobus_tell;
517	iobus->eio.read = bhnd_erom_iobus_read;
518	iobus->eio.fini = NULL;
519
520	iobus->addr = addr;
521	iobus->size = size;
522	iobus->bst = bst;
523	iobus->bsh = bsh;
524	iobus->mapped = false;
525
526	return (0);
527}
528
529static int
530bhnd_erom_iobus_map(struct bhnd_erom_io *eio, bhnd_addr_t addr,
531    bhnd_size_t size)
532{
533	struct bhnd_erom_iobus *iobus = (struct bhnd_erom_iobus *)eio;
534
535	/* Sanity check the addr/size */
536	if (size == 0)
537		return (EINVAL);
538
539	/* addr+size must not overflow */
540	if (BHND_ADDR_MAX - size < addr)
541		return (EINVAL);
542
543	/* addr/size must fit within our bus tag's mapping */
544	if (addr < iobus->addr || size > iobus->size)
545		return (ENXIO);
546
547	if (iobus->size - (addr - iobus->addr) < size)
548		return (ENXIO);
549
550	/* The new addr offset and size must be representible as a bus_size_t */
551	if ((addr - iobus->addr) > BUS_SPACE_MAXSIZE)
552		return (ENXIO);
553
554	if (size > BUS_SPACE_MAXSIZE)
555		return (ENXIO);
556
557	iobus->offset = addr - iobus->addr;
558	iobus->limit = size;
559	iobus->mapped = true;
560
561	return (0);
562}
563
564static int
565bhnd_erom_iobus_tell(struct bhnd_erom_io *eio, bhnd_addr_t *addr,
566    bhnd_size_t *size)
567{
568	struct bhnd_erom_iobus *iobus = (struct bhnd_erom_iobus *)eio;
569
570	if (!iobus->mapped)
571		return (ENXIO);
572
573	*addr = iobus->addr + iobus->offset;
574	*size = iobus->limit;
575
576	return (0);
577}
578
579static uint32_t
580bhnd_erom_iobus_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width)
581{
582	struct bhnd_erom_iobus *iobus = (struct bhnd_erom_iobus *)eio;
583
584	if (!iobus->mapped)
585		panic("no active mapping");
586
587	if (iobus->limit < width || iobus->limit - width < offset)
588		panic("invalid offset %#jx", offset);
589
590	switch (width) {
591	case 1:
592		return (bus_space_read_1(iobus->bst, iobus->bsh,
593		    iobus->offset + offset));
594	case 2:
595		return (bus_space_read_2(iobus->bst, iobus->bsh,
596		    iobus->offset + offset));
597	case 4:
598		return (bus_space_read_4(iobus->bst, iobus->bsh,
599		    iobus->offset + offset));
600	default:
601		panic("invalid width %u", width);
602	}
603}
604