Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/can/j1939/bus.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0
2
// Copyright (c) 2010-2011 EIA Electronics,
3
// Kurt Van Dijck <[email protected]>
4
// Copyright (c) 2017-2019 Pengutronix,
5
// Marc Kleine-Budde <[email protected]>
6
// Copyright (c) 2017-2019 Pengutronix,
7
// Oleksij Rempel <[email protected]>
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_setup(&ecu->ac_timer, j1939_ecu_timer_handler, CLOCK_MONOTONIC,
162
HRTIMER_MODE_REL_SOFT);
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
335