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
ecache_scan_dir(const char * dir,const char * pref,char * buf,size_t bufsz)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
ecache_find_device(char * buf,size_t bufsz)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
cmd_ecache_init(void)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
cmd_ecache_flush(int cpuid)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