Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: dma: Add Xilinx AXI DMA driver #73926

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

WorldofJARcraft
Copy link
Contributor

The Xilinx AXI DMA Controller is commonly used in FPGA designs. For example, it is a part of the 1G/2.5G AXI Ethernet subsystem. This patch adds a driver for the Xilinx AXI DMA that supports single MM2S and S2MM channels as well as the control and status streams used by the AXI Ethernet subsystem.
I will send a pull request for MAC and MDIO drivers for the AXI Ethernet subsystem shortly.

@zephyrbot zephyrbot added area: Devicetree Binding PR modifies or adds a Device Tree binding area: DMA Direct Memory Access labels Jun 7, 2024
@zephyrbot zephyrbot requested review from decsny, galak and teburd June 7, 2024 14:50
Copy link

github-actions bot commented Jun 7, 2024

Hello @WorldofJARcraft, and thank you very much for your first pull request to the Zephyr project!
Our Continuous Integration pipeline will execute a series of checks on your Pull Request commit messages and code, and you are expected to address any failures by updating the PR. Please take a look at our commit message guidelines to find out how to format your commit messages, and at our contribution workflow to understand how to update your Pull Request. If you haven't already, please make sure to review the project's Contributor Expectations and update (by amending and force-pushing the commits) your pull request if necessary.
If you are stuck or need help please join us on Discord and ask your question there. Additionally, you can escalate the review when applicable. 😊

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is a different compatible needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comes down to an idiosyncrasy in the Xilinx tools: Vitis can automatically generate a device tree from an (Vivado) FPGA project. This is useful, because MMIO addresses are assigned in the FPGA project and need to be reflected in the device tree. I have noticed that when the DMA is paired with any core other than the AXI Ethernet MAC core from the AXI Ethernet subsystem in the FPGA project, Vitis will generate a compatible string xlnx,axi-dma-1.00.a. However, if the DMA core is used with the MAC core, Vitis will generate a compatible xlnx,eth-dma. The main difference between using the DMA with the Ethernet MAC vs. with any other AXI-Stream module is that in the Ethernet subsystem, the DMA has additional control and status streams that are currently only used for checksum offloading. I hope that gets more clear when I send pull requests for the MAC driver next week.
Whether these additional streams are present is also encoded in the axistream-control-connected property, making the different compatible strings redundant. However, currently (at least until version 2023.2), Vitis will still generate two different compatible strings for the DMA.
I elected to allow both compatibles, because especially on the Zynq MPSOC, someone might use the Vitis-generated device tree for both the first-stage bootloader or u-boot (which is necessary for programming the DMA) and in Zephyr.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have submitted a pull request for the MAC driver: #73986

teburd
teburd previously approved these changes Jul 31, 2024
xlnx,addrwidth:
type: int
default: 32
description: DMA address width (64 or 32 bit), defaults to 32 bit
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does it default to 32 bit? should it just be required: true?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I have changed this accordingly.

@saizen408
Copy link

@WorldofJARcraft Is it on purpose that zephyr_library_sources_ifdef(CONFIG_XILINX_AXI_DMA dma_xilinx_axi_dma.c) is not included in zephyr/drivers/dma/CMakeLists.txt?

I'm fairly new to zephyr so forgive if I am missing something.

@WorldofJARcraft WorldofJARcraft force-pushed the xilinx_axi_dma_driver branch 2 times, most recently from 3017083 to 5e9675d Compare August 29, 2024 13:14
teburd
teburd previously approved these changes Aug 29, 2024
Copy link
Collaborator

@teburd teburd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some small changes could make this driver a bit more Zephyr-like.

k_oops() is pretty rare to see in a driver, generally if its a programming error __ASSERT(), if its a runtime error propogate the error code up the call stack along with a reasonable log message to inform whats going on.

config DMA_XILINX_AXI_DMA_SG_DESCRIPTOR_NUM_TX
int "Number of transfer descriptors allocated for transmission (TX)."
depends on DMA_XILINX_AXI_DMA
default 1024
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a very large number of scatter gather descriptors as a default, this could use some justification as a comment here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to 16, which is what I use on my test platform.
As the DMA is used with a variety of different peripherals, I expect users of this driver to overwrite the value with a value suitable for their specific application anyway.

bool halted = false;

