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