Page 1 of 1

Internal Oops with 4.9.83 Kernel - Atmel SPI Driver

Posted: Thu Mar 01, 2018 12:14 am
by jay214128
I have been trying out the 4.9.83 kernel from https://github.com/linux4sam/linux-at91 ... x-4.9-at91. When I shutdown/reboot, I get a kernel Oops in the SPI driver. Probably related to the recent DMA bounce buffer that was added.

Code: Select all

Unable to handle kernel paging request at virtual address 01222160
pgd = c0004000
[01222160] *pgd=00000000
Internal error: Oops: 5 [#1] PREEMPT ARM
Modules linked in: bnep hci_uart btqca bluetooth rt2800usb rt2800lib rt2x00usb rt2x00lib option usb_wwan usbserial
CPU: 0 PID: 579 Comm: kworker/0:2 Not tainted 4.9.83-r5041+ #119
Hardware name: Atmel AT91SAM9
Workqueue: mtdblock5 mtd_blktrans_work
task: c7978ae0 task.stack: c7b6e000
PC is at dma_cache_maint_page+0x8/0x11c
LR is at arm_dma_map_page+0x38/0x80
pc : [<c010d448>]    lr : [<c010d594>]    psr: 60000093
sp : c7b6fc38  ip : c010d55c  fp : 00000000
r10: 00000000  r9 : c793e400  r8 : c793e410
r7 : c7b6fd70  r6 : c0938484  r5 : 00000000  r4 : 01222160
r3 : 00000002  r2 : 00000210  r1 : 00000000  r0 : 01222160
Flags: nZCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 0005317f  Table: 772a8000  DAC: 00000055
Process kworker/0:2 (pid: 579, stack limit = 0xc7b6e190)
Stack: (0xc7b6fc38 to 0xc7b70000)
fc20:                                                       01222160 00000000
fc40: c793e410 c010d594 c0111d48 01222160 c7b6fde4 c7b422b8 c7b42000 c03a1b54
fc60: 00000002 00000000 c7981a00 00000000 c7981a00 00000000 c7b6fc8c c013b0d4
fc80: 00208040 c79b3060 c7b6fcb4 c013b880 00000000 c09135c0 00000000 c7b421b8
fca0: 00000000 00000023 00000001 c0322710 00000000 c7b6fd70 c7b422b8 c7b6fde4
fcc0: c7981a00 c7b42000 00000000 00000002 00000001 c03a2374 c03a231c c7b42000
fce0: c7b6fd3c c7b6fd70 c7b42168 c793e410 c793e410 c039d850 00000000 c0608af4
fd00: c7b6fd78 c7b42000 c7b42000 60000013 c7981a00 c7b6fd70 c7b42000 c7b6fd34
fd20: c039c88c 60000013 00000000 c039f340 c7981a00 00000000 c7b6fd38 c7b6fd38
fd40: c7981a00 c7b6fd70 c7994c24 00004200 00004200 00000000 00000000 c039f55c
fd60: 00000080 c7994c00 00008000 c037b294 c7b6fddc c7b6fe18 c7981a00 00000000
fd80: c039c78c c7b6fd34 00000218 00000008 00000000 c7b6fd94 c7b6fd94 00000000
fda0: c7b6fda0 c7b6fda0 c7994c00 c72f59a0 00000008 77994c00 772f59a0 00000000
fdc0: 00000000 00000000 00000000 00000000 00000000 00000802 00e4e1c0 c7b6fe18
fde0: c7b6fd70 c71f2400 e110b000 00000210 771f2400 ffffffff 00000000 00000000
fe00: 00000000 00000000 00000000 00000000 00000810 00e4e1c0 c7b6fd70 c7b6fddc
fe20: c091d748 c7994000 00000000 00000000 00000000 c0373be0 00000210 c7b6feac
fe40: e110b000 00000000 c7994000 00000200 00004200 c3476000 c7994000 c0371608
fe60: 00000210 c7b6feac e110b000 00000000 c7908180 00000200 00000000 c3476000
fe80: c7994000 00000000 00000210 c0378698 00000210 c7b6feac e110b000 00000000
fea0: 0000000c 00000000 00000000 00000000 c037855c c3476000 c7b45040 c79081c0
fec0: c7b6e000 00000001 c7908180 00000000 c091d748 c0377590 00000001 00000000
fee0: 00000001 00000000 c6b72000 c091d748 c7908190 c7b44820 41f84e51 c7b0f300
ff00: c79081c0 00000000 c78b1b00 c090f1ec 00000000 c090f1ec 00000008 c0132094
ff20: c7b0f300 c79081c0 c7b0f300 c7b0f318 c090f1ec c7b6e000 c09135c0 c090f200
ff40: c090f1ec c0132540 00000000 c7b0ef00 00000000 c7b0f300 c013221c 00000000
ff60: 00000000 00000000 00000000 c0136dfc c7b6ff70 00000000 c7b6ff9c c7b0f300
ff80: 00000000 c7b6ff84 c7b6ff84 00000000 c7b6ff90 c7b6ff90 c7b6ffac c7b0ef00
ffa0: c0136d38 00000000 00000000 c0106f98 00000000 00000000 00000000 00000000
ffc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
ffe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
[<c010d448>] (dma_cache_maint_page) from [<c010d594>] (arm_dma_map_page+0x38/0x80)
[<c010d594>] (arm_dma_map_page) from [<c03a1b54>] (atmel_spi_one_transfer+0x220/0x9e8)
[<c03a1b54>] (atmel_spi_one_transfer) from [<c03a2374>] (atmel_spi_transfer_one_message+0x58/0xe8)
[<c03a2374>] (atmel_spi_transfer_one_message) from [<c039d850>] (__spi_pump_messages+0x520/0x550)
[<c039d850>] (__spi_pump_messages) from [<c039f340>] (__spi_sync+0x248/0x2a8)
[<c039f340>] (__spi_sync) from [<c039f55c>] (spi_sync+0x24/0x3c)
[<c039f55c>] (spi_sync) from [<c037b294>] (dataflash_read+0xd4/0x104)
[<c037b294>] (dataflash_read) from [<c0373be0>] (part_read+0x44/0x7c)
[<c0373be0>] (part_read) from [<c0371608>] (mtd_read+0x70/0xa4)
[<c0371608>] (mtd_read) from [<c0378698>] (mtdblock_writesect+0x13c/0x1b0)
[<c0378698>] (mtdblock_writesect) from [<c0377590>] (mtd_blktrans_work+0x3cc/0x4f8)
[<c0377590>] (mtd_blktrans_work) from [<c0132094>] (process_one_work+0x1e0/0x338)
[<c0132094>] (process_one_work) from [<c0132540>] (worker_thread+0x324/0x498)
[<c0132540>] (worker_thread) from [<c0136dfc>] (kthread+0xc4/0xd8)
[<c0136dfc>] (kthread) from [<c0106f98>] (ret_from_fork+0x14/0x3c)
Code: e12fff1e c0938484 e92d4070 e59f610c (e590e000) 
---[ end trace 20454e11649e132e ]---
Kernel panic - not syncing: Fatal exception
---[ end Kernel panic - not syncing: Fatal exception
This is with a AT91SAM9G45 SOC. Backing out the DMA bounce buffer change in drivers/spi/spi-atmel.c fixes the problem.

Re: Internal Oops with 4.9.83 Kernel - Atmel SPI Driver

Posted: Thu Mar 01, 2018 1:03 am
by blue_z
Since you found a problem with a patch, then you should CC the patch author.

Regards

Re: Internal Oops with 4.9.83 Kernel - Atmel SPI Driver

Posted: Fri Mar 02, 2018 1:41 am
by jay214128
I figured out what happened. When I saw that the latest Atmel SPI driver was using a DMA bounce buffer to work around the DMA issue, I assumed it would replace the work around I had been using for years, so I removed my change in favor of the new DMA bounce buffer. Turns out, I still need my change too.

The DMA bounce buffer recently added only affects the use_dma DMA code path. It does not affect the use_pdc DMA code path, which is what is used with the AT91SAM9G45 SOC. The fix I have been using was discussed at viewtopic.php?f=12&t=25846&sid=dfc15143 ... aebed70157, and included here for reference.

Code: Select all

--- a/drivers/spi/spi-atmel.c	2018-03-01 15:31:59.000000000 -0800
+++ b/drivers/spi/spi-atmel.c	2018-03-01 15:33:29.000000000 -0800
@@ -983,6 +983,30 @@
 }
 
 /*
+ * Convert any vmalloc addresses to their corresponding kmap address
+ * so it can find a valid physical address for DMA mapping.
+ */
+static void *adjust_buffer_location(struct device *dev, const void *buf)
+{
+	void *ptr;
+
+	if (likely(buf < high_memory)) { /* !is_vmalloc_addr(buf) */
+		return (void *)buf;
+	} else {
+		struct page *pg;
+
+		pg = vmalloc_to_page(buf);
+		if (pg == 0) {
+			dev_err(dev, "failed to vmalloc_to_page\n");
+			return NULL;
+		}
+		ptr = page_address(pg) + ((size_t)buf & ~PAGE_MASK);
+		dev_dbg(dev, "adjust_buffer_location: %p => %p\n", buf, ptr);
+		return ptr;
+	}
+}
+
+/*
  * For DMA, tx_buf/tx_dma have the same relationship as rx_buf/rx_dma:
  *  - The buffer is either valid for CPU access, else NULL
  *  - If the buffer is valid, so is its DMA address
@@ -993,23 +1017,26 @@
 atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
 {
 	struct device	*dev = &as->pdev->dev;
+	void *ptr;
 
 	xfer->tx_dma = xfer->rx_dma = INVALID_DMA_ADDRESS;
 	if (xfer->tx_buf) {
-		/* tx_buf is a const void* where we need a void * for the dma
-		 * mapping */
-		void *nonconst_tx = (void *)xfer->tx_buf;
-
-		xfer->tx_dma = dma_map_single(dev,
-				nonconst_tx, xfer->len,
-				DMA_TO_DEVICE);
+		ptr = adjust_buffer_location(dev, xfer->tx_buf);
+		if (ptr) {
+			xfer->tx_dma = dma_map_single(dev,
+					ptr, xfer->len,
+					DMA_TO_DEVICE);
+		}
 		if (dma_mapping_error(dev, xfer->tx_dma))
 			return -ENOMEM;
 	}
 	if (xfer->rx_buf) {
-		xfer->rx_dma = dma_map_single(dev,
-				xfer->rx_buf, xfer->len,
-				DMA_FROM_DEVICE);
+		ptr = adjust_buffer_location(dev, xfer->rx_buf);
+		if (ptr) {
+			xfer->rx_dma = dma_map_single(dev,
+					ptr, xfer->len,
+					DMA_FROM_DEVICE);
+		}
 		if (dma_mapping_error(dev, xfer->rx_dma)) {
 			if (xfer->tx_buf)
 				dma_unmap_single(dev,
Jay