File: /usr/src/linux/arch/ia64/sn/io/io.c
1 /* $Id$
2 *
3 * This file is subject to the terms and conditions of the GNU General Public
4 * License. See the file "COPYING" in the main directory of this archive
5 * for more details.
6 *
7 * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
8 * Copyright (C) 2000 by Colin Ngam
9 */
10
11 #include <linux/types.h>
12 #include <linux/config.h>
13 #include <linux/slab.h>
14 #include <asm/sn/types.h>
15 #include <asm/sn/sgi.h>
16 #include <asm/sn/iobus.h>
17 #include <asm/sn/iograph.h>
18 #include <asm/param.h>
19 #include <asm/sn/pio.h>
20 #include <asm/sn/xtalk/xwidget.h>
21 #include <asm/sn/sn_private.h>
22 #include <asm/sn/addrs.h>
23 #include <asm/sn/invent.h>
24 #include <asm/sn/hcl.h>
25 #include <asm/sn/hcl_util.h>
26 #include <asm/sn/agent.h>
27 #include <asm/sn/intr.h>
28 #include <asm/sn/xtalk/xtalkaddrs.h>
29 #include <asm/sn/klconfig.h>
30 #include <asm/sn/io.h>
31 #include <asm/sn/sn_cpuid.h>
32
33 extern xtalk_provider_t hub_provider;
34
35 /*
36 * Perform any initializations needed to support hub-based I/O.
37 * Called once during startup.
38 */
39 void
40 hubio_init(void)
41 {
42 #ifdef LATER
43 /* This isn't needed unless we port the entire sio driver ... */
44 extern void early_brl1_port_init( void );
45 early_brl1_port_init();
46 #endif
47 }
48
49 /*
50 * Implementation of hub iobus operations.
51 *
52 * Hub provides a crosstalk "iobus" on IP27 systems. These routines
53 * provide a platform-specific implementation of xtalk used by all xtalk
54 * cards on IP27 systems.
55 *
56 * Called from corresponding xtalk_* routines.
57 */
58
59
60 /* PIO MANAGEMENT */
61 /* For mapping system virtual address space to xtalk space on a specified widget */
62
63 /*
64 * Setup pio structures needed for a particular hub.
65 */
66 static void
67 hub_pio_init(devfs_handle_t hubv)
68 {
69 xwidgetnum_t widget;
70 hubinfo_t hubinfo;
71 nasid_t nasid;
72 int bigwin;
73 hub_piomap_t hub_piomap;
74
75 hubinfo_get(hubv, &hubinfo);
76 nasid = hubinfo->h_nasid;
77
78 /* Initialize small window piomaps for this hub */
79 for (widget=0; widget <= HUB_WIDGET_ID_MAX; widget++) {
80 hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget);
81 hub_piomap->hpio_xtalk_info.xp_target = widget;
82 hub_piomap->hpio_xtalk_info.xp_xtalk_addr = 0;
83 hub_piomap->hpio_xtalk_info.xp_mapsz = SWIN_SIZE;
84 hub_piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)NODE_SWIN_BASE(nasid, widget);
85 hub_piomap->hpio_hub = hubv;
86 hub_piomap->hpio_flags = HUB_PIOMAP_IS_VALID;
87 }
88
89 /* Initialize big window piomaps for this hub */
90 for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) {
91 hub_piomap = hubinfo_bwin_piomap_get(hubinfo, bigwin);
92 hub_piomap->hpio_xtalk_info.xp_mapsz = BWIN_SIZE;
93 hub_piomap->hpio_hub = hubv;
94 hub_piomap->hpio_holdcnt = 0;
95 hub_piomap->hpio_flags = HUB_PIOMAP_IS_BIGWINDOW;
96 IIO_ITTE_DISABLE(nasid, bigwin);
97 }
98 hub_set_piomode(nasid, HUB_PIO_CONVEYOR);
99
100 mutex_spinlock_init(&hubinfo->h_bwlock);
101 /*
102 * If this lock can be acquired from interrupts or bh's, add SV_INTS or SV_BHS,
103 * respectively, to the flags here.
104 */
105 sv_init(&hubinfo->h_bwwait, &hubinfo->h_bwlock, SV_ORDER_FIFO | SV_MON_SPIN);
106 }
107
108 /*
109 * Create a caddr_t-to-xtalk_addr mapping.
110 *
111 * Use a small window if possible (that's the usual case), but
112 * manage big windows if needed. Big window mappings can be
113 * either FIXED or UNFIXED -- we keep at least 1 big window available
114 * for UNFIXED mappings.
115 *
116 * Returns an opaque pointer-sized type which can be passed to
117 * other hub_pio_* routines on success, or NULL if the request
118 * cannot be satisfied.
119 */
120 /* ARGSUSED */
121 hub_piomap_t
122 hub_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */
123 device_desc_t dev_desc, /* device descriptor */
124 iopaddr_t xtalk_addr, /* map for this xtalk_addr range */
125 size_t byte_count,
126 size_t byte_count_max, /* maximum size of a mapping */
127 unsigned flags) /* defined in sys/pio.h */
128 {
129 xwidget_info_t widget_info = xwidget_info_get(dev);
130 xwidgetnum_t widget = xwidget_info_id_get(widget_info);
131 devfs_handle_t hubv = xwidget_info_master_get(widget_info);
132 hubinfo_t hubinfo;
133 hub_piomap_t bw_piomap;
134 int bigwin, free_bw_index;
135 nasid_t nasid;
136 volatile hubreg_t junk;
137 unsigned long s;
138
139 /* sanity check */
140 if (byte_count_max > byte_count)
141 return(NULL);
142
143 hubinfo_get(hubv, &hubinfo);
144
145 /* If xtalk_addr range is mapped by a small window, we don't have
146 * to do much
147 */
148 if (xtalk_addr + byte_count <= SWIN_SIZE)
149 return(hubinfo_swin_piomap_get(hubinfo, (int)widget));
150
151 /* We need to use a big window mapping. */
152
153 /*
154 * TBD: Allow requests that would consume multiple big windows --
155 * split the request up and use multiple mapping entries.
156 * For now, reject requests that span big windows.
157 */
158 if ((xtalk_addr % BWIN_SIZE) + byte_count > BWIN_SIZE)
159 return(NULL);
160
161
162 /* Round xtalk address down for big window alignement */
163 xtalk_addr = xtalk_addr & ~(BWIN_SIZE-1);
164
165 /*
166 * Check to see if an existing big window mapping will suffice.
167 */
168 tryagain:
169 free_bw_index = -1;
170 s = mutex_spinlock(&hubinfo->h_bwlock);
171 for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) {
172 bw_piomap = hubinfo_bwin_piomap_get(hubinfo, bigwin);
173
174 /* If mapping is not valid, skip it */
175 if (!(bw_piomap->hpio_flags & HUB_PIOMAP_IS_VALID)) {
176 free_bw_index = bigwin;
177 continue;
178 }
179
180 /*
181 * If mapping is UNFIXED, skip it. We don't allow sharing
182 * of UNFIXED mappings, because this would allow starvation.
183 */
184 if (!(bw_piomap->hpio_flags & HUB_PIOMAP_IS_FIXED))
185 continue;
186
187 if ( xtalk_addr == bw_piomap->hpio_xtalk_info.xp_xtalk_addr &&
188 widget == bw_piomap->hpio_xtalk_info.xp_target) {
189 bw_piomap->hpio_holdcnt++;
190 mutex_spinunlock(&hubinfo->h_bwlock, s);
191 return(bw_piomap);
192 }
193 }
194
195 /*
196 * None of the existing big window mappings will work for us --
197 * we need to establish a new mapping.
198 */
199
200 /* Insure that we don't consume all big windows with FIXED mappings */
201 if (flags & PIOMAP_FIXED) {
202 if (hubinfo->h_num_big_window_fixed < HUB_NUM_BIG_WINDOW-1) {
203 ASSERT(free_bw_index >= 0);
204 hubinfo->h_num_big_window_fixed++;
205 } else {
206 bw_piomap = NULL;
207 goto done;
208 }
209 } else /* PIOMAP_UNFIXED */ {
210 if (free_bw_index < 0) {
211 if (flags & PIOMAP_NOSLEEP) {
212 bw_piomap = NULL;
213 goto done;
214 }
215
216 sv_wait(&hubinfo->h_bwwait, 0, 0);
217 goto tryagain;
218 }
219 }
220
221
222 /* OK! Allocate big window free_bw_index for this mapping. */
223 /*
224 * The code below does a PIO write to setup an ITTE entry.
225 * We need to prevent other CPUs from seeing our updated memory
226 * shadow of the ITTE (in the piomap) until the ITTE entry is
227 * actually set up; otherwise, another CPU might attempt a PIO
228 * prematurely.
229 *
230 * Also, the only way we can know that an entry has been received
231 * by the hub and can be used by future PIO reads/writes is by
232 * reading back the ITTE entry after writing it.
233 *
234 * For these two reasons, we PIO read back the ITTE entry after
235 * we write it.
236 */
237
238 nasid = hubinfo->h_nasid;
239 IIO_ITTE_PUT(nasid, free_bw_index, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr);
240 junk = HUB_L(IIO_ITTE_GET(nasid, free_bw_index));
241
242 bw_piomap = hubinfo_bwin_piomap_get(hubinfo, free_bw_index);
243 bw_piomap->hpio_xtalk_info.xp_dev = dev;
244 bw_piomap->hpio_xtalk_info.xp_target = widget;
245 bw_piomap->hpio_xtalk_info.xp_xtalk_addr = xtalk_addr;
246 bw_piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)NODE_BWIN_BASE(nasid, free_bw_index);
247 bw_piomap->hpio_holdcnt++;
248 bw_piomap->hpio_bigwin_num = free_bw_index;
249
250 if (flags & PIOMAP_FIXED)
251 bw_piomap->hpio_flags |= HUB_PIOMAP_IS_VALID | HUB_PIOMAP_IS_FIXED;
252 else
253 bw_piomap->hpio_flags |= HUB_PIOMAP_IS_VALID;
254
255 done:
256 mutex_spinunlock(&hubinfo->h_bwlock, s);
257 return(bw_piomap);
258 }
259
260 /*
261 * hub_piomap_free destroys a caddr_t-to-xtalk pio mapping and frees
262 * any associated mapping resources.
263 *
264 * If this * piomap was handled with a small window, or if it was handled
265 * in a big window that's still in use by someone else, then there's
266 * nothing to do. On the other hand, if this mapping was handled
267 * with a big window, AND if we were the final user of that mapping,
268 * then destroy the mapping.
269 */
270 void
271 hub_piomap_free(hub_piomap_t hub_piomap)
272 {
273 devfs_handle_t hubv;
274 hubinfo_t hubinfo;
275 nasid_t nasid;
276 unsigned long s;
277
278 /*
279 * Small windows are permanently mapped to corresponding widgets,
280 * so there're no resources to free.
281 */
282 if (!(hub_piomap->hpio_flags & HUB_PIOMAP_IS_BIGWINDOW))
283 return;
284
285 ASSERT(hub_piomap->hpio_flags & HUB_PIOMAP_IS_VALID);
286 ASSERT(hub_piomap->hpio_holdcnt > 0);
287
288 hubv = hub_piomap->hpio_hub;
289 hubinfo_get(hubv, &hubinfo);
290 nasid = hubinfo->h_nasid;
291
292 s = mutex_spinlock(&hubinfo->h_bwlock);
293
294 /*
295 * If this is the last hold on this mapping, free it.
296 */
297 if (--hub_piomap->hpio_holdcnt == 0) {
298 IIO_ITTE_DISABLE(nasid, hub_piomap->hpio_bigwin_num );
299
300 if (hub_piomap->hpio_flags & HUB_PIOMAP_IS_FIXED) {
301 hub_piomap->hpio_flags &= ~(HUB_PIOMAP_IS_VALID | HUB_PIOMAP_IS_FIXED);
302 hubinfo->h_num_big_window_fixed--;
303 ASSERT(hubinfo->h_num_big_window_fixed >= 0);
304 } else
305 hub_piomap->hpio_flags &= ~HUB_PIOMAP_IS_VALID;
306
307 (void)sv_signal(&hubinfo->h_bwwait);
308 }
309
310 mutex_spinunlock(&hubinfo->h_bwlock, s);
311 }
312
313 /*
314 * Establish a mapping to a given xtalk address range using the resources
315 * allocated earlier.
316 */
317 caddr_t
318 hub_piomap_addr(hub_piomap_t hub_piomap, /* mapping resources */
319 iopaddr_t xtalk_addr, /* map for this xtalk address */
320 size_t byte_count) /* map this many bytes */
321 {
322 /* Verify that range can be mapped using the specified piomap */
323 if (xtalk_addr < hub_piomap->hpio_xtalk_info.xp_xtalk_addr)
324 return(0);
325
326 if (xtalk_addr + byte_count >
327 ( hub_piomap->hpio_xtalk_info.xp_xtalk_addr +
328 hub_piomap->hpio_xtalk_info.xp_mapsz))
329 return(0);
330
331 if (hub_piomap->hpio_flags & HUB_PIOMAP_IS_VALID)
332 return(hub_piomap->hpio_xtalk_info.xp_kvaddr +
333 (xtalk_addr % hub_piomap->hpio_xtalk_info.xp_mapsz));
334 else
335 return(0);
336 }
337
338
339 /*
340 * Driver indicates that it's done with PIO's from an earlier piomap_addr.
341 */
342 /* ARGSUSED */
343 void
344 hub_piomap_done(hub_piomap_t hub_piomap) /* done with these mapping resources */
345 {
346 /* Nothing to do */
347 }
348
349
350 /*
351 * For translations that require no mapping resources, supply a kernel virtual
352 * address that maps to the specified xtalk address range.
353 */
354 /* ARGSUSED */
355 caddr_t
356 hub_piotrans_addr( devfs_handle_t dev, /* translate to this device */
357 device_desc_t dev_desc, /* device descriptor */
358 iopaddr_t xtalk_addr, /* Crosstalk address */
359 size_t byte_count, /* map this many bytes */
360 unsigned flags) /* (currently unused) */
361 {
362 xwidget_info_t widget_info = xwidget_info_get(dev);
363 xwidgetnum_t widget = xwidget_info_id_get(widget_info);
364 devfs_handle_t hubv = xwidget_info_master_get(widget_info);
365 hub_piomap_t hub_piomap;
366 hubinfo_t hubinfo;
367
368 hubinfo_get(hubv, &hubinfo);
369
370 if (xtalk_addr + byte_count <= SWIN_SIZE) {
371 hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget);
372 return(hub_piomap_addr(hub_piomap, xtalk_addr, byte_count));
373 } else
374 return(0);
375 }
376
377
378 /* DMA MANAGEMENT */
379 /* Mapping from crosstalk space to system physical space */
380
381 /*
382 * There's not really very much to do here, since crosstalk maps
383 * directly to system physical space. It's quite possible that this
384 * DMA layer will be bypassed in performance kernels.
385 */
386
387
388 /* ARGSUSED */
389 static void
390 hub_dma_init(devfs_handle_t hubv)
391 {
392 }
393
394
395 /*
396 * Allocate resources needed to set up DMA mappings up to a specified size
397 * on a specified adapter.
398 *
399 * We don't actually use the adapter ID for anything. It's just the adapter
400 * that the lower level driver plans to use for DMA.
401 */
402 /* ARGSUSED */
403 hub_dmamap_t
404 hub_dmamap_alloc( devfs_handle_t dev, /* set up mappings for this device */
405 device_desc_t dev_desc, /* device descriptor */
406 size_t byte_count_max, /* max size of a mapping */
407 unsigned flags) /* defined in dma.h */
408 {
409 hub_dmamap_t dmamap;
410 xwidget_info_t widget_info = xwidget_info_get(dev);
411 xwidgetnum_t widget = xwidget_info_id_get(widget_info);
412 devfs_handle_t hubv = xwidget_info_master_get(widget_info);
413
414 dmamap = kern_malloc(sizeof(struct hub_dmamap_s));
415 dmamap->hdma_xtalk_info.xd_dev = dev;
416 dmamap->hdma_xtalk_info.xd_target = widget;
417 dmamap->hdma_hub = hubv;
418 dmamap->hdma_flags = HUB_DMAMAP_IS_VALID;
419 if (flags & XTALK_FIXED)
420 dmamap->hdma_flags |= HUB_DMAMAP_IS_FIXED;
421
422 return(dmamap);
423 }
424
425 /*
426 * Destroy a DMA mapping from crosstalk space to system address space.
427 * There is no actual mapping hardware to destroy, but we at least mark
428 * the dmamap INVALID and free the space that it took.
429 */
430 void
431 hub_dmamap_free(hub_dmamap_t hub_dmamap)
432 {
433 hub_dmamap->hdma_flags &= ~HUB_DMAMAP_IS_VALID;
434 kern_free(hub_dmamap);
435 }
436
437 /*
438 * Establish a DMA mapping using the resources allocated in a previous dmamap_alloc.
439 * Return an appropriate crosstalk address range that maps to the specified physical
440 * address range.
441 */
442 /* ARGSUSED */
443 extern iopaddr_t
444 hub_dmamap_addr( hub_dmamap_t dmamap, /* use these mapping resources */
445 paddr_t paddr, /* map for this address */
446 size_t byte_count) /* map this many bytes */
447 {
448 devfs_handle_t vhdl;
449
450 ASSERT(dmamap->hdma_flags & HUB_DMAMAP_IS_VALID);
451
452 if (dmamap->hdma_flags & HUB_DMAMAP_USED) {
453 /* If the map is FIXED, re-use is OK. */
454 if (!(dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) {
455 vhdl = dmamap->hdma_xtalk_info.xd_dev;
456 #if defined(SUPPORT_PRINTING_V_FORMAT)
457 PRINT_WARNING("%v: hub_dmamap_addr re-uses dmamap.\n",vhdl);
458 #else
459 PRINT_WARNING("0x%x: hub_dmamap_addr re-uses dmamap.\n", vhdl);
460 #endif
461 }
462 } else {
463 dmamap->hdma_flags |= HUB_DMAMAP_USED;
464 }
465
466 /* There isn't actually any DMA mapping hardware on the hub. */
467 return(paddr);
468 }
469
470 /*
471 * Establish a DMA mapping using the resources allocated in a previous dmamap_alloc.
472 * Return an appropriate crosstalk address list that maps to the specified physical
473 * address list.
474 */
475 /* ARGSUSED */
476 alenlist_t
477 hub_dmamap_list(hub_dmamap_t hub_dmamap, /* use these mapping resources */
478 alenlist_t palenlist, /* map this area of memory */
479 unsigned flags)
480 {
481 devfs_handle_t vhdl;
482
483 ASSERT(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_VALID);
484
485 if (hub_dmamap->hdma_flags & HUB_DMAMAP_USED) {
486 /* If the map is FIXED, re-use is OK. */
487 if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) {
488 vhdl = hub_dmamap->hdma_xtalk_info.xd_dev;
489 #if defined(SUPPORT_PRINTING_V_FORMAT)
490 PRINT_WARNING("%v: hub_dmamap_list re-uses dmamap\n",vhdl);
491 #else
492 PRINT_WARNING("0x%x: hub_dmamap_list re-uses dmamap\n", vhdl);
493 #endif
494 }
495 } else {
496 hub_dmamap->hdma_flags |= HUB_DMAMAP_USED;
497 }
498
499 /* There isn't actually any DMA mapping hardware on the hub. */
500 return(palenlist);
501 }
502
503 /*
504 * Driver indicates that it has completed whatever DMA it may have started
505 * after an earlier dmamap_addr or dmamap_list call.
506 */
507 void
508 hub_dmamap_done(hub_dmamap_t hub_dmamap) /* done with these mapping resources */
509 {
510 devfs_handle_t vhdl;
511
512 if (hub_dmamap->hdma_flags & HUB_DMAMAP_USED) {
513 hub_dmamap->hdma_flags &= ~HUB_DMAMAP_USED;
514 } else {
515 /* If the map is FIXED, re-done is OK. */
516 if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) {
517 vhdl = hub_dmamap->hdma_xtalk_info.xd_dev;
518 #if defined(SUPPORT_PRINTING_V_FORMAT)
519 PRINT_WARNING("%v: hub_dmamap_done already done with dmamap\n",vhdl);
520 #else
521 PRINT_WARNING("0x%x: hub_dmamap_done already done with dmamap\n", vhdl);
522 #endif
523 }
524 }
525 }
526
527 /*
528 * Translate a single system physical address into a crosstalk address.
529 */
530 /* ARGSUSED */
531 iopaddr_t
532 hub_dmatrans_addr( devfs_handle_t dev, /* translate for this device */
533 device_desc_t dev_desc, /* device descriptor */
534 paddr_t paddr, /* system physical address */
535 size_t byte_count, /* length */
536 unsigned flags) /* defined in dma.h */
537 {
538 /* no translation needed */
539 return(paddr);
540 }
541
542 /*
543 * Translate a list of IP27 addresses and lengths into a list of crosstalk
544 * addresses and lengths. No actual hardware mapping takes place; the hub
545 * has no DMA mapping registers -- crosstalk addresses map directly.
546 */
547 /* ARGSUSED */
548 alenlist_t
549 hub_dmatrans_list( devfs_handle_t dev, /* translate for this device */
550 device_desc_t dev_desc, /* device descriptor */
551 alenlist_t palenlist, /* system address/length list */
552 unsigned flags) /* defined in dma.h */
553 {
554 /* no translation needed */
555 return(palenlist);
556 }
557
558 /*ARGSUSED*/
559 void
560 hub_dmamap_drain( hub_dmamap_t map)
561 {
562 /* XXX- flush caches, if cache coherency WAR is needed */
563 }
564
565 /*ARGSUSED*/
566 void
567 hub_dmaaddr_drain( devfs_handle_t vhdl,
568 paddr_t addr,
569 size_t bytes)
570 {
571 /* XXX- flush caches, if cache coherency WAR is needed */
572 }
573
574 /*ARGSUSED*/
575 void
576 hub_dmalist_drain( devfs_handle_t vhdl,
577 alenlist_t list)
578 {
579 /* XXX- flush caches, if cache coherency WAR is needed */
580 }
581
582
583
584 /* INTERRUPT MANAGEMENT */
585
586 /* ARGSUSED */
587 static void
588 hub_intr_init(devfs_handle_t hubv)
589 {
590 }
591
592 /*
593 * hub_device_desc_update
594 * Update the passed in device descriptor with the actual the
595 * target cpu number and interrupt priority level.
596 * NOTE : These might be the same as the ones passed in thru
597 * the descriptor.
598 */
599 static void
600 hub_device_desc_update(device_desc_t dev_desc,
601 ilvl_t intr_swlevel,
602 cpuid_t cpu)
603 {
604 char cpuname[40];
605
606 /* Store the interrupt priority level in the device descriptor */
607 device_desc_intr_swlevel_set(dev_desc, intr_swlevel);
608
609 /* Convert the cpuid to the vertex handle in the hwgraph and
610 * save it in the device descriptor.
611 */
612 sprintf(cpuname,"/hw/cpunum/%ld",cpu);
613 device_desc_intr_target_set(dev_desc,
614 hwgraph_path_to_dev(cpuname));
615 }
616
617 int allocate_my_bit = INTRCONNECT_ANYBIT;
618
619 /*
620 * Allocate resources required for an interrupt as specified in dev_desc.
621 * Returns a hub interrupt handle on success, or 0 on failure.
622 */
623 static hub_intr_t
624 do_hub_intr_alloc(devfs_handle_t dev, /* which crosstalk device */
625 device_desc_t dev_desc, /* device descriptor */
626 devfs_handle_t owner_dev, /* owner of this interrupt, if known */
627 int uncond_nothread) /* unconditionally non-threaded */
628 {
629 cpuid_t cpu = (cpuid_t)0; /* cpu to receive interrupt */
630 int cpupicked = 0;
631 int bit; /* interrupt vector */
632 /*REFERENCED*/
633 int intr_resflags = 0;
634 hub_intr_t intr_hdl;
635 cnodeid_t nodeid; /* node to receive interrupt */
636 /*REFERENCED*/
637 nasid_t nasid; /* nasid to receive interrupt */
638 struct xtalk_intr_s *xtalk_info;
639 iopaddr_t xtalk_addr; /* xtalk addr on hub to set intr */
640 xwidget_info_t xwidget_info; /* standard crosstalk widget info handle */
641 char *intr_name = NULL;
642 ilvl_t intr_swlevel;
643 extern int default_intr_pri;
644 #ifdef CONFIG_IA64_SGI_SN1
645 extern void synergy_intr_alloc(int, int);
646 #endif
647
648 /*
649 * If caller didn't explicily specify a device descriptor, see if there's
650 * a default descriptor associated with the device.
651 */
652 if (!dev_desc)
653 dev_desc = device_desc_default_get(dev);
654
655 if (dev_desc) {
656 intr_name = device_desc_intr_name_get(dev_desc);
657 intr_swlevel = device_desc_intr_swlevel_get(dev_desc);
658 if (dev_desc->flags & D_INTR_ISERR) {
659 intr_resflags = II_ERRORINT;
660 } else if (!uncond_nothread && !(dev_desc->flags & D_INTR_NOTHREAD)) {
661 intr_resflags = II_THREADED;
662 } else {
663 /* Neither an error nor a thread. */
664 intr_resflags = 0;
665 }
666 } else {
667 intr_swlevel = default_intr_pri;
668 if (!uncond_nothread)
669 intr_resflags = II_THREADED;
670 }
671
672 /* XXX - Need to determine if the interrupt should be threaded. */
673
674 /* If the cpu has not been picked already then choose a candidate
675 * interrupt target and reserve the interrupt bit
676 */
677 #if defined(NEW_INTERRUPTS)
678 if (!cpupicked) {
679 cpu = intr_heuristic(dev,dev_desc,allocate_my_bit,
680 intr_resflags,owner_dev,
681 intr_name,&bit);
682 }
683 #endif
684
685 /* At this point we SHOULD have a valid cpu */
686 if (cpu == CPU_NONE) {
687 #if defined(SUPPORT_PRINTING_V_FORMAT)
688 PRINT_WARNING("%v hub_intr_alloc could not allocate interrupt\n",
689 owner_dev);
690 #else
691 PRINT_WARNING("0x%x hub_intr_alloc could not allocate interrupt\n",
692 owner_dev);
693 #endif
694 return(0);
695
696 }
697
698 /* If the cpu has been picked already (due to the bridge data
699 * corruption bug) then try to reserve an interrupt bit .
700 */
701 #if defined(NEW_INTERRUPTS)
702 if (cpupicked) {
703 bit = intr_reserve_level(cpu, allocate_my_bit,
704 intr_resflags,
705 owner_dev, intr_name);
706 if (bit < 0) {
707 #if defined(SUPPORT_PRINTING_V_FORMAT)
708 PRINT_WARNING("Could not reserve an interrupt bit for cpu "
709 " %d and dev %v\n",
710 cpu,owner_dev);
711 #else
712 PRINT_WARNING("Could not reserve an interrupt bit for cpu "
713 " %d and dev 0x%x\n",
714 cpu, owner_dev);
715 #endif
716
717 return(0);
718 }
719 }
720 #endif /* NEW_INTERRUPTS */
721
722 nodeid = cpuid_to_cnodeid(cpu);
723 nasid = cpuid_to_nasid(cpu);
724 xtalk_addr = HUBREG_AS_XTALKADDR(nasid, PIREG(PI_INT_PEND_MOD, cpuid_to_subnode(cpu)));
725
726 /*
727 * Allocate an interrupt handle, and fill it in. There are two
728 * pieces to an interrupt handle: the piece needed by generic
729 * xtalk code which is used by crosstalk device drivers, and
730 * the piece needed by low-level IP27 hardware code.
731 */
732 intr_hdl = kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, nodeid);
733 ASSERT_ALWAYS(intr_hdl);
734
735 /*
736 * Fill in xtalk information for generic xtalk interfaces that
737 * operate on xtalk_intr_hdl's.
738 */
739 xtalk_info = &intr_hdl->i_xtalk_info;
740 xtalk_info->xi_dev = dev;
741 xtalk_info->xi_vector = bit;
742 xtalk_info->xi_addr = xtalk_addr;
743
744 /*
745 * Regardless of which CPU we ultimately interrupt, a given crosstalk
746 * widget always handles interrupts (and PIO and DMA) through its
747 * designated "master" crosstalk provider.
748 */
749 xwidget_info = xwidget_info_get(dev);
750 if (xwidget_info)
751 xtalk_info->xi_target = xwidget_info_masterid_get(xwidget_info);
752
753 /* Fill in low level hub information for hub_* interrupt interface */
754 intr_hdl->i_swlevel = intr_swlevel;
755 intr_hdl->i_cpuid = cpu;
756 intr_hdl->i_bit = bit;
757 intr_hdl->i_flags = HUB_INTR_IS_ALLOCED;
758
759 /* Store the actual interrupt priority level & interrupt target
760 * cpu back in the device descriptor.
761 */
762 hub_device_desc_update(dev_desc, intr_swlevel, cpu);
763 #ifdef CONFIG_IA64_SGI_SN1
764 synergy_intr_alloc((int)bit, (int)cpu);
765 #endif
766 return(intr_hdl);
767 }
768
769 /*
770 * Allocate resources required for an interrupt as specified in dev_desc.
771 * Returns a hub interrupt handle on success, or 0 on failure.
772 */
773 hub_intr_t
774 hub_intr_alloc( devfs_handle_t dev, /* which crosstalk device */
775 device_desc_t dev_desc, /* device descriptor */
776 devfs_handle_t owner_dev) /* owner of this interrupt, if known */
777 {
778 return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0));
779 }
780
781 /*
782 * Allocate resources required for an interrupt as specified in dev_desc.
783 * Uncondtionally request non-threaded, regardless of what the device
784 * descriptor might say.
785 * Returns a hub interrupt handle on success, or 0 on failure.
786 */
787 hub_intr_t
788 hub_intr_alloc_nothd(devfs_handle_t dev, /* which crosstalk device */
789 device_desc_t dev_desc, /* device descriptor */
790 devfs_handle_t owner_dev) /* owner of this interrupt, if known */
791 {
792 return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1));
793 }
794
795 /*
796 * Free resources consumed by intr_alloc.
797 */
798 void
799 hub_intr_free(hub_intr_t intr_hdl)
800 {
801 cpuid_t cpu = intr_hdl->i_cpuid;
802 int bit = intr_hdl->i_bit;
803 xtalk_intr_t xtalk_info;
804
805 if (intr_hdl->i_flags & HUB_INTR_IS_CONNECTED) {
806 /* Setting the following fields in the xtalk interrupt info
807 * clears the interrupt target register in the xtalk user
808 */
809 xtalk_info = &intr_hdl->i_xtalk_info;
810 xtalk_info->xi_dev = NODEV;
811 xtalk_info->xi_vector = 0;
812 xtalk_info->xi_addr = 0;
813 hub_intr_disconnect(intr_hdl);
814 }
815
816 if (intr_hdl->i_flags & HUB_INTR_IS_ALLOCED)
817 kfree(intr_hdl);
818
819 #if defined(NEW_INTERRUPTS)
820 intr_unreserve_level(cpu, bit);
821 #endif
822 }
823
824
825 /*
826 * Associate resources allocated with a previous hub_intr_alloc call with the
827 * described handler, arg, name, etc.
828 */
829 /*ARGSUSED*/
830 int
831 hub_intr_connect( hub_intr_t intr_hdl, /* xtalk intr resource handle */
832 intr_func_t intr_func, /* xtalk intr handler */
833 void *intr_arg, /* arg to intr handler */
834 xtalk_intr_setfunc_t setfunc, /* func to set intr hw */
835 void *setfunc_arg, /* arg to setfunc */
836 void *thread) /* intr thread to use */
837 {
838 int rv;
839 cpuid_t cpu = intr_hdl->i_cpuid;
840 int bit = intr_hdl->i_bit;
841 #ifdef CONFIG_IA64_SGI_SN1
842 extern int synergy_intr_connect(int, int);
843 #endif
844
845 ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED);
846
847 #if defined(NEW_INTERRUPTS)
848 rv = intr_connect_level(cpu, bit, intr_hdl->i_swlevel,
849 intr_func, intr_arg, NULL);
850 if (rv < 0)
851 return(rv);
852
853 #endif
854 intr_hdl->i_xtalk_info.xi_setfunc = setfunc;
855 intr_hdl->i_xtalk_info.xi_sfarg = setfunc_arg;
856
857 if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl);
858
859 intr_hdl->i_flags |= HUB_INTR_IS_CONNECTED;
860 #ifdef CONFIG_IA64_SGI_SN1
861 return(synergy_intr_connect((int)bit, (int)cpu));
862 #endif
863 }
864
865
866 /*
867 * Disassociate handler with the specified interrupt.
868 */
869 void
870 hub_intr_disconnect(hub_intr_t intr_hdl)
871 {
872 /*REFERENCED*/
873 int rv;
874 cpuid_t cpu = intr_hdl->i_cpuid;
875 int bit = intr_hdl->i_bit;
876 xtalk_intr_setfunc_t setfunc;
877
878 setfunc = intr_hdl->i_xtalk_info.xi_setfunc;
879
880 /* TBD: send disconnected interrupts somewhere harmless */
881 if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl);
882
883 #if defined(NEW_INTERRUPTS)
884 rv = intr_disconnect_level(cpu, bit);
885 ASSERT(rv == 0);
886 #endif
887
888 intr_hdl->i_flags &= ~HUB_INTR_IS_CONNECTED;
889 }
890
891
892 /*
893 * Return a hwgraph vertex that represents the CPU currently
894 * targeted by an interrupt.
895 */
896 devfs_handle_t
897 hub_intr_cpu_get(hub_intr_t intr_hdl)
898 {
899 cpuid_t cpuid = intr_hdl->i_cpuid;
900 ASSERT(cpuid != CPU_NONE);
901
902 return(cpuid_to_vertex(cpuid));
903 }
904
905
906
907 /* CONFIGURATION MANAGEMENT */
908
909 /*
910 * Perform initializations that allow this hub to start crosstalk support.
911 */
912 void
913 hub_provider_startup(devfs_handle_t hubv)
914 {
915 hub_pio_init(hubv);
916 hub_dma_init(hubv);
917 hub_intr_init(hubv);
918 }
919
920 /*
921 * Shutdown crosstalk support from a hub.
922 */
923 void
924 hub_provider_shutdown(devfs_handle_t hub)
925 {
926 /* TBD */
927 xtalk_provider_unregister(hub);
928 }
929
930 /*
931 * Check that an address is in teh real small window widget 0 space
932 * or else in the big window we're using to emulate small window 0
933 * in the kernel.
934 */
935 int
936 hub_check_is_widget0(void *addr)
937 {
938 nasid_t nasid = NASID_GET(addr);
939
940 if (((__psunsigned_t)addr >= RAW_NODE_SWIN_BASE(nasid, 0)) &&
941 ((__psunsigned_t)addr < RAW_NODE_SWIN_BASE(nasid, 1)))
942 return 1;
943 return 0;
944 }
945
946
947 /*
948 * Check that two addresses use the same widget
949 */
950 int
951 hub_check_window_equiv(void *addra, void *addrb)
952 {
953 if (hub_check_is_widget0(addra) && hub_check_is_widget0(addrb))
954 return 1;
955
956 /* XXX - Assume this is really a small window address */
957 if (WIDGETID_GET((__psunsigned_t)addra) ==
958 WIDGETID_GET((__psunsigned_t)addrb))
959 return 1;
960
961 return 0;
962 }
963
964
965 /*
966 * Determine whether two PCI addresses actually refer to the same device.
967 * This only works if both addresses are in small windows. It's used to
968 * determine whether prom addresses refer to particular PCI devices.
969 */
970 /*
971 * XXX - This won't work as written if we ever have more than two nodes
972 * on a crossbow. In that case, we'll need an array or partners.
973 */
974 int
975 hub_check_pci_equiv(void *addra, void *addrb)
976 {
977 nasid_t nasida, nasidb;
978
979 /*
980 * This is for a permanent workaround that causes us to use a
981 * big window in place of small window 0.
982 */
983 if (!hub_check_window_equiv(addra, addrb))
984 return 0;
985
986 /* If the offsets aren't the same, forget it. */
987 if (SWIN_WIDGETADDR((__psunsigned_t)addra) !=
988 (SWIN_WIDGETADDR((__psunsigned_t)addrb)))
989 return 0;
990
991 /* Now, check the nasids */
992 nasida = NASID_GET(addra);
993 nasidb = NASID_GET(addrb);
994
995 ASSERT(NASID_TO_COMPACT_NODEID(nasida) != INVALID_NASID);
996 ASSERT(NASID_TO_COMPACT_NODEID(nasidb) != INVALID_NASID);
997
998 /*
999 * Either the NASIDs must be the same or they must be crossbow
1000 * partners (on the same crossbow).
1001 */
1002 return (check_nasid_equiv(nasida, nasidb));
1003 }
1004
1005 /*
1006 * hub_setup_prb(nasid, prbnum, credits, conveyor)
1007 *
1008 * Put a PRB into fire-and-forget mode if conveyor isn't set. Otehrwise,
1009 * put it into conveyor belt mode with the specified number of credits.
1010 */
1011 void
1012 hub_setup_prb(nasid_t nasid, int prbnum, int credits, int conveyor)
1013 {
1014 iprb_t prb;
1015 int prb_offset;
1016 #ifdef LATER
1017 extern int force_fire_and_forget;
1018 extern volatile int ignore_conveyor_override;
1019
1020 if (force_fire_and_forget && !ignore_conveyor_override)
1021 if (conveyor == HUB_PIO_CONVEYOR)
1022 conveyor = HUB_PIO_FIRE_N_FORGET;
1023 #endif
1024
1025 /*
1026 * Get the current register value.
1027 */
1028 prb_offset = IIO_IOPRB(prbnum);
1029 prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset);
1030
1031 /*
1032 * Clear out some fields.
1033 */
1034 prb.iprb_ovflow = 1;
1035 prb.iprb_bnakctr = 0;
1036 prb.iprb_anakctr = 0;
1037
1038 /*
1039 * Enable or disable fire-and-forget mode.
1040 */
1041 prb.iprb_ff = ((conveyor == HUB_PIO_CONVEYOR) ? 0 : 1);
1042
1043 /*
1044 * Set the appropriate number of PIO cresits for the widget.
1045 */
1046 prb.iprb_xtalkctr = credits;
1047
1048 /*
1049 * Store the new value to the register.
1050 */
1051 REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval);
1052 }
1053
1054 /*
1055 * hub_set_piomode()
1056 *
1057 * Put the hub into either "PIO conveyor belt" mode or "fire-and-forget"
1058 * mode. To do this, we have to make absolutely sure that no PIOs
1059 * are in progress so we turn off access to all widgets for the duration
1060 * of the function.
1061 *
1062 * XXX - This code should really check what kind of widget we're talking
1063 * to. Bridges can only handle three requests, but XG will do more.
1064 * How many can crossbow handle to widget 0? We're assuming 1.
1065 *
1066 * XXX - There is a bug in the crossbow that link reset PIOs do not
1067 * return write responses. The easiest solution to this problem is to
1068 * leave widget 0 (xbow) in fire-and-forget mode at all times. This
1069 * only affects pio's to xbow registers, which should be rare.
1070 */
1071 void
1072 hub_set_piomode(nasid_t nasid, int conveyor)
1073 {
1074 hubreg_t ii_iowa;
1075 int direct_connect;
1076 hubii_wcr_t ii_wcr;
1077 int prbnum;
1078 int cons_lock = 0;
1079
1080 ASSERT(NASID_TO_COMPACT_NODEID(nasid) != INVALID_CNODEID);
1081 if (nasid == get_console_nasid()) {
1082 PUTBUF_LOCK(s);
1083 cons_lock = 1;
1084 }
1085
1086 ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS);
1087 REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0);
1088
1089 ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR);
1090 direct_connect = ii_wcr.iwcr_dir_con;
1091
1092 if (direct_connect) {
1093 /*
1094 * Assume a bridge here.
1095 */
1096 hub_setup_prb(nasid, 0, 3, conveyor);
1097 } else {
1098 /*
1099 * Assume a crossbow here.
1100 */
1101 hub_setup_prb(nasid, 0, 1, conveyor);
1102 }
1103
1104 for (prbnum = HUB_WIDGET_ID_MIN; prbnum <= HUB_WIDGET_ID_MAX; prbnum++) {
1105 /*
1106 * XXX - Here's where we should take the widget type into
1107 * when account assigning credits.
1108 */
1109 /* Always set the PRBs in fire-and-forget mode */
1110 hub_setup_prb(nasid, prbnum, 3, conveyor);
1111 }
1112
1113 REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa);
1114
1115 if (cons_lock)
1116 PUTBUF_UNLOCK(s);
1117 }
1118 /* Interface to allow special drivers to set hub specific
1119 * device flags.
1120 * Return 0 on failure , 1 on success
1121 */
1122 int
1123 hub_widget_flags_set(nasid_t nasid,
1124 xwidgetnum_t widget_num,
1125 hub_widget_flags_t flags)
1126 {
1127
1128 ASSERT((flags & HUB_WIDGET_FLAGS) == flags);
1129
1130 if (flags & HUB_PIO_CONVEYOR) {
1131 hub_setup_prb(nasid,widget_num,
1132 3,HUB_PIO_CONVEYOR); /* set the PRB in conveyor
1133 * belt mode with 3 credits
1134 */
1135 } else if (flags & HUB_PIO_FIRE_N_FORGET) {
1136 hub_setup_prb(nasid,widget_num,
1137 3,HUB_PIO_FIRE_N_FORGET); /* set the PRB in fire
1138 * and forget mode
1139 */
1140 }
1141
1142 return 1;
1143 }
1144 /* Interface to allow special drivers to set hub specific
1145 * device flags.
1146 * Return 0 on failure , 1 on success
1147 */
1148 int
1149 hub_device_flags_set(devfs_handle_t widget_vhdl,
1150 hub_widget_flags_t flags)
1151 {
1152 xwidget_info_t widget_info = xwidget_info_get(widget_vhdl);
1153 xwidgetnum_t widget_num = xwidget_info_id_get(widget_info);
1154 devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info);
1155 hubinfo_t hub_info = 0;
1156 nasid_t nasid;
1157 unsigned long s;
1158 int rv;
1159
1160 /* Use the nasid from the hub info hanging off the hub vertex
1161 * and widget number from the widget vertex
1162 */
1163 hubinfo_get(hub_vhdl, &hub_info);
1164 /* Being over cautious by grabbing a lock */
1165 s = mutex_spinlock(&hub_info->h_bwlock);
1166 nasid = hub_info->h_nasid;
1167 rv = hub_widget_flags_set(nasid,widget_num,flags);
1168 mutex_spinunlock(&hub_info->h_bwlock, s);
1169
1170 return rv;
1171 }
1172
1173 #if ((defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && defined(BRINGUP))
1174 /* BRINGUP: This ought to be useful for IP27 too but, for now,
1175 * make it SN1 only because `ii_ixtt_u_t' is not in IP27/hubio.h
1176 * (or anywhere else :-).
1177 */
1178 int
1179 hubii_ixtt_set(devfs_handle_t widget_vhdl, ii_ixtt_u_t *ixtt)
1180 {
1181 xwidget_info_t widget_info = xwidget_info_get(widget_vhdl);
1182 devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info);
1183 hubinfo_t hub_info = 0;
1184 nasid_t nasid;
1185 unsigned long s;
1186
1187 /* Use the nasid from the hub info hanging off the hub vertex
1188 * and widget number from the widget vertex
1189 */
1190 hubinfo_get(hub_vhdl, &hub_info);
1191 /* Being over cautious by grabbing a lock */
1192 s = mutex_spinlock(&hub_info->h_bwlock);
1193 nasid = hub_info->h_nasid;
1194
1195 REMOTE_HUB_S(nasid, IIO_IXTT, ixtt->ii_ixtt_regval);
1196
1197 mutex_spinunlock(&hub_info->h_bwlock, s);
1198 return 0;
1199 }
1200
1201 int
1202 hubii_ixtt_get(devfs_handle_t widget_vhdl, ii_ixtt_u_t *ixtt)
1203 {
1204 xwidget_info_t widget_info = xwidget_info_get(widget_vhdl);
1205 devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info);
1206 hubinfo_t hub_info = 0;
1207 nasid_t nasid;
1208 unsigned long s;
1209
1210 /* Use the nasid from the hub info hanging off the hub vertex
1211 * and widget number from the widget vertex
1212 */
1213 hubinfo_get(hub_vhdl, &hub_info);
1214 /* Being over cautious by grabbing a lock */
1215 s = mutex_spinlock(&hub_info->h_bwlock);
1216 nasid = hub_info->h_nasid;
1217
1218 ixtt->ii_ixtt_regval = REMOTE_HUB_L(nasid, IIO_IXTT);
1219
1220 mutex_spinunlock(&hub_info->h_bwlock, s);
1221 return 0;
1222 }
1223 #endif /* CONFIG_IA64_SGI_SN1 */
1224
1225 /*
1226 * hub_device_inquiry
1227 * Find out the xtalk widget related information stored in this
1228 * hub's II.
1229 */
1230 void
1231 hub_device_inquiry(devfs_handle_t xbus_vhdl, xwidgetnum_t widget)
1232 {
1233 devfs_handle_t xconn, hub_vhdl;
1234 char widget_name[8];
1235 hubreg_t ii_iidem,ii_iiwa, ii_iowa;
1236 hubinfo_t hubinfo;
1237 nasid_t nasid;
1238 int d;
1239
1240 sprintf(widget_name, "%d", widget);
1241 if (hwgraph_traverse(xbus_vhdl, widget_name, &xconn)
1242 != GRAPH_SUCCESS)
1243 return;
1244
1245 hub_vhdl = device_master_get(xconn);
1246 if (hub_vhdl == GRAPH_VERTEX_NONE)
1247 return;
1248
1249 hubinfo_get(hub_vhdl, &hubinfo);
1250 if (!hubinfo)
1251 return;
1252
1253 nasid = hubinfo->h_nasid;
1254
1255 ii_iidem = REMOTE_HUB_L(nasid, IIO_IIDEM);
1256 ii_iiwa = REMOTE_HUB_L(nasid, IIO_IIWA);
1257 ii_iowa = REMOTE_HUB_L(nasid, IIO_IOWA);
1258
1259 #if defined(SUPPORT_PRINTING_V_FORMAT)
1260 printk("Inquiry Info for %v\n", xconn);
1261 #else
1262 printk("Inquiry Info for 0x%x\n", xconn);
1263 #endif
1264
1265 printk("\tDevices shutdown [ ");
1266
1267 for (d = 0 ; d <= 7 ; d++)
1268 if (!(ii_iidem & (IIO_IIDEM_WIDGETDEV_MASK(widget,d))))
1269 printk(" %d", d);
1270
1271 printk("]\n");
1272
1273 printk("\tInbound access ? %s\n",
1274 ii_iiwa & IIO_IIWA_WIDGET(widget) ? "yes" : "no");
1275
1276 printk("\tOutbound access ? %s\n",
1277 ii_iowa & IIO_IOWA_WIDGET(widget) ? "yes" : "no");
1278
1279 }
1280
1281 /*
1282 * A pointer to this structure hangs off of every hub hwgraph vertex.
1283 * The generic xtalk layer may indirect through it to get to this specific
1284 * crosstalk bus provider.
1285 */
1286 xtalk_provider_t hub_provider = {
1287 (xtalk_piomap_alloc_f *) hub_piomap_alloc,
1288 (xtalk_piomap_free_f *) hub_piomap_free,
1289 (xtalk_piomap_addr_f *) hub_piomap_addr,
1290 (xtalk_piomap_done_f *) hub_piomap_done,
1291 (xtalk_piotrans_addr_f *) hub_piotrans_addr,
1292
1293 (xtalk_dmamap_alloc_f *) hub_dmamap_alloc,
1294 (xtalk_dmamap_free_f *) hub_dmamap_free,
1295 (xtalk_dmamap_addr_f *) hub_dmamap_addr,
1296 (xtalk_dmamap_list_f *) hub_dmamap_list,
1297 (xtalk_dmamap_done_f *) hub_dmamap_done,
1298 (xtalk_dmatrans_addr_f *) hub_dmatrans_addr,
1299 (xtalk_dmatrans_list_f *) hub_dmatrans_list,
1300 (xtalk_dmamap_drain_f *) hub_dmamap_drain,
1301 (xtalk_dmaaddr_drain_f *) hub_dmaaddr_drain,
1302 (xtalk_dmalist_drain_f *) hub_dmalist_drain,
1303
1304 (xtalk_intr_alloc_f *) hub_intr_alloc,
1305 (xtalk_intr_alloc_f *) hub_intr_alloc_nothd,
1306 (xtalk_intr_free_f *) hub_intr_free,
1307 (xtalk_intr_connect_f *) hub_intr_connect,
1308 (xtalk_intr_disconnect_f *) hub_intr_disconnect,
1309 (xtalk_intr_cpu_get_f *) hub_intr_cpu_get,
1310
1311 (xtalk_provider_startup_f *) hub_provider_startup,
1312 (xtalk_provider_shutdown_f *) hub_provider_shutdown,
1313 };
1314
1315