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