...
 
Commits (7)
......@@ -45,6 +45,8 @@
#include <linux/can/error.h>
#include <linux/can/led.h>
#include <linux/pm_runtime.h>
#include <linux/ktime.h>
#include <linux/net_tstamp.h>
#include "ctu_can_fd_hw.h"
#include "ctu_can_fd_regs.h"
......@@ -59,6 +61,8 @@ static bool pci_use_second = 1;
module_param(pci_use_second, bool, 0444);
MODULE_PARM_DESC(pci_use_second, "Use the second CAN core on PCIe card. Default: 1 (yes)");
#define CTUCAN_IOCDBG_MASKRX (SIOCDEVPRIVATE)
/* TX buffer rotation:
* - when a buffer transitions to empty state, rotate order and priorities
* - if more buffers seem to transition at the same time, rotate
......@@ -90,7 +94,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 +227,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;
......@@ -359,6 +364,14 @@ static int ctucan_rx(struct net_device *ndev)
}
ctu_can_fd_read_rx_frame_ffw(&priv->p, cf, &ts, ffw);
// TEST
{
struct skb_shared_hwtstamps *hwts;
hwts = skb_hwtstamps(skb);
memset(hwts, 0, sizeof(*hwts));
netdev_dbg(ndev, "RX: timestamp = %llu", ts);
hwts->hwtstamp = (ktime_t) ts;
}
stats->rx_bytes += cf->len;
stats->rx_packets++;
......@@ -535,9 +548,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 +640,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 +652,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 +690,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 +701,19 @@ 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 */
/* Clear and mask RXBNEI, schedule NAPI.
* Even if another IRQ fires, isr.s.rbnei will always
* be 0 (masked). */
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);
ctu_can_fd_int_mask_set(&priv->p, icr);
// 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 +738,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 +755,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;
}
......@@ -864,11 +880,96 @@ static int ctucan_get_berr_counter(const struct net_device *ndev,
return 0;
}
static int ctucan_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
{
//struct xcan_priv *priv = netdev_priv(dev);
struct hwtstamp_config cfg;
if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
return -EFAULT;
/* reserved for future extensions */
if (cfg.flags)
return -EINVAL;
if (cfg.tx_type != HWTSTAMP_TX_OFF)
return -ERANGE;
switch (cfg.rx_filter) {
case HWTSTAMP_FILTER_NONE:
//priv->rx_enable = 0;
break;
case HWTSTAMP_FILTER_ALL:
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
//priv->rx_enable = 1;
cfg.rx_filter = HWTSTAMP_FILTER_ALL;
break;
default:
return -ERANGE;
}
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
}
static int ctucan_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
{
//struct xcan_priv *priv = netdev_priv(dev);
struct hwtstamp_config cfg;
cfg.flags = 0;
cfg.tx_type = HWTSTAMP_TX_OFF;
cfg.rx_filter = //(xcan->rx_enable ?
HWTSTAMP_FILTER_ALL;// : HWTSTAMP_FILTER_NONE);
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
}
static int ctucan_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
{
struct ctucan_priv *priv = netdev_priv(ndev);
netdev_dbg(ndev, "ctucan_ioctl");
switch(cmd)
{
case SIOCSHWTSTAMP:
return ctucan_hwtstamp_set(ndev, ifr);
case SIOCGHWTSTAMP:
return ctucan_hwtstamp_get(ndev, ifr);
case CTUCAN_IOCDBG_MASKRX: {
union ctu_can_fd_int_stat mask;
bool mask_rx = ifr->ifr_flags & 1;
mask.u32 = 0;
mask.s.rbnei = 1;
netdev_info(ndev, "DBG: setting mask_rx to %d", mask_rx);
if (mask_rx)
ctu_can_fd_int_mask_set(&priv->p, mask);
else
ctu_can_fd_int_mask_clr(&priv->p, mask);
return 0;
} break;
default:
return -EOPNOTSUPP;
}
}
static const struct net_device_ops ctucan_netdev_ops = {
.ndo_open = ctucan_open,
.ndo_stop = ctucan_close,
.ndo_start_xmit = ctucan_start_xmit,
.ndo_change_mtu = can_change_mtu,
.ndo_do_ioctl = ctucan_ioctl,
};
static __maybe_unused int ctucan_suspend(struct device *dev)
......
......@@ -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.
*
......