Import changeset
[linux-flexiantxendom0-3.2.10.git] / 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 lock_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         int     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         int     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         int     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         spinlock_init(&cpuprom_spinlock, "promlist");
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                 /* Check if the user has proper access rights to 
316                  * read/write the prom space.
317                  */
318                 if (!cap_able(CAP_DEVICE_MGT)) {
319                         errcode = EPERM;
320                 }                
321                 break;
322
323         default:
324                 errcode = ENODEV;
325         }
326
327 #ifdef  HUBSPC_DEBUG
328         printf("hubspc_open: Completed open for type %d\n",
329                (hubspc_subdevice_t)(ulong)device_info_get(*devp));
330 #endif  /* HUBSPC_DEBUG */
331
332         return (errcode);
333 }
334
335
336 /* ARGSUSED */
337 int
338 hubspc_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp)
339 {
340         int errcode = 0;
341         
342         switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) {
343         case HUBSPC_REFCOUNTERS:
344                 errcode = mem_refcnt_close(dev, oflag, otyp, crp);
345                 break;
346
347         case HUBSPC_PROM:
348                 break;
349         default:
350                 errcode = ENODEV;
351         }
352
353 #ifdef  HUBSPC_DEBUG
354         printf("hubspc_close: Completed close for type %d\n",
355                (hubspc_subdevice_t)(ulong)device_info_get(dev));
356 #endif  /* HUBSPC_DEBUG */
357
358         return (errcode);
359 }
360
361 /* ARGSUSED */
362 int
363 hubspc_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot)
364 {
365         /*REFERENCED*/
366         hubspc_subdevice_t subdevice;
367         int errcode = 0;
368
369         /* check validity of request */
370         if( len == 0 ) {
371                 return ENXIO;
372         }
373
374         subdevice = (hubspc_subdevice_t)(ulong)device_info_get(dev);
375
376 #ifdef  HUBSPC_DEBUG
377         printf("hubspc_map: subdevice: %d vaddr: 0x%x phyaddr: 0x%x len: 0x%x\n",
378                subdevice, v_getaddr(vt), off, len);
379 #endif /* HUBSPC_DEBUG */
380
381         switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) {
382         case HUBSPC_REFCOUNTERS:
383                 errcode = mem_refcnt_mmap(dev, vt, off, len, prot);
384                 break;
385
386         case HUBSPC_PROM:
387                 errcode = cpuprom_map(dev, vt, off, len);
388                 break;
389         default:
390                 errcode = ENODEV;
391         }
392
393 #ifdef  HUBSPC_DEBUG
394         printf("hubspc_map finished: spctype: %d vaddr: 0x%x len: 0x%x\n",
395                (hubspc_subdevice_t)(ulong)device_info_get(dev), v_getaddr(vt), len);
396 #endif /* HUBSPC_DEBUG */
397
398         return errcode;
399 }
400
401 /* ARGSUSED */
402 int
403 hubspc_unmap(devfs_handle_t dev, vhandl_t *vt)
404 {
405         int errcode = 0;
406         
407         switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) {
408         case HUBSPC_REFCOUNTERS:
409                 errcode = mem_refcnt_unmap(dev, vt);
410                 break;
411
412         case HUBSPC_PROM:
413                 errcode = cpuprom_unmap(dev, vt);
414                 break;
415
416         default:
417                 errcode = ENODEV;
418         }
419         return errcode;
420
421 }
422
423 /* ARGSUSED */
424 int
425 hubspc_ioctl(devfs_handle_t dev,
426              int cmd,
427              void *arg,
428              int mode,
429              cred_t *cred_p,
430              int *rvalp)
431 {
432         int errcode = 0;
433         
434         switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) {
435         case HUBSPC_REFCOUNTERS:
436                 errcode = mem_refcnt_ioctl(dev, cmd, arg, mode, cred_p, rvalp);
437                 break;
438
439         case HUBSPC_PROM:
440                 break;
441
442         default:
443                 errcode = ENODEV;
444         }
445         return errcode;
446
447 }