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/param.h>
35 #include <sys/bus.h>
36 #include <sys/kernel.h>
37 #include <sys/limits.h>
38 #include <sys/systm.h>
39
40 #include <machine/bus.h>
41 #include <machine/resource.h>
42
43 #include <dev/bhnd/bhndvar.h>
44
45 #include "sibareg.h"
46 #include "sibavar.h"
47
48 static int siba_register_interrupts(device_t dev, device_t child,
49 struct siba_devinfo *dinfo);
50 static int siba_append_dinfo_region(struct siba_devinfo *dinfo,
51 uint8_t addridx, uint32_t base, uint32_t size,
52 uint32_t bus_reserved);
53
54 /**
55 * Map a siba(4) OCP vendor code to its corresponding JEDEC JEP-106 vendor
56 * code.
57 *
58 * @param ocp_vendor An OCP vendor code.
59 * @return The BHND_MFGID constant corresponding to @p ocp_vendor, or
60 * BHND_MFGID_INVALID if the OCP vendor is unknown.
61 */
62 uint16_t
siba_get_bhnd_mfgid(uint16_t ocp_vendor)63 siba_get_bhnd_mfgid(uint16_t ocp_vendor)
64 {
65 switch (ocp_vendor) {
66 case OCP_VENDOR_BCM:
67 return (BHND_MFGID_BCM);
68 default:
69 return (BHND_MFGID_INVALID);
70 }
71 }
72
73 /**
74 * Allocate and return a new empty device info structure.
75 *
76 * @param bus The requesting bus device.
77 *
78 * @retval NULL if allocation failed.
79 */
80 struct siba_devinfo *
siba_alloc_dinfo(device_t bus)81 siba_alloc_dinfo(device_t bus)
82 {
83 struct siba_devinfo *dinfo;
84
85 dinfo = malloc(sizeof(struct siba_devinfo), M_BHND, M_NOWAIT|M_ZERO);
86 if (dinfo == NULL)
87 return NULL;
88
89 for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
90 dinfo->cfg[i] = ((struct siba_cfg_block){
91 .cb_base = 0,
92 .cb_size = 0,
93 .cb_rid = -1,
94 });
95 dinfo->cfg_res[i] = NULL;
96 dinfo->cfg_rid[i] = -1;
97 }
98
99 resource_list_init(&dinfo->resources);
100
101 dinfo->pmu_state = SIBA_PMU_NONE;
102
103 dinfo->intr = (struct siba_intr) {
104 .mapped = false,
105 .rid = -1
106 };
107
108 return dinfo;
109 }
110
111 /**
112 * Initialize a device info structure previously allocated via
113 * siba_alloc_dinfo, copying the provided core id.
114 *
115 * @param dev The requesting bus device.
116 * @param child The siba child device.
117 * @param dinfo The device info instance.
118 * @param core Device core info.
119 *
120 * @retval 0 success
121 * @retval non-zero initialization failed.
122 */
123 int
siba_init_dinfo(device_t dev,device_t child,struct siba_devinfo * dinfo,const struct siba_core_id * core_id)124 siba_init_dinfo(device_t dev, device_t child, struct siba_devinfo *dinfo,
125 const struct siba_core_id *core_id)
126 {
127 int error;
128
129 dinfo->core_id = *core_id;
130
131 /* Register all address space mappings */
132 for (uint8_t i = 0; i < core_id->num_admatch; i++) {
133 uint32_t bus_reserved;
134
135 /* If this is the device's core/enumeration addrespace,
136 * reserve the Sonics configuration register blocks for the
137 * use of our bus. */
138 bus_reserved = 0;
139 if (i == SIBA_CORE_ADDRSPACE)
140 bus_reserved = core_id->num_cfg_blocks * SIBA_CFG_SIZE;
141
142 /* Append the region info */
143 error = siba_append_dinfo_region(dinfo, i,
144 core_id->admatch[i].am_base, core_id->admatch[i].am_size,
145 bus_reserved);
146 if (error)
147 return (error);
148 }
149
150 /* Register all interrupt(s) */
151 if ((error = siba_register_interrupts(dev, child, dinfo)))
152 return (error);
153
154 return (0);
155 }
156
157 /**
158 * Register and map all interrupts for @p dinfo.
159 *
160 * @param dev The siba bus device.
161 * @param child The siba child device.
162 * @param dinfo The device info instance on which to register all interrupt
163 * entries.
164 */
165 static int
siba_register_interrupts(device_t dev,device_t child,struct siba_devinfo * dinfo)166 siba_register_interrupts(device_t dev, device_t child,
167 struct siba_devinfo *dinfo)
168 {
169 int error;
170
171 /* Is backplane interrupt distribution enabled for this core? */
172 if (!dinfo->core_id.intr_en)
173 return (0);
174
175 /* Have one interrupt */
176 dinfo->intr.mapped = false;
177 dinfo->intr.irq = 0;
178 dinfo->intr.rid = -1;
179
180 /* Map the interrupt */
181 error = BHND_BUS_MAP_INTR(dev, child, 0 /* single intr is always 0 */,
182 &dinfo->intr.irq);
183 if (error) {
184 device_printf(dev, "failed mapping interrupt line for core %u: "
185 "%d\n", dinfo->core_id.core_info.core_idx, error);
186 return (error);
187 }
188 dinfo->intr.mapped = true;
189
190 /* Update the resource list */
191 dinfo->intr.rid = resource_list_add_next(&dinfo->resources, SYS_RES_IRQ,
192 dinfo->intr.irq, dinfo->intr.irq, 1);
193
194 return (0);
195 }
196
197 /**
198 * Map an addrspace index to its corresponding bhnd(4) BHND_PORT_DEVICE port
199 * number.
200 *
201 * @param addrspace Address space index.
202 */
203 u_int
siba_addrspace_device_port(u_int addrspace)204 siba_addrspace_device_port(u_int addrspace)
205 {
206 /* The first addrspace is always mapped to device0; the remainder
207 * are mapped to device1 */
208 if (addrspace == 0)
209 return (0);
210 else
211 return (1);
212 }
213
214 /**
215 * Map an addrspace index to its corresponding bhnd(4) BHND_PORT_DEVICE port
216 * region number.
217 *
218 * @param addrspace Address space index.
219 */
220 u_int
siba_addrspace_device_region(u_int addrspace)221 siba_addrspace_device_region(u_int addrspace)
222 {
223 /* The first addrspace is always mapped to device0.0; the remainder
224 * are mapped to device1.0 + (n - 1) */
225 if (addrspace == 0)
226 return (0);
227 else
228 return (addrspace - 1);
229 }
230
231 /**
232 * Map an config block index to its corresponding bhnd(4) BHND_PORT_AGENT port
233 * number.
234 *
235 * @param cfg Config block index.
236 */
237 u_int
siba_cfg_agent_port(u_int cfg)238 siba_cfg_agent_port(u_int cfg)
239 {
240 /* Always agent0 */
241 return (0);
242 }
243
244 /**
245 * Map an config block index to its corresponding bhnd(4) BHND_PORT_AGENT port
246 * region number.
247 *
248 * @param cfg Config block index.
249 */
250 u_int
siba_cfg_agent_region(u_int cfg)251 siba_cfg_agent_region(u_int cfg)
252 {
253 /* Always agent0.<idx> */
254 return (cfg);
255 }
256
257 /**
258 * Return the number of bhnd(4) ports to advertise for the given
259 * @p core_id and @p port_type.
260 *
261 * Refer to the siba_addrspace_index() and siba_cfg_index() functions for
262 * information on siba's mapping of bhnd(4) port and region identifiers.
263 *
264 * @param core_id The siba core info.
265 * @param port_type The bhnd(4) port type.
266 */
267 u_int
siba_port_count(struct siba_core_id * core_id,bhnd_port_type port_type)268 siba_port_count(struct siba_core_id *core_id, bhnd_port_type port_type)
269 {
270 switch (port_type) {
271 case BHND_PORT_DEVICE:
272 /* 0, 1, or 2 ports */
273 return (min(core_id->num_admatch, 2));
274
275 case BHND_PORT_AGENT:
276 /* One agent port maps all configuration blocks */
277 if (core_id->num_cfg_blocks > 0)
278 return (1);
279
280 /* Do not advertise an agent port if there are no configuration
281 * register blocks */
282 return (0);
283
284 default:
285 return (0);
286 }
287 }
288
289 /**
290 * Return true if @p port of @p port_type is defined by @p core_id, false
291 * otherwise.
292 *
293 * @param core_id The siba core info.
294 * @param port_type The bhnd(4) port type.
295 * @param port The bhnd(4) port number.
296 */
297 bool
siba_is_port_valid(struct siba_core_id * core_id,bhnd_port_type port_type,u_int port)298 siba_is_port_valid(struct siba_core_id *core_id, bhnd_port_type port_type,
299 u_int port)
300 {
301 /* Verify the index against the port count */
302 if (siba_port_count(core_id, port_type) <= port)
303 return (false);
304
305 return (true);
306 }
307
308 /**
309 * Return the number of bhnd(4) regions to advertise for @p core_id on the
310 * @p port of @p port_type.
311 *
312 * @param core_id The siba core info.
313 * @param port_type The bhnd(4) port type.
314 */
315 u_int
siba_port_region_count(struct siba_core_id * core_id,bhnd_port_type port_type,u_int port)316 siba_port_region_count(struct siba_core_id *core_id, bhnd_port_type port_type,
317 u_int port)
318 {
319 /* The port must exist */
320 if (!siba_is_port_valid(core_id, port_type, port))
321 return (0);
322
323 switch (port_type) {
324 case BHND_PORT_DEVICE:
325 /* The first address space, if any, is mapped to device0.0 */
326 if (port == 0)
327 return (min(core_id->num_admatch, 1));
328
329 /* All remaining address spaces are mapped to device0.(n - 1) */
330 if (port == 1 && core_id->num_admatch >= 2)
331 return (core_id->num_admatch - 1);
332
333 break;
334
335 case BHND_PORT_AGENT:
336 /* All config blocks are mapped to a single port */
337 if (port == 0)
338 return (core_id->num_cfg_blocks);
339
340 break;
341
342 default:
343 break;
344 }
345
346 /* Validated above */
347 panic("siba_is_port_valid() returned true for unknown %s.%u port",
348 bhnd_port_type_name(port_type), port);
349
350 }
351
352 /**
353 * Map a bhnd(4) type/port/region triplet to its associated config block index,
354 * if any.
355 *
356 * We map config registers to port/region identifiers as follows:
357 *
358 * [port].[region] [cfg register block]
359 * agent0.0 0
360 * agent0.1 1
361 *
362 * @param port_type The bhnd(4) port type.
363 * @param port The bhnd(4) port number.
364 * @param region The bhnd(4) port region.
365 * @param addridx On success, the corresponding addrspace index.
366 *
367 * @retval 0 success
368 * @retval ENOENT if the given type/port/region cannot be mapped to a
369 * siba config register block.
370 */
371 int
siba_cfg_index(struct siba_core_id * core_id,bhnd_port_type port_type,u_int port,u_int region,u_int * cfgidx)372 siba_cfg_index(struct siba_core_id *core_id, bhnd_port_type port_type,
373 u_int port, u_int region, u_int *cfgidx)
374 {
375 /* Config blocks are mapped to agent ports */
376 if (port_type != BHND_PORT_AGENT)
377 return (ENOENT);
378
379 /* Port must be valid */
380 if (!siba_is_port_valid(core_id, port_type, port))
381 return (ENOENT);
382
383 if (region >= core_id->num_cfg_blocks)
384 return (ENOENT);
385
386 if (region >= SIBA_MAX_CFG)
387 return (ENOENT);
388
389 /* Found */
390 *cfgidx = region;
391 return (0);
392 }
393
394 /**
395 * Map an bhnd(4) type/port/region triplet to its associated config block
396 * entry, if any.
397 *
398 * The only supported port type is BHND_PORT_DEVICE.
399 *
400 * @param dinfo The device info to search for a matching address space.
401 * @param type The bhnd(4) port type.
402 * @param port The bhnd(4) port number.
403 * @param region The bhnd(4) port region.
404 */
405 struct siba_cfg_block *
siba_find_cfg_block(struct siba_devinfo * dinfo,bhnd_port_type type,u_int port,u_int region)406 siba_find_cfg_block(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port,
407 u_int region)
408 {
409 u_int cfgidx;
410 int error;
411
412 /* Map to addrspace index */
413 error = siba_cfg_index(&dinfo->core_id, type, port, region, &cfgidx);
414 if (error)
415 return (NULL);
416
417 /* Found */
418 return (&dinfo->cfg[cfgidx]);
419 }
420
421 /**
422 * Map a bhnd(4) type/port/region triplet to its associated address space
423 * index, if any.
424 *
425 * For compatibility with bcma(4), we map address spaces to port/region
426 * identifiers as follows:
427 *
428 * [port.region] [admatch index]
429 * device0.0 0
430 * device1.0 1
431 * device1.1 2
432 * device1.2 3
433 *
434 * @param core_id The siba core info.
435 * @param port_type The bhnd(4) port type.
436 * @param port The bhnd(4) port number.
437 * @param region The bhnd(4) port region.
438 * @param addridx On success, the corresponding addrspace index.
439 *
440 * @retval 0 success
441 * @retval ENOENT if the given type/port/region cannot be mapped to a
442 * siba address space.
443 */
444 int
siba_addrspace_index(struct siba_core_id * core_id,bhnd_port_type port_type,u_int port,u_int region,u_int * addridx)445 siba_addrspace_index(struct siba_core_id *core_id, bhnd_port_type port_type,
446 u_int port, u_int region, u_int *addridx)
447 {
448 u_int idx;
449
450 /* Address spaces are always device ports */
451 if (port_type != BHND_PORT_DEVICE)
452 return (ENOENT);
453
454 /* Port must be valid */
455 if (!siba_is_port_valid(core_id, port_type, port))
456 return (ENOENT);
457
458 if (port == 0)
459 idx = region;
460 else if (port == 1)
461 idx = region + 1;
462 else
463 return (ENOENT);
464
465 if (idx >= core_id->num_admatch)
466 return (ENOENT);
467
468 /* Found */
469 *addridx = idx;
470 return (0);
471 }
472
473 /**
474 * Map an bhnd(4) type/port/region triplet to its associated address space
475 * entry, if any.
476 *
477 * The only supported port type is BHND_PORT_DEVICE.
478 *
479 * @param dinfo The device info to search for a matching address space.
480 * @param type The bhnd(4) port type.
481 * @param port The bhnd(4) port number.
482 * @param region The bhnd(4) port region.
483 */
484 struct siba_addrspace *
siba_find_addrspace(struct siba_devinfo * dinfo,bhnd_port_type type,u_int port,u_int region)485 siba_find_addrspace(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port,
486 u_int region)
487 {
488 u_int addridx;
489 int error;
490
491 /* Map to addrspace index */
492 error = siba_addrspace_index(&dinfo->core_id, type, port, region,
493 &addridx);
494 if (error)
495 return (NULL);
496
497 /* Found */
498 if (addridx >= SIBA_MAX_ADDRSPACE)
499 return (NULL);
500
501 return (&dinfo->addrspace[addridx]);
502 }
503
504 /**
505 * Append an address space entry to @p dinfo.
506 *
507 * @param dinfo The device info entry to update.
508 * @param addridx The address space index.
509 * @param base The mapping's base address.
510 * @param size The mapping size.
511 * @param bus_reserved Number of bytes to reserve in @p size for bus use
512 * when registering the resource list entry. This is used to reserve bus
513 * access to the core's SIBA_CFG* register blocks.
514 *
515 * @retval 0 success
516 * @retval non-zero An error occurred appending the entry.
517 */
518 static int
siba_append_dinfo_region(struct siba_devinfo * dinfo,uint8_t addridx,uint32_t base,uint32_t size,uint32_t bus_reserved)519 siba_append_dinfo_region(struct siba_devinfo *dinfo, uint8_t addridx,
520 uint32_t base, uint32_t size, uint32_t bus_reserved)
521 {
522 struct siba_addrspace *sa;
523 rman_res_t r_size;
524
525 /* Verify that base + size will not overflow */
526 if (size > 0 && UINT32_MAX - (size - 1) < base)
527 return (ERANGE);
528
529 /* Verify that size - bus_reserved will not underflow */
530 if (size < bus_reserved)
531 return (ERANGE);
532
533 /* Must not be 0-length */
534 if (size == 0)
535 return (EINVAL);
536
537 /* Must not exceed addrspace array size */
538 if (addridx >= nitems(dinfo->addrspace))
539 return (EINVAL);
540
541 /* Initialize new addrspace entry */
542 sa = &dinfo->addrspace[addridx];
543 sa->sa_base = base;
544 sa->sa_size = size;
545 sa->sa_bus_reserved = bus_reserved;
546
547 /* Populate the resource list */
548 r_size = size - bus_reserved;
549 sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY,
550 base, base + (r_size - 1), r_size);
551
552 return (0);
553 }
554
555 /**
556 * Deallocate the given device info structure and any associated resources.
557 *
558 * @param dev The requesting bus device.
559 * @param child The siba child device.
560 * @param dinfo Device info associated with @p child to be deallocated.
561 */
562 void
siba_free_dinfo(device_t dev,device_t child,struct siba_devinfo * dinfo)563 siba_free_dinfo(device_t dev, device_t child, struct siba_devinfo *dinfo)
564 {
565 resource_list_free(&dinfo->resources);
566
567 /* Free all mapped configuration blocks */
568 for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
569 if (dinfo->cfg_res[i] == NULL)
570 continue;
571
572 bhnd_release_resource(dev, SYS_RES_MEMORY, dinfo->cfg_rid[i],
573 dinfo->cfg_res[i]);
574
575 dinfo->cfg_res[i] = NULL;
576 dinfo->cfg_rid[i] = -1;
577 }
578
579 /* Unmap the core's interrupt */
580 if (dinfo->core_id.intr_en && dinfo->intr.mapped) {
581 BHND_BUS_UNMAP_INTR(dev, child, dinfo->intr.irq);
582 dinfo->intr.mapped = false;
583 }
584
585 free(dinfo, M_BHND);
586 }
587
588 /**
589 * Return the core-enumeration-relative offset for the @p addrspace
590 * SIBA_R0_ADMATCH* register.
591 *
592 * @param addrspace The address space index.
593 *
594 * @retval non-zero success
595 * @retval 0 the given @p addrspace index is not supported.
596 */
597 u_int
siba_admatch_offset(uint8_t addrspace)598 siba_admatch_offset(uint8_t addrspace)
599 {
600 switch (addrspace) {
601 case 0:
602 return SB0_REG_ABS(SIBA_CFG0_ADMATCH0);
603 case 1:
604 return SB0_REG_ABS(SIBA_CFG0_ADMATCH1);
605 case 2:
606 return SB0_REG_ABS(SIBA_CFG0_ADMATCH2);
607 case 3:
608 return SB0_REG_ABS(SIBA_CFG0_ADMATCH3);
609 default:
610 return (0);
611 }
612 }
613
614 /**
615 * Parse a SIBA_R0_ADMATCH* register.
616 *
617 * @param addrspace The address space index.
618 * @param am The address match register value to be parsed.
619 * @param[out] admatch The parsed address match descriptor
620 *
621 * @retval 0 success
622 * @retval non-zero a parse error occurred.
623 */
624 int
siba_parse_admatch(uint32_t am,struct siba_admatch * admatch)625 siba_parse_admatch(uint32_t am, struct siba_admatch *admatch)
626 {
627 u_int am_type;
628
629 /* Extract the base address and size */
630 am_type = SIBA_REG_GET(am, AM_TYPE);
631 switch (am_type) {
632 case 0:
633 /* Type 0 entries are always enabled, and do not support
634 * negative matching */
635 admatch->am_base = am & SIBA_AM_BASE0_MASK;
636 admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1);
637 admatch->am_enabled = true;
638 admatch->am_negative = false;
639 break;
640 case 1:
641 admatch->am_base = am & SIBA_AM_BASE1_MASK;
642 admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1);
643 admatch->am_enabled = ((am & SIBA_AM_ADEN) != 0);
644 admatch->am_negative = ((am & SIBA_AM_ADNEG) != 0);
645 break;
646 case 2:
647 admatch->am_base = am & SIBA_AM_BASE2_MASK;
648 admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1);
649 admatch->am_enabled = ((am & SIBA_AM_ADEN) != 0);
650 admatch->am_negative = ((am & SIBA_AM_ADNEG) != 0);
651 break;
652 default:
653 return (EINVAL);
654 }
655
656 return (0);
657 }
658
659 /**
660 * Write @p value to @p dev's CFG0 target/initiator state register, performing
661 * required read-back and waiting for completion.
662 *
663 * @param dev The siba(4) child device.
664 * @param reg The CFG0 state register to write (e.g. SIBA_CFG0_TMSTATELOW,
665 * SIBA_CFG0_IMSTATE)
666 * @param value The value to write to @p reg.
667 * @param mask The mask of bits to be included from @p value.
668 */
669 void
siba_write_target_state(device_t dev,struct siba_devinfo * dinfo,bus_size_t reg,uint32_t value,uint32_t mask)670 siba_write_target_state(device_t dev, struct siba_devinfo *dinfo,
671 bus_size_t reg, uint32_t value, uint32_t mask)
672 {
673 struct bhnd_resource *r;
674 uint32_t rval;
675
676 r = dinfo->cfg_res[0];
677
678 KASSERT(r != NULL, ("%s missing CFG0 mapping",
679 device_get_nameunit(dev)));
680 KASSERT(reg <= SIBA_CFG_SIZE-4, ("%s invalid CFG0 register offset %#jx",
681 device_get_nameunit(dev), (uintmax_t)reg));
682
683 rval = bhnd_bus_read_4(r, reg);
684 rval &= ~mask;
685 rval |= (value & mask);
686
687 bhnd_bus_write_4(r, reg, rval);
688 bhnd_bus_read_4(r, reg); /* read-back */
689 DELAY(1);
690 }
691
692 /**
693 * Spin for up to @p usec waiting for @p dev's CFG0 target/initiator state
694 * register value to be equal to @p value after applying @p mask bits to both
695 * values.
696 *
697 * @param dev The siba(4) child device to wait on.
698 * @param dinfo The @p dev's device info
699 * @param reg The state register to read (e.g. SIBA_CFG0_TMSTATEHIGH,
700 * SIBA_CFG0_IMSTATE)
701 * @param value The value against which @p reg will be compared.
702 * @param mask The mask to be applied when comparing @p value with @p reg.
703 * @param usec The maximum number of microseconds to wait for completion.
704 *
705 * @retval 0 if SIBA_TMH_BUSY is cleared prior to the @p usec timeout.
706 * @retval ENODEV if SIBA_CFG0 is not mapped by @p dinfo.
707 * @retval ETIMEDOUT if a timeout occurs.
708 */
709 int
siba_wait_target_state(device_t dev,struct siba_devinfo * dinfo,bus_size_t reg,uint32_t value,uint32_t mask,u_int usec)710 siba_wait_target_state(device_t dev, struct siba_devinfo *dinfo, bus_size_t reg,
711 uint32_t value, uint32_t mask, u_int usec)
712 {
713 struct bhnd_resource *r;
714 uint32_t rval;
715
716 if ((r = dinfo->cfg_res[0]) == NULL)
717 return (ENODEV);
718
719 value &= mask;
720 for (int i = 0; i < usec; i += 10) {
721 rval = bhnd_bus_read_4(r, reg);
722 if ((rval & mask) == value)
723 return (0);
724
725 DELAY(10);
726 }
727
728 return (ETIMEDOUT);
729 }
730