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
7 * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
8 * Copyright (C) 2000 by Colin Ngam
12 * hubspc.c - Hub Memory Space Management Driver
13 * This driver implements the managers for the following
15 * 1) reference counters
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>
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>
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>
40 #include <asm/sn/hubspc.h>
43 /* Uncomment the following line for tracing */
44 /* #define HUBSPC_DEBUG 1 */
46 int hubspc_devflag = D_MP;
48 extern void *device_info_get(devfs_handle_t device);
49 extern void device_info_set(devfs_handle_t device, void *info);
53 /***********************************************************************/
55 /***********************************************************************/
57 typedef struct cpuprom_info {
58 devfs_handle_t prom_dev;
59 devfs_handle_t nodevrtx;
60 struct cpuprom_info *next;
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))
69 * Add prominfo to the linked list maintained.
72 prominfo_add(devfs_handle_t hub, devfs_handle_t prom)
77 info = kmalloc(sizeof(cpuprom_info_t), GFP_KERNEL);
79 info->prom_dev = prom;
84 info->next = cpuprom_head;
90 prominfo_del(devfs_handle_t prom)
94 cpuprom_info_t **prev;
98 while ( (info = *prev) ) {
99 if (info->prom_dev == prom) {
112 prominfo_nodeget(devfs_handle_t prom)
115 cpuprom_info_t *info;
120 if(info->prom_dev == prom) {
122 return info->nodevrtx;
130 #if defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
131 #define SN_PROMVERSION INV_IP35PROM
134 /* Add "detailed" labelled inventory information to the
138 cpuprom_detailed_inventory_info_add(devfs_handle_t prom_dev,devfs_handle_t node)
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);
145 /* Allocate memory for the extra inventory information
148 cpuprom_inventory_info = (invent_miscinfo_t *)
149 klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t));
151 ASSERT(cpuprom_inventory_info);
153 /* Set the enabled flag so that the hinv interprets this
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;
163 /* Store this info as labelled information hanging off the
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()
171 hwgraph_info_export_LBL(prom_dev, INFO_LBL_DETAIL_INVENT,
172 sizeof(invent_miscinfo_t));
176 cpuprom_attach(devfs_handle_t node)
178 devfs_handle_t prom_dev;
180 hwgraph_char_device_add(node, EDGE_LBL_PROM, "hubspc_", &prom_dev);
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);
187 /* Add additional inventory info about the cpu prom like
188 * revision & version numbers etc.
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);
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
207 cpuprom_map(devfs_handle_t dev, vhandl_t *vt, off_t addr, size_t len)
214 node = prominfo_nodeget(dev);
220 kvaddr = hubdev_prombase_get(node);
221 cnode = hubdev_cnodeid_get(node);
223 printf("cpuprom_map: hubnode %d kvaddr 0x%x\n", node, kvaddr);
226 if (len > RBOOT_SIZE)
229 * Map in the prom space
231 errcode = v_mapphys(vt, kvaddr, len);
235 * Set the MD configuration registers suitably.
239 volatile hubreg_t *regaddr;
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);
246 value |= (((long)CONFIG_FPROM_SETUP << FPROM_SETUP_SHFT) |
247 ((long)CONFIG_FPROM_ENABLE << FPROM_ENABLE_SHFT));
249 HUB_S(regaddr, value);
257 cpuprom_unmap(devfs_handle_t dev, vhandl_t *vt)
262 /***********************************************************************/
263 /* Base Hub Space Driver */
264 /***********************************************************************/
266 // extern int l1_attach( devfs_handle_t );
270 * Registration of the hubspc devices with the hub manager
276 * Register with the hub manager
279 /* The reference counters */
280 hubdev_register(mem_refcnt_attach);
283 hubdev_register(cpuprom_attach);
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);
292 l1_cons_init((l1sc_t *)get_elsc());
297 printf("hubspc_init: Completed\n");
298 #endif /* HUBSPC_DEBUG */
299 /* Initialize spinlocks */
300 spinlock_init(&cpuprom_spinlock, "promlist");
305 hubspc_open(devfs_handle_t *devp, mode_t oflag, int otyp, cred_t *crp)
309 switch ((hubspc_subdevice_t)(ulong)device_info_get(*devp)) {
310 case HUBSPC_REFCOUNTERS:
311 errcode = mem_refcnt_open(devp, oflag, otyp, crp);
315 /* Check if the user has proper access rights to
316 * read/write the prom space.
318 if (!cap_able(CAP_DEVICE_MGT)) {
328 printf("hubspc_open: Completed open for type %d\n",
329 (hubspc_subdevice_t)(ulong)device_info_get(*devp));
330 #endif /* HUBSPC_DEBUG */
338 hubspc_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp)
342 switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) {
343 case HUBSPC_REFCOUNTERS:
344 errcode = mem_refcnt_close(dev, oflag, otyp, crp);
354 printf("hubspc_close: Completed close for type %d\n",
355 (hubspc_subdevice_t)(ulong)device_info_get(dev));
356 #endif /* HUBSPC_DEBUG */
363 hubspc_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot)
366 hubspc_subdevice_t subdevice;
369 /* check validity of request */
374 subdevice = (hubspc_subdevice_t)(ulong)device_info_get(dev);
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 */
381 switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) {
382 case HUBSPC_REFCOUNTERS:
383 errcode = mem_refcnt_mmap(dev, vt, off, len, prot);
387 errcode = cpuprom_map(dev, vt, off, len);
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 */
403 hubspc_unmap(devfs_handle_t dev, vhandl_t *vt)
407 switch ((hubspc_subdevice_t)(ulong)device_info_get(dev)) {
408 case HUBSPC_REFCOUNTERS:
409 errcode = mem_refcnt_unmap(dev, vt);
413 errcode = cpuprom_unmap(dev, vt);
425 hubspc_ioctl(devfs_handle_t dev,
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);