Skip to content

Commit 32f80e2

Browse files
M-Vaittinenjic23
authored andcommitted
iio: gts: Simplify available scale table build
Make available scale building more clear. This hurts the performance quite a bit by looping throgh the scales many times instead of doing everything in one loop. It however simplifies logic by: - decoupling the gain and scale allocations & computations - keeping the temporary 'per_time_gains' table inside the per_time_scales computation function. - separating building the 'all scales' table in own function and doing it based on the already computed per-time scales. Signed-off-by: Matti Vaittinen <[email protected]> Tested-by: [email protected] Link: https://patch.msgid.link/Z1_rRXqdhxhL6wBw@mva-rohm Signed-off-by: Jonathan Cameron <[email protected]>
1 parent 6eaf49f commit 32f80e2

File tree

1 file changed

+174
-98
lines changed

1 file changed

+174
-98
lines changed

drivers/iio/industrialio-gts-helper.c

Lines changed: 174 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -160,16 +160,123 @@ static void iio_gts_purge_avail_scale_table(struct iio_gts *gts)
160160
gts->num_avail_all_scales = 0;
161161
}
162162

163+
static int scale_eq(int *sc1, int *sc2)
164+
{
165+
return sc1[0] == sc2[0] && sc1[1] == sc2[1];
166+
}
167+
168+
static int scale_smaller(int *sc1, int *sc2)
169+
{
170+
if (sc1[0] != sc2[0])
171+
return sc1[0] < sc2[0];
172+
173+
/* If integer parts are equal, fixp parts */
174+
return sc1[1] < sc2[1];
175+
}
176+
177+
/*
178+
* Do a single table listing all the unique scales that any combination of
179+
* supported gains and times can provide.
180+
*/
181+
static int do_combined_scaletable(struct iio_gts *gts,
182+
size_t all_scales_tbl_bytes)
183+
{
184+
int t_idx, i, new_idx;
185+
int **scales = gts->per_time_avail_scale_tables;
186+
int *all_scales = kcalloc(gts->num_itime, all_scales_tbl_bytes,
187+
GFP_KERNEL);
188+
189+
if (!all_scales)
190+
return -ENOMEM;
191+
/*
192+
* Create table containing all of the supported scales by looping
193+
* through all of the per-time scales and copying the unique scales
194+
* into one sorted table.
195+
*
196+
* We assume all the gains for same integration time were unique.
197+
* It is likely the first time table had greatest time multiplier as
198+
* the times are in the order of preference and greater times are
199+
* usually preferred. Hence we start from the last table which is likely
200+
* to have the smallest total gains.
201+
*/
202+
t_idx = gts->num_itime - 1;
203+
memcpy(all_scales, scales[t_idx], all_scales_tbl_bytes);
204+
new_idx = gts->num_hwgain * 2;
205+
206+
while (t_idx-- > 0) {
207+
for (i = 0; i < gts->num_hwgain ; i++) {
208+
int *candidate = &scales[t_idx][i * 2];
209+
int chk;
210+
211+
if (scale_smaller(candidate, &all_scales[new_idx - 2])) {
212+
all_scales[new_idx] = candidate[0];
213+
all_scales[new_idx + 1] = candidate[1];
214+
new_idx += 2;
215+
216+
continue;
217+
}
218+
for (chk = 0; chk < new_idx; chk += 2)
219+
if (!scale_smaller(candidate, &all_scales[chk]))
220+
break;
221+
222+
if (scale_eq(candidate, &all_scales[chk]))
223+
continue;
224+
225+
memmove(&all_scales[chk + 2], &all_scales[chk],
226+
(new_idx - chk) * sizeof(int));
227+
all_scales[chk] = candidate[0];
228+
all_scales[chk + 1] = candidate[1];
229+
new_idx += 2;
230+
}
231+
}
232+
233+
gts->num_avail_all_scales = new_idx / 2;
234+
gts->avail_all_scales_table = all_scales;
235+
236+
return 0;
237+
}
238+
239+
static void iio_gts_free_int_table_array(int **arr, int num_tables)
240+
{
241+
int i;
242+
243+
for (i = 0; i < num_tables; i++)
244+
kfree(arr[i]);
245+
246+
kfree(arr);
247+
}
248+
249+
static int iio_gts_alloc_int_table_array(int ***arr, int num_tables, int num_table_items)
250+
{
251+
int i, **tmp;
252+
253+
tmp = kcalloc(num_tables, sizeof(**arr), GFP_KERNEL);
254+
if (!tmp)
255+
return -ENOMEM;
256+
257+
for (i = 0; i < num_tables; i++) {
258+
tmp[i] = kcalloc(num_table_items, sizeof(int), GFP_KERNEL);
259+
if (!tmp[i])
260+
goto err_free;
261+
}
262+
263+
*arr = tmp;
264+
265+
return 0;
266+
err_free:
267+
iio_gts_free_int_table_array(tmp, i);
268+
269+
return -ENOMEM;
270+
}
271+
163272
static int iio_gts_gain_cmp(const void *a, const void *b)
164273
{
165274
return *(int *)a - *(int *)b;
166275
}
167276

