Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 15283469 authored by Asai Thambi S P's avatar Asai Thambi S P Committed by Jens Axboe
Browse files

mtip32xx: add trim support



TRIM support added through vendor unique command.

Signed-off-by: default avatarSam Bradshaw &lt; <sbradshaw@micron.com>
Signed-off-by: default avatarAsai Thambi S P <asamymuthupa@micron.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 16c906e5
Loading
Loading
Loading
Loading
+96 −0
Original line number Diff line number Diff line
@@ -1519,6 +1519,12 @@ static int mtip_get_identify(struct mtip_port *port, void __user *user_buffer)
	}
#endif

	/* Demux ID.DRAT & ID.RZAT to determine trim support */
	if (port->identify[69] & (1 << 14) && port->identify[69] & (1 << 5))
		port->dd->trim_supp = true;
	else
		port->dd->trim_supp = false;

	/* Set the identify buffer as valid. */
	port->identify_valid = 1;

@@ -1705,6 +1711,81 @@ static int mtip_get_smart_attr(struct mtip_port *port, unsigned int id,
	return rv;
}

/*
 * Trim unused sectors
 *
 * @dd		pointer to driver_data structure
 * @lba		starting lba
 * @len		# of 512b sectors to trim
 *
 * return value
 *      -ENOMEM		Out of dma memory
 *      -EINVAL		Invalid parameters passed in, trim not supported
 *      -EIO		Error submitting trim request to hw
 */
int mtip_send_trim(struct driver_data *dd, unsigned int lba, unsigned int len)
{
	int i, rv = 0;
	u64 tlba, tlen, sect_left;
	struct mtip_trim_entry *buf;
	dma_addr_t dma_addr;
	struct host_to_dev_fis fis;

	if (!len || dd->trim_supp == false)
		return -EINVAL;

	/* Trim request too big */
	WARN_ON(len > (MTIP_MAX_TRIM_ENTRY_LEN * MTIP_MAX_TRIM_ENTRIES));

	/* Trim request not aligned on 4k boundary */
	WARN_ON(len % 8 != 0);

	/* Warn if vu_trim structure is too big */
	WARN_ON(sizeof(struct mtip_trim) > ATA_SECT_SIZE);

	/* Allocate a DMA buffer for the trim structure */
	buf = dmam_alloc_coherent(&dd->pdev->dev, ATA_SECT_SIZE, &dma_addr,
								GFP_KERNEL);
	if (!buf)
		return -ENOMEM;
	memset(buf, 0, ATA_SECT_SIZE);

	for (i = 0, sect_left = len, tlba = lba;
			i < MTIP_MAX_TRIM_ENTRIES && sect_left;
			i++) {
		tlen = (sect_left >= MTIP_MAX_TRIM_ENTRY_LEN ?
					MTIP_MAX_TRIM_ENTRY_LEN :
					sect_left);
		buf[i].lba = __force_bit2int cpu_to_le32(tlba);
		buf[i].range = __force_bit2int cpu_to_le16(tlen);
		tlba += tlen;
		sect_left -= tlen;
	}
	WARN_ON(sect_left != 0);

	/* Build the fis */
	memset(&fis, 0, sizeof(struct host_to_dev_fis));
	fis.type       = 0x27;
	fis.opts       = 1 << 7;
	fis.command    = 0xfb;
	fis.features   = 0x60;
	fis.sect_count = 1;
	fis.device     = ATA_DEVICE_OBS;

	if (mtip_exec_internal_command(dd->port,
					&fis,
					5,
					dma_addr,
					ATA_SECT_SIZE,
					0,
					GFP_KERNEL,
					MTIP_TRIM_TIMEOUT_MS) < 0)
		rv = -EIO;

	dmam_free_coherent(&dd->pdev->dev, ATA_SECT_SIZE, buf, dma_addr);
	return rv;
}

/*
 * Get the drive capacity.
 *
@@ -3675,6 +3756,12 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
		}
	}

	if (unlikely(bio->bi_rw & REQ_DISCARD)) {
		bio_endio(bio, mtip_send_trim(dd, bio->bi_sector,
						bio_sectors(bio)));
		return;
	}

	if (unlikely(!bio_has_data(bio))) {
		blk_queue_flush(queue, 0);
		bio_endio(bio, 0);
@@ -3817,6 +3904,15 @@ skip_create_disk:
	 */
	blk_queue_flush(dd->queue, 0);

	/* Signal trim support */
	if (dd->trim_supp == true) {
		set_bit(QUEUE_FLAG_DISCARD, &dd->queue->queue_flags);
		dd->queue->limits.discard_granularity = 4096;
		blk_queue_max_discard_sectors(dd->queue,
			MTIP_MAX_TRIM_ENTRY_LEN * MTIP_MAX_TRIM_ENTRIES);
		dd->queue->limits.discard_zeroes_data = 0;
	}

	/* Set the capacity of the device in 512 byte sectors. */
	if (!(mtip_hw_get_capacity(dd, &capacity))) {
		dev_warn(&dd->pdev->dev,
+17 −0
Original line number Diff line number Diff line
@@ -178,6 +178,21 @@ struct mtip_work {
		mtip_workq_sdbfx(w->port, group, w->completed);     \
	}

#define MTIP_TRIM_TIMEOUT_MS		240000
#define MTIP_MAX_TRIM_ENTRIES		8
#define MTIP_MAX_TRIM_ENTRY_LEN 	0xfff8

struct mtip_trim_entry {
	u32 lba;   /* starting lba of region */
	u16 rsvd;  /* unused */
	u16 range; /* # of 512b blocks to trim */
} __packed;

struct mtip_trim {
	/* Array of regions to trim */
	struct mtip_trim_entry entry[MTIP_MAX_TRIM_ENTRIES];
} __packed;

/* Register Frame Information Structure (FIS), host to device. */
struct host_to_dev_fis {
	/*
@@ -473,6 +488,8 @@ struct driver_data {

	struct dentry *dfs_node;

	bool trim_supp; /* flag indicating trim support */

	int numa_node; /* NUMA support */

	char workq_name[32];