asmlinkage int sys_olduname(struct oldold_utsname * name) { int error; PPCDBG(PPCDBG_SYS64X, "sys_olduname - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); if (!name) return -EFAULT; if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) return -EFAULT; down_read(&uts_sem); error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); error -= __put_user(0,name->sysname+__OLD_UTS_LEN); error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); error -= __put_user(0,name->nodename+__OLD_UTS_LEN); error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); error -= __put_user(0,name->release+__OLD_UTS_LEN); error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); error -= __put_user(0,name->version+__OLD_UTS_LEN); error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); error = __put_user(0,name->machine+__OLD_UTS_LEN); up_read(&uts_sem); error = error ? -EFAULT : 0; PPCDBG(PPCDBG_SYS64X, "sys_olduname - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); return error; }
asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, unsigned long prot, unsigned long flags, unsigned long fd, off_t offset) { struct file * file = NULL; unsigned long ret = -EBADF; PPCDBG(PPCDBG_SYS64X, "sys_mmap - entered - addr=%lx, len=%lx - pid=%ld, comm=%s \n", addr, len, current->pid, current->comm); if (!(flags & MAP_ANONYMOUS)) { if (!(file = fget(fd))) goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); down_write(¤t->mm->mmap_sem); ret = do_mmap(file, addr, len, prot, flags, offset); up_write(¤t->mm->mmap_sem); if (file) fput(file); out: PPCDBG(PPCDBG_SYS64X, "sys_mmap - exited - ret=%x \n", ret); return ret; }
static void tce_build_pSeriesLP(struct TceTable *tbl, long tcenum, unsigned long uaddr, int direction ) { u64 set_tce_rc; union Tce tce; PPCDBG(PPCDBG_TCE, "build_tce: uaddr = 0x%lx\n", uaddr); PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx, tbl = 0x%lx, index=%lx\n", tcenum, tbl, tbl->index); tce.wholeTce = 0; tce.tceBits.rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT; tce.tceBits.readWrite = 1; if ( direction != PCI_DMA_TODEVICE ) tce.tceBits.pciWrite = 1; set_tce_rc = plpar_tce_put((u64)tbl->index, (u64)tcenum << 12, tce.wholeTce ); if(set_tce_rc) { printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", set_tce_rc); printk("\tindex = 0x%lx\n", (u64)tbl->index); printk("\ttcenum = 0x%lx\n", (u64)tcenum); printk("\ttce val = 0x%lx\n", tce.wholeTce ); } }
/****************************************************************** * pci_read_irq_line * * Reads the Interrupt Pin to determine if interrupt is use by card. * If the interrupt is used, then gets the interrupt line from the * openfirmware and sets it in the pci_dev and pci_config line. * ******************************************************************/ int pci_read_irq_line(struct pci_dev *Pci_Dev) { u8 InterruptPin; struct device_node *Node; pci_read_config_byte(Pci_Dev, PCI_INTERRUPT_PIN, &InterruptPin); if (InterruptPin == 0) { PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Interrupt used by device.\n",Pci_Dev->slot_name); return 0; } Node = pci_device_to_OF_node(Pci_Dev); if ( Node == NULL) { PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s Device Node not found.\n",Pci_Dev->slot_name); return -1; } if (Node->n_intrs == 0) { PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Device OF interrupts defined.\n",Pci_Dev->slot_name); return -1; } Pci_Dev->irq = Node->intrs[0].line; if (s7a_workaround) { if (Pci_Dev->irq > 16) Pci_Dev->irq -= 3; } pci_write_config_byte(Pci_Dev, PCI_INTERRUPT_LINE, Pci_Dev->irq); PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s pci_dev->irq = 0x%02X\n",Pci_Dev->slot_name,Pci_Dev->irq); return 0; }
asmlinkage int sys_pause(void) { PPCDBG(PPCDBG_SYS64X, "sys_pause - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); current->state = TASK_INTERRUPTIBLE; schedule(); PPCDBG(PPCDBG_SYS64X, "sys_pause - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); return -ERESTARTNOHAND; }
/*********************************************************************** * ppc64_pcibios_init * * Chance to initialize and structures or variable before PCI Bus walk. * *<4>buswalk [swapper : iSeries_pcibios_init Entry. *<4>buswalk [swapper : IoMmTable Initialized 0xC00000000034BD30 *<4>buswalk [swapper : find_and_init_phbs Entry *<4>buswalk [swapper : Create iSeries pci_controller:(0xC00000001F5C7000), Bus 0x0017 *<4>buswalk [swapper : Connect EADs: 0x17.00.12 = 0x00 *<4>buswalk [swapper : iSeries_assign_IRQ 0x0017.00.12 = 0x0091 *<4>buswalk [swapper : - allocate and assign IRQ 0x17.00.12 = 0x91 *<4>buswalk [swapper : - FoundDevice: 0x17.28.10 = 0x12AE *<4>buswalk [swapper : - build_device_node 0x17.28.12 *<4>buswalk [swapper : iSeries_pcibios_init Exit. ***********************************************************************/ void iSeries_pcibios_init(void) { PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_init Entry.\n"); iSeries_IoMmTable_Initialize(); find_and_init_phbs(); pci_assign_all_busses = 0; PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_init Exit.\n"); }
asmlinkage int sys_uname(struct old_utsname * name) { int err = -EFAULT; PPCDBG(PPCDBG_SYS64X, "sys_uname - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); down_read(&uts_sem); if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) err = 0; up_read(&uts_sem); PPCDBG(PPCDBG_SYS64X, "sys_uname - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); return err; }
/* * Atomically swap in the new signal mask, and wait for a signal. */ long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, struct pt_regs *regs) { sigset_t saveset; PPCDBG(PPCDBG_SYS64X, "sys_sigsuspend - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); mask &= _BLOCKABLE; spin_lock_irq(¤t->sigmask_lock); saveset = current->blocked; siginitset(¤t->blocked, mask); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs->gpr[3] = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); if (do_signal(&saveset, regs)) /* * If a signal handler needs to be called, * do_signal() has set R3 to the signal number (the * first argument of the signal handler), so don't * overwrite that with EINTR ! * In the other cases, do_signal() doesn't touch * R3, so it's still set to -EINTR (see above). */ return regs->gpr[3]; } }
long sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6, int p7, struct pt_regs *regs) { sigset_t saveset, newset; PPCDBG(PPCDBG_SYS64X, "sys_rt_sigsuspend - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) return -EINVAL; if (copy_from_user(&newset, unewset, sizeof(newset))) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); saveset = current->blocked; current->blocked = newset; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs->gpr[3] = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); if (do_signal(&saveset, regs)) return regs->gpr[3]; } }
/* * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. */ asmlinkage int sys_pipe(int *fildes) { int fd[2]; int error; PPCDBG(PPCDBG_SYS64X, "sys_pipe - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); error = do_pipe(fd); if (!error) { if (copy_to_user(fildes, fd, 2*sizeof(int))) error = -EFAULT; } PPCDBG(PPCDBG_SYS64X, "sys_pipe - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); return error; }
void iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel) { struct HvCallPci_BridgeInfo* BridgeInfo; HvAgentId AgentId; int Function; int HvRc; BridgeInfo = (struct HvCallPci_BridgeInfo*)kmalloc(sizeof(struct HvCallPci_BridgeInfo), GFP_KERNEL); if(BridgeInfo == NULL) return; /********************************************************************* * Note: hvSubBus and irq is always be 0 at this level! *********************************************************************/ for (Function=0; Function < 8; ++Function) { AgentId = ISERIES_PCI_AGENTID(IdSel, Function); HvRc = HvCallXm_connectBusUnit(Bus, SubBus, AgentId, 0); if (HvRc == 0) { /* Connect EADs: 0x18.00.12 = 0x00 */ PPCDBG(PPCDBG_BUSWALK,"PCI:Connect EADs: 0x%02X.%02X.%02X\n",Bus, SubBus, AgentId); PCIFR( "Connect EADs: 0x%02X.%02X.%02X", Bus, SubBus, AgentId); HvRc = HvCallPci_getBusUnitInfo(Bus, SubBus, AgentId, REALADDR(BridgeInfo), sizeof(struct HvCallPci_BridgeInfo)); if (HvRc == 0) { PPCDBG(PPCDBG_BUSWALK,"PCI: BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X\n", BridgeInfo->busUnitInfo.deviceType, BridgeInfo->subBusNumber, BridgeInfo->maxAgents, BridgeInfo->maxSubBusNumber, BridgeInfo->logicalSlotNumber); PCIFR( "BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X", BridgeInfo->busUnitInfo.deviceType, BridgeInfo->subBusNumber, BridgeInfo->maxAgents, BridgeInfo->maxSubBusNumber, BridgeInfo->logicalSlotNumber); if (BridgeInfo->busUnitInfo.deviceType == HvCallPci_BridgeDevice) { /* Scan_Bridge_Slot...: 0x18.00.12 */ iSeries_Scan_Bridge_Slot(Bus,BridgeInfo); } else printk("PCI: Invalid Bridge Configuration(0x%02X)",BridgeInfo->busUnitInfo.deviceType); } } else if(HvRc != 0x000B) pci_Log_Error("EADs Connect",Bus,SubBus,AgentId,HvRc); } kfree(BridgeInfo); }
__openfirmware long rtas_call(int token, int nargs, int nret, unsigned long *outputs, ...) { va_list list; int i; unsigned long s; struct rtas_args *rtas_args = &(get_paca()->xRtas); PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n"); PPCDBG(PPCDBG_RTAS, "\ttoken = 0x%x\n", token); PPCDBG(PPCDBG_RTAS, "\tnargs = %d\n", nargs); PPCDBG(PPCDBG_RTAS, "\tnret = %d\n", nret); PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs); if (token == RTAS_UNKNOWN_SERVICE) return -1; rtas_args->token = token; rtas_args->nargs = nargs; rtas_args->nret = nret; rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); va_start(list, outputs); for (i = 0; i < nargs; ++i) { rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong)); PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]); } va_end(list); for (i = 0; i < nret; ++i) rtas_args->rets[i] = 0; #if 0 /* Gotta do something different here, use global lock for now... */ spin_lock_irqsave(&rtas_args->lock, s); #else spin_lock_irqsave(&rtas.lock, s); #endif PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", (void *)__pa((unsigned long)rtas_args)); enter_rtas((void *)__pa((unsigned long)rtas_args)); PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); #if 0 /* Gotta do something different here, use global lock for now... */ spin_unlock_irqrestore(&rtas_args->lock, s); #else spin_unlock_irqrestore(&rtas.lock, s); #endif ifppcdebug(PPCDBG_RTAS) { for(i=0; i < nret ;i++) udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); } if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = rtas_args->rets[i+1]; return (ulong)((nret > 0) ? rtas_args->rets[0] : 0); }
asmlinkage long sys_sigaltstack(const stack_t *uss, stack_t *uoss) { struct pt_regs *regs = (struct pt_regs *) &uss; PPCDBG(PPCDBG_SYS64X, "sys_sigaltstack - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); return do_sigaltstack(uss, uoss, regs->gpr[1]); }
void __init smp_commence(void) { /* * Lets the callin's below out of their loop. */ PPCDBG(PPCDBG_SMP, "smp_commence: start\n"); wmb(); smp_commenced = 1; }
int rtas_token(const char *service) { int *tokp; if (rtas.dev == NULL) { PPCDBG(PPCDBG_RTAS,"\tNo rtas device in device-tree...\n"); return RTAS_UNKNOWN_SERVICE; } tokp = (int *) get_property(rtas.dev, service, NULL); return tokp ? *tokp : RTAS_UNKNOWN_SERVICE; }
/*********************************************************************** * iSeries_pcibios_fixup(void) ***********************************************************************/ void __init iSeries_pcibios_fixup(void) { struct pci_dev* PciDev; struct iSeries_Device_Node* DeviceNode; char Buffer[256]; int DeviceCount = 0; PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_fixup Entry.\n"); /******************************************************/ /* Fix up at the device node and pci_dev relationship */ /******************************************************/ mf_displaySrc(0xC9000100); pci_for_each_dev(PciDev) { DeviceNode = find_Device_Node(PciDev); if(DeviceNode != NULL) { ++DeviceCount; PciDev->sysdata = (void*)DeviceNode; DeviceNode->PciDev = PciDev; PPCDBG(PPCDBG_BUSWALK,"PciDev 0x%p <==> DevNode 0x%p\n",PciDev,DeviceNode ); iSeries_allocateDeviceBars(PciDev); PPCDBGCALL(PPCDBG_BUSWALK,dumpPci_Dev(PciDev) ); iSeries_Device_Information(PciDev,Buffer, sizeof(Buffer) ); printk("%d. %s\n",DeviceCount,Buffer); create_pci_bus_tce_table((unsigned long)DeviceNode); } else { printk("PCI: Device Tree not found for 0x%016lX\n",(unsigned long)PciDev); } } iSeries_IoMmTable_Status(); iSeries_activate_IRQs(); mf_displaySrc(0xC9000200); }
/**************************************************************************** * * unsigned int __init find_and_init_phbs(void) * * Description: * This function checks for all possible system PCI host bridges that connect * PCI buses. The system hypervisor is queried as to the guest partition * ownership status. A pci_controller is build for any bus which is partially * owned or fully owned by this guest partition. ****************************************************************************/ unsigned long __init find_and_init_phbs(void) { struct pci_controller* phb; HvBusNumber BusNumber; PPCDBG(PPCDBG_BUSWALK,"find_and_init_phbs Entry\n"); /* Check all possible buses. */ for (BusNumber = 0; BusNumber < 256; BusNumber++) { int RtnCode = HvCallXm_testBus(BusNumber); if (RtnCode == 0) { phb = pci_alloc_pci_controllerX("PHB HV", phb_type_hypervisor); if(phb == NULL) { printk("PCI: Allocate pci_controller failed.\n"); PCIFR( "Allocate pci_controller failed."); return -1; } phb->pci_mem_offset = phb->local_number = BusNumber; phb->first_busno = BusNumber; phb->last_busno = BusNumber; phb->ops = &iSeries_pci_ops; PPCDBG(PPCDBG_BUSWALK, "PCI:Create iSeries pci_controller(%p), Bus: %04X\n",phb,BusNumber); PCIFR("Create iSeries PHB controller: %04X",BusNumber); /***************************************************/ /* Find and connect the devices. */ /***************************************************/ iSeries_Scan_PHBs_Slots(phb); } /* Check for Unexpected Return code, a clue that something */ /* has gone wrong. */ else if(RtnCode != 0x0301) { PCIFR("Unexpected Return on Probe(0x%04X): 0x%04X",BusNumber,RtnCode); } } return 0; }
/* This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c */ void __init iSeries_init_IRQ(void) { int i; for (i = 0; i < NR_IRQS; i++) { irq_desc[i].handler = &iSeries_IRQ_handler; irq_desc[i].status = 0; irq_desc[i].status |= IRQ_DISABLED; irq_desc[i].depth = 1; iSeries_init_irqMap(i); } /* Register PCI event handler and open an event path */ PPCDBG(PPCDBG_BUSWALK,"Register PCI event handler and open an event path\n"); XmPciLpEvent_init(); return; }
/** Return a copy of the detailed error text associated with the * most recent failed call to rtas. Because the error text * might go stale if there are any other intervening rtas calls, * this routine must be called atomically with whatever produced * the error (i.e. with rtas.lock still held from the previous call). */ static int __fetch_rtas_last_error(void) { struct rtas_args err_args, save_args; u32 bufsz; bufsz = rtas_token ("rtas-error-log-max"); if ((bufsz == RTAS_UNKNOWN_SERVICE) || (bufsz > RTAS_ERROR_LOG_MAX)) { printk (KERN_WARNING "RTAS: bad log buffer size %d\n", bufsz); bufsz = RTAS_ERROR_LOG_MAX; } err_args.token = rtas_token("rtas-last-error"); err_args.nargs = 2; err_args.nret = 1; err_args.args[0] = (rtas_arg_t)__pa(rtas_err_buf); err_args.args[1] = bufsz; err_args.args[2] = 0; save_args = rtas.args; rtas.args = err_args; rtas.args.rets = (rtas_arg_t *)&(rtas.args.args[2]); PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", __pa(&err_args)); enter_rtas((void *)__pa((unsigned long)(&rtas.args))); PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); err_args = rtas.args; rtas.args = save_args; err_args.rets = (rtas_arg_t *)&(err_args.args[2]); return err_args.rets[0]; }
/* This should be called sometime prior to buswalk (init_IRQ would be good) */ int XmPciLpEvent_init() { int xRc; PPCDBG(PPCDBG_BUSWALK,"XmPciLpEvent_init, Register Event type 0x%04X\n",HvLpEvent_Type_PciIo); xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, &XmPciLpEvent_handler); if (xRc == 0) { xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); if (xRc != 0) { printk(KERN_ERR "XmPciLpEvent.c: open event path failed with rc 0x%x\n", xRc); } } else { printk(KERN_ERR "XmPciLpEvent.c: register handler failed with rc 0x%x\n", xRc); } return xRc; }
long sys_sigaction(int sig, const struct old_sigaction *act, struct old_sigaction *oact) { struct k_sigaction new_ka, old_ka; int ret; PPCDBG(PPCDBG_SYS64X, "sys_sigaction - running - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); if (act) { old_sigset_t mask; if (verify_area(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) return -EFAULT; __get_user(new_ka.sa.sa_flags, &act->sa_flags); __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) return -EFAULT; __put_user(old_ka.sa.sa_flags, &oact->sa_flags); __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret; }
/*********************************************************************** * build_device_node(u16 Bus, int SubBus, u8 DevFn) * ***********************************************************************/ struct iSeries_Device_Node* build_device_node(HvBusNumber Bus, HvSubBusNumber SubBus, int AgentId, int Function) { struct iSeries_Device_Node* DeviceNode; PPCDBG(PPCDBG_BUSWALK,"-build_device_node 0x%02X.%02X.%02X Function: %02X\n",Bus,SubBus,AgentId, Function); DeviceNode = kmalloc(sizeof(struct iSeries_Device_Node), GFP_KERNEL); if(DeviceNode == NULL) return NULL; memset(DeviceNode,0,sizeof(struct iSeries_Device_Node) ); list_add_tail(&DeviceNode->Device_List,&iSeries_Global_Device_List); /*DeviceNode->DsaAddr = ((u64)Bus<<48)+((u64)SubBus<<40)+((u64)0x10<<32); */ ISERIES_BUS(DeviceNode) = Bus; ISERIES_SUBBUS(DeviceNode) = SubBus; DeviceNode->DsaAddr.deviceId = 0x10; DeviceNode->DsaAddr.barNumber = 0; DeviceNode->AgentId = AgentId; DeviceNode->DevFn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId),Function ); DeviceNode->IoRetry = 0; iSeries_Get_Location_Code(DeviceNode); PCIFR("Device 0x%02X.%2X, Node:0x%p ",ISERIES_BUS(DeviceNode),ISERIES_DEVFUN(DeviceNode),DeviceNode); return DeviceNode; }
int do_signal(sigset_t *oldset, struct pt_regs *regs) { siginfo_t info; struct k_sigaction *ka; unsigned long frame, newsp; /* * If the current thread is 32 bit - invoke the * 32 bit signal handling code */ if (current->thread.flags & PPC_FLAG_32BIT) return do_signal32(oldset, regs); if (!oldset) oldset = ¤t->blocked; newsp = frame = 0; for (;;) { unsigned long signr; PPCDBG(PPCDBG_SIGNAL, "do_signal - (pre) dequeueing signal - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); spin_lock_irq(¤t->sigmask_lock); signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); PPCDBG(PPCDBG_SIGNAL, "do_signal - (aft) dequeueing signal - signal=%lx - pid=%ld current=%lx comm=%s \n", signr, current->pid, current, current->comm); if (!signr) break; if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) continue; current->exit_code = 0; /* The debugger continued. Ignore SIGSTOP. */ if (signr == SIGSTOP) continue; /* Update the siginfo structure. Is this good? */ if (signr != info.si_signo) { info.si_signo = signr; info.si_errno = 0; info.si_code = SI_USER; info.si_pid = current->p_pptr->pid; info.si_uid = current->p_pptr->uid; } /* If the (new) signal is now blocked, requeue it. */ if (sigismember(¤t->blocked, signr)) { send_sig_info(signr, &info, current); continue; } } ka = ¤t->sig->action[signr-1]; PPCDBG(PPCDBG_SIGNAL, "do_signal - ka=%p, action handler=%lx \n", ka, ka->sa.sa_handler); if (ka->sa.sa_handler == SIG_IGN) { PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_IGN logic \n"); if (signr != SIGCHLD) continue; /* Check for SIGCHLD: it's special. */ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) /* nothing */; continue; } if (ka->sa.sa_handler == SIG_DFL) { int exit_code = signr; PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_DFL logic \n"); /* Init gets no signals it doesn't want. */ if (current->pid == 1) continue; switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) continue; /* FALLTHRU */ case SIGSTOP: { struct signal_struct *sig; current->state = TASK_STOPPED; current->exit_code = signr; sig = current->p_pptr->sig; if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; } case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ default: sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } if ( (ka->sa.sa_flags & SA_ONSTACK) && (! on_sig_stack(regs->gpr[1]))) newsp = (current->sas_ss_sp + current->sas_ss_size); else newsp = regs->gpr[1]; newsp = frame = newsp - sizeof(struct sigregs); /* Whee! Actually deliver the signal. */ PPCDBG(PPCDBG_SIGNAL, "do_signal - GOING TO RUN SIGNAL HANDLER - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); handle_signal(signr, ka, &info, oldset, regs, &newsp, frame); PPCDBG(PPCDBG_SIGNAL, "do_signal - after running signal handler - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm); break; } if (regs->trap == 0x0C00 /* System Call! */ && ((int)regs->result == -ERESTARTNOHAND || (int)regs->result == -ERESTARTSYS || (int)regs->result == -ERESTARTNOINTR)) { PPCDBG(PPCDBG_SIGNAL, "do_signal - going to back up & retry system call \n"); regs->gpr[3] = regs->orig_gpr3; regs->nip -= 4; /* Back up & retry system call */ regs->result = 0; } if (newsp == frame) { PPCDBG(PPCDBG_SIGNAL, "do_signal - returning w/ no signal delivered \n"); return 0; /* no signals delivered */ } if (ka->sa.sa_flags & SA_SIGINFO) setup_rt_frame(regs, (struct sigregs *) frame, newsp); else setup_frame(regs, (struct sigregs *) frame, newsp); PPCDBG(PPCDBG_SIGNAL, "do_signal - returning a signal was delivered \n"); return 1; }
/* * Set up a signal frame. */ static void setup_frame(struct pt_regs *regs, struct sigregs *frame, unsigned long newsp) { /* Handler is *really* a pointer to the function descriptor for * the signal routine. The first entry in the function * descriptor is the entry address of signal and the second * entry is the TOC value we need to use. */ struct funct_descr_entry { unsigned long entry; unsigned long toc; }; struct funct_descr_entry * funct_desc_ptr; unsigned long temp_ptr; struct sigcontext_struct *sc = (struct sigcontext_struct *) newsp; if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) goto badframe; if (regs->msr & MSR_FP) giveup_fpu(current); if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) || __copy_to_user(&frame->fp_regs, current->thread.fpr, ELF_NFPREG * sizeof(double)) || __put_user(0x38000000UL + __NR_sigreturn, &frame->tramp[0]) /* li r0, __NR_sigreturn */ || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */ goto badframe; flush_icache_range((unsigned long) &frame->tramp[0], (unsigned long) &frame->tramp[2]); newsp -= __SIGNAL_FRAMESIZE; if ( get_user(temp_ptr, &sc->handler)) goto badframe; funct_desc_ptr = ( struct funct_descr_entry *) temp_ptr; if (put_user(regs->gpr[1], (unsigned long *)newsp) || get_user(regs->nip, & funct_desc_ptr ->entry) || get_user(regs->gpr[2],& funct_desc_ptr->toc) || get_user(regs->gpr[3], &sc->signal)) goto badframe; regs->gpr[1] = newsp; regs->gpr[4] = (unsigned long) sc; regs->link = (unsigned long) frame->tramp; PPCDBG(PPCDBG_SIGNAL, "setup_frame - returning - regs->gpr[1]=%lx, regs->gpr[4]=%lx, regs->link=%lx \n", regs->gpr[1], regs->gpr[4], regs->link); return; badframe: PPCDBG(PPCDBG_SIGNAL, "setup_frame - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); PPCDBG_ENTER_DEBUGGER(); #if DEBUG_SIG printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif do_exit(SIGSEGV); }
int rtas_call(int token, int nargs, int nret, int *outputs, ...) { va_list list; int i, logit = 0; unsigned long s; struct rtas_args *rtas_args; char * buff_copy = NULL; int ret; PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n"); PPCDBG(PPCDBG_RTAS, "\ttoken = 0x%x\n", token); PPCDBG(PPCDBG_RTAS, "\tnargs = %d\n", nargs); PPCDBG(PPCDBG_RTAS, "\tnret = %d\n", nret); PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs); if (token == RTAS_UNKNOWN_SERVICE) return -1; /* Gotta do something different here, use global lock for now... */ spin_lock_irqsave(&rtas.lock, s); rtas_args = &rtas.args; rtas_args->token = token; rtas_args->nargs = nargs; rtas_args->nret = nret; rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); va_start(list, outputs); for (i = 0; i < nargs; ++i) { rtas_args->args[i] = va_arg(list, rtas_arg_t); PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%x\n", i, rtas_args->args[i]); } va_end(list); for (i = 0; i < nret; ++i) rtas_args->rets[i] = 0; PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", __pa(rtas_args)); enter_rtas(__pa(rtas_args)); PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); /* A -1 return code indicates that the last command couldn't be completed due to a hardware error. */ if (rtas_args->rets[0] == -1) logit = (__fetch_rtas_last_error() == 0); ifppcdebug(PPCDBG_RTAS) { for(i=0; i < nret ;i++) udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); } if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = rtas_args->rets[i+1]; ret = (nret > 0)? rtas_args->rets[0]: 0; /* Log the error in the unlikely case that there was one. */ if (unlikely(logit)) { buff_copy = rtas_err_buf; if (mem_init_done) { buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); if (buff_copy) memcpy(buff_copy, rtas_err_buf, RTAS_ERROR_LOG_MAX); } } /* Gotta do something different here, use global lock for now... */ spin_unlock_irqrestore(&rtas.lock, s); if (buff_copy) { log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); if (mem_init_done) kfree(buff_copy); } return ret; }
/******************************************************************************** * * This assumes that the node slot is always on the primary bus! * *********************************************************************************/ int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo* BridgeInfo) { struct iSeries_Device_Node* DeviceNode; HvSubBusNumber SubBus = BridgeInfo->subBusNumber; u16 VendorId = 0; int HvRc = 0; u8 Irq = 0; int IdSel = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus); int Function = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus); HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function); HvAgentId EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function); int FirstSlotId = 0; /**********************************************************/ /* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */ /**********************************************************/ Irq = iSeries_allocate_IRQ(Bus, 0, AgentId); iSeries_assign_IRQ(Irq, Bus, 0, AgentId); PPCDBG(PPCDBG_BUSWALK,"PCI:- allocate and assign IRQ 0x%02X.%02X.%02X = 0x%02X\n",Bus, 0, AgentId, Irq ); /**************************************************************************** * Connect all functions of any device found. ****************************************************************************/ for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) { for (Function = 0; Function < 8; ++Function) { AgentId = ISERIES_PCI_AGENTID(IdSel, Function); HvRc = HvCallXm_connectBusUnit(Bus, SubBus, AgentId, Irq); if( HvRc == 0) { HvRc = HvCallPci_configLoad16(Bus, SubBus, AgentId, PCI_VENDOR_ID, &VendorId); if( HvRc == 0) { /**********************************************************/ /* FoundDevice: 0x18.28.10 = 0x12AE */ /**********************************************************/ PPCDBG(PPCDBG_BUSWALK,"PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X\n", Bus, SubBus, AgentId, VendorId); HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId, PCI_INTERRUPT_LINE, Irq); if( HvRc != 0) { pci_Log_Error("PciCfgStore Irq Failed!",Bus,SubBus,AgentId,HvRc); } ++DeviceCount; DeviceNode = build_device_node(Bus, SubBus, EADsIdSel, Function); DeviceNode->Vendor = VendorId; DeviceNode->Irq = Irq; DeviceNode->LogicalSlot = BridgeInfo->logicalSlotNumber; PCIFR("Device(%4d): 0x%02X.%02X.%02X 0x%02X 0x%04X", DeviceCount,Bus, SubBus, AgentId, DeviceNode->LogicalSlot,DeviceNode->Vendor); /*********************************************************** * On the first device/function, assign irq to slot ***********************************************************/ if(Function == 0) { FirstSlotId = AgentId; // AHT iSeries_assign_IRQ(Irq, Bus, SubBus, AgentId); } } else pci_Log_Error("Read Vendor",Bus,SubBus,AgentId,HvRc); } else pci_Log_Error("Connect Bus Unit",Bus,SubBus, AgentId,HvRc); } /* for (Function = 0; Function < 8; ++Function) */ } /* for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) */ return HvRc; }
/****************************************************************** * Find all PHBs in the system and initialize a set of data * structures to represent them. ******************************************************************/ unsigned long __init find_and_init_phbs(void) { struct device_node *Pci_Node; struct pci_controller *phb; unsigned int root_addr_size_words = 0, this_addr_size_words = 0; unsigned int this_addr_count = 0, range_stride; unsigned int *ui_ptr = NULL, *ranges; char *model; struct pci_range64 range; struct resource *res; unsigned int memno, rlen, i, index; unsigned int *opprop; int has_isa = 0; PPCDBG(PPCDBG_PHBINIT, "find_and_init_phbs\n"); read_pci_config = rtas_token("read-pci-config"); write_pci_config = rtas_token("write-pci-config"); ibm_read_pci_config = rtas_token("ibm,read-pci-config"); ibm_write_pci_config = rtas_token("ibm,write-pci-config"); if (naca->interrupt_controller == IC_OPEN_PIC) { opprop = (unsigned int *)get_property(find_path_device("/"), "platform-open-pic", NULL); } /* Get the root address word size. */ ui_ptr = (unsigned int *) get_property(find_path_device("/"), "#size-cells", NULL); if (ui_ptr) { root_addr_size_words = *ui_ptr; } else { PPCDBG(PPCDBG_PHBINIT, "\tget #size-cells failed.\n"); return(-1); } if (find_type_devices("isa")) { has_isa = 1; PPCDBG(PPCDBG_PHBINIT, "\tFound an ISA bus.\n"); } index = 0; /****************************************************************** * Find all PHB devices and create an object for them. ******************************************************************/ for (Pci_Node = find_devices("pci"); Pci_Node != NULL; Pci_Node = Pci_Node->next) { model = (char *) get_property(Pci_Node, "model", NULL); if (model != NULL) { phb = alloc_phb(Pci_Node, model, root_addr_size_words); if (phb == NULL) return(-1); } else { continue; } /* Get this node's address word size. */ ui_ptr = (unsigned int *) get_property(Pci_Node, "#size-cells", NULL); if (ui_ptr) this_addr_size_words = *ui_ptr; else this_addr_size_words = 1; /* Get this node's address word count. */ ui_ptr = (unsigned int *) get_property(Pci_Node, "#address-cells", NULL); if (ui_ptr) this_addr_count = *ui_ptr; else this_addr_count = 3; range_stride = this_addr_count + root_addr_size_words + this_addr_size_words; memno = 0; phb->io_base_phys = 0; ranges = (unsigned int *) get_property(Pci_Node, "ranges", &rlen); PPCDBG(PPCDBG_PHBINIT, "\trange_stride = 0x%lx, rlen = 0x%x\n", range_stride, rlen); for (i = 0; i < (rlen/sizeof(*ranges)); i+=range_stride) { /* Put the PCI addr part of the current element into a * '64' struct. */ range = *((struct pci_range64 *)(ranges + i)); /* If this is a '32' element, map into a 64 struct. */ if ((range_stride * sizeof(int)) == sizeof(struct pci_range32)) { range.parent_addr = (unsigned long)(*(ranges + i + 3)); range.size = (((unsigned long)(*(ranges + i + 4)))<<32) | (*(ranges + i + 5)); } else { range.parent_addr = (((unsigned long)(*(ranges + i + 3)))<<32) | (*(ranges + i + 4)); range.size = (((unsigned long)(*(ranges + i + 5)))<<32) | (*(ranges + i + 6)); } PPCDBG(PPCDBG_PHBINIT, "\trange.parent_addr = 0x%lx\n", range.parent_addr); PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.hi = 0x%lx\n", range.child_addr.a_hi); PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.mid = 0x%lx\n", range.child_addr.a_mid); PPCDBG(PPCDBG_PHBINIT, "\trange.child_addr.lo = 0x%lx\n", range.child_addr.a_lo); PPCDBG(PPCDBG_PHBINIT, "\trange.size = 0x%lx\n", range.size); res = NULL; switch ((range.child_addr.a_hi >> 24) & 0x3) { case 1: /* I/O space */ PPCDBG(PPCDBG_PHBINIT, "\tIO Space\n"); phb->io_base_phys = range.parent_addr; res = &phb->io_resource; res->name = Pci_Node->full_name; res->flags = IORESOURCE_IO; phb->io_base_virt = __ioremap(phb->io_base_phys, range.size, _PAGE_NO_CACHE); if (!pci_io_base) { pci_io_base = (unsigned long)phb->io_base_virt; if (has_isa) isa_io_base = pci_io_base; } res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo)); res->start += (unsigned long)phb->io_base_virt - pci_io_base; res->end = res->start + range.size - 1; res->parent = NULL; res->sibling = NULL; res->child = NULL; phb->pci_io_offset = range.parent_addr - ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo)); PPCDBG(PPCDBG_PHBINIT, "\tpci_io_offset = 0x%lx\n", phb->pci_io_offset); break; case 2: /* mem space */ PPCDBG(PPCDBG_PHBINIT, "\tMem Space\n"); phb->pci_mem_offset = range.parent_addr - ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo)); PPCDBG(PPCDBG_PHBINIT, "\tpci_mem_offset = 0x%lx\n", phb->pci_mem_offset); if (memno < sizeof(phb->mem_resources)/sizeof(phb->mem_resources[0])) { res = &(phb->mem_resources[memno]); ++memno; res->name = Pci_Node->full_name; res->flags = IORESOURCE_MEM; res->start = range.parent_addr; res->end = range.parent_addr + range.size - 1; res->parent = NULL; res->sibling = NULL; res->child = NULL; } break; } } PPCDBG(PPCDBG_PHBINIT, "\tphb->io_base_phys = 0x%lx\n", phb->io_base_phys); PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_mem_offset = 0x%lx\n", phb->pci_mem_offset); if (naca->interrupt_controller == IC_OPEN_PIC) { int addr = root_addr_size_words * (index + 2) - 1; openpic_setup_ISU(index, opprop[addr]); } index++; } pci_devs_phb_init(); return 0; /*Success */ }
/*********************************************************************** * fixup_resources(struct pci_dev *dev) * ***********************************************************************/ void fixup_resources(struct pci_dev *PciDev) { PPCDBG(PPCDBG_BUSWALK,"fixup_resources PciDev %p\n",PciDev); }
/****************************************************************** * * Allocate and partially initialize a structure to represent a PHB. * ******************************************************************/ struct pci_controller * alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) { struct pci_controller *phb; unsigned int *ui_ptr = NULL, len; struct reg_property64 reg_struct; struct property *of_prop; int *bus_range; int *buid_vals; PPCDBG(PPCDBG_PHBINIT, "alloc_phb: %s\n", dev->full_name); PPCDBG(PPCDBG_PHBINIT, "\tdev = 0x%lx\n", dev); PPCDBG(PPCDBG_PHBINIT, "\tmodel = 0x%lx\n", model); PPCDBG(PPCDBG_PHBINIT, "\taddr_size_words = 0x%lx\n", addr_size_words); /* Found a PHB, now figure out where his registers are mapped. */ ui_ptr = (unsigned int *) get_property(dev, "reg", &len); if (ui_ptr == NULL) { PPCDBG(PPCDBG_PHBINIT, "\tget reg failed.\n"); return(NULL); } if (addr_size_words == 1) { reg_struct.address = ((struct reg_property32 *)ui_ptr)->address; reg_struct.size = ((struct reg_property32 *)ui_ptr)->size; } else { reg_struct = *((struct reg_property64 *)ui_ptr); } PPCDBG(PPCDBG_PHBINIT, "\treg_struct.address = 0x%lx\n", reg_struct.address); PPCDBG(PPCDBG_PHBINIT, "\treg_struct.size = 0x%lx\n", reg_struct.size); /*************************************************************** * Set chip specific data in the phb, including types & * register pointers. ***************************************************************/ /**************************************************************** * Python ***************************************************************/ if (strstr(model, "Python")) { PPCDBG(PPCDBG_PHBINIT, "\tCreate python\n"); phb = pci_alloc_pci_controller("PHB PY",phb_type_python); if (phb == NULL) return NULL; phb->cfg_addr = (volatile unsigned long *) ioremap(reg_struct.address + 0xf8000, PAGE_SIZE); PPCDBG(PPCDBG_PHBINIT, "\tcfg_addr_r = 0x%lx\n", reg_struct.address + 0xf8000); PPCDBG(PPCDBG_PHBINIT, "\tcfg_addr_v = 0x%lx\n", phb->cfg_addr); phb->cfg_data = (char*)(phb->cfg_addr + 0x02); phb->phb_regs = (volatile unsigned long *) ioremap(reg_struct.address + 0xf7000, PAGE_SIZE); /* Python's register file is 1 MB in size. */ phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); /* * Firmware doesn't always clear this bit which is critical * for good performance - Anton */ { volatile u32 *tmp, i; #define PRG_CL_RESET_VALID 0x00010000 tmp = (u32 *)((unsigned long)phb->chip_regs + 0xf6030); if (*tmp & PRG_CL_RESET_VALID) { printk("Python workaround: "); *tmp &= ~PRG_CL_RESET_VALID; /* * We must read it back for changes to * take effect */ i = *tmp; printk("reg0: %x\n", i); } } /*************************************************************** * Speedwagon * include Winnipeg as well for the time being. ***************************************************************/ } else if ((strstr(model, "Speedwagon")) || (strstr(model, "Winnipeg"))) { PPCDBG(PPCDBG_PHBINIT, "\tCreate speedwagon\n"); phb = pci_alloc_pci_controller("PHB SW",phb_type_speedwagon); if (phb == NULL) return NULL; if (systemcfg->platform == PLATFORM_PSERIES) { phb->cfg_addr = (volatile unsigned long *) ioremap(reg_struct.address + 0x140, PAGE_SIZE); phb->cfg_data = (char*)(phb->cfg_addr - 0x02); /* minus is correct */ phb->phb_regs = (volatile unsigned long *) ioremap(reg_struct.address, PAGE_SIZE); /* Speedwagon's register file is 1 MB in size. */ phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); PPCDBG(PPCDBG_PHBINIT, "\tmapping chip_regs from 0x%lx -> 0x%lx\n", reg_struct.address & 0xfffff, phb->chip_regs); } else { phb->cfg_addr = NULL; phb->cfg_data = NULL; phb->phb_regs = NULL; phb->chip_regs = NULL; } phb->local_number = ((reg_struct.address >> 12) & 0xf) - 0x8; } else {
/*********************************************************************** * iSeries_pcibios_fixup_bus(int Bus) * ***********************************************************************/ void iSeries_pcibios_fixup_bus(struct pci_bus* PciBus) { PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_fixup_bus(0x%04X) Entry.\n",PciBus->number); }