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