/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SHUB_NUM_ECF_REGISTERS 8 static uint32_t shub_perf_counts[SHUB_NUM_ECF_REGISTERS]; static shubreg_t shub_perf_counts_regs[SHUB_NUM_ECF_REGISTERS] = { SH_PERFORMANCE_COUNTER0, SH_PERFORMANCE_COUNTER1, SH_PERFORMANCE_COUNTER2, SH_PERFORMANCE_COUNTER3, SH_PERFORMANCE_COUNTER4, SH_PERFORMANCE_COUNTER5, SH_PERFORMANCE_COUNTER6, SH_PERFORMANCE_COUNTER7 }; static inline void shub_mmr_write(cnodeid_t cnode, shubreg_t reg, uint64_t val) { int nasid = cnodeid_to_nasid(cnode); volatile uint64_t *addr = (uint64_t *)(GLOBAL_MMR_ADDR(nasid, reg)); *addr = val; __ia64_mf_a(); } static inline void shub_mmr_write_iospace(cnodeid_t cnode, shubreg_t reg, uint64_t val) { int nasid = cnodeid_to_nasid(cnode); REMOTE_HUB_S(nasid, reg, val); } static inline void shub_mmr_write32(cnodeid_t cnode, shubreg_t reg, uint32_t val) { int nasid = cnodeid_to_nasid(cnode); volatile uint32_t *addr = (uint32_t *)(GLOBAL_MMR_ADDR(nasid, reg)); *addr = val; __ia64_mf_a(); } static inline uint64_t shub_mmr_read(cnodeid_t cnode, shubreg_t reg) { int nasid = cnodeid_to_nasid(cnode); volatile uint64_t val; val = *(uint64_t *)(GLOBAL_MMR_ADDR(nasid, reg)); __ia64_mf_a(); return val; } static inline uint64_t shub_mmr_read_iospace(cnodeid_t cnode, shubreg_t reg) { int nasid = cnodeid_to_nasid(cnode); return REMOTE_HUB_L(nasid, reg); } static inline uint32_t shub_mmr_read32(cnodeid_t cnode, shubreg_t reg) { int nasid = cnodeid_to_nasid(cnode); volatile uint32_t val; val = *(uint32_t *)(GLOBAL_MMR_ADDR(nasid, reg)); __ia64_mf_a(); return val; } static int reset_shub_stats(cnodeid_t cnode) { int i; for (i=0; i < SHUB_NUM_ECF_REGISTERS; i++) { shub_perf_counts[i] = 0; shub_mmr_write32(cnode, shub_perf_counts_regs[i], 0); } return 0; } static int configure_shub_stats(cnodeid_t cnode, unsigned long arg) { uint64_t *p = (uint64_t *)arg; uint64_t i; uint64_t regcnt; uint64_t regval[2]; if (copy_from_user((void *)®cnt, p, sizeof(regcnt))) return -EFAULT; for (p++, i=0; i < regcnt; i++, p += 2) { if (copy_from_user((void *)regval, (void *)p, sizeof(regval))) return -EFAULT; if (regval[0] & 0x7) { printk("Error: configure_shub_stats: unaligned address 0x%016lx\n", regval[0]); return -EINVAL; } shub_mmr_write(cnode, (shubreg_t)regval[0], regval[1]); } return 0; } static int capture_shub_stats(cnodeid_t cnode, uint32_t *counts) { int i; for (i=0; i < SHUB_NUM_ECF_REGISTERS; i++) { counts[i] = shub_mmr_read32(cnode, shub_perf_counts_regs[i]); } return 0; } static int shubstats_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { cnodeid_t cnode; uint64_t longarg; uint64_t intarg; uint64_t regval[2]; int nasid; cnode = (cnodeid_t)(u64)file->f_dentry->d_fsdata; if (cnode < 0 || cnode >= numnodes) return -ENODEV; switch (cmd) { case SNDRV_SHUB_CONFIGURE: return configure_shub_stats(cnode, arg); break; case SNDRV_SHUB_RESETSTATS: reset_shub_stats(cnode); break; case SNDRV_SHUB_INFOSIZE: longarg = sizeof(shub_perf_counts); if (copy_to_user((void *)arg, &longarg, sizeof(longarg))) { return -EFAULT; } break; case SNDRV_SHUB_GETSTATS: capture_shub_stats(cnode, shub_perf_counts); if (copy_to_user((void *)arg, shub_perf_counts, sizeof(shub_perf_counts))) { return -EFAULT; } break; case SNDRV_SHUB_GETNASID: nasid = cnodeid_to_nasid(cnode); if (copy_to_user((void *)arg, &nasid, sizeof(nasid))) { return -EFAULT; } break; case SNDRV_SHUB_GETMMR32: intarg = shub_mmr_read32(cnode, arg); if (copy_to_user((void *)arg, &intarg, sizeof(intarg))) { return -EFAULT; } break; case SNDRV_SHUB_GETMMR64: case SNDRV_SHUB_GETMMR64_IO: if (cmd == SNDRV_SHUB_GETMMR64) longarg = shub_mmr_read(cnode, arg); else longarg = shub_mmr_read_iospace(cnode, arg); if (copy_to_user((void *)arg, &longarg, sizeof(longarg))) return -EFAULT; break; case SNDRV_SHUB_PUTMMR64: case SNDRV_SHUB_PUTMMR64_IO: if (copy_from_user((void *)regval, (void *)arg, sizeof(regval))) return -EFAULT; if (regval[0] & 0x7) { printk("Error: configure_shub_stats: unaligned address 0x%016lx\n", regval[0]); return -EINVAL; } if (cmd == SNDRV_SHUB_PUTMMR64) shub_mmr_write(cnode, (shubreg_t)regval[0], regval[1]); else shub_mmr_write_iospace(cnode, (shubreg_t)regval[0], regval[1]); break; default: return -EINVAL; } return 0; } struct file_operations shub_mon_fops = { .ioctl = shubstats_ioctl, };