Commit 6a573df8 authored by Mikhail Karpenko's avatar Mikhail Karpenko
Browse files

Write multiple sectors from a buffer pointed by S/G list

parent bbfc3d59
Loading
Loading
Loading
Loading
+52 −73
Original line number Original line Diff line number Diff line
@@ -442,12 +442,6 @@ static ssize_t elphel_test_write(struct device *dev, struct device_attribute *at
		msleep(1);
		msleep(1);
	}
	}


//	printk(KERN_DEBUG ">>> dump test buffer after reading: %d bytes\n", TEST_BUFF_SZ);
//	dma_sync_single_for_cpu(dev, pElphel_buf->d2h_paddr, pElphel_buf->d2h_size, DMA_FROM_DEVICE);
//	print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, test_buff, TEST_BUFF_SZ);
//	dma_sync_single_for_device(dev, pElphel_buf->d2h_paddr, pElphel_buf->d2h_size, DMA_FROM_DEVICE);
//	printk(KERN_DEBUG ">>> buffer has been mapped for device\n");

	printk(KERN_DEBUG ">>> dump test buffer after reading: %d bytes\n", TEST_BUFF_SZ);
	printk(KERN_DEBUG ">>> dump test buffer after reading: %d bytes\n", TEST_BUFF_SZ);
	dma_unmap_sg(dev, sgl, sg_elems, DMA_FROM_DEVICE);
	dma_unmap_sg(dev, sgl, sg_elems, DMA_FROM_DEVICE);
	for (i = 0; i < sg_elems; i++) {
	for (i = 0; i < sg_elems; i++) {
@@ -456,42 +450,36 @@ static ssize_t elphel_test_write(struct device *dev, struct device_attribute *at
		sg_copy_to_buffer(&sgl[i], 1, buff, TEST_BUFF_SZ);
		sg_copy_to_buffer(&sgl[i], 1, buff, TEST_BUFF_SZ);
		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buff, TEST_BUFF_SZ);
		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buff, TEST_BUFF_SZ);
	}
	}

	/* end of read test */
	/* end of read test */


//	printk(KERN_DEBUG ">>> interrupt flag has been cleared\n");
	printk(KERN_DEBUG ">>> *** proceeding to write test *** <<<\n");
//	printk(KERN_DEBUG ">>> dump of SG list area\n");

//	dma_sync_single_for_cpu(dev, pElphel_buf->h2d_paddr, pElphel_buf->h2d_size, DMA_TO_DEVICE);
	/* write test */
//	print_hex_dump_bytes("", DUMP_PREFIX_NONE, test_buff, TEST_BUFF_SZ);
	for_each_sg(sgl, sg_ptr, SG_TBL_SZ, n_elem) {
//	dma_sync_single_for_device(dev, pElphel_buf->h2d_paddr, pElphel_buf->h2d_size, DMA_TO_DEVICE);
		u8 pattern_buff[TEST_BUFF_SZ];
//	/* end of read test */
		memset(pattern_buff, 0x5a, TEST_BUFF_SZ);
//
		sg_copy_from_buffer(sg_ptr, 1, pattern_buff, TEST_BUFF_SZ);
//	/* write test */
	}
//	printk(KERN_DEBUG ">>> filling test buffer: %d bytes\n", TEST_BUFF_SZ);
	dma_map_sg(dev, sgl, sg_elems, DMA_TO_DEVICE);
//	dma_sync_single_for_cpu(dev, pElphel_buf->h2d_paddr, pElphel_buf->h2d_size, DMA_TO_DEVICE);

//	for (i = 0; i < TEST_BUFF_SZ - 1; i += 2) {
	printk(KERN_DEBUG ">>> trying to write data from sg list\n");
//		test_buff[i] = 0xaa;
	elphel_write_dma(port, lba_addr, sg_elems, sgl, sg_elems);
//		test_buff[i + 1] = 0x55;
	printk(KERN_DEBUG ">>> command has been issued\n");
//	}

//	print_hex_dump_bytes("", DUMP_PREFIX_NONE, test_buff, TEST_BUFF_SZ);
	while (dpriv->flags & IRQ_SIMPLE) {
//	dma_sync_single_for_device(dev, pElphel_buf->h2d_paddr, pElphel_buf->h2d_size, DMA_TO_DEVICE);
		printk_once(KERN_DEBUG ">>> waiting for interrupt\n");
//	printk(KERN_DEBUG ">>> buffer has been mapped\n");
		msleep(1);
//
	}
