/** * ia64_sn_probe_io_slot - test a memory location for readability * @paddr: physical address to probe * @size: number bytes to read (1,2,4,8) * @data_ptr: address to store value read by probe (-1 returned if probe fails) * * This function will probe a physical address to determine if * the address can be read. If reading the address causes a BUS * error, an error is returned. If the probe succeeds, the contents * of the memory location is returned. * * Return values: * 0 - probe successful * 1 - probe failed (generated MCA) * 2 - Bad arg * <0 - PAL error */ u64 ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr) { struct ia64_sal_retval isrv; SAL_CALL(isrv, SN_SAL_PROBE, paddr, size, 0, 0, 0, 0, 0); if (data_ptr) { switch (size) { case 1: *((u8*)data_ptr) = (u8)isrv.v0; break; case 2: *((u16*)data_ptr) = (u16)isrv.v0; break; case 4: *((u32*)data_ptr) = (u32)isrv.v0; break; case 8: *((u64*)data_ptr) = (u64)isrv.v0; break; default: isrv.status = 2; } } return isrv.status; }
int ia64_sal_oemcall(struct ia64_sal_retval *isrvp, u64 oemfunc, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7) { if (oemfunc < IA64_SAL_OEMFUNC_MIN || oemfunc > IA64_SAL_OEMFUNC_MAX) return -1; SAL_CALL(*isrvp, oemfunc, arg1, arg2, arg3, arg4, arg5, arg6, arg7); return 0; }
int sn_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size) { int ret = size; unsigned long paddr; unsigned long *addr; struct ia64_sal_retval isrv; /* * First, try the SN_SAL_IOIF_PCI_SAFE SAL call which can work * around hw issues at the pci bus level. SGI proms older than * 4.10 don't implment this. */ SAL_CALL(isrv, SN_SAL_IOIF_PCI_SAFE, pci_domain_nr(bus), bus->number, 0, /* io */ 1, /* write */ port, size, __pa(&val)); if (isrv.status == 0) return size; /* * If the above failed, retry using the SAL_PROBE call which should * be present in all proms (but which cannot work round PCI chipset * bugs). This code is retained for compatability with old * pre-4.10 proms, and should be removed at some point in the future. */ if (!SN_PCIBUS_BUSSOFT(bus)) { ret = -ENODEV; goto out; } /* Put the phys addr in uncached space */ paddr = SN_PCIBUS_BUSSOFT(bus)->bs_legacy_io | __IA64_UNCACHED_OFFSET; paddr += port; addr = (unsigned long *)paddr; switch (size) { case 1: *(volatile u8 *)(addr) = (u8)(val); break; case 2: *(volatile u16 *)(addr) = (u16)(val); break; case 4: *(volatile u32 *)(addr) = (u32)(val); break; default: ret = -EINVAL; break; } out: return ret; }
long ia64_sal_freq_base (unsigned long which, unsigned long *ticks_per_second, unsigned long *drift_info) { struct ia64_sal_retval isrv; SAL_CALL(isrv, SAL_FREQ_BASE, which, 0, 0, 0, 0, 0, 0); *ticks_per_second = isrv.v0; *drift_info = isrv.v1; return isrv.status; }
int sn_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size) { unsigned long addr; int ret; struct ia64_sal_retval isrv; /* * First, try the SN_SAL_IOIF_PCI_SAFE SAL call which can work * around hw issues at the pci bus level. SGI proms older than * 4.10 don't implment this. */ SAL_CALL(isrv, SN_SAL_IOIF_PCI_SAFE, pci_domain_nr(bus), bus->number, 0, /* io */ 0, /* read */ port, size, __pa(val)); if (isrv.status == 0) return size; /* * If the above failed, retry using the SAL_PROBE call which should * be present in all proms (but which cannot work round PCI chipset * bugs). This code is retained for compatability with old * pre-4.10 proms, and should be removed at some point in the future. */ if (!SN_PCIBUS_BUSSOFT(bus)) return -ENODEV; addr = SN_PCIBUS_BUSSOFT(bus)->bs_legacy_io | __IA64_UNCACHED_OFFSET; addr += port; ret = ia64_sn_probe_mem(addr, (long)size, (void *)val); if (ret == 2) return -EINVAL; if (ret == 1) *val = -1; return size; }
void __init check_sal_cache_flush (void) { unsigned long flags; int cpu; u64 vector, cache_type = 3; struct ia64_sal_retval isrv; if (sal_cache_flush_drops_interrupts) return; cpu = get_cpu(); local_irq_save(flags); /* * Send ourselves a timer interrupt, wait until it's reported, and see * if SAL_CACHE_FLUSH drops it. */ platform_send_ipi(cpu, IA64_TIMER_VECTOR, IA64_IPI_DM_INT, 0); while (!ia64_get_irr(IA64_TIMER_VECTOR)) cpu_relax(); SAL_CALL(isrv, SAL_CACHE_FLUSH, cache_type, 0, 0, 0, 0, 0, 0); if (isrv.status) printk(KERN_ERR "SAL_CAL_FLUSH failed with %ld\n", isrv.status); if (ia64_get_irr(IA64_TIMER_VECTOR)) { vector = ia64_get_ivr(); ia64_eoi(); WARN_ON(vector != IA64_TIMER_VECTOR); } else { sal_cache_flush_drops_interrupts = 1; printk(KERN_ERR "SAL: SAL_CACHE_FLUSH drops interrupts; " "PAL_CACHE_FLUSH will be used instead\n"); ia64_eoi(); } local_irq_restore(flags); put_cpu(); }
s64 ia64_sal_cache_flush (u64 cache_type) { struct ia64_sal_retval isrv; if (sal_cache_flush_drops_interrupts) { unsigned long flags; u64 progress; s64 rc; progress = 0; local_irq_save(flags); rc = ia64_pal_cache_flush(cache_type, PAL_CACHE_FLUSH_INVALIDATE, &progress, NULL); local_irq_restore(flags); return rc; } SAL_CALL(isrv, SAL_CACHE_FLUSH, cache_type, 0, 0, 0, 0, 0, 0); return isrv.status; }
void intr_init_vecblk( nodepda_t *npda, cnodeid_t node, int sn) { int nasid = cnodeid_to_nasid(node); sh_ii_int0_config_u_t ii_int_config; cpuid_t cpu; cpuid_t cpu0, cpu1; nodepda_t *lnodepda; sh_ii_int0_enable_u_t ii_int_enable; sh_int_node_id_config_u_t node_id_config; sh_local_int5_config_u_t local5_config; sh_local_int5_enable_u_t local5_enable; extern void sn_init_cpei_timer(void); static int timer_added = 0; if (is_headless_node(node) ) { int cnode; struct ia64_sal_retval ret_stuff; // retarget all interrupts on this node to the master node. node_id_config.sh_int_node_id_config_regval = 0; node_id_config.sh_int_node_id_config_s.node_id = master_nasid; node_id_config.sh_int_node_id_config_s.id_sel = 1; HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_INT_NODE_ID_CONFIG), node_id_config.sh_int_node_id_config_regval); cnode = nasid_to_cnodeid(master_nasid); lnodepda = NODEPDA(cnode); cpu = lnodepda->node_first_cpu; cpu = cpu_physical_id(cpu); SAL_CALL(ret_stuff, SN_SAL_REGISTER_CE, nasid, cpu, master_nasid,0,0,0,0); if (ret_stuff.status < 0) { printk("%s: SN_SAL_REGISTER_CE SAL_CALL failed\n",__FUNCTION__); } } else { lnodepda = NODEPDA(node); cpu = lnodepda->node_first_cpu; cpu = cpu_physical_id(cpu); } // Get the physical id's of the cpu's on this node. cpu0 = nasid_slice_to_cpu_physical_id(nasid, 0); cpu1 = nasid_slice_to_cpu_physical_id(nasid, 2); HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_ERROR_MASK), 0); HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_CRBP_ERROR_MASK), 0); // Config and enable UART interrupt, all nodes. local5_config.sh_local_int5_config_regval = 0; local5_config.sh_local_int5_config_s.idx = SGI_UART_VECTOR; local5_config.sh_local_int5_config_s.pid = cpu; HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_CONFIG), local5_config.sh_local_int5_config_regval); local5_enable.sh_local_int5_enable_regval = 0; local5_enable.sh_local_int5_enable_s.uart_int = 1; HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_ENABLE), local5_enable.sh_local_int5_enable_regval); // The II_INT_CONFIG register for cpu 0. ii_int_config.sh_ii_int0_config_regval = 0; ii_int_config.sh_ii_int0_config_s.type = 0; ii_int_config.sh_ii_int0_config_s.agt = 0; ii_int_config.sh_ii_int0_config_s.pid = cpu0; ii_int_config.sh_ii_int0_config_s.base = 0; HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_CONFIG), ii_int_config.sh_ii_int0_config_regval); // The II_INT_CONFIG register for cpu 1. ii_int_config.sh_ii_int0_config_regval = 0; ii_int_config.sh_ii_int0_config_s.type = 0; ii_int_config.sh_ii_int0_config_s.agt = 0; ii_int_config.sh_ii_int0_config_s.pid = cpu1; ii_int_config.sh_ii_int0_config_s.base = 0; HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_CONFIG), ii_int_config.sh_ii_int0_config_regval); // Enable interrupts for II_INT0 and 1. ii_int_enable.sh_ii_int0_enable_regval = 0; ii_int_enable.sh_ii_int0_enable_s.ii_enable = 1; HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_ENABLE), ii_int_enable.sh_ii_int0_enable_regval); HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_ENABLE), ii_int_enable.sh_ii_int0_enable_regval); if (!timer_added) { // can only init the timer once. timer_added = 1; sn_init_cpei_timer(); } }