168-
static int gain_to_scaletables(struct iio_gts *gts, int **gains, int **scales)
277+
static int fill_and_sort_scaletables(struct iio_gts *gts, int **gains, int **scales)
169278
{
170-
int i, j, new_idx, time_idx, ret = 0;
171-
int *all_gains;
172-
size_t gain_bytes;
279+
int i, j, ret;
173280

174281
for (i = 0; i < gts->num_itime; i++) {
175282
/*
@@ -189,71 +296,69 @@ static int gain_to_scaletables(struct iio_gts *gts, int **gains, int **scales)
189296
}
190297
}
191298

192-
gain_bytes = array_size(gts->num_hwgain, sizeof(int));
193-
all_gains = kcalloc(gts->num_itime, gain_bytes, GFP_KERNEL);
194-
if (!all_gains)
195-
return -ENOMEM;
299+
return 0;
300+
}
301+
302+
static void compute_per_time_gains(struct iio_gts *gts, int **gains)
303+
{
304+
int i, j;
305+
306+
for (i = 0; i < gts->num_itime; i++) {
307+
for (j = 0; j < gts->num_hwgain; j++)
308+
gains[i][j] = gts->hwgain_table[j].gain *
309+
gts->itime_table[i].mul;
310+
}
311+
}
312+
313+
static int compute_per_time_tables(struct iio_gts *gts, int **scales)
314+
{
315+
int **per_time_gains;
316+
int ret;
196317

197318
/*
198-
* We assume all the gains for same integration time were unique.
199-
* It is likely the first time table had greatest time multiplier as
200-
* the times are in the order of preference and greater times are
201-
* usually preferred. Hence we start from the last table which is likely
202-
* to have the smallest total gains.
319+
* Create a temporary array of the 'total gains' for each integration
320+
* time.
203321
*/
204-
time_idx = gts->num_itime - 1;
205-
memcpy(all_gains, gains[time_idx], gain_bytes);
206-
new_idx = gts->num_hwgain;
322+
ret = iio_gts_alloc_int_table_array(&per_time_gains, gts->num_itime,
323+
gts->num_hwgain);
324+
if (ret)
325+
return ret;
207326

208-
while (time_idx-- > 0) {
209-
for (j = 0; j < gts->num_hwgain; j++) {
210-
int candidate = gains[time_idx][j];
211-
int chk;
327+
compute_per_time_gains(gts, per_time_gains);
212328

213-
if (candidate > all_gains[new_idx - 1]) {
214-
all_gains[new_idx] = candidate;
215-
new_idx++;
329+
/* Convert the gains to scales and populate the scale tables */
330+
ret = fill_and_sort_scaletables(gts, per_time_gains, scales);
216331

217-
continue;
218-
}
219-
for (chk = 0; chk < new_idx; chk++)
220-
if (candidate <= all_gains[chk])
221-
break;
332+
iio_gts_free_int_table_array(per_time_gains, gts->num_itime);
222333

223-
if (candidate == all_gains[chk])
224-
continue;
334+
return ret;
335+
}
225336

226-
memmove(&all_gains[chk + 1], &all_gains[chk],
227-
(new_idx - chk) * sizeof(int));
228-
all_gains[chk] = candidate;
229-
new_idx++;
230-
}
231-
}
337+
/*
338+
* Create a table of supported scales for each supported integration time.
339+
* This can be used as available_scales by drivers which don't allow scale
340+
* setting to change the integration time to display correct set of scales
341+
* depending on the used integration time.
342+
*/
343+
static int **create_per_time_scales(struct iio_gts *gts)
344+
{
345+
int **per_time_scales, ret;
232346

233-
gts->avail_all_scales_table = kcalloc(new_idx, 2 * sizeof(int),
234-
GFP_KERNEL);
235-
if (!gts->avail_all_scales_table) {
236-
ret = -ENOMEM;
237-
goto free_out;
238-
}
239-
gts->num_avail_all_scales = new_idx;
347+
ret = iio_gts_alloc_int_table_array(&per_time_scales, gts->num_itime,
348+
gts->num_hwgain * 2);
349+
if (ret)
350+
return ERR_PTR(ret);
240351

241-
for (i = 0; i < gts->num_avail_all_scales; i++) {
242-
ret = iio_gts_total_gain_to_scale(gts, all_gains[i],
243-
&gts->avail_all_scales_table[i * 2],
244-
&gts->avail_all_scales_table[i * 2 + 1]);
352+
ret = compute_per_time_tables(gts, per_time_scales);
353+
if (ret)
354+
goto err_out;
245355

246-
if (ret) {
247-
kfree(gts->avail_all_scales_table);
248-
gts->num_avail_all_scales = 0;
249-
goto free_out;
250-
}
251-
}
356+
return per_time_scales;
252357

253-
free_out:
254-
kfree(all_gains);
358+
err_out:
359+
iio_gts_free_int_table_array(per_time_scales, gts->num_itime);
255360

256-
return ret;
361+
return ERR_PTR(ret);
257362
}
258363

259364
/**
@@ -275,55 +380,26 @@ static int gain_to_scaletables(struct iio_gts *gts, int **gains, int **scales)
275380
*/
276381
static int iio_gts_build_avail_scale_table(struct iio_gts *gts)
277382
{
278-
int **per_time_gains, **per_time_scales, i, j, ret = -ENOMEM;
383+
int ret, all_scales_tbl_bytes;
384+
int **per_time_scales;
279385

280-
per_time_gains = kcalloc(gts->num_itime, sizeof(*per_time_gains), GFP_KERNEL);
281-
if (!per_time_gains)
282-
return ret;
283-
284-
per_time_scales = kcalloc(gts->num_itime, sizeof(*per_time_scales), GFP_KERNEL);
285-
if (!per_time_scales)
286-
goto free_gains;
287-
288-
for (i = 0; i < gts->num_itime; i++) {
289-
per_time_scales[i] = kcalloc(gts->num_hwgain, 2 * sizeof(int),
290-
GFP_KERNEL);
291-
if (!per_time_scales[i])
292-
goto err_free_out;
293-
294-
per_time_gains[i] = kcalloc(gts->num_hwgain, sizeof(int),
295-
GFP_KERNEL);
296-
if (!per_time_gains[i]) {
297-
kfree(per_time_scales[i]);
298-
goto err_free_out;
299-
}
300-
301-
for (j = 0; j < gts->num_hwgain; j++)
302-
per_time_gains[i][j] = gts->hwgain_table[j].gain *
303-
gts->itime_table[i].mul;
304-
}
386+
if (unlikely(check_mul_overflow(gts->num_hwgain, 2 * sizeof(int),
387+
&all_scales_tbl_bytes)))
388+
return -EOVERFLOW;
305389

306-
ret = gain_to_scaletables(gts, per_time_gains, per_time_scales);
307-
if (ret)
308-
goto err_free_out;
390+
per_time_scales = create_per_time_scales(gts);
391+
if (IS_ERR(per_time_scales))
392+
return PTR_ERR(per_time_scales);
309393

310-
for (i = 0; i < gts->num_itime; i++)
311-
kfree(per_time_gains[i]);
312-
kfree(per_time_gains);
313394
gts->per_time_avail_scale_tables = per_time_scales;
314395

315-
return 0;
316-
317-
err_free_out:
318-
for (i--; i >= 0; i--) {
319-
kfree(per_time_scales[i]);
320-
kfree(per_time_gains[i]);
396+
ret = do_combined_scaletable(gts, all_scales_tbl_bytes);
397+
if (ret) {
398+
iio_gts_free_int_table_array(per_time_scales, gts->num_itime);
399+
return ret;
321400
}
322-
kfree(per_time_scales);
323-
free_gains:
324-
kfree(per_time_gains);
325401

326-
return ret;
402+
return 0;
327403
}
328404

329405
static void iio_gts_us_to_int_micro(int *time_us, int *int_micro_times,

0 commit comments

Comments
 (0)