]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/bhnd/siba/siba.c
Update DTS files from Linux 4.12
[FreeBSD/FreeBSD.git] / sys / dev / bhnd / siba / siba.c
1 /*-
2  * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38 #include <sys/systm.h>
39
40 #include <machine/bus.h>
41
42 #include <dev/bhnd/cores/chipc/chipcreg.h>
43 #include <dev/bhnd/cores/pmu/bhnd_pmu.h>
44
45 #include "sibareg.h"
46 #include "sibavar.h"
47
48 static bhnd_erom_class_t *
49 siba_get_erom_class(driver_t *driver)
50 {
51         return (&siba_erom_parser);
52 }
53
54 int
55 siba_probe(device_t dev)
56 {
57         device_set_desc(dev, "SIBA BHND bus");
58         return (BUS_PROBE_DEFAULT);
59 }
60
61 /**
62  * Default siba(4) bus driver implementation of DEVICE_ATTACH().
63  * 
64  * This implementation initializes internal siba(4) state and performs
65  * bus enumeration, and must be called by subclassing drivers in
66  * DEVICE_ATTACH() before any other bus methods.
67  */
68 int
69 siba_attach(device_t dev)
70 {
71         struct siba_softc       *sc;
72         int                      error;
73
74         sc = device_get_softc(dev);
75         sc->dev = dev;
76
77         /* Enumerate children */
78         if ((error = siba_add_children(dev))) {
79                 device_delete_children(dev);
80                 return (error);
81         }
82
83         return (0);
84 }
85
86 int
87 siba_detach(device_t dev)
88 {
89         return (bhnd_generic_detach(dev));
90 }
91
92 int
93 siba_resume(device_t dev)
94 {
95         return (bhnd_generic_resume(dev));
96 }
97
98 int
99 siba_suspend(device_t dev)
100 {
101         return (bhnd_generic_suspend(dev));
102 }
103
104 static int
105 siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
106 {
107         const struct siba_devinfo *dinfo;
108         const struct bhnd_core_info *cfg;
109         
110         dinfo = device_get_ivars(child);
111         cfg = &dinfo->core_id.core_info;
112         
113         switch (index) {
114         case BHND_IVAR_VENDOR:
115                 *result = cfg->vendor;
116                 return (0);
117         case BHND_IVAR_DEVICE:
118                 *result = cfg->device;
119                 return (0);
120         case BHND_IVAR_HWREV:
121                 *result = cfg->hwrev;
122                 return (0);
123         case BHND_IVAR_DEVICE_CLASS:
124                 *result = bhnd_core_class(cfg);
125                 return (0);
126         case BHND_IVAR_VENDOR_NAME:
127                 *result = (uintptr_t) bhnd_vendor_name(cfg->vendor);
128                 return (0);
129         case BHND_IVAR_DEVICE_NAME:
130                 *result = (uintptr_t) bhnd_core_name(cfg);
131                 return (0);
132         case BHND_IVAR_CORE_INDEX:
133                 *result = cfg->core_idx;
134                 return (0);
135         case BHND_IVAR_CORE_UNIT:
136                 *result = cfg->unit;
137                 return (0);
138         case BHND_IVAR_PMU_INFO:
139                 *result = (uintptr_t) dinfo->pmu_info;
140                 return (0);
141         default:
142                 return (ENOENT);
143         }
144 }
145
146 static int
147 siba_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
148 {
149         struct siba_devinfo *dinfo;
150
151         dinfo = device_get_ivars(child);
152
153         switch (index) {
154         case BHND_IVAR_VENDOR:
155         case BHND_IVAR_DEVICE:
156         case BHND_IVAR_HWREV:
157         case BHND_IVAR_DEVICE_CLASS:
158         case BHND_IVAR_VENDOR_NAME:
159         case BHND_IVAR_DEVICE_NAME:
160         case BHND_IVAR_CORE_INDEX:
161         case BHND_IVAR_CORE_UNIT:
162                 return (EINVAL);
163         case BHND_IVAR_PMU_INFO:
164                 dinfo->pmu_info = (struct bhnd_core_pmu_info *) value;
165                 return (0);
166         default:
167                 return (ENOENT);
168         }
169 }
170
171 static struct resource_list *
172 siba_get_resource_list(device_t dev, device_t child)
173 {
174         struct siba_devinfo *dinfo = device_get_ivars(child);
175         return (&dinfo->resources);
176 }
177
178 static int
179 siba_read_iost(device_t dev, device_t child, uint16_t *iost)
180 {
181         uint32_t        tmhigh;
182         int             error;
183
184         error = bhnd_read_config(child, SIBA_CFG0_TMSTATEHIGH, &tmhigh, 4);
185         if (error)
186                 return (error);
187
188         *iost = (SIBA_REG_GET(tmhigh, TMH_SISF));
189         return (0);
190 }
191
192 static int
193 siba_read_ioctl(device_t dev, device_t child, uint16_t *ioctl)
194 {
195         uint32_t        ts_low;
196         int             error;
197
198         if ((error = bhnd_read_config(child, SIBA_CFG0_TMSTATELOW, &ts_low, 4)))
199                 return (error);
200
201         *ioctl = (SIBA_REG_GET(ts_low, TML_SICF));
202         return (0);
203 }
204
205 static int
206 siba_write_ioctl(device_t dev, device_t child, uint16_t value, uint16_t mask)
207 {
208         struct siba_devinfo     *dinfo;
209         struct bhnd_resource    *r;
210         uint32_t                 ts_low, ts_mask;
211
212         if (device_get_parent(child) != dev)
213                 return (EINVAL);
214
215         /* Fetch CFG0 mapping */
216         dinfo = device_get_ivars(child);
217         if ((r = dinfo->cfg[0]) == NULL)
218                 return (ENODEV);
219
220         /* Mask and set TMSTATELOW core flag bits */
221         ts_mask = (mask << SIBA_TML_SICF_SHIFT) & SIBA_TML_SICF_MASK;
222         ts_low = (value << SIBA_TML_SICF_SHIFT) & ts_mask;
223
224         return (siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
225             ts_low, ts_mask));
226 }
227
228 static bool
229 siba_is_hw_suspended(device_t dev, device_t child)
230 {
231         uint32_t                ts_low;
232         uint16_t                ioctl;
233         int                     error;
234
235         /* Fetch target state */
236         error = bhnd_read_config(child, SIBA_CFG0_TMSTATELOW, &ts_low, 4);
237         if (error) {
238                 device_printf(child, "error reading HW reset state: %d\n",
239                     error);
240                 return (true);
241         }
242
243         /* Is core held in RESET? */
244         if (ts_low & SIBA_TML_RESET)
245                 return (true);
246
247         /* Is core clocked? */
248         ioctl = SIBA_REG_GET(ts_low, TML_SICF);
249         if (!(ioctl & BHND_IOCTL_CLK_EN))
250                 return (true);
251
252         return (false);
253 }
254
255 static int
256 siba_reset_hw(device_t dev, device_t child, uint16_t ioctl)
257 {
258         struct siba_devinfo             *dinfo;
259         struct bhnd_resource            *r;
260         uint32_t                         ts_low, imstate;
261         int                              error;
262
263         if (device_get_parent(child) != dev)
264                 return (EINVAL);
265
266         dinfo = device_get_ivars(child);
267
268         /* Can't suspend the core without access to the CFG0 registers */
269         if ((r = dinfo->cfg[0]) == NULL)
270                 return (ENODEV);
271
272         /* We require exclusive control over BHND_IOCTL_CLK_EN and
273          * BHND_IOCTL_CLK_FORCE. */
274         if (ioctl & (BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE))
275                 return (EINVAL);
276
277         /* Place core into known RESET state */
278         if ((error = BHND_BUS_SUSPEND_HW(dev, child)))
279                 return (error);
280
281         /* Leaving the core in reset, set the caller's IOCTL flags and
282          * enable the core's clocks. */
283         ts_low = (ioctl | BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE) <<
284             SIBA_TML_SICF_SHIFT;
285         error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
286             ts_low, SIBA_TML_SICF_MASK);
287         if (error)
288                 return (error);
289
290         /* Clear any target errors */
291         if (bhnd_bus_read_4(r, SIBA_CFG0_TMSTATEHIGH) & SIBA_TMH_SERR) {
292                 error = siba_write_target_state(child, dinfo,
293                     SIBA_CFG0_TMSTATEHIGH, 0, SIBA_TMH_SERR);
294                 if (error)
295                         return (error);
296         }
297
298         /* Clear any initiator errors */
299         imstate = bhnd_bus_read_4(r, SIBA_CFG0_IMSTATE);
300         if (imstate & (SIBA_IM_IBE|SIBA_IM_TO)) {
301                 error = siba_write_target_state(child, dinfo, SIBA_CFG0_IMSTATE,
302                     0, SIBA_IM_IBE|SIBA_IM_TO);
303                 if (error)
304                         return (error);
305         }
306
307         /* Release from RESET while leaving clocks forced, ensuring the
308          * signal propagates throughout the core */
309         error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
310             0x0, SIBA_TML_RESET);
311         if (error)
312                 return (error);
313
314         /* The core should now be active; we can clear the BHND_IOCTL_CLK_FORCE
315          * bit and allow the core to manage clock gating. */
316         error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
317             0x0, (BHND_IOCTL_CLK_FORCE << SIBA_TML_SICF_SHIFT));
318         if (error)
319                 return (error);
320
321         return (0);
322 }
323
324 static int
325 siba_suspend_hw(device_t dev, device_t child)
326 {
327         struct siba_devinfo             *dinfo;
328         struct bhnd_core_pmu_info       *pm;
329         struct bhnd_resource            *r;
330         uint32_t                         idl, ts_low;
331         uint16_t                         ioctl;
332         int                              error;
333
334         if (device_get_parent(child) != dev)
335                 return (EINVAL);
336
337         dinfo = device_get_ivars(child);
338         pm = dinfo->pmu_info;
339
340         /* Can't suspend the core without access to the CFG0 registers */
341         if ((r = dinfo->cfg[0]) == NULL)
342                 return (ENODEV);
343
344         /* Already in RESET? */
345         ts_low = bhnd_bus_read_4(r, SIBA_CFG0_TMSTATELOW);
346         if (ts_low & SIBA_TML_RESET) {
347                 /* Clear IOCTL flags, ensuring the clock is disabled */
348                 return (siba_write_target_state(child, dinfo,
349                     SIBA_CFG0_TMSTATELOW, 0x0, SIBA_TML_SICF_MASK));
350
351                 return (0);
352         }
353
354         /* If clocks are already disabled, we can put the core directly
355          * into RESET */
356         ioctl = SIBA_REG_GET(ts_low, TML_SICF);
357         if (!(ioctl & BHND_IOCTL_CLK_EN)) {
358                 /* Set RESET and clear IOCTL flags */
359                 return (siba_write_target_state(child, dinfo, 
360                     SIBA_CFG0_TMSTATELOW,
361                     SIBA_TML_RESET,
362                     SIBA_TML_RESET | SIBA_TML_SICF_MASK));
363         }
364
365         /* Reject any further target backplane transactions */
366         error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
367             SIBA_TML_REJ, SIBA_TML_REJ);
368         if (error)
369                 return (error);
370
371         /* If this is an initiator core, we need to reject initiator
372          * transactions too. */
373         idl = bhnd_bus_read_4(r, SIBA_CFG0_IDLOW);
374         if (idl & SIBA_IDL_INIT) {
375                 error = siba_write_target_state(child, dinfo, SIBA_CFG0_IMSTATE,
376                     SIBA_IM_RJ, SIBA_IM_RJ);
377                 if (error)
378                         return (error);
379         }
380
381         /* Put the core into RESET|REJECT, forcing clocks to ensure the RESET
382          * signal propagates throughout the core, leaving REJECT asserted. */
383         ts_low = SIBA_TML_RESET;
384         ts_low |= (BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE) <<
385             SIBA_TML_SICF_SHIFT;
386
387         error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
388                 ts_low, ts_low);
389         if (error)
390                 return (error);
391
392         /* Give RESET ample time */
393         DELAY(10);
394
395         /* Leaving core in reset, disable all clocks, clear REJ flags and
396          * IOCTL state */
397         error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
398                 SIBA_TML_RESET,
399                 SIBA_TML_RESET | SIBA_TML_REJ | SIBA_TML_SICF_MASK);
400         if (error)
401                 return (error);
402
403         /* Clear previously asserted initiator reject */
404         if (idl & SIBA_IDL_INIT) {
405                 error = siba_write_target_state(child, dinfo, SIBA_CFG0_IMSTATE,
406                     0, SIBA_IM_RJ);
407                 if (error)
408                         return (error);
409         }
410
411         /* Core is now in RESET, with clocks disabled and REJ not asserted.
412          * 
413          * We lastly need to inform the PMU, releasing any outstanding per-core
414          * PMU requests */      
415         if (pm != NULL) {
416                 if ((error = BHND_PMU_CORE_RELEASE(pm->pm_pmu, pm)))
417                         return (error);
418         }
419
420         return (0);
421 }
422
423 static int
424 siba_read_config(device_t dev, device_t child, bus_size_t offset, void *value,
425     u_int width)
426 {
427         struct siba_devinfo     *dinfo;
428         rman_res_t               r_size;
429
430         /* Must be directly attached */
431         if (device_get_parent(child) != dev)
432                 return (EINVAL);
433
434         /* CFG0 registers must be available */
435         dinfo = device_get_ivars(child);
436         if (dinfo->cfg[0] == NULL)
437                 return (ENODEV);
438
439         /* Offset must fall within CFG0 */
440         r_size = rman_get_size(dinfo->cfg[0]->res);
441         if (r_size < offset || r_size - offset < width)
442                 return (EFAULT);
443
444         switch (width) {
445         case 1:
446                 *((uint8_t *)value) = bhnd_bus_read_1(dinfo->cfg[0], offset);
447                 return (0);
448         case 2:
449                 *((uint16_t *)value) = bhnd_bus_read_2(dinfo->cfg[0], offset);
450                 return (0);
451         case 4:
452                 *((uint32_t *)value) = bhnd_bus_read_4(dinfo->cfg[0], offset);
453                 return (0);
454         default:
455                 return (EINVAL);
456         }
457 }
458
459 static int
460 siba_write_config(device_t dev, device_t child, bus_size_t offset,
461     const void *value, u_int width)
462 {
463         struct siba_devinfo     *dinfo;
464         struct bhnd_resource    *r;
465         rman_res_t               r_size;
466
467         /* Must be directly attached */
468         if (device_get_parent(child) != dev)
469                 return (EINVAL);
470
471         /* CFG0 registers must be available */
472         dinfo = device_get_ivars(child);
473         if ((r = dinfo->cfg[0]) == NULL)
474                 return (ENODEV);
475
476         /* Offset must fall within CFG0 */
477         r_size = rman_get_size(r->res);
478         if (r_size < offset || r_size - offset < width)
479                 return (EFAULT);
480
481         switch (width) {
482         case 1:
483                 bhnd_bus_write_1(r, offset, *(const uint8_t *)value);
484                 return (0);
485         case 2:
486                 bhnd_bus_write_2(r, offset, *(const uint8_t *)value);
487                 return (0);
488         case 4:
489                 bhnd_bus_write_4(r, offset, *(const uint8_t *)value);
490                 return (0);
491         default:
492                 return (EINVAL);
493         }
494 }
495
496 static u_int
497 siba_get_port_count(device_t dev, device_t child, bhnd_port_type type)
498 {
499         struct siba_devinfo *dinfo;
500
501         /* delegate non-bus-attached devices to our parent */
502         if (device_get_parent(child) != dev)
503                 return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
504                     type));
505
506         dinfo = device_get_ivars(child);
507         return (siba_addrspace_port_count(dinfo->core_id.num_addrspace));
508 }
509
510 static u_int
511 siba_get_region_count(device_t dev, device_t child, bhnd_port_type type,
512     u_int port)
513 {
514         struct siba_devinfo     *dinfo;
515
516         /* delegate non-bus-attached devices to our parent */
517         if (device_get_parent(child) != dev)
518                 return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
519                     type, port));
520
521         dinfo = device_get_ivars(child);
522         if (!siba_is_port_valid(dinfo->core_id.num_addrspace, type, port))
523                 return (0);
524
525         return (siba_addrspace_region_count(dinfo->core_id.num_addrspace,
526             port));
527 }
528
529 static int
530 siba_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
531     u_int port_num, u_int region_num)
532 {
533         struct siba_devinfo     *dinfo;
534         struct siba_addrspace   *addrspace;
535
536         /* delegate non-bus-attached devices to our parent */
537         if (device_get_parent(child) != dev)
538                 return (BHND_BUS_GET_PORT_RID(device_get_parent(dev), child,
539                     port_type, port_num, region_num));
540
541         dinfo = device_get_ivars(child);
542         addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
543         if (addrspace == NULL)
544                 return (-1);
545
546         return (addrspace->sa_rid);
547 }
548
549 static int
550 siba_decode_port_rid(device_t dev, device_t child, int type, int rid,
551     bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
552 {
553         struct siba_devinfo     *dinfo;
554
555         /* delegate non-bus-attached devices to our parent */
556         if (device_get_parent(child) != dev)
557                 return (BHND_BUS_DECODE_PORT_RID(device_get_parent(dev), child,
558                     type, rid, port_type, port_num, region_num));
559
560         dinfo = device_get_ivars(child);
561
562         /* Ports are always memory mapped */
563         if (type != SYS_RES_MEMORY)
564                 return (EINVAL);
565
566         for (int i = 0; i < dinfo->core_id.num_addrspace; i++) {
567                 if (dinfo->addrspace[i].sa_rid != rid)
568                         continue;
569
570                 *port_type = BHND_PORT_DEVICE;
571                 *port_num = siba_addrspace_port(i);
572                 *region_num = siba_addrspace_region(i);
573                 return (0);
574         }
575
576         /* Not found */
577         return (ENOENT);
578 }
579
580 static int
581 siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
582     u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
583 {
584         struct siba_devinfo     *dinfo;
585         struct siba_addrspace   *addrspace;
586
587         /* delegate non-bus-attached devices to our parent */
588         if (device_get_parent(child) != dev) {
589                 return (BHND_BUS_GET_REGION_ADDR(device_get_parent(dev), child,
590                     port_type, port_num, region_num, addr, size));
591         }
592
593         dinfo = device_get_ivars(child);
594         addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
595         if (addrspace == NULL)
596                 return (ENOENT);
597
598         *addr = addrspace->sa_base;
599         *size = addrspace->sa_size - addrspace->sa_bus_reserved;
600         return (0);
601 }
602
603 /**
604  * Default siba(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT().
605  * 
606  * This implementation consults @p child's configuration block mapping,
607  * returning SIBA_CORE_NUM_INTR if a valid CFG0 block is mapped.
608  */
609 int
610 siba_get_intr_count(device_t dev, device_t child)
611 {
612         struct siba_devinfo *dinfo;
613
614         /* delegate non-bus-attached devices to our parent */
615         if (device_get_parent(child) != dev)
616                 return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child));
617
618         dinfo = device_get_ivars(child);
619
620         /* We can get/set interrupt sbflags on any core with a valid cfg0
621          * block; whether the core actually makes use of it is another matter
622          * entirely */
623         if (dinfo->cfg[0] == NULL)
624                 return (0);
625
626         return (SIBA_CORE_NUM_INTR);
627 }
628
629 /**
630  * Default siba(4) bus driver implementation of BHND_BUS_GET_CORE_IVEC().
631  * 
632  * This implementation consults @p child's CFG0 register block,
633  * returning the interrupt flag assigned to @p child.
634  */
635 int
636 siba_get_core_ivec(device_t dev, device_t child, u_int intr, uint32_t *ivec)
637 {
638         struct siba_devinfo     *dinfo;
639         uint32_t                 tpsflag;
640
641         /* delegate non-bus-attached devices to our parent */
642         if (device_get_parent(child) != dev)
643                 return (BHND_BUS_GET_CORE_IVEC(device_get_parent(dev), child,
644                     intr, ivec));
645
646         /* Must be a valid interrupt ID */
647         if (intr >= siba_get_intr_count(dev, child))
648                 return (ENXIO);
649
650         /* Fetch sbflag number */
651         dinfo = device_get_ivars(child);
652         tpsflag = bhnd_bus_read_4(dinfo->cfg[0], SIBA_CFG0_TPSFLAG);
653         *ivec = SIBA_REG_GET(tpsflag, TPS_NUM0);
654
655         return (0);
656 }
657
658 /**
659  * Register all address space mappings for @p di.
660  *
661  * @param dev The siba bus device.
662  * @param di The device info instance on which to register all address
663  * space entries.
664  * @param r A resource mapping the enumeration table block for @p di.
665  */
666 static int
667 siba_register_addrspaces(device_t dev, struct siba_devinfo *di,
668     struct bhnd_resource *r)
669 {
670         struct siba_core_id     *cid;
671         uint32_t                 addr;
672         uint32_t                 size;
673         int                      error;
674
675         cid = &di->core_id;
676
677
678         /* Register the device address space entries */
679         for (uint8_t i = 0; i < di->core_id.num_addrspace; i++) {
680                 uint32_t        adm;
681                 u_int           adm_offset;
682                 uint32_t        bus_reserved;
683
684                 /* Determine the register offset */
685                 adm_offset = siba_admatch_offset(i);
686                 if (adm_offset == 0) {
687                     device_printf(dev, "addrspace %hhu is unsupported", i);
688                     return (ENODEV);
689                 }
690
691                 /* Fetch the address match register value */
692                 adm = bhnd_bus_read_4(r, adm_offset);
693
694                 /* Parse the value */
695                 if ((error = siba_parse_admatch(adm, &addr, &size))) {
696                         device_printf(dev, "failed to decode address "
697                             " match register value 0x%x\n", adm);
698                         return (error);
699                 }
700
701                 /* If this is the device's core/enumeration addrespace,
702                  * reserve the Sonics configuration register blocks for the
703                  * use of our bus. */
704                 bus_reserved = 0;
705                 if (i == SIBA_CORE_ADDRSPACE)
706                         bus_reserved = cid->num_cfg_blocks * SIBA_CFG_SIZE;
707
708                 /* Append the region info */
709                 error = siba_append_dinfo_region(di, i, addr, size,
710                     bus_reserved);
711                 if (error)
712                         return (error);
713         }
714
715         return (0);
716 }
717
718 /**
719  * Map per-core configuration blocks for @p dinfo.
720  *
721  * @param dev The siba bus device.
722  * @param dinfo The device info instance on which to map all per-core
723  * configuration blocks.
724  */
725 static int
726 siba_map_cfg_resources(device_t dev, struct siba_devinfo *dinfo)
727 {
728         struct siba_addrspace   *addrspace;
729         rman_res_t               r_start, r_count, r_end;
730         uint8_t                  num_cfg;
731
732         num_cfg = dinfo->core_id.num_cfg_blocks;
733         if (num_cfg > SIBA_MAX_CFG) {
734                 device_printf(dev, "config block count %hhu out of range\n",
735                     num_cfg);
736                 return (ENXIO);
737         }
738         
739         /* Fetch the core register address space */
740         addrspace = siba_find_addrspace(dinfo, BHND_PORT_DEVICE, 0, 0);
741         if (addrspace == NULL) {
742                 device_printf(dev, "missing device registers\n");
743                 return (ENXIO);
744         }
745
746         /*
747          * Map the per-core configuration blocks
748          */
749         for (uint8_t i = 0; i < num_cfg; i++) {
750                 /* Determine the config block's address range; configuration
751                  * blocks are allocated starting at SIBA_CFG0_OFFSET,
752                  * growing downwards. */
753                 r_start = addrspace->sa_base + SIBA_CFG0_OFFSET;
754                 r_start -= i * SIBA_CFG_SIZE;
755
756                 r_count = SIBA_CFG_SIZE;
757                 r_end = r_start + r_count - 1;
758
759                 /* Allocate the config resource */
760                 dinfo->cfg_rid[i] = SIBA_CFG_RID(dinfo, i);
761                 dinfo->cfg[i] = BHND_BUS_ALLOC_RESOURCE(dev, dev,
762                     SYS_RES_MEMORY, &dinfo->cfg_rid[i], r_start, r_end,
763                     r_count, RF_ACTIVE);
764
765                 if (dinfo->cfg[i] == NULL) {
766                         device_printf(dev, "failed to allocate SIBA_CFG%hhu\n",
767                             i);
768                         return (ENXIO);
769                 }
770         }
771
772         return (0);
773 }
774
775 static device_t
776 siba_add_child(device_t dev, u_int order, const char *name, int unit)
777 {
778         struct siba_devinfo     *dinfo;
779         device_t                 child;
780
781         child = device_add_child_ordered(dev, order, name, unit);
782         if (child == NULL)
783                 return (NULL);
784
785         if ((dinfo = siba_alloc_dinfo(dev)) == NULL) {
786                 device_delete_child(dev, child);
787                 return (NULL);
788         }
789
790         device_set_ivars(child, dinfo);
791
792         return (child);
793 }
794
795 static void
796 siba_child_deleted(device_t dev, device_t child)
797 {
798         struct bhnd_softc       *sc;
799         struct siba_devinfo     *dinfo;
800
801         sc = device_get_softc(dev);
802
803         /* Call required bhnd(4) implementation */
804         bhnd_generic_child_deleted(dev, child);
805
806         /* Free siba device info */
807         if ((dinfo = device_get_ivars(child)) != NULL)
808                 siba_free_dinfo(dev, dinfo);
809
810         device_set_ivars(child, NULL);
811 }
812
813 /**
814  * Scan the core table and add all valid discovered cores to
815  * the bus.
816  * 
817  * @param dev The siba bus device.
818  */
819 int
820 siba_add_children(device_t dev)
821 {
822         const struct bhnd_chipid        *chipid;
823         struct bhnd_core_info           *cores;
824         struct siba_devinfo             *dinfo;
825         struct bhnd_resource            *r;
826         int                              rid;
827         int                              error;
828
829         dinfo = NULL;
830         cores = NULL;
831         r = NULL;
832
833         chipid = BHND_BUS_GET_CHIPID(dev, dev);
834
835         /* Allocate our temporary core table and enumerate all cores */
836         cores = malloc(sizeof(*cores) * chipid->ncores, M_BHND, M_NOWAIT);
837         if (cores == NULL)
838                 return (ENOMEM);
839
840         /* Add all cores. */
841         for (u_int i = 0; i < chipid->ncores; i++) {
842                 struct siba_core_id      cid;
843                 device_t                 child;
844                 uint32_t                 idhigh, idlow;
845                 rman_res_t               r_count, r_end, r_start;
846                 int                      nintr;
847
848                 /* Map the core's register block */
849                 rid = 0;
850                 r_start = SIBA_CORE_ADDR(i);
851                 r_count = SIBA_CORE_SIZE;
852                 r_end = r_start + SIBA_CORE_SIZE - 1;
853                 r = bhnd_alloc_resource(dev, SYS_RES_MEMORY, &rid, r_start,
854                     r_end, r_count, RF_ACTIVE);
855                 if (r == NULL) {
856                         error = ENXIO;
857                         goto cleanup;
858                 }
859
860                 /* Add the child device */
861                 child = BUS_ADD_CHILD(dev, 0, NULL, -1);
862                 if (child == NULL) {
863                         error = ENXIO;
864                         goto cleanup;
865                 }
866                 
867                 /* Read the core info */
868                 idhigh = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
869                 idlow = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW));
870
871                 cid = siba_parse_core_id(idhigh, idlow, i, 0);
872                 cores[i] = cid.core_info;
873
874                 /* Determine unit number */
875                 for (u_int j = 0; j < i; j++) {
876                         if (cores[j].vendor == cores[i].vendor &&
877                             cores[j].device == cores[i].device)
878                                 cores[i].unit++;
879                 }
880
881                 /* Initialize per-device bus info */
882                 if ((dinfo = device_get_ivars(child)) == NULL) {
883                         error = ENXIO;
884                         goto cleanup;
885                 }
886
887                 if ((error = siba_init_dinfo(dev, dinfo, &cid)))
888                         goto cleanup;
889
890                 /* Register the core's address space(s). */
891                 if ((error = siba_register_addrspaces(dev, dinfo, r)))
892                         goto cleanup;
893
894                 /* Release our resource covering the register blocks
895                  * we're about to map */
896                 bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
897                 r = NULL;
898
899                 /* Map the core's config blocks */
900                 if ((error = siba_map_cfg_resources(dev, dinfo)))
901                         goto cleanup;
902
903                 /* Assign interrupts */
904                 nintr = bhnd_get_intr_count(child);
905                 for (int rid = 0; rid < nintr; rid++) {
906                         error = BHND_BUS_ASSIGN_INTR(dev, child, rid);
907                         if (error) {
908                                 device_printf(dev, "failed to assign interrupt "
909                                     "%d to core %u: %d\n", rid, i, error);
910                         }
911                 }
912
913                 /* If pins are floating or the hardware is otherwise
914                  * unpopulated, the device shouldn't be used. */
915                 if (bhnd_is_hw_disabled(child))
916                         device_disable(child);
917
918                 /* Issue bus callback for fully initialized child. */
919                 BHND_BUS_CHILD_ADDED(dev, child);
920         }
921         
922 cleanup:
923         if (cores != NULL)
924                 free(cores, M_BHND);
925
926         if (r != NULL)
927                 bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
928
929         return (error);
930 }
931
932 static device_method_t siba_methods[] = {
933         /* Device interface */
934         DEVMETHOD(device_probe,                 siba_probe),
935         DEVMETHOD(device_attach,                siba_attach),
936         DEVMETHOD(device_detach,                siba_detach),
937         DEVMETHOD(device_resume,                siba_resume),
938         DEVMETHOD(device_suspend,               siba_suspend),
939         
940         /* Bus interface */
941         DEVMETHOD(bus_add_child,                siba_add_child),
942         DEVMETHOD(bus_child_deleted,            siba_child_deleted),
943         DEVMETHOD(bus_read_ivar,                siba_read_ivar),
944         DEVMETHOD(bus_write_ivar,               siba_write_ivar),
945         DEVMETHOD(bus_get_resource_list,        siba_get_resource_list),
946
947         /* BHND interface */
948         DEVMETHOD(bhnd_bus_get_erom_class,      siba_get_erom_class),
949         DEVMETHOD(bhnd_bus_read_ioctl,          siba_read_ioctl),
950         DEVMETHOD(bhnd_bus_write_ioctl,         siba_write_ioctl),
951         DEVMETHOD(bhnd_bus_read_iost,           siba_read_iost),
952         DEVMETHOD(bhnd_bus_is_hw_suspended,     siba_is_hw_suspended),
953         DEVMETHOD(bhnd_bus_reset_hw,            siba_reset_hw),
954         DEVMETHOD(bhnd_bus_suspend_hw,          siba_suspend_hw),
955         DEVMETHOD(bhnd_bus_read_config,         siba_read_config),
956         DEVMETHOD(bhnd_bus_write_config,        siba_write_config),
957         DEVMETHOD(bhnd_bus_get_port_count,      siba_get_port_count),
958         DEVMETHOD(bhnd_bus_get_region_count,    siba_get_region_count),
959         DEVMETHOD(bhnd_bus_get_port_rid,        siba_get_port_rid),
960         DEVMETHOD(bhnd_bus_decode_port_rid,     siba_decode_port_rid),
961         DEVMETHOD(bhnd_bus_get_region_addr,     siba_get_region_addr),
962         DEVMETHOD(bhnd_bus_get_intr_count,      siba_get_intr_count),
963         DEVMETHOD(bhnd_bus_get_core_ivec,       siba_get_core_ivec),
964
965         DEVMETHOD_END
966 };
967
968 DEFINE_CLASS_1(bhnd, siba_driver, siba_methods, sizeof(struct siba_softc), bhnd_driver);
969
970 MODULE_VERSION(siba, 1);
971 MODULE_DEPEND(siba, bhnd, 1, 1, 1);