LCOV - code coverage report
Current view: top level - core - opal-msg.c (source / functions) Hit Total Coverage
Test: skiboot.info Lines: 68 93 73.1 %
Date: 2024-01-02 21:04:04 Functions: 3 4 75.0 %
Branches: 0 0 -

           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                 :            : 

Generated by: LCOV version 1.14