System reset(crash)during PL353 NAND controller initialization when Data-Cache is enabled in CR4 based system, - datacachefactory

I have come across a system crash during the PL353 NAND controller initialization, if D-cache enabled in cortex-r4 based micro controller. The NAND chip interfaced with ARM’s PL353 Static Memory Controller, and SMC is connected to main matrix bus through AXI bus. The driver initialize the controller and does some basic communication (write and read of predefined data). The NAND driver works fine with d-cache disabled, whereas the system get crash during NAND controller initialization, when D-cache is enabled.
The issue is resolved with workaround of enabling MPU, and defining memory region for NAND device memory map. I am unable to understand the behavior. Its hard to debug the issue, as the debugger losing connection after crash (cannot load PC register error is reported).
Note: The system getting crash after sending AXI command to NAND controller.
Please let me know how can I debug or get hint of the issue to resolve or else please let me know what is going wrong.

Related

Does a HDD/SSD use 1 or 2 device controllers to connect to the OS?

I am studying Operating Systems, and came across divice controllers.
I gathered that a device controller is hardware whereas a device driver is software.
I also know that a HDD and a SSD both have a small PCB buit into them and I assume those PCB's are the device controllers.
Now what I want to know is if there is another device controller on the PC/motherboard side of the bus/cable connecting the HDD/SSD to the OS?
Is the configuration: OS >> Device Driver >> Bus >> Device Controller >> HDD/SSD
Or is it: OS >> Device Driver >> Device Controler >> Bus >> Device Controller >> HDD/SSD
Or is it some other configuration?
Sites I visited for answers:
Tutorialspoint
JavaPoint
Idc online
Quora
Most hard-disks on desktop are SATA or NVME. eMMC is popular for smartphones but some might use something else. These are hardware interface standards that describe the way to interact electrically with those disks. It tells you what voltage at what frequency and for what amount of time you need to apply (a signal) to a certain pin (a bus line) to make the device behave or react in a certain way.
Most computers are separated in a few external chips. On desktop, it is mostly SATA, NVME, DRAM, USB, Audio Output, network card and graphics card. Even though there is few chips, the CPU would be very expensive if it had to support all those hardware interface standards on the same silicon chip. Instead, the CPU implements PCI/PCI-e as a general interface to interact with all those chips using memory mapped registers. Each of these devices have an external PCI-e controller between the device and the CPU. In the same order as above, you have AHCI, NVME controller, DRAM (not PCI and in the CPU), xHCI (almost everywhere) and Intel HDA (example). Network cards are PCI-e and there isn't really a controller outside the card. Graphics card are also self standing PCI-e devices.
So, the OS detects the registers of those devices that are mapped in the address space. The OS writes at those locations, and it will write the registers of the devices. PCI-e devices can read/write DRAM directly but this is managed by the CPU in its general implementation of the PCI-e standard most likely by doing some bus arbitration. The CPU really doesn't care what's the device that it is writing. It knows that there is a PCI register there and the OS instructs to write it with something so it does. It just happens that this device is an implementation of a standard and that the OS developers read the standard so they write the proper values in those registers and the proper data structures in DRAM to make sure that the device knows what to do.
Drivers implement the standard of the software interface of those controllers. The drivers are the ones instructing the CPU on values to write and writing the proper data structures in DRAM for giving commands to the controllers. The user thread simply places the syscall number in a conventionnal register determined by the OS developers and they call an instruction to jump into the kernel at a specific address that the kernel decides by writing a register at boot. Once there, the kernel looks at the register for the number and determines what driver to call based on the operation.
On Linux and some place else, it is done with files. You call syscalls on files and the OS has a driver attached to the file. They are called virtual files. A lot of transfer mechanisms are similar to the reading/writing files pattern so Linux uses that to make a general driver model where the kernel doesn't even need to understand the driver. The driver just says create me a file there that's not really on the hard disk and if someone opens it and calls an operation on it then call this function that's there in my driver. From there, the driver can do whatever it wants because it is in kernel mode. It just creates the proper data structures in DRAM and writes the registers of the device it drives to make it do something.

How to access a registered I2C device in the linux kernel from userspace

I want to be able to modify registers in a I2C slave device.
The device has a driver in the kernel, and the driver registers an I2C client with the address of it.
The driver is very basic and does output all the device functionality.
I want to access the registers from user space, but when I try to access it with I2C-dev, I get the error - Device or resource busy.
I don't want to add functionality to the driver, and I prefer to write a user space application to modify the device registers.
How can use I2C-dev to modify the registers in such a case?
So after investigating the I2C-dev I managed to overcome the problem. I noticed the flag I2C_SLAVE_FORCE inside the ioctl function. With the flag set, the function ignores if the I2C address is already registered.

Linux driver PCI error detection

