/** * Driver for Altera PCIe core chaining DMA reference design. * * Copyright (C) 2008 Leon Woestenberg * Copyright (C) 2008 Nickolas Heppermann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * * Rationale: This driver exercises the chaining DMA read and write engine * in the reference design. It is meant as a complementary reference * driver that can be used for testing early designs as well as a basis to * write your custom driver. * * Status: Test results from Leon Woestenberg : * * Sendero Board w/ Cyclone II EP2C35F672C6N, PX1011A PCIe x1 PHY on a * Dell Precision 370 PC, x86, kernel 2.6.20 from Ubuntu 7.04. * * Sendero Board w/ Cyclone II EP2C35F672C6N, PX1011A PCIe x1 PHY on a * Freescale MPC8313E-RDB board, PowerPC, 2.6.24 w/ Freescale patches. * * Driver tests passed with PCIe Compiler 8.1. With PCIe 8.0 the DMA * loopback test had reproducable compare errors. I assume a change * in the compiler or reference design, but could not find evidence nor * documentation on a change or fix in that direction. * * The reference design does not have readable locations and thus a * dummy read, used to flush PCI posted writes, cannot be performed. * */ #include #include #include #include #include #include #include #include #include #include #include /* by default do not build the character device interface */ /* XXX It is non-functional yet */ #ifndef ALTPCIECHDMA_CDEV # define ALTPCIECHDMA_CDEV 0 #endif /* build the character device interface? */ #if ALTPCIECHDMA_CDEV # define MAX_CHDMA_SIZE (8 * 1024 * 1024) # include "mapper_user_to_sg.h" #endif /** driver name, mimicks Altera naming of the reference design */ #define DRV_NAME "altpciechdma" /** number of BARs on the device */ #define APE_BAR_NUM (6) /** BAR number where the RCSLAVE memory sits */ #define APE_BAR_RCSLAVE (0) /** BAR number where the Descriptor Header sits */ #define APE_BAR_HEADER (2) /** maximum size in bytes of the descriptor table, chdma logic limit */ #define APE_CHDMA_TABLE_SIZE (4096) /* single transfer must not exceed 255 table entries. worst case this can be * achieved by 255 scattered pages, with only a single byte in the head and * tail pages. 253 * PAGE_SIZE is a safe upper bound for the transfer size. */ #define APE_CHDMA_MAX_TRANSFER_LEN (253 * PAGE_SIZE) /** * Specifies those BARs to be mapped and the length of each mapping. * * Zero (0) means do not map, otherwise specifies the BAR lengths to be mapped. * If the actual BAR length is less, this is considered an error; then * reconfigure your PCIe core. * * @see ug_pci_express 8.0, table 7-2 at page 7-13. */ static const unsigned long bar_min_len[APE_BAR_NUM] = { 32768, 0, 256, 0, 32768, 0 }; /** * Descriptor Header, controls the DMA read engine or write engine. * * The descriptor header is the main data structure for starting DMA transfers. * * It sits in End Point (FPGA) memory BAR[2] for 32-bit or BAR[3:2] for 64-bit. * It references a descriptor table which exists in Root Complex (PC) memory. * Writing the rclast field starts the DMA operation, thus all other structures * and fields must be setup before doing so. * * @see ug_pci_express 8.0, tables 7-3, 7-4 and 7-5 at page 7-14. * @note This header must be written in four 32-bit (PCI DWORD) writes. */ struct ape_chdma_header { /** * w0 consists of two 16-bit fields: * lsb u16 number; number of descriptors in ape_chdma_table * msb u16 control; global control flags */ u32 w0; /* bus address to ape_chdma_table in Root Complex memory */ u32 bdt_addr_h; u32 bdt_addr_l; /** * w3 consists of two 16-bit fields: * - lsb u16 rclast; last descriptor number available in Root Complex * - zero (0) means the first descriptor is ready, * - one (1) means two descriptors are ready, etc. * - msb u16 reserved; * * @note writing to this memory location starts the DMA operation! */ u32 w3; } __attribute__ ((packed)); /** * Descriptor Entry, describing a (non-scattered) single memory block transfer. * * There is one descriptor for each memory block involved in the transfer, a * block being a contiguous address range on the bus. * * Multiple descriptors are chained by means of the ape_chdma_table data * structure. * * @see ug_pci_express 8.0, tables 7-6, 7-7 and 7-8 at page 7-14 and page 7-15. */ struct ape_chdma_desc { /** * w0 consists of two 16-bit fields: * number of DWORDS to transfer * - lsb u16 length; * global control * - msb u16 control; */ u32 w0; /* address of memory in the End Point */ u32 ep_addr; /* bus address of source or destination memory in the Root Complex */ u32 rc_addr_h; u32 rc_addr_l; } __attribute__ ((packed)); /** * Descriptor Table, an array of descriptors describing a chained transfer. * * An array of descriptors, preceded by workspace for the End Point. * It exists in Root Complex memory. * * The End Point can update its last completed descriptor number in the * eplast field if requested by setting the EPLAST_ENA bit either * globally in the header's or locally in any descriptor's control field. * * @note this structure may not exceed 4096 bytes. This results in a * maximum of 4096 / (4 * 4) - 1 = 255 descriptors per chained transfer. * * @see ug_pci_express 8.0, tables 7-9, 7-10 and 7-11 at page 7-17 and page 7-18. */ struct ape_chdma_table { /* workspace 0x00-0x0b, reserved */ u32 reserved1[3]; /* workspace 0x0c-0x0f, last descriptor handled by End Point */ u32 w3; /* the actual array of descriptors * 0x10-0x1f, 0x20-0x2f, ... 0xff0-0xfff (255 entries) */ struct ape_chdma_desc desc[255]; } __attribute__ ((packed)); /** * Altera PCI Express ('ape') board specific book keeping data * * Keeps state of the PCIe core and the Chaining DMA controller * application. */ struct ape_dev { /** the kernel pci device data structure provided by probe() */ struct pci_dev *pci_dev; /** * kernel virtual address of the mapped BAR memory and IO regions of * the End Point. Used by map_bars()/unmap_bars(). */ void * __iomem bar[APE_BAR_NUM]; /** kernel virtual address for Descriptor Table in Root Complex memory */ struct ape_chdma_table *table_virt; /** * bus address for the Descriptor Table in Root Complex memory, in * CPU-native endianess */ dma_addr_t table_bus; /* if the device regions could not be allocated, assume and remember it * is in use by another driver; this driver must not disable the device. */ int in_use; /* whether this driver enabled msi for the device */ int msi_enabled; /* whether this driver could obtain the regions */ int got_regions; /* irq line succesfully requested by this driver, -1 otherwise */ int irq_line; /* board revision */ u8 revision; /* interrupt count, incremented by the interrupt handler */ int irq_count; #if ALTPCIECHDMA_CDEV /* character device */ dev_t cdevno; struct cdev cdev; /* user space scatter gather mapper */ struct sg_mapping_t *sgm; #endif }; /** * Using the subsystem vendor id and subsystem id, it is possible to * distinguish between different cards bases around the same * (third-party) logic core. * * Default Altera vendor and device ID's, and some (non-reserved) * ID's are now used here that are used amongst the testers/developers. */ static const struct pci_device_id ids[] = { { PCI_DEVICE(0x1172, 0xE001), }, { PCI_DEVICE(0x2071, 0x2071), }, { 0, } }; MODULE_DEVICE_TABLE(pci, ids); #if ALTPCIECHDMA_CDEV /* prototypes for character device */ static int sg_init(struct ape_dev *ape); static void sg_exit(struct ape_dev *ape); #endif /** * altpciechdma_isr() - Interrupt handler * */ static irqreturn_t altpciechdma_isr(int irq, void *dev_id) { struct ape_dev *ape = (struct ape_dev *)dev_id; if (!ape) return IRQ_NONE; ape->irq_count++; return IRQ_HANDLED; } static int __devinit scan_bars(struct ape_dev *ape, struct pci_dev *dev) { int i; for (i = 0; i < APE_BAR_NUM; i++) { unsigned long bar_start = pci_resource_start(dev, i); if (bar_start) { unsigned long bar_end = pci_resource_end(dev, i); unsigned long bar_flags = pci_resource_flags(dev, i); printk(KERN_DEBUG "BAR%d 0x%08lx-0x%08lx flags 0x%08lx\n", i, bar_start, bar_end, bar_flags); } } return 0; } /** * Unmap the BAR regions that had been mapped earlier using map_bars() */ static void unmap_bars(struct ape_dev *ape, struct pci_dev *dev) { int i; for (i = 0; i < APE_BAR_NUM; i++) { /* is this BAR mapped? */ if (ape->bar[i]) { /* unmap BAR */ pci_iounmap(dev, ape->bar[i]); ape->bar[i] = NULL; } } } /** * Map the device memory regions into kernel virtual address space after * verifying their sizes respect the minimum sizes needed, given by the * bar_min_len[] array. */ static int __devinit map_bars(struct ape_dev *ape, struct pci_dev *dev) { int rc; int i; /* iterate through all the BARs */ for (i = 0; i < APE_BAR_NUM; i++) { unsigned long bar_start = pci_resource_start(dev, i); unsigned long bar_end = pci_resource_end(dev, i); unsigned long bar_length = bar_end - bar_start + 1; ape->bar[i] = NULL; /* do not map, and skip, BARs with length 0 */ if (!bar_min_len[i]) continue; /* do not map BARs with address 0 */ if (!bar_start || !bar_end) { printk(KERN_DEBUG "BAR #%d is not present?!\n", i); rc = -1; goto fail; } bar_length = bar_end - bar_start + 1; /* BAR length is less than driver requires? */ if (bar_length < bar_min_len[i]) { printk(KERN_DEBUG "BAR #%d length = %lu bytes but driver " "requires at least %lu bytes\n", i, bar_length, bar_min_len[i]); rc = -1; goto fail; } /* map the device memory or IO region into kernel virtual * address space */ ape->bar[i] = pci_iomap(dev, i, bar_min_len[i]); if (!ape->bar[i]) { printk(KERN_DEBUG "Could not map BAR #%d.\n", i); rc = -1; goto fail; } printk(KERN_DEBUG "BAR[%d] mapped at 0x%p with length %lu(/%lu).\n", i, ape->bar[i], bar_min_len[i], bar_length); } /* succesfully mapped all required BAR regions */ rc = 0; goto success; fail: /* unmap any BARs that we did map */ unmap_bars(ape, dev); success: return rc; } #if 0 /* not yet implemented fully FIXME add opcode */ static void __devinit rcslave_test(struct ape_dev *ape, struct pci_dev *dev) { u32 *rcslave_mem = (u32 *)ape->bar[APE_BAR_RCSLAVE]; u32 result = 0; /** this number is assumed to be different each time this test runs */ u32 seed = (u32)jiffies; u32 value = seed; int i; /* write loop */ value = seed; for (i = 1024; i < 32768 / 4 ; i++) { printk(KERN_DEBUG "Writing 0x%08x to 0x%p.\n", (u32)value, (void *)rcslave_mem + i); iowrite32(value, rcslave_mem + i); value++; } /* read-back loop */ value = seed; for (i = 1024; i < 32768 / 4; i++) { result = ioread32(rcslave_mem + i); if (result != value) { printk(KERN_DEBUG "Wrote 0x%08x to 0x%p, but read back 0x%08x.\n", (u32)value, (void *)rcslave_mem + i, (u32)result); break; } value++; } } #endif /* obtain the 32 most significant (high) bits of a 32-bit or 64-bit address */ #define pci_dma_h(addr) ((addr >> 16) >> 16) /* obtain the 32 least significant (low) bits of a 32-bit or 64-bit address */ #define pci_dma_l(addr) (addr & 0xffffffffUL) /* ape_fill_chdma_desc() - Fill a Altera PCI Express Chaining DMA descriptor * * @desc pointer to descriptor to be filled * @addr root complex address * @ep_addr end point address * @len number of bytes, must be a multiple of 4. */ static inline void ape_chdma_desc_set(struct ape_chdma_desc *desc, dma_addr_t addr, u32 ep_addr, int len) { BUG_ON(len & 3); desc->w0 = cpu_to_le32(len / 4); desc->ep_addr = cpu_to_le32(ep_addr); desc->rc_addr_h = cpu_to_le32(pci_dma_h(addr)); desc->rc_addr_l = cpu_to_le32(pci_dma_l(addr)); } /* * ape_sg_to_chdma_table() - Create a device descriptor table from a scatterlist. * * The scatterlist must have been mapped by pci_map_sg(sgm->sgl). * * @sgl scatterlist. * @nents Number of entries in the scatterlist. * @first Start index in the scatterlist sgm->sgl. * @ep_addr End Point address for the scatter/gather transfer. * @desc pointer to first descriptor * * Returns Number of entries in the table on success, -1 on error. */ static int ape_sg_to_chdma_table(struct scatterlist *sgl, int nents, int first, struct ape_chdma_desc *desc, u32 ep_addr) { int i = first, j = 0; /* inspect first entry */ dma_addr_t addr = sg_dma_address(&sgl[i]); unsigned int len = sg_dma_len(&sgl[i]); /* contiguous block */ dma_addr_t cont_addr = addr; unsigned int cont_len = len; /* iterate over remaining entries */ for (; j < 25 && i < nents - 1; i++) { /* bus address of next entry i + 1 */ dma_addr_t next = sg_dma_address(&sgl[i + 1]); /* length of this entry i */ len = sg_dma_len(&sgl[i]); printk(KERN_DEBUG "%04d: addr=0x%08x length=0x%08x\n", i, addr, len); /* entry i + 1 is non-contiguous with entry i? */ if (next != addr + len) { /* TODO create entry here (we could overwrite i) */ printk(KERN_DEBUG "%4d: cont_addr=0x%08x cont_len=0x%08x\n", j, cont_addr, cont_len); /* set descriptor for contiguous transfer */ ape_chdma_desc_set(&desc[j], cont_addr, ep_addr, cont_len); /* next end point memory address */ ep_addr += cont_len; /* start new contiguous block */ cont_addr = next; cont_len = 0; j++; } /* add entry i + 1 to current contiguous block */ cont_len += len; /* goto entry i + 1 */ addr = next; } /* TODO create entry here (we could overwrite i) */ printk(KERN_DEBUG "%04d: addr=0x%08x length=0x%08x\n", i, addr, len); printk(KERN_DEBUG "%4d: cont_addr=0x%08x length=0x%08x\n", j, cont_addr, cont_len); j++; return j; } /* compare buffers */ static inline int compare(u32 *p, u32 *q, int len) { int result = -1; int fail = 0; int i; for (i = 0; i < len / 4; i++) { if (*p == *q) { /* every so many u32 words, show equals */ if ((i & 255) == 0) printk(KERN_DEBUG "[%p] = 0x%08x [%p] = 0x%08x\n", p, *p, q, *q); } else { fail++; /* show the first few miscompares */ if (fail < 10) { printk(KERN_DEBUG "[%p] = 0x%08x != [%p] = 0x%08x ?!\n", p, *p, q, *q); /* but stop after a while */ } else if (fail == 10) { printk(KERN_DEBUG "---more errors follow! not printed---\n"); } else { /* stop compare after this many errors */ break; } } p++; q++; } if (!fail) result = 0; return result; } /* dma_test() - Perform DMA loop back test to end point and back to root complex. * * Allocate a cache-coherent buffer in host memory, consisting of four pages. * * Fill the four memory pages such that each 32-bit word contains its own address. * * Now perform a loop back test, have the end point device copy the first buffer * half to end point memory, then have it copy back into the second half. * * Create a descriptor table to copy the first buffer half into End Point * memory. Instruct the End Point to do a DMA read using that table. * * Create a descriptor table to copy End Point memory to the second buffer * half. Instruct the End Point to do a DMA write using that table. * * Compare results, fail or pass. * */ static int __devinit dma_test(struct ape_dev *ape, struct pci_dev *dev) { /* test result; guilty until proven innocent */ int result = -1; /* the DMA read header sits at address 0x00 of the DMA engine BAR */ struct ape_chdma_header *write_header = (struct ape_chdma_header *)ape->bar[APE_BAR_HEADER]; /* the write DMA header sits after the read header at address 0x10 */ struct ape_chdma_header *read_header = write_header + 1; /* virtual address of the allocated buffer */ u8 *buffer_virt = 0; /* bus address of the allocated buffer */ dma_addr_t buffer_bus = 0; int i, n = 0, irq_count; /* temporary value used to construct 32-bit data words */ u32 w; printk(KERN_DEBUG "bar_tests(), PAGE_SIZE = 0x%0x\n", (int)PAGE_SIZE); printk(KERN_DEBUG "write_header = 0x%p.\n", write_header); printk(KERN_DEBUG "read_header = 0x%p.\n", read_header); printk(KERN_DEBUG "&write_header->w3 = 0x%p\n", &write_header->w3); printk(KERN_DEBUG "&read_header->w3 = 0x%p\n", &read_header->w3); printk(KERN_DEBUG "ape->table_virt = 0x%p.\n", ape->table_virt); if (!write_header || !read_header || !ape->table_virt) goto fail; /* allocate and map coherently-cached memory for a DMA-able buffer */ /* @see 2.6.26.2/Documentation/DMA-mapping.txt line 318 */ buffer_virt = (u8 *)pci_alloc_consistent(dev, PAGE_SIZE * 4, &buffer_bus); if (!buffer_virt) { printk(KERN_DEBUG "Could not allocate coherent DMA buffer.\n"); goto fail; } printk(KERN_DEBUG "Allocated cache-coherent DMA buffer (virtual address = 0x%016llx, bus address = 0x%016llx).\n", (u64)buffer_virt, (u64)buffer_bus); /* fill first half of buffer with its virtual address as data */ for (i = 0; i < 4 * PAGE_SIZE; i += 4) #if 0 *(u32 *)(buffer_virt + i) = i / PAGE_SIZE + 1; #else *(u32 *)(buffer_virt + i) = (buffer_virt + i); #endif #if 0 compare((u32 *)buffer_virt, (u32 *)(buffer_virt + 2 * PAGE_SIZE), 8192); #endif #if 0 /* fill second half of buffer with zeroes */ for (i = 2 * PAGE_SIZE; i < 4 * PAGE_SIZE; i += 4) *(u32 *)(buffer_virt + i) = 0; #endif /* invalidate EPLAST, outside 0-255, 0xFADE is from the testbench */ ape->table_virt->w3 = cpu_to_le32(0x0000FADE); /* fill in first descriptor */ n = 0; /* read 8192 bytes from RC buffer to EP address 4096 */ ape_chdma_desc_set(&ape->table_virt->desc[n], buffer_bus, 4096, 2 * PAGE_SIZE); #if 1 for (i = 0; i < 255; i++) { ape_chdma_desc_set(&ape->table_virt->desc[i], buffer_bus, 4096, 2 * PAGE_SIZE); } /* index of last descriptor */ n = i - 1; #endif #if 0 /* fill in next descriptor */ n++; /* read 1024 bytes from RC buffer to EP address 4096 + 1024 */ ape_chdma_desc_set(&ape->table_virt->desc[n], buffer_bus + 1024, 4096 + 1024, 1024); #endif #if 1 /* enable MSI after the last descriptor is completed */ if (ape->msi_enabled) ape->table_virt->desc[n].w0 |= cpu_to_le32(1UL << 16)/*local MSI*/; #endif #if 0 /* dump descriptor table for debugging */ printk(KERN_DEBUG "Descriptor Table (Read, in Root Complex Memory, # = %d)\n", n + 1); for (i = 0; i < 4 + (n + 1) * 4; i += 4) { u32 *p = (u32 *)ape->table_virt; p += i; printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (LEN=0x%x)\n", (u32)p, (u32)p & 15, *p, 4 * le32_to_cpu(*p)); p++; printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (EPA=0x%x)\n", (u32)p, (u32)p & 15, *p, le32_to_cpu(*p)); p++; printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (RCH=0x%x)\n", (u32)p, (u32)p & 15, *p, le32_to_cpu(*p)); p++; printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (RCL=0x%x)\n", (u32)p, (u32)p & 15, *p, le32_to_cpu(*p)); } #endif /* set available number of descriptors in table */ w = (u32)(n + 1); w |= (1UL << 18)/*global EPLAST_EN*/; #if 0 if (ape->msi_enabled) w |= (1UL << 17)/*global MSI*/; #endif printk(KERN_DEBUG "writing 0x%08x to 0x%p\n", w, (void *)&read_header->w0); iowrite32(w, &read_header->w0); /* write table address (higher 32-bits) */ printk(KERN_DEBUG "writing 0x%08x to 0x%p\n", (u32)((ape->table_bus >> 16) >> 16), (void *)&read_header->bdt_addr_h); iowrite32(pci_dma_h(ape->table_bus), &read_header->bdt_addr_h); /* write table address (lower 32-bits) */ printk(KERN_DEBUG "writing 0x%08x to 0x%p\n", (u32)(ape->table_bus & 0xffffffffUL), (void *)&read_header->bdt_addr_l); iowrite32(pci_dma_l(ape->table_bus), &read_header->bdt_addr_l); /* memory write barrier */ wmb(); printk(KERN_DEBUG "Flush posted writes\n"); /** FIXME Add dummy read to flush posted writes but need a readable location! */ #if 0 (void)ioread32(); #endif /* remember IRQ count before the transfer */ irq_count = ape->irq_count; /* write number of descriptors - this starts the DMA */ printk(KERN_DEBUG "\nStart DMA read\n"); printk(KERN_DEBUG "writing 0x%08x to 0x%p\n", (u32)n, (void *)&read_header->w3); iowrite32(n, &read_header->w3); printk(KERN_DEBUG "EPLAST = %lu\n", le32_to_cpu(*(u32 *)&ape->table_virt->w3) & 0xffffUL); /** memory write barrier */ wmb(); /* dummy read to flush posted writes */ /* FIXME Need a readable location! */ #if 0 (void)ioread32(); #endif printk(KERN_DEBUG "POLL FOR READ:\n"); /* poll for chain completion, 1000 times 1 millisecond */ for (i = 0; i < 100; i++) { volatile u32 *p = &ape->table_virt->w3; u32 eplast = le32_to_cpu(*p) & 0xffffUL; printk(KERN_DEBUG "EPLAST = %u, n = %d\n", eplast, n); if (eplast == n) { printk(KERN_DEBUG "DONE\n"); /* print IRQ count before the transfer */ printk(KERN_DEBUG "#IRQs during transfer: %d\n", ape->irq_count - irq_count); break; } udelay(100); } /* invalidate EPLAST, outside 0-255, 0xFADE is from the testbench */ ape->table_virt->w3 = cpu_to_le32(0x0000FADE); /* setup first descriptor */ n = 0; ape_chdma_desc_set(&ape->table_virt->desc[n], buffer_bus + 8192, 4096, 2 * PAGE_SIZE); #if 1 for (i = 0; i < 255; i++) { ape_chdma_desc_set(&ape->table_virt->desc[i], buffer_bus + 8192, 4096, 2 * PAGE_SIZE); } /* index of last descriptor */ n = i - 1; #endif #if 1 /* test variable, make a module option later */ if (ape->msi_enabled) ape->table_virt->desc[n].w0 |= cpu_to_le32(1UL << 16)/*local MSI*/; #endif #if 0 /* dump descriptor table for debugging */ printk(KERN_DEBUG "Descriptor Table (Write, in Root Complex Memory, # = %d)\n", n + 1); for (i = 0; i < 4 + (n + 1) * 4; i += 4) { u32 *p = (u32 *)ape->table_virt; p += i; printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (LEN=0x%x)\n", (u32)p, (u32)p & 15, *p, 4 * le32_to_cpu(*p)); p++; printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (EPA=0x%x)\n", (u32)p, (u32)p & 15, *p, le32_to_cpu(*p)); p++; printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (RCH=0x%x)\n", (u32)p, (u32)p & 15, *p, le32_to_cpu(*p)); p++; printk(KERN_DEBUG "0x%08x/0x%02x: 0x%08x (RCL=0x%x)\n", (u32)p, (u32)p & 15, *p, le32_to_cpu(*p)); } #endif /* set number of available descriptors in the table */ w = (u32)(n + 1); /* enable updates of eplast for each descriptor completion */ w |= (u32)(1UL << 18)/*global EPLAST_EN*/; #if 0 // test variable, make a module option later /* enable MSI for each descriptor completion */ if (ape->msi_enabled) w |= (1UL << 17)/*global MSI*/; #endif iowrite32(w, &write_header->w0); iowrite32(pci_dma_h(ape->table_bus), &write_header->bdt_addr_h); iowrite32(pci_dma_l(ape->table_bus), &write_header->bdt_addr_l); /** memory write barrier and flush posted writes */ wmb(); /* dummy read to flush posted writes */ /* FIXME Need a readable location! */ #if 0 (void)ioread32(); #endif irq_count = ape->irq_count; printk(KERN_DEBUG "\nStart DMA write\n"); iowrite32(n, &write_header->w3); /** memory write barrier */ wmb(); /** dummy read to flush posted writes */ //(void)ioread32(); printk(KERN_DEBUG "POLL FOR WRITE:\n"); /* poll for completion, 1000 times 1 millisecond */ for (i = 0; i < 100; i++) { volatile u32 *p = &ape->table_virt->w3; u32 eplast = le32_to_cpu(*p) & 0xffffUL; printk(KERN_DEBUG "EPLAST = %u, n = %d\n", eplast, n); if (eplast == n) { printk(KERN_DEBUG "DONE\n"); /* print IRQ count before the transfer */ printk(KERN_DEBUG "#IRQs during transfer: %d\n", ape->irq_count - irq_count); break; } udelay(100); } /* soft-reset DMA write engine */ iowrite32(0x0000ffffUL, &write_header->w0); /* soft-reset DMA read engine */ iowrite32(0x0000ffffUL, &read_header->w0); /** memory write barrier */ wmb(); /* dummy read to flush posted writes */ /* FIXME Need a readable location! */ #if 0 (void)ioread32(); #endif /* compare first half of buffer with second half, should be identical */ result = compare((u32 *)buffer_virt, (u32 *)(buffer_virt + 2 * PAGE_SIZE), 8192); printk(KERN_DEBUG "DMA loop back test %s.\n", result ? "FAILED" : "PASSED"); pci_free_consistent(dev, 4 * PAGE_SIZE, buffer_virt, buffer_bus); fail: printk(KERN_DEBUG "bar_tests() end, result %d\n", result); return result; } /* Called when the PCI sub system thinks we can control the given device. * Inspect if we can support the device and if so take control of it. * * Return 0 when we have taken control of the given device. * * - allocate board specific bookkeeping * - allocate coherently-mapped memory for the descriptor table * - enable the board * - verify board revision * - request regions * - query DMA mask * - obtain and request irq * - map regions into kernel address space */ static int __devinit probe(struct pci_dev *dev, const struct pci_device_id *id) { int rc = 0; struct ape_dev *ape = NULL; u8 irq_pin, irq_line; printk(KERN_DEBUG "probe(dev = 0x%p, pciid = 0x%p)\n", dev, id); /* allocate memory for per-board book keeping */ ape = kzalloc(sizeof(struct ape_dev), GFP_KERNEL); if (!ape) { printk(KERN_DEBUG "Could not kzalloc()ate memory.\n"); goto err_ape; } ape->pci_dev = dev; dev->dev.driver_data = (void *)ape; printk(KERN_DEBUG "probe() ape = 0x%p\n", ape); printk(KERN_DEBUG "sizeof(struct ape_chdma_table) = %d.\n", (int)sizeof(struct ape_chdma_table)); /* the reference design has a size restriction on the table size */ BUG_ON(sizeof(struct ape_chdma_table) > APE_CHDMA_TABLE_SIZE); /* allocate and map coherently-cached memory for a descriptor table */ /* @see LDD3 page 446 */ ape->table_virt = (struct ape_chdma_table *)pci_alloc_consistent(dev, APE_CHDMA_TABLE_SIZE, &ape->table_bus); /* could not allocate table? */ if (!ape->table_virt) { printk(KERN_DEBUG "Could not dma_alloc()ate_coherent memory.\n"); goto err_table; } printk(KERN_DEBUG "table_virt = 0x%16llx, table_bus = 0x%16llx.\n", (u64)ape->table_virt, (u64)ape->table_bus); /* enable device */ rc = pci_enable_device(dev); if (rc) { printk(KERN_DEBUG "pci_enable_device() failed\n"); goto err_enable; } /* enable bus master capability on device */ pci_set_master(dev); /* enable message signaled interrupts */ rc = pci_enable_msi(dev); /* could not use MSI? */ if (rc) { /* resort to legacy interrupts */ printk(KERN_DEBUG "Could not enable MSI interrupting.\n"); ape->msi_enabled = 0; /* MSI enabled, remember for cleanup */ } else { printk(KERN_DEBUG "Enabled MSI interrupting.\n"); ape->msi_enabled = 1; } pci_read_config_byte(dev, PCI_REVISION_ID, &ape->revision); #if 0 /* example */ /* (for example) this driver does not support revision 0x42 */ if (ape->revision == 0x42) { printk(KERN_DEBUG "Revision 0x42 is not supported by this driver.\n"); rc = -ENODEV; goto err_rev; } #endif /** XXX check for native or legacy PCIe endpoint? */ rc = pci_request_regions(dev, DRV_NAME); /* could not request all regions? */ if (rc) { /* assume device is in use (and do not disable it later!) */ ape->in_use = 1; goto err_regions; } ape->got_regions = 1; #if 1 // @todo For now, disable 64-bit, because I do not understand the implications (DAC!) /* query for DMA transfer */ /* @see Documentation/DMA-mapping.txt */ if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)) { pci_set_consistent_dma_mask(dev, DMA_64BIT_MASK); /* use 64-bit DMA */ printk(KERN_DEBUG "Using a 64-bit DMA mask.\n"); } else #endif if (!pci_set_dma_mask(dev, DMA_32BIT_MASK)) { printk(KERN_DEBUG "Could not set 64-bit DMA mask.\n"); pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK); /* use 32-bit DMA */ printk(KERN_DEBUG "Using a 32-bit DMA mask.\n"); } else { printk(KERN_DEBUG "No suitable DMA possible.\n"); /** @todo Choose proper error return code */ rc = -1; goto err_mask; } rc = pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin); /* could not read? */ if (rc) goto err_irq; printk(KERN_DEBUG "IRQ pin #%d (0=none, 1=INTA#...4=INTD#).\n", irq_pin); /* @see LDD3, page 318 */ rc = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq_line); /* could not read? */ if (rc) { printk(KERN_DEBUG "Could not query PCI_INTERRUPT_LINE, error %d\n", rc); goto err_irq; } printk(KERN_DEBUG "IRQ line #%d.\n", irq_line); #if 1 irq_line = dev->irq; /* @see LDD3, page 259 */ rc = request_irq(irq_line, altpciechdma_isr, IRQF_SHARED, DRV_NAME, (void *)ape); if (rc) { printk(KERN_DEBUG "Could not request IRQ #%d, error %d\n", irq_line, rc); ape->irq_line = -1; goto err_irq; } /* remember which irq we allocated */ ape->irq_line = (int)irq_line; printk(KERN_DEBUG "Succesfully requested IRQ #%d with dev_id 0x%p\n", irq_line, ape); #endif /* show BARs */ scan_bars(ape, dev); /* map BARs */ rc = map_bars(ape, dev); if (rc) goto err_map; #if ALTPCIECHDMA_CDEV /* initialize character device */ rc = sg_init(ape); if (rc) goto err_cdev; #endif /* perform DMA engines loop back test */ rc = dma_test(ape, dev); (void)rc; /* succesfully took the device */ rc = 0; printk(KERN_DEBUG "probe() successful.\n"); goto end; err_cdev: /* unmap the BARs */ unmap_bars(ape, dev); err_map: /* free allocated irq */ if (ape->irq_line >= 0) free_irq(ape->irq_line, (void *)ape); err_irq: if (ape->msi_enabled) pci_disable_msi(dev); /* disable the device iff it is not in use */ if (!ape->in_use) pci_disable_device(dev); if (ape->got_regions) pci_release_regions(dev); err_mask: err_regions: err_rev: /* clean up everything before device enable() */ err_enable: if (ape->table_virt) pci_free_consistent(dev, APE_CHDMA_TABLE_SIZE, ape->table_virt, ape->table_bus); /* clean up everything before allocating descriptor table */ err_table: if (ape) kfree(ape); err_ape: end: return rc; } static void __devexit remove(struct pci_dev *dev) { struct ape_dev *ape; printk(KERN_DEBUG "remove(0x%p)\n", dev); if ((dev == 0) || (dev->dev.driver_data == 0)) { printk(KERN_DEBUG "remove(dev = 0x%p) dev->dev.driver_data = 0x%p\n", dev, dev->dev.driver_data); return; } ape = (struct ape_dev *)dev->dev.driver_data; printk(KERN_DEBUG "remove(dev = 0x%p) where dev->dev.driver_data = 0x%p\n", dev, ape); if (ape->pci_dev != dev) { printk(KERN_DEBUG "dev->dev.driver_data->pci_dev (0x%08lx) != dev (0x%08lx)\n", (unsigned long)ape->pci_dev, (unsigned long)dev); } /* remove character device */ #if ALTPCIECHDMA_CDEV sg_exit(ape); #endif if (ape->table_virt) pci_free_consistent(dev, APE_CHDMA_TABLE_SIZE, ape->table_virt, ape->table_bus); /* free IRQ * @see LDD3 page 279 */ if (ape->irq_line >= 0) { printk(KERN_DEBUG "Freeing IRQ #%d for dev_id 0x%08lx.\n", ape->irq_line, (unsigned long)ape); free_irq(ape->irq_line, (void *)ape); } /* MSI was enabled? */ if (ape->msi_enabled) { /* Disable MSI @see Documentation/MSI-HOWTO.txt */ pci_disable_msi(dev); ape->msi_enabled = 0; } /* unmap the BARs */ unmap_bars(ape, dev); if (!ape->in_use) pci_disable_device(dev); if (ape->got_regions) /* to be called after device disable */ pci_release_regions(dev); } #if ALTPCIECHDMA_CDEV /* * Called when the device goes from unused to used. */ static int sg_open(struct inode *inode, struct file *file) { struct ape_dev *ape; printk(KERN_DEBUG DRV_NAME "_open()\n"); /* pointer to containing data structure of the character device inode */ ape = container_of(inode->i_cdev, struct ape_dev, cdev); /* create a reference to our device state in the opened file */ file->private_data = ape; /* create virtual memory mapper */ ape->sgm = sg_create_mapper(MAX_CHDMA_SIZE); return 0; } /* * Called when the device goes from used to unused. */ static int sg_close(struct inode *inode, struct file *file) { /* fetch device specific data stored earlier during open */ struct ape_dev *ape = (struct ape_dev *)file->private_data; printk(KERN_DEBUG DRV_NAME "_close()\n"); /* destroy virtual memory mapper */ sg_destroy_mapper(ape->sgm); return 0; } static ssize_t sg_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { /* fetch device specific data stored earlier during open */ struct ape_dev *ape = (struct ape_dev *)file->private_data; (void)ape; printk(KERN_DEBUG DRV_NAME "_read(buf=0x%p, count=%lld, pos=%llu)\n", buf, (s64)count, (u64)*pos); return count; } /* sg_write() - Write to the device * * @buf userspace buffer * @count number of bytes in the userspace buffer * * Iterate over the userspace buffer, taking at most 255 * PAGE_SIZE bytes for * each DMA transfer. * For each transfer, get the user pages, build a sglist, map, build a * descriptor table. submit the transfer. wait for the interrupt handler * to wake us on completion. */ static ssize_t sg_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { int hwnents, tents; size_t transfer_len, remaining = count, done = 0; u64 transfer_addr = (u64)buf; /* fetch device specific data stored earlier during open */ struct ape_dev *ape = (struct ape_dev *)file->private_data; printk(KERN_DEBUG DRV_NAME "_write(buf=0x%p, count=%lld, pos=%llu)\n", buf, (s64)count, (u64)*pos); /* TODO transfer boundaries at PAGE_SIZE granularity */ while (remaining > 0) { /* limit DMA transfer size */ transfer_len = (remaining < APE_CHDMA_MAX_TRANSFER_LEN)? remaining: APE_CHDMA_MAX_TRANSFER_LEN; /* get all user space buffer pages and create a scattergather list */ sgm_map_user_pages(ape->sgm, transfer_addr, transfer_len, 0/*read from userspace*/); printk(KERN_DEBUG DRV_NAME "mapped_pages=%d\n", ape->sgm->mapped_pages); /* map all entries in the scattergather list */ hwnents = pci_map_sg(ape->pci_dev, ape->sgm->sgl, ape->sgm->mapped_pages, DMA_TO_DEVICE); printk(KERN_DEBUG DRV_NAME "hwnents=%d\n", hwnents); /* build device descriptor tables and submit them to the DMA engine */ tents = ape_sg_to_chdma_table(ape->sgm->sgl, hwnents, 0, &ape->table_virt->desc[0], 4096); printk(KERN_DEBUG DRV_NAME "tents=%d\n", hwnents); #if 0 while (tables) { /* TODO build table */ /* TODO submit table to the device */ /* if engine stopped and unfinished work then start engine */ } put ourselves on wait queue #endif dma_unmap_sg(NULL, ape->sgm->sgl, ape->sgm->mapped_pages, DMA_TO_DEVICE); /* dirty and free the pages */ sgm_unmap_user_pages(ape->sgm, 1/*dirtied*/); /* book keeping */ transfer_addr += transfer_len; remaining -= transfer_len; done += transfer_len; } return done; } /* * character device file operations */ static struct file_operations sg_fops = { .owner = THIS_MODULE, .open = sg_open, .release = sg_close, .read = sg_read, .write = sg_write, }; /* sg_init() - Initialize character device * * XXX Should ideally be tied to the device, on device probe, not module init. */ static int sg_init(struct ape_dev *ape) { int rc; printk(KERN_DEBUG DRV_NAME " sg_init()\n"); /* allocate a dynamically allocated character device node */ rc = alloc_chrdev_region(&ape->cdevno, 0/*requested minor*/, 1/*count*/, DRV_NAME); /* allocation failed? */ if (rc < 0) { printk("alloc_chrdev_region() = %d\n", rc); goto fail_alloc; } /* couple the device file operations to the character device */ cdev_init(&ape->cdev, &sg_fops); ape->cdev.owner = THIS_MODULE; /* bring character device live */ rc = cdev_add(&ape->cdev, ape->cdevno, 1/*count*/); if (rc < 0) { printk("cdev_add() = %d\n", rc); goto fail_add; } printk(KERN_DEBUG "altpciechdma = %d:%d\n", MAJOR(ape->cdevno), MINOR(ape->cdevno)); return 0; fail_add: /* free the dynamically allocated character device node */ unregister_chrdev_region(ape->cdevno, 1/*count*/); fail_alloc: return -1; } /* sg_exit() - Cleanup character device * * XXX Should ideally be tied to the device, on device remove, not module exit. */ static void sg_exit(struct ape_dev *ape) { printk(KERN_DEBUG DRV_NAME " sg_exit()\n"); /* remove the character device */ cdev_del(&ape->cdev); /* free the dynamically allocated character device node */ unregister_chrdev_region(ape->cdevno, 1/*count*/); } #endif /* ALTPCIECHDMA_CDEV */ /* used to register the driver with the PCI kernel sub system * @see LDD3 page 311 */ static struct pci_driver pci_driver = { .name = DRV_NAME, .id_table = ids, .probe = probe, .remove = remove, /* resume, suspend are optional */ }; /** * alterapciechdma_init() - Module initialization, registers devices. */ static int __init alterapciechdma_init(void) { int rc = 0; printk(KERN_DEBUG DRV_NAME " init(), built at " __DATE__ " " __TIME__ "\n"); /* register this driver with the PCI bus driver */ rc = pci_register_driver(&pci_driver); if (rc < 0) return rc; return 0; } /** * alterapciechdma_init() - Module cleanup, unregisters devices. */ static void __exit alterapciechdma_exit(void) { printk(KERN_DEBUG DRV_NAME " exit(), built at " __DATE__ " " __TIME__ "\n"); /* unregister this driver from the PCI bus driver */ pci_unregister_driver(&pci_driver); } MODULE_LICENSE("GPL"); module_init(alterapciechdma_init); module_exit(alterapciechdma_exit);