Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 71 additions & 3 deletions drivers/jesd204/jesd204-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/property.h>
#include <linux/slab.h>
Expand Down Expand Up @@ -140,6 +141,11 @@
}
EXPORT_SYMBOL_GPL(jesd204_link_get_paused);

/**
* jesd204_device_count_get() - Get the total number of registered JESD204 devices
*
* Return: The current count of registered JESD204 devices in the framework.
*/
int jesd204_device_count_get(void)
{
return jesd204_device_count;
Expand Down Expand Up @@ -240,7 +246,7 @@

rate = lnk->num_converters * lnk->bits_per_sample *
encoding_n * lnk->sample_rate;
do_div(rate, lnk->num_lanes * encoding_d * sample_rate_div);

Check warning on line 249 in drivers/jesd204/jesd204-core.c

View workflow job for this annotation

GitHub Actions / checks / checks

coccicheck: 1-7 WARNING do_div() does a 64-by-32 division, please consider using div64_u64 instead.

*lane_rate_hz = rate;

Expand Down Expand Up @@ -432,20 +438,42 @@
}
EXPORT_SYMBOL_GPL(jesd204_link_get_lmfc_lemc_rate);

/**
* jesd204_dev_get_topology_top_dev() - Get the top-level device for a JESD204 topology
* @jdev: Pointer to a JESD204 device within the topology
*
* This function finds and returns the top-level device (typically ADC, DAC,
* or transceiver) for the JESD204 topology that contains the given device.
* If the device itself is a top-level device, it returns that directly.
* Otherwise, it searches through all topologies to find where this device
* has connections.
*
* Return: Pointer to the top-level jesd204_dev_top structure, or NULL if
* the device doesn't belong to any topology.
*/
struct jesd204_dev_top *jesd204_dev_get_topology_top_dev(struct jesd204_dev *jdev)
{
struct jesd204_dev_top *jdev_top = jesd204_dev_top_dev(jdev);
struct jesd204_dev_top *found = NULL;

if (jdev_top)
return jdev_top;

/* FIXME: enforce that one jdev object can only be in one topology */
list_for_each_entry(jdev_top, &jesd204_topologies, entry) {
if (!jesd204_dev_has_con_in_topology(jdev, jdev_top))
continue;
return jdev_top;
if (found) {
jesd204_warn(jdev,
"Device belongs to multiple topologies (%d, %d); using first\n",
found->topo_id, jdev_top->topo_id);
break;
}
found = jdev_top;
}

if (found)
return found;

jesd204_warn(jdev, "Device isn't a top-device, nor does it belong to topology with top-device\n");

return NULL;
Expand Down Expand Up @@ -617,6 +645,17 @@
vaf);
}

/**
* jesd204_printk() - Print a kernel message for a JESD204 device
* @level: Kernel log level string (e.g., KERN_ERR, KERN_INFO)
* @jdev: Pointer to the JESD204 device structure (may be NULL)
* @fmt: printf-style format string
* @...: Arguments for the format string
*
* This function prints a kernel message with JESD204 device context.
* It handles NULL device pointers gracefully and includes device tree
* node information when available.
*/
void jesd204_printk(const char *level, const struct jesd204_dev *jdev,
const char *fmt, ...)
{
Expand Down Expand Up @@ -663,6 +702,30 @@
return 0;
}

static void jesd204_dev_free_links(struct jesd204_dev_top *jdev_top)
{
unsigned int i;

if (jdev_top->active_links) {
for (i = 0; i < jdev_top->num_links; i++) {
/* Only free if not from init_links (static allocation) */
if (!jdev_top->init_links ||
!jdev_top->init_links[i].lane_ids)
kfree(jdev_top->active_links[i].link.lane_ids);
}
kfree(jdev_top->active_links);
}

if (jdev_top->staged_links) {
for (i = 0; i < jdev_top->num_links; i++) {
if (!jdev_top->init_links ||
!jdev_top->init_links[i].lane_ids)
kfree(jdev_top->staged_links[i].link.lane_ids);
}
kfree(jdev_top->staged_links);
}
}

static int jesd204_dev_init_stop_states(struct jesd204_dev *jdev,
struct device_node *np)
{
Expand Down Expand Up @@ -725,6 +788,7 @@

jdev = &jdev_top->jdev;

mutex_init(&jdev_top->fsm_lock);
jdev_top->topo_id = topo_id;
jdev_top->num_links = ret;
for (i = 0; i < jdev_top->num_links; i++)
Expand Down Expand Up @@ -923,8 +987,10 @@

for_each_node_with_property(np, "jesd204-device") {
jdev = jesd204_dev_alloc(np);
if (IS_ERR(jdev))
if (IS_ERR(jdev)) {
of_node_put(np);
return PTR_ERR(jdev);
}
}

list_for_each_entry(jdev, &jesd204_device_list, entry) {
Expand Down Expand Up @@ -962,7 +1028,7 @@
return 0;

if (jlink->lane_ids)
kfree(jlink->lane_ids);

Check warning on line 1031 in drivers/jesd204/jesd204-core.c

View workflow job for this annotation

GitHub Actions / checks / checks

coccicheck: 2-7 WARNING NULL check before some freeing functions is not needed.

jlink->lane_ids = kmalloc_array(jlink->num_lanes,
sizeof(*jlink->lane_ids),
Expand Down Expand Up @@ -1177,6 +1243,8 @@
}
jdev_top = jesd204_dev_top_dev(jdev);
list_del(&jdev_top->entry);
jesd204_dev_free_links(jdev_top);
mutex_destroy(&jdev_top->fsm_lock);
kfree(jdev_top);
jesd204_topologies_count--;
}
Expand Down
25 changes: 19 additions & 6 deletions drivers/jesd204/jesd204-fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@

#define JESD204_FSM_BUSY BIT(0)

/*
* Internal error code used to signal that the current FSM state doesn't match
* the expected state during validation. This is distinct from standard errno
* values to allow special handling (e.g., skipping states during resume).
* The value 9000 is chosen to be well outside the range of standard errno
* values (typically 1-4095) to avoid conflicts.
*/
#define EINVALID_STATE 9000

typedef int (*jesd204_fsm_cb)(struct jesd204_dev *jdev,
Expand Down Expand Up @@ -318,7 +325,7 @@
static int jesd204_fsm_propagate_cb_top_level(struct jesd204_dev *jdev_it,
struct jesd204_fsm_data *fsm_data)
{
int i, ret;
int i, ret = 0;

if (fsm_data->link_idx != JESD204_LINKS_ALL)
return jesd204_fsm_handle_con_cb(jdev_it, NULL,
Expand All @@ -330,7 +337,6 @@
if (ret)
break;
}
/* FIXME: error message here? */

return ret;
}
Expand Down Expand Up @@ -371,6 +377,10 @@
static int __jesd204_fsm_propagate_rollback_cb(struct jesd204_dev *jdev,
struct jesd204_fsm_data *data)
{
jesd204_dbg(jdev, "Rolling back from state %s to %s\n",
jesd204_state_str(data->cur_state),
jesd204_state_str(data->nxt_state));

jesd204_fsm_propagate_rollback_cb_top_level(jdev, data);
jesd204_fsm_propagate_rollback_cb_outputs(jdev, data);
jesd204_fsm_propagate_rollback_cb_inputs(jdev, data);
Expand Down Expand Up @@ -1180,6 +1190,9 @@

jesd204_fsm_handle_stop_state(jdev, link_idx, fsm_data);

if (!jdev->dev_data)
return JESD204_STATE_CHANGE_DONE;

state_op = &jdev->dev_data->state_ops[it->table[0].op];

if (fsm_data->rollback)
Expand Down Expand Up @@ -1294,20 +1307,16 @@
const struct jesd204_state_op *state_op;
int ret, ret1, cnt;

cnt = jesd204_device_count_get();

Check warning on line 1310 in drivers/jesd204/jesd204-fsm.c

View workflow job for this annotation

GitHub Actions / build_llvm_x86_64 / build

clang_analyzer: Value stored to 'cnt' is never read [deadcode.DeadStores] 1310 | cnt = jesd204_device_count_get(); | ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~

it->table = table;

ret1 = 0;
ret = 0;

Check warning on line 1315 in drivers/jesd204/jesd204-fsm.c

View workflow job for this annotation

GitHub Actions / build_llvm_x86_64 / build

clang_analyzer: Value stored to 'ret' is never read [deadcode.DeadStores] 1315 | ret = 0; | ^ ~
/**
* FIXME: the handle_busy_flags logic needs re-visit, we should lock
* here and unlock after the loop is done
*/
while (!jesd204_fsm_table_end(&it->table[0], rollback, jdev->fsm_rb_to_init)) {
it->table = table;

state_op = &jdev->dev_data->state_ops[table[0].op];

Check warning on line 1319 in drivers/jesd204/jesd204-fsm.c

View workflow job for this annotation

GitHub Actions / build_llvm_x86_64 / build

clang_analyzer: Value stored to 'state_op' is never read [deadcode.DeadStores] 1319 | state_op = &jdev->dev_data->state_ops[table[0].op]; | ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

data->completed = false;
data->cur_state = init_state;
Expand Down Expand Up @@ -1414,6 +1423,8 @@
if (!jdev_top)
return -EFAULT;

mutex_lock(&jdev_top->fsm_lock);
Copy link
Collaborator

Choose a reason for hiding this comment

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

we could use guard(mutex)...


memset(&data, 0, sizeof(data));
data.fsm_change_cb = jesd204_fsm_table_entry_cb;
data.fsm_complete_cb = jesd204_fsm_table_entry_done;
Expand Down Expand Up @@ -1443,6 +1454,8 @@

jesd204_fsm_run_finished_cb(jdev, jdev_top, link_idx, handle_busy_flags);

mutex_unlock(&jdev_top->fsm_lock);

return ret;
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/jesd204/jesd204-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@
* cb_ref on the jesd204_link_opaque struct, but each link
* increments/decrements it, to group transitions of multiple
* JESD204 links
* @fsm_lock mutex to serialize FSM state transitions
* @topo_id topology ID for this device (and top-level device)
* (connections should match against this)
* @link_ids JESD204 link IDs for this top-level device
Expand All @@ -211,6 +212,7 @@

struct jesd204_fsm_data *fsm_data;
struct kref cb_ref;
struct mutex fsm_lock;

Check warning on line 215 in drivers/jesd204/jesd204-priv.h

View workflow job for this annotation

GitHub Actions / checks / checks

checkpatch: struct mutex definition without comment + struct mutex fsm_lock;

int topo_id;
unsigned int link_ids[JESD204_MAX_LINKS];
Expand Down
16 changes: 10 additions & 6 deletions drivers/jesd204/jesd204-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
JESD204_LNK_ATTR_fsm_paused,
JESD204_LNK_ATTR_fsm_ignore_errors,
JESD204_LNK_ATTR_sample_rate,
JESD204_LNK_ATTR_sample_rate_div,
JESD204_LNK_ATTR_is_transmit,
JESD204_LNK_ATTR_num_lanes,
JESD204_LNK_ATTR_num_converters,
Expand Down Expand Up @@ -122,6 +123,7 @@
JESD204_LNK_ATTR_BOOL_PRIV(fsm_paused),
JESD204_LNK_ATTR_BOOL_PRIV(fsm_ignore_errors),
JESD204_LNK_ATTR_UINT(sample_rate),
JESD204_LNK_ATTR_UINT(sample_rate_div),
JESD204_LNK_ATTR_BOOL(is_transmit),
JESD204_LNK_ATTR_UINT(num_lanes),
JESD204_LNK_ATTR_UINT(num_converters),
Expand Down Expand Up @@ -212,7 +214,7 @@

static char *str_cut_from_chr(char *s, char c)
{
char *ptr = strchr(s, '_');
char *ptr = strchr(s, c);
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: I would just argue about a fixes tag given that all callers use _


if (!ptr)
return NULL;
Expand Down Expand Up @@ -297,7 +299,7 @@
if (rc)
goto out;

if (idx >= con->dests_count) {

Check warning on line 302 in drivers/jesd204/jesd204-sysfs.c

View workflow job for this annotation

GitHub Actions / checks / checks

coccicheck: 12-15 ERROR invalid reference to the index variable of the iterator on line 285
rc = -ERANGE;
goto out;
}
Expand All @@ -308,6 +310,7 @@
rc = jesd204_con_printf(e->jdev, ptr1, con, buf);
break;
}
iter_idx++;
}

out:
Expand All @@ -320,7 +323,8 @@
size_t count, bool store, bool is_signed)
{
u64 val1 = 0;
int ret, max;
u64 max;
int ret;

if (!store) {
memcpy(&val1, val, usize);
Expand All @@ -330,21 +334,21 @@
}

if (is_signed)
ret = kstrtoll(rbuf, 0, &val1);
ret = kstrtoll(rbuf, 0, (s64 *)&val1);
else
ret = kstrtoull(rbuf, 0, &val1);
if (ret)
return ret;

switch (usize) {
case 1:
max = 0xff;
max = U8_MAX;
break;
case 2:
max = 0xffff;
max = U16_MAX;
break;
case 4:
max = 0xffffffff;
max = U32_MAX;
break;
case 8:
max = 0;
Expand Down
2 changes: 2 additions & 0 deletions include/linux/jesd204/jesd204.h
Original file line number Diff line number Diff line change
Expand Up @@ -438,5 +438,7 @@ void jesd204_printk(const char *level, const struct jesd204_dev *jdev,
jesd204_printk(KERN_NOTICE, dev, fmt, ##__VA_ARGS__)
#define jesd204_info(dev, fmt, ...) \
jesd204_printk(KERN_INFO, dev, fmt, ##__VA_ARGS__)
#define jesd204_dbg(dev, fmt, ...) \
jesd204_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__)

#endif
Loading