/* Note: According to documentation clearing TXIE while MSGVAL is set *isnotallowed,butworksnicelyonC/DCAN.AndthatlowerstheI/O *loadsignificantly.
*/ staticvoid c_can_inval_tx_object(struct net_device *dev, int iface, int obj)
{ struct c_can_priv *priv = netdev_priv(dev);
/* If we change the DIR bit, we need to invalidate the buffer *first,i.e.cleartheMSGVALflaginthearbiter.
*/ if (rtr != (bool)test_bit(idx, &priv->tx_dir)) {
u32 obj = idx + priv->msg_obj_tx_first;
if (can_dev_dropped_skb(dev, skb)) return NETDEV_TX_OK;
if (c_can_tx_busy(priv, tx_ring)) return NETDEV_TX_BUSY;
idx = c_can_get_tx_head(tx_ring);
tx_ring->head++; if (c_can_get_tx_free(priv, tx_ring) == 0)
netif_stop_queue(dev);
if (idx < c_can_get_tx_tail(tx_ring))
cmd &= ~IF_COMM_TXRQST; /* Cache the message */
/* Store the message in the interface so we can call *can_put_echo_skb().Wemustdothisbeforeweenable *transmitaswemightraceagainstdo_tx().
*/
c_can_setup_tx_object(dev, IF_TX, frame, idx);
can_put_echo_skb(skb, dev, idx, 0);
obj = idx + priv->msg_obj_tx_first;
c_can_object_put(dev, IF_TX, obj, cmd);
/* Configure C_CAN message objects for Tx and Rx purposes: *C_CANprovidesatotalof32messageobjectsthatcanbeconfigured *eitherforTxorRxpurposes.Herethefirst16messageobjectsareusedas *areceptionFIFO.TheendofreceptionFIFOissignifiedbytheEoBbit *beingSET.Theremaining16messageobjectsarekeptasideforTxpurposes. *Seeuserguidedocumentforfurtherdetailsonconfiguringmessage *objects.
*/ staticvoid c_can_configure_msg_objects(struct net_device *dev)
{ struct c_can_priv *priv = netdev_priv(dev); int i;
/* first invalidate all message objects */ for (i = priv->msg_obj_rx_first; i <= priv->msg_obj_num; i++)
c_can_inval_msg_object(dev, IF_NAPI, i);
/* setup receive message objects */ for (i = priv->msg_obj_rx_first; i < priv->msg_obj_rx_last; i++)
c_can_setup_receive_object(dev, IF_NAPI, i, 0, 0, IF_MCONT_RCV);
/* Setup the command for new messages */
priv->comm_rcv_high = priv->type != BOSCH_D_CAN ?
IF_COMM_RCV_LOW : IF_COMM_RCV_HIGH;
priv->can.state = CAN_STATE_ERROR_ACTIVE;
/* Attempt to use "active" if available else use "default" */
p = pinctrl_get_select(priv->device, "active"); if (!IS_ERR(p))
pinctrl_put(p); else
pinctrl_pm_select_default_state(priv->device);
/* We use IF_NAPI interface instead of IF_TX because we *arecalledfromc_can_poll(),whichrunsinside *NAPI.Wearenottransmitting.
*/
c_can_inval_tx_object(dev, IF_NAPI, obj);
bytes += can_get_echo_skb(dev, idx, NULL);
pkts++;
}
if (!pkts) return;
tx_ring->tail += pkts; if (c_can_get_tx_free(priv, tx_ring)) { /* Make sure that anybody stopping the queue after *thisseesthenewtx_ring->tail.
*/
smp_mb();
netif_wake_queue(priv->dev);
}
tail = c_can_get_tx_tail(tx_ring); if (priv->type == BOSCH_D_CAN && tail == 0) {
u8 head = c_can_get_tx_head(tx_ring);
/* Start transmission for all cached messages */ for (idx = tail; idx < head; idx++) {
obj = idx + priv->msg_obj_tx_first;
c_can_object_put(dev, IF_NAPI, obj, IF_COMM_TXRQST);
}
}
}
/* If we have a gap in the pending bits, that means we either *racedwiththehardwareorfailedtoreadoutallupper *objectsinthelastrunduetoquotalimit.
*/ static u32 c_can_adjust_pending(u32 pend, u32 rx_mask)
{
u32 weight, lasts;
if (pend == rx_mask) return pend;
/* If the last set bit is larger than the number of pending *bitswehaveagap.
*/
weight = hweight32(pend);
lasts = fls(pend);
/* If the bits are linear, nothing to do */ if (lasts == weight) return pend;
/* Find the first set bit after the gap. We walk backwards *fromthelastsetbit.
*/ for (lasts--; pend & BIT(lasts - 1); lasts--)
;
n = c_can_handle_lost_msg_obj(dev, IF_NAPI, obj, ctrl);
pkts += n;
quota -= n; continue;
}
/* This really should not happen, but this covers some *oddHWbehaviour.Donotremovethatunlessyou *wanttobrickyourmachine.
*/ if (!(ctrl & IF_MCONT_NEWDAT)) continue;
/* read the data from the message object */
c_can_read_msg_object(dev, IF_NAPI, ctrl);
while (quota > 0) { if (!pend) {
pend = c_can_get_pending(priv); if (!pend) break; /* If the pending field has a gap, handle the *bitsabovethegapfirst.
*/
toread = c_can_adjust_pending(pend,
priv->msg_obj_rx_mask);
} else {
toread = pend;
} /* Remove the bits from pend */
pend &= ~toread; /* Read the objects */
n = c_can_read_objects(dev, priv, toread, quota);
pkts += n;
quota -= n;
}
/* early exit if no lec update or no error. *nolecupdatemeansthatnoCANbuseventhasbeendetected *sinceCPUwrote0x7valuetostatusreg.
*/ if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR) return0;
if (!(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) return0;
/* common for all type of bus errors */
priv->can.can_stats.bus_error++;
/* propagate the error condition to the CAN stack */
skb = alloc_can_err_skb(dev, &cf);
/* check for 'last error code' which tells us the *typeofthelasterrortooccurontheCANbus
*/ if (likely(skb))
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
switch (lec_type) { case LEC_STUFF_ERROR:
netdev_dbg(dev, "stuff error\n"); if (likely(skb))
cf->data[2] |= CAN_ERR_PROT_STUFF;
stats->rx_errors++; break; case LEC_FORM_ERROR:
netdev_dbg(dev, "form error\n"); if (likely(skb))
cf->data[2] |= CAN_ERR_PROT_FORM;
stats->rx_errors++; break; case LEC_ACK_ERROR:
netdev_dbg(dev, "ack error\n"); if (likely(skb))
cf->data[3] = CAN_ERR_PROT_LOC_ACK;
stats->tx_errors++; break; case LEC_BIT1_ERROR:
netdev_dbg(dev, "bit1 error\n"); if (likely(skb))
cf->data[2] |= CAN_ERR_PROT_BIT1;
stats->tx_errors++; break; case LEC_BIT0_ERROR:
netdev_dbg(dev, "bit0 error\n"); if (likely(skb))
cf->data[2] |= CAN_ERR_PROT_BIT0;
stats->tx_errors++; break; case LEC_CRC_ERROR:
netdev_dbg(dev, "CRC error\n"); if (likely(skb))
cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
stats->rx_errors++; break; default: break;
}
if (unlikely(!skb)) return0;
netif_receive_skb(skb); return1;
}
staticint c_can_poll(struct napi_struct *napi, int quota)
{ struct net_device *dev = napi->dev; struct c_can_priv *priv = netdev_priv(dev);
u16 curr, last = priv->last_status; int work_done = 0;
/* Only read the status register if a status interrupt was pending */ if (atomic_xchg(&priv->sie_pending, 0)) {
priv->last_status = priv->read_reg(priv, C_CAN_STS_REG);
curr = priv->last_status; /* Ack status on C_CAN. D_CAN is self clearing */ if (priv->type != BOSCH_D_CAN)
priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
} else { /* no change detected ... */
curr = last;
}
/* handle lec errors on the bus */
work_done += c_can_handle_bus_err(dev, curr & LEC_MASK);
/* Handle Tx/Rx events. We do this unconditionally */
work_done += c_can_do_rx_poll(dev, (quota - work_done));
c_can_do_tx(dev);
end: if (work_done < quota) {
napi_complete_done(napi, work_done); /* enable all IRQs if we are not in bus off state */ if (priv->can.state != CAN_STATE_BUS_OFF)
c_can_irq_control(priv, true);
}
/* set PDR value so the device goes to power down mode */
val = priv->read_reg(priv, C_CAN_CTRL_EX_REG);
val |= CONTROL_EX_PDR;
priv->write_reg(priv, C_CAN_CTRL_EX_REG, val);
/* Wait for the PDA bit to get set */
time_out = jiffies + msecs_to_jiffies(INIT_WAIT_MS); while (!(priv->read_reg(priv, C_CAN_STS_REG) & STATUS_PDA) &&
time_after(time_out, jiffies))
cpu_relax();
if (time_after(jiffies, time_out)) return -ETIMEDOUT;
/* Clear PDR and INIT bits */
val = priv->read_reg(priv, C_CAN_CTRL_EX_REG);
val &= ~CONTROL_EX_PDR;
priv->write_reg(priv, C_CAN_CTRL_EX_REG, val);
val = priv->read_reg(priv, C_CAN_CTRL_REG);
val &= ~CONTROL_INIT;
priv->write_reg(priv, C_CAN_CTRL_REG, val);
/* Wait for the PDA bit to get clear */
time_out = jiffies + msecs_to_jiffies(INIT_WAIT_MS); while ((priv->read_reg(priv, C_CAN_STS_REG) & STATUS_PDA) &&
time_after(time_out, jiffies))
cpu_relax();
if (time_after(jiffies, time_out)) {
ret = -ETIMEDOUT; goto err_out;
}
int register_c_can_dev(struct net_device *dev)
{ /* Deactivate pins to prevent DRA7 DCAN IP from being *stuckintransitionwhenmoduleisdisabled. *Pinsareactivatedinc_can_start()anddeactivated *inc_can_stop()
*/
pinctrl_pm_select_sleep_state(dev->dev.parent);
dev->flags |= IFF_ECHO; /* we support local echo */
dev->netdev_ops = &c_can_netdev_ops;
dev->ethtool_ops = &c_can_ethtool_ops;
MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CAN bus driver for Bosch C_CAN controller");
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.26Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.