1/*
2 * Copyright (c) 2008 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *
22 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
23 * contributors may be used to endorse or promote products derived from this
24 * software without specific prior written permission.
25 */
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <stdio.h>
32#include <unistd.h>
33#include <fcntl.h>
34#include <sys/types.h>
35#include <errno.h>
36
37#ifdef __OpenBSD__
38#include <sys/ioctl.h>
39#include <machine/amdmsr.h>
40#endif
41
42#ifdef __FreeBSD__
43#include <sys/ioctl.h>
44#include <sys/cpuctl.h>
45#endif
46
47#include "xorg-server.h"
48
49#include "os.h"
50#include "geode.h"
51
52#ifdef __OpenBSD__
53#define _PATH_MSRDEV	"/dev/amdmsr"
54#define X_PRIVSEP
55#elif defined __FreeBSD__
56#define _PATH_MSRDEV	"/dev/cpuctl0"
57#else
58#define _PATH_MSRDEV	"/dev/cpu/0/msr"
59#endif
60
61static int
62_msr_open(void)
63{
64    static int msrfd = 0;
65
66    if (msrfd == 0) {
67#ifdef X_PRIVSEP
68        msrfd = priv_open_device(_PATH_MSRDEV);
69#else
70        msrfd = open(_PATH_MSRDEV, O_RDWR);
71#endif
72        if (msrfd == -1)
73            FatalError("Unable to open %s: %s\n", _PATH_MSRDEV,
74                strerror(errno));
75    }
76
77    return msrfd;
78}
79
80int
81GeodeReadMSR(unsigned long addr, unsigned long *lo, unsigned long *hi)
82{
83#ifdef __OpenBSD__
84    struct amdmsr_req req;
85    int fd = _msr_open();
86
87    req.addr = addr;
88
89    if (ioctl(fd, RDMSR, &req) == -1)
90	FatalError("Unable to read MSR at address %0x06x: %s\n", addr,
91	    strerror(errno));
92
93    *hi = req.val >> 32;
94    *lo = req.val & 0xffffffff;
95#elif defined __FreeBSD__
96    cpuctl_msr_args_t args;
97    int fd = _msr_open();
98
99    args.msr = addr;
100
101    if (ioctl(fd, CPUCTL_RDMSR, &args) == -1)
102	FatalError("Unable to read MSR at address %0x06x: %s\n", addr,
103	    strerror(errno));
104
105    *hi = args.data >> 32;
106    *lo = args.data & 0xffffffff;
107#elif defined __NetBSD__
108    return -1;		/* fall back to assembly on NetBSD */
109#else
110    unsigned int data[2];
111    int fd = _msr_open();
112    int ret;
113
114    if (fd == -1)
115        return -1;
116
117    ret = lseek(fd, (off_t) addr, SEEK_SET);
118
119    if (ret == -1)
120        return -1;
121
122    ret = read(fd, (void *) data, sizeof(data));
123
124    if (ret != 8)
125        return -1;
126
127    *hi = data[1];
128    *lo = data[0];
129#endif
130    return 0;
131}
132
133int
134GeodeWriteMSR(unsigned long addr, unsigned long lo, unsigned long hi)
135{
136#ifdef __OpenBSD__
137    struct amdmsr_req req;
138    int fd = _msr_open();
139
140    req.addr = addr;
141    req.val = (u_int64_t) hi << 32 | (u_int64_t)lo;
142
143    if (ioctl(fd, WRMSR, &req) == -1)
144        FatalError("Unable to write MSR at address 0x%06x: %s\n", addr,
145            strerror(errno));
146#elif defined __FreeBSD__
147    cpuctl_msr_args_t args;
148    int fd = _msr_open();
149
150    args.msr = addr;
151    args.data = (u_int64_t) hi << 32 | (u_int64_t)lo;
152
153    if (ioctl(fd, CPUCTL_WRMSR, &args) == -1)
154        FatalError("Unable to write MSR at address 0x%06x: %s\n", addr,
155            strerror(errno));
156#elif defined __NetBSD__
157    return -1;		/* fall back to assembly on NetBSD */
158#else
159    unsigned int data[2];
160    int fd = _msr_open();
161
162    if (fd == -1)
163        return -1;
164
165    if (lseek(fd, (off_t) addr, SEEK_SET) == -1)
166        return -1;
167
168    data[0] = lo;
169    data[1] = hi;
170
171    if (write(fd, (void *) data, 8) != 8)
172        return -1;
173#endif
174    return 0;
175}
176