void hubni_eint_init(cnodeid_t cnode) { int intr_bit; cpuid_t targ; if ((targ = cnodeid_to_cpuid(cnode)) == CPU_NONE) return; /* The prom chooses which cpu gets these interrupts, but we * don't know which one it chose. We will register all of the * cpus to be sure. This only costs us an irqaction per cpu. */ for (; targ < CPUS_PER_NODE; targ++) { if (!cpu_enabled(targ) ) continue; /* connect the INTEND1 bits. */ for (intr_bit = XB_ERROR; intr_bit <= MSC_PANIC_INTR; intr_bit++) { intr_connect_level(targ, intr_bit, II_ERRORINT, NULL); } request_irq(SGI_HUB_ERROR_IRQ + (targ << 8), snia_error_intr_handler, 0, "SN hub error", NULL); /* synergy masks are initialized in the prom to enable all interrupts. */ /* We'll just leave them that way, here, for these interrupts. */ } }
/* * Switch to target cpu to run. */ static void set_cpu(int cpu, struct thread *td) { KASSERT(cpu >= 0 && cpu < mp_ncpus && cpu_enabled(cpu), ("[cpuctl,%d]: bad cpu number %d", __LINE__, cpu)); thread_lock(td); sched_bind(td, cpu); thread_unlock(td); KASSERT(td->td_oncpu == cpu, ("[cpuctl,%d]: cannot bind to target cpu %d", __LINE__, cpu)); }
int cpuctl_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) { int cpu, ret; cpu = dev2unit(dev); if (cpu > mp_maxid || !cpu_enabled(cpu)) { DPRINTF("[cpuctl,%d]: bad cpu number %d\n", __LINE__, cpu); return (ENXIO); } /* Require write flag for "write" requests. */ if ((cmd == CPUCTL_MSRCBIT || cmd == CPUCTL_MSRSBIT || cmd == CPUCTL_UPDATE || cmd == CPUCTL_WRMSR || cmd == CPUCTL_EVAL_CPU_FEATURES) && (flags & FWRITE) == 0) return (EPERM); switch (cmd) { case CPUCTL_RDMSR: ret = cpuctl_do_msr(cpu, (cpuctl_msr_args_t *)data, cmd, td); break; case CPUCTL_MSRSBIT: case CPUCTL_MSRCBIT: case CPUCTL_WRMSR: ret = priv_check(td, PRIV_CPUCTL_WRMSR); if (ret != 0) goto fail; ret = cpuctl_do_msr(cpu, (cpuctl_msr_args_t *)data, cmd, td); break; case CPUCTL_CPUID: ret = cpuctl_do_cpuid(cpu, (cpuctl_cpuid_args_t *)data, td); break; case CPUCTL_UPDATE: ret = priv_check(td, PRIV_CPUCTL_UPDATE); if (ret != 0) goto fail; ret = cpuctl_do_update(cpu, (cpuctl_update_args_t *)data, td); break; case CPUCTL_CPUID_COUNT: ret = cpuctl_do_cpuid_count(cpu, (cpuctl_cpuid_count_args_t *)data, td); break; case CPUCTL_EVAL_CPU_FEATURES: ret = cpuctl_do_eval_cpu_features(cpu, td); break; default: ret = EINVAL; break; } fail: return (ret); }
static void restore_cpu(int oldcpu, int is_bound, struct thread *td) { KASSERT(oldcpu >= 0 && oldcpu < mp_ncpus && cpu_enabled(oldcpu), ("[cpuctl,%d]: bad cpu number %d", __LINE__, oldcpu)); thread_lock(td); if (is_bound == 0) sched_unbind(td); else sched_bind(td, oldcpu); thread_unlock(td); }
static void debug_checkthread(struct gdbcontext *ctx, const char *threadid) { unsigned cpunum; cpunum = getthreadid(threadid); if (cpunum >= cpu_numcpus()) { debug_send(ctx, "E00"); return; } if (!cpu_enabled(cpunum)) { debug_send(ctx, "E01"); return; } debug_send(ctx, "OK"); }
/* * One-time setup for MP SN. * Allocate per-node data, slurp prom klconfig information and * convert it to hwgraph information. */ void sn_mp_setup(void) { cnodeid_t cnode; extern int maxnodes; cpuid_t cpu; DBG("sn_mp_setup: Entered.\n"); /* * NODEPDA(x) Macro depends on nodepda * subnodepda is also statically set to calias space which we * do not currently support yet .. just a hack for now. */ #ifdef NUMA_BASE maxnodes = numnodes; DBG("sn_mp_setup(): maxnodes= %d numnodes= %d\n", maxnodes,numnodes); printk("sn_mp_setup(): Allocating backing store for *Nodepdaindr[%2d] \n", maxnodes); /* * Initialize Nodpdaindr and per-node nodepdaindr array */ *Nodepdaindr = (nodepda_t *) kmalloc(sizeof(nodepda_t *)*numnodes, GFP_KERNEL); for (cnode=0; cnode<maxnodes; cnode++) { Nodepdaindr[cnode] = (nodepda_t *) kmalloc(sizeof(struct nodepda_s), GFP_KERNEL); Synergy_da_indr[cnode * 2] = (synergy_da_t *) kmalloc( sizeof(synergy_da_t), GFP_KERNEL); Synergy_da_indr[(cnode * 2) + 1] = (synergy_da_t *) kmalloc( sizeof(synergy_da_t), GFP_KERNEL); Nodepdaindr[cnode]->pernode_pdaindr = Nodepdaindr; subnodepda = &Nodepdaindr[cnode]->snpda[cnode]; } nodepda = Nodepdaindr[0]; #else Nodepdaindr = (nodepda_t *) kmalloc(sizeof(struct nodepda_s), GFP_KERNEL); nodepda = Nodepdaindr[0]; subnodepda = &Nodepdaindr[0]->snpda[0]; #endif /* NUMA_BASE */ /* * Before we let the other processors run, set up the platform specific * stuff in the nodepda. * * ???? maxnodes set in mlreset .. who sets it now ???? * ???? cpu_node_probe() called in mlreset to set up the following: * compact_to_nasid_node[] - cnode id gives nasid * nasid_to_compact_node[] - nasid gives cnode id * * do_cpumask() sets the following: * cpuid_to_compact_node[] - cpuid gives cnode id * * nasid comes from gdap->g_nasidtable[] * ml/SN/promif.c */ #ifdef CONFIG_IA64_SGI_SN1 for (cpu = 0; cpu < smp_num_cpus; cpu++) { /* Skip holes in CPU space */ if (cpu_enabled(cpu)) { init_platform_pda(cpu); } } #endif for (cnode = 0; cnode < maxnodes; cnode++) { /* * Set up platform-dependent nodepda fields. * The following routine actually sets up the hubinfo struct * in nodepda. */ DBG("sn_mp_io_setup: calling init_platform_nodepda(%2d)\n",cnode); init_platform_nodepda(Nodepdaindr[cnode], cnode); } /* * Initialize platform-dependent vertices in the hwgraph: * module * node * cpu * memory * slot * hub * router * xbow */ DBG("sn_mp_io_setup: calling io_module_init()\n"); io_module_init(); /* Use to be called module_init() .. */ DBG("sn_mp_setup: calling klhwg_add_all_modules()\n"); klhwg_add_all_modules(hwgraph_root); DBG("sn_mp_setup: calling klhwg_add_all_nodes()\n"); klhwg_add_all_nodes(hwgraph_root); for (cnode = 0; cnode < maxnodes; cnode++) { /* * This routine clears the Hub's Interrupt registers. */ #ifdef CONFIG_IA64_SGI_SN1 /* * We need to move this intr_clear_all() routine * from SN/intr.c to a more appropriate file. * Talk to Al Mayer. */ intr_clear_all(COMPACT_TO_NASID_NODEID(cnode)); /* now init the hub */ // per_hub_init(cnode); #endif } #if defined(CONFIG_IA64_SGI_SYNERGY_PERF) synergy_perf_init(); #endif /* CONFIG_IA64_SGI_SYNERGY_PERF */ }
/* pkt is null-terminated */ void debug_exec(struct gdbcontext *ctx, const char *pkt) { char *cs; /* start of the checksum */ int i; int check = 0, scheck; #ifdef SHOW_PACKETS msg("Got packet %s", pkt); #endif if (pkt[0] != '$') { return; } cs = strchr(pkt, '#'); if (cs == NULL) { return; } *cs = 0; cs++; for (i=1; pkt[i]; i++) { check += pkt[i]; } scheck = strtoul(cs, NULL, 16); if (scheck != check % 256) { write(ctx->myfd, "-", 1); return; } else { write(ctx->myfd, "+", 1); } switch (pkt[1]) { case '!': /* * Enable extended mode -- extended mode is apparently * where gdb can ask to rerun the program. We can't do * that... although it could probably be arranged. * * Reply with "OK" if extended mode is enabled. */ debug_notsupp(ctx); break; case '?': /* Report why the target stopped. */ debug_send_stopinfo(ctx); break; case 'A': /* * Set argv[]. We can't do this, although it might make * sense if we grow support for reloading the kernel. */ debug_notsupp(ctx); break; case 'b': if (pkt[2] == 0) { /* Set serial bit rate; deprecated. */ debug_notsupp(ctx); break; } else if (pkt[2] == 'c') { /* Backward continue - resume executing, backwards */ } else if (pkt[2] == 's') { /* Backward single step - execute one insn backwards */ } else { /* ? */ } debug_notsupp(ctx); break; case 'B': /* Set or clear breakpoint; old, deprecated. */ debug_notsupp(ctx); break; case 'c': /* * Continue. If an address follows the 'c', continue * from that address. debug_restart() does that. */ debug_restart(ctx, pkt + 2); unset_breakcond(); break; case 'C': /* * Continue with signal. A signal number in hex * follows the C; that may be followed with a * semicolon and an address to continue at. We don't * have signals per se; in theory we could fake up * some mapping of signals to hardware traps, but that * would be difficult to arrange and not serve much * purpose. */ debug_notsupp(ctx); break; case 'd': /* Toggle debug flag (whatever that means); deprecated. */ debug_notsupp(ctx); break; case 'D': /* * Detach. With a process-id, detach only one process, * if the multiprocess extension is in use. */ debug_send(ctx, "OK"); unset_breakcond(); break; case 'F': /* * File I/O extension reply; for now at least we have * no use for this. */ debug_notsupp(ctx); break; case 'g': /* Read general-purpose registers */ debug_register_print(ctx); break; case 'G': /* * Write general-purpose registers. The G is followed * by a register dump in the same format as the 'g' * reply. */ // XXX gcc docs say this is required debug_notsupp(ctx); break; case 'H': /* * Hc followed by a thread ID sets the thread that * step and continue operations should affect; Hg * followed by a thread ID sets the thread that * other operations should affect. */ if (pkt[2] == 'c') { debug_notsupp(ctx); } else if (pkt[2] == 'g') { unsigned cpunum; cpunum = getthreadid(pkt+3); if (cpunum >= cpu_numcpus()) { debug_send(ctx, "E00"); break; } debug_cpu = cpunum; debug_send(ctx, "OK"); } else { debug_send(ctx, "OK"); } break; case 'i': /* Step by cycle count */ debug_notsupp(ctx); break; case 'I': /* Step by cycle count with signal (apparently) */ debug_notsupp(ctx); break; case 'k': /* Kill the target */ // don't do this - debugger hangs up and we get SIGPIPE //debug_send(ctx, "OK"); msg("Debugger requested kill"); reqdie(); // To continue running instead of dying, do this instead //unset_breakcond(); break; case 'm': /* Read target memory */ debug_read_mem(ctx, pkt + 2); break; case 'M': /* Write target memory */ debug_write_mem(ctx, pkt + 2); break; case 'p': /* read one register */ debug_notsupp(ctx); break; case 'P': /* write one register */ debug_notsupp(ctx); break; case 'q': /* General query */ if (strcmp(pkt + 2, "C") == 0) { /* Return current thread id */ debug_sendf(ctx,"QC%x", mkthreadid(debug_cpu)); } else if (!strcmp(pkt+2, "fThreadInfo")) { char buf[128]; unsigned i; strcpy(buf, "m"); for (i=0; i<cpu_numcpus(); i++) { if (!cpu_enabled(i)) { continue; } if (i > 0) { strcat(buf, ","); } printbyte(buf, sizeof(buf), mkthreadid(i)); } debug_send(ctx, buf); } else if (!strcmp(pkt+2, "sThreadInfo")) { debug_send(ctx, "l"); } else if (strcmp(pkt+2, "Offsets") == 0) { /* Return info about load-time relocations */ debug_notsupp(ctx); } else if (strcmp(pkt+2, "Supported") == 0) { /* Features handshake */ debug_notsupp(ctx); } else if (!strncmp(pkt+2, "ThreadExtraInfo,", 16)) { debug_getthreadinfo(ctx, pkt+2+16); } else { debug_notsupp(ctx); } break; case 'Q': /* General set mode (I think) */ debug_notsupp(ctx); break; case 'r': /* Reset target - deprecated */ debug_notsupp(ctx); break; case 'R': /* * Restart target (only with extended mode enabled). * Do not reply. */ break; case 's': /* Single step */ debug_restart(ctx, pkt + 2); onecycle(); debug_send_stopinfo(ctx); break; case 'S': /* Single step with signal */ debug_notsupp(ctx); break; case 't': /* search memory for a pattern (underdocumented) */ debug_notsupp(ctx); break; case 'T': /* check if a thread is alive (OK - yes; E.. - no) */ debug_checkthread(ctx, pkt + 2); break; case 'v': /* various longer commands */ debug_notsupp(ctx); break; case 'X': /* Write target memory with a more efficient encoding */ debug_notsupp(ctx); break; case 'z': case 'Z': /* insert (Z) or remove (z) one of the following: */ switch (pkt[2]) { case '0': /* set or clear memory breakpoint */ debug_notsupp(ctx); break; case '1': /* set or clear hardware breakpoint */ debug_notsupp(ctx); break; case '2': /* set or clear write watchpoint */ debug_notsupp(ctx); break; case '3': /* set or clear read watchpoint */ debug_notsupp(ctx); break; case '4': /* set or clear access watchpoint */ debug_notsupp(ctx); break; default: /* ? */ debug_notsupp(ctx); break; } break; default: debug_notsupp(ctx); break; } }