File: /usr/src/linux/arch/ia64/sn/io/hubspc.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     /*
12      * hubspc.c - Hub Memory Space Management Driver
13      * This driver implements the managers for the following
14      * memory resources:
15      * 1) reference counters
16      */
17     
18     #include <linux/types.h>
19     #include <linux/config.h>
20     #include <linux/slab.h>
21     #include <asm/sn/sgi.h>
22     #include <linux/devfs_fs.h>
23     #include <linux/devfs_fs_kernel.h>
24     #include <asm/io.h>
25     #include <asm/sn/iograph.h>
26     #include <asm/sn/invent.h>
27     #include <asm/sn/hcl.h>
28     #include <asm/sn/labelcl.h>
29     #include <asm/sn/mem_refcnt.h>
30     #include <asm/sn/agent.h>
31     #include <asm/sn/addrs.h>
32     
33     
34     #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
35     #include <asm/sn/sn1/ip27config.h>
36     #include <asm/sn/sn1/hubdev.h>
37     #include <asm/sn/ksys/elsc.h>
38     #endif
39     
40     #include <asm/sn/hubspc.h>
41     
42     
43     /* Uncomment the following line for tracing */
44     /* #define HUBSPC_DEBUG 1 */
45     
46     int hubspc_devflag = D_MP;
47     
48     extern void *device_info_get(devfs_handle_t device);
49     extern void device_info_set(devfs_handle_t device, void *info);
50     
51     
52     
53     /***********************************************************************/
54     /* CPU Prom Space 						       */
55     /***********************************************************************/
56     
57     typedef struct cpuprom_info {
58     	devfs_handle_t	prom_dev;
59     	devfs_handle_t	nodevrtx;
60     	struct	cpuprom_info *next;
61     }cpuprom_info_t;
62     
63     static cpuprom_info_t	*cpuprom_head;
64     spinlock_t	cpuprom_spinlock;
65     #define	PROM_LOCK()	mutex_spinlock(&cpuprom_spinlock)
66     #define	PROM_UNLOCK(s)	mutex_spinunlock(&cpuprom_spinlock, (s))
67     
68     /*
69      * Add prominfo to the linked list maintained.
70      */
71     void
72     prominfo_add(devfs_handle_t hub, devfs_handle_t prom)
73     {
74     	cpuprom_info_t	*info;
75     	unsigned long	s;
76     
77     	info = kmalloc(sizeof(cpuprom_info_t), GFP_KERNEL);
78     	ASSERT(info);
79     	info->prom_dev = prom;
80     	info->nodevrtx = hub;
81     
82     
83     	s = PROM_LOCK();
84     	info->next = cpuprom_head;
85     	cpuprom_head = info;
86     	PROM_UNLOCK(s);
87     }
88     
89     void
90     prominfo_del(devfs_handle_t prom)
91     {
92     	unsigned long	s;
93     	cpuprom_info_t	*info;
94     	cpuprom_info_t	**prev;
95     
96     	s = PROM_LOCK();
97     	prev = &cpuprom_head;
98     	while ( (info = *prev) ) {
99     		if (info->prom_dev == prom) {
100     			*prev = info->next;
101     			PROM_UNLOCK(s);
102     			return;
103     		}
104     		
105     		prev = &info->next;
106     	}
107     	PROM_UNLOCK(s);
108     	ASSERT(0);
109     }
110     
111     devfs_handle_t
112     prominfo_nodeget(devfs_handle_t prom)
113     {
114     	unsigned long	s;
115     	cpuprom_info_t	*info;
116     
117     	s = PROM_LOCK();
118     	info = cpuprom_head;
119     	while (info) {
120     		if(info->prom_dev == prom) {
121     			PROM_UNLOCK(s);
122     			return info->nodevrtx;
123     		}
124     		info = info->next;
125     	}
126     	PROM_UNLOCK(s);
127     	return 0;
128     }
129     
130     #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
131     #define	SN_PROMVERSION		INV_IP35PROM
132     #endif
133     
134     /* Add "detailed" labelled inventory information to the
135      * prom vertex 
136      */
137     void
138     cpuprom_detailed_inventory_info_add(devfs_handle_t prom_dev,devfs_handle_t node)
139     {
140     	invent_miscinfo_t 	*cpuprom_inventory_info;
141     	extern invent_generic_t *klhwg_invent_alloc(cnodeid_t cnode, 
142     						     int class, int size);
143     	cnodeid_t		cnode = hubdev_cnodeid_get(node);
144     
145     	/* Allocate memory for the extra inventory information
146     	 * for the  prom
147     	 */
148     	cpuprom_inventory_info = (invent_miscinfo_t *) 
149     		klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t));
150     
151     	ASSERT(cpuprom_inventory_info);
152     
153     	/* Set the enabled flag so that the hinv interprets this
154     	 * information
155     	 */
156     	cpuprom_inventory_info->im_gen.ig_flag = INVENT_ENABLED;
157     	cpuprom_inventory_info->im_type = SN_PROMVERSION;
158     	/* Store prom revision into inventory information */
159     	cpuprom_inventory_info->im_rev = IP27CONFIG.pvers_rev;
160     	cpuprom_inventory_info->im_version = IP27CONFIG.pvers_vers;
161     
162     
163     	/* Store this info as labelled information hanging off the
164     	 * prom device vertex
165     	 */
166     	hwgraph_info_add_LBL(prom_dev, INFO_LBL_DETAIL_INVENT, 
167     			     (arbitrary_info_t) cpuprom_inventory_info);
168     	/* Export this information so that user programs can get to
169     	 * this by using attr_get()
170     	 */
171             hwgraph_info_export_LBL(prom_dev, INFO_LBL_DETAIL_INVENT,
172     				sizeof(invent_miscinfo_t));
173     }
174     
175     int
176     cpuprom_attach(devfs_handle_t node)
177     {
178             devfs_handle_t prom_dev;
179     
180             hwgraph_char_device_add(node, EDGE_LBL_PROM, "hubspc_", &prom_dev);
181     #ifdef	HUBSPC_DEBUG
182     	printf("hubspc: prom_attach hub: 0x%x prom: 0x%x\n", node, prom_dev);
183     #endif	/* HUBSPC_DEBUG */
184     	device_inventory_add(prom_dev, INV_PROM, SN_PROMVERSION,
185     				(major_t)0, (minor_t)0, 0);
186     
187     	/* Add additional inventory info about the cpu prom like
188     	 * revision & version numbers etc.
189     	 */
190     	cpuprom_detailed_inventory_info_add(prom_dev,node);
191             device_info_set(prom_dev, (void*)(ulong)HUBSPC_PROM);
192     	prominfo_add(node, prom_dev);
193     
194             return (0);
195     }
196     
197     #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
198     #define FPROM_CONFIG_ADDR	MD_JUNK_BUS_TIMING
199     #define FPROM_ENABLE_MASK	MJT_FPROM_ENABLE_MASK
200     #define FPROM_ENABLE_SHFT	MJT_FPROM_ENABLE_SHFT
201     #define FPROM_SETUP_MASK	MJT_FPROM_SETUP_MASK
202     #define FPROM_SETUP_SHFT	MJT_FPROM_SETUP_SHFT
203     #endif
204     
205     /*ARGSUSED*/
206     int
207     cpuprom_map(devfs_handle_t dev, vhandl_t *vt, off_t addr, size_t len)
208     {
209             int 		errcode;
210     	caddr_t 	kvaddr;
211     	devfs_handle_t		node;
212     	cnodeid_t 	cnode;
213     
214     	node = prominfo_nodeget(dev);
215     
216     	if (!node)
217     		return EIO;
218             
219     
220     	kvaddr = hubdev_prombase_get(node);
221     	cnode  = hubdev_cnodeid_get(node);
222     #ifdef	HUBSPC_DEBUG
223     	printf("cpuprom_map: hubnode %d kvaddr 0x%x\n", node, kvaddr);
224     #endif
225     
226     	if (len > RBOOT_SIZE)
227     		len = RBOOT_SIZE;
228             /*
229              * Map in the prom space
230              */
231     	errcode = v_mapphys(vt, kvaddr, len);
232     
233     	if (errcode == 0 ){
234     		/*
235     		 * Set the MD configuration registers suitably.
236     		 */
237     		nasid_t		nasid;
238     		uint64_t	value;
239     		volatile hubreg_t	*regaddr;
240     
241     		nasid = COMPACT_TO_NASID_NODEID(cnode);
242     		regaddr = REMOTE_HUB_ADDR(nasid, FPROM_CONFIG_ADDR);
243     		value = HUB_L(regaddr);
244     		value &= ~(FPROM_SETUP_MASK | FPROM_ENABLE_MASK);
245     		{
246     			value |= (((long)CONFIG_FPROM_SETUP << FPROM_SETUP_SHFT) | 
247     				  ((long)CONFIG_FPROM_ENABLE << FPROM_ENABLE_SHFT));
248     		}
249     		HUB_S(regaddr, value);
250     
251     	}
252             return (errcode);
253     }
254     
255     /*ARGSUSED*/
256     int
257     cpuprom_unmap(devfs_handle_t dev, vhandl_t *vt)
258     {
259             return 0;
260     }
261     
262     /***********************************************************************/
263     /* Base Hub Space Driver                                               */
264     /***********************************************************************/
265     
266     // extern int l1_attach( devfs_handle_t );
267     
268     /*
269      * hubspc_init
270      * Registration of the hubspc devices with the hub manager
271      */
272     void
273     hubspc_init(void)
274     {
275             /*
276              * Register with the hub manager
277              */
278     
279             /* The reference counters */
280             hubdev_register(mem_refcnt_attach);
281     
282     	/* Prom space */
283     	hubdev_register(cpuprom_attach);
284     
285     #if defined(CONFIG_SERIAL_SGI_L1_PROTOCOL)
286     	/* L1 system controller link */
287     	if ( !IS_RUNNING_ON_SIMULATOR() ) {
288     		/* initialize the L1 link */
289     		void l1_cons_init( l1sc_t *sc );
290     		elsc_t *get_elsc(void);
291     
292     		l1_cons_init((l1sc_t *)get_elsc());
293     	}
294     #endif
295     
296     #ifdef	HUBSPC_DEBUG
297     	printf("hubspc_init: Completed\n");
298     #endif	/* HUBSPC_DEBUG */
299     	/* Initialize spinlocks */
300     	mutex_spinlock_init(&cpuprom_spinlock);
301     }
302     
303     /* ARGSUSED */
304     int
305     hubspc_open(devfs_handle_t *devp, mode_t oflag, int otyp, cred_t *crp)
306     {
307             int errcode = 0;
308             
309             switch ((hubspc_subdevice_t)(ulong)device_info_get(*devp)) {
310             case HUBSPC_REFCOUNTERS:
311                     errcode = mem_refcnt_open(devp, oflag, otyp, crp);
312                     break;
313     
314             case HUBSPC_PROM:
315                     break;
316     
317             default:
318                     errcode = ENODEV;
319             }
320     
321     #ifdef	HUBSPC_DEBUG
322     	printf("hubspc_open: Completed open for type %d\n",
323                    (hubspc_subdevice_t)(ulong)device_info_get(*devp));
324     #endif	/* HUBSPC_DEBUG */
325     
326             return (errcode);
327     }
328     
329     
330     /* ARGSUSED */
331     int
332     hubspc_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp)
333     {
334             int errcode = 0;
335             
336             switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) {
337             case HUBSPC_REFCOUNTERS:
338                     errcode = mem_refcnt_close(dev, oflag, otyp, crp);
339                     break;
340     
341             case HUBSPC_PROM:
342                     break;
343             default:
344                     errcode = ENODEV;
345             }
346     
347     #ifdef	HUBSPC_DEBUG
348     	printf("hubspc_close: Completed close for type %d\n",
349                    (hubspc_subdevice_t)(ulong)device_info_get(dev));
350     #endif	/* HUBSPC_DEBUG */
351     
352             return (errcode);
353     }
354     
355     /* ARGSUSED */
356     int
357     hubspc_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot)
358     {
359     	/*REFERENCED*/
360             hubspc_subdevice_t subdevice;
361             int errcode = 0;
362     
363     	/* check validity of request */
364     	if( len == 0 ) {
365     		return ENXIO;
366             }
367     
368             subdevice = (hubspc_subdevice_t)(ulong)device_info_get(dev);
369     
370     #ifdef	HUBSPC_DEBUG
371     	printf("hubspc_map: subdevice: %d vaddr: 0x%x phyaddr: 0x%x len: 0x%x\n",
372     	       subdevice, v_getaddr(vt), off, len);
373     #endif /* HUBSPC_DEBUG */
374     
375             switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) {
376             case HUBSPC_REFCOUNTERS:
377                     errcode = mem_refcnt_mmap(dev, vt, off, len, prot);
378                     break;
379     
380             case HUBSPC_PROM:
381     		errcode = cpuprom_map(dev, vt, off, len);
382                     break;
383             default:
384                     errcode = ENODEV;
385             }
386     
387     #ifdef	HUBSPC_DEBUG
388     	printf("hubspc_map finished: spctype: %d vaddr: 0x%x len: 0x%x\n",
389     	       (hubspc_subdevice_t)(ulong)device_info_get(dev), v_getaddr(vt), len);
390     #endif /* HUBSPC_DEBUG */
391     
392     	return errcode;
393     }
394     
395     /* ARGSUSED */
396     int
397     hubspc_unmap(devfs_handle_t dev, vhandl_t *vt)
398     {
399             int errcode = 0;
400             
401             switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) {
402             case HUBSPC_REFCOUNTERS:
403                     errcode = mem_refcnt_unmap(dev, vt);
404                     break;
405     
406             case HUBSPC_PROM:
407                     errcode = cpuprom_unmap(dev, vt);
408                     break;
409     
410             default:
411                     errcode = ENODEV;
412             }
413     	return errcode;
414     
415     }
416     
417     /* ARGSUSED */
418     int
419     hubspc_ioctl(devfs_handle_t dev,
420                  int cmd,
421                  void *arg,
422                  int mode,
423                  cred_t *cred_p,
424                  int *rvalp)
425     {
426             int errcode = 0;
427             
428             switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) {
429             case HUBSPC_REFCOUNTERS:
430                     errcode = mem_refcnt_ioctl(dev, cmd, arg, mode, cred_p, rvalp);
431                     break;
432     
433             case HUBSPC_PROM:
434                     break;
435     
436             default:
437                     errcode = ENODEV;
438             }
439     	return errcode;
440     
441     }
442