18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2016 CNEX Labs
48c2ecf20Sopenharmony_ci * Initial release: Javier Gonzalez <javier@cnexlabs.com>
58c2ecf20Sopenharmony_ci *                  Matias Bjorling <matias@cnexlabs.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or
88c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License version
98c2ecf20Sopenharmony_ci * 2 as published by the Free Software Foundation.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
128c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
138c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
148c2ecf20Sopenharmony_ci * General Public License for more details.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * pblk-cache.c - pblk's write cache
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "pblk.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_civoid pblk_write_to_cache(struct pblk *pblk, struct bio *bio,
228c2ecf20Sopenharmony_ci				unsigned long flags)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	struct pblk_w_ctx w_ctx;
258c2ecf20Sopenharmony_ci	sector_t lba = pblk_get_lba(bio);
268c2ecf20Sopenharmony_ci	unsigned long start_time;
278c2ecf20Sopenharmony_ci	unsigned int bpos, pos;
288c2ecf20Sopenharmony_ci	int nr_entries = pblk_get_secs(bio);
298c2ecf20Sopenharmony_ci	int i, ret;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	start_time = bio_start_io_acct(bio);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	/* Update the write buffer head (mem) with the entries that we can
348c2ecf20Sopenharmony_ci	 * write. The write in itself cannot fail, so there is no need to
358c2ecf20Sopenharmony_ci	 * rollback from here on.
368c2ecf20Sopenharmony_ci	 */
378c2ecf20Sopenharmony_ciretry:
388c2ecf20Sopenharmony_ci	ret = pblk_rb_may_write_user(&pblk->rwb, bio, nr_entries, &bpos);
398c2ecf20Sopenharmony_ci	switch (ret) {
408c2ecf20Sopenharmony_ci	case NVM_IO_REQUEUE:
418c2ecf20Sopenharmony_ci		io_schedule();
428c2ecf20Sopenharmony_ci		goto retry;
438c2ecf20Sopenharmony_ci	case NVM_IO_ERR:
448c2ecf20Sopenharmony_ci		pblk_pipeline_stop(pblk);
458c2ecf20Sopenharmony_ci		bio_io_error(bio);
468c2ecf20Sopenharmony_ci		goto out;
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	pblk_ppa_set_empty(&w_ctx.ppa);
508c2ecf20Sopenharmony_ci	w_ctx.flags = flags;
518c2ecf20Sopenharmony_ci	if (bio->bi_opf & REQ_PREFLUSH) {
528c2ecf20Sopenharmony_ci		w_ctx.flags |= PBLK_FLUSH_ENTRY;
538c2ecf20Sopenharmony_ci		pblk_write_kick(pblk);
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	if (unlikely(!bio_has_data(bio)))
578c2ecf20Sopenharmony_ci		goto out;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	for (i = 0; i < nr_entries; i++) {
608c2ecf20Sopenharmony_ci		void *data = bio_data(bio);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci		w_ctx.lba = lba + i;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci		pos = pblk_rb_wrap_pos(&pblk->rwb, bpos + i);
658c2ecf20Sopenharmony_ci		pblk_rb_write_entry_user(&pblk->rwb, data, w_ctx, pos);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci		bio_advance(bio, PBLK_EXPOSED_PAGE_SIZE);
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	atomic64_add(nr_entries, &pblk->user_wa);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci#ifdef CONFIG_NVM_PBLK_DEBUG
738c2ecf20Sopenharmony_ci	atomic_long_add(nr_entries, &pblk->inflight_writes);
748c2ecf20Sopenharmony_ci	atomic_long_add(nr_entries, &pblk->req_writes);
758c2ecf20Sopenharmony_ci#endif
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	pblk_rl_inserted(&pblk->rl, nr_entries);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ciout:
808c2ecf20Sopenharmony_ci	bio_end_io_acct(bio, start_time);
818c2ecf20Sopenharmony_ci	pblk_write_should_kick(pblk);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (ret == NVM_IO_DONE)
848c2ecf20Sopenharmony_ci		bio_endio(bio);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/*
888c2ecf20Sopenharmony_ci * On GC the incoming lbas are not necessarily sequential. Also, some of the
898c2ecf20Sopenharmony_ci * lbas might not be valid entries, which are marked as empty by the GC thread
908c2ecf20Sopenharmony_ci */
918c2ecf20Sopenharmony_ciint pblk_write_gc_to_cache(struct pblk *pblk, struct pblk_gc_rq *gc_rq)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct pblk_w_ctx w_ctx;
948c2ecf20Sopenharmony_ci	unsigned int bpos, pos;
958c2ecf20Sopenharmony_ci	void *data = gc_rq->data;
968c2ecf20Sopenharmony_ci	int i, valid_entries;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	/* Update the write buffer head (mem) with the entries that we can
998c2ecf20Sopenharmony_ci	 * write. The write in itself cannot fail, so there is no need to
1008c2ecf20Sopenharmony_ci	 * rollback from here on.
1018c2ecf20Sopenharmony_ci	 */
1028c2ecf20Sopenharmony_ciretry:
1038c2ecf20Sopenharmony_ci	if (!pblk_rb_may_write_gc(&pblk->rwb, gc_rq->secs_to_gc, &bpos)) {
1048c2ecf20Sopenharmony_ci		io_schedule();
1058c2ecf20Sopenharmony_ci		goto retry;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	w_ctx.flags = PBLK_IOTYPE_GC;
1098c2ecf20Sopenharmony_ci	pblk_ppa_set_empty(&w_ctx.ppa);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	for (i = 0, valid_entries = 0; i < gc_rq->nr_secs; i++) {
1128c2ecf20Sopenharmony_ci		if (gc_rq->lba_list[i] == ADDR_EMPTY)
1138c2ecf20Sopenharmony_ci			continue;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci		w_ctx.lba = gc_rq->lba_list[i];
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci		pos = pblk_rb_wrap_pos(&pblk->rwb, bpos + valid_entries);
1188c2ecf20Sopenharmony_ci		pblk_rb_write_entry_gc(&pblk->rwb, data, w_ctx, gc_rq->line,
1198c2ecf20Sopenharmony_ci						gc_rq->paddr_list[i], pos);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		data += PBLK_EXPOSED_PAGE_SIZE;
1228c2ecf20Sopenharmony_ci		valid_entries++;
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	WARN_ONCE(gc_rq->secs_to_gc != valid_entries,
1268c2ecf20Sopenharmony_ci					"pblk: inconsistent GC write\n");
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	atomic64_add(valid_entries, &pblk->gc_wa);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci#ifdef CONFIG_NVM_PBLK_DEBUG
1318c2ecf20Sopenharmony_ci	atomic_long_add(valid_entries, &pblk->inflight_writes);
1328c2ecf20Sopenharmony_ci	atomic_long_add(valid_entries, &pblk->recov_gc_writes);
1338c2ecf20Sopenharmony_ci#endif
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	pblk_write_should_kick(pblk);
1368c2ecf20Sopenharmony_ci	return NVM_IO_OK;
1378c2ecf20Sopenharmony_ci}
138