xref: /linux/drivers/mmc/host/mmc_hsq.c (revision 8cb0606271a9102f1ccac34e9fc9ee76f350a2ab)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *
4  * MMC software queue support based on command queue interfaces
5  *
6  * Copyright (C) 2019 Linaro, Inc.
7  * Author: Baolin Wang <baolin.wang@linaro.org>
8  */
9 
10 #include <linux/devm-helpers.h>
11 #include <linux/mmc/card.h>
12 #include <linux/mmc/host.h>
13 #include <linux/module.h>
14 
15 #include "mmc_hsq.h"
16 
mmc_hsq_retry_handler(struct work_struct * work)17 static void mmc_hsq_retry_handler(struct work_struct *work)
18 {
19 	struct mmc_hsq *hsq = container_of(work, struct mmc_hsq, retry_work);
20 	struct mmc_host *mmc = hsq->mmc;
21 
22 	mmc->ops->request(mmc, hsq->mrq);
23 }
24 
mmc_hsq_modify_threshold(struct mmc_hsq * hsq)25 static void mmc_hsq_modify_threshold(struct mmc_hsq *hsq)
26 {
27 	struct mmc_host *mmc = hsq->mmc;
28 	struct mmc_request *mrq;
29 	unsigned int tag, need_change = 0;
30 
31 	mmc->hsq_depth = HSQ_NORMAL_DEPTH;
32 	for (tag = 0; tag < HSQ_NUM_SLOTS; tag++) {
33 		mrq = hsq->slot[tag].mrq;
34 		if (mrq && mrq->data &&
35 		   (mrq->data->blksz * mrq->data->blocks == 4096) &&
36 		   (mrq->data->flags & MMC_DATA_WRITE) &&
37 		   (++need_change == 2)) {
38 			mmc->hsq_depth = HSQ_PERFORMANCE_DEPTH;
39 			break;
40 		}
41 	}
42 }
43 
mmc_hsq_pump_requests(struct mmc_hsq * hsq)44 static void mmc_hsq_pump_requests(struct mmc_hsq *hsq)
45 {
46 	struct mmc_host *mmc = hsq->mmc;
47 	struct hsq_slot *slot;
48 	unsigned long flags;
49 	int ret = 0;
50 
51 	spin_lock_irqsave(&hsq->lock, flags);
52 
53 	/* Make sure we are not already running a request now */
54 	if (hsq->mrq || hsq->recovery_halt) {
55 		spin_unlock_irqrestore(&hsq->lock, flags);
56 		return;
57 	}
58 
59 	/* Make sure there are remain requests need to pump */
60 	if (!hsq->qcnt || !hsq->enabled) {
61 		spin_unlock_irqrestore(&hsq->lock, flags);
62 		return;
63 	}
64 
65 	mmc_hsq_modify_threshold(hsq);
66 
67 	slot = &hsq->slot[hsq->next_tag];
68 	hsq->mrq = slot->mrq;
69 	hsq->qcnt--;
70 
71 	spin_unlock_irqrestore(&hsq->lock, flags);
72 
73 	if (mmc->ops->request_atomic)
74 		ret = mmc->ops->request_atomic(mmc, hsq->mrq);
75 	else
76 		mmc->ops->request(mmc, hsq->mrq);
77 
78 	/*
79 	 * If returning BUSY from request_atomic(), which means the card
80 	 * may be busy now, and we should change to non-atomic context to
81 	 * try again for this unusual case, to avoid time-consuming operations
82 	 * in the atomic context.
83 	 *
84 	 * Note: we just give a warning for other error cases, since the host
85 	 * driver will handle them.
86 	 */
87 	if (ret == -EBUSY)
88 		schedule_work(&hsq->retry_work);
89 	else
90 		WARN_ON_ONCE(ret);
91 }
92 
mmc_hsq_update_next_tag(struct mmc_hsq * hsq,int remains)93 static void mmc_hsq_update_next_tag(struct mmc_hsq *hsq, int remains)
94 {
95 	int tag;
96 
97 	/*
98 	 * If there are no remain requests in software queue, then set a invalid
99 	 * tag.
100 	 */
101 	if (!remains) {
102 		hsq->next_tag = HSQ_INVALID_TAG;
103 		hsq->tail_tag = HSQ_INVALID_TAG;
104 		return;
105 	}
106 
107 	tag = hsq->tag_slot[hsq->next_tag];
108 	hsq->tag_slot[hsq->next_tag] = HSQ_INVALID_TAG;
109 	hsq->next_tag = tag;
110 }
111 
mmc_hsq_post_request(struct mmc_hsq * hsq)112 static void mmc_hsq_post_request(struct mmc_hsq *hsq)
113 {
114 	unsigned long flags;
115 	int remains;
116 
117 	spin_lock_irqsave(&hsq->lock, flags);
118 
119 	remains = hsq->qcnt;
120 	hsq->mrq = NULL;
121 
122 	/* Update the next available tag to be queued. */
123 	mmc_hsq_update_next_tag(hsq, remains);
124 
125 	if (hsq->waiting_for_idle && !remains) {
126 		hsq->waiting_for_idle = false;
127 		wake_up(&hsq->wait_queue);
128 	}
129 
130 	/* Do not pump new request in recovery mode. */
131 	if (hsq->recovery_halt) {
132 		spin_unlock_irqrestore(&hsq->lock, flags);
133 		return;
134 	}
135 
136 	spin_unlock_irqrestore(&hsq->lock, flags);
137 
138 	 /*
139 	  * Try to pump new request to host controller as fast as possible,
140 	  * after completing previous request.
141 	  */
142 	if (remains > 0)
143 		mmc_hsq_pump_requests(hsq);
144 }
145 
146 /**
147  * mmc_hsq_finalize_request - finalize one request if the request is done
148  * @mmc: the host controller
149  * @mrq: the request need to be finalized
150  *
151  * Return true if we finalized the corresponding request in software queue,
152  * otherwise return false.
153  */
mmc_hsq_finalize_request(struct mmc_host * mmc,struct mmc_request * mrq)154 bool mmc_hsq_finalize_request(struct mmc_host *mmc, struct mmc_request *mrq)
155 {
156 	struct mmc_hsq *hsq = mmc->cqe_private;
157 	unsigned long flags;
158 
159 	spin_lock_irqsave(&hsq->lock, flags);
160 
161 	if (!hsq->enabled || !hsq->mrq || hsq->mrq != mrq) {
162 		spin_unlock_irqrestore(&hsq->lock, flags);
163 		return false;
164 	}
165 
166 	/*
167 	 * Clear current completed slot request to make a room for new request.
168 	 */
169 	hsq->slot[hsq->next_tag].mrq = NULL;
170 
171 	spin_unlock_irqrestore(&hsq->lock, flags);
172 
173 	mmc_cqe_request_done(mmc, hsq->mrq);
174 
175 	mmc_hsq_post_request(hsq);
176 
177 	return true;
178 }
179 EXPORT_SYMBOL_GPL(mmc_hsq_finalize_request);
180 
mmc_hsq_recovery_start(struct mmc_host * mmc)181 static void mmc_hsq_recovery_start(struct mmc_host *mmc)
182 {
183 	struct mmc_hsq *hsq = mmc->cqe_private;
184 	unsigned long flags;
185 
186 	spin_lock_irqsave(&hsq->lock, flags);
187 
188 	hsq->recovery_halt = true;
189 
190 	spin_unlock_irqrestore(&hsq->lock, flags);
191 }
192 
mmc_hsq_recovery_finish(struct mmc_host * mmc)193 static void mmc_hsq_recovery_finish(struct mmc_host *mmc)
194 {
195 	struct mmc_hsq *hsq = mmc->cqe_private;
196 	int remains;
197 
198 	spin_lock_irq(&hsq->lock);
199 
200 	hsq->recovery_halt = false;
201 	remains = hsq->qcnt;
202 
203 	spin_unlock_irq(&hsq->lock);
204 
205 	/*
206 	 * Try to pump new request if there are request pending in software
207 	 * queue after finishing recovery.
208 	 */
209 	if (remains > 0)
210 		mmc_hsq_pump_requests(hsq);
211 }
212 
mmc_hsq_request(struct mmc_host * mmc,struct mmc_request * mrq)213 static int mmc_hsq_request(struct mmc_host *mmc, struct mmc_request *mrq)
214 {
215 	struct mmc_hsq *hsq = mmc->cqe_private;
216 	int tag = mrq->tag;
217 
218 	spin_lock_irq(&hsq->lock);
219 
220 	if (!hsq->enabled) {
221 		spin_unlock_irq(&hsq->lock);
222 		return -ESHUTDOWN;
223 	}
224 
225 	/* Do not queue any new requests in recovery mode. */
226 	if (hsq->recovery_halt) {
227 		spin_unlock_irq(&hsq->lock);
228 		return -EBUSY;
229 	}
230 
231 	hsq->slot[tag].mrq = mrq;
232 
233 	/*
234 	 * Set the next tag as current request tag if no available
235 	 * next tag.
236 	 */
237 	if (hsq->next_tag == HSQ_INVALID_TAG) {
238 		hsq->next_tag = tag;
239 		hsq->tail_tag = tag;
240 		hsq->tag_slot[hsq->tail_tag] = HSQ_INVALID_TAG;
241 	} else {
242 		hsq->tag_slot[hsq->tail_tag] = tag;
243 		hsq->tail_tag = tag;
244 	}
245 
246 	hsq->qcnt++;
247 
248 	spin_unlock_irq(&hsq->lock);
249 
250 	mmc_hsq_pump_requests(hsq);
251 
252 	return 0;
253 }
254 
mmc_hsq_post_req(struct mmc_host * mmc,struct mmc_request * mrq)255 static void mmc_hsq_post_req(struct mmc_host *mmc, struct mmc_request *mrq)
256 {
257 	if (mmc->ops->post_req)
258 		mmc->ops->post_req(mmc, mrq, 0);
259 }
260 
mmc_hsq_queue_is_idle(struct mmc_hsq * hsq,int * ret)261 static bool mmc_hsq_queue_is_idle(struct mmc_hsq *hsq, int *ret)
262 {
263 	bool is_idle;
264 
265 	spin_lock_irq(&hsq->lock);
266 
267 	is_idle = (!hsq->mrq && !hsq->qcnt) ||
268 		hsq->recovery_halt;
269 
270 	*ret = hsq->recovery_halt ? -EBUSY : 0;
271 	hsq->waiting_for_idle = !is_idle;
272 
273 	spin_unlock_irq(&hsq->lock);
274 
275 	return is_idle;
276 }
277 
mmc_hsq_wait_for_idle(struct mmc_host * mmc)278 static int mmc_hsq_wait_for_idle(struct mmc_host *mmc)
279 {
280 	struct mmc_hsq *hsq = mmc->cqe_private;
281 	int ret;
282 
283 	wait_event(hsq->wait_queue,
284 		   mmc_hsq_queue_is_idle(hsq, &ret));
285 
286 	return ret;
287 }
288 
mmc_hsq_disable(struct mmc_host * mmc)289 static void mmc_hsq_disable(struct mmc_host *mmc)
290 {
291 	struct mmc_hsq *hsq = mmc->cqe_private;
292 	u32 timeout = 500;
293 	int ret;
294 
295 	spin_lock_irq(&hsq->lock);
296 
297 	if (!hsq->enabled) {
298 		spin_unlock_irq(&hsq->lock);
299 		return;
300 	}
301 
302 	spin_unlock_irq(&hsq->lock);
303 
304 	ret = wait_event_timeout(hsq->wait_queue,
305 				 mmc_hsq_queue_is_idle(hsq, &ret),
306 				 msecs_to_jiffies(timeout));
307 	if (ret == 0) {
308 		pr_warn("could not stop mmc software queue\n");
309 		return;
310 	}
311 
312 	spin_lock_irq(&hsq->lock);
313 
314 	hsq->enabled = false;
315 
316 	spin_unlock_irq(&hsq->lock);
317 }
318 
mmc_hsq_enable(struct mmc_host * mmc,struct mmc_card * card)319 static int mmc_hsq_enable(struct mmc_host *mmc, struct mmc_card *card)
320 {
321 	struct mmc_hsq *hsq = mmc->cqe_private;
322 
323 	spin_lock_irq(&hsq->lock);
324 
325 	if (hsq->enabled) {
326 		spin_unlock_irq(&hsq->lock);
327 		return -EBUSY;
328 	}
329 
330 	hsq->enabled = true;
331 
332 	spin_unlock_irq(&hsq->lock);
333 
334 	return 0;
335 }
336 
337 static const struct mmc_cqe_ops mmc_hsq_ops = {
338 	.cqe_enable = mmc_hsq_enable,
339 	.cqe_disable = mmc_hsq_disable,
340 	.cqe_request = mmc_hsq_request,
341 	.cqe_post_req = mmc_hsq_post_req,
342 	.cqe_wait_for_idle = mmc_hsq_wait_for_idle,
343 	.cqe_recovery_start = mmc_hsq_recovery_start,
344 	.cqe_recovery_finish = mmc_hsq_recovery_finish,
345 };
346 
mmc_hsq_init(struct mmc_hsq * hsq,struct mmc_host * mmc)347 int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
348 {
349 	int ret;
350 	int i;
351 	hsq->num_slots = HSQ_NUM_SLOTS;
352 	hsq->next_tag = HSQ_INVALID_TAG;
353 	hsq->tail_tag = HSQ_INVALID_TAG;
354 
355 	hsq->slot = devm_kcalloc(mmc_dev(mmc), hsq->num_slots,
356 				 sizeof(struct hsq_slot), GFP_KERNEL);
357 	if (!hsq->slot)
358 		return -ENOMEM;
359 
360 	hsq->mmc = mmc;
361 	hsq->mmc->cqe_private = hsq;
362 	mmc->cqe_ops = &mmc_hsq_ops;
363 	mmc->hsq_depth = HSQ_NORMAL_DEPTH;
364 
365 	for (i = 0; i < HSQ_NUM_SLOTS; i++)
366 		hsq->tag_slot[i] = HSQ_INVALID_TAG;
367 
368 	ret = devm_work_autocancel(mmc_dev(mmc), &hsq->retry_work,
369 				   mmc_hsq_retry_handler);
370 	if (ret)
371 		return ret;
372 
373 	spin_lock_init(&hsq->lock);
374 	init_waitqueue_head(&hsq->wait_queue);
375 
376 	return 0;
377 }
378 EXPORT_SYMBOL_GPL(mmc_hsq_init);
379 
mmc_hsq_suspend(struct mmc_host * mmc)380 void mmc_hsq_suspend(struct mmc_host *mmc)
381 {
382 	mmc_hsq_disable(mmc);
383 }
384 EXPORT_SYMBOL_GPL(mmc_hsq_suspend);
385 
mmc_hsq_resume(struct mmc_host * mmc)386 int mmc_hsq_resume(struct mmc_host *mmc)
387 {
388 	return mmc_hsq_enable(mmc, NULL);
389 }
390 EXPORT_SYMBOL_GPL(mmc_hsq_resume);
391 
392 MODULE_DESCRIPTION("MMC Host Software Queue support");
393 MODULE_LICENSE("GPL v2");
394