xref: /freebsd/sys/dev/bhnd/siba/siba_subr.c (revision 224e0c2f)
1 /*-
2  * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
3  * Copyright (c) 2017 The FreeBSD Foundation
4  * All rights reserved.
5  *
6  * Portions of this software were developed by Landon Fuller
7  * under sponsorship from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer,
14  *    without modification.
15  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
16  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
17  *    redistribution must be conditioned upon including a substantially
18  *    similar Disclaimer requirement for further binary redistribution.
19  *
20  * NO WARRANTY
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
24  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
25  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
26  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGES.
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/limits.h>
41 #include <sys/systm.h>
42 
43 #include <machine/bus.h>
44 #include <machine/resource.h>
45 
46 #include <dev/bhnd/bhndvar.h>
47 
48 #include "sibareg.h"
49 #include "sibavar.h"
50 
51 /**
52  * Map a siba(4) OCP vendor code to its corresponding JEDEC JEP-106 vendor
53  * code.
54  *
55  * @param ocp_vendor An OCP vendor code.
56  * @return The BHND_MFGID constant corresponding to @p ocp_vendor, or
57  * BHND_MFGID_INVALID if the OCP vendor is unknown.
58  */
59 uint16_t
60 siba_get_bhnd_mfgid(uint16_t ocp_vendor)
61 {
62 	switch (ocp_vendor) {
63 	case OCP_VENDOR_BCM:
64 		return (BHND_MFGID_BCM);
65 	default:
66 		return (BHND_MFGID_INVALID);
67 	}
68 }
69 
70 /**
71  * Parse the SIBA_IDH_* fields from the per-core identification
72  * registers, returning a siba_core_id representation.
73  *
74  * @param idhigh The SIBA_R0_IDHIGH register.
75  * @param idlow The SIBA_R0_IDLOW register.
76  * @param core_id The core id (index) to include in the result.
77  * @param unit The unit number to include in the result.
78  */
79 struct siba_core_id
80 siba_parse_core_id(uint32_t idhigh, uint32_t idlow, u_int core_idx, int unit)
81 {
82 
83 	uint16_t	ocp_vendor;
84 	uint8_t		sonics_rev;
85 	uint8_t		num_addrspace;
86 	uint8_t		num_cfg;
87 
88 	ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
89 	sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV);
90 	num_addrspace = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */;
91 
92 	/* Determine the number of sonics config register blocks */
93 	num_cfg = SIBA_CFG_NUM_2_2;
94 	if (sonics_rev >= SIBA_IDL_SBREV_2_3)
95 		num_cfg = SIBA_CFG_NUM_2_3;
96 
97 	return (struct siba_core_id) {
98 		.core_info	= {
99 			.vendor	= siba_get_bhnd_mfgid(ocp_vendor),
100 			.device	= SIBA_REG_GET(idhigh, IDH_DEVICE),
101 			.hwrev	= SIBA_IDH_CORE_REV(idhigh),
102 			.core_idx = core_idx,
103 			.unit	= unit
104 		},
105 		.sonics_vendor	= ocp_vendor,
106 		.sonics_rev	= sonics_rev,
107 		.num_addrspace	= num_addrspace,
108 		.num_cfg_blocks	= num_cfg
109 	};
110 }
111 
112 /**
113  * Allocate and return a new empty device info structure.
114  *
115  * @param bus The requesting bus device.
116  *
117  * @retval NULL if allocation failed.
118  */
119 struct siba_devinfo *
120 siba_alloc_dinfo(device_t bus)
121 {
122 	struct siba_devinfo *dinfo;
123 
124 	dinfo = malloc(sizeof(struct siba_devinfo), M_BHND, M_NOWAIT|M_ZERO);
125 	if (dinfo == NULL)
126 		return NULL;
127 
128 	for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
129 		dinfo->cfg[i] = ((struct siba_cfg_block){
130 			.cb_base = 0,
131 			.cb_size = 0,
132 			.cb_rid = -1,
133 		});
134 		dinfo->cfg_res[i] = NULL;
135 		dinfo->cfg_rid[i] = -1;
136 	}
137 
138 	resource_list_init(&dinfo->resources);
139 
140 	dinfo->pmu_state = SIBA_PMU_NONE;
141 	dinfo->intr_en = false;
142 
143 	return dinfo;
144 }
145 
146 /**
147  * Initialize a device info structure previously allocated via
148  * siba_alloc_dinfo, copying the provided core id.
149  *
150  * @param dev The requesting bus device.
151  * @param dinfo The device info instance.
152  * @param core Device core info.
153  *
154  * @retval 0 success
155  * @retval non-zero initialization failed.
156  */
157 int
158 siba_init_dinfo(device_t dev, struct siba_devinfo *dinfo,
159     const struct siba_core_id *core_id)
160 {
161 	dinfo->core_id = *core_id;
162 	return (0);
163 }
164 
165 /**
166  * Map an addrspace index to its corresponding bhnd(4) BHND_PORT_DEVICE port
167  * number.
168  *
169  * @param addrspace Address space index.
170  */
171 u_int
172 siba_addrspace_device_port(u_int addrspace)
173 {
174 	/* The first addrspace is always mapped to device0; the remainder
175 	 * are mapped to device1 */
176 	if (addrspace == 0)
177 		return (0);
178 	else
179 		return (1);
180 }
181 
182 /**
183  * Map an addrspace index to its corresponding bhnd(4) BHND_PORT_DEVICE port
184  * region number.
185  *
186  * @param addrspace Address space index.
187  */
188 u_int
189 siba_addrspace_device_region(u_int addrspace)
190 {
191 	/* The first addrspace is always mapped to device0.0; the remainder
192 	 * are mapped to device1.0 + (n - 1) */
193 	if (addrspace == 0)
194 		return (0);
195 	else
196 		return (addrspace - 1);
197 }
198 
199 /**
200  * Map an config block index to its corresponding bhnd(4) BHND_PORT_AGENT port
201  * number.
202  *
203  * @param cfg Config block index.
204  */
205 u_int
206 siba_cfg_agent_port(u_int cfg)
207 {
208 	/* Always agent0 */
209 	return (0);
210 }
211 
212 /**
213  * Map an config block index to its corresponding bhnd(4) BHND_PORT_AGENT port
214  * region number.
215  *
216  * @param cfg Config block index.
217  */
218 u_int
219 siba_cfg_agent_region(u_int cfg)
220 {
221 	/* Always agent0.<idx> */
222 	return (cfg);
223 }
224 
225 /**
226  * Return the number of bhnd(4) ports to advertise for the given
227  * @p core_id and @p port_type.
228  *
229  * Refer to the siba_addrspace_index() and siba_cfg_index() functions for
230  * information on siba's mapping of bhnd(4) port and region identifiers.
231  *
232  * @param core_id The siba core info.
233  * @param port_type The bhnd(4) port type.
234  */
235 u_int
236 siba_port_count(struct siba_core_id *core_id, bhnd_port_type port_type)
237 {
238 	switch (port_type) {
239 	case BHND_PORT_DEVICE:
240 		/* 0, 1, or 2 ports */
241 		return (min(core_id->num_addrspace, 2));
242 
243 	case BHND_PORT_AGENT:
244 		/* One agent port maps all configuration blocks */
245 		if (core_id->num_cfg_blocks > 0)
246 			return (1);
247 
248 		/* Do not advertise an agent port if there are no configuration
249 		 * register blocks */
250 		return (0);
251 
252 	default:
253 		return (0);
254 	}
255 }
256 
257 /**
258  * Return true if @p port of @p port_type is defined by @p core_id, false
259  * otherwise.
260  *
261  * @param core_id The siba core info.
262  * @param port_type The bhnd(4) port type.
263  * @param port The bhnd(4) port number.
264  */
265 bool
266 siba_is_port_valid(struct siba_core_id *core_id, bhnd_port_type port_type,
267     u_int port)
268 {
269 	/* Verify the index against the port count */
270 	if (siba_port_count(core_id, port_type) <= port)
271 		return (false);
272 
273 	return (true);
274 }
275 
276 /**
277  * Return the number of bhnd(4) regions to advertise for @p core_id on the
278  * @p port of @p port_type.
279  *
280  * @param core_id The siba core info.
281  * @param port_type The bhnd(4) port type.
282  */
283 u_int
284 siba_port_region_count(struct siba_core_id *core_id, bhnd_port_type port_type,
285     u_int port)
286 {
287 	/* The port must exist */
288 	if (!siba_is_port_valid(core_id, port_type, port))
289 		return (0);
290 
291 	switch (port_type) {
292 	case BHND_PORT_DEVICE:
293 		/* The first address space, if any, is mapped to device0.0 */
294 		if (port == 0)
295 			return (min(core_id->num_addrspace, 1));
296 
297 		/* All remaining address spaces are mapped to device0.(n - 1) */
298 		if (port == 1 && core_id->num_addrspace >= 2)
299 			return (core_id->num_addrspace - 1);
300 
301 		break;
302 
303 	case BHND_PORT_AGENT:
304 		/* All config blocks are mapped to a single port */
305 		if (port == 0)
306 			return (core_id->num_cfg_blocks);
307 
308 		break;
309 
310 	default:
311 		break;
312 	}
313 
314 	/* Validated above */
315 	panic("siba_is_port_valid() returned true for unknown %s.%u port",
316 	    bhnd_port_type_name(port_type), port);
317 
318 }
319 
320 /**
321  * Map a bhnd(4) type/port/region triplet to its associated config block index,
322  * if any.
323  *
324  * We map config registers to port/region identifiers as follows:
325  *
326  * 	[port].[region]	[cfg register block]
327  * 	agent0.0	0
328  * 	agent0.1	1
329  *
330  * @param num_addrspace The number of available siba address spaces.
331  * @param port_type The bhnd(4) port type.
332  * @param port The bhnd(4) port number.
333  * @param region The bhnd(4) port region.
334  * @param addridx On success, the corresponding addrspace index.
335  *
336  * @retval 0 success
337  * @retval ENOENT if the given type/port/region cannot be mapped to a
338  * siba config register block.
339  */
340 int
341 siba_cfg_index(struct siba_core_id *core_id, bhnd_port_type port_type,
342     u_int port, u_int region, u_int *cfgidx)
343 {
344 	/* Config blocks are mapped to agent ports */
345 	if (port_type != BHND_PORT_AGENT)
346 		return (ENOENT);
347 
348 	/* Port must be valid */
349 	if (!siba_is_port_valid(core_id, port_type, port))
350 		return (ENOENT);
351 
352 	if (region >= core_id->num_cfg_blocks)
353 		return (ENOENT);
354 
355 	if (region >= SIBA_MAX_CFG)
356 		return (ENOENT);
357 
358 	/* Found */
359 	*cfgidx = region;
360 	return (0);
361 }
362 
363 /**
364  * Map an bhnd(4) type/port/region triplet to its associated config block
365  * entry, if any.
366  *
367  * The only supported port type is BHND_PORT_DEVICE.
368  *
369  * @param dinfo The device info to search for a matching address space.
370  * @param type The bhnd(4) port type.
371  * @param port The bhnd(4) port number.
372  * @param region The bhnd(4) port region.
373  */
374 struct siba_cfg_block *
375 siba_find_cfg_block(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port,
376     u_int region)
377 {
378 	u_int	cfgidx;
379 	int	error;
380 
381 	/* Map to addrspace index */
382 	error = siba_cfg_index(&dinfo->core_id, type, port, region, &cfgidx);
383 	if (error)
384 		return (NULL);
385 
386 	/* Found */
387 	return (&dinfo->cfg[cfgidx]);
388 }
389 
390 /**
391  * Map a bhnd(4) type/port/region triplet to its associated address space
392  * index, if any.
393  *
394  * For compatibility with bcma(4), we map address spaces to port/region
395  * identifiers as follows:
396  *
397  * 	[port]		[addrspace]
398  * 	device0.0	0
399  * 	device1.0	1
400  * 	device1.1	2
401  * 	device1.2	3
402  *
403  * @param core_id The siba core info.
404  * @param port_type The bhnd(4) port type.
405  * @param port The bhnd(4) port number.
406  * @param region The bhnd(4) port region.
407  * @param addridx On success, the corresponding addrspace index.
408  *
409  * @retval 0 success
410  * @retval ENOENT if the given type/port/region cannot be mapped to a
411  * siba address space.
412  */
413 int
414 siba_addrspace_index(struct siba_core_id *core_id, bhnd_port_type port_type,
415     u_int port, u_int region, u_int *addridx)
416 {
417 	u_int idx;
418 
419 	/* Address spaces are always device ports */
420 	if (port_type != BHND_PORT_DEVICE)
421 		return (ENOENT);
422 
423 	/* Port must be valid */
424 	if (!siba_is_port_valid(core_id, port_type, port))
425 		return (ENOENT);
426 
427 	if (port == 0)
428 		idx = region;
429 	else if (port == 1)
430 		idx = region + 1;
431 	else
432 		return (ENOENT);
433 
434 	if (idx >= core_id->num_addrspace)
435 		return (ENOENT);
436 
437 	/* Found */
438 	*addridx = idx;
439 	return (0);
440 }
441 
442 /**
443  * Map an bhnd(4) type/port/region triplet to its associated address space
444  * entry, if any.
445  *
446  * The only supported port type is BHND_PORT_DEVICE.
447  *
448  * @param dinfo The device info to search for a matching address space.
449  * @param type The bhnd(4) port type.
450  * @param port The bhnd(4) port number.
451  * @param region The bhnd(4) port region.
452  */
453 struct siba_addrspace *
454 siba_find_addrspace(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port,
455     u_int region)
456 {
457 	u_int	addridx;
458 	int	error;
459 
460 	/* Map to addrspace index */
461 	error = siba_addrspace_index(&dinfo->core_id, type, port, region,
462 	    &addridx);
463 	if (error)
464 		return (NULL);
465 
466 	/* Found */
467 	if (addridx >= SIBA_MAX_ADDRSPACE)
468 		return (NULL);
469 
470 	return (&dinfo->addrspace[addridx]);
471 }
472 
473 /**
474  * Append an address space entry to @p dinfo.
475  *
476  * @param dinfo The device info entry to update.
477  * @param addridx The address space index.
478  * @param base The mapping's base address.
479  * @param size The mapping size.
480  * @param bus_reserved Number of bytes to reserve in @p size for bus use
481  * when registering the resource list entry. This is used to reserve bus
482  * access to the core's SIBA_CFG* register blocks.
483  *
484  * @retval 0 success
485  * @retval non-zero An error occurred appending the entry.
486  */
487 int
488 siba_append_dinfo_region(struct siba_devinfo *dinfo, uint8_t addridx,
489     uint32_t base, uint32_t size, uint32_t bus_reserved)
490 {
491 	struct siba_addrspace	*sa;
492 	rman_res_t		 r_size;
493 
494 	/* Verify that base + size will not overflow */
495 	if (size > 0 && UINT32_MAX - (size - 1) < base)
496 		return (ERANGE);
497 
498 	/* Verify that size - bus_reserved will not underflow */
499 	if (size < bus_reserved)
500 		return (ERANGE);
501 
502 	/* Must not be 0-length */
503 	if (size == 0)
504 		return (EINVAL);
505 
506 	/* Must not exceed addrspace array size */
507 	if (addridx >= nitems(dinfo->addrspace))
508 		return (EINVAL);
509 
510 	/* Initialize new addrspace entry */
511 	sa = &dinfo->addrspace[addridx];
512 	sa->sa_base = base;
513 	sa->sa_size = size;
514 	sa->sa_bus_reserved = bus_reserved;
515 
516 	/* Populate the resource list */
517 	r_size = size - bus_reserved;
518 	sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY,
519 	    base, base + (r_size - 1), r_size);
520 
521 	return (0);
522 }
523 
524 /**
525  * Deallocate the given device info structure and any associated resources.
526  *
527  * @param dev The requesting bus device.
528  * @param child The siba child device.
529  * @param dinfo Device info associated with @p child to be deallocated.
530  */
531 void
532 siba_free_dinfo(device_t dev, device_t child, struct siba_devinfo *dinfo)
533 {
534 	resource_list_free(&dinfo->resources);
535 
536 	/* Free all mapped configuration blocks */
537 	for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
538 		if (dinfo->cfg_res[i] == NULL)
539 			continue;
540 
541 		bhnd_release_resource(dev, SYS_RES_MEMORY, dinfo->cfg_rid[i],
542 		    dinfo->cfg_res[i]);
543 
544 		dinfo->cfg_res[i] = NULL;
545 		dinfo->cfg_rid[i] = -1;
546 	}
547 
548 	/* Unmap the core's interrupt */
549 	if (dinfo->intr_en && dinfo->intr.mapped) {
550 		BHND_BUS_UNMAP_INTR(dev, child, dinfo->intr.irq);
551 		dinfo->intr.mapped = false;
552 	}
553 
554 	free(dinfo, M_BHND);
555 }
556 
557 /**
558  * Return the core-enumeration-relative offset for the @p addrspace
559  * SIBA_R0_ADMATCH* register.
560  *
561  * @param addrspace The address space index.
562  *
563  * @retval non-zero success
564  * @retval 0 the given @p addrspace index is not supported.
565  */
566 u_int
567 siba_admatch_offset(uint8_t addrspace)
568 {
569 	switch (addrspace) {
570 	case 0:
571 		return SB0_REG_ABS(SIBA_CFG0_ADMATCH0);
572 	case 1:
573 		return SB0_REG_ABS(SIBA_CFG0_ADMATCH1);
574 	case 2:
575 		return SB0_REG_ABS(SIBA_CFG0_ADMATCH2);
576 	case 3:
577 		return SB0_REG_ABS(SIBA_CFG0_ADMATCH3);
578 	default:
579 		return (0);
580 	}
581 }
582 
583 /**
584  * Parse a SIBA_R0_ADMATCH* register.
585  *
586  * @param addrspace The address space index.
587  * @param am The address match register value to be parsed.
588  * @param[out] addr The parsed address.
589  * @param[out] size The parsed size.
590  *
591  * @retval 0 success
592  * @retval non-zero a parse error occurred.
593  */
594 int
595 siba_parse_admatch(uint32_t am, uint32_t *addr, uint32_t *size)
596 {
597 	u_int		am_type;
598 
599 	/* Negative encoding is not supported. This is not used on any
600 	 * currently known devices*/
601 	if (am & SIBA_AM_ADNEG)
602 		return (EINVAL);
603 
604 	/* Extract the base address and size */
605 	am_type = SIBA_REG_GET(am, AM_TYPE);
606 	switch (am_type) {
607 	case 0:
608 		*addr = am & SIBA_AM_BASE0_MASK;
609 		*size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1);
610 		break;
611 	case 1:
612 		*addr = am & SIBA_AM_BASE1_MASK;
613 		*size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1);
614 		break;
615 	case 2:
616 		*addr = am & SIBA_AM_BASE2_MASK;
617 		*size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1);
618 		break;
619 	default:
620 		return (EINVAL);
621 	}
622 
623 	return (0);
624 }
625 
626 /**
627  * Write @p value to @p dev's CFG0 target/initiator state register, performing
628  * required read-back and waiting for completion.
629  *
630  * @param dev The siba(4) child device.
631  * @param reg The CFG0 state register to write (e.g. SIBA_CFG0_TMSTATELOW,
632  * SIBA_CFG0_IMSTATE)
633  * @param value The value to write to @p reg.
634  * @param mask The mask of bits to be included from @p value.
635  */
636 void
637 siba_write_target_state(device_t dev, struct siba_devinfo *dinfo,
638     bus_size_t reg, uint32_t value, uint32_t mask)
639 {
640 	struct bhnd_resource	*r;
641 	uint32_t		 rval;
642 
643 	r = dinfo->cfg_res[0];
644 
645 	KASSERT(r != NULL, ("%s missing CFG0 mapping",
646 	    device_get_nameunit(dev)));
647 	KASSERT(reg <= SIBA_CFG_SIZE-4, ("%s invalid CFG0 register offset %#jx",
648 	    device_get_nameunit(dev), (uintmax_t)reg));
649 
650 	rval = bhnd_bus_read_4(r, reg);
651 	rval &= ~mask;
652 	rval |= (value & mask);
653 
654 	bhnd_bus_write_4(r, reg, rval);
655 	bhnd_bus_read_4(r, reg); /* read-back */
656 	DELAY(1);
657 }
658 
659 /**
660  * Spin for up to @p usec waiting for @p dev's CFG0 target/initiator state
661  * register value to be equal to @p value after applying @p mask bits to both
662  * values.
663  *
664  * @param dev The siba(4) child device to wait on.
665  * @param dinfo The @p dev's device info
666  * @param reg The state register to read (e.g. SIBA_CFG0_TMSTATEHIGH,
667  * SIBA_CFG0_IMSTATE)
668  * @param value The value against which @p reg will be compared.
669  * @param mask The mask to be applied when comparing @p value with @p reg.
670  * @param usec The maximum number of microseconds to wait for completion.
671  *
672  * @retval 0 if SIBA_TMH_BUSY is cleared prior to the @p usec timeout.
673  * @retval ENODEV if SIBA_CFG0 is not mapped by @p dinfo.
674  * @retval ETIMEDOUT if a timeout occurs.
675  */
676 int
677 siba_wait_target_state(device_t dev, struct siba_devinfo *dinfo, bus_size_t reg,
678     uint32_t value, uint32_t mask, u_int usec)
679 {
680 	struct bhnd_resource	*r;
681 	uint32_t		 rval;
682 
683 	if ((r = dinfo->cfg_res[0]) == NULL)
684 		return (ENODEV);
685 
686 	value &= mask;
687 	for (int i = 0; i < usec; i += 10) {
688 		rval = bhnd_bus_read_4(r, reg);
689 		if ((rval & mask) == value)
690 			return (0);
691 
692 		DELAY(10);
693 	}
694 
695 	return (ETIMEDOUT);
696 }
697