1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <ddk/binding.h>
6 #include <ddk/debug.h>
7 #include <ddk/device.h>
8 #include <ddk/platform-defs.h>
9 #include <ddk/protocol/platform/device.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 typedef struct cpu_trace_dev {
14     zx_device_t* zxdev;
15     zx_handle_t bti;
16 } cpu_trace_dev_t;
17 
18 static const pdev_device_info_t cpu_trace_pdev_device_info = {
19     .vid = PDEV_VID_INTEL,
20     .pid = PDEV_PID_GENERIC,
21     .did = PDEV_DID_INTEL_CPU_TRACE,
22     .bti_count = 1,
23 };
24 
cpu_trace_get_bti(void * ctx,uint32_t index,zx_handle_t * out_handle)25 static zx_status_t cpu_trace_get_bti(void* ctx, uint32_t index, zx_handle_t* out_handle) {
26     cpu_trace_dev_t* dev = ctx;
27     if (index >= cpu_trace_pdev_device_info.bti_count || out_handle == NULL) {
28         return ZX_ERR_INVALID_ARGS;
29     }
30     return zx_handle_duplicate(dev->bti, ZX_RIGHT_SAME_RIGHTS, out_handle);
31 }
32 
cpu_trace_get_device_info(void * ctx,pdev_device_info_t * out_info)33 static zx_status_t cpu_trace_get_device_info(void* ctx, pdev_device_info_t* out_info) {
34     memcpy(out_info, &cpu_trace_pdev_device_info, sizeof(*out_info));
35     return ZX_OK;
36 }
37 
cpu_trace_get_mmio(void * ctx,uint32_t index,pdev_mmio_t * mmio)38 static zx_status_t cpu_trace_get_mmio(void* ctx, uint32_t index, pdev_mmio_t* mmio) {
39     return ZX_ERR_NOT_SUPPORTED;
40 }
41 
cpu_trace_get_interrupt(void * ctx,uint32_t index,uint32_t flags,zx_handle_t * out_handle)42 static zx_status_t cpu_trace_get_interrupt(void* ctx, uint32_t index, uint32_t flags, zx_handle_t* out_handle) {
43     return ZX_ERR_NOT_SUPPORTED;
44 }
45 
46 static pdev_protocol_ops_t cpu_trace_proto_ops = {
47     .get_mmio = cpu_trace_get_mmio,
48     .get_interrupt = cpu_trace_get_interrupt,
49     .get_bti = cpu_trace_get_bti,
50     .get_device_info = cpu_trace_get_device_info,
51 };
52 
53 
cpu_trace_release(void * ctx)54 static void cpu_trace_release(void* ctx) {
55     cpu_trace_dev_t* dev = ctx;
56     zx_handle_close(dev->bti);
57     free(dev);
58 }
59 
60 static zx_protocol_device_t cpu_trace_dev_proto = {
61     .version = DEVICE_OPS_VERSION,
62     .release = cpu_trace_release,
63 };
64 
publish_cpu_trace(zx_handle_t bti,zx_device_t * sys_root)65 zx_status_t publish_cpu_trace(zx_handle_t bti, zx_device_t* sys_root) {
66     cpu_trace_dev_t* dev = calloc(1, sizeof(*dev));
67     if (dev == NULL) {
68         return ZX_ERR_NO_MEMORY;
69     }
70     dev->bti = bti;
71 
72     zx_device_prop_t props[] = {
73         {BIND_PLATFORM_DEV_VID, 0, cpu_trace_pdev_device_info.vid},
74         {BIND_PLATFORM_DEV_PID, 0, cpu_trace_pdev_device_info.pid},
75         {BIND_PLATFORM_DEV_DID, 0, cpu_trace_pdev_device_info.did},
76     };
77     device_add_args_t args = {
78         .version = DEVICE_ADD_ARGS_VERSION,
79         .name = "cpu-trace",
80         .ctx = dev,
81         .ops = &cpu_trace_dev_proto,
82         .proto_id = ZX_PROTOCOL_PDEV,
83         .proto_ops = &cpu_trace_proto_ops,
84         .props = props,
85         .prop_count = countof(props),
86         .proxy_args = NULL,
87         .flags = 0,
88     };
89 
90     // add as a child of the sysroot
91     zx_status_t status = device_add(sys_root, &args, &dev->zxdev);
92     if (status != ZX_OK) {
93         zxlogf(ERROR, "acpi-bus: error %d in device_add(sys/cpu-trace)\n", status);
94         cpu_trace_release(dev);
95         return status;
96     }
97 
98     return ZX_OK;
99 }
100