In my Linux pcie driver for a certain pcie device, I implemented the pcie error
handler functions (error_detected, slot_reset methods, etc). I want
to trigger a pci error for me to exercise those handlers and observe
its behavior. I've read from the pci error recovery kernel
documentation that the 1st step is with error_detected method, called
by the system if it detected any error related to the pci device. The
good thing is that the system will detect it for the driver,
simplifying things. But I'm having problems with error detection
itself.
I tried to trigger the error via the PCIe device. On its FW, I
triggered a reset of its PCIe subsystem. As a result, the I/O rate
dropped to zero and the driver now can't send to the device.
Something indeed happened in their PCIe connection. However, I
couldn't see my error_detected method being called, when I was
expecting the kernel will detect the PCI error and call the handler.
Instead, some warning message appeared in the console as follows:
irq 16: nobody cared
handlers:
<...>
<...>
Disabling IRQ # 16
What baffles me more is that the injected PCI error seemed to brought
down that IRQ 16 device as well - which is definitely not the irq # of
my driver/device. This looks like a destructive event in the bus. Is this result expected for a PCI errors Any thoughts on why the kernel did not detect that
PCI error? Is there anything I could possibly missed during
registration of error handler methods?
If that is so, I'd like to ask for other means of injecting PCI
errors, in order for me to exercise my error handlers. Thanks!

How to simulate PCIe to debug my fpga endpoint

Im working on an fpga controller connected through pcie.
The only way i can debug the hardware is using chipscope. So i execute commands through my driver and check out the signals from the fpga.
The problem is that it takes a lot of time to build the project and load it to the fpga every time i want to check a signal to debug the project.
Is there an easier way to debug an fpga connected to pcie?
Is there a way i can simulate all the pcie signals and not have to run the fpga at all?
One thing you can do is to capture a trace of the PCIe transactions into a buffer, then read that out and replay it as the stimulus in a testbench during simulation.
You can use a BRAM or possibly FPGA-attached DRAM for the buffer.
You will probably need an alternate path for reading out the buffer. Xilinx has a JTAG to AXI master that you could use to read out the buffer. Or if your PCIe is stable you can read it out that way.
As mentioned in several comments, you want to do detailed debugging in simulation rather than in hardware. The loop time to debug via chipscope, determine the problem, come up with a new set of signals to probe, recompile, and push new code into the FPGA. This is a very painful process compared to debug in simulation.
If you are trying to debug PCIe, you can either get a PCIe BFM from a commercial vendor or possibly off of OpenCores, or you can use the capture buffer described.
If you are trying to debug your own logic and PCIe only comes in because that is the interface to the device, you are best off writing your own BFM that drives transactions to your internal logic as if it were the PCIe core. Reproduce the problem in sim, debug there, then go back to the FPGA once you have good code coverage and a decent suite of passing tests.

How does base address register gets address?

I've finished developing a pcie driver for an FPGA under a linux distributiuon. Everything works fine. But I'm wondering where the base address register in the PCI Endpoint of the FPGA gets the base address. When I've generated the PCIe Endpoint I was able to set up the length of the BAR, but not more.
In the PCIe driver I do the standard functions like pci_enable_device, but I do not set up specifically a base address.
So does the operating system set up the base address during startup? or how does it work?
By the side I would like to know what initialisations the operating system gernerally do if an pcie pcie device is connected. Since I do see my pci device in lspci even if the driver is unloaded.
Kind regards
Thomas
The address allocation for the PCI devices are generally done at the BIOS level. Let us refer to the x86 platform. If we look closely at the system address map, it would be something like this (image taken from BIOS DISASSEMBLY NINJUTSU, by Darmawan Salihun)
On the address map, there is a dedicated space to map the PCI memory regions. The same could be replicated using the output of /proc/iomem.
This implementation is platform dependent, and as the BIOS "knows" about the platform, it would set aside the addresses dedicated to the PCI slots. When a device is plugged into the slot, the BIOS interacts with the firmware on the device and actually sets up the memory regions for the device, such that the OS could make use of it.
Now coming to the drivers part. In Linux, the drivers follow a specific standard known as the 'Linux Device Model', which constitutes a Core Layer(PCI core), Host Controller Drivers(PCI Controller/Masters) and Client Drivers(PCI devices). When the PCI device(client) is plugged into the slot, the corresponding host controller knows about the attachment and it further informs the PCI core about it, and hence appears in the output of lspci.
lspci shows the devices which are identified by the host controller, in which case, it may or may not be tied to a driver. The core further traverses the drivers in the system, finds a matching one, and attaches to this device.
So, the reason you are seeing the device in the output of lspci is because the host controller has identified the device, and has informed the PCI core. It doesn't matter even if any driver is attached to the device or not.
On most consumer grade computers, BAR allocation seem to be done in the BIOS.
I suppose that in a hotplug capable architecture this must be done or at least triggered by the OS.

Resources