Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dmaengine: pl08x: allocate OF slave channel data at probe time

The current OF translation of channels can never work with
any DMA client using the DMA channels directly: the only way
to get the channels initialized properly is in the
dma_async_device_register() call, where chan->dev etc is
allocated and initialized.

Allocate and initialize all possible DMA channels and
only augment a target channel with the periph_buses at
of_xlate(). Remove some const settings to make things work.

Cc: Maxime Ripard <maxime.ripard@free-electrons.com>
Tested-by: Joachim Eastwood <manabian@gmail.com>
Tested-by: Johannes Stezenbach <js@sig21.net>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>

authored by

Linus Walleij and committed by
Vinod Koul
f9cd4761 f55532a0

+59 -29
+58 -28
drivers/dma/amba-pl08x.c
··· 107 107 /** 108 108 * struct vendor_data - vendor-specific config parameters for PL08x derivatives 109 109 * @channels: the number of channels available in this variant 110 + * @signals: the number of request signals available from the hardware 110 111 * @dualmaster: whether this version supports dual AHB masters or not. 111 112 * @nomadik: whether the channels have Nomadik security extension bits 112 113 * that need to be checked for permission before use and some registers are 113 114 * missing 114 115 * @pl080s: whether this version is a PL080S, which has separate register and 115 116 * LLI word for transfer size. 117 + * @max_transfer_size: the maximum single element transfer size for this 118 + * PL08x variant. 116 119 */ 117 120 struct vendor_data { 118 121 u8 config_offset; 119 122 u8 channels; 123 + u8 signals; 120 124 bool dualmaster; 121 125 bool nomadik; 122 126 bool pl080s; ··· 239 235 struct virt_dma_chan vc; 240 236 struct pl08x_phy_chan *phychan; 241 237 const char *name; 242 - const struct pl08x_channel_data *cd; 238 + struct pl08x_channel_data *cd; 243 239 struct dma_slave_config cfg; 244 240 struct pl08x_txd *at; 245 241 struct pl08x_driver_data *host; ··· 1913 1909 1914 1910 if (slave) { 1915 1911 chan->cd = &pl08x->pd->slave_channels[i]; 1912 + /* 1913 + * Some implementations have muxed signals, whereas some 1914 + * use a mux in front of the signals and need dynamic 1915 + * assignment of signals. 1916 + */ 1917 + chan->signal = i; 1916 1918 pl08x_dma_slave_init(chan); 1917 1919 } else { 1918 1920 chan->cd = &pl08x->pd->memcpy_channel; ··· 2060 2050 struct of_dma *ofdma) 2061 2051 { 2062 2052 struct pl08x_driver_data *pl08x = ofdma->of_dma_data; 2063 - struct pl08x_channel_data *data; 2064 - struct pl08x_dma_chan *chan; 2065 2053 struct dma_chan *dma_chan; 2054 + struct pl08x_dma_chan *plchan; 2066 2055 2067 2056 if (!pl08x) 2068 2057 return NULL; 2069 2058 2070 - if (dma_spec->args_count != 2) 2059 + if (dma_spec->args_count != 2) { 2060 + dev_err(&pl08x->adev->dev, 2061 + "DMA channel translation requires two cells\n"); 2071 2062 return NULL; 2063 + } 2072 2064 2073 2065 dma_chan = pl08x_find_chan_id(pl08x, dma_spec->args[0]); 2074 - if (dma_chan) 2075 - return dma_get_slave_channel(dma_chan); 2076 - 2077 - chan = devm_kzalloc(pl08x->slave.dev, sizeof(*chan) + sizeof(*data), 2078 - GFP_KERNEL); 2079 - if (!chan) 2066 + if (!dma_chan) { 2067 + dev_err(&pl08x->adev->dev, 2068 + "DMA slave channel not found\n"); 2080 2069 return NULL; 2070 + } 2081 2071 2082 - data = (void *)&chan[1]; 2083 - data->bus_id = "(none)"; 2084 - data->periph_buses = dma_spec->args[1]; 2072 + plchan = to_pl08x_chan(dma_chan); 2073 + dev_dbg(&pl08x->adev->dev, 2074 + "translated channel for signal %d\n", 2075 + dma_spec->args[0]); 2085 2076 2086 - chan->cd = data; 2087 - chan->host = pl08x; 2088 - chan->slave = true; 2089 - chan->name = data->bus_id; 2090 - chan->state = PL08X_CHAN_IDLE; 2091 - chan->signal = dma_spec->args[0]; 2092 - chan->vc.desc_free = pl08x_desc_free; 2093 - 2094 - vchan_init(&chan->vc, &pl08x->slave); 2095 - 2096 - return dma_get_slave_channel(&chan->vc.chan); 2077 + /* Augment channel data for applicable AHB buses */ 2078 + plchan->cd->periph_buses = dma_spec->args[1]; 2079 + return dma_get_slave_channel(dma_chan); 2097 2080 } 2098 2081 2099 2082 static int pl08x_of_probe(struct amba_device *adev, ··· 2094 2091 struct device_node *np) 2095 2092 { 2096 2093 struct pl08x_platform_data *pd; 2094 + struct pl08x_channel_data *chanp = NULL; 2097 2095 u32 cctl_memcpy = 0; 2098 2096 u32 val; 2099 2097 int ret; 2098 + int i; 2100 2099 2101 2100 pd = devm_kzalloc(&adev->dev, sizeof(*pd), GFP_KERNEL); 2102 2101 if (!pd) ··· 2200 2195 /* Use the buses that can access memory, obviously */ 2201 2196 pd->memcpy_channel.periph_buses = pd->mem_buses; 2202 2197 2198 + /* 2199 + * Allocate channel data for all possible slave channels (one 2200 + * for each possible signal), channels will then be allocated 2201 + * for a device and have it's AHB interfaces set up at 2202 + * translation time. 2203 + */ 2204 + chanp = devm_kcalloc(&adev->dev, 2205 + pl08x->vd->signals, 2206 + sizeof(struct pl08x_channel_data), 2207 + GFP_KERNEL); 2208 + if (!chanp) 2209 + return -ENOMEM; 2210 + 2211 + pd->slave_channels = chanp; 2212 + for (i = 0; i < pl08x->vd->signals; i++) { 2213 + /* chanp->periph_buses will be assigned at translation */ 2214 + chanp->bus_id = kasprintf(GFP_KERNEL, "slave%d", i); 2215 + chanp++; 2216 + } 2217 + pd->num_slave_channels = pl08x->vd->signals; 2218 + 2203 2219 pl08x->pd = pd; 2204 2220 2205 2221 return of_dma_controller_register(adev->dev.of_node, pl08x_of_xlate, ··· 2259 2233 ret = -ENOMEM; 2260 2234 goto out_no_pl08x; 2261 2235 } 2236 + 2237 + /* Assign useful pointers to the driver state */ 2238 + pl08x->adev = adev; 2239 + pl08x->vd = vd; 2262 2240 2263 2241 /* Initialize memcpy engine */ 2264 2242 dma_cap_set(DMA_MEMCPY, pl08x->memcpy.cap_mask); ··· 2313 2283 goto out_no_platdata; 2314 2284 } 2315 2285 } 2316 - 2317 - /* Assign useful pointers to the driver state */ 2318 - pl08x->adev = adev; 2319 - pl08x->vd = vd; 2320 2286 2321 2287 /* By default, AHB1 only. If dualmaster, from platform */ 2322 2288 pl08x->lli_buses = PL08X_AHB1; ··· 2464 2438 static struct vendor_data vendor_pl080 = { 2465 2439 .config_offset = PL080_CH_CONFIG, 2466 2440 .channels = 8, 2441 + .signals = 16, 2467 2442 .dualmaster = true, 2468 2443 .max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK, 2469 2444 }; ··· 2472 2445 static struct vendor_data vendor_nomadik = { 2473 2446 .config_offset = PL080_CH_CONFIG, 2474 2447 .channels = 8, 2448 + .signals = 32, 2475 2449 .dualmaster = true, 2476 2450 .nomadik = true, 2477 2451 .max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK, ··· 2481 2453 static struct vendor_data vendor_pl080s = { 2482 2454 .config_offset = PL080S_CH_CONFIG, 2483 2455 .channels = 8, 2456 + .signals = 32, 2484 2457 .pl080s = true, 2485 2458 .max_transfer_size = PL080S_CONTROL_TRANSFER_SIZE_MASK, 2486 2459 }; ··· 2489 2460 static struct vendor_data vendor_pl081 = { 2490 2461 .config_offset = PL080_CH_CONFIG, 2491 2462 .channels = 2, 2463 + .signals = 16, 2492 2464 .dualmaster = false, 2493 2465 .max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK, 2494 2466 };
+1 -1
include/linux/amba/pl08x.h
··· 86 86 * @mem_buses: buses which memory can be accessed from: PL08X_AHB1 | PL08X_AHB2 87 87 */ 88 88 struct pl08x_platform_data { 89 - const struct pl08x_channel_data *slave_channels; 89 + struct pl08x_channel_data *slave_channels; 90 90 unsigned int num_slave_channels; 91 91 struct pl08x_channel_data memcpy_channel; 92 92 int (*get_xfer_signal)(const struct pl08x_channel_data *);