//	sg_init_one(&sg, pElphel_buf->h2d_vaddr, TEST_BUFF_SZ);

//
	printk(KERN_DEBUG ">>> dump test buffer after writing: %d bytes\n", TEST_BUFF_SZ);
//	printk(KERN_DEBUG ">>> trying to read data to sg list\n");
	dma_unmap_sg(dev, sgl, sg_elems, DMA_TO_DEVICE);
//	elphel_read_dma(port, SDA2_LBA_ADDR, 1, &sg, 1);
	for (i = 0; i < sg_elems; i++) {
//	printk(KERN_DEBUG ">>> command has been issued\n");
		dev_dbg(dev, ">>> sector %i\n", i);
//	/* end of write test */
		u8 buff[TEST_BUFF_SZ];
//
		sg_copy_to_buffer(&sgl[i], 1, buff, TEST_BUFF_SZ);
////	while (dpriv->flags & IRQ_SIMPLE) {
		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buff, TEST_BUFF_SZ);
////		msleep(1);
	}
////	}
	/* end of write test */
//	printk(KERN_DEBUG ">>> interrupt flag has been cleared\n");
//	printk(KERN_DEBUG ">>> dump of SG list area\n");
//	dma_sync_single_for_cpu(dev, pElphel_buf->h2d_paddr, pElphel_buf->h2d_size, DMA_TO_DEVICE);
//	print_hex_dump_bytes("", DUMP_PREFIX_NONE, test_buff, TEST_BUFF_SZ);
//	dma_sync_single_for_device(dev, pElphel_buf->h2d_paddr, pElphel_buf->h2d_size, DMA_TO_DEVICE);


	return buff_sz;
	return buff_sz;
}
}
@@ -511,10 +499,19 @@ inline void prep_cfis(u8 *cmd_tbl, ///< pointer to the beginning o
	 * a command in ATA/ATAPI command set documentation
	 * a command in ATA/ATAPI command set documentation
	 */
	 */
	switch (cmd) {
	switch (cmd) {
	case ATA_CMD_WRITE:
		device = 0xe0 | ((start_addr >> 24) & 0x0f);
		ctrl = 0x08;
		/* this is 28-bit command; 4 bits of the address have already been
		 * placed to Device register, invalidate the remaining (if any) upper
		 * bits of the address and leave only 24 significant bits (just in case)
		 */
		start_addr &= 0xffffff;
		break;
	case ATA_CMD_WRITE_EXT:
	case ATA_CMD_WRITE_EXT:
		// not verified yet
		// not verified yet
		device = 0x00;
		device = 0x00;
		ctrl = 0x00;
		ctrl = 0x08;
		break;
		break;
	case ATA_CMD_READ:
	case ATA_CMD_READ:
		device = 0xe0 | ((start_addr >> 24) & 0x0f);
		device = 0xe0 | ((start_addr >> 24) & 0x0f);
@@ -572,18 +569,15 @@ inline void prep_prdt(struct scatterlist *sgl, ///< pointer to S/G list which
	}
	}
}
}


