xref: /freebsd/sys/dev/bhnd/bhnd_erom.c (revision 0957b409)
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 
55 static int	bhnd_erom_iores_map(struct bhnd_erom_io *eio, bhnd_addr_t addr,
56 		    bhnd_size_t size);
57 static int	bhnd_erom_iores_tell(struct bhnd_erom_io *eio,
58 		    bhnd_addr_t *addr, bhnd_size_t *size);
59 static uint32_t	bhnd_erom_iores_read(struct bhnd_erom_io *eio,
60 		    bhnd_size_t offset, u_int width);
61 static void	bhnd_erom_iores_fini(struct bhnd_erom_io *eio);
62 
63 static int	bhnd_erom_iobus_map(struct bhnd_erom_io *eio, bhnd_addr_t addr,
64 		    bhnd_size_t size);
65 static int	bhnd_erom_iobus_tell(struct bhnd_erom_io *eio,
66 		    bhnd_addr_t *addr, bhnd_size_t *size);
67 static 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  */
74 struct 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  */
101 bhnd_erom_class_t *
102 bhnd_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  */
173 bhnd_erom_t *
174 bhnd_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  */
215 int
216 bhnd_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  */
239 void
240 bhnd_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  */
252 void
253 bhnd_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  */
273 int
274 bhnd_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  */
328 int
329 bhnd_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  */
344 int
345 bhnd_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  */
359 uint32_t
360 bhnd_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  */
368 void
369 bhnd_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  */
383 struct bhnd_erom_io *
384 bhnd_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 
402 static int
403 bhnd_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 
446 static int
447 bhnd_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 
461 static uint32_t
462 bhnd_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 
481 static void
482 bhnd_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  */
511 int
512 bhnd_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 
529 static int
530 bhnd_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 
564 static int
565 bhnd_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 
579 static uint32_t
580 bhnd_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