Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /*
3 : : * OPAL Message queue between host and skiboot
4 : : *
5 : : * Copyright 2013-2019 IBM Corp.
6 : : */
7 : :
8 : : #define pr_fmt(fmt) "opalmsg: " fmt
9 : : #include <skiboot.h>
10 : : #include <opal-msg.h>
11 : : #include <opal-api.h>
12 : : #include <lock.h>
13 : :
14 : : #define OPAL_MAX_MSGS (OPAL_MSG_TYPE_MAX + OPAL_MAX_ASYNC_COMP - 1)
15 : :
16 : : struct opal_msg_entry {
17 : : struct list_node link;
18 : : void (*consumed)(void *data, int status);
19 : : bool extended;
20 : : void *data;
21 : : struct opal_msg msg;
22 : : };
23 : :
24 : : static LIST_HEAD(msg_free_list);
25 : : static LIST_HEAD(msg_pending_list);
26 : :
27 : : static struct lock opal_msg_lock = LOCK_UNLOCKED;
28 : :
29 : 41 : int _opal_queue_msg(enum opal_msg_type msg_type, void *data,
30 : : void (*consumed)(void *data, int status),
31 : : size_t params_size, const void *params)
32 : : {
33 : : struct opal_msg_entry *entry;
34 : : uint64_t entry_size;
35 : :
36 : 41 : if ((params_size + OPAL_MSG_HDR_SIZE) > OPAL_MSG_SIZE) {
37 : 1 : prlog(PR_DEBUG, "param_size (0x%x) > opal_msg param size (0x%x)\n",
38 : : (u32)params_size, (u32)(OPAL_MSG_SIZE - OPAL_MSG_HDR_SIZE));
39 : 1 : return OPAL_PARAMETER;
40 : : }
41 : :
42 : 40 : lock(&opal_msg_lock);
43 : :
44 : 40 : if (params_size > OPAL_MSG_FIXED_PARAMS_SIZE) {
45 : 2 : entry_size = sizeof(struct opal_msg_entry) + params_size;
46 : 2 : entry_size -= OPAL_MSG_FIXED_PARAMS_SIZE;
47 : 2 : entry = zalloc(entry_size);
48 : 2 : if (entry)
49 : 2 : entry->extended = true;
50 : : } else {
51 : 38 : entry = list_pop(&msg_free_list, struct opal_msg_entry, link);
52 : 38 : if (!entry) {
53 : 2 : prerror("No available node in the free list, allocating\n");
54 : 2 : entry = zalloc(sizeof(struct opal_msg_entry));
55 : : }
56 : : }
57 : 40 : if (!entry) {
58 : 1 : prerror("Allocation failed\n");
59 : 1 : unlock(&opal_msg_lock);
60 : 1 : return OPAL_RESOURCE;
61 : : }
62 : :
63 : 39 : entry->consumed = consumed;
64 : 39 : entry->data = data;
65 : 39 : entry->msg.msg_type = cpu_to_be32(msg_type);
66 : 39 : entry->msg.size = cpu_to_be32(params_size);
67 : 39 : memcpy(entry->msg.params, params, params_size);
68 : :
69 : 39 : list_add_tail(&msg_pending_list, &entry->link);
70 : 39 : opal_update_pending_evt(OPAL_EVENT_MSG_PENDING,
71 : : OPAL_EVENT_MSG_PENDING);
72 : 39 : unlock(&opal_msg_lock);
73 : :
74 : 39 : return OPAL_SUCCESS;
75 : : }
76 : :
77 : 42 : static int64_t opal_get_msg(uint64_t *buffer, uint64_t size)
78 : : {
79 : : struct opal_msg_entry *entry;
80 : : void (*callback)(void *data, int status);
81 : : void *data;
82 : : uint64_t msg_size;
83 : 42 : int rc = OPAL_SUCCESS;
84 : :
85 : 42 : if (size < sizeof(struct opal_msg) || !buffer)
86 : 2 : return OPAL_PARAMETER;
87 : :
88 : 40 : if (!opal_addr_valid(buffer))
89 : 0 : return OPAL_PARAMETER;
90 : :
91 : 40 : lock(&opal_msg_lock);
92 : :
93 : 40 : entry = list_pop(&msg_pending_list, struct opal_msg_entry, link);
94 : 40 : if (!entry) {
95 : 1 : unlock(&opal_msg_lock);
96 : 1 : return OPAL_RESOURCE;
97 : : }
98 : :
99 : 39 : msg_size = OPAL_MSG_HDR_SIZE + be32_to_cpu(entry->msg.size);
100 : 39 : if (size < msg_size) {
101 : : /* Send partial data to Linux */
102 : 2 : prlog(PR_NOTICE, "Sending partial data [msg_type : 0x%x, "
103 : : "msg_size : 0x%x, buf_size : 0x%x]\n",
104 : : be32_to_cpu(entry->msg.msg_type),
105 : : (u32)msg_size, (u32)size);
106 : :
107 : 2 : entry->msg.size = cpu_to_be32(size - OPAL_MSG_HDR_SIZE);
108 : 2 : msg_size = size;
109 : 2 : rc = OPAL_PARTIAL;
110 : : }
111 : :
112 : 39 : memcpy((void *)buffer, (void *)&entry->msg, msg_size);
113 : 39 : callback = entry->consumed;
114 : 39 : data = entry->data;
115 : :
116 : 39 : if (entry->extended)
117 : 2 : free(entry);
118 : : else
119 : 37 : list_add(&msg_free_list, &entry->link);
120 : :
121 : 39 : if (list_empty(&msg_pending_list))
122 : 15 : opal_update_pending_evt(OPAL_EVENT_MSG_PENDING, 0);
123 : :
124 : 39 : unlock(&opal_msg_lock);
125 : :
126 : 39 : if (callback)
127 : 2 : callback(data, rc);
128 : :
129 : 39 : return rc;
130 : : }
131 : : opal_call(OPAL_GET_MSG, opal_get_msg, 2);
132 : :
133 : 0 : static int64_t opal_check_completion(uint64_t *buffer, uint64_t size,
134 : : uint64_t token)
135 : : {
136 : : struct opal_msg_entry *entry, *next_entry;
137 : 0 : void (*callback)(void *data, int status) = NULL;
138 : 0 : int rc = OPAL_BUSY;
139 : 0 : void *data = NULL;
140 : :
141 : 0 : if (!opal_addr_valid(buffer))
142 : 0 : return OPAL_PARAMETER;
143 : :
144 : 0 : lock(&opal_msg_lock);
145 : 0 : list_for_each_safe(&msg_pending_list, entry, next_entry, link) {
146 : 0 : if (be32_to_cpu(entry->msg.msg_type) == OPAL_MSG_ASYNC_COMP &&
147 : 0 : be64_to_cpu(entry->msg.params[0]) == token) {
148 : 0 : list_del(&entry->link);
149 : 0 : callback = entry->consumed;
150 : 0 : data = entry->data;
151 : 0 : list_add(&msg_free_list, &entry->link);
152 : 0 : if (list_empty(&msg_pending_list))
153 : 0 : opal_update_pending_evt(OPAL_EVENT_MSG_PENDING,
154 : : 0);
155 : 0 : rc = OPAL_SUCCESS;
156 : 0 : break;
157 : : }
158 : : }
159 : :
160 : 0 : if (rc == OPAL_SUCCESS && size >= sizeof(struct opal_msg))
161 : 0 : memcpy(buffer, &entry->msg, sizeof(entry->msg));
162 : :
163 : 0 : unlock(&opal_msg_lock);
164 : :
165 : 0 : if (callback)
166 : 0 : callback(data, OPAL_SUCCESS);
167 : :
168 : 0 : return rc;
169 : :
170 : : }
171 : : opal_call(OPAL_CHECK_ASYNC_COMPLETION, opal_check_completion, 3);
172 : :
173 : 2 : void opal_init_msg(void)
174 : : {
175 : : struct opal_msg_entry *entry;
176 : : int i;
177 : :
178 : 29 : for (i = 0; i < OPAL_MAX_MSGS; i++, entry++) {
179 : 28 : entry = zalloc(sizeof(*entry));
180 : 28 : if (!entry)
181 : 1 : goto err;
182 : 27 : list_add_tail(&msg_free_list, &entry->link);
183 : : }
184 : 1 : return;
185 : :
186 : 1 : err:
187 : 4 : for (; i > 0; i--) {
188 : 3 : entry = list_pop(&msg_free_list, struct opal_msg_entry, link);
189 : 3 : if (entry)
190 : 3 : free(entry);
191 : : }
192 : : }
193 : :
|