mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
drm/amd/display: Add KUnit tests for HDCP DDC link adapters
Expose the mod_hdcp DDC adapter callbacks for KUnit and add tests: lp_write_i2c / lp_read_i2c / lp_write_dpcd / lp_read_dpcd use recording fake i2c and DP aux backends to assert the built payloads (write flag, address, length, buffer, and the read offset-then-data sequence), plus failure when the connector is missing. lp_atomic_write_poll_read_i2c / lp_atomic_write_poll_read_aux cover the hardware-free early returns (NULL link and a payload too large to convert); the success path submits fused-IO to the DMCUB and is out of reach for a unit test. Reviewed-by: Alex Hung <alex.hung@amd.com> Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com> Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com> Tested-by: Dan Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
eb5e911dff
commit
249401c325
|
|
@ -38,8 +38,7 @@
|
|||
*/
|
||||
#define PSP_SRM_VERSION_MAX 0xFFFF
|
||||
|
||||
static bool
|
||||
lp_write_i2c(void *handle, uint32_t address, const uint8_t *data, uint32_t size)
|
||||
STATIC_IFN_KUNIT bool lp_write_i2c(void *handle, uint32_t address, const uint8_t *data, uint32_t size)
|
||||
{
|
||||
struct dc_link *link = handle;
|
||||
struct i2c_payload i2c_payloads[] = {{true, address, size, (void *)data} };
|
||||
|
|
@ -48,9 +47,9 @@ lp_write_i2c(void *handle, uint32_t address, const uint8_t *data, uint32_t size)
|
|||
|
||||
return dm_helpers_submit_i2c(link->ctx, link, &cmd);
|
||||
}
|
||||
EXPORT_IF_KUNIT(lp_write_i2c);
|
||||
|
||||
static bool
|
||||
lp_read_i2c(void *handle, uint32_t address, uint8_t offset, uint8_t *data, uint32_t size)
|
||||
STATIC_IFN_KUNIT bool lp_read_i2c(void *handle, uint32_t address, uint8_t offset, uint8_t *data, uint32_t size)
|
||||
{
|
||||
struct dc_link *link = handle;
|
||||
|
||||
|
|
@ -61,50 +60,53 @@ lp_read_i2c(void *handle, uint32_t address, uint8_t offset, uint8_t *data, uint3
|
|||
|
||||
return dm_helpers_submit_i2c(link->ctx, link, &cmd);
|
||||
}
|
||||
EXPORT_IF_KUNIT(lp_read_i2c);
|
||||
|
||||
static bool
|
||||
lp_write_dpcd(void *handle, uint32_t address, const uint8_t *data, uint32_t size)
|
||||
STATIC_IFN_KUNIT bool lp_write_dpcd(void *handle, uint32_t address, const uint8_t *data, uint32_t size)
|
||||
{
|
||||
struct dc_link *link = handle;
|
||||
|
||||
return dm_helpers_dp_write_dpcd(link->ctx, link, address, data, size);
|
||||
}
|
||||
EXPORT_IF_KUNIT(lp_write_dpcd);
|
||||
|
||||
static bool
|
||||
lp_read_dpcd(void *handle, uint32_t address, uint8_t *data, uint32_t size)
|
||||
STATIC_IFN_KUNIT bool lp_read_dpcd(void *handle, uint32_t address, uint8_t *data, uint32_t size)
|
||||
{
|
||||
struct dc_link *link = handle;
|
||||
|
||||
return dm_helpers_dp_read_dpcd(link->ctx, link, address, data, size);
|
||||
}
|
||||
EXPORT_IF_KUNIT(lp_read_dpcd);
|
||||
|
||||
static bool lp_atomic_write_poll_read_i2c(
|
||||
void *handle,
|
||||
const struct mod_hdcp_atomic_op_i2c *write,
|
||||
const struct mod_hdcp_atomic_op_i2c *poll,
|
||||
struct mod_hdcp_atomic_op_i2c *read,
|
||||
uint32_t poll_timeout_us,
|
||||
uint8_t poll_mask_msb
|
||||
STATIC_IFN_KUNIT bool lp_atomic_write_poll_read_i2c(
|
||||
void *handle,
|
||||
const struct mod_hdcp_atomic_op_i2c *write,
|
||||
const struct mod_hdcp_atomic_op_i2c *poll,
|
||||
struct mod_hdcp_atomic_op_i2c *read,
|
||||
uint32_t poll_timeout_us,
|
||||
uint8_t poll_mask_msb
|
||||
)
|
||||
{
|
||||
struct dc_link *link = handle;
|
||||
|
||||
return dm_atomic_write_poll_read_i2c(link, write, poll, read, poll_timeout_us, poll_mask_msb);
|
||||
}
|
||||
EXPORT_IF_KUNIT(lp_atomic_write_poll_read_i2c);
|
||||
|
||||
static bool lp_atomic_write_poll_read_aux(
|
||||
void *handle,
|
||||
const struct mod_hdcp_atomic_op_aux *write,
|
||||
const struct mod_hdcp_atomic_op_aux *poll,
|
||||
struct mod_hdcp_atomic_op_aux *read,
|
||||
uint32_t poll_timeout_us,
|
||||
uint8_t poll_mask_msb
|
||||
STATIC_IFN_KUNIT bool lp_atomic_write_poll_read_aux(
|
||||
void *handle,
|
||||
const struct mod_hdcp_atomic_op_aux *write,
|
||||
const struct mod_hdcp_atomic_op_aux *poll,
|
||||
struct mod_hdcp_atomic_op_aux *read,
|
||||
uint32_t poll_timeout_us,
|
||||
uint8_t poll_mask_msb
|
||||
)
|
||||
{
|
||||
struct dc_link *link = handle;
|
||||
|
||||
return dm_atomic_write_poll_read_aux(link, write, poll, read, poll_timeout_us, poll_mask_msb);
|
||||
}
|
||||
EXPORT_IF_KUNIT(lp_atomic_write_poll_read_aux);
|
||||
|
||||
STATIC_IFN_KUNIT
|
||||
uint8_t *psp_get_srm(struct psp_context *psp, uint32_t *srm_version, uint32_t *srm_size)
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ struct psp_context;
|
|||
struct file;
|
||||
struct kobject;
|
||||
struct bin_attribute;
|
||||
struct mod_hdcp_atomic_op_i2c;
|
||||
struct mod_hdcp_atomic_op_aux;
|
||||
|
||||
struct hdcp_workqueue {
|
||||
struct work_struct cpirq_work;
|
||||
|
|
@ -134,6 +136,20 @@ ssize_t srm_data_write(struct file *filp, struct kobject *kobj,
|
|||
ssize_t srm_data_read(struct file *filp, struct kobject *kobj,
|
||||
const struct bin_attribute *bin_attr, char *buffer,
|
||||
loff_t pos, size_t count);
|
||||
bool lp_write_i2c(void *handle, uint32_t address, const uint8_t *data, uint32_t size);
|
||||
bool lp_read_i2c(void *handle, uint32_t address, uint8_t offset, uint8_t *data, uint32_t size);
|
||||
bool lp_write_dpcd(void *handle, uint32_t address, const uint8_t *data, uint32_t size);
|
||||
bool lp_read_dpcd(void *handle, uint32_t address, uint8_t *data, uint32_t size);
|
||||
bool lp_atomic_write_poll_read_i2c(void *handle,
|
||||
const struct mod_hdcp_atomic_op_i2c *write,
|
||||
const struct mod_hdcp_atomic_op_i2c *poll,
|
||||
struct mod_hdcp_atomic_op_i2c *read,
|
||||
uint32_t poll_timeout_us, uint8_t poll_mask_msb);
|
||||
bool lp_atomic_write_poll_read_aux(void *handle,
|
||||
const struct mod_hdcp_atomic_op_aux *write,
|
||||
const struct mod_hdcp_atomic_op_aux *poll,
|
||||
struct mod_hdcp_atomic_op_aux *read,
|
||||
uint32_t poll_timeout_us, uint8_t poll_mask_msb);
|
||||
#endif
|
||||
|
||||
#endif /* AMDGPU_DM_AMDGPU_DM_HDCP_H_ */
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
#include <linux/kobject.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_dm.h"
|
||||
|
|
@ -1461,6 +1464,369 @@ static void dm_test_srm_data_read_empty_srm_returns_zero(struct kunit *test)
|
|||
|
||||
/* End of tests for srm_data_write() and srm_data_read() */
|
||||
|
||||
/* Tests for lp_write_i2c() / lp_read_i2c() / lp_write_dpcd() / lp_read_dpcd() */
|
||||
|
||||
/* Defined further below with the display helper tests. */
|
||||
static struct amdgpu_dm_connector *alloc_test_connector(struct kunit *test,
|
||||
unsigned int index);
|
||||
|
||||
/*
|
||||
* Recording fakes for the DDC layer. The lp_* wrappers build i2c/DPCD
|
||||
* transactions and forward them through dm_helpers_*, which end up calling
|
||||
* i2c_transfer() / drm_dp_dpcd_*(). These fakes capture the resulting
|
||||
* messages so the tests can assert what the wrappers built, without touching
|
||||
* real hardware. KUnit runs cases sequentially, so file-scope capture state
|
||||
* is reset at the start of each test.
|
||||
*/
|
||||
#define FAKE_DDC_MAX_MSGS 4
|
||||
|
||||
static struct fake_i2c_capture {
|
||||
int num;
|
||||
struct i2c_msg msgs[FAKE_DDC_MAX_MSGS];
|
||||
} fake_i2c_cap;
|
||||
|
||||
static int fake_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
fake_i2c_cap.num = num;
|
||||
for (i = 0; i < num && i < FAKE_DDC_MAX_MSGS; i++)
|
||||
fake_i2c_cap.msgs[i] = msgs[i];
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static u32 fake_i2c_functionality(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm fake_i2c_algo = {
|
||||
.master_xfer = fake_i2c_master_xfer,
|
||||
.functionality = fake_i2c_functionality,
|
||||
};
|
||||
|
||||
static void fake_i2c_lock_bus(struct i2c_adapter *adap, unsigned int flags) {}
|
||||
static int fake_i2c_trylock_bus(struct i2c_adapter *adap, unsigned int flags)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
static void fake_i2c_unlock_bus(struct i2c_adapter *adap, unsigned int flags) {}
|
||||
|
||||
static const struct i2c_lock_operations fake_i2c_lock_ops = {
|
||||
.lock_bus = fake_i2c_lock_bus,
|
||||
.trylock_bus = fake_i2c_trylock_bus,
|
||||
.unlock_bus = fake_i2c_unlock_bus,
|
||||
};
|
||||
|
||||
static struct fake_aux_capture {
|
||||
int calls;
|
||||
u8 request;
|
||||
unsigned int address;
|
||||
size_t size;
|
||||
} fake_aux_cap;
|
||||
|
||||
static ssize_t fake_aux_transfer(struct drm_dp_aux *aux,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
fake_aux_cap.calls++;
|
||||
fake_aux_cap.request = msg->request;
|
||||
fake_aux_cap.address = msg->address;
|
||||
fake_aux_cap.size = msg->size;
|
||||
msg->reply = DP_AUX_NATIVE_REPLY_ACK;
|
||||
|
||||
return msg->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_test_ddc_link - connector/link wired to the recording i2c + aux fakes
|
||||
* @test: KUnit test context for managed allocation
|
||||
*
|
||||
* Builds an amdgpu_dm_connector with a fake i2c adapter and a fake DP aux, and
|
||||
* points link->priv at the connector so dm_helpers_* find it. Returns the
|
||||
* dc_link that the lp_* wrappers take as their opaque handle.
|
||||
*/
|
||||
static struct dc_link *alloc_test_ddc_link(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_connector *aconnector = alloc_test_connector(test, 0);
|
||||
struct amdgpu_i2c_adapter *i2c;
|
||||
struct dc_link *link;
|
||||
|
||||
KUNIT_ASSERT_NOT_NULL(test, aconnector);
|
||||
|
||||
i2c = kunit_kzalloc(test, sizeof(*i2c), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, i2c);
|
||||
i2c->base.algo = &fake_i2c_algo;
|
||||
i2c->base.lock_ops = &fake_i2c_lock_ops;
|
||||
aconnector->i2c = i2c;
|
||||
|
||||
mutex_init(&aconnector->dm_dp_aux.aux.hw_mutex);
|
||||
aconnector->dm_dp_aux.aux.transfer = fake_aux_transfer;
|
||||
/* Skip the DPCD "throw away" probe read so we capture only our access. */
|
||||
aconnector->dm_dp_aux.aux.dpcd_probe_disabled = true;
|
||||
|
||||
link = aconnector->dc_link;
|
||||
link->priv = aconnector;
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_lp_write_i2c_builds_single_write_payload - write builds one i2c msg
|
||||
* @test: KUnit test context
|
||||
*
|
||||
* lp_write_i2c() must forward a single write payload carrying the address,
|
||||
* length and data buffer unchanged.
|
||||
*/
|
||||
static void dm_test_lp_write_i2c_builds_single_write_payload(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_ddc_link(test);
|
||||
u8 data[3] = {0x11, 0x22, 0x33};
|
||||
bool ok;
|
||||
|
||||
memset(&fake_i2c_cap, 0, sizeof(fake_i2c_cap));
|
||||
|
||||
ok = lp_write_i2c(link, 0x3a, data, sizeof(data));
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_ASSERT_EQ(test, fake_i2c_cap.num, 1);
|
||||
/* write => flags without I2C_M_RD */
|
||||
KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[0].flags, 0);
|
||||
KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[0].addr, 0x3a);
|
||||
KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[0].len, (int)sizeof(data));
|
||||
KUNIT_EXPECT_PTR_EQ(test, fake_i2c_cap.msgs[0].buf, (void *)data);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_lp_read_i2c_builds_offset_then_read - read builds offset + read msgs
|
||||
* @test: KUnit test context
|
||||
*
|
||||
* lp_read_i2c() must build a 1-byte write of the offset followed by a
|
||||
* size-byte read into the caller buffer, both at the same address.
|
||||
*/
|
||||
static void dm_test_lp_read_i2c_builds_offset_then_read(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_ddc_link(test);
|
||||
u8 data[4];
|
||||
bool ok;
|
||||
|
||||
memset(&fake_i2c_cap, 0, sizeof(fake_i2c_cap));
|
||||
|
||||
ok = lp_read_i2c(link, 0x50, 0x07, data, sizeof(data));
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_ASSERT_EQ(test, fake_i2c_cap.num, 2);
|
||||
/* first: 1-byte write of the offset */
|
||||
KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[0].flags, 0);
|
||||
KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[0].addr, 0x50);
|
||||
KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[0].len, 1);
|
||||
/* second: size-byte read into the caller buffer */
|
||||
KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[1].flags, I2C_M_RD);
|
||||
KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[1].addr, 0x50);
|
||||
KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[1].len, (int)sizeof(data));
|
||||
KUNIT_EXPECT_PTR_EQ(test, fake_i2c_cap.msgs[1].buf, (void *)data);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_lp_write_dpcd_forwards_native_write - write forwards a native write
|
||||
* @test: KUnit test context
|
||||
*
|
||||
* lp_write_dpcd() must issue a single DP_AUX_NATIVE_WRITE at the requested
|
||||
* address for the requested size.
|
||||
*/
|
||||
static void dm_test_lp_write_dpcd_forwards_native_write(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_ddc_link(test);
|
||||
u8 data[2] = {0xDE, 0xAD};
|
||||
bool ok;
|
||||
|
||||
memset(&fake_aux_cap, 0, sizeof(fake_aux_cap));
|
||||
|
||||
ok = lp_write_dpcd(link, 0x68000, data, sizeof(data));
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, fake_aux_cap.calls, 1);
|
||||
KUNIT_EXPECT_EQ(test, (int)fake_aux_cap.request, DP_AUX_NATIVE_WRITE);
|
||||
KUNIT_EXPECT_EQ(test, fake_aux_cap.address, 0x68000u);
|
||||
KUNIT_EXPECT_EQ(test, (int)fake_aux_cap.size, (int)sizeof(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_lp_read_dpcd_forwards_native_read - read forwards a native read
|
||||
* @test: KUnit test context
|
||||
*
|
||||
* lp_read_dpcd() must issue a single DP_AUX_NATIVE_READ at the requested
|
||||
* address for the requested size.
|
||||
*/
|
||||
static void dm_test_lp_read_dpcd_forwards_native_read(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_ddc_link(test);
|
||||
u8 data[4];
|
||||
bool ok;
|
||||
|
||||
memset(&fake_aux_cap, 0, sizeof(fake_aux_cap));
|
||||
|
||||
ok = lp_read_dpcd(link, 0x00220, data, sizeof(data));
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, fake_aux_cap.calls, 1);
|
||||
KUNIT_EXPECT_EQ(test, (int)fake_aux_cap.request, DP_AUX_NATIVE_READ);
|
||||
KUNIT_EXPECT_EQ(test, fake_aux_cap.address, 0x00220u);
|
||||
KUNIT_EXPECT_EQ(test, (int)fake_aux_cap.size, (int)sizeof(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_lp_write_i2c_no_connector_returns_false - missing connector fails
|
||||
* @test: KUnit test context
|
||||
*
|
||||
* When link->priv has no connector, dm_helpers_submit_i2c() cannot proceed,
|
||||
* so lp_write_i2c() must report failure without invoking the adapter.
|
||||
*/
|
||||
static void dm_test_lp_write_i2c_no_connector_returns_false(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_ddc_link(test);
|
||||
u8 data[2] = {0x01, 0x02};
|
||||
bool ok;
|
||||
|
||||
link->priv = NULL;
|
||||
memset(&fake_i2c_cap, 0, sizeof(fake_i2c_cap));
|
||||
|
||||
ok = lp_write_i2c(link, 0x3a, data, sizeof(data));
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, fake_i2c_cap.num, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_lp_read_dpcd_no_connector_returns_false - missing connector fails
|
||||
* @test: KUnit test context
|
||||
*
|
||||
* When link->priv has no connector, dm_helpers_dp_read_dpcd() cannot proceed,
|
||||
* so lp_read_dpcd() must report failure without invoking the aux transfer.
|
||||
*/
|
||||
static void dm_test_lp_read_dpcd_no_connector_returns_false(struct kunit *test)
|
||||
{
|
||||
struct dc_link *link = alloc_test_ddc_link(test);
|
||||
u8 data[4];
|
||||
bool ok;
|
||||
|
||||
link->priv = NULL;
|
||||
memset(&fake_aux_cap, 0, sizeof(fake_aux_cap));
|
||||
|
||||
ok = lp_read_dpcd(link, 0x00220, data, sizeof(data));
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, ok);
|
||||
KUNIT_EXPECT_EQ(test, fake_aux_cap.calls, 0);
|
||||
}
|
||||
|
||||
/* End of tests for lp_write_i2c() / lp_read_i2c() / lp_write_dpcd() / lp_read_dpcd() */
|
||||
|
||||
/*
|
||||
* Tests for lp_atomic_write_poll_read_i2c() / lp_atomic_write_poll_read_aux()
|
||||
*
|
||||
* These wrappers cast the opaque handle to a dc_link and forward to the
|
||||
* dc_fused_io helpers. The success path submits a fused-IO command sequence to
|
||||
* the DMCUB, which is out of reach for a unit test, so the coverage here is the
|
||||
* hardware-free early returns: a NULL link and a payload that fails conversion
|
||||
* (op size larger than the fused request buffer).
|
||||
*/
|
||||
|
||||
/**
|
||||
* dm_test_lp_atomic_i2c_null_handle_returns_false - NULL link fails cleanly
|
||||
* @test: KUnit test context
|
||||
*
|
||||
* With a NULL handle the forwarded dc_link is NULL, so the helper must return
|
||||
* false without dereferencing anything.
|
||||
*/
|
||||
static void dm_test_lp_atomic_i2c_null_handle_returns_false(struct kunit *test)
|
||||
{
|
||||
struct mod_hdcp_atomic_op_i2c op = { 0 };
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
lp_atomic_write_poll_read_i2c(NULL, &op, &op, &op, 0, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_lp_atomic_i2c_oversized_op_returns_false - bad payload fails conversion
|
||||
* @test: KUnit test context
|
||||
*
|
||||
* An op whose size exceeds the fused request buffer must fail conversion, so
|
||||
* the helper returns false before any fused-IO submission. no_ddc_pin routes
|
||||
* the DDC line through aux_hw_inst, avoiding the GPIO pin dereference.
|
||||
*/
|
||||
static void dm_test_lp_atomic_i2c_oversized_op_returns_false(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_connector *aconnector = alloc_test_connector(test, 0);
|
||||
struct mod_hdcp_atomic_op_i2c write = { .size = 0x100 };
|
||||
struct mod_hdcp_atomic_op_i2c op = { 0 };
|
||||
struct dc_link *link;
|
||||
|
||||
KUNIT_ASSERT_NOT_NULL(test, aconnector);
|
||||
|
||||
link = aconnector->dc_link;
|
||||
link->no_ddc_pin = true;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
lp_atomic_write_poll_read_i2c(link, &write, &op, &op, 0, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_lp_atomic_aux_null_handle_returns_false - NULL link fails cleanly
|
||||
* @test: KUnit test context
|
||||
*
|
||||
* With a NULL handle the forwarded dc_link is NULL, so the helper must return
|
||||
* false without dereferencing anything.
|
||||
*/
|
||||
static void dm_test_lp_atomic_aux_null_handle_returns_false(struct kunit *test)
|
||||
{
|
||||
struct mod_hdcp_atomic_op_aux op = { 0 };
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
lp_atomic_write_poll_read_aux(NULL, &op, &op, &op, 0, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_lp_atomic_aux_oversized_op_returns_false - bad payload fails conversion
|
||||
* @test: KUnit test context
|
||||
*
|
||||
* The aux helper reads the DDC line from link->ddc->ddc_pin->pin_data before
|
||||
* converting, so a minimal pin chain is wired up. An op larger than the fused
|
||||
* request buffer then fails conversion and the helper returns false without
|
||||
* any fused-IO submission.
|
||||
*/
|
||||
static void dm_test_lp_atomic_aux_oversized_op_returns_false(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_dm_connector *aconnector = alloc_test_connector(test, 0);
|
||||
struct mod_hdcp_atomic_op_aux write = { .size = 0x100 };
|
||||
struct mod_hdcp_atomic_op_aux op = { 0 };
|
||||
struct ddc_service *ddc;
|
||||
struct ddc *ddc_pin;
|
||||
struct dc_link *link;
|
||||
void *pin_data;
|
||||
|
||||
KUNIT_ASSERT_NOT_NULL(test, aconnector);
|
||||
|
||||
ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ddc);
|
||||
ddc_pin = kunit_kzalloc(test, sizeof(*ddc_pin), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ddc_pin);
|
||||
/* Only ->en is read; over-allocate so struct gpio stays opaque here. */
|
||||
pin_data = kunit_kzalloc(test, 128, GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, pin_data);
|
||||
|
||||
ddc_pin->pin_data = pin_data;
|
||||
ddc->ddc_pin = ddc_pin;
|
||||
|
||||
link = aconnector->dc_link;
|
||||
link->ddc = ddc;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
lp_atomic_write_poll_read_aux(link, &write, &op, &op, 0, 0));
|
||||
}
|
||||
|
||||
/* End of tests for lp_atomic_write_poll_read_i2c() / lp_atomic_write_poll_read_aux() */
|
||||
|
||||
/*
|
||||
* Tests for hdcp_update_display() / hdcp_remove_display() /
|
||||
* hdcp_reset_display().
|
||||
|
|
@ -1994,6 +2360,18 @@ static struct kunit_case dm_hdcp_test_cases[] = {
|
|||
KUNIT_CASE(dm_test_srm_data_write_uninitialized_ta_keeps_srm),
|
||||
KUNIT_CASE(dm_test_srm_data_read_uninitialized_ta_returns_einval),
|
||||
KUNIT_CASE(dm_test_srm_data_read_empty_srm_returns_zero),
|
||||
/* lp_write_i2c() / lp_read_i2c() / lp_write_dpcd() / lp_read_dpcd() */
|
||||
KUNIT_CASE(dm_test_lp_write_i2c_builds_single_write_payload),
|
||||
KUNIT_CASE(dm_test_lp_read_i2c_builds_offset_then_read),
|
||||
KUNIT_CASE(dm_test_lp_write_dpcd_forwards_native_write),
|
||||
KUNIT_CASE(dm_test_lp_read_dpcd_forwards_native_read),
|
||||
KUNIT_CASE(dm_test_lp_write_i2c_no_connector_returns_false),
|
||||
KUNIT_CASE(dm_test_lp_read_dpcd_no_connector_returns_false),
|
||||
/* lp_atomic_write_poll_read_i2c() / lp_atomic_write_poll_read_aux() */
|
||||
KUNIT_CASE(dm_test_lp_atomic_i2c_null_handle_returns_false),
|
||||
KUNIT_CASE(dm_test_lp_atomic_i2c_oversized_op_returns_false),
|
||||
KUNIT_CASE(dm_test_lp_atomic_aux_null_handle_returns_false),
|
||||
KUNIT_CASE(dm_test_lp_atomic_aux_oversized_op_returns_false),
|
||||
/* hdcp_update_display() / hdcp_remove_display() / hdcp_reset_display() */
|
||||
KUNIT_CASE(dm_test_hdcp_update_display_enable_registers_connector),
|
||||
KUNIT_CASE(dm_test_hdcp_update_display_disable_sets_status_off),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user