...
 
Commits (7)
......@@ -90,7 +90,7 @@ struct ctucan_priv {
struct list_head peers_on_pdev;
};
#define CTUCAN_FLAG_RX_SCHED 1
// #define CTUCAN_FLAG_RX_SCHED 1
#define CTUCAN_FLAG_RX_FFW_BUFFERED 2
static int ctucan_reset(struct net_device *ndev)
......@@ -223,10 +223,11 @@ static int ctucan_chip_start(struct net_device *ndev)
int_msk.u32 = ~int_ena.u32; /* mask all disabled interrupts */
clear_bit(CTUCAN_FLAG_RX_SCHED, &priv->drv_flags);
// clear_bit(CTUCAN_FLAG_RX_SCHED, &priv->drv_flags);
ctu_can_fd_int_mask(&priv->p, int_msk, int_enamask_mask);
ctu_can_fd_int_ena(&priv->p, int_ena, int_enamask_mask);
/* It's after reset, so there is no need to clear anything */
ctu_can_fd_int_mask_set(&priv->p, int_msk);
ctu_can_fd_int_ena_set(&priv->p, int_ena);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
......@@ -384,11 +385,16 @@ static void ctucan_err_interrupt(struct net_device *ndev,
struct can_frame *cf;
struct sk_buff *skb;
struct can_berr_counter berr;
union ctu_can_fd_err_capt_alc err_capt_alc;
ctu_can_fd_read_err_ctrs(&priv->p, &berr);
netdev_info(ndev, "%s: ISR = 0x%08x, rxerr %d, txerr %d",
__func__, isr.u32, berr.rxerr, berr.txerr);
err_capt_alc = ctu_can_fd_read_err_capt_alc(&priv->p);
netdev_info(ndev, "%s: ISR = 0x%08x, rxerr %d, txerr %d, error type %u, pos %u, ALC id_field %u, bit %u\n",
__func__, isr.u32, berr.rxerr, berr.txerr,
err_capt_alc.s.err_type, err_capt_alc.s.err_pos,
err_capt_alc.s.alc_id_field, err_capt_alc.s.alc_bit);
skb = alloc_can_err_skb(ndev, &cf);
......@@ -488,16 +494,13 @@ static int ctucan_rx_poll(struct napi_struct *napi, int quota)
int work_done = 0;
union ctu_can_fd_status status;
u32 framecnt;
u32 i;
//netdev_dbg(ndev, "ctucan_rx_poll");
framecnt = ctu_can_fd_get_rx_frame_count(&priv->p);
netdev_dbg(ndev, "rx_poll: %d frames in RX FIFO", framecnt);
while (framecnt && work_done < quota) {
netdev_dbg(ndev, "rx_poll: %d frames in RX FIFO", framecnt);
for (i = 0; i < framecnt; ++i) {
ctucan_rx(ndev);
work_done++;
}
ctucan_rx(ndev);
work_done++;
framecnt = ctu_can_fd_get_rx_frame_count(&priv->p);
}
......@@ -527,7 +530,7 @@ static int ctucan_rx_poll(struct napi_struct *napi, int quota)
if (work_done)
can_led_event(ndev, CAN_LED_EVENT_RX);
if (work_done < quota) {
if (!framecnt) {
if (napi_complete_done(napi, work_done)) {
union ctu_can_fd_int_stat iec;
/* Clear and enable RBNEI. It is level-triggered, so
......@@ -535,9 +538,9 @@ static int ctucan_rx_poll(struct napi_struct *napi, int quota)
*/
iec.u32 = 0;
iec.s.rbnei = 1;
clear_bit(CTUCAN_FLAG_RX_SCHED, &priv->drv_flags);
// clear_bit(CTUCAN_FLAG_RX_SCHED, &priv->drv_flags);
ctu_can_fd_int_clr(&priv->p, iec);
ctu_can_fd_int_ena_set(&priv->p, iec);
ctu_can_fd_int_mask_clr(&priv->p, iec);
}
}
......@@ -627,13 +630,11 @@ static void ctucan_tx_interrupt(struct net_device *ndev)
/* do not clear nor wake */
return;
}
/* some_buffers_processed is still false */
goto clear;
}
priv->txb_tail++;
first = false;
some_buffers_processed = true;
/* Adjust priorities *before* marking the buffer
* as empty.
*/
......@@ -641,11 +642,16 @@ static void ctucan_tx_interrupt(struct net_device *ndev)
ctu_can_fd_txt_set_empty(&priv->p, txb_idx);
}
clear:
/* Clear the interrupt again as not to receive it again for
* a buffer we already handled (possibly causing the bug log)
*/
ctu_can_fd_int_clr(&priv->p, icr);
/* If no buffers were processed this time, wa cannot
* clear - that would introduce a race condition. */
if (some_buffers_processed) {
/* Clear the interrupt again as not to receive it again
* for a buffer we already handled (possibly causing
* the bug log) */
ctu_can_fd_int_clr(&priv->p, icr);
}
} while (some_buffers_processed);
can_led_event(ndev, CAN_LED_EVENT_TX);
netif_wake_queue(ndev);
}
......@@ -674,8 +680,8 @@ static irqreturn_t ctucan_interrupt(int irq, void *dev_id)
/* Get the interrupt status */
isr = ctu_can_fd_int_sts(&priv->p);
if (test_bit(CTUCAN_FLAG_RX_SCHED, &priv->drv_flags))
isr.s.rbnei = 0;
//if (test_bit(CTUCAN_FLAG_RX_SCHED, &priv->drv_flags))
// isr.s.rbnei = 0;
if (!isr.u32)
return irq_loops ? IRQ_HANDLED : IRQ_NONE;
......@@ -685,19 +691,20 @@ static irqreturn_t ctucan_interrupt(int irq, void *dev_id)
netdev_dbg(ndev, "RXBNEI");
icr.u32 = 0;
icr.s.rbnei = 1;
/* Clear and disable RXBNEI, schedule NAPI */
/* Mask RXBNEI the first then clear interrupt,
* then schedule NAPI. Even if another IRQ fires,
* isr.s.rbnei will always be 0 (masked).
*/
ctu_can_fd_int_mask_set(&priv->p, icr);
ctu_can_fd_int_clr(&priv->p, icr);
ctu_can_fd_int_ena_clr(&priv->p, icr);
set_bit(CTUCAN_FLAG_RX_SCHED, &priv->drv_flags);
// set_bit(CTUCAN_FLAG_RX_SCHED, &priv->drv_flags);
napi_schedule(&priv->napi);
}
/* TX Buffer HW Command Interrupt */
if (isr.s.txbhci) {
netdev_dbg(ndev, "TXBHCI");
icr.u32 = 0;
icr.s.txbhci = 1;
ctu_can_fd_int_clr(&priv->p, icr);
/* Cleared inside */
ctucan_tx_interrupt(ndev);
}
......@@ -722,8 +729,8 @@ static irqreturn_t ctucan_interrupt(int irq, void *dev_id)
imask.u32 = 0xffffffff;
ival.u32 = 0;
ctu_can_fd_int_ena(&priv->p, imask, ival);
ctu_can_fd_int_mask(&priv->p, imask, ival);
ctu_can_fd_int_ena_clr(&priv->p, ival);
ctu_can_fd_int_mask_set(&priv->p, imask);
}
return IRQ_HANDLED;
......@@ -739,16 +746,16 @@ static irqreturn_t ctucan_interrupt(int irq, void *dev_id)
static void ctucan_chip_stop(struct net_device *ndev)
{
struct ctucan_priv *priv = netdev_priv(ndev);
union ctu_can_fd_int_stat ena, mask;
union ctu_can_fd_int_stat mask;
netdev_dbg(ndev, "ctucan_chip_stop");
ena.u32 = 0;
mask.u32 = 0xffffffff;
/* Disable interrupts and disable can */
ctu_can_fd_int_ena(&priv->p, ena, mask);
ctu_can_fd_int_mask_set(&priv->p, mask);
ctu_can_fd_enable(&priv->p, false);
clear_bit(CTUCAN_FLAG_RX_SCHED, &priv->drv_flags);
// clear_bit(CTUCAN_FLAG_RX_SCHED, &priv->drv_flags);
priv->can.state = CAN_STATE_STOPPED;
}
......
......@@ -370,6 +370,32 @@ void ctu_can_fd_int_ena(struct ctucanfd_priv *priv,
union ctu_can_fd_int_stat mask,
union ctu_can_fd_int_stat val);
/*
* Mask interrupts of CTU CAN FD Core.
*
* Arguments:
* priv Private info
* mask Mask of interrupts which should be masked.
*/
static inline void ctu_can_fd_int_mask_set(struct ctucanfd_priv *priv,
union ctu_can_fd_int_stat mask)
{
priv->write_reg(priv, CTU_CAN_FD_INT_MASK_SET, mask.u32);
}
/*
* Unmask interrupts of CTU CAN FD Core.
*
* Arguments:
* priv Private info
* mask Mask of interrupts which should be unmasked.
*/
static inline void ctu_can_fd_int_mask_clr(struct ctucanfd_priv *priv,
union ctu_can_fd_int_stat mask)
{
priv->write_reg(priv, CTU_CAN_FD_INT_MASK_CLR, mask.u32);
}
/*
* Mask/Unmask interrupts of CTU CAN FD Core.
*
......@@ -540,6 +566,22 @@ enum can_state ctu_can_fd_read_error_state(struct ctucanfd_priv *priv);
void ctu_can_fd_set_err_ctrs(struct ctucanfd_priv *priv,
const struct can_berr_counter *ctr);
/*
* Read core captured last error or arbitration lost reason.
*
* Arguments:
* priv Private info
* Returns:
* Error state of the CTU CAN FD.
*/
static inline union ctu_can_fd_err_capt_alc
ctu_can_fd_read_err_capt_alc(struct ctucanfd_priv *priv)
{
union ctu_can_fd_err_capt_alc res;
res.u32 = priv->read_reg(priv, CTU_CAN_FD_ERR_CAPT);
return res;
}
/*
* Check Mask filters support of given filter.
*
......
......@@ -191,7 +191,6 @@ timespec_sub (struct timespec *diff, const struct timespec *left,
}
}
int main(int argc, char *argv[])
{
uintptr_t addr_base = 0;
......@@ -201,6 +200,7 @@ int main(int argc, char *argv[])
int gap = 1000;
int bitrate = 1000000;
int dbitrate = 0;
int tx_can_id = 0x1ff;
bool do_periodic_transmit = false;
bool transmit_fdf = false;
bool loopback_mode = false;
......@@ -211,7 +211,7 @@ int main(int argc, char *argv[])
int c;
char *e;
const char *progname = argv[0];
while ((c = getopt(argc, argv, "i:a:g:b:B:fltThpr")) != -1) {
while ((c = getopt(argc, argv, "i:a:g:b:B:I:fltThpr")) != -1) {
switch (c) {
case 'i':
ifc = strtoul(optarg, &e, 0);
......@@ -243,6 +243,12 @@ int main(int argc, char *argv[])
err(1, "-B expects a number");
break;
case 'I':
tx_can_id = strtoul(optarg, &e, 0);
if (*e != '\0')
err(1, "-I expects a number");
break;
case 'l': loopback_mode = true; break;
case 't': do_transmit = true; break;
case 'T': do_periodic_transmit = true; break;
......@@ -402,7 +408,7 @@ int main(int argc, char *argv[])
if (do_transmit) {
struct canfd_frame txf;
txf.can_id = 0x1FF;
txf.can_id = tx_can_id;
txf.flags = 0;
//u8 d[] = {0xde, 0xad, 0xbe, 0xef};
u8 d[] = {0xDE, 0xAD, 0xBE, 0xEF};
......@@ -421,11 +427,16 @@ int main(int argc, char *argv[])
union ctu_can_fd_rx_mem_info reg;
reg.u32 = ctu_can_fd_read32(priv, CTU_CAN_FD_RX_MEM_INFO);
u32 rxsz = reg.s.rx_buff_size - reg.s.rx_mem_free;
union ctu_can_fd_status status = ctu_can_get_status(priv);
union ctu_can_fd_err_capt_alc err_capt_alc;
union ctu_can_fd_int_stat int_stat = ctu_can_fd_int_sts(priv);
ctu_can_fd_int_clr(priv, int_stat);
printf("%u RX frames, %u words", nrxf, rxsz);
printf(", status 0x%08hhx", ctu_can_fd_read32(priv, CTU_CAN_FD_STATUS));
printf(", status 0x%08hx", status.u32);
printf(", settings 0x%04hhx", ctu_can_fd_read16(priv, CTU_CAN_FD_SETTINGS));
printf(", INT_STAT 0x%04hhx", ctu_can_fd_read16(priv, CTU_CAN_FD_INT_STAT));
printf(", INT_STAT 0x%04hx", int_stat.u32);
printf(", INT_ENA_SET 0x%04hx", priv->read_reg(priv, CTU_CAN_FD_INT_ENA_SET));
printf(", INT_MASK_SET 0x%04hx", priv->read_reg(priv, CTU_CAN_FD_INT_MASK_SET));
printf(", TX_STATUS 0x%04hx", priv->read_reg(priv, CTU_CAN_FD_TX_STATUS));
......@@ -433,6 +444,14 @@ int main(int argc, char *argv[])
printf(", TRV_DELAY 0x%0hx", priv->read_reg(priv, CTU_CAN_FD_TRV_DELAY));
printf("\n");
if (status.s.ewl) {
err_capt_alc = ctu_can_fd_read_err_capt_alc(priv);
printf("ERROR type %u pos %u ALC id_field %u bit %u\n",
err_capt_alc.s.err_type, err_capt_alc.s.err_pos,
err_capt_alc.s.alc_id_field, err_capt_alc.s.alc_bit);
}
/*
while (rxsz--) {
u32 data = priv->read_reg(priv, CTU_CAN_FD_RX_DATA);
......@@ -454,13 +473,12 @@ int main(int argc, char *argv[])
if (do_periodic_transmit && (loop_cycle & 1)) {
struct canfd_frame txf;
memset(&txf, 0, sizeof(txf));
txf.can_id = 0x1FF;
txf.can_id = tx_can_id;
txf.flags = 0;
if (transmit_fdf) {
txf.flags |= CANFD_BRS;
u8 dfd[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee};
txf.can_id = 0x123;
memcpy(txf.data, dfd, sizeof(dfd));
txf.len = sizeof(dfd);
} else {
......