I had a frustrating problem with the TI Sitara AM335x at work that first cropped up as non-working wl12xx WiFi on kernels newer than 3.12 (incidentally, 3.12 is the last kernel on which TI “supports” the wl12xx, they are now telling customers to use wl18xx, though in this case it will not make a difference).

I hooked up the platform data glue for the wlcore SDIO module in the new way introduced in 3.13 – add your board to the table in arch/arm/mach-omap2/pdata-quirks.c and have your routine call legacy_init_wl12xx() with the appropriate clock and IRQ pin setting. See, for example, the omap3_evm_legacy_init() routine. With that and the right information in our device tree (DTS) file, the wlcore driver found our card and began to initialize it.

Unfortunately SDIO then stalled, and it did so on its first attempt to use DMA – turning on CONFIG_MMC_DEBUG showed that CMD52 worked fine (single register accesses) but then it came time to use CMD53 to perform a block transfer and this never returned because the DMA callback never triggered.

As it turned out our board places the WiFi interface on the MMC2 bus (the third controller on Sitara, called mmc3 in Device Tree as they are numbered starting with 1 rather than 0). mmc1 and mmc2 have direct DMA channels but mmc3 requires the use of a cross-bar or “xbar” switch. In our case we mapped Event 1 and Event 2 to channels 12 and 13 like this:

&edma {
        ti,edma-xbar-event-map = <1 12
                                  2 13>;

The DMA linkage in &mmc3 then looks like:

dmas = <&edma 12
        &edma 13>;
dma-names = "tx", "rx";

The code responsible for looking at ti,edma-xbar-event-map and actually configuring these mappings is found in arch/arm/common/edma.c and this is where I finally found a problem. The function edma_of_read_u32_to_s16_array() is supposed to read out the device tree data and it does so in the 3.12 kernel, terminating the entries with a -1 to indicate the end of the list. In 3.13 someone cleaned up this admittedly sloppy-looking routine and unfortunately terminated the list at the zeroeth entry unconditionally.

The solution is as simple as replacing the implementation of edma_of_read_u32_to_s16_array() with the one from the 3.12 kernel. However I noticed that the (at the time of writing this) in-development 3.16 kernel contains a more thorough and cleaner fix by Thomas Gleixner so users of 3.16 and beyond will not have to worry about this.

In the end we have wl12xx (or wl18xx for that matter) WiFi working on 3.13 through 3.15 kernels now, and it should continue to work beyond that as well.