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/protocol/platform-defs.h>
9#include <ddk/protocol/platform-device.h>
10#include <stdlib.h>
11#include <string.h>
12
13typedef struct cpu_trace_dev {
14    zx_device_t* zxdev;
15    zx_handle_t bti;
16} cpu_trace_dev_t;
17
18static 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
25static 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
33static 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
38static zx_status_t cpu_trace_map_mmio(void* ctx, uint32_t index, uint32_t cache_policy, void** out_vaddr,
39                                      size_t* out_size, zx_paddr_t* out_paddr, zx_handle_t* out_handle) {
40    return ZX_ERR_NOT_SUPPORTED;
41}
42
43static zx_status_t cpu_trace_map_interrupt(void* ctx, uint32_t index, uint32_t flags, zx_handle_t* out_handle) {
44    return ZX_ERR_NOT_SUPPORTED;
45}
46
47static platform_device_protocol_ops_t cpu_trace_proto_ops = {
48    .map_mmio = cpu_trace_map_mmio,
49    .map_interrupt = cpu_trace_map_interrupt,
50    .get_bti = cpu_trace_get_bti,
51    .get_device_info = cpu_trace_get_device_info,
52};
53
54
55static void cpu_trace_release(void* ctx) {
56    cpu_trace_dev_t* dev = ctx;
57    zx_handle_close(dev->bti);
58    free(dev);
59}
60
61static zx_protocol_device_t cpu_trace_dev_proto = {
62    .version = DEVICE_OPS_VERSION,
63    .release = cpu_trace_release,
64};
65
66zx_status_t publish_cpu_trace(zx_handle_t bti, zx_device_t* sys_root) {
67    cpu_trace_dev_t* dev = calloc(1, sizeof(*dev));
68    if (dev == NULL) {
69        return ZX_ERR_NO_MEMORY;
70    }
71    dev->bti = bti;
72
73    zx_device_prop_t props[] = {
74        {BIND_PLATFORM_DEV_VID, 0, cpu_trace_pdev_device_info.vid},
75        {BIND_PLATFORM_DEV_PID, 0, cpu_trace_pdev_device_info.pid},
76        {BIND_PLATFORM_DEV_DID, 0, cpu_trace_pdev_device_info.did},
77    };
78    device_add_args_t args = {
79        .version = DEVICE_ADD_ARGS_VERSION,
80        .name = "cpu-trace",
81        .ctx = dev,
82        .ops = &cpu_trace_dev_proto,
83        .proto_id = ZX_PROTOCOL_PLATFORM_DEV,
84        .proto_ops = &cpu_trace_proto_ops,
85        .props = props,
86        .prop_count = countof(props),
87        .proxy_args = NULL,
88        .flags = 0,
89    };
90
91    // add as a child of the sysroot
92    zx_status_t status = device_add(sys_root, &args, &dev->zxdev);
93    if (status != ZX_OK) {
94        zxlogf(ERROR, "acpi-bus: error %d in device_add(sys/cpu-trace)\n", status);
95        cpu_trace_release(dev);
96        return status;
97    }
98
99    return ZX_OK;
100}
101