| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769 |
- // SPDX-License-Identifier: GPL-2.0-only
- /* Copyright (C) 2015 - 2016 Thomas Körper, esd electronic system design gmbh
- * Copyright (C) 2017 - 2023 Stefan Mätje, esd electronics gmbh
- */
- #include "esdacc.h"
- #include <linux/bitfield.h>
- #include <linux/delay.h>
- #include <linux/io.h>
- #include <linux/ktime.h>
- /* esdACC ID register layout */
- #define ACC_ID_ID_MASK GENMASK(28, 0)
- #define ACC_ID_EFF_FLAG BIT(29)
- /* esdACC DLC register layout */
- #define ACC_DLC_DLC_MASK GENMASK(3, 0)
- #define ACC_DLC_RTR_FLAG BIT(4)
- #define ACC_DLC_SSTX_FLAG BIT(24) /* Single Shot TX */
- /* esdACC DLC in struct acc_bmmsg_rxtxdone::acc_dlc.len only! */
- #define ACC_DLC_TXD_FLAG BIT(5)
- /* ecc value of esdACC equals SJA1000's ECC register */
- #define ACC_ECC_SEG 0x1f
- #define ACC_ECC_DIR 0x20
- #define ACC_ECC_BIT 0x00
- #define ACC_ECC_FORM 0x40
- #define ACC_ECC_STUFF 0x80
- #define ACC_ECC_MASK 0xc0
- /* esdACC Status Register bits. Unused bits not documented. */
- #define ACC_REG_STATUS_MASK_STATUS_ES BIT(17)
- #define ACC_REG_STATUS_MASK_STATUS_EP BIT(18)
- #define ACC_REG_STATUS_MASK_STATUS_BS BIT(19)
- /* esdACC Overview Module BM_IRQ_Mask register related defines */
- /* Two bit wide command masks to mask or unmask a single core IRQ */
- #define ACC_BM_IRQ_UNMASK BIT(0)
- #define ACC_BM_IRQ_MASK (ACC_BM_IRQ_UNMASK << 1)
- /* Command to unmask all IRQ sources. Created by shifting
- * and oring the two bit wide ACC_BM_IRQ_UNMASK 16 times.
- */
- #define ACC_BM_IRQ_UNMASK_ALL 0x55555555U
- static void acc_resetmode_enter(struct acc_core *core)
- {
- acc_set_bits(core, ACC_CORE_OF_CTRL,
- ACC_REG_CTRL_MASK_RESETMODE);
- /* Read back reset mode bit to flush PCI write posting */
- acc_resetmode_entered(core);
- }
- static void acc_resetmode_leave(struct acc_core *core)
- {
- acc_clear_bits(core, ACC_CORE_OF_CTRL,
- ACC_REG_CTRL_MASK_RESETMODE);
- /* Read back reset mode bit to flush PCI write posting */
- acc_resetmode_entered(core);
- }
- static void acc_txq_put(struct acc_core *core, u32 acc_id, u32 acc_dlc,
- const void *data)
- {
- acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_1,
- *((const u32 *)(data + 4)));
- acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_0,
- *((const u32 *)data));
- acc_write32(core, ACC_CORE_OF_TXFIFO_DLC, acc_dlc);
- /* CAN id must be written at last. This write starts TX. */
- acc_write32(core, ACC_CORE_OF_TXFIFO_ID, acc_id);
- }
- static u8 acc_tx_fifo_next(struct acc_core *core, u8 tx_fifo_idx)
- {
- ++tx_fifo_idx;
- if (tx_fifo_idx >= core->tx_fifo_size)
- tx_fifo_idx = 0U;
- return tx_fifo_idx;
- }
- /* Convert timestamp from esdACC time stamp ticks to ns
- *
- * The conversion factor ts2ns from time stamp counts to ns is basically
- * ts2ns = NSEC_PER_SEC / timestamp_frequency
- *
- * We handle here only a fixed timestamp frequency of 80MHz. The
- * resulting ts2ns factor would be 12.5.
- *
- * At the end we multiply by 12 and add the half of the HW timestamp
- * to get a multiplication by 12.5. This way any overflow is
- * avoided until ktime_t itself overflows.
- */
- #define ACC_TS_FACTOR (NSEC_PER_SEC / ACC_TS_FREQ_80MHZ)
- #define ACC_TS_80MHZ_SHIFT 1
- static ktime_t acc_ts2ktime(struct acc_ov *ov, u64 ts)
- {
- u64 ns;
- ns = (ts * ACC_TS_FACTOR) + (ts >> ACC_TS_80MHZ_SHIFT);
- return ns_to_ktime(ns);
- }
- #undef ACC_TS_FACTOR
- #undef ACC_TS_80MHZ_SHIFT
- void acc_init_ov(struct acc_ov *ov, struct device *dev)
- {
- u32 temp;
- temp = acc_ov_read32(ov, ACC_OV_OF_VERSION);
- ov->version = temp;
- ov->features = (temp >> 16);
- temp = acc_ov_read32(ov, ACC_OV_OF_INFO);
- ov->total_cores = temp;
- ov->active_cores = (temp >> 8);
- ov->core_frequency = acc_ov_read32(ov, ACC_OV_OF_CANCORE_FREQ);
- ov->timestamp_frequency = acc_ov_read32(ov, ACC_OV_OF_TS_FREQ_LO);
- /* Depending on esdACC feature NEW_PSC enable the new prescaler
- * or adjust core_frequency according to the implicit division by 2.
- */
- if (ov->features & ACC_OV_REG_FEAT_MASK_NEW_PSC) {
- acc_ov_set_bits(ov, ACC_OV_OF_MODE,
- ACC_OV_REG_MODE_MASK_NEW_PSC_ENABLE);
- } else {
- ov->core_frequency /= 2;
- }
- dev_dbg(dev,
- "esdACC v%u, freq: %u/%u, feat/strap: 0x%x/0x%x, cores: %u/%u\n",
- ov->version, ov->core_frequency, ov->timestamp_frequency,
- ov->features, acc_ov_read32(ov, ACC_OV_OF_INFO) >> 16,
- ov->active_cores, ov->total_cores);
- }
- void acc_init_bm_ptr(struct acc_ov *ov, struct acc_core *cores, const void *mem)
- {
- unsigned int u;
- /* DMA buffer layout as follows where N is the number of CAN cores
- * implemented in the FPGA, i.e. N = ov->total_cores
- *
- * Section Layout Section size
- * ----------------------------------------------
- * FIFO Card/Overview ACC_CORE_DMABUF_SIZE
- * FIFO Core0 ACC_CORE_DMABUF_SIZE
- * ... ...
- * FIFO CoreN ACC_CORE_DMABUF_SIZE
- * irq_cnt Card/Overview sizeof(u32)
- * irq_cnt Core0 sizeof(u32)
- * ... ...
- * irq_cnt CoreN sizeof(u32)
- */
- ov->bmfifo.messages = mem;
- ov->bmfifo.irq_cnt = mem + (ov->total_cores + 1U) * ACC_CORE_DMABUF_SIZE;
- for (u = 0U; u < ov->active_cores; u++) {
- struct acc_core *core = &cores[u];
- core->bmfifo.messages = mem + (u + 1U) * ACC_CORE_DMABUF_SIZE;
- core->bmfifo.irq_cnt = ov->bmfifo.irq_cnt + (u + 1U);
- }
- }
- int acc_open(struct net_device *netdev)
- {
- struct acc_net_priv *priv = netdev_priv(netdev);
- struct acc_core *core = priv->core;
- u32 tx_fifo_status;
- u32 ctrl;
- int err;
- /* Retry to enter RESET mode if out of sync. */
- if (priv->can.state != CAN_STATE_STOPPED) {
- netdev_warn(netdev, "Entered %s() with bad can.state: %s\n",
- __func__, can_get_state_str(priv->can.state));
- acc_resetmode_enter(core);
- priv->can.state = CAN_STATE_STOPPED;
- }
- err = open_candev(netdev);
- if (err)
- return err;
- ctrl = ACC_REG_CTRL_MASK_IE_RXTX |
- ACC_REG_CTRL_MASK_IE_TXERROR |
- ACC_REG_CTRL_MASK_IE_ERRWARN |
- ACC_REG_CTRL_MASK_IE_OVERRUN |
- ACC_REG_CTRL_MASK_IE_ERRPASS;
- if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
- ctrl |= ACC_REG_CTRL_MASK_IE_BUSERR;
- if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
- ctrl |= ACC_REG_CTRL_MASK_LOM;
- acc_set_bits(core, ACC_CORE_OF_CTRL, ctrl);
- acc_resetmode_leave(core);
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
- /* Resync TX FIFO indices to HW state after (re-)start. */
- tx_fifo_status = acc_read32(core, ACC_CORE_OF_TXFIFO_STATUS);
- core->tx_fifo_head = tx_fifo_status & 0xff;
- core->tx_fifo_tail = (tx_fifo_status >> 8) & 0xff;
- netif_start_queue(netdev);
- return 0;
- }
- int acc_close(struct net_device *netdev)
- {
- struct acc_net_priv *priv = netdev_priv(netdev);
- struct acc_core *core = priv->core;
- acc_clear_bits(core, ACC_CORE_OF_CTRL,
- ACC_REG_CTRL_MASK_IE_RXTX |
- ACC_REG_CTRL_MASK_IE_TXERROR |
- ACC_REG_CTRL_MASK_IE_ERRWARN |
- ACC_REG_CTRL_MASK_IE_OVERRUN |
- ACC_REG_CTRL_MASK_IE_ERRPASS |
- ACC_REG_CTRL_MASK_IE_BUSERR);
- netif_stop_queue(netdev);
- acc_resetmode_enter(core);
- priv->can.state = CAN_STATE_STOPPED;
- /* Mark pending TX requests to be aborted after controller restart. */
- acc_write32(core, ACC_CORE_OF_TX_ABORT_MASK, 0xffff);
- /* ACC_REG_CTRL_MASK_LOM is only accessible in RESET mode */
- acc_clear_bits(core, ACC_CORE_OF_CTRL,
- ACC_REG_CTRL_MASK_LOM);
- close_candev(netdev);
- return 0;
- }
- netdev_tx_t acc_start_xmit(struct sk_buff *skb, struct net_device *netdev)
- {
- struct acc_net_priv *priv = netdev_priv(netdev);
- struct acc_core *core = priv->core;
- struct can_frame *cf = (struct can_frame *)skb->data;
- u8 tx_fifo_head = core->tx_fifo_head;
- int fifo_usage;
- u32 acc_id;
- u32 acc_dlc;
- if (can_dev_dropped_skb(netdev, skb))
- return NETDEV_TX_OK;
- /* Access core->tx_fifo_tail only once because it may be changed
- * from the interrupt level.
- */
- fifo_usage = tx_fifo_head - core->tx_fifo_tail;
- if (fifo_usage < 0)
- fifo_usage += core->tx_fifo_size;
- if (fifo_usage >= core->tx_fifo_size - 1) {
- netdev_err(core->netdev,
- "BUG: TX ring full when queue awake!\n");
- netif_stop_queue(netdev);
- return NETDEV_TX_BUSY;
- }
- if (fifo_usage == core->tx_fifo_size - 2)
- netif_stop_queue(netdev);
- acc_dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
- if (cf->can_id & CAN_RTR_FLAG)
- acc_dlc |= ACC_DLC_RTR_FLAG;
- if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
- acc_dlc |= ACC_DLC_SSTX_FLAG;
- if (cf->can_id & CAN_EFF_FLAG) {
- acc_id = cf->can_id & CAN_EFF_MASK;
- acc_id |= ACC_ID_EFF_FLAG;
- } else {
- acc_id = cf->can_id & CAN_SFF_MASK;
- }
- can_put_echo_skb(skb, netdev, core->tx_fifo_head, 0);
- core->tx_fifo_head = acc_tx_fifo_next(core, tx_fifo_head);
- acc_txq_put(core, acc_id, acc_dlc, cf->data);
- return NETDEV_TX_OK;
- }
- int acc_get_berr_counter(const struct net_device *netdev,
- struct can_berr_counter *bec)
- {
- struct acc_net_priv *priv = netdev_priv(netdev);
- u32 core_status = acc_read32(priv->core, ACC_CORE_OF_STATUS);
- bec->txerr = (core_status >> 8) & 0xff;
- bec->rxerr = core_status & 0xff;
- return 0;
- }
- int acc_set_mode(struct net_device *netdev, enum can_mode mode)
- {
- struct acc_net_priv *priv = netdev_priv(netdev);
- switch (mode) {
- case CAN_MODE_START:
- /* Paranoid FIFO index check. */
- {
- const u32 tx_fifo_status =
- acc_read32(priv->core, ACC_CORE_OF_TXFIFO_STATUS);
- const u8 hw_fifo_head = tx_fifo_status;
- if (hw_fifo_head != priv->core->tx_fifo_head ||
- hw_fifo_head != priv->core->tx_fifo_tail) {
- netdev_warn(netdev,
- "TX FIFO mismatch: T %2u H %2u; TFHW %#08x\n",
- priv->core->tx_fifo_tail,
- priv->core->tx_fifo_head,
- tx_fifo_status);
- }
- }
- acc_resetmode_leave(priv->core);
- /* To leave the bus-off state the esdACC controller begins
- * here a grace period where it counts 128 "idle conditions" (each
- * of 11 consecutive recessive bits) on the bus as required
- * by the CAN spec.
- *
- * During this time the TX FIFO may still contain already
- * aborted "zombie" frames that are only drained from the FIFO
- * at the end of the grace period.
- *
- * To not to interfere with this drain process we don't
- * call netif_wake_queue() here. When the controller reaches
- * the error-active state again, it informs us about that
- * with an acc_bmmsg_errstatechange message. Then
- * netif_wake_queue() is called from
- * handle_core_msg_errstatechange() instead.
- */
- break;
- default:
- return -EOPNOTSUPP;
- }
- return 0;
- }
- int acc_set_bittiming(struct net_device *netdev)
- {
- struct acc_net_priv *priv = netdev_priv(netdev);
- const struct can_bittiming *bt = &priv->can.bittiming;
- u32 brp;
- u32 btr;
- if (priv->ov->features & ACC_OV_REG_FEAT_MASK_CANFD) {
- u32 fbtr = 0;
- netdev_dbg(netdev, "bit timing: brp %u, prop %u, ph1 %u ph2 %u, sjw %u\n",
- bt->brp, bt->prop_seg,
- bt->phase_seg1, bt->phase_seg2, bt->sjw);
- brp = FIELD_PREP(ACC_REG_BRP_FD_MASK_BRP, bt->brp - 1);
- btr = FIELD_PREP(ACC_REG_BTR_FD_MASK_TSEG1, bt->phase_seg1 + bt->prop_seg - 1);
- btr |= FIELD_PREP(ACC_REG_BTR_FD_MASK_TSEG2, bt->phase_seg2 - 1);
- btr |= FIELD_PREP(ACC_REG_BTR_FD_MASK_SJW, bt->sjw - 1);
- /* Keep order of accesses to ACC_CORE_OF_BRP and ACC_CORE_OF_BTR. */
- acc_write32(priv->core, ACC_CORE_OF_BRP, brp);
- acc_write32(priv->core, ACC_CORE_OF_BTR, btr);
- netdev_dbg(netdev, "esdACC: BRP %u, NBTR 0x%08x, DBTR 0x%08x",
- brp, btr, fbtr);
- } else {
- netdev_dbg(netdev, "bit timing: brp %u, prop %u, ph1 %u ph2 %u, sjw %u\n",
- bt->brp, bt->prop_seg,
- bt->phase_seg1, bt->phase_seg2, bt->sjw);
- brp = FIELD_PREP(ACC_REG_BRP_CL_MASK_BRP, bt->brp - 1);
- btr = FIELD_PREP(ACC_REG_BTR_CL_MASK_TSEG1, bt->phase_seg1 + bt->prop_seg - 1);
- btr |= FIELD_PREP(ACC_REG_BTR_CL_MASK_TSEG2, bt->phase_seg2 - 1);
- btr |= FIELD_PREP(ACC_REG_BTR_CL_MASK_SJW, bt->sjw - 1);
- /* Keep order of accesses to ACC_CORE_OF_BRP and ACC_CORE_OF_BTR. */
- acc_write32(priv->core, ACC_CORE_OF_BRP, brp);
- acc_write32(priv->core, ACC_CORE_OF_BTR, btr);
- netdev_dbg(netdev, "esdACC: BRP %u, BTR 0x%08x", brp, btr);
- }
- return 0;
- }
- static void handle_core_msg_rxtxdone(struct acc_core *core,
- const struct acc_bmmsg_rxtxdone *msg)
- {
- struct acc_net_priv *priv = netdev_priv(core->netdev);
- struct net_device_stats *stats = &core->netdev->stats;
- struct sk_buff *skb;
- if (msg->acc_dlc.len & ACC_DLC_TXD_FLAG) {
- u8 tx_fifo_tail = core->tx_fifo_tail;
- if (core->tx_fifo_head == tx_fifo_tail) {
- netdev_warn(core->netdev,
- "TX interrupt, but queue is empty!?\n");
- return;
- }
- /* Direct access echo skb to attach HW time stamp. */
- skb = priv->can.echo_skb[tx_fifo_tail];
- if (skb) {
- skb_hwtstamps(skb)->hwtstamp =
- acc_ts2ktime(priv->ov, msg->ts);
- }
- stats->tx_packets++;
- stats->tx_bytes += can_get_echo_skb(core->netdev, tx_fifo_tail,
- NULL);
- core->tx_fifo_tail = acc_tx_fifo_next(core, tx_fifo_tail);
- netif_wake_queue(core->netdev);
- } else {
- struct can_frame *cf;
- skb = alloc_can_skb(core->netdev, &cf);
- if (!skb) {
- stats->rx_dropped++;
- return;
- }
- cf->can_id = msg->id & ACC_ID_ID_MASK;
- if (msg->id & ACC_ID_EFF_FLAG)
- cf->can_id |= CAN_EFF_FLAG;
- can_frame_set_cc_len(cf, msg->acc_dlc.len & ACC_DLC_DLC_MASK,
- priv->can.ctrlmode);
- if (msg->acc_dlc.len & ACC_DLC_RTR_FLAG) {
- cf->can_id |= CAN_RTR_FLAG;
- } else {
- memcpy(cf->data, msg->data, cf->len);
- stats->rx_bytes += cf->len;
- }
- stats->rx_packets++;
- skb_hwtstamps(skb)->hwtstamp = acc_ts2ktime(priv->ov, msg->ts);
- netif_rx(skb);
- }
- }
- static void handle_core_msg_txabort(struct acc_core *core,
- const struct acc_bmmsg_txabort *msg)
- {
- struct net_device_stats *stats = &core->netdev->stats;
- u8 tx_fifo_tail = core->tx_fifo_tail;
- u32 abort_mask = msg->abort_mask; /* u32 extend to avoid warnings later */
- /* The abort_mask shows which frames were aborted in esdACC's FIFO. */
- while (tx_fifo_tail != core->tx_fifo_head && (abort_mask)) {
- const u32 tail_mask = (1U << tx_fifo_tail);
- if (!(abort_mask & tail_mask))
- break;
- abort_mask &= ~tail_mask;
- can_free_echo_skb(core->netdev, tx_fifo_tail, NULL);
- stats->tx_dropped++;
- stats->tx_aborted_errors++;
- tx_fifo_tail = acc_tx_fifo_next(core, tx_fifo_tail);
- }
- core->tx_fifo_tail = tx_fifo_tail;
- if (abort_mask)
- netdev_warn(core->netdev, "Unhandled aborted messages\n");
- if (!acc_resetmode_entered(core))
- netif_wake_queue(core->netdev);
- }
- static void handle_core_msg_overrun(struct acc_core *core,
- const struct acc_bmmsg_overrun *msg)
- {
- struct acc_net_priv *priv = netdev_priv(core->netdev);
- struct net_device_stats *stats = &core->netdev->stats;
- struct can_frame *cf;
- struct sk_buff *skb;
- /* lost_cnt may be 0 if not supported by esdACC version */
- if (msg->lost_cnt) {
- stats->rx_errors += msg->lost_cnt;
- stats->rx_over_errors += msg->lost_cnt;
- } else {
- stats->rx_errors++;
- stats->rx_over_errors++;
- }
- skb = alloc_can_err_skb(core->netdev, &cf);
- if (!skb)
- return;
- cf->can_id |= CAN_ERR_CRTL;
- cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
- skb_hwtstamps(skb)->hwtstamp = acc_ts2ktime(priv->ov, msg->ts);
- netif_rx(skb);
- }
- static void handle_core_msg_buserr(struct acc_core *core,
- const struct acc_bmmsg_buserr *msg)
- {
- struct acc_net_priv *priv = netdev_priv(core->netdev);
- struct net_device_stats *stats = &core->netdev->stats;
- struct can_frame *cf;
- struct sk_buff *skb;
- const u32 reg_status = msg->reg_status;
- const u8 rxerr = reg_status;
- const u8 txerr = (reg_status >> 8);
- u8 can_err_prot_type = 0U;
- priv->can.can_stats.bus_error++;
- /* Error occurred during transmission? */
- if (msg->ecc & ACC_ECC_DIR) {
- stats->rx_errors++;
- } else {
- can_err_prot_type |= CAN_ERR_PROT_TX;
- stats->tx_errors++;
- }
- /* Determine error type */
- switch (msg->ecc & ACC_ECC_MASK) {
- case ACC_ECC_BIT:
- can_err_prot_type |= CAN_ERR_PROT_BIT;
- break;
- case ACC_ECC_FORM:
- can_err_prot_type |= CAN_ERR_PROT_FORM;
- break;
- case ACC_ECC_STUFF:
- can_err_prot_type |= CAN_ERR_PROT_STUFF;
- break;
- default:
- can_err_prot_type |= CAN_ERR_PROT_UNSPEC;
- break;
- }
- skb = alloc_can_err_skb(core->netdev, &cf);
- if (!skb)
- return;
- cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR | CAN_ERR_CNT;
- /* Set protocol error type */
- cf->data[2] = can_err_prot_type;
- /* Set error location */
- cf->data[3] = msg->ecc & ACC_ECC_SEG;
- /* Insert CAN TX and RX error counters. */
- cf->data[6] = txerr;
- cf->data[7] = rxerr;
- skb_hwtstamps(skb)->hwtstamp = acc_ts2ktime(priv->ov, msg->ts);
- netif_rx(skb);
- }
- static void
- handle_core_msg_errstatechange(struct acc_core *core,
- const struct acc_bmmsg_errstatechange *msg)
- {
- struct acc_net_priv *priv = netdev_priv(core->netdev);
- struct can_frame *cf = NULL;
- struct sk_buff *skb;
- const u32 reg_status = msg->reg_status;
- const u8 rxerr = reg_status;
- const u8 txerr = (reg_status >> 8);
- enum can_state new_state;
- if (reg_status & ACC_REG_STATUS_MASK_STATUS_BS) {
- new_state = CAN_STATE_BUS_OFF;
- } else if (reg_status & ACC_REG_STATUS_MASK_STATUS_EP) {
- new_state = CAN_STATE_ERROR_PASSIVE;
- } else if (reg_status & ACC_REG_STATUS_MASK_STATUS_ES) {
- new_state = CAN_STATE_ERROR_WARNING;
- } else {
- new_state = CAN_STATE_ERROR_ACTIVE;
- if (priv->can.state == CAN_STATE_BUS_OFF) {
- /* See comment in acc_set_mode() for CAN_MODE_START */
- netif_wake_queue(core->netdev);
- }
- }
- skb = alloc_can_err_skb(core->netdev, &cf);
- if (new_state != priv->can.state) {
- enum can_state tx_state, rx_state;
- tx_state = (txerr >= rxerr) ?
- new_state : CAN_STATE_ERROR_ACTIVE;
- rx_state = (rxerr >= txerr) ?
- new_state : CAN_STATE_ERROR_ACTIVE;
- /* Always call can_change_state() to update the state
- * even if alloc_can_err_skb() may have failed.
- * can_change_state() can cope with a NULL cf pointer.
- */
- can_change_state(core->netdev, cf, tx_state, rx_state);
- }
- if (skb) {
- cf->can_id |= CAN_ERR_CNT;
- cf->data[6] = txerr;
- cf->data[7] = rxerr;
- skb_hwtstamps(skb)->hwtstamp = acc_ts2ktime(priv->ov, msg->ts);
- netif_rx(skb);
- }
- if (new_state == CAN_STATE_BUS_OFF) {
- acc_write32(core, ACC_CORE_OF_TX_ABORT_MASK, 0xffff);
- can_bus_off(core->netdev);
- }
- }
- static void handle_core_interrupt(struct acc_core *core)
- {
- u32 msg_fifo_head = core->bmfifo.local_irq_cnt & 0xff;
- while (core->bmfifo.msg_fifo_tail != msg_fifo_head) {
- const union acc_bmmsg *msg =
- &core->bmfifo.messages[core->bmfifo.msg_fifo_tail];
- switch (msg->msg_id) {
- case BM_MSG_ID_RXTXDONE:
- handle_core_msg_rxtxdone(core, &msg->rxtxdone);
- break;
- case BM_MSG_ID_TXABORT:
- handle_core_msg_txabort(core, &msg->txabort);
- break;
- case BM_MSG_ID_OVERRUN:
- handle_core_msg_overrun(core, &msg->overrun);
- break;
- case BM_MSG_ID_BUSERR:
- handle_core_msg_buserr(core, &msg->buserr);
- break;
- case BM_MSG_ID_ERRPASSIVE:
- case BM_MSG_ID_ERRWARN:
- handle_core_msg_errstatechange(core,
- &msg->errstatechange);
- break;
- default:
- /* Ignore all other BM messages (like the CAN-FD messages) */
- break;
- }
- core->bmfifo.msg_fifo_tail =
- (core->bmfifo.msg_fifo_tail + 1) & 0xff;
- }
- }
- /**
- * acc_card_interrupt() - handle the interrupts of an esdACC FPGA
- *
- * @ov: overview module structure
- * @cores: array of core structures
- *
- * This function handles all interrupts pending for the overview module and the
- * CAN cores of the esdACC FPGA.
- *
- * It examines for all cores (the overview module core and the CAN cores)
- * the bmfifo.irq_cnt and compares it with the previously saved
- * bmfifo.local_irq_cnt. An IRQ is pending if they differ. The esdACC FPGA
- * updates the bmfifo.irq_cnt values by DMA.
- *
- * The pending interrupts are masked by writing to the IRQ mask register at
- * ACC_OV_OF_BM_IRQ_MASK. This register has for each core a two bit command
- * field evaluated as follows:
- *
- * Define, bit pattern: meaning
- * 00: no action
- * ACC_BM_IRQ_UNMASK, 01: unmask interrupt
- * ACC_BM_IRQ_MASK, 10: mask interrupt
- * 11: no action
- *
- * For each CAN core with a pending IRQ handle_core_interrupt() handles all
- * busmaster messages from the message FIFO. The last handled message (FIFO
- * index) is written to the CAN core to acknowledge its handling.
- *
- * Last step is to unmask all interrupts in the FPGA using
- * ACC_BM_IRQ_UNMASK_ALL.
- *
- * Return:
- * IRQ_HANDLED, if card generated an interrupt that was handled
- * IRQ_NONE, if the interrupt is not ours
- */
- irqreturn_t acc_card_interrupt(struct acc_ov *ov, struct acc_core *cores)
- {
- u32 irqmask;
- int i;
- /* First we look for whom interrupts are pending, card/overview
- * or any of the cores. Two bits in irqmask are used for each;
- * Each two bit field is set to ACC_BM_IRQ_MASK if an IRQ is
- * pending.
- */
- irqmask = 0U;
- if (READ_ONCE(*ov->bmfifo.irq_cnt) != ov->bmfifo.local_irq_cnt) {
- irqmask |= ACC_BM_IRQ_MASK;
- ov->bmfifo.local_irq_cnt = READ_ONCE(*ov->bmfifo.irq_cnt);
- }
- for (i = 0; i < ov->active_cores; i++) {
- struct acc_core *core = &cores[i];
- if (READ_ONCE(*core->bmfifo.irq_cnt) != core->bmfifo.local_irq_cnt) {
- irqmask |= (ACC_BM_IRQ_MASK << (2 * (i + 1)));
- core->bmfifo.local_irq_cnt = READ_ONCE(*core->bmfifo.irq_cnt);
- }
- }
- if (!irqmask)
- return IRQ_NONE;
- /* At second we tell the card we're working on them by writing irqmask,
- * call handle_{ov|core}_interrupt and then acknowledge the
- * interrupts by writing irq_cnt:
- */
- acc_ov_write32(ov, ACC_OV_OF_BM_IRQ_MASK, irqmask);
- if (irqmask & ACC_BM_IRQ_MASK) {
- /* handle_ov_interrupt(); - no use yet. */
- acc_ov_write32(ov, ACC_OV_OF_BM_IRQ_COUNTER,
- ov->bmfifo.local_irq_cnt);
- }
- for (i = 0; i < ov->active_cores; i++) {
- struct acc_core *core = &cores[i];
- if (irqmask & (ACC_BM_IRQ_MASK << (2 * (i + 1)))) {
- handle_core_interrupt(core);
- acc_write32(core, ACC_OV_OF_BM_IRQ_COUNTER,
- core->bmfifo.local_irq_cnt);
- }
- }
- acc_ov_write32(ov, ACC_OV_OF_BM_IRQ_MASK, ACC_BM_IRQ_UNMASK_ALL);
- return IRQ_HANDLED;
- }
|