| /* 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 <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; | 
 | 	int err; | 
 | }; | 
 |  | 
 | struct smp_write_values { | 
 | 	const struct msr_address *msra; | 
 | 	const struct msr_value *msrv; | 
 | 	int 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 (err) | 
 | 		goto errout; | 
 | 	err = read_msr_safe(addr, &value); | 
 | 	if (err) | 
 | 		goto errout; | 
 | 	err = msr_set_core_value(coreno, value, srv->msrv); | 
 | 	if (err) | 
 | 		goto errout; | 
 |  | 
 | 	return; | 
 |  | 
 | errout: | 
 | 	srv->err = 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; | 
 | 	srv.err = 0; | 
 | 	smp_do_in_cores(cset, msr_smp_read, &srv); | 
 |  | 
 | 	return 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 (err) | 
 | 		goto errout; | 
 | 	err = msr_get_core_value(coreno, swv->msrv, &value); | 
 | 	if (err) | 
 | 		goto errout; | 
 | 	err = write_msr_safe(addr, value); | 
 | 	if (err) | 
 | 		goto errout; | 
 |  | 
 | 	return; | 
 |  | 
 | errout: | 
 | 	swv->err = 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; | 
 | 	swv.err = 0; | 
 | 	smp_do_in_cores(cset, msr_smp_write, &swv); | 
 |  | 
 | 	return 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); | 
 | } |