LCOV - code coverage report
Current view: top level - drivers/gpu/drm/i915/gt/uc - intel_guc_ct.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 316 0.0 %
Date: 2022-04-01 14:58:12 Functions: 0 18 0.0 %
Branches: 0 124 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: MIT
       2                 :            : /*
       3                 :            :  * Copyright © 2016-2019 Intel Corporation
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "i915_drv.h"
       7                 :            : #include "intel_guc_ct.h"
       8                 :            : 
       9                 :            : #ifdef CONFIG_DRM_I915_DEBUG_GUC
      10                 :            : #define CT_DEBUG_DRIVER(...)    DRM_DEBUG_DRIVER(__VA_ARGS__)
      11                 :            : #else
      12                 :            : #define CT_DEBUG_DRIVER(...)    do { } while (0)
      13                 :            : #endif
      14                 :            : 
      15                 :            : struct ct_request {
      16                 :            :         struct list_head link;
      17                 :            :         u32 fence;
      18                 :            :         u32 status;
      19                 :            :         u32 response_len;
      20                 :            :         u32 *response_buf;
      21                 :            : };
      22                 :            : 
      23                 :            : struct ct_incoming_request {
      24                 :            :         struct list_head link;
      25                 :            :         u32 msg[];
      26                 :            : };
      27                 :            : 
      28                 :            : enum { CTB_SEND = 0, CTB_RECV = 1 };
      29                 :            : 
      30                 :            : enum { CTB_OWNER_HOST = 0 };
      31                 :            : 
      32                 :            : static void ct_incoming_request_worker_func(struct work_struct *w);
      33                 :            : 
      34                 :            : /**
      35                 :            :  * intel_guc_ct_init_early - Initialize CT state without requiring device access
      36                 :            :  * @ct: pointer to CT struct
      37                 :            :  */
      38                 :          0 : void intel_guc_ct_init_early(struct intel_guc_ct *ct)
      39                 :            : {
      40                 :          0 :         spin_lock_init(&ct->requests.lock);
      41                 :          0 :         INIT_LIST_HEAD(&ct->requests.pending);
      42                 :          0 :         INIT_LIST_HEAD(&ct->requests.incoming);
      43                 :          0 :         INIT_WORK(&ct->requests.worker, ct_incoming_request_worker_func);
      44                 :          0 : }
      45                 :            : 
      46                 :          0 : static inline struct intel_guc *ct_to_guc(struct intel_guc_ct *ct)
      47                 :            : {
      48                 :          0 :         return container_of(ct, struct intel_guc, ct);
      49                 :            : }
      50                 :            : 
      51                 :          0 : static inline const char *guc_ct_buffer_type_to_str(u32 type)
      52                 :            : {
      53                 :          0 :         switch (type) {
      54                 :            :         case INTEL_GUC_CT_BUFFER_TYPE_SEND:
      55                 :            :                 return "SEND";
      56                 :          0 :         case INTEL_GUC_CT_BUFFER_TYPE_RECV:
      57                 :          0 :                 return "RECV";
      58                 :          0 :         default:
      59                 :          0 :                 return "<invalid>";
      60                 :            :         }
      61                 :            : }
      62                 :            : 
      63                 :          0 : static void guc_ct_buffer_desc_init(struct guc_ct_buffer_desc *desc,
      64                 :            :                                     u32 cmds_addr, u32 size)
      65                 :            : {
      66                 :          0 :         CT_DEBUG_DRIVER("CT: init addr=%#x size=%u\n", cmds_addr, size);
      67                 :          0 :         memset(desc, 0, sizeof(*desc));
      68                 :          0 :         desc->addr = cmds_addr;
      69                 :          0 :         desc->size = size;
      70                 :          0 :         desc->owner = CTB_OWNER_HOST;
      71                 :            : }
      72                 :            : 
      73                 :          0 : static void guc_ct_buffer_desc_reset(struct guc_ct_buffer_desc *desc)
      74                 :            : {
      75                 :          0 :         CT_DEBUG_DRIVER("CT: desc %p reset head=%u tail=%u\n",
      76                 :            :                         desc, desc->head, desc->tail);
      77                 :          0 :         desc->head = 0;
      78                 :          0 :         desc->tail = 0;
      79                 :          0 :         desc->is_in_error = 0;
      80                 :            : }
      81                 :            : 
      82                 :          0 : static int guc_action_register_ct_buffer(struct intel_guc *guc,
      83                 :            :                                          u32 desc_addr,
      84                 :            :                                          u32 type)
      85                 :            : {
      86                 :          0 :         u32 action[] = {
      87                 :            :                 INTEL_GUC_ACTION_REGISTER_COMMAND_TRANSPORT_BUFFER,
      88                 :            :                 desc_addr,
      89                 :            :                 sizeof(struct guc_ct_buffer_desc),
      90                 :            :                 type
      91                 :            :         };
      92                 :          0 :         int err;
      93                 :            : 
      94                 :            :         /* Can't use generic send(), CT registration must go over MMIO */
      95                 :          0 :         err = intel_guc_send_mmio(guc, action, ARRAY_SIZE(action), NULL, 0);
      96         [ #  # ]:          0 :         if (err)
      97      [ #  #  # ]:          0 :                 DRM_ERROR("CT: register %s buffer failed; err=%d\n",
      98                 :            :                           guc_ct_buffer_type_to_str(type), err);
      99                 :          0 :         return err;
     100                 :            : }
     101                 :            : 
     102                 :          0 : static int guc_action_deregister_ct_buffer(struct intel_guc *guc,
     103                 :            :                                            u32 type)
     104                 :            : {
     105                 :          0 :         u32 action[] = {
     106                 :            :                 INTEL_GUC_ACTION_DEREGISTER_COMMAND_TRANSPORT_BUFFER,
     107                 :            :                 CTB_OWNER_HOST,
     108                 :            :                 type
     109                 :            :         };
     110                 :          0 :         int err;
     111                 :            : 
     112                 :            :         /* Can't use generic send(), CT deregistration must go over MMIO */
     113                 :          0 :         err = intel_guc_send_mmio(guc, action, ARRAY_SIZE(action), NULL, 0);
     114         [ #  # ]:          0 :         if (err)
     115      [ #  #  # ]:          0 :                 DRM_ERROR("CT: deregister %s buffer failed; err=%d\n",
     116                 :            :                           guc_ct_buffer_type_to_str(type), err);
     117                 :          0 :         return err;
     118                 :            : }
     119                 :            : 
     120                 :            : /**
     121                 :            :  * intel_guc_ct_init - Init buffer-based communication
     122                 :            :  * @ct: pointer to CT struct
     123                 :            :  *
     124                 :            :  * Allocate memory required for buffer-based communication.
     125                 :            :  *
     126                 :            :  * Return: 0 on success, a negative errno code on failure.
     127                 :            :  */
     128                 :          0 : int intel_guc_ct_init(struct intel_guc_ct *ct)
     129                 :            : {
     130                 :          0 :         struct intel_guc *guc = ct_to_guc(ct);
     131                 :          0 :         void *blob;
     132                 :          0 :         int err;
     133                 :          0 :         int i;
     134                 :            : 
     135                 :          0 :         GEM_BUG_ON(ct->vma);
     136                 :            : 
     137                 :            :         /* We allocate 1 page to hold both descriptors and both buffers.
     138                 :            :          *       ___________.....................
     139                 :            :          *      |desc (SEND)|                   :
     140                 :            :          *      |___________|                   PAGE/4
     141                 :            :          *      :___________....................:
     142                 :            :          *      |desc (RECV)|                   :
     143                 :            :          *      |___________|                   PAGE/4
     144                 :            :          *      :_______________________________:
     145                 :            :          *      |cmds (SEND)                    |
     146                 :            :          *      |                               PAGE/4
     147                 :            :          *      |_______________________________|
     148                 :            :          *      |cmds (RECV)                    |
     149                 :            :          *      |                               PAGE/4
     150                 :            :          *      |_______________________________|
     151                 :            :          *
     152                 :            :          * Each message can use a maximum of 32 dwords and we don't expect to
     153                 :            :          * have more than 1 in flight at any time, so we have enough space.
     154                 :            :          * Some logic further ahead will rely on the fact that there is only 1
     155                 :            :          * page and that it is always mapped, so if the size is changed the
     156                 :            :          * other code will need updating as well.
     157                 :            :          */
     158                 :            : 
     159                 :          0 :         err = intel_guc_allocate_and_map_vma(guc, PAGE_SIZE, &ct->vma, &blob);
     160         [ #  # ]:          0 :         if (err) {
     161                 :          0 :                 DRM_ERROR("CT: channel allocation failed; err=%d\n", err);
     162                 :          0 :                 return err;
     163                 :            :         }
     164                 :            : 
     165                 :            :         CT_DEBUG_DRIVER("CT: vma base=%#x\n",
     166                 :            :                         intel_guc_ggtt_offset(guc, ct->vma));
     167                 :            : 
     168                 :            :         /* store pointers to desc and cmds */
     169         [ #  # ]:          0 :         for (i = 0; i < ARRAY_SIZE(ct->ctbs); i++) {
     170                 :          0 :                 GEM_BUG_ON((i !=  CTB_SEND) && (i != CTB_RECV));
     171                 :          0 :                 ct->ctbs[i].desc = blob + PAGE_SIZE/4 * i;
     172                 :          0 :                 ct->ctbs[i].cmds = blob + PAGE_SIZE/4 * i + PAGE_SIZE/2;
     173                 :            :         }
     174                 :            : 
     175                 :            :         return 0;
     176                 :            : }
     177                 :            : 
     178                 :            : /**
     179                 :            :  * intel_guc_ct_fini - Fini buffer-based communication
     180                 :            :  * @ct: pointer to CT struct
     181                 :            :  *
     182                 :            :  * Deallocate memory required for buffer-based communication.
     183                 :            :  */
     184                 :          0 : void intel_guc_ct_fini(struct intel_guc_ct *ct)
     185                 :            : {
     186                 :          0 :         GEM_BUG_ON(ct->enabled);
     187                 :            : 
     188                 :          0 :         i915_vma_unpin_and_release(&ct->vma, I915_VMA_RELEASE_MAP);
     189                 :          0 : }
     190                 :            : 
     191                 :            : /**
     192                 :            :  * intel_guc_ct_enable - Enable buffer based command transport.
     193                 :            :  * @ct: pointer to CT struct
     194                 :            :  *
     195                 :            :  * Return: 0 on success, a negative errno code on failure.
     196                 :            :  */
     197                 :          0 : int intel_guc_ct_enable(struct intel_guc_ct *ct)
     198                 :            : {
     199                 :          0 :         struct intel_guc *guc = ct_to_guc(ct);
     200                 :          0 :         u32 base;
     201                 :          0 :         int err;
     202                 :          0 :         int i;
     203                 :            : 
     204                 :          0 :         GEM_BUG_ON(ct->enabled);
     205                 :            : 
     206                 :            :         /* vma should be already allocated and map'ed */
     207                 :          0 :         GEM_BUG_ON(!ct->vma);
     208                 :          0 :         base = intel_guc_ggtt_offset(guc, ct->vma);
     209                 :            : 
     210                 :            :         /* (re)initialize descriptors
     211                 :            :          * cmds buffers are in the second half of the blob page
     212                 :            :          */
     213         [ #  # ]:          0 :         for (i = 0; i < ARRAY_SIZE(ct->ctbs); i++) {
     214                 :          0 :                 GEM_BUG_ON((i != CTB_SEND) && (i != CTB_RECV));
     215                 :          0 :                 guc_ct_buffer_desc_init(ct->ctbs[i].desc,
     216                 :          0 :                                         base + PAGE_SIZE/4 * i + PAGE_SIZE/2,
     217                 :            :                                         PAGE_SIZE/4);
     218                 :            :         }
     219                 :            : 
     220                 :            :         /* register buffers, starting wirh RECV buffer
     221                 :            :          * descriptors are in first half of the blob
     222                 :            :          */
     223                 :          0 :         err = guc_action_register_ct_buffer(guc,
     224                 :            :                                             base + PAGE_SIZE/4 * CTB_RECV,
     225                 :            :                                             INTEL_GUC_CT_BUFFER_TYPE_RECV);
     226         [ #  # ]:          0 :         if (unlikely(err))
     227                 :          0 :                 goto err_out;
     228                 :            : 
     229                 :          0 :         err = guc_action_register_ct_buffer(guc,
     230                 :            :                                             base + PAGE_SIZE/4 * CTB_SEND,
     231                 :            :                                             INTEL_GUC_CT_BUFFER_TYPE_SEND);
     232         [ #  # ]:          0 :         if (unlikely(err))
     233                 :          0 :                 goto err_deregister;
     234                 :            : 
     235                 :          0 :         ct->enabled = true;
     236                 :            : 
     237                 :          0 :         return 0;
     238                 :            : 
     239                 :            : err_deregister:
     240                 :          0 :         guc_action_deregister_ct_buffer(guc,
     241                 :            :                                         INTEL_GUC_CT_BUFFER_TYPE_RECV);
     242                 :          0 : err_out:
     243                 :          0 :         DRM_ERROR("CT: can't open channel; err=%d\n", err);
     244                 :          0 :         return err;
     245                 :            : }
     246                 :            : 
     247                 :            : /**
     248                 :            :  * intel_guc_ct_disable - Disable buffer based command transport.
     249                 :            :  * @ct: pointer to CT struct
     250                 :            :  */
     251                 :          0 : void intel_guc_ct_disable(struct intel_guc_ct *ct)
     252                 :            : {
     253                 :          0 :         struct intel_guc *guc = ct_to_guc(ct);
     254                 :            : 
     255                 :          0 :         GEM_BUG_ON(!ct->enabled);
     256                 :            : 
     257                 :          0 :         ct->enabled = false;
     258                 :            : 
     259         [ #  # ]:          0 :         if (intel_guc_is_running(guc)) {
     260                 :          0 :                 guc_action_deregister_ct_buffer(guc,
     261                 :            :                                                 INTEL_GUC_CT_BUFFER_TYPE_SEND);
     262                 :          0 :                 guc_action_deregister_ct_buffer(guc,
     263                 :            :                                                 INTEL_GUC_CT_BUFFER_TYPE_RECV);
     264                 :            :         }
     265                 :          0 : }
     266                 :            : 
     267                 :          0 : static u32 ct_get_next_fence(struct intel_guc_ct *ct)
     268                 :            : {
     269                 :            :         /* For now it's trivial */
     270                 :          0 :         return ++ct->requests.next_fence;
     271                 :            : }
     272                 :            : 
     273                 :            : /**
     274                 :            :  * DOC: CTB Host to GuC request
     275                 :            :  *
     276                 :            :  * Format of the CTB Host to GuC request message is as follows::
     277                 :            :  *
     278                 :            :  *      +------------+---------+---------+---------+---------+
     279                 :            :  *      |   msg[0]   |   [1]   |   [2]   |   ...   |  [n-1]  |
     280                 :            :  *      +------------+---------+---------+---------+---------+
     281                 :            :  *      |   MESSAGE  |       MESSAGE PAYLOAD                 |
     282                 :            :  *      +   HEADER   +---------+---------+---------+---------+
     283                 :            :  *      |            |    0    |    1    |   ...   |    n    |
     284                 :            :  *      +============+=========+=========+=========+=========+
     285                 :            :  *      |  len >= 1  |  FENCE  |     request specific data   |
     286                 :            :  *      +------+-----+---------+---------+---------+---------+
     287                 :            :  *
     288                 :            :  *                   ^-----------------len-------------------^
     289                 :            :  */
     290                 :            : 
     291                 :          0 : static int ctb_write(struct intel_guc_ct_buffer *ctb,
     292                 :            :                      const u32 *action,
     293                 :            :                      u32 len /* in dwords */,
     294                 :            :                      u32 fence,
     295                 :            :                      bool want_response)
     296                 :            : {
     297                 :          0 :         struct guc_ct_buffer_desc *desc = ctb->desc;
     298                 :          0 :         u32 head = desc->head / 4;   /* in dwords */
     299                 :          0 :         u32 tail = desc->tail / 4;   /* in dwords */
     300                 :          0 :         u32 size = desc->size / 4;   /* in dwords */
     301                 :          0 :         u32 used;                       /* in dwords */
     302                 :          0 :         u32 header;
     303                 :          0 :         u32 *cmds = ctb->cmds;
     304                 :          0 :         unsigned int i;
     305                 :            : 
     306                 :          0 :         GEM_BUG_ON(desc->size % 4);
     307                 :          0 :         GEM_BUG_ON(desc->head % 4);
     308                 :          0 :         GEM_BUG_ON(desc->tail % 4);
     309                 :          0 :         GEM_BUG_ON(tail >= size);
     310                 :            : 
     311                 :            :         /*
     312                 :            :          * tail == head condition indicates empty. GuC FW does not support
     313                 :            :          * using up the entire buffer to get tail == head meaning full.
     314                 :            :          */
     315         [ #  # ]:          0 :         if (tail < head)
     316                 :          0 :                 used = (size - head) + tail;
     317                 :            :         else
     318                 :          0 :                 used = tail - head;
     319                 :            : 
     320                 :            :         /* make sure there is a space including extra dw for the fence */
     321         [ #  # ]:          0 :         if (unlikely(used + len + 1 >= size))
     322                 :            :                 return -ENOSPC;
     323                 :            : 
     324                 :            :         /*
     325                 :            :          * Write the message. The format is the following:
     326                 :            :          * DW0: header (including action code)
     327                 :            :          * DW1: fence
     328                 :            :          * DW2+: action data
     329                 :            :          */
     330                 :          0 :         header = (len << GUC_CT_MSG_LEN_SHIFT) |
     331                 :          0 :                  (GUC_CT_MSG_WRITE_FENCE_TO_DESC) |
     332         [ #  # ]:          0 :                  (want_response ? GUC_CT_MSG_SEND_STATUS : 0) |
     333                 :          0 :                  (action[0] << GUC_CT_MSG_ACTION_SHIFT);
     334                 :            : 
     335                 :          0 :         CT_DEBUG_DRIVER("CT: writing %*ph %*ph %*ph\n",
     336                 :            :                         4, &header, 4, &fence,
     337                 :            :                         4 * (len - 1), &action[1]);
     338                 :            : 
     339                 :          0 :         cmds[tail] = header;
     340                 :          0 :         tail = (tail + 1) % size;
     341                 :            : 
     342                 :          0 :         cmds[tail] = fence;
     343                 :          0 :         tail = (tail + 1) % size;
     344                 :            : 
     345         [ #  # ]:          0 :         for (i = 1; i < len; i++) {
     346                 :          0 :                 cmds[tail] = action[i];
     347                 :          0 :                 tail = (tail + 1) % size;
     348                 :            :         }
     349                 :            : 
     350                 :            :         /* now update desc tail (back in bytes) */
     351                 :          0 :         desc->tail = tail * 4;
     352                 :          0 :         GEM_BUG_ON(desc->tail > desc->size);
     353                 :            : 
     354                 :          0 :         return 0;
     355                 :            : }
     356                 :            : 
     357                 :            : /**
     358                 :            :  * wait_for_ctb_desc_update - Wait for the CT buffer descriptor update.
     359                 :            :  * @desc:       buffer descriptor
     360                 :            :  * @fence:      response fence
     361                 :            :  * @status:     placeholder for status
     362                 :            :  *
     363                 :            :  * Guc will update CT buffer descriptor with new fence and status
     364                 :            :  * after processing the command identified by the fence. Wait for
     365                 :            :  * specified fence and then read from the descriptor status of the
     366                 :            :  * command.
     367                 :            :  *
     368                 :            :  * Return:
     369                 :            :  * *    0 response received (status is valid)
     370                 :            :  * *    -ETIMEDOUT no response within hardcoded timeout
     371                 :            :  * *    -EPROTO no response, CT buffer is in error
     372                 :            :  */
     373                 :          0 : static int wait_for_ctb_desc_update(struct guc_ct_buffer_desc *desc,
     374                 :            :                                     u32 fence,
     375                 :            :                                     u32 *status)
     376                 :            : {
     377                 :          0 :         int err;
     378                 :            : 
     379                 :            :         /*
     380                 :            :          * Fast commands should complete in less than 10us, so sample quickly
     381                 :            :          * up to that length of time, then switch to a slower sleep-wait loop.
     382                 :            :          * No GuC command should ever take longer than 10ms.
     383                 :            :          */
     384                 :            : #define done (READ_ONCE(desc->fence) == fence)
     385   [ #  #  #  #  :          0 :         err = wait_for_us(done, 10);
                   #  # ]
     386         [ #  # ]:          0 :         if (err)
     387   [ #  #  #  #  :          0 :                 err = wait_for(done, 10);
                   #  # ]
     388                 :            : #undef done
     389                 :            : 
     390         [ #  # ]:          0 :         if (unlikely(err)) {
     391                 :          0 :                 DRM_ERROR("CT: fence %u failed; reported fence=%u\n",
     392                 :            :                           fence, desc->fence);
     393                 :            : 
     394   [ #  #  #  # ]:          0 :                 if (WARN_ON(desc->is_in_error)) {
     395                 :            :                         /* Something went wrong with the messaging, try to reset
     396                 :            :                          * the buffer and hope for the best
     397                 :            :                          */
     398                 :          0 :                         guc_ct_buffer_desc_reset(desc);
     399                 :          0 :                         err = -EPROTO;
     400                 :            :                 }
     401                 :            :         }
     402                 :            : 
     403                 :          0 :         *status = desc->status;
     404                 :          0 :         return err;
     405                 :            : }
     406                 :            : 
     407                 :            : /**
     408                 :            :  * wait_for_ct_request_update - Wait for CT request state update.
     409                 :            :  * @req:        pointer to pending request
     410                 :            :  * @status:     placeholder for status
     411                 :            :  *
     412                 :            :  * For each sent request, Guc shall send bac CT response message.
     413                 :            :  * Our message handler will update status of tracked request once
     414                 :            :  * response message with given fence is received. Wait here and
     415                 :            :  * check for valid response status value.
     416                 :            :  *
     417                 :            :  * Return:
     418                 :            :  * *    0 response received (status is valid)
     419                 :            :  * *    -ETIMEDOUT no response within hardcoded timeout
     420                 :            :  */
     421                 :          0 : static int wait_for_ct_request_update(struct ct_request *req, u32 *status)
     422                 :            : {
     423                 :          0 :         int err;
     424                 :            : 
     425                 :            :         /*
     426                 :            :          * Fast commands should complete in less than 10us, so sample quickly
     427                 :            :          * up to that length of time, then switch to a slower sleep-wait loop.
     428                 :            :          * No GuC command should ever take longer than 10ms.
     429                 :            :          */
     430                 :            : #define done INTEL_GUC_MSG_IS_RESPONSE(READ_ONCE(req->status))
     431   [ #  #  #  #  :          0 :         err = wait_for_us(done, 10);
                   #  # ]
     432         [ #  # ]:          0 :         if (err)
     433   [ #  #  #  #  :          0 :                 err = wait_for(done, 10);
                   #  # ]
     434                 :            : #undef done
     435                 :            : 
     436         [ #  # ]:          0 :         if (unlikely(err))
     437                 :          0 :                 DRM_ERROR("CT: fence %u err %d\n", req->fence, err);
     438                 :            : 
     439                 :          0 :         *status = req->status;
     440                 :          0 :         return err;
     441                 :            : }
     442                 :            : 
     443                 :          0 : static int ct_send(struct intel_guc_ct *ct,
     444                 :            :                    const u32 *action,
     445                 :            :                    u32 len,
     446                 :            :                    u32 *response_buf,
     447                 :            :                    u32 response_buf_size,
     448                 :            :                    u32 *status)
     449                 :            : {
     450                 :          0 :         struct intel_guc_ct_buffer *ctb = &ct->ctbs[CTB_SEND];
     451                 :          0 :         struct guc_ct_buffer_desc *desc = ctb->desc;
     452                 :          0 :         struct ct_request request;
     453                 :          0 :         unsigned long flags;
     454                 :          0 :         u32 fence;
     455                 :          0 :         int err;
     456                 :            : 
     457                 :          0 :         GEM_BUG_ON(!ct->enabled);
     458                 :          0 :         GEM_BUG_ON(!len);
     459                 :          0 :         GEM_BUG_ON(len & ~GUC_CT_MSG_LEN_MASK);
     460                 :          0 :         GEM_BUG_ON(!response_buf && response_buf_size);
     461                 :            : 
     462                 :          0 :         fence = ct_get_next_fence(ct);
     463                 :          0 :         request.fence = fence;
     464                 :          0 :         request.status = 0;
     465                 :          0 :         request.response_len = response_buf_size;
     466                 :          0 :         request.response_buf = response_buf;
     467                 :            : 
     468                 :          0 :         spin_lock_irqsave(&ct->requests.lock, flags);
     469                 :          0 :         list_add_tail(&request.link, &ct->requests.pending);
     470                 :          0 :         spin_unlock_irqrestore(&ct->requests.lock, flags);
     471                 :            : 
     472                 :          0 :         err = ctb_write(ctb, action, len, fence, !!response_buf);
     473         [ #  # ]:          0 :         if (unlikely(err))
     474                 :          0 :                 goto unlink;
     475                 :            : 
     476                 :          0 :         intel_guc_notify(ct_to_guc(ct));
     477                 :            : 
     478         [ #  # ]:          0 :         if (response_buf)
     479                 :          0 :                 err = wait_for_ct_request_update(&request, status);
     480                 :            :         else
     481                 :          0 :                 err = wait_for_ctb_desc_update(desc, fence, status);
     482         [ #  # ]:          0 :         if (unlikely(err))
     483                 :          0 :                 goto unlink;
     484                 :            : 
     485         [ #  # ]:          0 :         if (!INTEL_GUC_MSG_IS_RESPONSE_SUCCESS(*status)) {
     486                 :          0 :                 err = -EIO;
     487                 :          0 :                 goto unlink;
     488                 :            :         }
     489                 :            : 
     490         [ #  # ]:          0 :         if (response_buf) {
     491                 :            :                 /* There shall be no data in the status */
     492         [ #  # ]:          0 :                 WARN_ON(INTEL_GUC_MSG_TO_DATA(request.status));
     493                 :            :                 /* Return actual response len */
     494                 :          0 :                 err = request.response_len;
     495                 :            :         } else {
     496                 :            :                 /* There shall be no response payload */
     497         [ #  # ]:          0 :                 WARN_ON(request.response_len);
     498                 :            :                 /* Return data decoded from the status dword */
     499                 :          0 :                 err = INTEL_GUC_MSG_TO_DATA(*status);
     500                 :            :         }
     501                 :            : 
     502                 :          0 : unlink:
     503                 :          0 :         spin_lock_irqsave(&ct->requests.lock, flags);
     504                 :          0 :         list_del(&request.link);
     505                 :          0 :         spin_unlock_irqrestore(&ct->requests.lock, flags);
     506                 :            : 
     507                 :          0 :         return err;
     508                 :            : }
     509                 :            : 
     510                 :            : /*
     511                 :            :  * Command Transport (CT) buffer based GuC send function.
     512                 :            :  */
     513                 :          0 : int intel_guc_ct_send(struct intel_guc_ct *ct, const u32 *action, u32 len,
     514                 :            :                       u32 *response_buf, u32 response_buf_size)
     515                 :            : {
     516                 :          0 :         struct intel_guc *guc = ct_to_guc(ct);
     517                 :          0 :         u32 status = ~0; /* undefined */
     518                 :          0 :         int ret;
     519                 :            : 
     520         [ #  # ]:          0 :         if (unlikely(!ct->enabled)) {
     521                 :          0 :                 WARN(1, "Unexpected send: action=%#x\n", *action);
     522                 :          0 :                 return -ENODEV;
     523                 :            :         }
     524                 :            : 
     525                 :          0 :         mutex_lock(&guc->send_mutex);
     526                 :            : 
     527                 :          0 :         ret = ct_send(ct, action, len, response_buf, response_buf_size, &status);
     528         [ #  # ]:          0 :         if (unlikely(ret < 0)) {
     529                 :          0 :                 DRM_ERROR("CT: send action %#X failed; err=%d status=%#X\n",
     530                 :            :                           action[0], ret, status);
     531                 :            :         } else if (unlikely(ret)) {
     532                 :          0 :                 CT_DEBUG_DRIVER("CT: send action %#x returned %d (%#x)\n",
     533                 :            :                                 action[0], ret, ret);
     534                 :            :         }
     535                 :            : 
     536                 :          0 :         mutex_unlock(&guc->send_mutex);
     537                 :          0 :         return ret;
     538                 :            : }
     539                 :            : 
     540                 :          0 : static inline unsigned int ct_header_get_len(u32 header)
     541                 :            : {
     542                 :          0 :         return (header >> GUC_CT_MSG_LEN_SHIFT) & GUC_CT_MSG_LEN_MASK;
     543                 :            : }
     544                 :            : 
     545                 :          0 : static inline unsigned int ct_header_get_action(u32 header)
     546                 :            : {
     547                 :          0 :         return (header >> GUC_CT_MSG_ACTION_SHIFT) & GUC_CT_MSG_ACTION_MASK;
     548                 :            : }
     549                 :            : 
     550                 :          0 : static inline bool ct_header_is_response(u32 header)
     551                 :            : {
     552                 :          0 :         return !!(header & GUC_CT_MSG_IS_RESPONSE);
     553                 :            : }
     554                 :            : 
     555                 :            : static int ctb_read(struct intel_guc_ct_buffer *ctb, u32 *data)
     556                 :            : {
     557                 :            :         struct guc_ct_buffer_desc *desc = ctb->desc;
     558                 :            :         u32 head = desc->head / 4;   /* in dwords */
     559                 :            :         u32 tail = desc->tail / 4;   /* in dwords */
     560                 :            :         u32 size = desc->size / 4;   /* in dwords */
     561                 :            :         u32 *cmds = ctb->cmds;
     562                 :            :         s32 available;                  /* in dwords */
     563                 :            :         unsigned int len;
     564                 :            :         unsigned int i;
     565                 :            : 
     566                 :            :         GEM_BUG_ON(desc->size % 4);
     567                 :            :         GEM_BUG_ON(desc->head % 4);
     568                 :            :         GEM_BUG_ON(desc->tail % 4);
     569                 :            :         GEM_BUG_ON(tail >= size);
     570                 :            :         GEM_BUG_ON(head >= size);
     571                 :            : 
     572                 :            :         /* tail == head condition indicates empty */
     573                 :            :         available = tail - head;
     574                 :            :         if (unlikely(available == 0))
     575                 :            :                 return -ENODATA;
     576                 :            : 
     577                 :            :         /* beware of buffer wrap case */
     578                 :            :         if (unlikely(available < 0))
     579                 :            :                 available += size;
     580                 :            :         CT_DEBUG_DRIVER("CT: available %d (%u:%u)\n", available, head, tail);
     581                 :            :         GEM_BUG_ON(available < 0);
     582                 :            : 
     583                 :            :         data[0] = cmds[head];
     584                 :            :         head = (head + 1) % size;
     585                 :            : 
     586                 :            :         /* message len with header */
     587                 :            :         len = ct_header_get_len(data[0]) + 1;
     588                 :            :         if (unlikely(len > (u32)available)) {
     589                 :            :                 DRM_ERROR("CT: incomplete message %*ph %*ph %*ph\n",
     590                 :            :                           4, data,
     591                 :            :                           4 * (head + available - 1 > size ?
     592                 :            :                                size - head : available - 1), &cmds[head],
     593                 :            :                           4 * (head + available - 1 > size ?
     594                 :            :                                available - 1 - size + head : 0), &cmds[0]);
     595                 :            :                 return -EPROTO;
     596                 :            :         }
     597                 :            : 
     598                 :            :         for (i = 1; i < len; i++) {
     599                 :            :                 data[i] = cmds[head];
     600                 :            :                 head = (head + 1) % size;
     601                 :            :         }
     602                 :            :         CT_DEBUG_DRIVER("CT: received %*ph\n", 4 * len, data);
     603                 :            : 
     604                 :            :         desc->head = head * 4;
     605                 :            :         return 0;
     606                 :            : }
     607                 :            : 
     608                 :            : /**
     609                 :            :  * DOC: CTB GuC to Host response
     610                 :            :  *
     611                 :            :  * Format of the CTB GuC to Host response message is as follows::
     612                 :            :  *
     613                 :            :  *      +------------+---------+---------+---------+---------+---------+
     614                 :            :  *      |   msg[0]   |   [1]   |   [2]   |   [3]   |   ...   |  [n-1]  |
     615                 :            :  *      +------------+---------+---------+---------+---------+---------+
     616                 :            :  *      |   MESSAGE  |       MESSAGE PAYLOAD                           |
     617                 :            :  *      +   HEADER   +---------+---------+---------+---------+---------+
     618                 :            :  *      |            |    0    |    1    |    2    |   ...   |    n    |
     619                 :            :  *      +============+=========+=========+=========+=========+=========+
     620                 :            :  *      |  len >= 2  |  FENCE  |  STATUS |   response specific data    |
     621                 :            :  *      +------+-----+---------+---------+---------+---------+---------+
     622                 :            :  *
     623                 :            :  *                   ^-----------------------len-----------------------^
     624                 :            :  */
     625                 :            : 
     626                 :          0 : static int ct_handle_response(struct intel_guc_ct *ct, const u32 *msg)
     627                 :            : {
     628                 :          0 :         u32 header = msg[0];
     629                 :          0 :         u32 len = ct_header_get_len(header);
     630                 :          0 :         u32 msglen = len + 1; /* total message length including header */
     631                 :          0 :         u32 fence;
     632                 :          0 :         u32 status;
     633                 :          0 :         u32 datalen;
     634                 :          0 :         struct ct_request *req;
     635                 :          0 :         bool found = false;
     636                 :            : 
     637                 :          0 :         GEM_BUG_ON(!ct_header_is_response(header));
     638                 :          0 :         GEM_BUG_ON(!in_irq());
     639                 :            : 
     640                 :            :         /* Response payload shall at least include fence and status */
     641         [ #  # ]:          0 :         if (unlikely(len < 2)) {
     642                 :          0 :                 DRM_ERROR("CT: corrupted response %*ph\n", 4 * msglen, msg);
     643                 :          0 :                 return -EPROTO;
     644                 :            :         }
     645                 :            : 
     646                 :          0 :         fence = msg[1];
     647                 :          0 :         status = msg[2];
     648                 :          0 :         datalen = len - 2;
     649                 :            : 
     650                 :            :         /* Format of the status follows RESPONSE message */
     651         [ #  # ]:          0 :         if (unlikely(!INTEL_GUC_MSG_IS_RESPONSE(status))) {
     652                 :          0 :                 DRM_ERROR("CT: corrupted response %*ph\n", 4 * msglen, msg);
     653                 :          0 :                 return -EPROTO;
     654                 :            :         }
     655                 :            : 
     656                 :          0 :         CT_DEBUG_DRIVER("CT: response fence %u status %#x\n", fence, status);
     657                 :            : 
     658                 :          0 :         spin_lock(&ct->requests.lock);
     659         [ #  # ]:          0 :         list_for_each_entry(req, &ct->requests.pending, link) {
     660         [ #  # ]:          0 :                 if (unlikely(fence != req->fence)) {
     661                 :          0 :                         CT_DEBUG_DRIVER("CT: request %u awaits response\n",
     662                 :            :                                         req->fence);
     663                 :          0 :                         continue;
     664                 :            :                 }
     665         [ #  # ]:          0 :                 if (unlikely(datalen > req->response_len)) {
     666                 :          0 :                         DRM_ERROR("CT: response %u too long %*ph\n",
     667                 :            :                                   req->fence, 4 * msglen, msg);
     668                 :          0 :                         datalen = 0;
     669                 :            :                 }
     670         [ #  # ]:          0 :                 if (datalen)
     671                 :          0 :                         memcpy(req->response_buf, msg + 3, 4 * datalen);
     672                 :          0 :                 req->response_len = datalen;
     673                 :          0 :                 WRITE_ONCE(req->status, status);
     674                 :          0 :                 found = true;
     675                 :          0 :                 break;
     676                 :            :         }
     677                 :          0 :         spin_unlock(&ct->requests.lock);
     678                 :            : 
     679         [ #  # ]:          0 :         if (!found)
     680                 :          0 :                 DRM_ERROR("CT: unsolicited response %*ph\n", 4 * msglen, msg);
     681                 :            :         return 0;
     682                 :            : }
     683                 :            : 
     684                 :          0 : static void ct_process_request(struct intel_guc_ct *ct,
     685                 :            :                                u32 action, u32 len, const u32 *payload)
     686                 :            : {
     687                 :          0 :         struct intel_guc *guc = ct_to_guc(ct);
     688                 :          0 :         int ret;
     689                 :            : 
     690                 :          0 :         CT_DEBUG_DRIVER("CT: request %x %*ph\n", action, 4 * len, payload);
     691                 :            : 
     692         [ #  # ]:          0 :         switch (action) {
     693                 :          0 :         case INTEL_GUC_ACTION_DEFAULT:
     694                 :          0 :                 ret = intel_guc_to_host_process_recv_msg(guc, payload, len);
     695         [ #  # ]:          0 :                 if (unlikely(ret))
     696                 :          0 :                         goto fail_unexpected;
     697                 :            :                 break;
     698                 :            : 
     699                 :            :         default:
     700                 :          0 : fail_unexpected:
     701                 :          0 :                 DRM_ERROR("CT: unexpected request %x %*ph\n",
     702                 :            :                           action, 4 * len, payload);
     703                 :          0 :                 break;
     704                 :            :         }
     705                 :          0 : }
     706                 :            : 
     707                 :          0 : static bool ct_process_incoming_requests(struct intel_guc_ct *ct)
     708                 :            : {
     709                 :          0 :         unsigned long flags;
     710                 :          0 :         struct ct_incoming_request *request;
     711                 :          0 :         u32 header;
     712                 :          0 :         u32 *payload;
     713                 :          0 :         bool done;
     714                 :            : 
     715                 :          0 :         spin_lock_irqsave(&ct->requests.lock, flags);
     716         [ #  # ]:          0 :         request = list_first_entry_or_null(&ct->requests.incoming,
     717                 :            :                                            struct ct_incoming_request, link);
     718         [ #  # ]:          0 :         if (request)
     719                 :          0 :                 list_del(&request->link);
     720                 :          0 :         done = !!list_empty(&ct->requests.incoming);
     721                 :          0 :         spin_unlock_irqrestore(&ct->requests.lock, flags);
     722                 :            : 
     723         [ #  # ]:          0 :         if (!request)
     724                 :            :                 return true;
     725                 :            : 
     726                 :          0 :         header = request->msg[0];
     727                 :          0 :         payload = &request->msg[1];
     728                 :          0 :         ct_process_request(ct,
     729                 :            :                            ct_header_get_action(header),
     730                 :            :                            ct_header_get_len(header),
     731                 :            :                            payload);
     732                 :            : 
     733                 :          0 :         kfree(request);
     734                 :          0 :         return done;
     735                 :            : }
     736                 :            : 
     737                 :          0 : static void ct_incoming_request_worker_func(struct work_struct *w)
     738                 :            : {
     739                 :          0 :         struct intel_guc_ct *ct =
     740                 :          0 :                 container_of(w, struct intel_guc_ct, requests.worker);
     741                 :          0 :         bool done;
     742                 :            : 
     743                 :          0 :         done = ct_process_incoming_requests(ct);
     744         [ #  # ]:          0 :         if (!done)
     745                 :          0 :                 queue_work(system_unbound_wq, &ct->requests.worker);
     746                 :          0 : }
     747                 :            : 
     748                 :            : /**
     749                 :            :  * DOC: CTB GuC to Host request
     750                 :            :  *
     751                 :            :  * Format of the CTB GuC to Host request message is as follows::
     752                 :            :  *
     753                 :            :  *      +------------+---------+---------+---------+---------+---------+
     754                 :            :  *      |   msg[0]   |   [1]   |   [2]   |   [3]   |   ...   |  [n-1]  |
     755                 :            :  *      +------------+---------+---------+---------+---------+---------+
     756                 :            :  *      |   MESSAGE  |       MESSAGE PAYLOAD                           |
     757                 :            :  *      +   HEADER   +---------+---------+---------+---------+---------+
     758                 :            :  *      |            |    0    |    1    |    2    |   ...   |    n    |
     759                 :            :  *      +============+=========+=========+=========+=========+=========+
     760                 :            :  *      |     len    |            request specific data                |
     761                 :            :  *      +------+-----+---------+---------+---------+---------+---------+
     762                 :            :  *
     763                 :            :  *                   ^-----------------------len-----------------------^
     764                 :            :  */
     765                 :            : 
     766                 :          0 : static int ct_handle_request(struct intel_guc_ct *ct, const u32 *msg)
     767                 :            : {
     768                 :          0 :         u32 header = msg[0];
     769                 :          0 :         u32 len = ct_header_get_len(header);
     770                 :          0 :         u32 msglen = len + 1; /* total message length including header */
     771                 :          0 :         struct ct_incoming_request *request;
     772                 :          0 :         unsigned long flags;
     773                 :            : 
     774                 :          0 :         GEM_BUG_ON(ct_header_is_response(header));
     775                 :            : 
     776         [ #  # ]:          0 :         request = kmalloc(sizeof(*request) + 4 * msglen, GFP_ATOMIC);
     777         [ #  # ]:          0 :         if (unlikely(!request)) {
     778                 :          0 :                 DRM_ERROR("CT: dropping request %*ph\n", 4 * msglen, msg);
     779                 :          0 :                 return 0; /* XXX: -ENOMEM ? */
     780                 :            :         }
     781                 :          0 :         memcpy(request->msg, msg, 4 * msglen);
     782                 :            : 
     783                 :          0 :         spin_lock_irqsave(&ct->requests.lock, flags);
     784                 :          0 :         list_add_tail(&request->link, &ct->requests.incoming);
     785                 :          0 :         spin_unlock_irqrestore(&ct->requests.lock, flags);
     786                 :            : 
     787                 :          0 :         queue_work(system_unbound_wq, &ct->requests.worker);
     788                 :          0 :         return 0;
     789                 :            : }
     790                 :            : 
     791                 :            : /*
     792                 :            :  * When we're communicating with the GuC over CT, GuC uses events
     793                 :            :  * to notify us about new messages being posted on the RECV buffer.
     794                 :            :  */
     795                 :          0 : void intel_guc_ct_event_handler(struct intel_guc_ct *ct)
     796                 :            : {
     797                 :          0 :         struct intel_guc_ct_buffer *ctb = &ct->ctbs[CTB_RECV];
     798                 :          0 :         u32 msg[GUC_CT_MSG_LEN_MASK + 1]; /* one extra dw for the header */
     799                 :          0 :         int err = 0;
     800                 :            : 
     801         [ #  # ]:          0 :         if (unlikely(!ct->enabled)) {
     802                 :          0 :                 WARN(1, "Unexpected GuC event received while CT disabled!\n");
     803                 :          0 :                 return;
     804                 :            :         }
     805                 :            : 
     806                 :          0 :         do {
     807                 :          0 :                 err = ctb_read(ctb, msg);
     808         [ #  # ]:          0 :                 if (err)
     809                 :            :                         break;
     810                 :            : 
     811         [ #  # ]:          0 :                 if (ct_header_is_response(msg[0]))
     812                 :          0 :                         err = ct_handle_response(ct, msg);
     813                 :            :                 else
     814                 :          0 :                         err = ct_handle_request(ct, msg);
     815         [ #  # ]:          0 :         } while (!err);
     816                 :            : 
     817         [ #  # ]:          0 :         if (GEM_WARN_ON(err == -EPROTO)) {
     818                 :          0 :                 DRM_ERROR("CT: corrupted message detected!\n");
     819                 :          0 :                 ctb->desc->is_in_error = 1;
     820                 :            :         }
     821                 :            : }
     822                 :            : 

Generated by: LCOV version 1.14