/* running ISR in parallel could cause issues with the metadata */
const int irq_key = irq_lock();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need to lock all interrupts or is masking the dma interrupt enough?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depending on the application, this function might be called from interrupt handlers triggered by different devices, periodically using threads or timers or in any other possible context. Thus, I think locking all IRQs generally is the safest action.
I will wrap this into a configuration variable, such that users of the driver can choose to only mask the DMA interrupt on the same or both channels, respectively, if their application allows it.

if (channel >= cfg->channels) {
LOG_ERR("Invalid channel %" PRIu32 " - must be < %" PRIu32 "!", channel,
cfg->channels);
k_oops();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configuration errors shouldn't be a k_oops(), the error should be propogated up the callstack to the application which can do what it likes, perhaps asserting or panicking (k_oops())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed the oops() and use appropriate error messages / return values instead.

}
/* SG descriptors have 64-byte alignment requirements */
/* we check this here, were each descriptor */
if (nextdesc & XILINX_AXI_DMA_SG_DESCRIPTOR_ADDRESS_MASK) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__ASSERT() instead, this is a programming error

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

return 0;
}

static int dma_xilinx_axi_dma_suspend(const struct device *dev, uint32_t channel)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is unimplemented (along with resume) set the function pointers to NULL in the API struct instead, this is dealt with at an API level for you already

e.g. https://github.com/zephyrproject-rtos/zephyr/blob/main/include/zephyr/drivers/dma.h#L501

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@WorldofJARcraft
Copy link
Contributor Author

I have noticed that the DMA in conjunction with the Ethernet driver (#73986) stops receiving Ethernet packets at some point when CONFIG_NET_TC_RX_COUNT is not 0. Please do not merge while I investigate this.

@WorldofJARcraft
Copy link
Contributor Author

I have noticed that the DMA in conjunction with the Ethernet driver (#73986) stops receiving Ethernet packets at some point when CONFIG_NET_TC_RX_COUNT is not 0. Please do not merge while I investigate this.

This is fixed; the cause was resetting the DMA multiple times.

@WorldofJARcraft WorldofJARcraft marked this pull request as ready for review October 7, 2024 09:37
teburd
teburd previously approved these changes Oct 7, 2024
# SPDX-License-Identifier: Apache-2.0

description: |
Xilinx AXI DMA LogiCORE IP controller with compatibility string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why can't the same string be used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Xilinx' Vitis tool can automatically generate device trees. This feature is often used as a starting point before further customization. The output generated by Vitis is context-dependent; for DMAs used together with the Ethernet subsystem, it generates an eth-dma compatible, for other uses it generates the other, more generic, compatible.
Linux actually binds different drivers for the DMA depending on the compatible: the entirety of the Ethernet subsystem including DMA has one driver, and there is an independent driver for the stand-alone DMA (e.g., useful for custom IPs connected to the DMA).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small correction: Upstream Linux actually does not actively use the eth-dma compatible. Instead, the Ethernet driver resolves the dma using the axistream-connected handle. Still, using the eth-dma handle prevents the generic DMA driver from claiming the device.
References:

@WorldofJARcraft
Copy link
Contributor Author

I would like to do additional testing before this is eventually merged.
Should I convert this pull request back to a draft, or is it better to add a Do Not Merge label?

@decsny
Copy link
Member

decsny commented Oct 8, 2024

I would like to do additional testing before this is eventually merged. Should I convert this pull request back to a draft, or is it better to add a Do Not Merge label?

either works

@WorldofJARcraft WorldofJARcraft marked this pull request as draft October 9, 2024 06:16
The Xilinx AXI DMA Controller is commonly used in FPGA designs.
For example, it is a part of the 1G/2.5G AXI Ethernet subsystem.
This patch adds a driver for the Xilinx AXI DMA that supports
single MM2S and S2MM channels as well as the control and status
streams used by the AXI Ethernet subsystem.

Signed-off-by: Eric Ackermann <eric.ackermann@cispa.de>
@WorldofJARcraft
Copy link
Contributor Author

I found a small issue in the Ethernet driver (it allocated a buffer that was slightly too small).
I am confident that the DMA driver works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Devicetree Binding PR modifies or adds a Device Tree binding area: DMA Direct Memory Access platform: Xilinx Xilinx
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants