xref: /linux/drivers/spi/tests/spi-dma-kunit.c (revision 307b9ddbbcf987db77d52da6f9ff5b4096ac9599)
1*9b81a87cSHonghui Jiang // SPDX-License-Identifier: GPL-2.0
2*9b81a87cSHonghui Jiang // KUnit tests for the SPI core DMA mapping error paths.
3*9b81a87cSHonghui Jiang //
4*9b81a87cSHonghui Jiang // A mapping error must clear all SG tables and *_sg_mapped flags while
5*9b81a87cSHonghui Jiang // cur_{tx,rx}_dma_dev identify the devices used for the attempted mapping.
6*9b81a87cSHonghui Jiang // Zero-length transfers make sg_alloc_table() fail with -EINVAL, providing
7*9b81a87cSHonghui Jiang // deterministic failure injection without test hooks.
8*9b81a87cSHonghui Jiang 
9*9b81a87cSHonghui Jiang #include <kunit/device.h>
10*9b81a87cSHonghui Jiang #include <kunit/test.h>
11*9b81a87cSHonghui Jiang #include <linux/dma-mapping.h>
12*9b81a87cSHonghui Jiang #include <linux/limits.h>
13*9b81a87cSHonghui Jiang #include <linux/spi/spi.h>
14*9b81a87cSHonghui Jiang 
15*9b81a87cSHonghui Jiang #include "../internals.h"
16*9b81a87cSHonghui Jiang 
17*9b81a87cSHonghui Jiang MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
18*9b81a87cSHonghui Jiang 
19*9b81a87cSHonghui Jiang #define SPI_DMA_TEST_LEN		256
20*9b81a87cSHonghui Jiang #define SPI_DMA_TEST_XFERS		2
21*9b81a87cSHonghui Jiang 
22*9b81a87cSHonghui Jiang struct spi_dma_test_ctx {
23*9b81a87cSHonghui Jiang 	struct spi_controller	*ctlr;
24*9b81a87cSHonghui Jiang 	struct spi_device	*spi;
25*9b81a87cSHonghui Jiang 	struct device		*dma_dev;
26*9b81a87cSHonghui Jiang 	struct device		*stale_dma_dev;
27*9b81a87cSHonghui Jiang 	struct spi_transfer	xfer[SPI_DMA_TEST_XFERS];
28*9b81a87cSHonghui Jiang 	struct spi_message	msg;
29*9b81a87cSHonghui Jiang 	void			*buf[SPI_DMA_TEST_XFERS * 2];
30*9b81a87cSHonghui Jiang };
31*9b81a87cSHonghui Jiang 
32*9b81a87cSHonghui Jiang static bool spi_dma_test_can_dma(struct spi_controller *ctlr,
33*9b81a87cSHonghui Jiang 				 struct spi_device *spi,
34*9b81a87cSHonghui Jiang 				 struct spi_transfer *xfer)
35*9b81a87cSHonghui Jiang {
36*9b81a87cSHonghui Jiang 	/* Opt every transfer into the core DMA mapping path. */
37*9b81a87cSHonghui Jiang 	return true;
38*9b81a87cSHonghui Jiang }
39*9b81a87cSHonghui Jiang 
40*9b81a87cSHonghui Jiang /*
41*9b81a87cSHonghui Jiang  * A bare controller is sufficient because the mapping helpers do not
42*9b81a87cSHonghui Jiang  * dereference ctlr->dev. With dma_tx and dma_rx unset, both directions use
43*9b81a87cSHonghui Jiang  * dma_map_dev, so the controller need not be registered.
44*9b81a87cSHonghui Jiang  */
45*9b81a87cSHonghui Jiang static struct spi_dma_test_ctx *spi_dma_test_ctx_new(struct kunit *test)
46*9b81a87cSHonghui Jiang {
47*9b81a87cSHonghui Jiang 	struct spi_dma_test_ctx *ctx;
48*9b81a87cSHonghui Jiang 
49*9b81a87cSHonghui Jiang 	ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
50*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
51*9b81a87cSHonghui Jiang 
52*9b81a87cSHonghui Jiang 	ctx->dma_dev = kunit_device_register(test, "spi-dma-error-path");
53*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->dma_dev);
54*9b81a87cSHonghui Jiang 	ctx->stale_dma_dev =
55*9b81a87cSHonghui Jiang 		kunit_device_register(test, "spi-dma-stale-device");
56*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->stale_dma_dev);
57*9b81a87cSHonghui Jiang 
58*9b81a87cSHonghui Jiang 	/* Keep both devices valid if an assertion aborts the test. */
59*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_EQ(test, 0,
60*9b81a87cSHonghui Jiang 			dma_coerce_mask_and_coherent(ctx->dma_dev,
61*9b81a87cSHonghui Jiang 						     DMA_BIT_MASK(64)));
62*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_EQ(test, 0,
63*9b81a87cSHonghui Jiang 			dma_coerce_mask_and_coherent(ctx->stale_dma_dev,
64*9b81a87cSHonghui Jiang 						     DMA_BIT_MASK(64)));
65*9b81a87cSHonghui Jiang 
66*9b81a87cSHonghui Jiang 	ctx->ctlr = kunit_kzalloc(test, sizeof(*ctx->ctlr), GFP_KERNEL);
67*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->ctlr);
68*9b81a87cSHonghui Jiang 
69*9b81a87cSHonghui Jiang 	ctx->spi = kunit_kzalloc(test, sizeof(*ctx->spi), GFP_KERNEL);
70*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->spi);
71*9b81a87cSHonghui Jiang 
72*9b81a87cSHonghui Jiang 	ctx->ctlr->can_dma = spi_dma_test_can_dma;
73*9b81a87cSHonghui Jiang 	ctx->ctlr->dma_map_dev = ctx->dma_dev;
74*9b81a87cSHonghui Jiang 	/* Normally initialized by spi_register_controller(). */
75*9b81a87cSHonghui Jiang 	ctx->ctlr->max_dma_len = INT_MAX;
76*9b81a87cSHonghui Jiang 
77*9b81a87cSHonghui Jiang 	ctx->spi->controller = ctx->ctlr;
78*9b81a87cSHonghui Jiang 	spi_message_init(&ctx->msg);
79*9b81a87cSHonghui Jiang 	ctx->msg.spi = ctx->spi;
80*9b81a87cSHonghui Jiang 
81*9b81a87cSHonghui Jiang 	return ctx;
82*9b81a87cSHonghui Jiang }
83*9b81a87cSHonghui Jiang 
84*9b81a87cSHonghui Jiang static void *spi_dma_test_buf(struct kunit *test, struct spi_dma_test_ctx *ctx,
85*9b81a87cSHonghui Jiang 			      unsigned int slot)
86*9b81a87cSHonghui Jiang {
87*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_LT(test, slot, ARRAY_SIZE(ctx->buf));
88*9b81a87cSHonghui Jiang 
89*9b81a87cSHonghui Jiang 	ctx->buf[slot] = kunit_kzalloc(test, SPI_DMA_TEST_LEN, GFP_KERNEL);
90*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->buf[slot]);
91*9b81a87cSHonghui Jiang 
92*9b81a87cSHonghui Jiang 	return ctx->buf[slot];
93*9b81a87cSHonghui Jiang }
94*9b81a87cSHonghui Jiang 
95*9b81a87cSHonghui Jiang /*
96*9b81a87cSHonghui Jiang  * Emulate DMA devices retained from an earlier message. Using valid devices
97*9b81a87cSHonghui Jiang  * also lets the unfixed path reach the assertions instead of dereferencing
98*9b81a87cSHonghui Jiang  * NULL during cleanup.
99*9b81a87cSHonghui Jiang  */
100*9b81a87cSHonghui Jiang static void spi_dma_test_pin_stale_dma_devs(struct spi_dma_test_ctx *ctx)
101*9b81a87cSHonghui Jiang {
102*9b81a87cSHonghui Jiang 	ctx->ctlr->cur_tx_dma_dev = ctx->stale_dma_dev;
103*9b81a87cSHonghui Jiang 	ctx->ctlr->cur_rx_dma_dev = ctx->stale_dma_dev;
104*9b81a87cSHonghui Jiang }
105*9b81a87cSHonghui Jiang 
106*9b81a87cSHonghui Jiang static void spi_dma_test_assert_dma_devs_published(struct kunit *test,
107*9b81a87cSHonghui Jiang 						   struct spi_dma_test_ctx *ctx)
108*9b81a87cSHonghui Jiang {
109*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_PTR_EQ(test, ctx->ctlr->cur_tx_dma_dev, ctx->dma_dev);
110*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_PTR_EQ(test, ctx->ctlr->cur_rx_dma_dev, ctx->dma_dev);
111*9b81a87cSHonghui Jiang }
112*9b81a87cSHonghui Jiang 
113*9b81a87cSHonghui Jiang static void spi_dma_test_assert_nothing_mapped(struct kunit *test,
114*9b81a87cSHonghui Jiang 					       struct spi_dma_test_ctx *ctx,
115*9b81a87cSHonghui Jiang 					       unsigned int nr_xfers)
116*9b81a87cSHonghui Jiang {
117*9b81a87cSHonghui Jiang 	unsigned int i;
118*9b81a87cSHonghui Jiang 
119*9b81a87cSHonghui Jiang 	for (i = 0; i < nr_xfers; i++) {
120*9b81a87cSHonghui Jiang 		KUNIT_ASSERT_FALSE_MSG(test, ctx->xfer[i].tx_sg_mapped,
121*9b81a87cSHonghui Jiang 				       "xfer[%u] still claims a TX mapping after __spi_map_msg() failed",
122*9b81a87cSHonghui Jiang 				       i);
123*9b81a87cSHonghui Jiang 		KUNIT_ASSERT_FALSE_MSG(test, ctx->xfer[i].rx_sg_mapped,
124*9b81a87cSHonghui Jiang 				       "xfer[%u] still claims an RX mapping after __spi_map_msg() failed",
125*9b81a87cSHonghui Jiang 				       i);
126*9b81a87cSHonghui Jiang 		KUNIT_EXPECT_NULL(test, ctx->xfer[i].tx_sg.sgl);
127*9b81a87cSHonghui Jiang 		KUNIT_EXPECT_EQ(test, ctx->xfer[i].tx_sg.orig_nents, 0U);
128*9b81a87cSHonghui Jiang 		KUNIT_EXPECT_EQ(test, ctx->xfer[i].tx_sg.nents, 0U);
129*9b81a87cSHonghui Jiang 		KUNIT_EXPECT_NULL(test, ctx->xfer[i].rx_sg.sgl);
130*9b81a87cSHonghui Jiang 		KUNIT_EXPECT_EQ(test, ctx->xfer[i].rx_sg.orig_nents, 0U);
131*9b81a87cSHonghui Jiang 		KUNIT_EXPECT_EQ(test, ctx->xfer[i].rx_sg.nents, 0U);
132*9b81a87cSHonghui Jiang 	}
133*9b81a87cSHonghui Jiang }
134*9b81a87cSHonghui Jiang 
135*9b81a87cSHonghui Jiang /*
136*9b81a87cSHonghui Jiang  * xfer0 maps TX and RX; zero-length xfer1 then fails its TX mapping.
137*9b81a87cSHonghui Jiang  * The failure must unwind xfer0 and update cur_*_dma_dev.
138*9b81a87cSHonghui Jiang  */
139*9b81a87cSHonghui Jiang static void spi_dma_later_tx_fail_rolls_back_earlier(struct kunit *test)
140*9b81a87cSHonghui Jiang {
141*9b81a87cSHonghui Jiang 	struct spi_dma_test_ctx *ctx = spi_dma_test_ctx_new(test);
142*9b81a87cSHonghui Jiang 	int ret;
143*9b81a87cSHonghui Jiang 
144*9b81a87cSHonghui Jiang 	ctx->xfer[0].tx_buf = spi_dma_test_buf(test, ctx, 0);
145*9b81a87cSHonghui Jiang 	ctx->xfer[0].rx_buf = spi_dma_test_buf(test, ctx, 1);
146*9b81a87cSHonghui Jiang 	ctx->xfer[0].len = SPI_DMA_TEST_LEN;
147*9b81a87cSHonghui Jiang 
148*9b81a87cSHonghui Jiang 	ctx->xfer[1].tx_buf = spi_dma_test_buf(test, ctx, 2);
149*9b81a87cSHonghui Jiang 	ctx->xfer[1].rx_buf = NULL;
150*9b81a87cSHonghui Jiang 	ctx->xfer[1].len = 0;			/* forces -EINVAL */
151*9b81a87cSHonghui Jiang 
152*9b81a87cSHonghui Jiang 	spi_message_add_tail(&ctx->xfer[0], &ctx->msg);
153*9b81a87cSHonghui Jiang 	spi_message_add_tail(&ctx->xfer[1], &ctx->msg);
154*9b81a87cSHonghui Jiang 
155*9b81a87cSHonghui Jiang 	spi_dma_test_pin_stale_dma_devs(ctx);
156*9b81a87cSHonghui Jiang 
157*9b81a87cSHonghui Jiang 	ret = __spi_map_msg(ctx->ctlr, &ctx->msg);
158*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_EQ(test, ret, -EINVAL);
159*9b81a87cSHonghui Jiang 
160*9b81a87cSHonghui Jiang 	spi_dma_test_assert_dma_devs_published(test, ctx);
161*9b81a87cSHonghui Jiang 	spi_dma_test_assert_nothing_mapped(test, ctx, SPI_DMA_TEST_XFERS);
162*9b81a87cSHonghui Jiang 
163*9b81a87cSHonghui Jiang 	KUNIT_EXPECT_EQ(test, 0, __spi_unmap_msg(ctx->ctlr, &ctx->msg));
164*9b81a87cSHonghui Jiang }
165*9b81a87cSHonghui Jiang 
166*9b81a87cSHonghui Jiang /*
167*9b81a87cSHonghui Jiang  * xfer0 maps TX and RX; zero-length RX-only xfer1 then fails.
168*9b81a87cSHonghui Jiang  * The failure must unwind xfer0 without leaving either mapping flag set.
169*9b81a87cSHonghui Jiang  */
170*9b81a87cSHonghui Jiang static void spi_dma_later_rx_fail_rolls_back_earlier(struct kunit *test)
171*9b81a87cSHonghui Jiang {
172*9b81a87cSHonghui Jiang 	struct spi_dma_test_ctx *ctx = spi_dma_test_ctx_new(test);
173*9b81a87cSHonghui Jiang 	int ret;
174*9b81a87cSHonghui Jiang 
175*9b81a87cSHonghui Jiang 	ctx->xfer[0].tx_buf = spi_dma_test_buf(test, ctx, 0);
176*9b81a87cSHonghui Jiang 	ctx->xfer[0].rx_buf = spi_dma_test_buf(test, ctx, 1);
177*9b81a87cSHonghui Jiang 	ctx->xfer[0].len = SPI_DMA_TEST_LEN;
178*9b81a87cSHonghui Jiang 
179*9b81a87cSHonghui Jiang 	ctx->xfer[1].tx_buf = NULL;
180*9b81a87cSHonghui Jiang 	ctx->xfer[1].rx_buf = spi_dma_test_buf(test, ctx, 2);
181*9b81a87cSHonghui Jiang 	ctx->xfer[1].len = 0;			/* forces -EINVAL */
182*9b81a87cSHonghui Jiang 
183*9b81a87cSHonghui Jiang 	spi_message_add_tail(&ctx->xfer[0], &ctx->msg);
184*9b81a87cSHonghui Jiang 	spi_message_add_tail(&ctx->xfer[1], &ctx->msg);
185*9b81a87cSHonghui Jiang 
186*9b81a87cSHonghui Jiang 	spi_dma_test_pin_stale_dma_devs(ctx);
187*9b81a87cSHonghui Jiang 
188*9b81a87cSHonghui Jiang 	ret = __spi_map_msg(ctx->ctlr, &ctx->msg);
189*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_EQ(test, ret, -EINVAL);
190*9b81a87cSHonghui Jiang 
191*9b81a87cSHonghui Jiang 	spi_dma_test_assert_dma_devs_published(test, ctx);
192*9b81a87cSHonghui Jiang 	spi_dma_test_assert_nothing_mapped(test, ctx, SPI_DMA_TEST_XFERS);
193*9b81a87cSHonghui Jiang 
194*9b81a87cSHonghui Jiang 	KUNIT_EXPECT_EQ(test, 0, __spi_unmap_msg(ctx->ctlr, &ctx->msg));
195*9b81a87cSHonghui Jiang }
196*9b81a87cSHonghui Jiang 
197*9b81a87cSHonghui Jiang /* Ensure the error unwind does not affect successful mappings. */
198*9b81a87cSHonghui Jiang static void spi_dma_map_success_publishes_dma_devs(struct kunit *test)
199*9b81a87cSHonghui Jiang {
200*9b81a87cSHonghui Jiang 	struct spi_dma_test_ctx *ctx = spi_dma_test_ctx_new(test);
201*9b81a87cSHonghui Jiang 	int ret;
202*9b81a87cSHonghui Jiang 
203*9b81a87cSHonghui Jiang 	ctx->xfer[0].tx_buf = spi_dma_test_buf(test, ctx, 0);
204*9b81a87cSHonghui Jiang 	ctx->xfer[0].rx_buf = spi_dma_test_buf(test, ctx, 1);
205*9b81a87cSHonghui Jiang 	ctx->xfer[0].len = SPI_DMA_TEST_LEN;
206*9b81a87cSHonghui Jiang 
207*9b81a87cSHonghui Jiang 	spi_message_add_tail(&ctx->xfer[0], &ctx->msg);
208*9b81a87cSHonghui Jiang 
209*9b81a87cSHonghui Jiang 	ret = __spi_map_msg(ctx->ctlr, &ctx->msg);
210*9b81a87cSHonghui Jiang 	KUNIT_ASSERT_EQ(test, ret, 0);
211*9b81a87cSHonghui Jiang 
212*9b81a87cSHonghui Jiang 	KUNIT_EXPECT_TRUE(test, ctx->xfer[0].tx_sg_mapped);
213*9b81a87cSHonghui Jiang 	KUNIT_EXPECT_TRUE(test, ctx->xfer[0].rx_sg_mapped);
214*9b81a87cSHonghui Jiang 	KUNIT_EXPECT_PTR_EQ(test, ctx->ctlr->cur_tx_dma_dev, ctx->dma_dev);
215*9b81a87cSHonghui Jiang 	KUNIT_EXPECT_PTR_EQ(test, ctx->ctlr->cur_rx_dma_dev, ctx->dma_dev);
216*9b81a87cSHonghui Jiang 
217*9b81a87cSHonghui Jiang 	KUNIT_EXPECT_EQ(test, 0, __spi_unmap_msg(ctx->ctlr, &ctx->msg));
218*9b81a87cSHonghui Jiang 
219*9b81a87cSHonghui Jiang 	KUNIT_EXPECT_FALSE(test, ctx->xfer[0].tx_sg_mapped);
220*9b81a87cSHonghui Jiang 	KUNIT_EXPECT_FALSE(test, ctx->xfer[0].rx_sg_mapped);
221*9b81a87cSHonghui Jiang 	KUNIT_EXPECT_NULL(test, ctx->xfer[0].tx_sg.sgl);
222*9b81a87cSHonghui Jiang 	KUNIT_EXPECT_NULL(test, ctx->xfer[0].rx_sg.sgl);
223*9b81a87cSHonghui Jiang }
224*9b81a87cSHonghui Jiang 
225*9b81a87cSHonghui Jiang /* A transfer without buffers requires no DMA mapping. */
226*9b81a87cSHonghui Jiang static void spi_dma_map_nothing_is_success(struct kunit *test)
227*9b81a87cSHonghui Jiang {
228*9b81a87cSHonghui Jiang 	struct spi_dma_test_ctx *ctx = spi_dma_test_ctx_new(test);
229*9b81a87cSHonghui Jiang 	int ret;
230*9b81a87cSHonghui Jiang 
231*9b81a87cSHonghui Jiang 	ctx->xfer[0].tx_buf = NULL;
232*9b81a87cSHonghui Jiang 	ctx->xfer[0].rx_buf = NULL;
233*9b81a87cSHonghui Jiang 	ctx->xfer[0].len = SPI_DMA_TEST_LEN;
234*9b81a87cSHonghui Jiang 
235*9b81a87cSHonghui Jiang 	spi_message_add_tail(&ctx->xfer[0], &ctx->msg);
236*9b81a87cSHonghui Jiang 
237*9b81a87cSHonghui Jiang 	ret = __spi_map_msg(ctx->ctlr, &ctx->msg);
238*9b81a87cSHonghui Jiang 	KUNIT_EXPECT_EQ(test, ret, 0);
239*9b81a87cSHonghui Jiang 
240*9b81a87cSHonghui Jiang 	spi_dma_test_assert_nothing_mapped(test, ctx, 1);
241*9b81a87cSHonghui Jiang }
242*9b81a87cSHonghui Jiang 
243*9b81a87cSHonghui Jiang static struct kunit_case spi_dma_error_path_cases[] = {
244*9b81a87cSHonghui Jiang 	KUNIT_CASE(spi_dma_later_tx_fail_rolls_back_earlier),
245*9b81a87cSHonghui Jiang 	KUNIT_CASE(spi_dma_later_rx_fail_rolls_back_earlier),
246*9b81a87cSHonghui Jiang 	KUNIT_CASE(spi_dma_map_success_publishes_dma_devs),
247*9b81a87cSHonghui Jiang 	KUNIT_CASE(spi_dma_map_nothing_is_success),
248*9b81a87cSHonghui Jiang 	{}
249*9b81a87cSHonghui Jiang };
250*9b81a87cSHonghui Jiang 
251*9b81a87cSHonghui Jiang static struct kunit_suite spi_dma_error_path_suite = {
252*9b81a87cSHonghui Jiang 	.name = "spi_dma",
253*9b81a87cSHonghui Jiang 	.test_cases = spi_dma_error_path_cases,
254*9b81a87cSHonghui Jiang };
255*9b81a87cSHonghui Jiang 
256*9b81a87cSHonghui Jiang kunit_test_suite(spi_dma_error_path_suite);
257*9b81a87cSHonghui Jiang 
258*9b81a87cSHonghui Jiang MODULE_DESCRIPTION("KUnit tests for SPI core DMA mapping");
259*9b81a87cSHonghui Jiang MODULE_LICENSE("GPL");
260