static int elphel_write_dma(struct ata_port *ap, u64 start, u16 count, struct scatterlist *sg, unsigned int elem)
static int elphel_write_dma(struct ata_port *ap, u64 start, u16 count, struct scatterlist *sgl, unsigned int elem)
{
{
	u32 opts;
	u32 opts;
	const u32 cmd_fis_len = 5;
	unsigned int n_elem;
//	void *cmd_tbl;
	u8 *cmd_tbl;
	u8 *cmd_tbl;
	u8 cmd;
	unsigned int slot_num = 0;
	unsigned int slot_num = 0;
	struct ahci_port_priv *pp = ap->private_data;
	struct ahci_port_priv *pp = ap->private_data;
	struct ahci_host_priv *hpriv = ap->host->private_data;
	struct ahci_host_priv *hpriv = ap->host->private_data;
	struct elphel_ahci_priv *dpriv = hpriv->plat_data;
	struct elphel_ahci_priv *dpriv = hpriv->plat_data;
	struct scatterlist *sg_ptr;
	struct ahci_sg *ahci_sg;
	struct ahci_sg *ahci_sg;
	void __iomem *port_mmio = ahci_port_base(ap);
	void __iomem *port_mmio = ahci_port_base(ap);


@@ -592,42 +586,27 @@ static int elphel_write_dma(struct ata_port *ap, u64 start, u16 count, struct sc
	/* prepare command FIS */
	/* prepare command FIS */
	dma_sync_single_for_cpu(ap->dev, pp->cmd_tbl_dma, AHCI_CMD_TBL_AR_SZ, DMA_TO_DEVICE);
	dma_sync_single_for_cpu(ap->dev, pp->cmd_tbl_dma, AHCI_CMD_TBL_AR_SZ, DMA_TO_DEVICE);
	cmd_tbl = pp->cmd_tbl + slot_num * AHCI_CMD_TBL_SZ;
	cmd_tbl = pp->cmd_tbl + slot_num * AHCI_CMD_TBL_SZ;
	cmd_tbl[0] = 0x27;                  // H2D register FIS
	if (start & ~ADDR_MASK_28_BIT)
	cmd_tbl[1] = 0x80;                  // set C = 1
		cmd = ATA_CMD_WRITE_EXT;
	cmd_tbl[2] = ATA_CMD_WRITE;         // ATA WRITE DMA command as described in ATA/ATAPI command set
	else
	cmd_tbl[3] = 0;                     // features(7:0)
		cmd = ATA_CMD_WRITE;
	cmd_tbl[4] = (start >> 0)  & 0xff;  // LBA(7:0)
	prep_cfis(cmd_tbl, cmd, start, count);
	cmd_tbl[5] = (start >> 8)  & 0xff;  // LBA(15:8)
	cmd_tbl[6] = (start >> 16) & 0xff;  // LBA(23:16)
	cmd_tbl[7] = 0;                     // device
	cmd_tbl[8] = (start >> 24)  & 0xff; // LBA(31:24)
	cmd_tbl[9] = (start >> 32)  & 0xff; // LBA(39:32)
	cmd_tbl[10] = (start >> 40) & 0xff; // LBA(47:40)
	cmd_tbl[11] = 0;                    // features(15:8)
	cmd_tbl[12] = (count >> 0) & 0xff;  // count(7:0)
	cmd_tbl[13] = (count >> 8) & 0xff;  // count(15:8)
	cmd_tbl[14] = 0;                    // ICC (isochronous command completion)
	cmd_tbl[15] = 0;                    // control


	/* prepare physical region descriptor table */
	/* prepare physical region descriptor table */
	n_elem = 0;
	ahci_sg = pp->cmd_tbl + slot_num * AHCI_CMD_TBL_SZ + AHCI_CMD_TBL_HDR_SZ;
	ahci_sg = pp->cmd_tbl + slot_num * AHCI_CMD_TBL_SZ + AHCI_CMD_TBL_HDR_SZ;
	prep_prdt(sg, elem, ahci_sg);
	prep_prdt(sgl, elem, ahci_sg);
//	for_each_sg(sg, sg_ptr, elem, n_elem) {
//		dma_addr_t addr = sg_dma_address(sg_ptr);
//		u32 sg_len = sg_dma_len(sg_ptr);
//
//		ahci_sg[n_elem].addr = cpu_to_le32(addr & 0xffffffff);
//		ahci_sg[n_elem].addr_hi = cpu_to_le32((addr >> 16) >> 16);
//		ahci_sg[n_elem].flags_size = cpu_to_le32(sg_len - 1);
//	}


	/* prepare command header */
	/* prepare command header */
	opts = cmd_fis_len | (n_elem << 16) | AHCI_CMD_WRITE | AHCI_CMD_PREFETCH | AHCI_CMD_CLR_BUSY;
	opts = CMD_FIS_LEN | (elem << 16) | AHCI_CMD_PREFETCH | AHCI_CMD_CLR_BUSY | AHCI_CMD_WRITE;
	ahci_fill_cmd_slot(pp, slot_num, opts);
	ahci_fill_cmd_slot(pp, slot_num, opts);

	printk(KERN_DEBUG ">>> dump command table content, first %d bytes, phys addr = 0x%x:\n", TEST_BUFF_SZ, pp->cmd_tbl_dma);
	print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, pp->cmd_tbl, TEST_BUFF_SZ);

	dma_sync_single_for_device(ap->dev, pp->cmd_tbl_dma, AHCI_CMD_TBL_AR_SZ, DMA_TO_DEVICE);
	dma_sync_single_for_device(ap->dev, pp->cmd_tbl_dma, AHCI_CMD_TBL_AR_SZ, DMA_TO_DEVICE);


	/* issue command */
	/* issue command */
	writel(0x11, port_mmio + PORT_CMD);
	writel(1 << slot_num, port_mmio + PORT_CMD_ISSUE);
	writel(1 << slot_num, port_mmio + PORT_CMD_ISSUE);


	return 0;
	return 0;