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