bus.c (7152B)
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 17static 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 27void j1939_ecu_put(struct j1939_ecu *ecu) 28{ 29 kref_put(&ecu->kref, __j1939_ecu_release); 30} 31 32static void j1939_ecu_get(struct j1939_ecu *ecu) 33{ 34 kref_get(&ecu->kref); 35} 36 37static 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 */ 48static 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 */ 72void 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 91void 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 98void 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 109void 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 121void j1939_ecu_timer_cancel(struct j1939_ecu *ecu) 122{ 123 if (hrtimer_cancel(&ecu->ac_timer)) 124 j1939_ecu_put(ecu); 125} 126 127static 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 148struct 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 172struct 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 180struct 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 196struct 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 */ 208static 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 223struct 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 240struct 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 251u8 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 276int 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 308void 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}