-
Notifications
You must be signed in to change notification settings - Fork 6.6k
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
base: main
Are you sure you want to change the base?
drivers: dma: Add Xilinx AXI DMA driver #73926
Conversation
Hello @WorldofJARcraft, and thank you very much for your first pull request to the Zephyr project! |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
1279281
to
edaca6d
Compare
edaca6d
to
500e561
Compare
xlnx,addrwidth: | ||
type: int | ||
default: 32 | ||
description: DMA address width (64 or 32 bit), defaults to 32 bit |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
500e561
to
1d7260b
Compare
@WorldofJARcraft Is it on purpose that I'm fairly new to zephyr so forgive if I am missing something. |
3017083
to
5e9675d
Compare
b0f1bfd
to
2c7871f
Compare
There was a problem hiding this 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.
drivers/dma/Kconfig.xilinx_axi_dma
Outdated
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
drivers/dma/dma_xilinx_axi_dma.c
Outdated
bool halted = false; | ||
|
||
/* running ISR in parallel could cause issues with the metadata */ | ||
const int irq_key = irq_lock(); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
drivers/dma/dma_xilinx_axi_dma.c
Outdated
if (channel >= cfg->channels) { | ||
LOG_ERR("Invalid channel %" PRIu32 " - must be < %" PRIu32 "!", channel, | ||
cfg->channels); | ||
k_oops(); |
There was a problem hiding this comment.
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())
There was a problem hiding this comment.
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.
drivers/dma/dma_xilinx_axi_dma.c
Outdated
} | ||
/* SG descriptors have 64-byte alignment requirements */ | ||
/* we check this here, were each descriptor */ | ||
if (nextdesc & XILINX_AXI_DMA_SG_DESCRIPTOR_ADDRESS_MASK) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
drivers/dma/dma_xilinx_axi_dma.c
Outdated
return 0; | ||
} | ||
|
||
static int dma_xilinx_axi_dma_suspend(const struct device *dev, uint32_t channel) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
2c7871f
to
d9cf04e
Compare
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. |
d9cf04e
to
89b98d2
Compare
This is fixed; the cause was resetting the DMA multiple times. |
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
description: | | ||
Xilinx AXI DMA LogiCORE IP controller with compatibility string |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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:
- Ethernet driver: https://github.com/torvalds/linux/blob/master/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
- DMA driver: https://github.com/torvalds/linux/blob/master/drivers/dma/xilinx/xilinx_dma.c
- My other PR soc: add OpenHW Group CVA6 SoC #77732 has an exemplary device tree based on what Vitis generated automatically (notice the
eth-dma
compatible): https://github.com/zephyrproject-rtos/zephyr/blob/eda4bedfb96b2f07dd65142dc335d247e680b971/dts/riscv/openhwgroup/cv64a6.dtsi
3f7c836
to
0f49ae5
Compare
I would like to do additional testing before this is eventually merged. |
either works |
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>
0f49ae5
to
0369124
Compare
I found a small issue in the Ethernet driver (it allocated a buffer that was slightly too small). |
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.