Moved MSR read/write APIs out of devarch and into a dedicated file
authorDavide Libenzi <dlibenzi@google.com>
Tue, 24 Nov 2015 23:56:48 +0000 (15:56 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 16 Dec 2015 21:27:06 +0000 (16:27 -0500)
Moved MSR read/write APIs out of devarch and into a dedicated file.

Signed-off-by: Davide Libenzi <dlibenzi@google.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/Kbuild
kern/arch/x86/devarch.c
kern/arch/x86/devarch.h
kern/arch/x86/msr.c [new file with mode: 0644]
kern/arch/x86/msr.h [new file with mode: 0644]

index ae25726..8bb34b2 100644 (file)
@@ -14,6 +14,7 @@ obj-y                                         += kdebug.o
 obj-y                                          += mpacpi.o
 obj-y                                          += mp.o
 obj-y                                          += msi.o
+obj-y                                          += msr.o
 obj-y                                          += page_alloc.o
 obj-y                                          += pci.o
 obj-y                                          += pic.o
index 1c0aa21..be7def9 100644 (file)
 #include <smp.h>
 #include <ip.h>
 #include <time.h>
-#include <atomic.h>
 #include <core_set.h>
-#include <completion.h>
 #include <address_range.h>
 #include <arch/ros/msr-index.h>
-#include <arch/uaccess.h>
+#include <arch/msr.h>
 #include <arch/devarch.h>
 
 #define REAL_MEM_SIZE (1024 * 1024)
@@ -63,17 +61,6 @@ enum {
        Linelen = 31,
 };
 
-struct smp_read_values {
-       uint64_t *values;
-       uint32_t addr;
-       atomic_t err;
-};
-struct smp_write_values {
-       uint32_t addr;
-       uint64_t value;
-       atomic_t err;
-};
-
 struct dev archdevtab;
 static struct dirtab archdir[Qmax] = {
        {".", {Qdir, 0, QTDIR}, 0, 0555},
@@ -104,61 +91,6 @@ static const struct address_range msr_wr_wlist[] = {
 };
 int gdbactive = 0;
 
-static void cpu_read_msr(void *opaque)
-{
-       int err, cpu = core_id();
-       struct smp_read_values *srv = (struct smp_read_values *) opaque;
-
-       err = safe_read_msr(srv->addr, &srv->values[cpu]);
-       if (unlikely(err))
-               atomic_cas(&srv->err, 0, err);
-}
-
-uint64_t *coreset_read_msr(const struct core_set *cset, uint32_t addr,
-                                                  size_t *nvalues)
-{
-       int err;
-       struct smp_read_values srv;
-
-       srv.addr = addr;
-       atomic_init(&srv.err, 0);
-       srv.values = kzmalloc(num_cores * sizeof(*srv.values), 0);
-       if (unlikely(!srv.values))
-               return ERR_PTR(-ENOMEM);
-       smp_do_in_cores(cset, cpu_read_msr, &srv);
-       err = (int) atomic_read(&srv.err);
-       if (unlikely(err)) {
-               kfree(srv.values);
-               return ERR_PTR(err);
-       }
-       *nvalues = num_cores;
-
-       return srv.values;
-}
-
-static void cpu_write_msr(void *opaque)
-{
-       int err;
-       struct smp_write_values *swv = (struct smp_write_values *) opaque;
-
-       err = safe_write_msr(swv->addr, swv->value);
-       if (unlikely(err))
-               atomic_cas(&swv->err, 0, err);
-}
-
-int coreset_write_msr(const struct core_set *cset, uint32_t addr,
-                                          uint64_t value)
-{
-       struct smp_write_values swv;
-
-       swv.addr = addr;
-       swv.value = value;
-       atomic_init(&swv.err, 0);
-       smp_do_in_cores(cset, cpu_write_msr, &swv);
-
-       return (int) atomic_read(&swv.err);
-}
-
 //
 //  alloc some io port space and remember who it was
 //  alloced to.  if port < 0, find a free region.
@@ -430,7 +362,7 @@ static long archread(struct chan *c, void *a, long n, int64_t offset)
                                error(EPERM, NULL);
                        core_set_init(&cset);
                        core_set_fill_available(&cset);
-                       values = coreset_read_msr(&cset, (uint32_t) offset, &nvalues);
+                       values = msr_cores_read(&cset, (uint32_t) offset, &nvalues);
                        if (likely(!IS_ERR(values))) {
                                if (n >= nvalues * sizeof(uint64_t)) {
                                        if (memcpy_to_user_errno(current, a, values,
@@ -532,7 +464,7 @@ static long archwrite(struct chan *c, void *a, long n, int64_t offset)
                                error(EINVAL, NULL);
                        if (memcpy_from_user_errno(current, &value, a, sizeof(value)))
                                return -1;
-                       err = coreset_write_msr(&cset, (uint32_t) offset, value);
+                       err = msr_cores_write(&cset, (uint32_t) offset, value);
                        if (unlikely(err))
                                error(-err, NULL);
                        return sizeof(uint64_t);
index ffc94f7..9a58c67 100644 (file)
@@ -5,11 +5,9 @@
 
 #pragma once
 
-#include <sys/types.h>
-#include <stdio.h>
-#include <core_set.h>
-
-uint64_t *coreset_read_msr(const struct core_set *cset, uint32_t addr,
-                                                  size_t *nvalues);
-int coreset_write_msr(const struct core_set *cset, uint32_t addr,
-                                         uint64_t value);
+int ioalloc(int port, int size, int align, char *tag);
+void iofree(int port);
+int iounused(int start, int end);
+void ioinit(void);
+int ioreserve(int unused_int, int size, int align, char *tag);
+void archreset(void);
diff --git a/kern/arch/x86/msr.c b/kern/arch/x86/msr.c
new file mode 100644 (file)
index 0000000..33216a4
--- /dev/null
@@ -0,0 +1,127 @@
+/* Copyright (c) 2015 Google Inc
+ * Davide Libenzi <dlibenzi@google.com>
+ * See LICENSE for details.
+ */
+
+#include <ros/common.h>
+#include <compiler.h>
+#include <kmalloc.h>
+#include <kthread.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <pmap.h>
+#include <umem.h>
+#include <smp.h>
+#include <atomic.h>
+#include <core_set.h>
+#include <completion.h>
+#include <arch/uaccess.h>
+#include <arch/msr.h>
+
+struct smp_read_values {
+       const struct msr_address *msra;
+       struct msr_value *msrv;
+       atomic_t err;
+};
+
+struct smp_write_values {
+       const struct msr_address *msra;
+       const struct msr_value *msrv;
+       atomic_t err;
+};
+
+static void msr_smp_read(void *opaque)
+{
+       struct smp_read_values *srv = (struct smp_read_values *) opaque;
+       int err, coreno = core_id();
+       uint32_t addr;
+       uint64_t value;
+
+       err = msr_get_core_address(coreno, srv->msra, &addr);
+       if (likely(!err)) {
+               err = safe_read_msr(addr, &value);
+               if (likely(!err))
+                       err = msr_set_core_value(coreno, value, srv->msrv);
+       }
+       if (unlikely(err))
+               atomic_cas(&srv->err, 0, err);
+}
+
+int msr_cores_read(const struct core_set *cset, const struct msr_address *msra,
+                                  struct msr_value *msrv)
+{
+       int err;
+       struct smp_read_values srv;
+
+       ZERO_DATA(srv);
+       srv.msra = msra;
+       srv.msrv = msrv;
+       atomic_init(&srv.err, 0);
+       smp_do_in_cores(cset, msr_smp_read, &srv);
+
+       return (int) atomic_read(&srv.err);
+}
+
+int msr_core_read(unsigned int coreno, uint32_t addr, uint64_t *value)
+{
+       int err;
+       struct core_set cset;
+       struct msr_address msra;
+       struct msr_value msrv;
+
+       core_set_init(&cset);
+       core_set_setcpu(&cset, coreno);
+       msr_set_address(&msra, addr);
+       msr_set_values(&msrv, NULL, 0);
+       err = msr_cores_read(&cset, &msra, &msrv);
+       *value = msrv.value;
+
+       return err;
+}
+
+static void msr_smp_write(void *opaque)
+{
+       struct smp_write_values *swv = (struct smp_write_values *) opaque;
+       int err, coreno = core_id();
+       uint32_t addr;
+       uint64_t value;
+
+       err = msr_get_core_address(coreno, swv->msra, &addr);
+       if (likely(!err)) {
+               err = msr_get_core_value(coreno, swv->msrv, &value);
+               if (likely(!err))
+                       err = safe_write_msr(addr, value);
+       }
+       if (unlikely(err))
+               atomic_cas(&swv->err, 0, err);
+}
+
+int msr_cores_write(const struct core_set *cset, const struct msr_address *msra,
+                                       const struct msr_value *msrv)
+{
+       struct smp_write_values swv;
+
+       ZERO_DATA(swv);
+       swv.msra = msra;
+       swv.msrv = msrv;
+       atomic_init(&swv.err, 0);
+       smp_do_in_cores(cset, msr_smp_write, &swv);
+
+       return (int) atomic_read(&swv.err);
+}
+
+int msr_core_write(unsigned int coreno, uint32_t addr, uint64_t value)
+{
+       struct core_set cset;
+       struct msr_address msra;
+       struct msr_value msrv;
+
+       core_set_init(&cset);
+       core_set_setcpu(&cset, coreno);
+       msr_set_address(&msra, addr);
+       msr_set_value(&msrv, value);
+
+       return msr_cores_write(&cset, &msra, &msrv);
+}
diff --git a/kern/arch/x86/msr.h b/kern/arch/x86/msr.h
new file mode 100644 (file)
index 0000000..42f9af6
--- /dev/null
@@ -0,0 +1,116 @@
+/* Copyright (c) 2015 Google Inc
+ * Davide Libenzi <dlibenzi@google.com>
+ * See LICENSE for details.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+#include <ros/errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <core_set.h>
+
+/* The msr_address and msr_value structures allow to specify either a single
+ * address/value for all cores, or dedicated ones for every core.
+ * This allow a single logical call to msr_cores_read()/msr_cores_write() APIs,
+ * to read/write MSRs at different addresses and using different values.
+ */
+struct msr_address {
+       uint32_t addr;
+       const uint32_t *addresses;
+       size_t num_addresses;
+};
+
+struct msr_value {
+       uint64_t value;
+       uint64_t *values;
+       size_t num_values;
+};
+
+int msr_cores_read(const struct core_set *cset, const struct msr_address *msra,
+                                  struct msr_value *msrv);
+int msr_core_read(unsigned int core, uint32_t addr, uint64_t *value);
+int msr_cores_write(const struct core_set *cset, const struct msr_address *msra,
+                                       const struct msr_value *msrv);
+int msr_core_write(unsigned int core, uint32_t addr, uint64_t value);
+
+static inline void msr_set_address(struct msr_address *msra, uint32_t addr)
+{
+       ZERO_DATA(*msra);
+       msra->addr = addr;
+}
+
+static inline void msr_set_addresses(struct msr_address *msra,
+                                                                        const uint32_t *addresses,
+                                                                        size_t num_addresses)
+{
+       ZERO_DATA(*msra);
+       msra->addresses = addresses;
+       msra->num_addresses = num_addresses;
+}
+
+static inline int msr_get_core_address(unsigned int coreno,
+                                                                          const struct msr_address *msra,
+                                                                          uint32_t *paddr)
+{
+       if (msra->addresses != NULL) {
+               if (coreno >= (unsigned int) msra->num_addresses)
+                       return -ERANGE;
+
+               *paddr = msra->addresses[coreno];
+       } else {
+               *paddr = msra->addr;
+       }
+
+       return 0;
+}
+
+static inline void msr_set_value(struct msr_value *msrv, uint64_t value)
+{
+       ZERO_DATA(*msrv);
+       msrv->value = value;
+}
+
+static inline void msr_set_values(struct msr_value *msrv,
+                                                                 const uint64_t *values, size_t num_values)
+{
+       ZERO_DATA(*msrv);
+
+       /* Avoid supporting two APIs, one for setting const values, and one for
+        * setting the non const ones.
+        */
+       msrv->values = (uint64_t *) values;
+       msrv->num_values = num_values;
+}
+
+static inline int msr_set_core_value(unsigned int coreno, uint64_t value,
+                                                                        struct msr_value *msrv)
+{
+       if (msrv->values != NULL) {
+               if (coreno >= (unsigned int) msrv->num_values)
+                       return -ERANGE;
+
+               msrv->values[coreno] = value;
+       } else {
+               msrv->value = value;
+       }
+
+       return 0;
+}
+
+static inline int msr_get_core_value(unsigned int coreno,
+                                                                        const struct msr_value *msrv,
+                                                                        uint64_t *pvalue)
+{
+       if (msrv->values != NULL) {
+               if (coreno >= (unsigned int) msrv->num_values)
+                       return -ERANGE;
+
+               *pvalue = msrv->values[coreno];
+       } else {
+               *pvalue = msrv->value;
+       }
+
+       return 0;
+}