1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * E-cache flushing 31 * 32 * Prior to clearing the UE cache, the CPU state code needs to ensure that the 33 * CPU's E-cache has been flushed. The flushing is handled by the routines in 34 * in this file, which use the memory controller (mc) driver to perform the 35 * flush. 36 * 37 * Matters are complicated by the fact that there isn't a well-known device name 38 * for driver access - we have to hunt around for one. Furthermore, the minor 39 * nodes that are created correspond to individual memory controllers, and as 40 * such can change during a DR. We'll search for a memory controller device 41 * during initialization just to make sure that we can do E$ flushing on this 42 * platform, but we're also able to rescan if the device we found suddenly 43 * disappears. 44 */ 45 46 #include <cmd_ecache.h> 47 #include <cmd.h> 48 49 #include <string.h> 50 #include <fcntl.h> 51 #include <unistd.h> 52 #include <errno.h> 53 #include <dirent.h> 54 #include <fm/fmd_api.h> 55 #include <sys/mc.h> 56 #include <sys/param.h> 57 58 static int 59 ecache_scan_dir(const char *dir, const char *pref, char *buf, size_t bufsz) 60 { 61 struct dirent *dp; 62 char path[MAXPATHLEN]; 63 DIR *mcdir; 64 65 if ((mcdir = opendir(dir)) == NULL) 66 return (-1); /* errno is set for us */ 67 68 while ((dp = readdir(mcdir)) != NULL) { 69 struct mc_ctrlconf mcc; 70 int fd; 71 72 if (strncmp(dp->d_name, pref, strlen(pref)) != 0) 73 continue; 74 75 (void) snprintf(path, sizeof (path), "%s/%s", dir, dp->d_name); 76 77 if ((fd = open(path, O_RDONLY)) < 0) 78 continue; 79 80 mcc.nmcs = 0; 81 if (ioctl(fd, MCIOC_CTRLCONF, &mcc) >= 0 || errno != EINVAL || 82 mcc.nmcs == 0) { 83 (void) close(fd); 84 continue; 85 } 86 87 (void) close(fd); 88 (void) closedir(mcdir); 89 90 if (strlen(path) >= bufsz) 91 return (cmd_set_errno(ENOSPC)); 92 (void) strcpy(buf, path); 93 return (0); 94 } 95 96 (void) closedir(mcdir); 97 return (cmd_set_errno(ENOENT)); 98 } 99 100 static int 101 ecache_find_device(char *buf, size_t bufsz) 102 { 103 if (ecache_scan_dir("/dev/mc", "mc", buf, bufsz) != 0) { 104 /* 105 * Yet more platform-specific hackery. It's possible that the 106 * /dev/mc links could be out of date, and thus we may not be 107 * able to use any of them. As a fallback, therefore, we're 108 * going to search a couple of well-known locations in /devices. 109 */ 110 const char *dir = "/devices/ssm@0,0"; 111 112 if (access(dir, R_OK) != 0) 113 dir = "/devices"; 114 115 return (ecache_scan_dir(dir, "memory-controller", buf, bufsz)); 116 } 117 118 return (0); 119 } 120 121 int 122 cmd_ecache_init(void) 123 { 124 return (ecache_find_device(cmd.cmd_ecache_dev, 125 sizeof (cmd.cmd_ecache_dev))); 126 } 127 128 int 129 cmd_ecache_flush(int cpuid) 130 { 131 int fd; 132 133 if ((fd = open(cmd.cmd_ecache_dev, O_RDONLY)) < 0) { 134 if (errno != ENOENT) 135 return (-1); /* errno is set for us */ 136 137 /* 138 * A DR may have occurred, thus rendering our path invalid. 139 * Try once to find another one. 140 */ 141 if (cmd_ecache_init() < 0 || 142 (fd = open(cmd.cmd_ecache_dev, O_RDONLY)) < 0) 143 return (-1); /* errno is set for us */ 144 } 145 146 if (ioctl(fd, MCIOC_ECFLUSH, cpuid) < 0) { 147 int oserr = errno; 148 (void) close(fd); 149 return (cmd_set_errno(oserr)); 150 } 151 152 (void) close(fd); 153 return (0); 154 } 155