Are the am335x_pru_package examples incorrectly (dangerously) accessing DDR memory?

I have been able to load/start/run/stop a PRU core from 4.4.30-ti-r64 using just the uio_pruss (& uio) drivers, without any of the prussdrv code. Big milestone in my project.

A long time ago I asked a question about the examples in the pru here: https://groups.google.com/d/topic/beagleboard/Kv03QMsgOmo/discussion

as did someone else here: https://groups.google.com/d/topic/beagleboard/vnZ9eSzoo6Y/discussion

but I found no answer to help me. From a thorough review of the examples in the am335x_pru_package (using the prussdrv uio-based pru driver) here: https://github.com/beagleboard/am335x_pru_package/blob/master/pru_sw/example_apps/PRU_PRUtoPRU_Interrupt/PRU_PRUtoPRU_Interrupt.c

it appears to me that this example (to teach/illustrate proper use of pru in the BB family) works only by luck - or taking advantage of some bit of information that is undocumented (from my research).

Specifically, when using the L3 DDR (main) memory to share data between the A8 and PRU, it seems that rather than using the 256KiB size region starting at 0x9c94_0000 (on my BBB rev C) it seems to simply hardcode 0x8000_0000 and write away. See here:

static int LOCAL_exampleInit () { void *DDR_regaddr; /* open the device */ mem_fd = open("/dev/mem", O_RDWR); if (mem_fd < 0) { printf("Failed to open /dev/mem (%s)\n", strerror(errno)); return -1; } /* map the memory */ ddrMem = mmap(0, 0x0FFFFFFF, PROT_WRITE | PROT_READ, MAP_SHARED, mem_fd, DDR_BASEADDR); if (ddrMem == NULL) { printf("Failed to map the device (%s)\n", strerror(errno)); close(mem_fd); return -1; } //FLush the flag locations of PRU0 and PRU1 DDR_regaddr = ddrMem; *(unsigned long*) DDR_regaddr = 0x00; DDR_regaddr = ddrMem + 0x000000004; *(unsigned long*) DDR_regaddr = 0x00; return(0); }

Hi,

I believe the example is indeed buggy, and works by accident. You can check “cat /proc/iomem” and see that your mapped region overlaps the kernel code.

If you need to properly allocate and map DDR between ARM and PRU, then I would suggest to:

  1. Load PRU UIO with “modprobe uio_pruss extram_pool_sz=2097152” in order to tell it allocate contiguous memory.

  2. Use prussdrv_map_extmem() from ARM side to map the allocated DDR chunk. Example

  3. Get the physical DDR base address of the chunk by using prussdrv_get_phys_addr(). Example

  4. Write the physical DDR base address to a pre-defined location in PRU DRAM. If you are using pasm, then just hard-code the pre-defined location. If your firmware is in ELF format, there is a bit nicer way.

Regards,
Dimitar

Very useful response. At the least it verifies that my conclusions are not totally unfounded. I suppose it could be just dumb luck that it works at all - but I also wonder if there’s not something that kernel gurus know about what the first pages of memory are used for, and the author took advantage of that. I also see that on my system, kernel code starts at 0x08000_8000. Still not a good practice though IMO.

I’m wondering if there isn’t some way to use the DT to not only enable the PRUSS, but also select a driver, and configure the driver parameters (e.g. “extram_pool_sz”) automatically. I read that the remoteproc and uio drivers conflict, so none is loaded by default. I suppose it would require a change to the pruss driver (whatever reads the “ti,pruss-v2” entry in the device tree) to support this, but it would be convenient.

Thanks.

Per arch/arm/kernel/head.S, 0x80004000 or 0x80003000 is where the MMU page directory table is stored. I could not trace who uses the lower addresses. Nevertheless, I wouldn’t hardcode my PRU to write there :slight_smile:

I do not see DT bindings for extram_pool_sz in Beagleboard v4.4 kernel.

Regards,
Dimitar