1 /* $NetBSD: sunxi_can.c,v 1.13 2022/11/19 09:05:42 yamt Exp $ */ 2 3 /*- 4 * Copyright (c) 2017,2018 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Manuel Bouyer. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 33 #include "locators.h" 34 #include "opt_can.h" 35 36 37 #include <sys/cdefs.h> 38 39 __KERNEL_RCSID(1, "$NetBSD: sunxi_can.c,v 1.13 2022/11/19 09:05:42 yamt Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/bus.h> 43 #include <sys/device.h> 44 #include <sys/intr.h> 45 #include <sys/ioctl.h> 46 #include <sys/kmem.h> 47 #include <sys/mutex.h> 48 #include <sys/rndsource.h> 49 #include <sys/mbuf.h> 50 #include <sys/systm.h> 51 52 #include <net/if.h> 53 #include <net/if_types.h> 54 #include <net/bpf.h> 55 56 #ifdef CAN 57 #include <netcan/can.h> 58 #include <netcan/can_var.h> 59 #endif 60 61 #include <dev/fdt/fdtvar.h> 62 63 #include <arm/sunxi/sunxi_can.h> 64 65 /* shortcut for all error interrupts */ 66 #define SUNXI_CAN_INT_ALLERRS (\ 67 SUNXI_CAN_INT_BERR | \ 68 SUNXI_CAN_INT_ARB_LOST | \ 69 SUNXI_CAN_INT_ERR_PASSIVE | \ 70 SUNXI_CAN_INT_DATA_OR | \ 71 SUNXI_CAN_INT_ERR \ 72 ) 73 74 struct sunxi_can_softc { 75 struct canif_softc sc_cansc; 76 bus_space_tag_t sc_bst; 77 bus_space_handle_t sc_bsh; 78 kmutex_t sc_intr_lock; 79 void *sc_ih; 80 struct ifnet *sc_ifp; 81 krndsource_t sc_rnd_source; /* random source */ 82 struct mbuf *sc_m_transmit; /* mbuf being transmitted */ 83 }; 84 #define sc_dev sc_cansc.csc_dev 85 #define sc_timecaps sc_cansc.csc_timecaps 86 #define sc_timings sc_cansc.csc_timings 87 #define sc_linkmodes sc_cansc.csc_linkmodes 88 89 static const struct device_compatible_entry compat_data[] = { 90 { .compat = "allwinner,sun4i-a10-can" }, 91 DEVICE_COMPAT_EOL 92 }; 93 94 static int sunxi_can_match(device_t, cfdata_t, void *); 95 static void sunxi_can_attach(device_t, device_t, void *); 96 97 static int sunxi_can_intr(void *); 98 99 static void sunxi_can_ifstart(struct ifnet *); 100 static int sunxi_can_ifioctl(struct ifnet *, u_long, void *); 101 static void sunxi_can_ifwatchdog(struct ifnet *); 102 103 static void sunxi_can_enter_reset(struct sunxi_can_softc *); 104 static void sunxi_can_exit_reset(struct sunxi_can_softc *); 105 static void sunxi_can_ifdown(struct sunxi_can_softc * const); 106 static int sunxi_can_ifup(struct sunxi_can_softc * const); 107 108 CFATTACH_DECL_NEW(sunxi_can, sizeof(struct sunxi_can_softc), 109 sunxi_can_match, sunxi_can_attach, NULL, NULL); 110 111 static inline uint32_t 112 sunxi_can_read(struct sunxi_can_softc *sc, bus_size_t o) 113 { 114 return bus_space_read_4(sc->sc_bst, sc->sc_bsh, o); 115 } 116 117 static inline void 118 sunxi_can_write(struct sunxi_can_softc *sc, bus_size_t o, uint32_t v) 119 { 120 return bus_space_write_4(sc->sc_bst, sc->sc_bsh, o, v); 121 } 122 123 static int 124 sunxi_can_match(device_t parent, cfdata_t cf, void *aux) 125 { 126 struct fdt_attach_args * const faa = aux; 127 128 return of_compatible_match(faa->faa_phandle, compat_data); 129 } 130 131 static void 132 sunxi_can_attach(device_t parent, device_t self, void *aux) 133 { 134 struct sunxi_can_softc * const sc = device_private(self); 135 struct fdt_attach_args * const faa = aux; 136 struct ifnet *ifp; 137 const int phandle = faa->faa_phandle; 138 bus_addr_t addr; 139 bus_size_t size; 140 char intrstr[128]; 141 struct clk *clk; 142 struct fdtbus_reset *rst; 143 144 sc->sc_dev = self; 145 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NET); 146 147 sc->sc_bst = faa->faa_bst; 148 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 149 aprint_error(": couldn't get registers\n"); 150 return; 151 } 152 153 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 154 aprint_error(": couldn't map registers\n"); 155 return; 156 } 157 158 if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { 159 aprint_error(": failed to decode interrupt\n"); 160 return; 161 } 162 163 if ((clk = fdtbus_clock_get_index(phandle, 0)) != NULL) { 164 if (clk_enable(clk) != 0) { 165 aprint_error(": couldn't enable clock\n"); 166 return; 167 } 168 } 169 170 if ((rst = fdtbus_reset_get_index(phandle, 0)) != NULL) { 171 if (fdtbus_reset_deassert(rst) != 0) { 172 aprint_error(": couldn't de-assert reset\n"); 173 return; 174 } 175 } 176 177 sc->sc_timecaps.cltc_prop_min = 0; 178 sc->sc_timecaps.cltc_prop_max = 0; 179 sc->sc_timecaps.cltc_ps1_min = 1; 180 sc->sc_timecaps.cltc_ps1_max = 16; 181 sc->sc_timecaps.cltc_ps2_min = 1; 182 sc->sc_timecaps.cltc_ps2_max = 8; 183 sc->sc_timecaps.cltc_sjw_max = 4; 184 sc->sc_timecaps.cltc_brp_min = 1; 185 sc->sc_timecaps.cltc_brp_max = 64; 186 sc->sc_timecaps.cltc_brp_inc = 1; 187 sc->sc_timecaps.cltc_clock_freq = clk_get_rate(clk); 188 sc->sc_timecaps.cltc_linkmode_caps = 189 CAN_LINKMODE_3SAMPLES | CAN_LINKMODE_LISTENONLY | 190 CAN_LINKMODE_LOOPBACK; 191 can_ifinit_timings(&sc->sc_cansc); 192 sc->sc_timings.clt_prop = 0; 193 sc->sc_timings.clt_sjw = 1; 194 195 aprint_naive("\n"); 196 aprint_normal(": CAN bus controller\n"); 197 aprint_debug_dev(self, ": clock freq %d\n", 198 sc->sc_timecaps.cltc_clock_freq); 199 200 sunxi_can_enter_reset(sc); 201 /* 202 * Disable and then clear all interrupts 203 */ 204 sunxi_can_write(sc, SUNXI_CAN_INTE_REG, 0); 205 sunxi_can_write(sc, SUNXI_CAN_INT_REG, 206 sunxi_can_read(sc, SUNXI_CAN_INT_REG)); 207 208 sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_NET, 0, 209 sunxi_can_intr, sc, device_xname(self)); 210 if (sc->sc_ih == NULL) { 211 aprint_error_dev(self, "failed to establish interrupt on %s\n", 212 intrstr); 213 return; 214 } 215 aprint_normal_dev(self, "interrupting on %s\n", intrstr); 216 217 ifp = if_alloc(IFT_OTHER); 218 sc->sc_ifp = ifp; 219 strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ); 220 ifp->if_softc = sc; 221 ifp->if_capabilities = 0; 222 ifp->if_flags = 0; 223 ifp->if_start = sunxi_can_ifstart; 224 ifp->if_ioctl = sunxi_can_ifioctl; 225 ifp->if_watchdog = sunxi_can_ifwatchdog; 226 227 /* 228 * Attach the interface. 229 */ 230 can_ifattach(ifp); 231 if_deferred_start_init(ifp, NULL); 232 bpf_mtap_softint_init(ifp); 233 rnd_attach_source(&sc->sc_rnd_source, device_xname(self), 234 RND_TYPE_NET, RND_FLAG_DEFAULT); 235 #ifdef MBUFTRACE 236 ifp->if_mowner = kmem_zalloc(sizeof(*ifp->if_mowner), KM_SLEEP); 237 strlcpy(ifp->if_mowner->mo_name, ifp->if_xname, 238 sizeof(ifp->if_mowner->mo_name)); 239 MOWNER_ATTACH(ifp->if_mowner); 240 #endif 241 } 242 243 static void 244 sunxi_can_rx_intr(struct sunxi_can_softc *sc) 245 { 246 uint32_t reg0v; 247 struct mbuf *m; 248 struct ifnet *ifp = sc->sc_ifp; 249 struct can_frame *cf; 250 int dlc; 251 int regd, i; 252 253 KASSERT(mutex_owned(&sc->sc_intr_lock)); 254 reg0v = sunxi_can_read(sc, SUNXI_CAN_TXBUF0_REG); 255 dlc = reg0v & SUNXI_CAN_TXBUF0_DL; 256 257 if (dlc > CAN_MAX_DLC) { 258 if_statinc(ifp, if_ierrors); 259 sunxi_can_write(sc, SUNXI_CAN_CMD_REG, SUNXI_CAN_CMD_REL_RX_BUF); 260 return; 261 } 262 263 m = m_gethdr(M_NOWAIT, MT_HEADER); 264 if (m == NULL) { 265 if_statinc(ifp, if_ierrors); 266 sunxi_can_write(sc, SUNXI_CAN_CMD_REG, SUNXI_CAN_CMD_REL_RX_BUF); 267 return; 268 } 269 cf = mtod(m, struct can_frame *); 270 memset(cf, 0, sizeof(struct can_frame)); 271 272 cf->can_dlc = dlc; 273 274 if (reg0v & SUNXI_CAN_TXBUF0_EFF) { 275 cf->can_id = 276 (sunxi_can_read(sc, SUNXI_CAN_TXBUF1_REG) << 21) | 277 (sunxi_can_read(sc, SUNXI_CAN_TXBUF2_REG) << 13) | 278 (sunxi_can_read(sc, SUNXI_CAN_TXBUF3_REG) << 5) | 279 ((sunxi_can_read(sc, SUNXI_CAN_TXBUF4_REG) >> 3) & 0x1f); 280 cf->can_id |= CAN_EFF_FLAG; 281 regd = SUNXI_CAN_TXBUF5_REG; 282 } else { 283 cf->can_id = 284 (sunxi_can_read(sc, SUNXI_CAN_TXBUF1_REG) << 3) | 285 ((sunxi_can_read(sc, SUNXI_CAN_TXBUF2_REG) << 5) & 0x7); 286 regd = SUNXI_CAN_TXBUF3_REG; 287 } 288 if (reg0v & SUNXI_CAN_TXBUF0_RTR) { 289 cf->can_id |= CAN_RTR_FLAG; 290 } else { 291 for (i = 0; i < cf->can_dlc; i++) { 292 cf->data[i] = sunxi_can_read(sc, regd + i * 4); 293 } 294 } 295 sunxi_can_write(sc, SUNXI_CAN_CMD_REG, SUNXI_CAN_CMD_REL_RX_BUF); 296 m->m_len = m->m_pkthdr.len = CAN_MTU; 297 if_statadd(ifp, if_ibytes, m->m_len); 298 m_set_rcvif(m, ifp); 299 can_bpf_mtap(ifp, m, 1); 300 can_input(ifp, m); 301 } 302 303 static void 304 sunxi_can_tx_intr(struct sunxi_can_softc *sc) 305 { 306 struct ifnet * const ifp = sc->sc_ifp; 307 struct mbuf *m; 308 309 KASSERT(mutex_owned(&sc->sc_intr_lock)); 310 if ((m = sc->sc_m_transmit) != NULL) { 311 if_statadd2(ifp, if_obytes, m->m_len, if_opackets, 1); 312 can_mbuf_tag_clean(m); 313 m_set_rcvif(m, ifp); 314 can_input(ifp, m); /* loopback */ 315 sc->sc_m_transmit = NULL; 316 ifp->if_timer = 0; 317 } 318 if_schedule_deferred_start(ifp); 319 } 320 321 static int 322 sunxi_can_tx_abort(struct sunxi_can_softc *sc) 323 { 324 KASSERT(mutex_owned(&sc->sc_intr_lock)); 325 if (sc->sc_m_transmit) { 326 m_freem(sc->sc_m_transmit); 327 sc->sc_m_transmit = NULL; 328 sc->sc_ifp->if_timer = 0; 329 /* 330 * the transmit abort will trigger a TX interrupt 331 * which will restart the queue as appropriate. 332 */ 333 sunxi_can_write(sc, SUNXI_CAN_CMD_REG, SUNXI_CAN_CMD_ABT_REQ); 334 return 1; 335 } 336 return 0; 337 } 338 339 static void 340 sunxi_can_err_intr(struct sunxi_can_softc *sc, uint32_t irq, uint32_t sts) 341 { 342 struct ifnet * const ifp = sc->sc_ifp; 343 KASSERT(mutex_owned(&sc->sc_intr_lock)); 344 int txerr = 0; 345 uint32_t reg; 346 347 if (irq & SUNXI_CAN_INT_DATA_OR) { 348 if_statinc(ifp, if_ierrors); 349 sunxi_can_ifdown(sc); 350 sunxi_can_write(sc, SUNXI_CAN_CMD_REG, SUNXI_CAN_CMD_CLR_OR); 351 sunxi_can_ifup(sc); 352 } 353 if (irq & SUNXI_CAN_INT_ERR) { 354 reg = sunxi_can_read(sc, SUNXI_CAN_REC_REG); 355 printf("%s: ERR interrupt status 0x%x counters 0x%x\n", 356 device_xname(sc->sc_dev), sts, reg); 357 358 } 359 if (irq & SUNXI_CAN_INT_BERR) { 360 if (sts & SUNXI_CAN_STA_TX) 361 txerr++; 362 if (sts & SUNXI_CAN_STA_RX) 363 if_statinc(ifp, if_ierrors); 364 } 365 if (irq & SUNXI_CAN_INT_ERR_PASSIVE) { 366 printf("%s: PASSV interrupt status 0x%x\n", 367 device_xname(sc->sc_dev), sts); 368 } 369 if (irq & SUNXI_CAN_INT_ARB_LOST) { 370 txerr++; 371 } 372 if (txerr) { 373 if_statadd(ifp, if_oerrors, txerr); 374 (void) sunxi_can_tx_abort(sc); 375 } 376 } 377 378 int 379 sunxi_can_intr(void *arg) 380 { 381 struct sunxi_can_softc * const sc = arg; 382 int rv = 0; 383 int irq; 384 385 mutex_enter(&sc->sc_intr_lock); 386 387 while ((irq = sunxi_can_read(sc, SUNXI_CAN_INT_REG)) != 0) { 388 uint32_t sts = sunxi_can_read(sc, SUNXI_CAN_STA_REG); 389 rv = 1; 390 rnd_add_uint32(&sc->sc_rnd_source, irq); 391 392 if ((irq & (SUNXI_CAN_INT_RX_FLAG | SUNXI_CAN_INT_DATA_OR)) == 393 SUNXI_CAN_INT_RX_FLAG) { 394 while (sts & SUNXI_CAN_STA_RX_RDY) { 395 sunxi_can_rx_intr(sc); 396 sts = sunxi_can_read(sc, SUNXI_CAN_STA_REG); 397 } 398 /* 399 * Don't write SUNXI_CAN_INT_RX_FLAG to the interrupt 400 * register, this may clear the RX pending flag 401 * while there is indeed a packet pending. 402 * Reading packets should have cleared the RX interrupt, 403 * so just restart the loop and re-read the interrupt 404 * register. In the common case irq will now be 0. 405 */ 406 continue; 407 } 408 if (irq & SUNXI_CAN_INT_TX_FLAG) { 409 sunxi_can_tx_intr(sc); 410 } 411 if (irq & SUNXI_CAN_INT_ALLERRS) { 412 sunxi_can_err_intr(sc, irq, sts); 413 } 414 sunxi_can_write(sc, SUNXI_CAN_INT_REG, irq); 415 } 416 mutex_exit(&sc->sc_intr_lock); 417 418 return rv; 419 } 420 421 void 422 sunxi_can_ifstart(struct ifnet *ifp) 423 { 424 struct sunxi_can_softc * const sc = ifp->if_softc; 425 struct mbuf *m; 426 struct can_frame *cf; 427 int regd; 428 uint32_t reg0val; 429 int i; 430 431 mutex_enter(&sc->sc_intr_lock); 432 if (sc->sc_m_transmit != NULL) 433 goto out; 434 435 IF_DEQUEUE(&ifp->if_snd, m); 436 437 if (m == NULL) 438 goto out; 439 440 MCLAIM(m, ifp->if_mowner); 441 sc->sc_m_transmit = m; 442 443 KASSERT((m->m_flags & M_PKTHDR) != 0); 444 KASSERT(m->m_len == m->m_pkthdr.len); 445 446 cf = mtod(m, struct can_frame *); 447 reg0val = cf->can_dlc & SUNXI_CAN_TXBUF0_DL; 448 if (cf->can_id & CAN_RTR_FLAG) 449 reg0val |= SUNXI_CAN_TXBUF0_RTR; 450 451 if (cf->can_id & CAN_EFF_FLAG) { 452 reg0val |= SUNXI_CAN_TXBUF0_EFF; 453 sunxi_can_write(sc, SUNXI_CAN_TXBUF1_REG, 454 (cf->can_id >> 21) & 0xff); 455 sunxi_can_write(sc, SUNXI_CAN_TXBUF2_REG, 456 (cf->can_id >> 13) & 0xff); 457 sunxi_can_write(sc, SUNXI_CAN_TXBUF3_REG, 458 (cf->can_id >> 5) & 0xff); 459 sunxi_can_write(sc, SUNXI_CAN_TXBUF4_REG, 460 (cf->can_id << 3) & 0xf8); 461 regd = SUNXI_CAN_TXBUF5_REG; 462 } else { 463 sunxi_can_write(sc, SUNXI_CAN_TXBUF1_REG, 464 (cf->can_id >> 3) & 0xff); 465 sunxi_can_write(sc, SUNXI_CAN_TXBUF2_REG, 466 (cf->can_id << 5) & 0xe0); 467 regd = SUNXI_CAN_TXBUF3_REG; 468 } 469 470 for (i = 0; i < cf->can_dlc; i++) { 471 sunxi_can_write(sc, regd + i * 4, cf->data[i]); 472 } 473 sunxi_can_write(sc, SUNXI_CAN_TXBUF0_REG, reg0val); 474 475 if (sc->sc_linkmodes & CAN_LINKMODE_LOOPBACK) { 476 sunxi_can_write(sc, SUNXI_CAN_CMD_REG, 477 SUNXI_CAN_CMD_TANS_REQ | SUNXI_CAN_CMD_SELF_REQ); 478 } else { 479 sunxi_can_write(sc, SUNXI_CAN_CMD_REG, SUNXI_CAN_CMD_TANS_REQ); 480 } 481 ifp->if_timer = 5; 482 can_bpf_mtap(ifp, m, 0); 483 out: 484 mutex_exit(&sc->sc_intr_lock); 485 } 486 487 static int 488 sunxi_can_ifup(struct sunxi_can_softc * const sc) 489 { 490 uint32_t reg; 491 492 /* setup timings and mode - has to be done in reset */ 493 reg = SUNXI_CAN_MODSEL_RST; 494 if (sc->sc_linkmodes & CAN_LINKMODE_LISTENONLY) 495 reg |= SUNXI_CAN_MODSEL_LST_ONLY; 496 497 if (sc->sc_linkmodes & CAN_LINKMODE_LOOPBACK) 498 reg |= SUNXI_CAN_MODSEL_LB_MOD; 499 500 sunxi_can_write(sc, SUNXI_CAN_MODSEL_REG, reg); 501 502 reg = 0; 503 if (sc->sc_timings.clt_prop != 0) 504 return EINVAL; 505 506 if (sc->sc_timings.clt_brp > sc->sc_timecaps.cltc_brp_max || 507 sc->sc_timings.clt_brp < sc->sc_timecaps.cltc_brp_min) 508 return EINVAL; 509 reg |= (sc->sc_timings.clt_brp - 1) << 0; 510 511 if (sc->sc_timings.clt_ps1 > sc->sc_timecaps.cltc_ps1_max || 512 sc->sc_timings.clt_ps1 < sc->sc_timecaps.cltc_ps1_min) 513 return EINVAL; 514 reg |= (sc->sc_timings.clt_ps1 - 1) << 16; 515 516 if (sc->sc_timings.clt_ps2 > sc->sc_timecaps.cltc_ps2_max || 517 sc->sc_timings.clt_ps2 < sc->sc_timecaps.cltc_ps2_min) 518 return EINVAL; 519 reg |= (sc->sc_timings.clt_ps2 - 1) << 20; 520 521 if (sc->sc_timings.clt_sjw > sc->sc_timecaps.cltc_sjw_max || 522 sc->sc_timings.clt_sjw < 1) 523 return EINVAL; 524 reg |= (sc->sc_timings.clt_sjw - 1) << 14; 525 526 if (sc->sc_linkmodes & CAN_LINKMODE_3SAMPLES) 527 reg |= SUNXI_CAN_BUS_TIME_SAM; 528 529 sunxi_can_write(sc, SUNXI_CAN_BUS_TIME_REG, reg); 530 531 /* set filters to accept all frames */ 532 sunxi_can_write(sc, SUNXI_CAN_ACPC, 0x00000000); 533 sunxi_can_write(sc, SUNXI_CAN_ACPM, 0xffffffff); 534 535 /* clear errors counter */ 536 sunxi_can_write(sc, SUNXI_CAN_REC_REG, 0); 537 538 /* leave reset mode and enable interrupts */ 539 sunxi_can_exit_reset(sc); 540 sunxi_can_write(sc, SUNXI_CAN_INTE_REG, 541 SUNXI_CAN_INT_TX_FLAG | SUNXI_CAN_INT_RX_FLAG | SUNXI_CAN_INT_ALLERRS); 542 sc->sc_ifp->if_flags |= IFF_RUNNING; 543 return 0; 544 } 545 546 static void 547 sunxi_can_ifdown(struct sunxi_can_softc * const sc) 548 { 549 sc->sc_ifp->if_flags &= ~IFF_RUNNING; 550 sc->sc_ifp->if_timer = 0; 551 sunxi_can_enter_reset(sc); 552 sunxi_can_write(sc, SUNXI_CAN_INTE_REG, 0); 553 sunxi_can_write(sc, SUNXI_CAN_INT_REG, 554 sunxi_can_read(sc, SUNXI_CAN_INT_REG)); 555 } 556 557 static int 558 sunxi_can_ifioctl(struct ifnet *ifp, u_long cmd, void *data) 559 { 560 struct sunxi_can_softc * const sc = ifp->if_softc; 561 struct ifreq *ifr = (struct ifreq *)data; 562 int error = 0; 563 564 mutex_enter(&sc->sc_intr_lock); 565 566 switch (cmd) { 567 case SIOCINITIFADDR: 568 error = EAFNOSUPPORT; 569 break; 570 case SIOCSIFMTU: 571 if ((unsigned)ifr->ifr_mtu != sizeof(struct can_frame)) 572 error = EINVAL; 573 break; 574 case SIOCADDMULTI: 575 case SIOCDELMULTI: 576 error = EAFNOSUPPORT; 577 break; 578 default: 579 error = ifioctl_common(ifp, cmd, data); 580 if (error == 0) { 581 if ((ifp->if_flags & IFF_UP) != 0 && 582 (ifp->if_flags & IFF_RUNNING) == 0) { 583 error = sunxi_can_ifup(sc); 584 if (error) { 585 ifp->if_flags &= ~IFF_UP; 586 } 587 } else if ((ifp->if_flags & IFF_UP) == 0 && 588 (ifp->if_flags & IFF_RUNNING) != 0) { 589 sunxi_can_ifdown(sc); 590 } 591 } 592 break; 593 } 594 595 mutex_exit(&sc->sc_intr_lock); 596 return error; 597 } 598 599 void 600 sunxi_can_ifwatchdog(struct ifnet *ifp) 601 { 602 struct sunxi_can_softc * const sc = ifp->if_softc; 603 printf("%s: watchdog timeout\n", device_xname(sc->sc_dev)); 604 605 mutex_enter(&sc->sc_intr_lock); 606 printf("irq 0x%x en 0x%x mode 0x%x status 0x%x timings 0x%x err 0x%x\n", 607 sunxi_can_read(sc, SUNXI_CAN_INT_REG), 608 sunxi_can_read(sc, SUNXI_CAN_INTE_REG), 609 sunxi_can_read(sc, SUNXI_CAN_MODSEL_REG), 610 sunxi_can_read(sc, SUNXI_CAN_STA_REG), 611 sunxi_can_read(sc, SUNXI_CAN_BUS_TIME_REG), 612 sunxi_can_read(sc, SUNXI_CAN_REC_REG)); 613 /* if there is a transmit in progress abort */ 614 if (sunxi_can_tx_abort(sc)) { 615 if_statinc(ifp, if_oerrors); 616 } 617 mutex_exit(&sc->sc_intr_lock); 618 } 619 620 static void 621 sunxi_can_enter_reset(struct sunxi_can_softc *sc) 622 { 623 int i; 624 uint32_t val; 625 626 for (i = 0; i < 1000; i++) { 627 val = sunxi_can_read(sc, SUNXI_CAN_MODSEL_REG); 628 val |= SUNXI_CAN_MODSEL_RST; 629 sunxi_can_write(sc, SUNXI_CAN_MODSEL_REG, val); 630 val = sunxi_can_read(sc, SUNXI_CAN_MODSEL_REG); 631 if (val & SUNXI_CAN_MODSEL_RST) 632 return; 633 } 634 printf("%s: couldn't enter reset mode\n", device_xname(sc->sc_dev)); 635 } 636 637 static void 638 sunxi_can_exit_reset(struct sunxi_can_softc *sc) 639 { 640 int i; 641 uint32_t val; 642 643 for (i = 0; i < 1000; i++) { 644 val = sunxi_can_read(sc, SUNXI_CAN_MODSEL_REG); 645 val &= ~SUNXI_CAN_MODSEL_RST; 646 sunxi_can_write(sc, SUNXI_CAN_MODSEL_REG, val); 647 val = sunxi_can_read(sc, SUNXI_CAN_MODSEL_REG); 648 if ((val & SUNXI_CAN_MODSEL_RST) == 0) 649 return; 650 } 651 printf("%s: couldn't leave reset mode\n", device_xname(sc->sc_dev)); 652 } 653