File: /usr/src/linux/arch/ia64/sn/io/ml_SN_init.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/sgi.h>
15     #include <asm/sn/iograph.h>
16     #include <asm/sn/invent.h>
17     #include <asm/sn/hcl.h>
18     #include <asm/sn/labelcl.h>
19     #include <asm/sn/nodemask.h>
20     #include <asm/sn/sn_private.h>
21     #include <asm/sn/klconfig.h>
22     #include <asm/sn/sn_cpuid.h>
23     #include <asm/sn/synergy.h>
24     
25     
26     #if defined (CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
27     #include <asm/sn/sn1/ip27config.h>
28     #include <asm/sn/sn1/hubdev.h>
29     #include <asm/sn/sn1/sn1.h>
30     #endif /* CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 */
31     
32     
33     extern int numcpus;
34     extern char arg_maxnodes[];
35     extern cpuid_t master_procid;
36     extern void * kmem_alloc_node(register size_t, register int , cnodeid_t);
37     extern synergy_da_t    *Synergy_da_indr[];
38     
39     extern int hasmetarouter;
40     
41     int		maxcpus;
42     cpumask_t	boot_cpumask;
43     hubreg_t	region_mask = 0;
44     
45     
46     extern xwidgetnum_t hub_widget_id(nasid_t);
47     
48     static int	fine_mode = 0;
49     
50     static cnodemask_t	hub_init_mask;	/* Mask of cpu in a node doing init */
51     static volatile cnodemask_t hub_init_done_mask;
52     					/* Node mask where we wait for
53     					 * per hub initialization
54     					 */
55     spinlock_t		hub_mask_lock;  /* Lock for hub_init_mask above. */
56     
57     extern int valid_icache_reasons;	/* Reasons to flush the icache */
58     extern int valid_dcache_reasons;	/* Reasons to flush the dcache */
59     extern int numnodes;
60     extern u_char miniroot;
61     extern volatile int	need_utlbmiss_patch;
62     extern void iograph_early_init(void);
63     
64     nasid_t master_nasid = INVALID_NASID;
65     
66     
67     /*
68      * mlreset(int slave)
69      * 	very early machine reset - at this point NO interrupts have been
70      * 	enabled; nor is memory, tlb, p0, etc setup.
71      *
72      * 	slave is zero when mlreset is called for the master processor and
73      *	is nonzero thereafter.
74      */
75     
76     
77     void
78     mlreset(int slave)
79     {
80     	if (!slave) {
81     		/*
82     		 * We are the master cpu and node.
83     		 */ 
84     		master_nasid = get_nasid();
85     		set_master_bridge_base();
86     		FIXME("mlreset: Enable when we support ioc3 ..");
87     #ifdef	LATER
88     		if (get_console_nasid() == master_nasid) 
89     			/* Set up the IOC3 */
90     			ioc3_mlreset((ioc3_cfg_t *)KL_CONFIG_CH_CONS_INFO(master_nasid)->config_base,
91     				     (ioc3_mem_t *)KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base);
92     
93     		/*
94     		 * Initialize Master nvram base.
95     		 */
96     		nvram_baseinit();
97     
98     		fine_mode = is_fine_dirmode();
99     #endif /* LATER */
100     
101     		/* We're the master processor */
102     		master_procid = smp_processor_id();
103     		master_nasid = cpuid_to_nasid(master_procid);
104     
105     		/*
106     		 * master_nasid we get back better be same as one from
107     		 * get_nasid()
108     		 */
109     		ASSERT_ALWAYS(master_nasid == get_nasid());
110     
111     #ifdef	LATER
112     
113     	/*
114     	 * Activate when calias is implemented.
115     	 */
116     		/* Set all nodes' calias sizes to 8k */
117     		for (i = 0; i < maxnodes; i++) {
118     			nasid_t nasid;
119     			int	sn;
120     
121     			nasid = COMPACT_TO_NASID_NODEID(i);
122     
123     			/*
124     			 * Always have node 0 in the region mask, otherwise CALIAS accesses
125     			 * get exceptions since the hub thinks it is a node 0 address.
126     			 */
127     			for (sn=0; sn<NUM_SUBNODES; sn++) {
128     				REMOTE_HUB_PI_S(nasid, sn, PI_REGION_PRESENT, (region_mask | 1));
129     				REMOTE_HUB_PI_S(nasid, sn, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K);
130     			}
131     
132     			/*
133     			 * Set up all hubs to havew a big window pointing at
134     			 * widget 0.
135     			 * Memory mode, widget 0, offset 0
136     			 */
137     			REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN),
138     				((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) |
139     				(0 << IIO_ITTE_WIDGET_SHIFT)));
140     		}
141     #endif /* LATER */
142     
143     		/* Set up the hub initialization mask and init the lock */
144     		CNODEMASK_CLRALL(hub_init_mask);
145     		CNODEMASK_CLRALL(hub_init_done_mask);
146     
147     		spin_lock_init(&hub_mask_lock);
148     
149     		/* early initialization of iograph */
150     		iograph_early_init();
151     
152     		/* Initialize Hub Pseudodriver Management */
153     		hubdev_init();
154     
155     #ifdef	LATER
156     		/*
157     		 * Our IO system doesn't require cache writebacks.  Set some
158     		 * variables appropriately.
159     		 */
160     		cachewrback = 0;
161     		valid_icache_reasons &= ~(CACH_AVOID_VCES | CACH_IO_COHERENCY);
162     		valid_dcache_reasons &= ~(CACH_AVOID_VCES | CACH_IO_COHERENCY);
163     
164     		/*
165     		 * make sure we are running with the right rev of chips
166     		 */
167     		verify_snchip_rev();
168     
169     		/*
170                      * Since we've wiped out memory at this point, we
171                      * need to reset the ARCS vector table so that it
172                      * points to appropriate functions in the kernel
173                      * itself.  In this way, we can maintain the ARCS
174                      * vector table conventions without having to actually
175                      * keep redundant PROM code in memory.
176                      */
177     		he_arcs_set_vectors();
178     #endif /* LATER */
179     
180     	} else { /* slave != 0 */
181     		/*
182     		 * This code is performed ONLY by slave processors.
183     		 */
184     
185     	}
186     }
187     
188     
189     /* XXX - Move the meat of this to intr.c ? */
190     /*
191      * Set up the platform-dependent fields in the nodepda.
192      */
193     void init_platform_nodepda(nodepda_t *npda, cnodeid_t node)
194     {
195     	hubinfo_t hubinfo;
196     	int	  sn;
197     	cnodeid_t i;
198     	ushort *numcpus_p;
199     
200     	extern void router_map_init(nodepda_t *);
201     	extern void router_queue_init(nodepda_t *,cnodeid_t);
202     	extern void intr_init_vecblk(nodepda_t *, cnodeid_t, int);
203     
204     #if defined(DEBUG)
205     	extern spinlock_t	intr_dev_targ_map_lock;
206     	extern uint64_t 	intr_dev_targ_map_size;
207     
208     	/* Initialize the lock to access the device - target cpu mapping
209     	 * table. This table is explicitly for debugging purposes only and
210     	 * to aid the "intrmap" idbg command
211     	 */
212     	if (node == 0) {
213     		/* Make sure we do this only once .
214     		 * There is always a cnode 0 present.
215     		 */
216     		intr_dev_targ_map_size = 0;
217     		spin_lock_init(&intr_dev_targ_map_lock);
218     	}
219     #endif	/* DEBUG */
220     	/* Allocate per-node platform-dependent data */
221     	hubinfo = (hubinfo_t)kmem_alloc_node(sizeof(struct hubinfo_s), GFP_ATOMIC, node);
222     
223     	ASSERT_ALWAYS(hubinfo);
224     	npda->pdinfo = (void *)hubinfo;
225     	hubinfo->h_nodepda = npda;
226     	hubinfo->h_cnodeid = node;
227     	hubinfo->h_nasid = COMPACT_TO_NASID_NODEID(node);
228     
229     	spin_lock_init(&hubinfo->h_crblock);
230     
231     	hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid);
232     	npda->xbow_peer = INVALID_NASID;
233     	/* Initialize the linked list of
234     	 * router info pointers to the dependent routers
235     	 */
236     	npda->npda_rip_first = NULL;
237     	/* npda_rip_last always points to the place
238     	 * where the next element is to be inserted
239     	 * into the list 
240     	 */
241     	npda->npda_rip_last = &npda->npda_rip_first;
242     	npda->dependent_routers = 0;
243     	npda->module_id = INVALID_MODULE;
244     
245     	/*
246     	 * Initialize the subnodePDA.
247     	 */
248     	for (sn=0; sn<NUM_SUBNODES; sn++) {
249     		SNPDA(npda,sn)->prof_count = 0;
250     		SNPDA(npda,sn)->next_prof_timeout = 0;
251     		intr_init_vecblk(npda, node, sn);
252     	}
253     
254     	npda->vector_unit_busy = 0;
255     
256     	spin_lock_init(&npda->vector_lock);
257     	mutex_init_locked(&npda->xbow_sema); /* init it locked? */
258     	spin_lock_init(&npda->fprom_lock);
259     
260     	spin_lock_init(&npda->node_utlbswitchlock);
261     	npda->ni_error_print = 0;
262     #ifdef	LATER
263     	if (need_utlbmiss_patch) {
264     		npda->node_need_utlbmiss_patch = 1;
265     		npda->node_utlbmiss_patched = 1;
266     	}
267     #endif
268     
269     	/*
270     	 * Clear out the nasid mask.
271     	 */
272     	for (i = 0; i < NASID_MASK_BYTES; i++)
273     		npda->nasid_mask[i] = 0;
274     
275     	for (i = 0; i < numnodes; i++) {
276     		nasid_t nasid = COMPACT_TO_NASID_NODEID(i);
277     
278     		/* Set my mask bit */
279     		npda->nasid_mask[nasid / 8] |= (1 << nasid % 8);
280     	}
281     
282     #ifdef	LATER
283     	npda->node_first_cpu = get_cnode_cpu(node);
284     #endif
285     
286     	if (npda->node_first_cpu != CPU_NONE) {
287     		/*
288     		 * Count number of cpus only if first CPU is valid.
289     		 */
290     		numcpus_p = &npda->node_num_cpus;
291     		*numcpus_p = 0;
292     		for (i = npda->node_first_cpu; i < MAXCPUS; i++) {
293     			if (CPUID_TO_COMPACT_NODEID(i) != node)
294     			    break;
295     			else
296     			    (*numcpus_p)++;
297     		}
298     	} else {
299     		npda->node_num_cpus = 0; 
300     	}
301     
302     	/* Allocate memory for the dump stack on each node 
303     	 * This is useful during nmi handling since we
304     	 * may not be guaranteed shared memory at that time
305     	 * which precludes depending on a global dump stack
306     	 */
307     #ifdef	LATER
308     	npda->dump_stack = (uint64_t *)kmem_zalloc_node(DUMP_STACK_SIZE,VM_NOSLEEP,
309     							  node);
310     	ASSERT_ALWAYS(npda->dump_stack);
311     	ASSERT(npda->dump_stack);
312     #endif
313     	/* Initialize the counter which prevents
314     	 * both the cpus on a node to proceed with nmi
315     	 * handling.
316     	 */
317     #ifdef	LATER
318     	npda->dump_count = 0;
319     
320     	/* Setup the (module,slot) --> nic mapping for all the routers
321     	 * in the system. This is useful during error handling when
322     	 * there is no shared memory.
323     	 */
324     	router_map_init(npda);
325     
326     	/* Allocate memory for the per-node router traversal queue */
327     	router_queue_init(npda,node);
328     	npda->sbe_info = kmem_zalloc_node_hint(sizeof (sbe_info_t), 0, node);
329     	ASSERT(npda->sbe_info);
330     
331     #ifdef CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || CONFIG_IA64_GENERIC
332     	/*
333     	 * Initialize bte info pointers to NULL
334     	 */
335     	for (i = 0; i < BTES_PER_NODE; i++) {
336     		npda->node_bte_info[i] = (bteinfo_t *)NULL;
337     	}
338     #endif
339     #endif /* LATER */
340     }
341     
342     /* XXX - Move the interrupt stuff to intr.c ? */
343     /*
344      * Set up the platform-dependent fields in the processor pda.
345      * Must be done _after_ init_platform_nodepda().
346      * If we need a lock here, something else is wrong!
347      */
348     // void init_platform_pda(pda_t *ppda, cpuid_t cpu)
349     void init_platform_pda(cpuid_t cpu)
350     {
351     	hub_intmasks_t *intmasks;
352     #ifdef	LATER
353     	cpuinfo_t cpuinfo;
354     #endif
355     	int i;
356     	cnodeid_t	cnode;
357     	synergy_da_t	*sda;
358     	int	which_synergy;
359     
360     #ifdef	LATER
361     	/* Allocate per-cpu platform-dependent data */
362     	cpuinfo = (cpuinfo_t)kmem_alloc_node(sizeof(struct cpuinfo_s), GFP_ATOMIC, cputocnode(cpu));
363     	ASSERT_ALWAYS(cpuinfo);
364     	ppda->pdinfo = (void *)cpuinfo;
365     	cpuinfo->ci_cpupda = ppda;
366     	cpuinfo->ci_cpuid = cpu;
367     #endif
368     
369     	cnode = cpuid_to_cnodeid(cpu);
370     	which_synergy = cpuid_to_synergy(cpu);
371     	sda = Synergy_da_indr[(cnode * 2) + which_synergy];
372     	// intmasks = &ppda->p_intmasks;
373     	intmasks = &sda->s_intmasks;
374     
375     #ifdef	LATER
376     	ASSERT_ALWAYS(&ppda->p_nodepda);
377     #endif
378     
379     	/* Clear INT_PEND0 masks. */
380     	for (i = 0; i < N_INTPEND0_MASKS; i++)
381     		intmasks->intpend0_masks[i] = 0;
382     
383     	/* Set up pointer to the vector block in the nodepda. */
384     	/* (Cant use SUBNODEPDA - not working yet) */
385     	intmasks->dispatch0 = &Nodepdaindr[cnode]->snpda[cpuid_to_subnode(cpu)].intr_dispatch0;
386     	intmasks->dispatch1 = &Nodepdaindr[cnode]->snpda[cpuid_to_subnode(cpu)].intr_dispatch1;
387     
388     	/* Clear INT_PEND1 masks. */
389     	for (i = 0; i < N_INTPEND1_MASKS; i++)
390     		intmasks->intpend1_masks[i] = 0;
391     
392     
393     #ifdef	LATER
394     	/* Don't read the routers unless we're the master. */
395     	ppda->p_routertick = 0;
396     #endif
397     
398     }
399     
400     #if (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && !defined(BRINGUP)	/* protect low mem for IP35/7 */
401     #error "need protect_hub_calias, protect_nmi_handler_data"
402     #endif
403     
404     #ifdef	LATER
405     /*
406      * For now, just protect the first page (exception handlers). We
407      * may want to protect more stuff later.
408      */
409     void
410     protect_hub_calias(nasid_t nasid)
411     {
412     	paddr_t pa = NODE_OFFSET(nasid) + 0; /* page 0 on node nasid */
413     	int i;
414     
415     	for (i = 0; i < MAX_REGIONS; i++) {
416     		if (i == nasid_to_region(nasid))
417     			continue;
418     	}
419     }
420     
421     /*
422      * Protect the page of low memory used to communicate with the NMI handler.
423      */
424     void
425     protect_nmi_handler_data(nasid_t nasid, int slice)
426     {
427     	paddr_t pa = NODE_OFFSET(nasid) + NMI_OFFSET(nasid, slice);
428     	int i;
429     
430     	for (i = 0; i < MAX_REGIONS; i++) {
431     		if (i == nasid_to_region(nasid))
432     			continue;
433     	}
434     }
435     #endif /* LATER */
436     
437     
438     #ifdef LATER
439     /*
440      * Protect areas of memory that we access uncached by marking them as
441      * poisoned so the T5 can't read them speculatively and erroneously
442      * mark them dirty in its cache only to write them back with old data
443      * later.
444      */
445     static void
446     protect_low_memory(nasid_t nasid)
447     {
448     	/* Protect low memory directory */
449     	poison_state_alter_range(KLDIR_ADDR(nasid), KLDIR_SIZE, 1);
450     
451     	/* Protect klconfig area */
452     	poison_state_alter_range(KLCONFIG_ADDR(nasid), KLCONFIG_SIZE(nasid), 1);
453     
454     	/* Protect the PI error spool area. */
455     	poison_state_alter_range(PI_ERROR_ADDR(nasid), PI_ERROR_SIZE(nasid), 1);
456     
457     	/* Protect CPU A's cache error eframe area. */
458     	poison_state_alter_range(TO_NODE_UNCAC(nasid, CACHE_ERR_EFRAME),
459     				CACHE_ERR_AREA_SIZE, 1);
460     
461     	/* Protect CPU B's area */
462     	poison_state_alter_range(TO_NODE_UNCAC(nasid, CACHE_ERR_EFRAME)
463     				^ UALIAS_FLIP_BIT,
464     				CACHE_ERR_AREA_SIZE, 1);
465     #error "SN1 not handled correctly"
466     }
467     #endif	/* LATER */
468     
469     /*
470      * per_hub_init
471      *
472      * 	This code is executed once for each Hub chip.
473      */
474     void
475     per_hub_init(cnodeid_t cnode)
476     {
477     	uint64_t	done;
478     	nasid_t		nasid;
479     	nodepda_t	*npdap;
480     #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)	/* SN1 specific */
481     	ii_icmr_u_t	ii_icmr;
482     	ii_ibcr_u_t	ii_ibcr;
483     #endif
484     #ifdef	LATER
485     	int i;
486     #endif
487     
488     	nasid = COMPACT_TO_NASID_NODEID(cnode);
489     
490     	ASSERT(nasid != INVALID_NASID);
491     	ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode);
492     
493     	/* Grab the hub_mask lock. */
494     	spin_lock(&hub_mask_lock);
495     
496     	/* Test our bit. */
497     	if (!(done = CNODEMASK_TSTB(hub_init_mask, cnode))) {
498     
499     		/* Turn our bit on in the mask. */
500     		CNODEMASK_SETB(hub_init_mask, cnode);
501     	}
502     
503     #if defined(SN0_HWDEBUG)
504     	hub_config_setup();
505     #endif
506     	/* Release the hub_mask lock. */
507     	spin_unlock(&hub_mask_lock);
508     
509     	/*
510     	 * Do the actual initialization if it hasn't been done yet.
511     	 * We don't need to hold a lock for this work.
512     	 */
513     	if (!done) {
514     		npdap = NODEPDA(cnode);
515     
516     #if defined(CONFIG_IA64_SGI_SYNERGY_PERF)
517     		/* initialize per-node synergy perf instrumentation */
518     		npdap->synergy_perf_enabled = 0; /* off by default */
519     		npdap->synergy_perf_lock = SPIN_LOCK_UNLOCKED;
520     		npdap->synergy_perf_freq = SYNERGY_PERF_FREQ_DEFAULT;
521     		npdap->synergy_inactive_intervals = 0;
522     		npdap->synergy_active_intervals = 0;
523     		npdap->synergy_perf_data = NULL;
524     		npdap->synergy_perf_first = NULL;
525     #endif /* CONFIG_IA64_SGI_SYNERGY_PERF */
526     
527     		npdap->hub_chip_rev = get_hub_chiprev(nasid);
528     
529     #ifdef	LATER
530     		for (i = 0; i < CPUS_PER_NODE; i++) {
531     			cpu = cnode_slice_to_cpuid(cnode, i);
532     			if (!cpu_enabled(cpu))
533     			    SET_CPU_LEDS(nasid, i, 0xf);
534     		}
535     #endif /* LATER */
536     
537     #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) /* SN1 specific */
538     
539     		/*
540     		 * Set the total number of CRBs that can be used.
541     		 */
542     		ii_icmr.ii_icmr_regval= 0x0;
543     		ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xF;
544     		REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval);
545     
546     		/*
547     		 * Set the number of CRBs that both of the BTEs combined
548     		 * can use minus 1.
549     		 */
550     		ii_ibcr.ii_ibcr_regval= 0x0;
551     		ii_ibcr.ii_ibcr_fld_s.i_count = 0x8;
552     		REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval);
553     
554     		/*
555     		 * Set CRB timeout to be 10ms.
556     		 */
557     		REMOTE_HUB_S(nasid, IIO_ICTP, 0x1000 );
558     		REMOTE_HUB_S(nasid, IIO_ICTO, 0xff);
559     
560     #endif /* SN0_HWDEBUG */
561     
562     
563     
564     		/* Reserve all of the hardwired interrupt levels. */
565     		intr_reserve_hardwired(cnode);
566     
567     		/* Initialize error interrupts for this hub. */
568     		hub_error_init(cnode);
569     
570     #ifdef LATER
571     		/* Set up correctable memory/directory ECC error interrupt. */
572     		install_eccintr(cnode);
573     
574     		/* Protect our exception vectors from accidental corruption. */
575     		protect_hub_calias(nasid);
576     
577     		/* Enable RT clock interrupts */
578     		hub_rtc_init(cnode);
579     		hub_migrintr_init(cnode); /* Enable migration interrupt */
580     #endif	/* LATER */
581     
582     		spin_lock(&hub_mask_lock);
583     		CNODEMASK_SETB(hub_init_done_mask, cnode);
584     		spin_unlock(&hub_mask_lock);
585     
586     	} else {
587     		/*
588     		 * Wait for the other CPU to complete the initialization.
589     		 */
590     		while (CNODEMASK_TSTB(hub_init_done_mask, cnode) == 0) {
591     			/*
592     			 * On SNIA64 we should never get here ..
593     			 */
594     			printk("WARNING: per_hub_init: Should NEVER get here!\n");
595     			/* LOOP */
596     			;
597     		}
598     	}
599     }
600     
601     extern void
602     update_node_information(cnodeid_t cnodeid)
603     {
604     	nodepda_t *npda = NODEPDA(cnodeid);
605     	nodepda_router_info_t *npda_rip;
606     	
607     	/* Go through the list of router info 
608     	 * structures and copy some frequently
609     	 * accessed info from the info hanging
610     	 * off the corresponding router vertices
611     	 */
612     	npda_rip = npda->npda_rip_first;
613     	while(npda_rip) {
614     		if (npda_rip->router_infop) {
615     			npda_rip->router_portmask = 
616     				npda_rip->router_infop->ri_portmask;
617     			npda_rip->router_slot = 
618     				npda_rip->router_infop->ri_slotnum;
619     		} else {
620     			/* No router, no ports. */
621     			npda_rip->router_portmask = 0;
622     		}
623     		npda_rip = npda_rip->router_next;
624     	}
625     }
626     
627     hubreg_t
628     get_region(cnodeid_t cnode)
629     {
630     	if (fine_mode)
631     		return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT;
632     	else
633     		return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT;
634     }
635     
636     hubreg_t
637     nasid_to_region(nasid_t nasid)
638     {
639     	if (fine_mode)
640     		return nasid >> NASID_TO_FINEREG_SHFT;
641     	else
642     		return nasid >> NASID_TO_COARSEREG_SHFT;
643     }
644     
645