aboutsummaryrefslogtreecommitdiff
path: root/core/opal-msg.c
diff options
context:
space:
mode:
authorVasant Hegde <hegdevasant@linux.vnet.ibm.com>2019-05-28 11:17:21 +0530
committerStewart Smith <stewart@linux.ibm.com>2019-06-03 10:28:57 +1000
commitb6fce51e31703ea95bf8dede4d9dc1f2dcd56639 (patch)
tree8adb26aaefce4bf3cbc9f2272a099b6e4fc1a0db /core/opal-msg.c
parent66d0ad68687bb12f7fb4301652f434f886998bdf (diff)
downloadskiboot-b6fce51e31703ea95bf8dede4d9dc1f2dcd56639.zip
skiboot-b6fce51e31703ea95bf8dede4d9dc1f2dcd56639.tar.gz
skiboot-b6fce51e31703ea95bf8dede4d9dc1f2dcd56639.tar.bz2
opal-msg: Enhance opal-get-msg API
Linux uses opal_get_msg (OPAL_GET_MSG) API to get OPAL messages. This interface supports upto 8 params (64 bytes). We have a requirement to send bigger data to Linux. This patch enhances OPAL to send bigger data to Linux. - Linux will use "opal-msg-size" device tree property to allocate memory for OPAL messages (previous patch increased "opal-msg-size" to 64K). - Replaced `reserved` field in "struct opal_msg" with `size`. So that Linux side opal_get_msg user can detect actual data size. - If buffer size < actual message size, then opal_get_msg will copy partial data and return OPAL_PARTIAL to Linux. - Add new variable "extended" to "opal_msg_entry" structure to keep track of messages that has more than 64byte data. We will allocate separate memory for these messages and once kernel consumes message we will release that memory. Cc: Jeremy Kerr <jk@ozlabs.org> Cc: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> Cc: Oliver O'Halloran <oohall@gmail.com> Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com> Acked-by: Jeremy Kerr <jk@ozlabs.org> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
Diffstat (limited to 'core/opal-msg.c')
-rw-r--r--core/opal-msg.c66
1 files changed, 48 insertions, 18 deletions
diff --git a/core/opal-msg.c b/core/opal-msg.c
index 907a9e0..af1ec7d 100644
--- a/core/opal-msg.c
+++ b/core/opal-msg.c
@@ -25,6 +25,7 @@
struct opal_msg_entry {
struct list_node link;
void (*consumed)(void *data, int status);
+ bool extended;
void *data;
struct opal_msg msg;
};
@@ -39,37 +40,47 @@ int _opal_queue_msg(enum opal_msg_type msg_type, void *data,
size_t params_size, const void *params)
{
struct opal_msg_entry *entry;
+ uint64_t entry_size;
+
+ if ((params_size + OPAL_MSG_HDR_SIZE) > OPAL_MSG_SIZE) {
+ prlog(PR_DEBUG, "param_size (0x%x) > opal_msg param size (0x%x)\n",
+ (u32)params_size, (u32)(OPAL_MSG_SIZE - OPAL_MSG_HDR_SIZE));
+ return OPAL_PARAMETER;
+ }
lock(&opal_msg_lock);
- entry = list_pop(&msg_free_list, struct opal_msg_entry, link);
- if (!entry) {
- prerror("No available node in the free list, allocating\n");
- entry = zalloc(sizeof(struct opal_msg_entry));
+ if (params_size > OPAL_MSG_FIXED_PARAMS_SIZE) {
+ entry_size = sizeof(struct opal_msg_entry) + params_size;
+ entry_size -= OPAL_MSG_FIXED_PARAMS_SIZE;
+ entry = zalloc(entry_size);
+ if (entry)
+ entry->extended = true;
+ } else {
+ entry = list_pop(&msg_free_list, struct opal_msg_entry, link);
if (!entry) {
- prerror("Allocation failed\n");
- unlock(&opal_msg_lock);
- return OPAL_RESOURCE;
+ prerror("No available node in the free list, allocating\n");
+ entry = zalloc(sizeof(struct opal_msg_entry));
}
}
+ if (!entry) {
+ prerror("Allocation failed\n");
+ unlock(&opal_msg_lock);
+ return OPAL_RESOURCE;
+ }
entry->consumed = consumed;
entry->data = data;
entry->msg.msg_type = cpu_to_be32(msg_type);
-
- if (params_size > OPAL_MSG_FIXED_PARAMS_SIZE) {
- prerror("Discarding extra parameters\n");
- params_size = OPAL_MSG_FIXED_PARAMS_SIZE;
- }
+ entry->msg.size = cpu_to_be32(params_size);
memcpy(entry->msg.params, params, params_size);
list_add_tail(&msg_pending_list, &entry->link);
opal_update_pending_evt(OPAL_EVENT_MSG_PENDING,
OPAL_EVENT_MSG_PENDING);
-
unlock(&opal_msg_lock);
- return 0;
+ return OPAL_SUCCESS;
}
static int64_t opal_get_msg(uint64_t *buffer, uint64_t size)
@@ -77,6 +88,8 @@ static int64_t opal_get_msg(uint64_t *buffer, uint64_t size)
struct opal_msg_entry *entry;
void (*callback)(void *data, int status);
void *data;
+ uint64_t msg_size;
+ int rc = OPAL_SUCCESS;
if (size < sizeof(struct opal_msg) || !buffer)
return OPAL_PARAMETER;
@@ -92,20 +105,37 @@ static int64_t opal_get_msg(uint64_t *buffer, uint64_t size)
return OPAL_RESOURCE;
}
- memcpy(buffer, &entry->msg, sizeof(entry->msg));
+ msg_size = OPAL_MSG_HDR_SIZE + be32_to_cpu(entry->msg.size);
+ if (size < msg_size) {
+ /* Send partial data to Linux */
+ prlog(PR_NOTICE, "Sending partial data [msg_type : 0x%x, "
+ "msg_size : 0x%x, buf_size : 0x%x]\n",
+ be32_to_cpu(entry->msg.msg_type),
+ (u32)msg_size, (u32)size);
+
+ entry->msg.size = cpu_to_be32(size - OPAL_MSG_HDR_SIZE);
+ msg_size = size;
+ rc = OPAL_PARTIAL;
+ }
+
+ memcpy((void *)buffer, (void *)&entry->msg, msg_size);
callback = entry->consumed;
data = entry->data;
- list_add(&msg_free_list, &entry->link);
+ if (entry->extended)
+ free(entry);
+ else
+ list_add(&msg_free_list, &entry->link);
+
if (list_empty(&msg_pending_list))
opal_update_pending_evt(OPAL_EVENT_MSG_PENDING, 0);
unlock(&opal_msg_lock);
if (callback)
- callback(data, OPAL_SUCCESS);
+ callback(data, rc);
- return OPAL_SUCCESS;
+ return rc;
}
opal_call(OPAL_GET_MSG, opal_get_msg, 2);