// SPDX-License-Identifier: GPL-2.0-or-later /* Xilinx CAN device driver * * Copyright (C) 2012 - 2022 Xilinx, Inc. * Copyright (C) 2009 PetaLogix. All rights reserved. * Copyright (C) 2017 - 2018 Sandvik Mining and Construction Oy * * Description: * This driver is developed for AXI CAN IP, AXI CANFD IP, CANPS and CANFD PS Controller.
*/
/* TX-FIFO-empty interrupt available */ #define XCAN_FLAG_TXFEMP 0x0001 /* RX Match Not Finished interrupt available */ #define XCAN_FLAG_RXMNF 0x0002 /* Extended acceptance filters with control at 0xE0 */ #define XCAN_FLAG_EXT_FILTERS 0x0004 /* TX mailboxes instead of TX FIFO */ #define XCAN_FLAG_TX_MAILBOXES 0x0008 /* RX FIFO with each buffer in separate registers at 0x1100 * instead of the regular FIFO at 0x50
*/ #define XCAN_FLAG_RX_FIFO_MULTI 0x0010 #define XCAN_FLAG_CANFD_2 0x0020
/** * xcan_write_reg_le - Write a value to the device register little endian * @priv: Driver private data structure * @reg: Register offset * @val: Value to write at the Register offset * * Write data to the paricular CAN register
*/ staticvoid xcan_write_reg_le(conststruct xcan_priv *priv, enum xcan_reg reg,
u32 val)
{
iowrite32(val, priv->reg_base + reg);
}
/** * xcan_read_reg_le - Read a value from the device register little endian * @priv: Driver private data structure * @reg: Register offset * * Read data from the particular CAN register * Return: value read from the CAN register
*/ static u32 xcan_read_reg_le(conststruct xcan_priv *priv, enum xcan_reg reg)
{ return ioread32(priv->reg_base + reg);
}
/** * xcan_write_reg_be - Write a value to the device register big endian * @priv: Driver private data structure * @reg: Register offset * @val: Value to write at the Register offset * * Write data to the paricular CAN register
*/ staticvoid xcan_write_reg_be(conststruct xcan_priv *priv, enum xcan_reg reg,
u32 val)
{
iowrite32be(val, priv->reg_base + reg);
}
/** * xcan_read_reg_be - Read a value from the device register big endian * @priv: Driver private data structure * @reg: Register offset * * Read data from the particular CAN register * Return: value read from the CAN register
*/ static u32 xcan_read_reg_be(conststruct xcan_priv *priv, enum xcan_reg reg)
{ return ioread32be(priv->reg_base + reg);
}
/** * xcan_rx_int_mask - Get the mask for the receive interrupt * @priv: Driver private data structure * * Return: The receive interrupt mask used by the driver on this HW
*/ static u32 xcan_rx_int_mask(conststruct xcan_priv *priv)
{ /* RXNEMP is better suited for our use case as it cannot be cleared * while the FIFO is non-empty, but CAN FD HW does not have it
*/ if (priv->devtype.flags & XCAN_FLAG_RX_FIFO_MULTI) return XCAN_IXR_RXOK_MASK; else return XCAN_IXR_RXNEMP_MASK;
}
/** * set_reset_mode - Resets the CAN device mode * @ndev: Pointer to net_device structure * * This is the driver reset mode routine.The driver * enters into configuration mode. * * Return: 0 on success and failure value on error
*/ staticint set_reset_mode(struct net_device *ndev)
{ struct xcan_priv *priv = netdev_priv(ndev); unsignedlong timeout;
/** * xcan_set_bittiming - CAN set bit timing routine * @ndev: Pointer to net_device structure * * This is the driver set bittiming routine. * Return: 0 on success and failure value on error
*/ staticint xcan_set_bittiming(struct net_device *ndev)
{ struct xcan_priv *priv = netdev_priv(ndev); struct can_bittiming *bt = &priv->can.bittiming; struct can_bittiming *dbt = &priv->can.fd.data_bittiming;
u32 btr0, btr1;
u32 is_config_mode;
/* Check whether Xilinx CAN is in configuration mode. * It cannot set bit timing if Xilinx CAN is not in configuration mode.
*/
is_config_mode = priv->read_reg(priv, XCAN_SR_OFFSET) &
XCAN_SR_CONFIG_MASK; if (!is_config_mode) {
netdev_alert(ndev, "BUG! Cannot set bittiming - CAN is not in config mode\n"); return -EPERM;
}
/* Setting Baud Rate prescaler value in BRPR Register */
btr0 = (bt->brp - 1);
/* Setting Time Segment 1 in BTR Register */
btr1 = (bt->prop_seg + bt->phase_seg1 - 1);
/* Setting Time Segment 2 in BTR Register */
btr1 |= (bt->phase_seg2 - 1) << priv->devtype.btr_ts2_shift;
/** * xcan_chip_start - This the drivers start routine * @ndev: Pointer to net_device structure * * This is the drivers start routine. * Based on the State of the CAN device it puts * the CAN device into a proper mode. * * Return: 0 on success and failure value on error
*/ staticint xcan_chip_start(struct net_device *ndev)
{ struct xcan_priv *priv = netdev_priv(ndev);
u32 reg_msr; int err;
u32 ier;
/* Check if it is in reset mode */
err = set_reset_mode(ndev); if (err < 0) return err;
err = xcan_set_bittiming(ndev); if (err < 0) return err;
/* Enable interrupts * * We enable the ERROR interrupt even with * CAN_CTRLMODE_BERR_REPORTING disabled as there is no * dedicated interrupt for a state change to * ERROR_WARNING/ERROR_PASSIVE.
*/
ier = XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |
XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK |
XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK |
XCAN_IXR_ARBLST_MASK | xcan_rx_int_mask(priv);
if (priv->ecc_enable)
ier |= XCAN_IXR_ECC_MASK;
if (priv->devtype.flags & XCAN_FLAG_RXMNF)
ier |= XCAN_IXR_RXMNF_MASK;
priv->write_reg(priv, XCAN_IER_OFFSET, ier);
/* Check whether it is loopback mode or normal mode */ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
reg_msr = XCAN_MSR_LBACK_MASK; else
reg_msr = 0x0;
/* enable the first extended filter, if any, as cores with extended * filtering default to non-receipt if all filters are disabled
*/ if (priv->devtype.flags & XCAN_FLAG_EXT_FILTERS)
priv->write_reg(priv, XCAN_AFR_EXT_OFFSET, 0x00000001);
/** * xcan_do_set_mode - This sets the mode of the driver * @ndev: Pointer to net_device structure * @mode: Tells the mode of the driver * * This check the drivers state and calls the corresponding modes to set. * * Return: 0 on success and failure value on error
*/ staticint xcan_do_set_mode(struct net_device *ndev, enum can_mode mode)
{ int ret;
switch (mode) { case CAN_MODE_START:
ret = xcan_chip_start(ndev); if (ret < 0) {
netdev_err(ndev, "xcan_chip_start failed!\n"); return ret;
}
netif_wake_queue(ndev); break; default:
ret = -EOPNOTSUPP; break;
}
return ret;
}
/** * xcan_write_frame - Write a frame to HW * @ndev: Pointer to net_device structure * @skb: sk_buff pointer that contains data to be Txed * @frame_offset: Register offset to write the frame to
*/ staticvoid xcan_write_frame(struct net_device *ndev, struct sk_buff *skb, int frame_offset)
{
u32 id, dlc, data[2] = {0, 0}; struct canfd_frame *cf = (struct canfd_frame *)skb->data;
u32 ramoff, dwindex = 0, i; struct xcan_priv *priv = netdev_priv(ndev);
/* Watch carefully on the bit sequence */ if (cf->can_id & CAN_EFF_FLAG) { /* Extended CAN ID format */
id = ((cf->can_id & CAN_EFF_MASK) << XCAN_IDR_ID2_SHIFT) &
XCAN_IDR_ID2_MASK;
id |= (((cf->can_id & CAN_EFF_MASK) >>
(CAN_EFF_ID_BITS - CAN_SFF_ID_BITS)) <<
XCAN_IDR_ID1_SHIFT) & XCAN_IDR_ID1_MASK;
/* The substibute remote TX request bit should be "1" * for extended frames as in the Xilinx CAN datasheet
*/
id |= XCAN_IDR_IDE_MASK | XCAN_IDR_SRR_MASK;
if (cf->can_id & CAN_RTR_FLAG) /* Extended frames remote TX request */
id |= XCAN_IDR_RTR_MASK;
} else { /* Standard CAN ID format */
id = ((cf->can_id & CAN_SFF_MASK) << XCAN_IDR_ID1_SHIFT) &
XCAN_IDR_ID1_MASK;
if (cf->can_id & CAN_RTR_FLAG) /* Standard frames remote TX request */
id |= XCAN_IDR_SRR_MASK;
}
dlc = can_fd_len2dlc(cf->len) << XCAN_DLCR_DLC_SHIFT; if (can_is_canfd_skb(skb)) { if (cf->flags & CANFD_BRS)
dlc |= XCAN_DLCR_BRS_MASK;
dlc |= XCAN_DLCR_EDL_MASK;
}
priv->write_reg(priv, XCAN_FRAME_ID_OFFSET(frame_offset), id); /* If the CAN frame is RTR frame this write triggers transmission * (not on CAN FD)
*/
priv->write_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_offset), dlc); if (priv->devtype.cantype == XAXI_CANFD ||
priv->devtype.cantype == XAXI_CANFD_2_0) { for (i = 0; i < cf->len; i += 4) {
ramoff = XCANFD_FRAME_DW_OFFSET(frame_offset) +
(dwindex * XCANFD_DW_BYTES);
priv->write_reg(priv, ramoff,
be32_to_cpup((__be32 *)(cf->data + i)));
dwindex++;
}
} else { if (cf->len > 0)
data[0] = be32_to_cpup((__be32 *)(cf->data + 0)); if (cf->len > 4)
data[1] = be32_to_cpup((__be32 *)(cf->data + 4));
if (!(cf->can_id & CAN_RTR_FLAG)) {
priv->write_reg(priv,
XCAN_FRAME_DW1_OFFSET(frame_offset),
data[0]); /* If the CAN frame is Standard/Extended frame this * write triggers transmission (not on CAN FD)
*/
priv->write_reg(priv,
XCAN_FRAME_DW2_OFFSET(frame_offset),
data[1]);
}
}
/** * xcan_start_xmit_fifo - Starts the transmission (FIFO mode) * @skb: sk_buff pointer that contains data to be Txed * @ndev: Pointer to net_device structure * * Return: 0 on success, -ENOSPC if FIFO is full.
*/ staticint xcan_start_xmit_fifo(struct sk_buff *skb, struct net_device *ndev)
{ struct xcan_priv *priv = netdev_priv(ndev); unsignedlong flags;
/* Check if the TX buffer is full */ if (unlikely(priv->read_reg(priv, XCAN_SR_OFFSET) &
XCAN_SR_TXFLL_MASK)) return -ENOSPC;
spin_lock_irqsave(&priv->tx_lock, flags);
xcan_write_frame(ndev, skb, XCAN_TXFIFO_OFFSET);
/* Clear TX-FIFO-empty interrupt for xcan_tx_interrupt() */ if (priv->tx_max > 1)
priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXFEMP_MASK);
/* Check if the TX buffer is full */ if ((priv->tx_head - priv->tx_tail) == priv->tx_max)
netif_stop_queue(ndev);
spin_unlock_irqrestore(&priv->tx_lock, flags);
return 0;
}
/** * xcan_start_xmit_mailbox - Starts the transmission (mailbox mode) * @skb: sk_buff pointer that contains data to be Txed * @ndev: Pointer to net_device structure * * Return: 0 on success, -ENOSPC if there is no space
*/ staticint xcan_start_xmit_mailbox(struct sk_buff *skb, struct net_device *ndev)
{ struct xcan_priv *priv = netdev_priv(ndev); unsignedlong flags;
if (unlikely(priv->read_reg(priv, XCAN_TRR_OFFSET) &
BIT(XCAN_TX_MAILBOX_IDX))) return -ENOSPC;
/* Mark buffer as ready for transmit */
priv->write_reg(priv, XCAN_TRR_OFFSET, BIT(XCAN_TX_MAILBOX_IDX));
netif_stop_queue(ndev);
spin_unlock_irqrestore(&priv->tx_lock, flags);
return 0;
}
/** * xcan_start_xmit - Starts the transmission * @skb: sk_buff pointer that contains data to be Txed * @ndev: Pointer to net_device structure * * This function is invoked from upper layers to initiate transmission. * * Return: NETDEV_TX_OK on success and NETDEV_TX_BUSY when the tx queue is full
*/ static netdev_tx_t xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{ struct xcan_priv *priv = netdev_priv(ndev); int ret;
if (can_dev_dropped_skb(ndev, skb)) return NETDEV_TX_OK;
if (priv->devtype.flags & XCAN_FLAG_TX_MAILBOXES)
ret = xcan_start_xmit_mailbox(skb, ndev); else
ret = xcan_start_xmit_fifo(skb, ndev);
if (ret < 0) {
netdev_err(ndev, "BUG!, TX full when queue awake!\n");
netif_stop_queue(ndev); return NETDEV_TX_BUSY;
}
return NETDEV_TX_OK;
}
/** * xcan_rx - Is called from CAN isr to complete the received * frame processing * @ndev: Pointer to net_device structure * @frame_base: Register offset to the frame to be read * * This function is invoked from the CAN isr(poll) to process the Rx frames. It * does minimal processing and invokes "netif_receive_skb" to complete further * processing. * Return: 1 on success and 0 on failure.
*/ staticint xcan_rx(struct net_device *ndev, int frame_base)
{ struct xcan_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; struct can_frame *cf; struct sk_buff *skb;
u32 id_xcan, dlc, data[2] = {0, 0};
/* Read a frame from Xilinx zynq CANPS */
id_xcan = priv->read_reg(priv, XCAN_FRAME_ID_OFFSET(frame_base));
dlc = priv->read_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_base)) >>
XCAN_DLCR_DLC_SHIFT;
/* Change Xilinx CAN data length format to socketCAN data format */
cf->len = can_cc_dlc2len(dlc);
/* Change Xilinx CAN ID format to socketCAN ID format */ if (id_xcan & XCAN_IDR_IDE_MASK) { /* The received frame is an Extended format frame */
cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 3;
cf->can_id |= (id_xcan & XCAN_IDR_ID2_MASK) >>
XCAN_IDR_ID2_SHIFT;
cf->can_id |= CAN_EFF_FLAG; if (id_xcan & XCAN_IDR_RTR_MASK)
cf->can_id |= CAN_RTR_FLAG;
} else { /* The received frame is a standard format frame */
cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >>
XCAN_IDR_ID1_SHIFT; if (id_xcan & XCAN_IDR_SRR_MASK)
cf->can_id |= CAN_RTR_FLAG;
}
/* DW1/DW2 must always be read to remove message from RXFIFO */
data[0] = priv->read_reg(priv, XCAN_FRAME_DW1_OFFSET(frame_base));
data[1] = priv->read_reg(priv, XCAN_FRAME_DW2_OFFSET(frame_base));
if (!(cf->can_id & CAN_RTR_FLAG)) { /* Change Xilinx CAN data format to socketCAN data format */ if (cf->len > 0)
*(__be32 *)(cf->data) = cpu_to_be32(data[0]); if (cf->len > 4)
*(__be32 *)(cf->data + 4) = cpu_to_be32(data[1]);
/** * xcanfd_rx - Is called from CAN isr to complete the received * frame processing * @ndev: Pointer to net_device structure * @frame_base: Register offset to the frame to be read * * This function is invoked from the CAN isr(poll) to process the Rx frames. It * does minimal processing and invokes "netif_receive_skb" to complete further * processing. * Return: 1 on success and 0 on failure.
*/ staticint xcanfd_rx(struct net_device *ndev, int frame_base)
{ struct xcan_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; struct canfd_frame *cf; struct sk_buff *skb;
u32 id_xcan, dlc, data[2] = {0, 0}, dwindex = 0, i, dw_offset;
if (unlikely(!skb)) {
stats->rx_dropped++; return 0;
}
/* Change Xilinx CANFD data length format to socketCAN data * format
*/ if (dlc & XCAN_DLCR_EDL_MASK)
cf->len = can_fd_dlc2len((dlc & XCAN_DLCR_DLC_MASK) >>
XCAN_DLCR_DLC_SHIFT); else
cf->len = can_cc_dlc2len((dlc & XCAN_DLCR_DLC_MASK) >>
XCAN_DLCR_DLC_SHIFT);
/* Change Xilinx CAN ID format to socketCAN ID format */ if (id_xcan & XCAN_IDR_IDE_MASK) { /* The received frame is an Extended format frame */
cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 3;
cf->can_id |= (id_xcan & XCAN_IDR_ID2_MASK) >>
XCAN_IDR_ID2_SHIFT;
cf->can_id |= CAN_EFF_FLAG; if (id_xcan & XCAN_IDR_RTR_MASK)
cf->can_id |= CAN_RTR_FLAG;
} else { /* The received frame is a standard format frame */
cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >>
XCAN_IDR_ID1_SHIFT; if (!(dlc & XCAN_DLCR_EDL_MASK) && (id_xcan &
XCAN_IDR_SRR_MASK))
cf->can_id |= CAN_RTR_FLAG;
}
/* Check the frame received is FD or not*/ if (dlc & XCAN_DLCR_EDL_MASK) { for (i = 0; i < cf->len; i += 4) {
dw_offset = XCANFD_FRAME_DW_OFFSET(frame_base) +
(dwindex * XCANFD_DW_BYTES);
data[0] = priv->read_reg(priv, dw_offset);
*(__be32 *)(cf->data + i) = cpu_to_be32(data[0]);
dwindex++;
}
} else { for (i = 0; i < cf->len; i += 4) {
dw_offset = XCANFD_FRAME_DW_OFFSET(frame_base);
data[0] = priv->read_reg(priv, dw_offset + i);
*(__be32 *)(cf->data + i) = cpu_to_be32(data[0]);
}
}
if (!(cf->can_id & CAN_RTR_FLAG))
stats->rx_bytes += cf->len;
stats->rx_packets++;
netif_receive_skb(skb);
return 1;
}
/** * xcan_current_error_state - Get current error state from HW * @ndev: Pointer to net_device structure * * Checks the current CAN error state from the HW. Note that this * only checks for ERROR_PASSIVE and ERROR_WARNING. * * Return: * ERROR_PASSIVE or ERROR_WARNING if either is active, ERROR_ACTIVE * otherwise.
*/ staticenum can_state xcan_current_error_state(struct net_device *ndev)
{ struct xcan_priv *priv = netdev_priv(ndev);
u32 status = priv->read_reg(priv, XCAN_SR_OFFSET);
/** * xcan_set_error_state - Set new CAN error state * @ndev: Pointer to net_device structure * @new_state: The new CAN state to be set * @cf: Error frame to be populated or NULL * * Set new CAN error state for the device, updating statistics and * populating the error frame if given.
*/ staticvoid xcan_set_error_state(struct net_device *ndev, enum can_state new_state, struct can_frame *cf)
{ struct xcan_priv *priv = netdev_priv(ndev);
u32 ecr = priv->read_reg(priv, XCAN_ECR_OFFSET);
u32 txerr = ecr & XCAN_ECR_TEC_MASK;
u32 rxerr = (ecr & XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT; enum can_state tx_state = txerr >= rxerr ? new_state : 0; enum can_state rx_state = txerr <= rxerr ? new_state : 0;
/* non-ERROR states are handled elsewhere */ if (WARN_ON(new_state > CAN_STATE_ERROR_PASSIVE)) return;
/** * xcan_update_error_state_after_rxtx - Update CAN error state after RX/TX * @ndev: Pointer to net_device structure * * If the device is in a ERROR-WARNING or ERROR-PASSIVE state, check if * the performed RX/TX has caused it to drop to a lesser state and set * the interface state accordingly.
*/ staticvoid xcan_update_error_state_after_rxtx(struct net_device *ndev)
{ struct xcan_priv *priv = netdev_priv(ndev); enum can_state old_state = priv->can.state; enum can_state new_state;
/* changing error state due to successful frame RX/TX can only * occur from these states
*/ if (old_state != CAN_STATE_ERROR_WARNING &&
old_state != CAN_STATE_ERROR_PASSIVE) return;
/** * xcan_err_interrupt - error frame Isr * @ndev: net_device pointer * @isr: interrupt status register value * * This is the CAN error interrupt and it will * check the type of error and forward the error * frame to upper layers.
*/ staticvoid xcan_err_interrupt(struct net_device *ndev, u32 isr)
{ struct xcan_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; struct can_frame cf = { };
u32 err_status;
/* Check for RX Match Not Finished interrupt */ if (isr & XCAN_IXR_RXMNF_MASK) {
stats->rx_dropped++;
stats->rx_errors++;
netdev_err(ndev, "RX match not finished, frame discarded\n");
cf.can_id |= CAN_ERR_CRTL;
cf.data[1] |= CAN_ERR_CRTL_UNSPEC;
}
/* Check for error interrupt */ if (isr & XCAN_IXR_ERROR_MASK) { bool berr_reporting = false;
/* The counter reaches its maximum at 0xffff and does not overflow. * Accept the small race window between reading and resetting ECC counters.
*/
priv->write_reg(priv, XCAN_ECC_CFG_OFFSET, XCAN_ECC_CFG_REECRX_MASK |
XCAN_ECC_CFG_REECTXOL_MASK | XCAN_ECC_CFG_REECTXTL_MASK);
u64_stats_update_begin(&priv->syncp);
if (isr & XCAN_IXR_E2BERX_MASK) {
u64_stats_add(&priv->ecc_rx_2_bit_errors,
FIELD_GET(XCAN_ECC_2BIT_CNT_MASK, reg_rx_ecc));
}
if (isr & XCAN_IXR_E1BERX_MASK) {
u64_stats_add(&priv->ecc_rx_1_bit_errors,
FIELD_GET(XCAN_ECC_1BIT_CNT_MASK, reg_rx_ecc));
}
if (isr & XCAN_IXR_E2BETXOL_MASK) {
u64_stats_add(&priv->ecc_txol_2_bit_errors,
FIELD_GET(XCAN_ECC_2BIT_CNT_MASK, reg_txol_ecc));
}
if (isr & XCAN_IXR_E1BETXOL_MASK) {
u64_stats_add(&priv->ecc_txol_1_bit_errors,
FIELD_GET(XCAN_ECC_1BIT_CNT_MASK, reg_txol_ecc));
}
if (isr & XCAN_IXR_E2BETXTL_MASK) {
u64_stats_add(&priv->ecc_txtl_2_bit_errors,
FIELD_GET(XCAN_ECC_2BIT_CNT_MASK, reg_txtl_ecc));
}
if (isr & XCAN_IXR_E1BETXTL_MASK) {
u64_stats_add(&priv->ecc_txtl_1_bit_errors,
FIELD_GET(XCAN_ECC_1BIT_CNT_MASK, reg_txtl_ecc));
}
netdev_dbg(ndev, "%s: error status register:0x%x\n",
__func__, priv->read_reg(priv, XCAN_ESR_OFFSET));
}
/** * xcan_state_interrupt - It will check the state of the CAN device * @ndev: net_device pointer * @isr: interrupt status register value * * This will checks the state of the CAN device * and puts the device into appropriate state.
*/ staticvoid xcan_state_interrupt(struct net_device *ndev, u32 isr)
{ struct xcan_priv *priv = netdev_priv(ndev);
/* Check for Sleep interrupt if set put CAN device in sleep state */ if (isr & XCAN_IXR_SLP_MASK)
priv->can.state = CAN_STATE_SLEEPING;
/* Check for Wake up interrupt if set put CAN device in Active state */ if (isr & XCAN_IXR_WKUP_MASK)
priv->can.state = CAN_STATE_ERROR_ACTIVE;
}
/** * xcan_rx_fifo_get_next_frame - Get register offset of next RX frame * @priv: Driver private data structure * * Return: Register offset of the next frame in RX FIFO.
*/ staticint xcan_rx_fifo_get_next_frame(struct xcan_priv *priv)
{ int offset;
if (priv->devtype.flags & XCAN_FLAG_RX_FIFO_MULTI) {
u32 fsr, mask;
/* clear RXOK before the is-empty check so that any newly * received frame will reassert it without a race
*/
priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXOK_MASK);
fsr = priv->read_reg(priv, XCAN_FSR_OFFSET);
/* check if RX FIFO is empty */ if (priv->devtype.flags & XCAN_FLAG_CANFD_2)
mask = XCAN_2_FSR_FL_MASK; else
mask = XCAN_FSR_FL_MASK;
} else { /* check if RX FIFO is empty */ if (!(priv->read_reg(priv, XCAN_ISR_OFFSET) &
XCAN_IXR_RXNEMP_MASK)) return -ENOENT;
/* frames are read from a static offset */
offset = XCAN_RXFIFO_OFFSET;
}
return offset;
}
/** * xcan_rx_poll - Poll routine for rx packets (NAPI) * @napi: napi structure pointer * @quota: Max number of rx packets to be processed. * * This is the poll routine for rx part. * It will process the packets maximux quota value. * * Return: number of packets received
*/ staticint xcan_rx_poll(struct napi_struct *napi, int quota)
{ struct net_device *ndev = napi->dev; struct xcan_priv *priv = netdev_priv(ndev);
u32 ier; int work_done = 0; int frame_offset;
/** * xcan_tx_interrupt - Tx Done Isr * @ndev: net_device pointer * @isr: Interrupt status register value
*/ staticvoid xcan_tx_interrupt(struct net_device *ndev, u32 isr)
{ struct xcan_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; unsignedint frames_in_fifo; int frames_sent = 1; /* TXOK => at least 1 frame was sent */ unsignedlong flags; int retries = 0;
/* Synchronize with xmit as we need to know the exact number * of frames in the FIFO to stay in sync due to the TXFEMP * handling. * This also prevents a race between netif_wake_queue() and * netif_stop_queue().
*/
spin_lock_irqsave(&priv->tx_lock, flags);
frames_in_fifo = priv->tx_head - priv->tx_tail;
if (WARN_ON_ONCE(frames_in_fifo == 0)) { /* clear TXOK anyway to avoid getting back here */
priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK);
spin_unlock_irqrestore(&priv->tx_lock, flags); return;
}
/* Check if 2 frames were sent (TXOK only means that at least 1 * frame was sent).
*/ if (frames_in_fifo > 1) {
WARN_ON(frames_in_fifo > priv->tx_max);
/* Synchronize TXOK and isr so that after the loop: * (1) isr variable is up-to-date at least up to TXOK clear * time. This avoids us clearing a TXOK of a second frame * but not noticing that the FIFO is now empty and thus * marking only a single frame as sent. * (2) No TXOK is left. Having one could mean leaving a * stray TXOK as we might process the associated frame * via TXFEMP handling as we read TXFEMP *after* TXOK * clear to satisfy (1).
*/ while ((isr & XCAN_IXR_TXOK_MASK) &&
!WARN_ON(++retries == 100)) {
priv->write_reg(priv, XCAN_ICR_OFFSET,
XCAN_IXR_TXOK_MASK);
isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
}
if (isr & XCAN_IXR_TXFEMP_MASK) { /* nothing in FIFO anymore */
frames_sent = frames_in_fifo;
}
} else { /* single frame in fifo, just clear TXOK */
priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK);
}
/** * xcan_interrupt - CAN Isr * @irq: irq number * @dev_id: device id pointer * * This is the xilinx CAN Isr. It checks for the type of interrupt * and invokes the corresponding ISR. * * Return: * IRQ_NONE - If CAN device is in sleep mode, IRQ_HANDLED otherwise
*/ static irqreturn_t xcan_interrupt(int irq, void *dev_id)
{ struct net_device *ndev = (struct net_device *)dev_id; struct xcan_priv *priv = netdev_priv(ndev);
u32 isr_errors, mask;
u32 isr, ier;
u32 rx_int_mask = xcan_rx_int_mask(priv);
/* Get the interrupt status from Xilinx CAN */
isr = priv->read_reg(priv, XCAN_ISR_OFFSET); if (!isr) return IRQ_NONE;
/* Check for the type of interrupt and Processing it */ if (isr & (XCAN_IXR_SLP_MASK | XCAN_IXR_WKUP_MASK)) {
priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_SLP_MASK |
XCAN_IXR_WKUP_MASK));
xcan_state_interrupt(ndev, isr);
}
/* Check for Tx interrupt and Processing it */ if (isr & XCAN_IXR_TXOK_MASK)
xcan_tx_interrupt(ndev, isr);
/* Check for the type of error interrupt and Processing it */
isr_errors = isr & mask; if (isr_errors) {
priv->write_reg(priv, XCAN_ICR_OFFSET, isr_errors);
xcan_err_interrupt(ndev, isr);
}
/* Check for the type of receive interrupt and Processing it */ if (isr & rx_int_mask) {
ier = priv->read_reg(priv, XCAN_IER_OFFSET);
ier &= ~rx_int_mask;
priv->write_reg(priv, XCAN_IER_OFFSET, ier);
napi_schedule(&priv->napi);
} return IRQ_HANDLED;
}
/** * xcan_chip_stop - Driver stop routine * @ndev: Pointer to net_device structure * * This is the drivers stop routine. It will disable the * interrupts and put the device into configuration mode.
*/ staticvoid xcan_chip_stop(struct net_device *ndev)
{ struct xcan_priv *priv = netdev_priv(ndev); int ret;
/* Disable interrupts and leave the can in configuration mode */
ret = set_reset_mode(ndev); if (ret < 0)
netdev_dbg(ndev, "set_reset_mode() Failed\n");
priv->can.state = CAN_STATE_STOPPED;
}
/** * xcan_open - Driver open routine * @ndev: Pointer to net_device structure * * This is the driver open routine. * Return: 0 on success and failure value on error
*/ staticint xcan_open(struct net_device *ndev)
{ struct xcan_priv *priv = netdev_priv(ndev); int ret;
ret = phy_power_on(priv->transceiver); if (ret) return ret;
ret = pm_runtime_get_sync(priv->dev); if (ret < 0) {
netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n",
__func__, ret); goto err;
}
ret = request_irq(ndev->irq, xcan_interrupt, priv->irq_flags,
ndev->name, ndev); if (ret < 0) {
netdev_err(ndev, "irq allocation for CAN failed\n"); goto err;
}
/* Set chip into reset mode */
ret = set_reset_mode(ndev); if (ret < 0) {
netdev_err(ndev, "mode resetting failed!\n"); goto err_irq;
}
/* Common open */
ret = open_candev(ndev); if (ret) goto err_irq;
ret = xcan_chip_start(ndev); if (ret < 0) {
netdev_err(ndev, "xcan_chip_start failed!\n"); goto err_candev;
}
/** * xcan_suspend - Suspend method for the driver * @dev: Address of the device structure * * Put the driver into low power mode. * Return: 0 on success and failure value on error
*/ staticint __maybe_unused xcan_suspend(struct device *dev)
{ struct net_device *ndev = dev_get_drvdata(dev);
if (netif_running(ndev)) {
netif_stop_queue(ndev);
netif_device_detach(ndev);
xcan_chip_stop(ndev);
}
return pm_runtime_force_suspend(dev);
}
/** * xcan_resume - Resume from suspend * @dev: Address of the device structure * * Resume operation after suspend. * Return: 0 on success and failure value on error
*/ staticint __maybe_unused xcan_resume(struct device *dev)
{ struct net_device *ndev = dev_get_drvdata(dev); int ret;
ret = pm_runtime_force_resume(dev); if (ret) {
dev_err(dev, "pm_runtime_force_resume failed on resume\n"); return ret;
}
if (netif_running(ndev)) {
ret = xcan_chip_start(ndev); if (ret) {
dev_err(dev, "xcan_chip_start failed on resume\n"); return ret;
}
/* Match table for OF platform binding */ staticconststruct of_device_id xcan_of_match[] = {
{ .compatible = "xlnx,zynq-can-1.0", .data = &xcan_zynq_data },
{ .compatible = "xlnx,axi-can-1.00.a", .data = &xcan_axi_data },
{ .compatible = "xlnx,canfd-1.0", .data = &xcan_canfd_data },
{ .compatible = "xlnx,canfd-2.0", .data = &xcan_canfd2_data },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, xcan_of_match);
/** * xcan_probe - Platform registration call * @pdev: Handle to the platform device structure * * This function does all the memory allocation and registration for the CAN * device. * * Return: 0 on success and failure value on error
*/ staticint xcan_probe(struct platform_device *pdev)
{ struct net_device *ndev; struct xcan_priv *priv; struct phy *transceiver; conststruct xcan_devtype_data *devtype; void __iomem *addr; int ret; int rx_max, tx_max;
u32 hw_tx_max = 0, hw_rx_max = 0; constchar *hw_tx_max_property;
/* Get the virtual base address for the device */
addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(addr)) {
ret = PTR_ERR(addr); goto err;
}
ret = of_property_read_u32(pdev->dev.of_node, hw_tx_max_property,
&hw_tx_max); if (ret < 0) {
dev_err(&pdev->dev, "missing %s property\n",
hw_tx_max_property); goto err;
}
ret = of_property_read_u32(pdev->dev.of_node, "rx-fifo-depth",
&hw_rx_max); if (ret < 0) {
dev_err(&pdev->dev, "missing rx-fifo-depth property (mailbox mode is not supported)\n"); goto err;
}
/* With TX FIFO: * * There is no way to directly figure out how many frames have been * sent when the TXOK interrupt is processed. If TXFEMP * is supported, we can have 2 frames in the FIFO and use TXFEMP * to determine if 1 or 2 frames have been sent. * Theoretically we should be able to use TXFWMEMP to determine up * to 3 frames, but it seems that after putting a second frame in the * FIFO, with watermark at 2 frames, it can happen that TXFWMEMP (less * than 2 frames in FIFO) is set anyway with no TXOK (a frame was * sent), which is not a sensible state - possibly TXFWMEMP is not * completely synchronized with the rest of the bits? * * With TX mailboxes: * * HW sends frames in CAN ID priority order. To preserve FIFO ordering * we submit frames one at a time.
*/ if (!(devtype->flags & XCAN_FLAG_TX_MAILBOXES) &&
(devtype->flags & XCAN_FLAG_TXFEMP))
tx_max = min(hw_tx_max, 2U); else
tx_max = 1;
rx_max = hw_rx_max;
/* Create a CAN device instance */
ndev = alloc_candev(sizeof(struct xcan_priv), tx_max); if (!ndev) return -ENOMEM;
/* Getting the CAN can_clk info */
priv->can_clk = devm_clk_get(&pdev->dev, "can_clk"); if (IS_ERR(priv->can_clk)) {
ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->can_clk), "device clock not found\n"); goto err_reset;
}
priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name); if (IS_ERR(priv->bus_clk)) {
ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->bus_clk), "bus clock not found\n"); goto err_reset;
}
transceiver = devm_phy_optional_get(&pdev->dev, NULL); if (IS_ERR(transceiver)) {
ret = PTR_ERR(transceiver);
dev_err_probe(&pdev->dev, ret, "failed to get phy\n"); goto err_reset;
}
priv->transceiver = transceiver;
/** * xcan_remove - Unregister the device after releasing the resources * @pdev: Handle to the platform device structure * * This function frees all the resources allocated to the device. * Return: 0 always
*/ staticvoid xcan_remove(struct platform_device *pdev)
{ struct net_device *ndev = platform_get_drvdata(pdev); struct xcan_priv *priv = netdev_priv(ndev);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Xilinx Inc");
MODULE_DESCRIPTION("Xilinx CAN interface");
Messung V0.5
¤ 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.0.83Bemerkung:
¤
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.