patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / arch / ia64 / sn / io / io.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
7  */
8
9 #include <linux/types.h>
10 #include <linux/slab.h>
11 #include <linux/sched.h>
12 #include <asm/sn/types.h>
13 #include <asm/sn/sgi.h>
14 #include <asm/sn/driver.h>
15 #include <asm/param.h>
16 #include <asm/sn/pio.h>
17 #include <asm/sn/xtalk/xwidget.h>
18 #include <asm/sn/io.h>
19 #include <asm/sn/sn_private.h>
20 #include <asm/sn/addrs.h>
21 #include <asm/sn/hcl.h>
22 #include <asm/sn/hcl_util.h>
23 #include <asm/sn/intr.h>
24 #include <asm/sn/xtalk/xtalkaddrs.h>
25 #include <asm/sn/klconfig.h>
26 #include <asm/sn/sn_cpuid.h>
27
28 extern xtalk_provider_t hub_provider;
29
30 static int force_fire_and_forget = 1;
31 static int ignore_conveyor_override;
32
33
34 /* 
35  * Implementation of hub iobus operations.
36  *
37  * Hub provides a crosstalk "iobus" on IP27 systems.  These routines
38  * provide a platform-specific implementation of xtalk used by all xtalk 
39  * cards on IP27 systems.
40  *
41  * Called from corresponding xtalk_* routines.
42  */
43
44
45 /* PIO MANAGEMENT */
46 /* For mapping system virtual address space to xtalk space on a specified widget */
47
48 /*
49  * Setup pio structures needed for a particular hub.
50  */
51 static void
52 hub_pio_init(vertex_hdl_t hubv)
53 {
54         xwidgetnum_t widget;
55         hubinfo_t hubinfo;
56         nasid_t nasid;
57         int bigwin;
58         hub_piomap_t hub_piomap;
59
60         hubinfo_get(hubv, &hubinfo);
61         nasid = hubinfo->h_nasid;
62
63         /* Initialize small window piomaps for this hub */
64         for (widget=0; widget <= HUB_WIDGET_ID_MAX; widget++) {
65                 hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget);
66                 hub_piomap->hpio_xtalk_info.xp_target = widget;
67                 hub_piomap->hpio_xtalk_info.xp_xtalk_addr = 0;
68                 hub_piomap->hpio_xtalk_info.xp_mapsz = SWIN_SIZE;
69                 hub_piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)NODE_SWIN_BASE(nasid, widget);
70                 hub_piomap->hpio_hub = hubv;
71                 hub_piomap->hpio_flags = HUB_PIOMAP_IS_VALID;
72         }
73
74         /* Initialize big window piomaps for this hub */
75         for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) {
76                 hub_piomap = hubinfo_bwin_piomap_get(hubinfo, bigwin);
77                 hub_piomap->hpio_xtalk_info.xp_mapsz = BWIN_SIZE;
78                 hub_piomap->hpio_hub = hubv;
79                 hub_piomap->hpio_holdcnt = 0;
80                 hub_piomap->hpio_flags = HUB_PIOMAP_IS_BIGWINDOW;
81                 IIO_ITTE_DISABLE(nasid, bigwin);
82         }
83         hub_set_piomode(nasid, HUB_PIO_CONVEYOR);
84
85         spin_lock_init(&hubinfo->h_bwlock);
86         init_waitqueue_head(&hubinfo->h_bwwait);
87 }
88
89 /* 
90  * Create a caddr_t-to-xtalk_addr mapping.
91  *
92  * Use a small window if possible (that's the usual case), but
93  * manage big windows if needed.  Big window mappings can be
94  * either FIXED or UNFIXED -- we keep at least 1 big window available
95  * for UNFIXED mappings.
96  *
97  * Returns an opaque pointer-sized type which can be passed to
98  * other hub_pio_* routines on success, or NULL if the request
99  * cannot be satisfied.
100  */
101 /* ARGSUSED */
102 hub_piomap_t
103 hub_piomap_alloc(vertex_hdl_t dev,      /* set up mapping for this device */
104                 device_desc_t dev_desc, /* device descriptor */
105                 iopaddr_t xtalk_addr,   /* map for this xtalk_addr range */
106                 size_t byte_count,
107                 size_t byte_count_max,  /* maximum size of a mapping */
108                 unsigned flags)         /* defined in sys/pio.h */
109 {
110         xwidget_info_t widget_info = xwidget_info_get(dev);
111         xwidgetnum_t widget = xwidget_info_id_get(widget_info);
112         vertex_hdl_t hubv = xwidget_info_master_get(widget_info);
113         hubinfo_t hubinfo;
114         hub_piomap_t bw_piomap;
115         int bigwin, free_bw_index;
116         nasid_t nasid;
117         volatile hubreg_t junk;
118         caddr_t kvaddr;
119 #ifdef PIOMAP_UNC_ACC_SPACE
120         uint64_t addr;
121 #endif
122
123         /* sanity check */
124         if (byte_count_max > byte_count)
125                 return NULL;
126
127         hubinfo_get(hubv, &hubinfo);
128
129         /* If xtalk_addr range is mapped by a small window, we don't have 
130          * to do much 
131          */
132         if (xtalk_addr + byte_count <= SWIN_SIZE) {
133                 hub_piomap_t piomap;
134
135                 piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget);
136 #ifdef PIOMAP_UNC_ACC_SPACE
137                 if (flags & PIOMAP_UNC_ACC) {
138                         addr = (uint64_t)piomap->hpio_xtalk_info.xp_kvaddr;
139                         addr |= PIOMAP_UNC_ACC_SPACE;
140                         piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)addr;
141                 }
142 #endif
143                 return piomap;
144         }
145
146         /* We need to use a big window mapping.  */
147
148         /*
149          * TBD: Allow requests that would consume multiple big windows --
150          * split the request up and use multiple mapping entries.
151          * For now, reject requests that span big windows.
152          */
153         if ((xtalk_addr % BWIN_SIZE) + byte_count > BWIN_SIZE)
154                 return NULL;
155
156
157         /* Round xtalk address down for big window alignement */
158         xtalk_addr = xtalk_addr & ~(BWIN_SIZE-1);
159
160         /*
161          * Check to see if an existing big window mapping will suffice.
162          */
163 tryagain:
164         free_bw_index = -1;
165         spin_lock(&hubinfo->h_bwlock);
166         for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) {
167                 bw_piomap = hubinfo_bwin_piomap_get(hubinfo, bigwin);
168
169                 /* If mapping is not valid, skip it */
170                 if (!(bw_piomap->hpio_flags & HUB_PIOMAP_IS_VALID)) {
171                         free_bw_index = bigwin;
172                         continue;
173                 }
174
175                 /* 
176                  * If mapping is UNFIXED, skip it.  We don't allow sharing
177                  * of UNFIXED mappings, because this would allow starvation.
178                  */
179                 if (!(bw_piomap->hpio_flags & HUB_PIOMAP_IS_FIXED))
180                         continue;
181
182                 if ( xtalk_addr == bw_piomap->hpio_xtalk_info.xp_xtalk_addr &&
183                      widget == bw_piomap->hpio_xtalk_info.xp_target) {
184                         bw_piomap->hpio_holdcnt++;
185                         spin_unlock(&hubinfo->h_bwlock);
186                         return bw_piomap;
187                 }
188         }
189
190         /*
191          * None of the existing big window mappings will work for us --
192          * we need to establish a new mapping.
193          */
194
195         /* Insure that we don't consume all big windows with FIXED mappings */
196         if (flags & PIOMAP_FIXED) {
197                 if (hubinfo->h_num_big_window_fixed < HUB_NUM_BIG_WINDOW-1) {
198                         ASSERT(free_bw_index >= 0);
199                         hubinfo->h_num_big_window_fixed++;
200                 } else {
201                         bw_piomap = NULL;
202                         goto done;
203                 }
204         } else /* PIOMAP_UNFIXED */ {
205                 if (free_bw_index < 0) {
206                         if (flags & PIOMAP_NOSLEEP) {
207                                 bw_piomap = NULL;
208                                 goto done;
209                         } else {
210                                 DECLARE_WAITQUEUE(wait, current);
211
212                                 spin_unlock(&hubinfo->h_bwlock); 
213                                 set_current_state(TASK_UNINTERRUPTIBLE);
214                                 add_wait_queue_exclusive(&hubinfo->h_bwwait, &wait);
215                                 schedule();
216                                 remove_wait_queue(&hubinfo->h_bwwait, &wait);
217                                 goto tryagain;
218                         }
219                 }
220         }
221
222
223         /* OK!  Allocate big window free_bw_index for this mapping. */
224         /* 
225          * The code below does a PIO write to setup an ITTE entry.
226          * We need to prevent other CPUs from seeing our updated memory 
227          * shadow of the ITTE (in the piomap) until the ITTE entry is 
228          * actually set up; otherwise, another CPU might attempt a PIO 
229          * prematurely.  
230          *
231          * Also, the only way we can know that an entry has been received 
232          * by the hub and can be used by future PIO reads/writes is by 
233          * reading back the ITTE entry after writing it.
234          *
235          * For these two reasons, we PIO read back the ITTE entry after
236          * we write it.
237          */
238
239         nasid = hubinfo->h_nasid;
240         IIO_ITTE_PUT(nasid, free_bw_index, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr);     
241         junk = HUB_L(IIO_ITTE_GET(nasid, free_bw_index));
242
243         bw_piomap = hubinfo_bwin_piomap_get(hubinfo, free_bw_index);
244         bw_piomap->hpio_xtalk_info.xp_dev = dev;
245         bw_piomap->hpio_xtalk_info.xp_target = widget;
246         bw_piomap->hpio_xtalk_info.xp_xtalk_addr = xtalk_addr;
247         kvaddr = (caddr_t)NODE_BWIN_BASE(nasid, free_bw_index);
248 #ifdef PIOMAP_UNC_ACC_SPACE
249         if (flags & PIOMAP_UNC_ACC) {
250                 addr = (uint64_t)kvaddr;
251                 addr |= PIOMAP_UNC_ACC_SPACE;
252                 kvaddr = (caddr_t)addr;
253         }
254 #endif
255         bw_piomap->hpio_xtalk_info.xp_kvaddr = kvaddr;
256         bw_piomap->hpio_holdcnt++;
257         bw_piomap->hpio_bigwin_num = free_bw_index;
258
259         if (flags & PIOMAP_FIXED)
260                 bw_piomap->hpio_flags |= HUB_PIOMAP_IS_VALID | HUB_PIOMAP_IS_FIXED;
261         else
262                 bw_piomap->hpio_flags |= HUB_PIOMAP_IS_VALID;
263
264 done:
265         spin_unlock(&hubinfo->h_bwlock);
266         return bw_piomap;
267 }
268
269 /*
270  * hub_piomap_free destroys a caddr_t-to-xtalk pio mapping and frees
271  * any associated mapping resources.  
272  *
273  * If this * piomap was handled with a small window, or if it was handled
274  * in a big window that's still in use by someone else, then there's 
275  * nothing to do.  On the other hand, if this mapping was handled 
276  * with a big window, AND if we were the final user of that mapping, 
277  * then destroy the mapping.
278  */
279 void
280 hub_piomap_free(hub_piomap_t hub_piomap)
281 {
282         vertex_hdl_t hubv;
283         hubinfo_t hubinfo;
284         nasid_t nasid;
285
286         /* 
287          * Small windows are permanently mapped to corresponding widgets,
288          * so there're no resources to free.
289          */
290         if (!(hub_piomap->hpio_flags & HUB_PIOMAP_IS_BIGWINDOW))
291                 return;
292
293         ASSERT(hub_piomap->hpio_flags & HUB_PIOMAP_IS_VALID);
294         ASSERT(hub_piomap->hpio_holdcnt > 0);
295
296         hubv = hub_piomap->hpio_hub;
297         hubinfo_get(hubv, &hubinfo);
298         nasid = hubinfo->h_nasid;
299
300         spin_lock(&hubinfo->h_bwlock);
301
302         /*
303          * If this is the last hold on this mapping, free it.
304          */
305         if (--hub_piomap->hpio_holdcnt == 0) {
306                 IIO_ITTE_DISABLE(nasid, hub_piomap->hpio_bigwin_num );
307
308                 if (hub_piomap->hpio_flags & HUB_PIOMAP_IS_FIXED) {
309                         hub_piomap->hpio_flags &= ~(HUB_PIOMAP_IS_VALID | HUB_PIOMAP_IS_FIXED);
310                         hubinfo->h_num_big_window_fixed--;
311                         ASSERT(hubinfo->h_num_big_window_fixed >= 0);
312                 } else
313                         hub_piomap->hpio_flags &= ~HUB_PIOMAP_IS_VALID;
314
315                 wake_up(&hubinfo->h_bwwait);
316         }
317
318         spin_unlock(&hubinfo->h_bwlock);
319 }
320
321 /*
322  * Establish a mapping to a given xtalk address range using the resources
323  * allocated earlier.
324  */
325 caddr_t
326 hub_piomap_addr(hub_piomap_t hub_piomap,        /* mapping resources */
327                 iopaddr_t xtalk_addr,           /* map for this xtalk address */
328                 size_t byte_count)              /* map this many bytes */
329 {
330         /* Verify that range can be mapped using the specified piomap */
331         if (xtalk_addr < hub_piomap->hpio_xtalk_info.xp_xtalk_addr)
332                 return 0;
333
334         if (xtalk_addr + byte_count > 
335                 ( hub_piomap->hpio_xtalk_info.xp_xtalk_addr + 
336                         hub_piomap->hpio_xtalk_info.xp_mapsz))
337                 return 0;
338
339         if (hub_piomap->hpio_flags & HUB_PIOMAP_IS_VALID)
340                 return hub_piomap->hpio_xtalk_info.xp_kvaddr + 
341                         (xtalk_addr % hub_piomap->hpio_xtalk_info.xp_mapsz);
342         else
343                 return 0;
344 }
345
346
347 /*
348  * Driver indicates that it's done with PIO's from an earlier piomap_addr.
349  */
350 /* ARGSUSED */
351 void
352 hub_piomap_done(hub_piomap_t hub_piomap)        /* done with these mapping resources */
353 {
354         /* Nothing to do */
355 }
356
357
358 /*
359  * For translations that require no mapping resources, supply a kernel virtual
360  * address that maps to the specified xtalk address range.
361  */
362 /* ARGSUSED */
363 caddr_t
364 hub_piotrans_addr(      vertex_hdl_t dev,       /* translate to this device */
365                         device_desc_t dev_desc, /* device descriptor */
366                         iopaddr_t xtalk_addr,   /* Crosstalk address */
367                         size_t byte_count,      /* map this many bytes */
368                         unsigned flags)         /* (currently unused) */
369 {
370         xwidget_info_t widget_info = xwidget_info_get(dev);
371         xwidgetnum_t widget = xwidget_info_id_get(widget_info);
372         vertex_hdl_t hubv = xwidget_info_master_get(widget_info);
373         hub_piomap_t hub_piomap;
374         hubinfo_t hubinfo;
375         caddr_t addr;
376
377         hubinfo_get(hubv, &hubinfo);
378
379         if (xtalk_addr + byte_count <= SWIN_SIZE) {
380                 hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget);
381                 addr = hub_piomap_addr(hub_piomap, xtalk_addr, byte_count);
382 #ifdef PIOMAP_UNC_ACC_SPACE
383                 if (flags & PIOMAP_UNC_ACC) {
384                         uint64_t iaddr;
385                         iaddr = (uint64_t)addr;
386                         iaddr |= PIOMAP_UNC_ACC_SPACE;
387                         addr = (caddr_t)iaddr;
388                 }
389 #endif
390                 return addr;
391         } else
392                 return 0;
393 }
394
395
396 /* DMA MANAGEMENT */
397 /* Mapping from crosstalk space to system physical space */
398
399
400 /*
401  * Allocate resources needed to set up DMA mappings up to a specified size
402  * on a specified adapter.
403  * 
404  * We don't actually use the adapter ID for anything.  It's just the adapter
405  * that the lower level driver plans to use for DMA.
406  */
407 /* ARGSUSED */
408 hub_dmamap_t
409 hub_dmamap_alloc(       vertex_hdl_t dev,       /* set up mappings for this device */
410                         device_desc_t dev_desc, /* device descriptor */
411                         size_t byte_count_max,  /* max size of a mapping */
412                         unsigned flags)         /* defined in dma.h */
413 {
414         hub_dmamap_t dmamap;
415         xwidget_info_t widget_info = xwidget_info_get(dev);
416         xwidgetnum_t widget = xwidget_info_id_get(widget_info);
417         vertex_hdl_t hubv = xwidget_info_master_get(widget_info);
418
419         dmamap = kmalloc(sizeof(struct hub_dmamap_s), GFP_ATOMIC);
420         dmamap->hdma_xtalk_info.xd_dev = dev;
421         dmamap->hdma_xtalk_info.xd_target = widget;
422         dmamap->hdma_hub = hubv;
423         dmamap->hdma_flags = HUB_DMAMAP_IS_VALID;
424         if (flags & XTALK_FIXED)
425                 dmamap->hdma_flags |= HUB_DMAMAP_IS_FIXED;
426
427         return dmamap;
428 }
429
430 /*
431  * Destroy a DMA mapping from crosstalk space to system address space.
432  * There is no actual mapping hardware to destroy, but we at least mark
433  * the dmamap INVALID and free the space that it took.
434  */
435 void
436 hub_dmamap_free(hub_dmamap_t hub_dmamap)
437 {
438         hub_dmamap->hdma_flags &= ~HUB_DMAMAP_IS_VALID;
439         kfree(hub_dmamap);
440 }
441
442 /*
443  * Establish a DMA mapping using the resources allocated in a previous dmamap_alloc.
444  * Return an appropriate crosstalk address range that maps to the specified physical 
445  * address range.
446  */
447 /* ARGSUSED */
448 extern iopaddr_t
449 hub_dmamap_addr(        hub_dmamap_t dmamap,    /* use these mapping resources */
450                         paddr_t paddr,          /* map for this address */
451                         size_t byte_count)      /* map this many bytes */
452 {
453         vertex_hdl_t vhdl;
454
455         ASSERT(dmamap->hdma_flags & HUB_DMAMAP_IS_VALID);
456
457         if (dmamap->hdma_flags & HUB_DMAMAP_USED) {
458             /* If the map is FIXED, re-use is OK. */
459             if (!(dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) {
460                 char name[MAXDEVNAME];
461                 vhdl = dmamap->hdma_xtalk_info.xd_dev;
462                 printk(KERN_WARNING  "%s: hub_dmamap_addr re-uses dmamap.\n", vertex_to_name(vhdl, name, MAXDEVNAME));
463             }
464         } else {
465                 dmamap->hdma_flags |= HUB_DMAMAP_USED;
466         }
467
468         /* There isn't actually any DMA mapping hardware on the hub. */
469         return (PHYS_TO_DMA(paddr));
470 }
471
472 /*
473  * Driver indicates that it has completed whatever DMA it may have started
474  * after an earlier dmamap_addr call.
475  */
476 void
477 hub_dmamap_done(hub_dmamap_t hub_dmamap)        /* done with these mapping resources */
478 {
479         vertex_hdl_t vhdl;
480
481         if (hub_dmamap->hdma_flags & HUB_DMAMAP_USED) {
482                 hub_dmamap->hdma_flags &= ~HUB_DMAMAP_USED;
483         } else {
484             /* If the map is FIXED, re-done is OK. */
485             if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) {
486                 char name[MAXDEVNAME];
487                 vhdl = hub_dmamap->hdma_xtalk_info.xd_dev;
488                 printk(KERN_WARNING  "%s: hub_dmamap_done already done with dmamap\n", vertex_to_name(vhdl, name, MAXDEVNAME));
489             }
490         }
491 }
492
493 /*
494  * Translate a single system physical address into a crosstalk address.
495  */
496 /* ARGSUSED */
497 iopaddr_t
498 hub_dmatrans_addr(      vertex_hdl_t dev,       /* translate for this device */
499                         device_desc_t dev_desc, /* device descriptor */
500                         paddr_t paddr,          /* system physical address */
501                         size_t byte_count,      /* length */
502                         unsigned flags)         /* defined in dma.h */
503 {
504         return (PHYS_TO_DMA(paddr));
505 }
506
507 /*ARGSUSED*/
508 void
509 hub_dmamap_drain(       hub_dmamap_t map)
510 {
511     /* XXX- flush caches, if cache coherency WAR is needed */
512 }
513
514 /*ARGSUSED*/
515 void
516 hub_dmaaddr_drain(      vertex_hdl_t vhdl,
517                         paddr_t addr,
518                         size_t bytes)
519 {
520     /* XXX- flush caches, if cache coherency WAR is needed */
521 }
522
523
524 /* CONFIGURATION MANAGEMENT */
525
526 /*
527  * Perform initializations that allow this hub to start crosstalk support.
528  */
529 void
530 hub_provider_startup(vertex_hdl_t hubv)
531 {
532         hubinfo_t       hubinfo;
533
534         hubinfo_get(hubv, &hubinfo);
535         hub_pio_init(hubv);
536         intr_init_vecblk(nasid_to_cnodeid(hubinfo->h_nasid));
537 }
538
539 /*
540  * Shutdown crosstalk support from a hub.
541  */
542 void
543 hub_provider_shutdown(vertex_hdl_t hub)
544 {
545         /* TBD */
546         xtalk_provider_unregister(hub);
547 }
548
549 /*
550  * Check that an address is in the real small window widget 0 space
551  * or else in the big window we're using to emulate small window 0
552  * in the kernel.
553  */
554 int
555 hub_check_is_widget0(void *addr)
556 {
557         nasid_t nasid = NASID_GET(addr);
558
559         if (((unsigned long)addr >= RAW_NODE_SWIN_BASE(nasid, 0)) &&
560             ((unsigned long)addr < RAW_NODE_SWIN_BASE(nasid, 1)))
561                 return 1;
562         return 0;
563 }
564
565
566 /*
567  * Check that two addresses use the same widget
568  */
569 int
570 hub_check_window_equiv(void *addra, void *addrb)
571 {
572         if (hub_check_is_widget0(addra) && hub_check_is_widget0(addrb))
573                 return 1;
574
575         /* XXX - Assume this is really a small window address */
576         if (WIDGETID_GET((unsigned long)addra) ==
577             WIDGETID_GET((unsigned long)addrb))
578                 return 1;
579
580         return 0;
581 }
582
583
584 /*
585  * hub_setup_prb(nasid, prbnum, credits, conveyor)
586  *
587  *      Put a PRB into fire-and-forget mode if conveyor isn't set.  Otherwise,
588  *      put it into conveyor belt mode with the specified number of credits.
589  */
590 void
591 hub_setup_prb(nasid_t nasid, int prbnum, int credits, int conveyor)
592 {
593         iprb_t prb;
594         int prb_offset;
595
596         if (force_fire_and_forget && !ignore_conveyor_override)
597             if (conveyor == HUB_PIO_CONVEYOR)
598                 conveyor = HUB_PIO_FIRE_N_FORGET;
599
600         /*
601          * Get the current register value.
602          */
603         prb_offset = IIO_IOPRB(prbnum);
604         prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset);
605
606         /*
607          * Clear out some fields.
608          */
609         prb.iprb_ovflow = 1;
610         prb.iprb_bnakctr = 0;
611         prb.iprb_anakctr = 0;
612
613         /*
614          * Enable or disable fire-and-forget mode.
615          */
616         prb.iprb_ff = ((conveyor == HUB_PIO_CONVEYOR) ? 0 : 1);
617
618         /*
619          * Set the appropriate number of PIO cresits for the widget.
620          */
621         prb.iprb_xtalkctr = credits;
622
623         /*
624          * Store the new value to the register.
625          */
626         REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval);
627 }
628
629 /*
630  * hub_set_piomode()
631  *
632  *      Put the hub into either "PIO conveyor belt" mode or "fire-and-forget"
633  *      mode.  To do this, we have to make absolutely sure that no PIOs
634  *      are in progress so we turn off access to all widgets for the duration
635  *      of the function.
636  * 
637  * XXX - This code should really check what kind of widget we're talking
638  * to.  Bridges can only handle three requests, but XG will do more.
639  * How many can crossbow handle to widget 0?  We're assuming 1.
640  *
641  * XXX - There is a bug in the crossbow that link reset PIOs do not
642  * return write responses.  The easiest solution to this problem is to
643  * leave widget 0 (xbow) in fire-and-forget mode at all times.  This
644  * only affects pio's to xbow registers, which should be rare.
645  */
646 void
647 hub_set_piomode(nasid_t nasid, int conveyor)
648 {
649         hubreg_t ii_iowa;
650         int direct_connect;
651         hubii_wcr_t ii_wcr;
652         int prbnum;
653
654         ASSERT(nasid_to_cnodeid(nasid) != INVALID_CNODEID);
655
656         ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS);
657         REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0);
658
659         ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR);
660         direct_connect = ii_wcr.iwcr_dir_con;
661
662         if (direct_connect) {
663                 /* 
664                  * Assume a bridge here.
665                  */
666                 hub_setup_prb(nasid, 0, 3, conveyor);
667         } else {
668                 /* 
669                  * Assume a crossbow here.
670                  */
671                 hub_setup_prb(nasid, 0, 1, conveyor);
672         }
673
674         for (prbnum = HUB_WIDGET_ID_MIN; prbnum <= HUB_WIDGET_ID_MAX; prbnum++) {
675                 /*
676                  * XXX - Here's where we should take the widget type into
677                  * when account assigning credits.
678                  */
679                 /* Always set the PRBs in fire-and-forget mode */
680                 hub_setup_prb(nasid, prbnum, 3, conveyor);
681         }
682
683         REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa);
684 }
685 /* Interface to allow special drivers to set hub specific
686  * device flags.
687  * Return 0 on failure , 1 on success
688  */
689 int
690 hub_widget_flags_set(nasid_t            nasid,
691                      xwidgetnum_t       widget_num,
692                      hub_widget_flags_t flags)
693 {
694
695         ASSERT((flags & HUB_WIDGET_FLAGS) == flags);
696
697         if (flags & HUB_PIO_CONVEYOR) {
698                 hub_setup_prb(nasid,widget_num,
699                               3,HUB_PIO_CONVEYOR); /* set the PRB in conveyor 
700                                                     * belt mode with 3 credits
701                                                     */
702         } else if (flags & HUB_PIO_FIRE_N_FORGET) {
703                 hub_setup_prb(nasid,widget_num,
704                               3,HUB_PIO_FIRE_N_FORGET); /* set the PRB in fire
705                                                          *  and forget mode 
706                                                          */
707         }
708
709         return 1;
710 }
711
712 /*
713  * A pointer to this structure hangs off of every hub hwgraph vertex.
714  * The generic xtalk layer may indirect through it to get to this specific
715  * crosstalk bus provider.
716  */
717 xtalk_provider_t hub_provider = {
718         .piomap_alloc   = (xtalk_piomap_alloc_f *) hub_piomap_alloc,
719         .piomap_free    = (xtalk_piomap_free_f *) hub_piomap_free,
720         .piomap_addr    = (xtalk_piomap_addr_f *) hub_piomap_addr,
721         .piomap_done    = (xtalk_piomap_done_f *) hub_piomap_done,
722         .piotrans_addr  = (xtalk_piotrans_addr_f *) hub_piotrans_addr,
723
724         .dmamap_alloc   = (xtalk_dmamap_alloc_f *) hub_dmamap_alloc,
725         .dmamap_free    = (xtalk_dmamap_free_f *) hub_dmamap_free,
726         .dmamap_addr    = (xtalk_dmamap_addr_f *) hub_dmamap_addr,
727         .dmamap_done    = (xtalk_dmamap_done_f *) hub_dmamap_done,
728         .dmatrans_addr  = (xtalk_dmatrans_addr_f *) hub_dmatrans_addr,
729         .dmamap_drain   = (xtalk_dmamap_drain_f *) hub_dmamap_drain,
730         .dmaaddr_drain  = (xtalk_dmaaddr_drain_f *) hub_dmaaddr_drain,
731
732         .intr_alloc     = (xtalk_intr_alloc_f *) hub_intr_alloc,
733         .intr_alloc_nothd = (xtalk_intr_alloc_f *) hub_intr_alloc_nothd,
734         .intr_free      = (xtalk_intr_free_f *) hub_intr_free,
735         .intr_connect   = (xtalk_intr_connect_f *) hub_intr_connect,
736         .intr_disconnect = (xtalk_intr_disconnect_f *) hub_intr_disconnect,
737         .provider_startup = (xtalk_provider_startup_f *) hub_provider_startup,
738         .provider_shutdown = (xtalk_provider_shutdown_f *) hub_provider_shutdown,
739 };