1 /*
2  * Copyright (C) 2018-2022 Intel Corporation.
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 #include <types.h>
7 #include <asm/lib/atomic.h>
8 #include <acrn_hv_defs.h>
9 #include <asm/io.h>
10 #include <asm/per_cpu.h>
11 #include <asm/mmu.h>
12 #include <logmsg.h>
13 #include <npk_log.h>
14 
15 static int32_t npk_log_setup_ref;
16 static bool npk_log_enabled;
17 static uint64_t base;
18 
19 #define HV_NPK_LOG_REF_SHIFT  2U
20 #define HV_NPK_LOG_REF_MASK   ((1U << HV_NPK_LOG_REF_SHIFT) - 1U)
21 
22 #define HV_NPK_LOG_MAX 1024U
23 #define HV_NPK_LOG_HDR 0x01000242U
24 
25 enum {
26 	HV_NPK_LOG_CMD_INVALID = 0U,
27 	HV_NPK_LOG_CMD_CONF,
28 	HV_NPK_LOG_CMD_ENABLE,
29 	HV_NPK_LOG_CMD_DISABLE,
30 	HV_NPK_LOG_CMD_QUERY,
31 };
32 
33 #define	HV_NPK_LOG_RES_INVALID	0x0U
34 #define	HV_NPK_LOG_RES_OK	0x1U
35 #define	HV_NPK_LOG_RES_KO	0x2U
36 #define	HV_NPK_LOG_RES_ENABLED	0x3U
37 #define	HV_NPK_LOG_RES_DISABLED	0x4U
38 
39 struct npk_chan {
40 	uint64_t Dn;
41 	uint64_t DnM;
42 	uint64_t DnTS;
43 	uint64_t DnMTS;
44 	uint64_t USER;
45 	uint64_t USER_TS;
46 	uint32_t FLAG;
47 	uint32_t FLAG_TS;
48 	uint32_t MERR;
49 	uint32_t unused;
50 } __packed;
51 
npk_write(const char * value,void * addr,size_t sz)52 static inline int32_t npk_write(const char *value, void *addr, size_t sz)
53 {
54 	int32_t ret = -1;
55 
56 	if (sz >= 8U) {
57 		mmio_write64(*(uint64_t *)value, addr);
58 		ret = 8;
59 	} else if (sz >= 4U) {
60 		mmio_write32(*(uint32_t *)value, addr);
61 		ret = 4;
62 	} else if (sz >= 2U) {
63 		mmio_write16(*(uint16_t *)value, addr);
64 		ret = 2;
65 	} else if (sz >= 1U) {
66 		mmio_write8(*(uint8_t *)value, addr);
67 		ret = 1;
68 	} else {
69 		/* No other state currently, do nothing */
70 	}
71 
72 	return ret;
73 }
74 
npk_log_setup(struct hv_npk_log_param * param)75 void npk_log_setup(struct hv_npk_log_param *param)
76 {
77 	uint16_t i;
78 	uint16_t pcpu_nums;
79 
80 	pr_info("HV_NPK_LOG: cmd %d param 0x%lx\n", param->cmd,
81 			param->mmio_addr);
82 
83 	param->res = HV_NPK_LOG_RES_KO;
84 	if (atomic_inc_return(&npk_log_setup_ref) > 1) {
85 		goto out;
86 	}
87 
88 	switch (param->cmd) {
89 	case HV_NPK_LOG_CMD_CONF:
90 		if ((param->mmio_addr != 0UL) || (param->loglevel != 0xffffU)) {
91 			param->res = HV_NPK_LOG_RES_OK;
92 		}
93 		/* falls through */
94 	case HV_NPK_LOG_CMD_ENABLE:
95 		if (param->mmio_addr != 0UL) {
96 			base = param->mmio_addr;
97 		}
98 		if (param->loglevel != 0xffffU) {
99 			npk_loglevel = param->loglevel;
100 		}
101 		if ((base != 0UL) && (param->cmd == HV_NPK_LOG_CMD_ENABLE)) {
102 			if (!npk_log_enabled) {
103 				pcpu_nums = get_pcpu_nums();
104 				for (i = 0U; i < pcpu_nums; i++) {
105 					per_cpu(npk_log_ref, i) = 0U;
106 				}
107 				set_paging_supervisor(base,
108 					pcpu_nums * (HV_NPK_LOG_REF_MASK + 1U)
109 					* sizeof(struct npk_chan));
110 			}
111 			param->res = HV_NPK_LOG_RES_OK;
112 			npk_log_enabled = 1;
113 		}
114 		break;
115 	case HV_NPK_LOG_CMD_DISABLE:
116 		npk_log_enabled = 0;
117 		param->res = HV_NPK_LOG_RES_OK;
118 		break;
119 	case HV_NPK_LOG_CMD_QUERY:
120 		param->res = npk_log_enabled ? HV_NPK_LOG_RES_ENABLED :
121 			HV_NPK_LOG_RES_DISABLED;
122 		param->loglevel = npk_loglevel;
123 		param->mmio_addr = base;
124 		break;
125 	default:
126 		pr_err("HV_NPK_LOG: unknown cmd (%d)\n", param->cmd);
127 		break;
128 	}
129 
130 out:
131 	pr_info("HV_NPK_LOG: result %d\n", param->res);
132 	atomic_dec32((uint32_t *)&npk_log_setup_ref);
133 }
134 
npk_log_write(const char * buf,size_t buf_len)135 void npk_log_write(const char *buf, size_t buf_len)
136 {
137 	uint32_t cpu_id = get_pcpu_id();
138 	struct npk_chan *channel = (struct npk_chan *)base;
139 	const char *p = buf;
140 	int32_t sz;
141 	uint32_t ref;
142 	uint16_t len;
143 
144 	if (!npk_log_enabled || (channel == NULL)) {
145 		return;
146 	}
147 
148 	/* calculate the channel offset based on cpu_id and npk_log_ref */
149 	ref = (atomic_inc_return((int32_t *)&per_cpu(npk_log_ref, cpu_id)) - 1)
150 		& HV_NPK_LOG_REF_MASK;
151 	channel += (cpu_id << HV_NPK_LOG_REF_SHIFT) + ref;
152 	len = (uint16_t)(min(buf_len, HV_NPK_LOG_MAX));
153 	mmio_write32(HV_NPK_LOG_HDR, &(channel->DnTS));
154 	mmio_write16(len, &(channel->Dn));
155 
156 	for (sz = 0; sz >= 0; p += sz)
157 		sz = npk_write(p, &(channel->Dn), buf + len - p);
158 
159 	mmio_write8(0U, &(channel->FLAG));
160 
161 	atomic_dec32(&per_cpu(npk_log_ref, cpu_id));
162 }
163