// SPDX-License-Identifier: MIT
/*
* Copyright © 2022 Intel Corporation
*/
#include "xe_guc_ct.h"
#include <linux/bitfield.h>
#include <linux/circ_buf.h>
#include <linux/delay.h>
#include <kunit/static_stub.h>
#include <drm/drm_managed.h>
#include "abi/guc_actions_abi.h"
#include "abi/guc_actions_sriov_abi.h"
#include "abi/guc_klvs_abi.h"
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_gt.h"
#include "xe_gt_pagefault.h"
#include "xe_gt_printk.h"
#include "xe_gt_sriov_pf_control.h"
#include "xe_gt_sriov_pf_monitor.h"
#include "xe_gt_tlb_invalidation.h"
#include "xe_guc.h"
#include "xe_guc_relay.h"
#include "xe_guc_submit.h"
#include "xe_map.h"
#include "xe_pm.h"
#include "xe_trace_guc.h"
/* Used when a CT send wants to block and / or receive data */
struct g2h_fence {
u32 *response_buffer;
u32 seqno;
u32 response_data;
u16 response_len;
u16 error;
u16 hint;
u16 reason;
bool retry;
bool fail;
bool done;
};
static void g2h_fence_init(struct g2h_fence *g2h_fence, u32 *response_buffer)
{
g2h_fence->response_buffer = response_buffer;
g2h_fence->response_data = 0;
g2h_fence->response_len = 0;
g2h_fence->fail = false;
g2h_fence->retry = false;
g2h_fence->done = false;
g2h_fence->seqno = ~0x0;
}
static bool g2h_fence_needs_alloc(struct g2h_fence *g2h_fence)
{
return g2h_fence->seqno == ~0x0;
}
static struct xe_guc *
ct_to_guc(struct xe_guc_ct *ct)
{
return container_of(ct, struct xe_guc, ct);
}
static struct xe_gt *
ct_to_gt(struct xe_guc_ct *ct)
{
return container_of(ct, struct xe_gt, uc.guc.ct);
}
static struct xe_device *
ct_to_xe(struct xe_guc_ct *ct)
{
return gt_to_xe(ct_to_gt(ct));
}
/**
* DOC: GuC CTB Blob
*
* We allocate single blob to hold both CTB descriptors and buffers:
*
* +--------+-----------------------------------------------+------+
* | offset | contents | size |
* +========+===============================================+======+
* | 0x0000 | H2G CTB Descriptor (send) | |
* +--------+-----------------------------------------------+ 4K |
* | 0x0800 | G2H CTB Descriptor (g2h) | |
* +--------+-----------------------------------------------+------+
* | 0x1000 | H2G CT Buffer (send) | n*4K |
* | | | |
* +--------+-----------------------------------------------+------+
* | 0x1000 | G2H CT Buffer (g2h) | m*4K |
* | + n*4K | | |
* +--------+-----------------------------------------------+------+
*
* Size of each ``CT Buffer`` must be multiple of 4K.
* We don't expect too many messages in flight at any time, unless we are
* using the GuC submission. In that case each request requires a minimum
* 2 dwords which gives us a maximum 256 queue'd requests. Hopefully this
* enough space to avoid backpressure on the driver. We increase the size
* of the receive buffer (relative to the send) to ensure a G2H response
* CTB has a landing spot.
*
* In addition to submissions, the G2H buffer needs to be able to hold
* enough space for recoverable page fault notifications. The number of
* page faults is interrupt driven and can be as much as the number of
* compute resources available. However, most of the actual work for these
* is in a separate page fault worker thread. Therefore we only need to
* make sure the queue has enough space to handle all of the submissions
* and responses and an extra buffer for incoming page faults.
*/
#define CTB_DESC_SIZE ALIGN(sizeof(struct guc_ct_buffer_desc), SZ_2K)
#define CTB_H2G_BUFFER_SIZE (SZ_4K)
#define CTB_G2H_BUFFER_SIZE (SZ_128K)
#define G2H_ROOM_BUFFER_SIZE (CTB_G2H_BUFFER_SIZE / 2)
/**
* xe_guc_ct_queue_proc_time_jiffies - Return maximum time to process a full
* CT command queue
* @ct: the &xe_guc_ct. Unused at this moment but will be used in the future.
*
* Observation is that a 4KiB buffer full of commands takes a little over a
* second to process. Use that to calculate maximum time to process a full CT
* command queue.
*
* Return: Maximum time to process a full CT queue in jiffies.
*/
long xe_guc_ct_queue_proc_time_jiffies(struct xe_guc_ct *ct)
{
BUILD_BUG_ON(!IS_ALIGNED(CTB_H2G_BUFFER_SIZE, SZ_4));
return (CTB_H2G_BUFFER_SIZE / SZ_4K) * HZ;
}
static size_t guc_ct_size(void)
{
return 2 * CTB_DESC_SIZE + CTB_H2G_BUFFER_SIZE +
CTB_G2H_BUFFER_SIZE;
}
static void guc_ct_fini(struct drm_device *drm, void *arg)
{
struct xe_guc_ct *ct = arg;
destroy_workqueue(ct->g2h_wq);
xa_destroy(&ct->fence_lookup);
}
static void receive_g2h(struct xe_guc_ct *ct);
static void g2h_worker_func(struct work_struct *w);
static void safe_mode_worker_func(struct work_struct *w);
static void primelockdep(struct xe_guc_ct *ct)
{
if (!IS_ENABLED(CONFIG_LOCKDEP))
return;
fs_reclaim_acquire(GFP_KERNEL);
might_lock(&ct->lock);
fs_reclaim_release(GFP_KERNEL);
}
int xe_guc_
|