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