1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2010-2011 EIA Electronics,
3 // Kurt Van Dijck <kurt.van.dijck@eia.be>
4 // Copyright (c) 2017-2019 Pengutronix,
5 // Marc Kleine-Budde <kernel@pengutronix.de>
6 // Copyright (c) 2017-2019 Pengutronix,
7 // Oleksij Rempel <kernel@pengutronix.de>
9 /* bus for j1939 remote devices
10 * Since rtnetlink, no real bus is used.
15 #include "j1939-priv.h"
17 static void __j1939_ecu_release(struct kref
*kref
)
19 struct j1939_ecu
*ecu
= container_of(kref
, struct j1939_ecu
, kref
);
20 struct j1939_priv
*priv
= ecu
->priv
;
27 void j1939_ecu_put(struct j1939_ecu
*ecu
)
29 kref_put(&ecu
->kref
, __j1939_ecu_release
);
32 static void j1939_ecu_get(struct j1939_ecu
*ecu
)
37 static bool j1939_ecu_is_mapped_locked(struct j1939_ecu
*ecu
)
39 struct j1939_priv
*priv
= ecu
->priv
;
41 lockdep_assert_held(&priv
->lock
);
43 return j1939_ecu_find_by_addr_locked(priv
, ecu
->addr
) == ecu
;
46 /* ECU device interface */
47 /* map ECU to a bus address space */
48 static void j1939_ecu_map_locked(struct j1939_ecu
*ecu
)
50 struct j1939_priv
*priv
= ecu
->priv
;
51 struct j1939_addr_ent
*ent
;
53 lockdep_assert_held(&priv
->lock
);
55 if (!j1939_address_is_unicast(ecu
->addr
))
58 ent
= &priv
->ents
[ecu
->addr
];
61 netdev_warn(priv
->ndev
, "Trying to map already mapped ECU, addr: 0x%02x, name: 0x%016llx. Skip it.\n",
62 ecu
->addr
, ecu
->name
);
68 ent
->nusers
+= ecu
->nusers
;
71 /* unmap ECU from a bus address space */
72 void j1939_ecu_unmap_locked(struct j1939_ecu
*ecu
)
74 struct j1939_priv
*priv
= ecu
->priv
;
75 struct j1939_addr_ent
*ent
;
77 lockdep_assert_held(&priv
->lock
);
79 if (!j1939_address_is_unicast(ecu
->addr
))
82 if (!j1939_ecu_is_mapped_locked(ecu
))
85 ent
= &priv
->ents
[ecu
->addr
];
87 ent
->nusers
-= ecu
->nusers
;
91 void j1939_ecu_unmap(struct j1939_ecu
*ecu
)
93 write_lock_bh(&ecu
->priv
->lock
);
94 j1939_ecu_unmap_locked(ecu
);
95 write_unlock_bh(&ecu
->priv
->lock
);
98 void j1939_ecu_unmap_all(struct j1939_priv
*priv
)
102 write_lock_bh(&priv
->lock
);
103 for (i
= 0; i
< ARRAY_SIZE(priv
->ents
); i
++)
104 if (priv
->ents
[i
].ecu
)
105 j1939_ecu_unmap_locked(priv
->ents
[i
].ecu
);
106 write_unlock_bh(&priv
->lock
);
109 void j1939_ecu_timer_start(struct j1939_ecu
*ecu
)
111 /* The ECU is held here and released in the
112 * j1939_ecu_timer_handler() or j1939_ecu_timer_cancel().
116 /* Schedule timer in 250 msec to commit address change. */
117 hrtimer_start(&ecu
->ac_timer
, ms_to_ktime(250),
118 HRTIMER_MODE_REL_SOFT
);
121 void j1939_ecu_timer_cancel(struct j1939_ecu
*ecu
)
123 if (hrtimer_cancel(&ecu
->ac_timer
))
127 static enum hrtimer_restart
j1939_ecu_timer_handler(struct hrtimer
*hrtimer
)
129 struct j1939_ecu
*ecu
=
130 container_of(hrtimer
, struct j1939_ecu
, ac_timer
);
131 struct j1939_priv
*priv
= ecu
->priv
;
133 write_lock_bh(&priv
->lock
);
134 /* TODO: can we test if ecu->addr is unicast before starting
137 j1939_ecu_map_locked(ecu
);
139 /* The corresponding j1939_ecu_get() is in
140 * j1939_ecu_timer_start().
143 write_unlock_bh(&priv
->lock
);
145 return HRTIMER_NORESTART
;
148 struct j1939_ecu
*j1939_ecu_create_locked(struct j1939_priv
*priv
, name_t name
)
150 struct j1939_ecu
*ecu
;
152 lockdep_assert_held(&priv
->lock
);
154 ecu
= kzalloc(sizeof(*ecu
), gfp_any());
156 return ERR_PTR(-ENOMEM
);
157 kref_init(&ecu
->kref
);
158 ecu
->addr
= J1939_IDLE_ADDR
;
161 hrtimer_init(&ecu
->ac_timer
, CLOCK_MONOTONIC
, HRTIMER_MODE_REL_SOFT
);
162 ecu
->ac_timer
.function
= j1939_ecu_timer_handler
;
163 INIT_LIST_HEAD(&ecu
->list
);
165 j1939_priv_get(priv
);
167 list_add_tail(&ecu
->list
, &priv
->ecus
);
172 struct j1939_ecu
*j1939_ecu_find_by_addr_locked(struct j1939_priv
*priv
,
175 lockdep_assert_held(&priv
->lock
);
177 return priv
->ents
[addr
].ecu
;
180 struct j1939_ecu
*j1939_ecu_get_by_addr_locked(struct j1939_priv
*priv
, u8 addr
)
182 struct j1939_ecu
*ecu
;
184 lockdep_assert_held(&priv
->lock
);
186 if (!j1939_address_is_unicast(addr
))
189 ecu
= j1939_ecu_find_by_addr_locked(priv
, addr
);
196 struct j1939_ecu
*j1939_ecu_get_by_addr(struct j1939_priv
*priv
, u8 addr
)
198 struct j1939_ecu
*ecu
;
200 read_lock_bh(&priv
->lock
);
201 ecu
= j1939_ecu_get_by_addr_locked(priv
, addr
);
202 read_unlock_bh(&priv
->lock
);
207 /* get pointer to ecu without increasing ref counter */
208 static struct j1939_ecu
*j1939_ecu_find_by_name_locked(struct j1939_priv
*priv
,
211 struct j1939_ecu
*ecu
;
213 lockdep_assert_held(&priv
->lock
);
215 list_for_each_entry(ecu
, &priv
->ecus
, list
) {
216 if (ecu
->name
== name
)
223 struct j1939_ecu
*j1939_ecu_get_by_name_locked(struct j1939_priv
*priv
,
226 struct j1939_ecu
*ecu
;
228 lockdep_assert_held(&priv
->lock
);
233 ecu
= j1939_ecu_find_by_name_locked(priv
, name
);
240 struct j1939_ecu
*j1939_ecu_get_by_name(struct j1939_priv
*priv
, name_t name
)
242 struct j1939_ecu
*ecu
;
244 read_lock_bh(&priv
->lock
);
245 ecu
= j1939_ecu_get_by_name_locked(priv
, name
);
246 read_unlock_bh(&priv
->lock
);
251 u8
j1939_name_to_addr(struct j1939_priv
*priv
, name_t name
)
253 struct j1939_ecu
*ecu
;
254 int addr
= J1939_IDLE_ADDR
;
257 return J1939_NO_ADDR
;
259 read_lock_bh(&priv
->lock
);
260 ecu
= j1939_ecu_find_by_name_locked(priv
, name
);
261 if (ecu
&& j1939_ecu_is_mapped_locked(ecu
))
262 /* ecu's SA is registered */
265 read_unlock_bh(&priv
->lock
);
270 /* TX addr/name accounting
271 * Transport protocol needs to know if a SA is local or not
272 * These functions originate from userspace manipulating sockets,
273 * so locking is straigforward
276 int j1939_local_ecu_get(struct j1939_priv
*priv
, name_t name
, u8 sa
)
278 struct j1939_ecu
*ecu
;
281 write_lock_bh(&priv
->lock
);
283 if (j1939_address_is_unicast(sa
))
284 priv
->ents
[sa
].nusers
++;
289 ecu
= j1939_ecu_get_by_name_locked(priv
, name
);
291 ecu
= j1939_ecu_create_locked(priv
, name
);
292 err
= PTR_ERR_OR_ZERO(ecu
);
297 /* TODO: do we care if ecu->addr != sa? */
298 if (j1939_ecu_is_mapped_locked(ecu
))
299 /* ecu's sa is active already */
300 priv
->ents
[ecu
->addr
].nusers
++;
303 write_unlock_bh(&priv
->lock
);
308 void j1939_local_ecu_put(struct j1939_priv
*priv
, name_t name
, u8 sa
)
310 struct j1939_ecu
*ecu
;
312 write_lock_bh(&priv
->lock
);
314 if (j1939_address_is_unicast(sa
))
315 priv
->ents
[sa
].nusers
--;
320 ecu
= j1939_ecu_find_by_name_locked(priv
, name
);
321 if (WARN_ON_ONCE(!ecu
))
325 /* TODO: do we care if ecu->addr != sa? */
326 if (j1939_ecu_is_mapped_locked(ecu
))
327 /* ecu's sa is active already */
328 priv
->ents
[ecu
->addr
].nusers
--;
332 write_unlock_bh(&priv
->lock
);