xref: /openbmc/linux/net/can/j1939/bus.c (revision bc33f5e5)
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>
8 
9 /* bus for j1939 remote devices
10  * Since rtnetlink, no real bus is used.
11  */
12 
13 #include <net/sock.h>
14 
15 #include "j1939-priv.h"
16 
17 static void __j1939_ecu_release(struct kref *kref)
18 {
19 	struct j1939_ecu *ecu = container_of(kref, struct j1939_ecu, kref);
20 	struct j1939_priv *priv = ecu->priv;
21 
22 	list_del(&ecu->list);
23 	kfree(ecu);
24 	j1939_priv_put(priv);
25 }
26 
27 void j1939_ecu_put(struct j1939_ecu *ecu)
28 {
29 	kref_put(&ecu->kref, __j1939_ecu_release);
30 }
31 
32 static void j1939_ecu_get(struct j1939_ecu *ecu)
33 {
34 	kref_get(&ecu->kref);
35 }
36 
37 static bool j1939_ecu_is_mapped_locked(struct j1939_ecu *ecu)
38 {
39 	struct j1939_priv *priv = ecu->priv;
40 
41 	lockdep_assert_held(&priv->lock);
42 
43 	return j1939_ecu_find_by_addr_locked(priv, ecu->addr) == ecu;
44 }
45 
46 /* ECU device interface */
47 /* map ECU to a bus address space */
48 static void j1939_ecu_map_locked(struct j1939_ecu *ecu)
49 {
50 	struct j1939_priv *priv = ecu->priv;
51 	struct j1939_addr_ent *ent;
52 
53 	lockdep_assert_held(&priv->lock);
54 
55 	if (!j1939_address_is_unicast(ecu->addr))
56 		return;
57 
58 	ent = &priv->ents[ecu->addr];
59 
60 	if (ent->ecu) {
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);
63 		return;
64 	}
65 
66 	j1939_ecu_get(ecu);
67 	ent->ecu = ecu;
68 	ent->nusers += ecu->nusers;
69 }
70 
71 /* unmap ECU from a bus address space */
72 void j1939_ecu_unmap_locked(struct j1939_ecu *ecu)
73 {
74 	struct j1939_priv *priv = ecu->priv;
75 	struct j1939_addr_ent *ent;
76 
77 	lockdep_assert_held(&priv->lock);
78 
79 	if (!j1939_address_is_unicast(ecu->addr))
80 		return;
81 
82 	if (!j1939_ecu_is_mapped_locked(ecu))
83 		return;
84 
85 	ent = &priv->ents[ecu->addr];
86 	ent->ecu = NULL;
87 	ent->nusers -= ecu->nusers;
88 	j1939_ecu_put(ecu);
89 }
90 
91 void j1939_ecu_unmap(struct j1939_ecu *ecu)
92 {
93 	write_lock_bh(&ecu->priv->lock);
94 	j1939_ecu_unmap_locked(ecu);
95 	write_unlock_bh(&ecu->priv->lock);
96 }
97 
98 void j1939_ecu_unmap_all(struct j1939_priv *priv)
99 {
100 	int i;
101 
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);
107 }
108 
109 void j1939_ecu_timer_start(struct j1939_ecu *ecu)
110 {
111 	/* The ECU is held here and released in the
112 	 * j1939_ecu_timer_handler() or j1939_ecu_timer_cancel().
113 	 */
114 	j1939_ecu_get(ecu);
115 
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);
119 }
120 
121 void j1939_ecu_timer_cancel(struct j1939_ecu *ecu)
122 {
123 	if (hrtimer_cancel(&ecu->ac_timer))
124 		j1939_ecu_put(ecu);
125 }
126 
127 static enum hrtimer_restart j1939_ecu_timer_handler(struct hrtimer *hrtimer)
128 {
129 	struct j1939_ecu *ecu =
130 		container_of(hrtimer, struct j1939_ecu, ac_timer);
131 	struct j1939_priv *priv = ecu->priv;
132 
133 	write_lock_bh(&priv->lock);
134 	/* TODO: can we test if ecu->addr is unicast before starting
135 	 * the timer?
136 	 */
137 	j1939_ecu_map_locked(ecu);
138 
139 	/* The corresponding j1939_ecu_get() is in
140 	 * j1939_ecu_timer_start().
141 	 */
142 	j1939_ecu_put(ecu);
143 	write_unlock_bh(&priv->lock);
144 
145 	return HRTIMER_NORESTART;
146 }
147 
148 struct j1939_ecu *j1939_ecu_create_locked(struct j1939_priv *priv, name_t name)
149 {
150 	struct j1939_ecu *ecu;
151 
152 	lockdep_assert_held(&priv->lock);
153 
154 	ecu = kzalloc(sizeof(*ecu), gfp_any());
155 	if (!ecu)
156 		return ERR_PTR(-ENOMEM);
157 	kref_init(&ecu->kref);
158 	ecu->addr = J1939_IDLE_ADDR;
159 	ecu->name = name;
160 
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);
164 
165 	j1939_priv_get(priv);
166 	ecu->priv = priv;
167 	list_add_tail(&ecu->list, &priv->ecus);
168 
169 	return ecu;
170 }
171 
172 struct j1939_ecu *j1939_ecu_find_by_addr_locked(struct j1939_priv *priv,
173 						u8 addr)
174 {
175 	lockdep_assert_held(&priv->lock);
176 
177 	return priv->ents[addr].ecu;
178 }
179 
180 struct j1939_ecu *j1939_ecu_get_by_addr_locked(struct j1939_priv *priv, u8 addr)
181 {
182 	struct j1939_ecu *ecu;
183 
184 	lockdep_assert_held(&priv->lock);
185 
186 	if (!j1939_address_is_unicast(addr))
187 		return NULL;
188 
189 	ecu = j1939_ecu_find_by_addr_locked(priv, addr);
190 	if (ecu)
191 		j1939_ecu_get(ecu);
192 
193 	return ecu;
194 }
195 
196 struct j1939_ecu *j1939_ecu_get_by_addr(struct j1939_priv *priv, u8 addr)
197 {
198 	struct j1939_ecu *ecu;
199 
200 	read_lock_bh(&priv->lock);
201 	ecu = j1939_ecu_get_by_addr_locked(priv, addr);
202 	read_unlock_bh(&priv->lock);
203 
204 	return ecu;
205 }
206 
207 /* get pointer to ecu without increasing ref counter */
208 static struct j1939_ecu *j1939_ecu_find_by_name_locked(struct j1939_priv *priv,
209 						       name_t name)
210 {
211 	struct j1939_ecu *ecu;
212 
213 	lockdep_assert_held(&priv->lock);
214 
215 	list_for_each_entry(ecu, &priv->ecus, list) {
216 		if (ecu->name == name)
217 			return ecu;
218 	}
219 
220 	return NULL;
221 }
222 
223 struct j1939_ecu *j1939_ecu_get_by_name_locked(struct j1939_priv *priv,
224 					       name_t name)
225 {
226 	struct j1939_ecu *ecu;
227 
228 	lockdep_assert_held(&priv->lock);
229 
230 	if (!name)
231 		return NULL;
232 
233 	ecu = j1939_ecu_find_by_name_locked(priv, name);
234 	if (ecu)
235 		j1939_ecu_get(ecu);
236 
237 	return ecu;
238 }
239 
240 struct j1939_ecu *j1939_ecu_get_by_name(struct j1939_priv *priv, name_t name)
241 {
242 	struct j1939_ecu *ecu;
243 
244 	read_lock_bh(&priv->lock);
245 	ecu = j1939_ecu_get_by_name_locked(priv, name);
246 	read_unlock_bh(&priv->lock);
247 
248 	return ecu;
249 }
250 
251 u8 j1939_name_to_addr(struct j1939_priv *priv, name_t name)
252 {
253 	struct j1939_ecu *ecu;
254 	int addr = J1939_IDLE_ADDR;
255 
256 	if (!name)
257 		return J1939_NO_ADDR;
258 
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 */
263 		addr = ecu->addr;
264 
265 	read_unlock_bh(&priv->lock);
266 
267 	return addr;
268 }
269 
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
274  */
275 
276 int j1939_local_ecu_get(struct j1939_priv *priv, name_t name, u8 sa)
277 {
278 	struct j1939_ecu *ecu;
279 	int err = 0;
280 
281 	write_lock_bh(&priv->lock);
282 
283 	if (j1939_address_is_unicast(sa))
284 		priv->ents[sa].nusers++;
285 
286 	if (!name)
287 		goto done;
288 
289 	ecu = j1939_ecu_get_by_name_locked(priv, name);
290 	if (!ecu)
291 		ecu = j1939_ecu_create_locked(priv, name);
292 	err = PTR_ERR_OR_ZERO(ecu);
293 	if (err)
294 		goto done;
295 
296 	ecu->nusers++;
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++;
301 
302  done:
303 	write_unlock_bh(&priv->lock);
304 
305 	return err;
306 }
307 
308 void j1939_local_ecu_put(struct j1939_priv *priv, name_t name, u8 sa)
309 {
310 	struct j1939_ecu *ecu;
311 
312 	write_lock_bh(&priv->lock);
313 
314 	if (j1939_address_is_unicast(sa))
315 		priv->ents[sa].nusers--;
316 
317 	if (!name)
318 		goto done;
319 
320 	ecu = j1939_ecu_find_by_name_locked(priv, name);
321 	if (WARN_ON_ONCE(!ecu))
322 		goto done;
323 
324 	ecu->nusers--;
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--;
329 	j1939_ecu_put(ecu);
330 
331  done:
332 	write_unlock_bh(&priv->lock);
333 }
334