Commit 9c0ee085 authored by David S. Miller's avatar David S. Miller

Merge tag 'linux-can-next-for-5.13-20210330' of...

Merge tag 'linux-can-next-for-5.13-20210330' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next

Marc Kleine-Budde says:

====================
pull-request: can-next 2021-03-30

this is a pull request of 39 patches for net-next/master.

The first two patches update the MAINTAINERS file. One is by me and
removes Dan Murphy from the from m_can and tcan4x5x. The other one is
by Pankaj Sharma and updates the maintainership of the m-can mmio
driver.

The next three patches are by me and update the CAN echo skb handling.

Vincent Mailhol provides 5 patches where Transmitter Delay
Compensation is added CAN bittiming calculation is cleaned up.

The next patch is by me and adds a missing HAS_IOMEM to the grcan
driver.

Michal Simek's patch for the xilinx driver add dev_err_probe()
support.

Arnd Bergmann's patch for the ucan driver fixes a compiler warning.

Stephane Grosjean provides 3 patches for the peak USB drivers, which
add ethtool set_phys_id and CAN one-shot mode.

Xulin Sun's patch removes a not needed return check in the m-can
driver. Torin Cooper-Bennun provides 3 patches for the m-can driver
that add rx-offload support to ensure that skbs are sent from softirq
context. Wan Jiabing's patch for the tcan4x5x driver removes a
duplicate include.

The next 6 patches are by me and target the mcp251xfd driver. They add
devcoredump support, simplify the UINC handling, and add HW timestamp
support.

The remaining 12 patches target the c_can driver. The first 6 are by
me and do generic checkpatch related cleanup work. Dario Binacchi's
patches bring some cleanups and increase the number of usable message
objects from 16 to 64.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 402a66ed 132f2d45
...@@ -10910,8 +10910,7 @@ T: git git://linuxtv.org/media_tree.git ...@@ -10910,8 +10910,7 @@ T: git git://linuxtv.org/media_tree.git
F: drivers/media/radio/radio-maxiradio* F: drivers/media/radio/radio-maxiradio*
MCAN MMIO DEVICE DRIVER MCAN MMIO DEVICE DRIVER
M: Dan Murphy <dmurphy@ti.com> M: Chandrasekar Ramakrishnan <rcsekar@samsung.com>
M: Pankaj Sharma <pankj.sharma@samsung.com>
L: linux-can@vger.kernel.org L: linux-can@vger.kernel.org
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/net/can/bosch,m_can.yaml F: Documentation/devicetree/bindings/net/can/bosch,m_can.yaml
...@@ -17983,13 +17982,6 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) ...@@ -17983,13 +17982,6 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Odd Fixes S: Odd Fixes
F: sound/soc/codecs/tas571x* F: sound/soc/codecs/tas571x*
TI TCAN4X5X DEVICE DRIVER
M: Dan Murphy <dmurphy@ti.com>
L: linux-can@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/can/tcan4x5x.txt
F: drivers/net/can/m_can/tcan4x5x*
TI TRF7970A NFC DRIVER TI TRF7970A NFC DRIVER
M: Mark Greer <mgreer@animalcreek.com> M: Mark Greer <mgreer@animalcreek.com>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
......
...@@ -103,7 +103,7 @@ config CAN_FLEXCAN ...@@ -103,7 +103,7 @@ config CAN_FLEXCAN
config CAN_GRCAN config CAN_GRCAN
tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices" tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
depends on OF && HAS_DMA depends on OF && HAS_DMA && HAS_IOMEM
help help
Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN. Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
Note that the driver supports little endian, even though little Note that the driver supports little endian, even though little
......
...@@ -132,7 +132,6 @@ ...@@ -132,7 +132,6 @@
/* For the high buffers we clear the interrupt bit and newdat */ /* For the high buffers we clear the interrupt bit and newdat */
#define IF_COMM_RCV_HIGH (IF_COMM_RCV_LOW | IF_COMM_CLR_NEWDAT) #define IF_COMM_RCV_HIGH (IF_COMM_RCV_LOW | IF_COMM_CLR_NEWDAT)
/* Receive setup of message objects */ /* Receive setup of message objects */
#define IF_COMM_RCV_SETUP (IF_COMM_MASK | IF_COMM_ARB | IF_COMM_CONTROL) #define IF_COMM_RCV_SETUP (IF_COMM_MASK | IF_COMM_ARB | IF_COMM_CONTROL)
...@@ -161,9 +160,7 @@ ...@@ -161,9 +160,7 @@
#define IF_MCONT_TX (IF_MCONT_TXIE | IF_MCONT_EOB) #define IF_MCONT_TX (IF_MCONT_TXIE | IF_MCONT_EOB)
/* /* Use IF1 for RX and IF2 for TX */
* Use IF1 for RX and IF2 for TX
*/
#define IF_RX 0 #define IF_RX 0
#define IF_TX 1 #define IF_TX 1
...@@ -173,9 +170,6 @@ ...@@ -173,9 +170,6 @@
/* Wait for ~1 sec for INIT bit */ /* Wait for ~1 sec for INIT bit */
#define INIT_WAIT_MS 1000 #define INIT_WAIT_MS 1000
/* napi related */
#define C_CAN_NAPI_WEIGHT C_CAN_MSG_OBJ_RX_NUM
/* c_can lec values */ /* c_can lec values */
enum c_can_lec_type { enum c_can_lec_type {
LEC_NO_ERROR = 0, LEC_NO_ERROR = 0,
...@@ -189,8 +183,7 @@ enum c_can_lec_type { ...@@ -189,8 +183,7 @@ enum c_can_lec_type {
LEC_MASK = LEC_UNUSED, LEC_MASK = LEC_UNUSED,
}; };
/* /* c_can error types:
* c_can error types:
* Bus errors (BUS_OFF, ERROR_WARNING, ERROR_PASSIVE) are supported * Bus errors (BUS_OFF, ERROR_WARNING, ERROR_PASSIVE) are supported
*/ */
enum c_can_bus_error_types { enum c_can_bus_error_types {
...@@ -253,7 +246,6 @@ static void c_can_obj_update(struct net_device *dev, int iface, u32 cmd, u32 obj ...@@ -253,7 +246,6 @@ static void c_can_obj_update(struct net_device *dev, int iface, u32 cmd, u32 obj
udelay(1); udelay(1);
} }
netdev_err(dev, "Updating object timed out\n"); netdev_err(dev, "Updating object timed out\n");
} }
static inline void c_can_object_get(struct net_device *dev, int iface, static inline void c_can_object_get(struct net_device *dev, int iface,
...@@ -268,8 +260,7 @@ static inline void c_can_object_put(struct net_device *dev, int iface, ...@@ -268,8 +260,7 @@ static inline void c_can_object_put(struct net_device *dev, int iface,
c_can_obj_update(dev, iface, cmd | IF_COMM_WR, obj); c_can_obj_update(dev, iface, cmd | IF_COMM_WR, obj);
} }
/* /* Note: According to documentation clearing TXIE while MSGVAL is set
* Note: According to documentation clearing TXIE while MSGVAL is set
* is not allowed, but works nicely on C/DCAN. And that lowers the I/O * is not allowed, but works nicely on C/DCAN. And that lowers the I/O
* load significantly. * load significantly.
*/ */
...@@ -285,8 +276,7 @@ static void c_can_inval_msg_object(struct net_device *dev, int iface, int obj) ...@@ -285,8 +276,7 @@ static void c_can_inval_msg_object(struct net_device *dev, int iface, int obj)
{ {
struct c_can_priv *priv = netdev_priv(dev); struct c_can_priv *priv = netdev_priv(dev);
priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0); priv->write_reg32(priv, C_CAN_IFACE(ARB1_REG, iface), 0);
priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0);
c_can_inval_tx_object(dev, iface, obj); c_can_inval_tx_object(dev, iface, obj);
} }
...@@ -309,12 +299,11 @@ static void c_can_setup_tx_object(struct net_device *dev, int iface, ...@@ -309,12 +299,11 @@ static void c_can_setup_tx_object(struct net_device *dev, int iface,
if (!rtr) if (!rtr)
arb |= IF_ARB_TRANSMIT; arb |= IF_ARB_TRANSMIT;
/* /* If we change the DIR bit, we need to invalidate the buffer
* If we change the DIR bit, we need to invalidate the buffer
* first, i.e. clear the MSGVAL flag in the arbiter. * first, i.e. clear the MSGVAL flag in the arbiter.
*/ */
if (rtr != (bool)test_bit(idx, &priv->tx_dir)) { if (rtr != (bool)test_bit(idx, &priv->tx_dir)) {
u32 obj = idx + C_CAN_MSG_OBJ_TX_FIRST; u32 obj = idx + priv->msg_obj_tx_first;
c_can_inval_msg_object(dev, iface, obj); c_can_inval_msg_object(dev, iface, obj);
change_bit(idx, &priv->tx_dir); change_bit(idx, &priv->tx_dir);
...@@ -447,18 +436,16 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb, ...@@ -447,18 +436,16 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
if (can_dropped_invalid_skb(dev, skb)) if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK; return NETDEV_TX_OK;
/* /* This is not a FIFO. C/D_CAN sends out the buffers
* This is not a FIFO. C/D_CAN sends out the buffers
* prioritized. The lowest buffer number wins. * prioritized. The lowest buffer number wins.
*/ */
idx = fls(atomic_read(&priv->tx_active)); idx = fls(atomic_read(&priv->tx_active));
obj = idx + C_CAN_MSG_OBJ_TX_FIRST; obj = idx + priv->msg_obj_tx_first;
/* If this is the last buffer, stop the xmit queue */ /* If this is the last buffer, stop the xmit queue */
if (idx == C_CAN_MSG_OBJ_TX_NUM - 1) if (idx == priv->msg_obj_tx_num - 1)
netif_stop_queue(dev); netif_stop_queue(dev);
/* /* Store the message in the interface so we can call
* Store the message in the interface so we can call
* can_put_echo_skb(). We must do this before we enable * can_put_echo_skb(). We must do this before we enable
* transmit as we might race against do_tx(). * transmit as we might race against do_tx().
*/ */
...@@ -467,7 +454,7 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb, ...@@ -467,7 +454,7 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
can_put_echo_skb(skb, dev, idx, 0); can_put_echo_skb(skb, dev, idx, 0);
/* Update the active bits */ /* Update the active bits */
atomic_add((1 << idx), &priv->tx_active); atomic_add(BIT(idx), &priv->tx_active);
/* Start transmission */ /* Start transmission */
c_can_object_put(dev, IF_TX, obj, IF_COMM_TX); c_can_object_put(dev, IF_TX, obj, IF_COMM_TX);
...@@ -527,8 +514,7 @@ static int c_can_set_bittiming(struct net_device *dev) ...@@ -527,8 +514,7 @@ static int c_can_set_bittiming(struct net_device *dev)
return c_can_wait_for_ctrl_init(dev, priv, 0); return c_can_wait_for_ctrl_init(dev, priv, 0);
} }
/* /* Configure C_CAN message objects for Tx and Rx purposes:
* Configure C_CAN message objects for Tx and Rx purposes:
* C_CAN provides a total of 32 message objects that can be configured * C_CAN provides a total of 32 message objects that can be configured
* either for Tx or Rx purposes. Here the first 16 message objects are used as * either for Tx or Rx purposes. Here the first 16 message objects are used as
* a reception FIFO. The end of reception FIFO is signified by the EoB bit * a reception FIFO. The end of reception FIFO is signified by the EoB bit
...@@ -538,17 +524,18 @@ static int c_can_set_bittiming(struct net_device *dev) ...@@ -538,17 +524,18 @@ static int c_can_set_bittiming(struct net_device *dev)
*/ */
static void c_can_configure_msg_objects(struct net_device *dev) static void c_can_configure_msg_objects(struct net_device *dev)
{ {
struct c_can_priv *priv = netdev_priv(dev);
int i; int i;
/* first invalidate all message objects */ /* first invalidate all message objects */
for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_NO_OF_OBJECTS; i++) for (i = priv->msg_obj_rx_first; i <= priv->msg_obj_num; i++)
c_can_inval_msg_object(dev, IF_RX, i); c_can_inval_msg_object(dev, IF_RX, i);
/* setup receive message objects */ /* setup receive message objects */
for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++) for (i = priv->msg_obj_rx_first; i < priv->msg_obj_rx_last; i++)
c_can_setup_receive_object(dev, IF_RX, i, 0, 0, IF_MCONT_RCV); c_can_setup_receive_object(dev, IF_RX, i, 0, 0, IF_MCONT_RCV);
c_can_setup_receive_object(dev, IF_RX, C_CAN_MSG_OBJ_RX_LAST, 0, 0, c_can_setup_receive_object(dev, IF_RX, priv->msg_obj_rx_last, 0, 0,
IF_MCONT_RCV_EOB); IF_MCONT_RCV_EOB);
} }
...@@ -572,8 +559,7 @@ static int c_can_software_reset(struct net_device *dev) ...@@ -572,8 +559,7 @@ static int c_can_software_reset(struct net_device *dev)
return 0; return 0;
} }
/* /* Configure C_CAN chip:
* Configure C_CAN chip:
* - enable/disable auto-retransmission * - enable/disable auto-retransmission
* - set operating mode * - set operating mode
* - configure message objects * - configure message objects
...@@ -714,12 +700,21 @@ static void c_can_do_tx(struct net_device *dev) ...@@ -714,12 +700,21 @@ static void c_can_do_tx(struct net_device *dev)
struct net_device_stats *stats = &dev->stats; struct net_device_stats *stats = &dev->stats;
u32 idx, obj, pkts = 0, bytes = 0, pend, clr; u32 idx, obj, pkts = 0, bytes = 0, pend, clr;
clr = pend = priv->read_reg(priv, C_CAN_INTPND2_REG); if (priv->msg_obj_tx_last > 32)
pend = priv->read_reg32(priv, C_CAN_INTPND3_REG);
else
pend = priv->read_reg(priv, C_CAN_INTPND2_REG);
clr = pend;
while ((idx = ffs(pend))) { while ((idx = ffs(pend))) {
idx--; idx--;
pend &= ~(1 << idx); pend &= ~BIT(idx);
obj = idx + C_CAN_MSG_OBJ_TX_FIRST; obj = idx + priv->msg_obj_tx_first;
/* We use IF_RX interface instead of IF_TX because we
* are called from c_can_poll(), which runs inside
* NAPI. We are not trasmitting.
*/
c_can_inval_tx_object(dev, IF_RX, obj); c_can_inval_tx_object(dev, IF_RX, obj);
can_get_echo_skb(dev, idx, NULL); can_get_echo_skb(dev, idx, NULL);
bytes += priv->dlc[idx]; bytes += priv->dlc[idx];
...@@ -729,7 +724,7 @@ static void c_can_do_tx(struct net_device *dev) ...@@ -729,7 +724,7 @@ static void c_can_do_tx(struct net_device *dev)
/* Clear the bits in the tx_active mask */ /* Clear the bits in the tx_active mask */
atomic_sub(clr, &priv->tx_active); atomic_sub(clr, &priv->tx_active);
if (clr & (1 << (C_CAN_MSG_OBJ_TX_NUM - 1))) if (clr & BIT(priv->msg_obj_tx_num - 1))
netif_wake_queue(dev); netif_wake_queue(dev);
if (pkts) { if (pkts) {
...@@ -739,20 +734,18 @@ static void c_can_do_tx(struct net_device *dev) ...@@ -739,20 +734,18 @@ static void c_can_do_tx(struct net_device *dev)
} }
} }
/* /* If we have a gap in the pending bits, that means we either
* If we have a gap in the pending bits, that means we either
* raced with the hardware or failed to readout all upper * raced with the hardware or failed to readout all upper
* objects in the last run due to quota limit. * objects in the last run due to quota limit.
*/ */
static u32 c_can_adjust_pending(u32 pend) static u32 c_can_adjust_pending(u32 pend, u32 rx_mask)
{ {
u32 weight, lasts; u32 weight, lasts;
if (pend == RECEIVE_OBJECT_BITS) if (pend == rx_mask)
return pend; return pend;
/* /* If the last set bit is larger than the number of pending
* If the last set bit is larger than the number of pending
* bits we have a gap. * bits we have a gap.
*/ */
weight = hweight32(pend); weight = hweight32(pend);
...@@ -762,13 +755,13 @@ static u32 c_can_adjust_pending(u32 pend) ...@@ -762,13 +755,13 @@ static u32 c_can_adjust_pending(u32 pend)
if (lasts == weight) if (lasts == weight)
return pend; return pend;
/* /* Find the first set bit after the gap. We walk backwards
* Find the first set bit after the gap. We walk backwards
* from the last set bit. * from the last set bit.
*/ */
for (lasts--; pend & (1 << (lasts - 1)); lasts--); for (lasts--; pend & BIT(lasts - 1); lasts--)
;
return pend & ~((1 << lasts) - 1); return pend & ~GENMASK(lasts - 1, 0);
} }
static inline void c_can_rx_object_get(struct net_device *dev, static inline void c_can_rx_object_get(struct net_device *dev,
...@@ -803,8 +796,7 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv, ...@@ -803,8 +796,7 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
continue; continue;
} }
/* /* This really should not happen, but this covers some
* This really should not happen, but this covers some
* odd HW behaviour. Do not remove that unless you * odd HW behaviour. Do not remove that unless you
* want to brick your machine. * want to brick your machine.
*/ */
...@@ -825,19 +817,22 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv, ...@@ -825,19 +817,22 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
static inline u32 c_can_get_pending(struct c_can_priv *priv) static inline u32 c_can_get_pending(struct c_can_priv *priv)
{ {
u32 pend = priv->read_reg(priv, C_CAN_NEWDAT1_REG); u32 pend;
if (priv->msg_obj_rx_last > 16)
pend = priv->read_reg32(priv, C_CAN_NEWDAT1_REG);
else
pend = priv->read_reg(priv, C_CAN_NEWDAT1_REG);
return pend; return pend;
} }
/* /* theory of operation:
* theory of operation:
* *
* c_can core saves a received CAN message into the first free message * c_can core saves a received CAN message into the first free message
* object it finds free (starting with the lowest). Bits NEWDAT and * object it finds free (starting with the lowest). Bits NEWDAT and
* INTPND are set for this message object indicating that a new message * INTPND are set for this message object indicating that a new message
* has arrived. To work-around this issue, we keep two groups of message * has arrived.
* objects whose partitioning is defined by C_CAN_MSG_OBJ_RX_SPLIT.
* *
* We clear the newdat bit right away. * We clear the newdat bit right away.
* *
...@@ -848,23 +843,16 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota) ...@@ -848,23 +843,16 @@ static int c_can_do_rx_poll(struct net_device *dev, int quota)
struct c_can_priv *priv = netdev_priv(dev); struct c_can_priv *priv = netdev_priv(dev);
u32 pkts = 0, pend = 0, toread, n; u32 pkts = 0, pend = 0, toread, n;
/*
* It is faster to read only one 16bit register. This is only possible
* for a maximum number of 16 objects.
*/
BUILD_BUG_ON_MSG(C_CAN_MSG_OBJ_RX_LAST > 16,
"Implementation does not support more message objects than 16");
while (quota > 0) { while (quota > 0) {
if (!pend) { if (!pend) {
pend = c_can_get_pending(priv); pend = c_can_get_pending(priv);
if (!pend) if (!pend)
break; break;
/* /* If the pending field has a gap, handle the
* If the pending field has a gap, handle the
* bits above the gap first. * bits above the gap first.
*/ */
toread = c_can_adjust_pending(pend); toread = c_can_adjust_pending(pend,
priv->msg_obj_rx_mask);
} else { } else {
toread = pend; toread = pend;
} }
...@@ -979,8 +967,7 @@ static int c_can_handle_bus_err(struct net_device *dev, ...@@ -979,8 +967,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
struct can_frame *cf; struct can_frame *cf;
struct sk_buff *skb; struct sk_buff *skb;
/* /* early exit if no lec update or no error.
* early exit if no lec update or no error.
* no lec update means that no CAN bus event has been detected * no lec update means that no CAN bus event has been detected
* since CPU wrote 0x7 value to status reg. * since CPU wrote 0x7 value to status reg.
*/ */
...@@ -999,8 +986,7 @@ static int c_can_handle_bus_err(struct net_device *dev, ...@@ -999,8 +986,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
if (unlikely(!skb)) if (unlikely(!skb))
return 0; return 0;
/* /* check for 'last error code' which tells us the
* check for 'last error code' which tells us the
* type of the last error to occur on the CAN bus * type of the last error to occur on the CAN bus
*/ */
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
...@@ -1049,7 +1035,8 @@ static int c_can_poll(struct napi_struct *napi, int quota) ...@@ -1049,7 +1035,8 @@ static int c_can_poll(struct napi_struct *napi, int quota)
/* Only read the status register if a status interrupt was pending */ /* Only read the status register if a status interrupt was pending */
if (atomic_xchg(&priv->sie_pending, 0)) { if (atomic_xchg(&priv->sie_pending, 0)) {
priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG); 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 */ /* Ack status on C_CAN. D_CAN is self clearing */
if (priv->type != BOSCH_D_CAN) if (priv->type != BOSCH_D_CAN)
priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED); priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
...@@ -1195,17 +1182,31 @@ static int c_can_close(struct net_device *dev) ...@@ -1195,17 +1182,31 @@ static int c_can_close(struct net_device *dev)
return 0; return 0;
} }
struct net_device *alloc_c_can_dev(void) struct net_device *alloc_c_can_dev(int msg_obj_num)
{ {
struct net_device *dev; struct net_device *dev;
struct c_can_priv *priv; struct c_can_priv *priv;
int msg_obj_tx_num = msg_obj_num / 2;
dev = alloc_candev(sizeof(struct c_can_priv), C_CAN_MSG_OBJ_TX_NUM); dev = alloc_candev(struct_size(priv, dlc, msg_obj_tx_num),
msg_obj_tx_num);
if (!dev) if (!dev)
return NULL; return NULL;
priv = netdev_priv(dev); priv = netdev_priv(dev);
netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT); priv->msg_obj_num = msg_obj_num;
priv->msg_obj_rx_num = msg_obj_num - msg_obj_tx_num;
priv->msg_obj_rx_first = 1;
priv->msg_obj_rx_last =
priv->msg_obj_rx_first + priv->msg_obj_rx_num - 1;
priv->msg_obj_rx_mask = GENMASK(priv->msg_obj_rx_num - 1, 0);
priv->msg_obj_tx_num = msg_obj_tx_num;
priv->msg_obj_tx_first = priv->msg_obj_rx_last + 1;
priv->msg_obj_tx_last =
priv->msg_obj_tx_first + priv->msg_obj_tx_num - 1;
netif_napi_add(dev, &priv->napi, c_can_poll, priv->msg_obj_rx_num);
priv->dev = dev; priv->dev = dev;
priv->can.bittiming_const = &c_can_bittiming_const; priv->can.bittiming_const = &c_can_bittiming_const;
......
...@@ -22,23 +22,6 @@ ...@@ -22,23 +22,6 @@
#ifndef C_CAN_H #ifndef C_CAN_H
#define C_CAN_H #define C_CAN_H
/* message object split */
#define C_CAN_NO_OF_OBJECTS 32
#define C_CAN_MSG_OBJ_RX_NUM 16
#define C_CAN_MSG_OBJ_TX_NUM 16
#define C_CAN_MSG_OBJ_RX_FIRST 1
#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
C_CAN_MSG_OBJ_RX_NUM - 1)
#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1)
#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
C_CAN_MSG_OBJ_TX_NUM - 1)
#define C_CAN_MSG_OBJ_RX_SPLIT 9
#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1)
#define RECEIVE_OBJECT_BITS 0x0000ffff
enum reg { enum reg {
C_CAN_CTRL_REG = 0, C_CAN_CTRL_REG = 0,
C_CAN_CTRL_EX_REG, C_CAN_CTRL_EX_REG,
...@@ -76,6 +59,7 @@ enum reg { ...@@ -76,6 +59,7 @@ enum reg {
C_CAN_NEWDAT2_REG, C_CAN_NEWDAT2_REG,
C_CAN_INTPND1_REG, C_CAN_INTPND1_REG,
C_CAN_INTPND2_REG, C_CAN_INTPND2_REG,
C_CAN_INTPND3_REG,
C_CAN_MSGVAL1_REG, C_CAN_MSGVAL1_REG,
C_CAN_MSGVAL2_REG, C_CAN_MSGVAL2_REG,
C_CAN_FUNCTION_REG, C_CAN_FUNCTION_REG,
...@@ -137,6 +121,7 @@ static const u16 __maybe_unused reg_map_d_can[] = { ...@@ -137,6 +121,7 @@ static const u16 __maybe_unused reg_map_d_can[] = {
[C_CAN_NEWDAT2_REG] = 0x9E, [C_CAN_NEWDAT2_REG] = 0x9E,
[C_CAN_INTPND1_REG] = 0xB0, [C_CAN_INTPND1_REG] = 0xB0,
[C_CAN_INTPND2_REG] = 0xB2, [C_CAN_INTPND2_REG] = 0xB2,
[C_CAN_INTPND3_REG] = 0xB4,
[C_CAN_MSGVAL1_REG] = 0xC4, [C_CAN_MSGVAL1_REG] = 0xC4,
[C_CAN_MSGVAL2_REG] = 0xC6, [C_CAN_MSGVAL2_REG] = 0xC6,
[C_CAN_IF1_COMREQ_REG] = 0x100, [C_CAN_IF1_COMREQ_REG] = 0x100,
...@@ -176,6 +161,7 @@ struct raminit_bits { ...@@ -176,6 +161,7 @@ struct raminit_bits {
struct c_can_driver_data { struct c_can_driver_data {
enum c_can_dev_id id; enum c_can_dev_id id;
unsigned int msg_obj_num;
/* RAMINIT register description. Optional. */ /* RAMINIT register description. Optional. */
const struct raminit_bits *raminit_bits; /* Array of START/DONE bit positions */ const struct raminit_bits *raminit_bits; /* Array of START/DONE bit positions */
...@@ -197,26 +183,34 @@ struct c_can_priv { ...@@ -197,26 +183,34 @@ struct c_can_priv {
struct napi_struct napi; struct napi_struct napi;
struct net_device *dev; struct net_device *dev;
struct device *device; struct device *device;
unsigned int msg_obj_num;
unsigned int msg_obj_rx_num;
unsigned int msg_obj_tx_num;
unsigned int msg_obj_rx_first;
unsigned int msg_obj_rx_last;
unsigned int msg_obj_tx_first;
unsigned int msg_obj_tx_last;
u32 msg_obj_rx_mask;
atomic_t tx_active; atomic_t tx_active;
atomic_t sie_pending; atomic_t sie_pending;
unsigned long tx_dir; unsigned long tx_dir;
int last_status; int last_status;
u16 (*read_reg) (const struct c_can_priv *priv, enum reg index); u16 (*read_reg)(const struct c_can_priv *priv, enum reg index);
void (*write_reg) (const struct c_can_priv *priv, enum reg index, u16 val); void (*write_reg)(const struct c_can_priv *priv, enum reg index, u16 val);
u32 (*read_reg32) (const struct c_can_priv *priv, enum reg index); u32 (*read_reg32)(const struct c_can_priv *priv, enum reg index);
void (*write_reg32) (const struct c_can_priv *priv, enum reg index, u32 val); void (*write_reg32)(const struct c_can_priv *priv, enum reg index, u32 val);
void __iomem *base; void __iomem *base;
const u16 *regs; const u16 *regs;
void *priv; /* for board-specific data */ void *priv; /* for board-specific data */
enum c_can_dev_id type; enum c_can_dev_id type;
struct c_can_raminit raminit_sys; /* RAMINIT via syscon regmap */ struct c_can_raminit raminit_sys; /* RAMINIT via syscon regmap */
void (*raminit) (const struct c_can_priv *priv, bool enable); void (*raminit)(const struct c_can_priv *priv, bool enable);
u32 comm_rcv_high; u32 comm_rcv_high;
u32 rxmasked; u32 rxmasked;
u32 dlc[C_CAN_MSG_OBJ_TX_NUM]; u32 dlc[];
}; };
struct net_device *alloc_c_can_dev(void); struct net_device *alloc_c_can_dev(int msg_obj_num);
void free_c_can_dev(struct net_device *dev); void free_c_can_dev(struct net_device *dev);
int register_c_can_dev(struct net_device *dev); int register_c_can_dev(struct net_device *dev);
void unregister_c_can_dev(struct net_device *dev); void unregister_c_can_dev(struct net_device *dev);
......
...@@ -31,6 +31,8 @@ enum c_can_pci_reg_align { ...@@ -31,6 +31,8 @@ enum c_can_pci_reg_align {
struct c_can_pci_data { struct c_can_pci_data {
/* Specify if is C_CAN or D_CAN */ /* Specify if is C_CAN or D_CAN */
enum c_can_dev_id type; enum c_can_dev_id type;
/* Number of message objects */
unsigned int msg_obj_num;
/* Set the register alignment in the memory */ /* Set the register alignment in the memory */
enum c_can_pci_reg_align reg_align; enum c_can_pci_reg_align reg_align;
/* Set the frequency */ /* Set the frequency */
...@@ -41,8 +43,7 @@ struct c_can_pci_data { ...@@ -41,8 +43,7 @@ struct c_can_pci_data {
void (*init)(const struct c_can_priv *priv, bool enable); void (*init)(const struct c_can_priv *priv, bool enable);
}; };
/* /* 16-bit c_can registers can be arranged differently in the memory
* 16-bit c_can registers can be arranged differently in the memory
* architecture of different implementations. For example: 16-bit * architecture of different implementations. For example: 16-bit
* registers can be aligned to a 16-bit boundary or 32-bit boundary etc. * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
* Handle the same by providing a common read/write interface. * Handle the same by providing a common read/write interface.
...@@ -88,7 +89,7 @@ static u32 c_can_pci_read_reg32(const struct c_can_priv *priv, enum reg index) ...@@ -88,7 +89,7 @@ static u32 c_can_pci_read_reg32(const struct c_can_priv *priv, enum reg index)
u32 val; u32 val;
val = priv->read_reg(priv, index); val = priv->read_reg(priv, index);
val |= ((u32) priv->read_reg(priv, index + 1)) << 16; val |= ((u32)priv->read_reg(priv, index + 1)) << 16;
return val; return val;
} }
...@@ -142,14 +143,13 @@ static int c_can_pci_probe(struct pci_dev *pdev, ...@@ -142,14 +143,13 @@ static int c_can_pci_probe(struct pci_dev *pdev,
pci_resource_len(pdev, c_can_pci_data->bar)); pci_resource_len(pdev, c_can_pci_data->bar));
if (!addr) { if (!addr) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"device has no PCI memory resources, " "device has no PCI memory resources, failing adapter\n");
"failing adapter\n");
ret = -ENOMEM; ret = -ENOMEM;
goto out_release_regions; goto out_release_regions;
} }
/* allocate the c_can device */ /* allocate the c_can device */
dev = alloc_c_can_dev(); dev = alloc_c_can_dev(c_can_pci_data->msg_obj_num);
if (!dev) { if (!dev) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_iounmap; goto out_iounmap;
...@@ -252,8 +252,9 @@ static void c_can_pci_remove(struct pci_dev *pdev) ...@@ -252,8 +252,9 @@ static void c_can_pci_remove(struct pci_dev *pdev)
pci_disable_device(pdev); pci_disable_device(pdev);
} }
static const struct c_can_pci_data c_can_sta2x11= { static const struct c_can_pci_data c_can_sta2x11 = {
.type = BOSCH_C_CAN, .type = BOSCH_C_CAN,
.msg_obj_num = 32,
.reg_align = C_CAN_REG_ALIGN_32, .reg_align = C_CAN_REG_ALIGN_32,
.freq = 52000000, /* 52 Mhz */ .freq = 52000000, /* 52 Mhz */
.bar = 0, .bar = 0,
...@@ -261,6 +262,7 @@ static const struct c_can_pci_data c_can_sta2x11= { ...@@ -261,6 +262,7 @@ static const struct c_can_pci_data c_can_sta2x11= {
static const struct c_can_pci_data c_can_pch = { static const struct c_can_pci_data c_can_pch = {
.type = BOSCH_C_CAN, .type = BOSCH_C_CAN,
.msg_obj_num = 32,
.reg_align = C_CAN_REG_32, .reg_align = C_CAN_REG_32,
.freq = 50000000, /* 50 MHz */ .freq = 50000000, /* 50 MHz */
.init = c_can_pci_reset_pch, .init = c_can_pci_reset_pch,
...@@ -269,7 +271,7 @@ static const struct c_can_pci_data c_can_pch = { ...@@ -269,7 +271,7 @@ static const struct c_can_pci_data c_can_pch = {
#define C_CAN_ID(_vend, _dev, _driverdata) { \ #define C_CAN_ID(_vend, _dev, _driverdata) { \
PCI_DEVICE(_vend, _dev), \ PCI_DEVICE(_vend, _dev), \
.driver_data = (unsigned long)&_driverdata, \ .driver_data = (unsigned long)&(_driverdata), \
} }
static const struct pci_device_id c_can_pci_tbl[] = { static const struct pci_device_id c_can_pci_tbl[] = {
...@@ -279,6 +281,7 @@ static const struct pci_device_id c_can_pci_tbl[] = { ...@@ -279,6 +281,7 @@ static const struct pci_device_id c_can_pci_tbl[] = {
c_can_pch), c_can_pch),
{}, {},
}; };
static struct pci_driver c_can_pci_driver = { static struct pci_driver c_can_pci_driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.id_table = c_can_pci_tbl, .id_table = c_can_pci_tbl,
......
...@@ -193,10 +193,12 @@ static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable) ...@@ -193,10 +193,12 @@ static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
static const struct c_can_driver_data c_can_drvdata = { static const struct c_can_driver_data c_can_drvdata = {
.id = BOSCH_C_CAN, .id = BOSCH_C_CAN,
.msg_obj_num = 32,
}; };
static const struct c_can_driver_data d_can_drvdata = { static const struct c_can_driver_data d_can_drvdata = {
.id = BOSCH_D_CAN, .id = BOSCH_D_CAN,
.msg_obj_num = 32,
}; };
static const struct raminit_bits dra7_raminit_bits[] = { static const struct raminit_bits dra7_raminit_bits[] = {
...@@ -206,6 +208,7 @@ static const struct raminit_bits dra7_raminit_bits[] = { ...@@ -206,6 +208,7 @@ static const struct raminit_bits dra7_raminit_bits[] = {
static const struct c_can_driver_data dra7_dcan_drvdata = { static const struct c_can_driver_data dra7_dcan_drvdata = {
.id = BOSCH_D_CAN, .id = BOSCH_D_CAN,
.msg_obj_num = 64,
.raminit_num = ARRAY_SIZE(dra7_raminit_bits), .raminit_num = ARRAY_SIZE(dra7_raminit_bits),
.raminit_bits = dra7_raminit_bits, .raminit_bits = dra7_raminit_bits,
.raminit_pulse = true, .raminit_pulse = true,
...@@ -218,6 +221,7 @@ static const struct raminit_bits am3352_raminit_bits[] = { ...@@ -218,6 +221,7 @@ static const struct raminit_bits am3352_raminit_bits[] = {
static const struct c_can_driver_data am3352_dcan_drvdata = { static const struct c_can_driver_data am3352_dcan_drvdata = {
.id = BOSCH_D_CAN, .id = BOSCH_D_CAN,
.msg_obj_num = 64,
.raminit_num = ARRAY_SIZE(am3352_raminit_bits), .raminit_num = ARRAY_SIZE(am3352_raminit_bits),
.raminit_bits = am3352_raminit_bits, .raminit_bits = am3352_raminit_bits,
}; };
...@@ -294,7 +298,7 @@ static int c_can_plat_probe(struct platform_device *pdev) ...@@ -294,7 +298,7 @@ static int c_can_plat_probe(struct platform_device *pdev)
} }
/* allocate the c_can device */ /* allocate the c_can device */
dev = alloc_c_can_dev(); dev = alloc_c_can_dev(drvdata->msg_obj_num);
if (!dev) { if (!dev) {
ret = -ENOMEM; ret = -ENOMEM;
goto exit; goto exit;
......
...@@ -81,9 +81,9 @@ int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, ...@@ -81,9 +81,9 @@ int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
if (bt->sample_point) { if (bt->sample_point) {
sample_point_nominal = bt->sample_point; sample_point_nominal = bt->sample_point;
} else { } else {
if (bt->bitrate > 800000) if (bt->bitrate > 800 * CAN_KBPS)
sample_point_nominal = 750; sample_point_nominal = 750;
else if (bt->bitrate > 500000) else if (bt->bitrate > 500 * CAN_KBPS)
sample_point_nominal = 800; sample_point_nominal = 800;
else else
sample_point_nominal = 875; sample_point_nominal = 875;
...@@ -174,6 +174,30 @@ int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, ...@@ -174,6 +174,30 @@ int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
return 0; return 0;
} }
void can_calc_tdco(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
const struct can_bittiming *dbt = &priv->data_bittiming;
struct can_tdc *tdc = &priv->tdc;
const struct can_tdc_const *tdc_const = priv->tdc_const;
if (!tdc_const)
return;
/* As specified in ISO 11898-1 section 11.3.3 "Transmitter
* delay compensation" (TDC) is only applicable if data BRP is
* one or two.
*/
if (dbt->brp == 1 || dbt->brp == 2) {
/* Reuse "normal" sample point and convert it to time quanta */
u32 sample_point_in_tq = can_bit_time(dbt) * dbt->sample_point / 1000;
tdc->tdco = min(sample_point_in_tq, tdc_const->tdco_max);
} else {
tdc->tdco = 0;
}
}
#endif /* CONFIG_CAN_CALC_BITTIMING */ #endif /* CONFIG_CAN_CALC_BITTIMING */
/* Checks the validity of the specified bit-timing parameters prop_seg, /* Checks the validity of the specified bit-timing parameters prop_seg,
......
...@@ -13,14 +13,11 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { ...@@ -13,14 +13,11 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
[IFLA_CAN_RESTART_MS] = { .type = NLA_U32 }, [IFLA_CAN_RESTART_MS] = { .type = NLA_U32 },
[IFLA_CAN_RESTART] = { .type = NLA_U32 }, [IFLA_CAN_RESTART] = { .type = NLA_U32 },
[IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) }, [IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) },
[IFLA_CAN_BITTIMING_CONST] [IFLA_CAN_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) },
= { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) }, [IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) },
[IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) }, [IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
[IFLA_CAN_DATA_BITTIMING] [IFLA_CAN_DATA_BITTIMING] = { .len = sizeof(struct can_bittiming) },
= { .len = sizeof(struct can_bittiming) }, [IFLA_CAN_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_DATA_BITTIMING_CONST]
= { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_TERMINATION] = { .type = NLA_U16 }, [IFLA_CAN_TERMINATION] = { .type = NLA_U16 },
}; };
...@@ -189,6 +186,8 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], ...@@ -189,6 +186,8 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
memcpy(&priv->data_bittiming, &dbt, sizeof(dbt)); memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
can_calc_tdco(dev);
if (priv->do_set_data_bittiming) { if (priv->do_set_data_bittiming) {
/* Finally, set the bit-timing registers */ /* Finally, set the bit-timing registers */
err = priv->do_set_data_bittiming(dev); err = priv->do_set_data_bittiming(dev);
......
...@@ -45,7 +45,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, ...@@ -45,7 +45,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
BUG_ON(idx >= priv->echo_skb_max); BUG_ON(idx >= priv->echo_skb_max);
/* check flag whether this packet has to be looped back */ /* check flag whether this packet has to be looped back */
if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK || if (!(dev->flags & IFF_ECHO) ||
(skb->protocol != htons(ETH_P_CAN) && (skb->protocol != htons(ETH_P_CAN) &&
skb->protocol != htons(ETH_P_CANFD))) { skb->protocol != htons(ETH_P_CANFD))) {
kfree_skb(skb); kfree_skb(skb);
...@@ -58,7 +58,6 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, ...@@ -58,7 +58,6 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
return -ENOMEM; return -ENOMEM;
/* make settings for echo to reduce code in irq context */ /* make settings for echo to reduce code in irq context */
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->dev = dev; skb->dev = dev;
...@@ -111,6 +110,13 @@ __can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr, ...@@ -111,6 +110,13 @@ __can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr,
priv->echo_skb[idx] = NULL; priv->echo_skb[idx] = NULL;
if (skb->pkt_type == PACKET_LOOPBACK) {
skb->pkt_type = PACKET_BROADCAST;
} else {
dev_consume_skb_any(skb);
return NULL;
}
return skb; return skb;
} }
...@@ -147,14 +153,25 @@ EXPORT_SYMBOL_GPL(can_get_echo_skb); ...@@ -147,14 +153,25 @@ EXPORT_SYMBOL_GPL(can_get_echo_skb);
* *
* The function is typically called when TX failed. * The function is typically called when TX failed.
*/ */
void can_free_echo_skb(struct net_device *dev, unsigned int idx) void can_free_echo_skb(struct net_device *dev, unsigned int idx,
unsigned int *frame_len_ptr)
{ {
struct can_priv *priv = netdev_priv(dev); struct can_priv *priv = netdev_priv(dev);
BUG_ON(idx >= priv->echo_skb_max); if (idx >= priv->echo_skb_max) {
netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
__func__, idx, priv->echo_skb_max);
return;
}
if (priv->echo_skb[idx]) { if (priv->echo_skb[idx]) {
dev_kfree_skb_any(priv->echo_skb[idx]); struct sk_buff *skb = priv->echo_skb[idx];
struct can_skb_priv *can_skb_priv = can_skb_prv(skb);
if (frame_len_ptr)
*frame_len_ptr = can_skb_priv->frame_len;
dev_kfree_skb_any(skb);
priv->echo_skb[idx] = NULL; priv->echo_skb[idx] = NULL;
} }
} }
......
...@@ -520,7 +520,7 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo) ...@@ -520,7 +520,7 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo)
can_get_echo_skb(dev, i, NULL); can_get_echo_skb(dev, i, NULL);
} else { } else {
/* For cleanup of untransmitted messages */ /* For cleanup of untransmitted messages */
can_free_echo_skb(dev, i); can_free_echo_skb(dev, i, NULL);
} }
priv->eskbp = grcan_ring_add(priv->eskbp, GRCAN_MSG_SIZE, priv->eskbp = grcan_ring_add(priv->eskbp, GRCAN_MSG_SIZE,
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* https://github.com/linux-can/can-doc/tree/master/m_can * https://github.com/linux-can/can-doc/tree/master/m_can
*/ */
#include <linux/bitfield.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -148,6 +149,16 @@ enum m_can_reg { ...@@ -148,6 +149,16 @@ enum m_can_reg {
#define NBTP_NTSEG2_SHIFT 0 #define NBTP_NTSEG2_SHIFT 0
#define NBTP_NTSEG2_MASK (0x7f << NBTP_NTSEG2_SHIFT) #define NBTP_NTSEG2_MASK (0x7f << NBTP_NTSEG2_SHIFT)
/* Timestamp Counter Configuration Register (TSCC) */
#define TSCC_TCP_MASK GENMASK(19, 16)
#define TSCC_TSS_MASK GENMASK(1, 0)
#define TSCC_TSS_DISABLE 0x0
#define TSCC_TSS_INTERNAL 0x1
#define TSCC_TSS_EXTERNAL 0x2
/* Timestamp Counter Value Register (TSCV) */
#define TSCV_TSC_MASK GENMASK(15, 0)
/* Error Counter Register(ECR) */ /* Error Counter Register(ECR) */
#define ECR_RP BIT(15) #define ECR_RP BIT(15)
#define ECR_REC_SHIFT 8 #define ECR_REC_SHIFT 8
...@@ -302,6 +313,7 @@ enum m_can_reg { ...@@ -302,6 +313,7 @@ enum m_can_reg {
#define RX_BUF_ANMF BIT(31) #define RX_BUF_ANMF BIT(31)
#define RX_BUF_FDF BIT(21) #define RX_BUF_FDF BIT(21)
#define RX_BUF_BRS BIT(20) #define RX_BUF_BRS BIT(20)
#define RX_BUF_RXTS_MASK GENMASK(15, 0)
/* Tx Buffer Element */ /* Tx Buffer Element */
/* T0 */ /* T0 */
...@@ -319,6 +331,7 @@ enum m_can_reg { ...@@ -319,6 +331,7 @@ enum m_can_reg {
/* E1 */ /* E1 */
#define TX_EVENT_MM_SHIFT TX_BUF_MM_SHIFT #define TX_EVENT_MM_SHIFT TX_BUF_MM_SHIFT
#define TX_EVENT_MM_MASK (0xff << TX_EVENT_MM_SHIFT) #define TX_EVENT_MM_MASK (0xff << TX_EVENT_MM_SHIFT)
#define TX_EVENT_TXTS_MASK GENMASK(15, 0)
static inline u32 m_can_read(struct m_can_classdev *cdev, enum m_can_reg reg) static inline u32 m_can_read(struct m_can_classdev *cdev, enum m_can_reg reg)
{ {
...@@ -413,6 +426,20 @@ static inline void m_can_disable_all_interrupts(struct m_can_classdev *cdev) ...@@ -413,6 +426,20 @@ static inline void m_can_disable_all_interrupts(struct m_can_classdev *cdev)
m_can_write(cdev, M_CAN_ILE, 0x0); m_can_write(cdev, M_CAN_ILE, 0x0);
} }
/* Retrieve internal timestamp counter from TSCV.TSC, and shift it to 32-bit
* width.
*/
static u32 m_can_get_timestamp(struct m_can_classdev *cdev)
{
u32 tscv;
u32 tsc;
tscv = m_can_read(cdev, M_CAN_TSCV);
tsc = FIELD_GET(TSCV_TSC_MASK, tscv);
return (tsc << 16);
}
static void m_can_clean(struct net_device *net) static void m_can_clean(struct net_device *net)
{ {
struct m_can_classdev *cdev = netdev_priv(net); struct m_can_classdev *cdev = netdev_priv(net);
...@@ -425,11 +452,26 @@ static void m_can_clean(struct net_device *net) ...@@ -425,11 +452,26 @@ static void m_can_clean(struct net_device *net)
putidx = ((m_can_read(cdev, M_CAN_TXFQS) & putidx = ((m_can_read(cdev, M_CAN_TXFQS) &
TXFQS_TFQPI_MASK) >> TXFQS_TFQPI_SHIFT); TXFQS_TFQPI_MASK) >> TXFQS_TFQPI_SHIFT);
can_free_echo_skb(cdev->net, putidx); can_free_echo_skb(cdev->net, putidx, NULL);
cdev->tx_skb = NULL; cdev->tx_skb = NULL;
} }
} }
/* For peripherals, pass skb to rx-offload, which will push skb from
* napi. For non-peripherals, RX is done in napi already, so push
* directly. timestamp is used to ensure good skb ordering in
* rx-offload and is ignored for non-peripherals.
*/
static void m_can_receive_skb(struct m_can_classdev *cdev,
struct sk_buff *skb,
u32 timestamp)
{
if (cdev->is_peripheral)
can_rx_offload_queue_sorted(&cdev->offload, skb, timestamp);
else
netif_receive_skb(skb);
}
static void m_can_read_fifo(struct net_device *dev, u32 rxfs) static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
{ {
struct net_device_stats *stats = &dev->stats; struct net_device_stats *stats = &dev->stats;
...@@ -437,6 +479,7 @@ static void m_can_read_fifo(struct net_device *dev, u32 rxfs) ...@@ -437,6 +479,7 @@ static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
struct canfd_frame *cf; struct canfd_frame *cf;
struct sk_buff *skb; struct sk_buff *skb;
u32 id, fgi, dlc; u32 id, fgi, dlc;
u32 timestamp = 0;
int i; int i;
/* calculate the fifo get index for where to read data */ /* calculate the fifo get index for where to read data */
...@@ -485,7 +528,9 @@ static void m_can_read_fifo(struct net_device *dev, u32 rxfs) ...@@ -485,7 +528,9 @@ static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += cf->len; stats->rx_bytes += cf->len;
netif_receive_skb(skb); timestamp = FIELD_GET(RX_BUF_RXTS_MASK, dlc);
m_can_receive_skb(cdev, skb, timestamp);
} }
static int m_can_do_rx_poll(struct net_device *dev, int quota) static int m_can_do_rx_poll(struct net_device *dev, int quota)
...@@ -516,9 +561,11 @@ static int m_can_do_rx_poll(struct net_device *dev, int quota) ...@@ -516,9 +561,11 @@ static int m_can_do_rx_poll(struct net_device *dev, int quota)
static int m_can_handle_lost_msg(struct net_device *dev) static int m_can_handle_lost_msg(struct net_device *dev)
{ {
struct m_can_classdev *cdev = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats; struct net_device_stats *stats = &dev->stats;
struct sk_buff *skb; struct sk_buff *skb;
struct can_frame *frame; struct can_frame *frame;
u32 timestamp = 0;
netdev_err(dev, "msg lost in rxf0\n"); netdev_err(dev, "msg lost in rxf0\n");
...@@ -532,7 +579,10 @@ static int m_can_handle_lost_msg(struct net_device *dev) ...@@ -532,7 +579,10 @@ static int m_can_handle_lost_msg(struct net_device *dev)
frame->can_id |= CAN_ERR_CRTL; frame->can_id |= CAN_ERR_CRTL;
frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
netif_receive_skb(skb); if (cdev->is_peripheral)
timestamp = m_can_get_timestamp(cdev);
m_can_receive_skb(cdev, skb, timestamp);
return 1; return 1;
} }
...@@ -544,6 +594,7 @@ static int m_can_handle_lec_err(struct net_device *dev, ...@@ -544,6 +594,7 @@ static int m_can_handle_lec_err(struct net_device *dev,
struct net_device_stats *stats = &dev->stats; struct net_device_stats *stats = &dev->stats;
struct can_frame *cf; struct can_frame *cf;
struct sk_buff *skb; struct sk_buff *skb;
u32 timestamp = 0;
cdev->can.can_stats.bus_error++; cdev->can.can_stats.bus_error++;
stats->rx_errors++; stats->rx_errors++;
...@@ -589,7 +640,11 @@ static int m_can_handle_lec_err(struct net_device *dev, ...@@ -589,7 +640,11 @@ static int m_can_handle_lec_err(struct net_device *dev,
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += cf->len; stats->rx_bytes += cf->len;
netif_receive_skb(skb);
if (cdev->is_peripheral)
timestamp = m_can_get_timestamp(cdev);
m_can_receive_skb(cdev, skb, timestamp);
return 1; return 1;
} }
...@@ -647,6 +702,7 @@ static int m_can_handle_state_change(struct net_device *dev, ...@@ -647,6 +702,7 @@ static int m_can_handle_state_change(struct net_device *dev,
struct sk_buff *skb; struct sk_buff *skb;
struct can_berr_counter bec; struct can_berr_counter bec;
unsigned int ecr; unsigned int ecr;
u32 timestamp = 0;
switch (new_state) { switch (new_state) {
case CAN_STATE_ERROR_WARNING: case CAN_STATE_ERROR_WARNING:
...@@ -708,7 +764,11 @@ static int m_can_handle_state_change(struct net_device *dev, ...@@ -708,7 +764,11 @@ static int m_can_handle_state_change(struct net_device *dev,
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += cf->len; stats->rx_bytes += cf->len;
netif_receive_skb(skb);
if (cdev->is_peripheral)
timestamp = m_can_get_timestamp(cdev);
m_can_receive_skb(cdev, skb, timestamp);
return 1; return 1;
} }
...@@ -773,6 +833,7 @@ static int m_can_handle_protocol_error(struct net_device *dev, u32 irqstatus) ...@@ -773,6 +833,7 @@ static int m_can_handle_protocol_error(struct net_device *dev, u32 irqstatus)
struct m_can_classdev *cdev = netdev_priv(dev); struct m_can_classdev *cdev = netdev_priv(dev);
struct can_frame *cf; struct can_frame *cf;
struct sk_buff *skb; struct sk_buff *skb;
u32 timestamp = 0;
/* propagate the error condition to the CAN stack */ /* propagate the error condition to the CAN stack */
skb = alloc_can_err_skb(dev, &cf); skb = alloc_can_err_skb(dev, &cf);
...@@ -794,7 +855,11 @@ static int m_can_handle_protocol_error(struct net_device *dev, u32 irqstatus) ...@@ -794,7 +855,11 @@ static int m_can_handle_protocol_error(struct net_device *dev, u32 irqstatus)
netdev_dbg(dev, "allocation of skb failed\n"); netdev_dbg(dev, "allocation of skb failed\n");
return 0; return 0;
} }
netif_receive_skb(skb);
if (cdev->is_peripheral)
timestamp = m_can_get_timestamp(cdev);
m_can_receive_skb(cdev, skb, timestamp);
return 1; return 1;
} }
...@@ -895,6 +960,29 @@ static int m_can_poll(struct napi_struct *napi, int quota) ...@@ -895,6 +960,29 @@ static int m_can_poll(struct napi_struct *napi, int quota)
return work_done; return work_done;
} }
/* Echo tx skb and update net stats. Peripherals use rx-offload for
* echo. timestamp is used for peripherals to ensure correct ordering
* by rx-offload, and is ignored for non-peripherals.
*/
static void m_can_tx_update_stats(struct m_can_classdev *cdev,
unsigned int msg_mark,
u32 timestamp)
{
struct net_device *dev = cdev->net;
struct net_device_stats *stats = &dev->stats;
if (cdev->is_peripheral)
stats->tx_bytes +=
can_rx_offload_get_echo_skb(&cdev->offload,
msg_mark,
timestamp,
NULL);
else
stats->tx_bytes += can_get_echo_skb(dev, msg_mark, NULL);
stats->tx_packets++;
}
static void m_can_echo_tx_event(struct net_device *dev) static void m_can_echo_tx_event(struct net_device *dev)
{ {
u32 txe_count = 0; u32 txe_count = 0;
...@@ -904,7 +992,6 @@ static void m_can_echo_tx_event(struct net_device *dev) ...@@ -904,7 +992,6 @@ static void m_can_echo_tx_event(struct net_device *dev)
unsigned int msg_mark; unsigned int msg_mark;
struct m_can_classdev *cdev = netdev_priv(dev); struct m_can_classdev *cdev = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
/* read tx event fifo status */ /* read tx event fifo status */
m_can_txefs = m_can_read(cdev, M_CAN_TXEFS); m_can_txefs = m_can_read(cdev, M_CAN_TXEFS);
...@@ -914,21 +1001,23 @@ static void m_can_echo_tx_event(struct net_device *dev) ...@@ -914,21 +1001,23 @@ static void m_can_echo_tx_event(struct net_device *dev)
/* Get and process all sent elements */ /* Get and process all sent elements */
for (i = 0; i < txe_count; i++) { for (i = 0; i < txe_count; i++) {
u32 txe, timestamp = 0;
/* retrieve get index */ /* retrieve get index */
fgi = (m_can_read(cdev, M_CAN_TXEFS) & TXEFS_EFGI_MASK) >> fgi = (m_can_read(cdev, M_CAN_TXEFS) & TXEFS_EFGI_MASK) >>
TXEFS_EFGI_SHIFT; TXEFS_EFGI_SHIFT;
/* get message marker */ /* get message marker, timestamp */
msg_mark = (m_can_txe_fifo_read(cdev, fgi, 4) & txe = m_can_txe_fifo_read(cdev, fgi, 4);
TX_EVENT_MM_MASK) >> TX_EVENT_MM_SHIFT; msg_mark = (txe & TX_EVENT_MM_MASK) >> TX_EVENT_MM_SHIFT;
timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe);
/* ack txe element */ /* ack txe element */
m_can_write(cdev, M_CAN_TXEFA, (TXEFA_EFAI_MASK & m_can_write(cdev, M_CAN_TXEFA, (TXEFA_EFAI_MASK &
(fgi << TXEFA_EFAI_SHIFT))); (fgi << TXEFA_EFAI_SHIFT)));
/* update stats */ /* update stats */
stats->tx_bytes += can_get_echo_skb(dev, msg_mark, NULL); m_can_tx_update_stats(cdev, msg_mark, timestamp);
stats->tx_packets++;
} }
} }
...@@ -936,7 +1025,6 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) ...@@ -936,7 +1025,6 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)
{ {
struct net_device *dev = (struct net_device *)dev_id; struct net_device *dev = (struct net_device *)dev_id;
struct m_can_classdev *cdev = netdev_priv(dev); struct m_can_classdev *cdev = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
u32 ir; u32 ir;
if (pm_runtime_suspended(cdev->dev)) if (pm_runtime_suspended(cdev->dev))
...@@ -969,8 +1057,12 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) ...@@ -969,8 +1057,12 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)
if (cdev->version == 30) { if (cdev->version == 30) {
if (ir & IR_TC) { if (ir & IR_TC) {
/* Transmission Complete Interrupt*/ /* Transmission Complete Interrupt*/
stats->tx_bytes += can_get_echo_skb(dev, 0, NULL); u32 timestamp = 0;
stats->tx_packets++;
if (cdev->is_peripheral)
timestamp = m_can_get_timestamp(cdev);
m_can_tx_update_stats(cdev, 0, timestamp);
can_led_event(dev, CAN_LED_EVENT_TX); can_led_event(dev, CAN_LED_EVENT_TX);
netif_wake_queue(dev); netif_wake_queue(dev);
} }
...@@ -1108,6 +1200,7 @@ static int m_can_set_bittiming(struct net_device *dev) ...@@ -1108,6 +1200,7 @@ static int m_can_set_bittiming(struct net_device *dev)
* - >= v3.1.x: TX FIFO is used * - >= v3.1.x: TX FIFO is used
* - configure mode * - configure mode
* - setup bittiming * - setup bittiming
* - configure timestamp generation
*/ */
static void m_can_chip_config(struct net_device *dev) static void m_can_chip_config(struct net_device *dev)
{ {
...@@ -1219,6 +1312,10 @@ static void m_can_chip_config(struct net_device *dev) ...@@ -1219,6 +1312,10 @@ static void m_can_chip_config(struct net_device *dev)
/* set bittiming params */ /* set bittiming params */
m_can_set_bittiming(dev); m_can_set_bittiming(dev);
/* enable internal timestamp generation, with a prescalar of 16. The
* prescalar is applied to the nominal bit timing */
m_can_write(cdev, M_CAN_TSCC, FIELD_PREP(TSCC_TCP_MASK, 0xf));
m_can_config_endisable(cdev, false); m_can_config_endisable(cdev, false);
if (cdev->ops->init) if (cdev->ops->init)
...@@ -1426,6 +1523,9 @@ static int m_can_close(struct net_device *dev) ...@@ -1426,6 +1523,9 @@ static int m_can_close(struct net_device *dev)
cdev->tx_wq = NULL; cdev->tx_wq = NULL;
} }
if (cdev->is_peripheral)
can_rx_offload_disable(&cdev->offload);
close_candev(dev); close_candev(dev);
can_led_event(dev, CAN_LED_EVENT_STOP); can_led_event(dev, CAN_LED_EVENT_STOP);
...@@ -1624,6 +1724,9 @@ static int m_can_open(struct net_device *dev) ...@@ -1624,6 +1724,9 @@ static int m_can_open(struct net_device *dev)
goto exit_disable_clks; goto exit_disable_clks;
} }
if (cdev->is_peripheral)
can_rx_offload_enable(&cdev->offload);
/* register interrupt handler */ /* register interrupt handler */
if (cdev->is_peripheral) { if (cdev->is_peripheral) {
cdev->tx_skb = NULL; cdev->tx_skb = NULL;
...@@ -1665,6 +1768,8 @@ static int m_can_open(struct net_device *dev) ...@@ -1665,6 +1768,8 @@ static int m_can_open(struct net_device *dev)
if (cdev->is_peripheral) if (cdev->is_peripheral)
destroy_workqueue(cdev->tx_wq); destroy_workqueue(cdev->tx_wq);
out_wq_fail: out_wq_fail:
if (cdev->is_peripheral)
can_rx_offload_disable(&cdev->offload);
close_candev(dev); close_candev(dev);
exit_disable_clks: exit_disable_clks:
m_can_clk_stop(cdev); m_can_clk_stop(cdev);
...@@ -1787,11 +1892,6 @@ struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, ...@@ -1787,11 +1892,6 @@ struct m_can_classdev *m_can_class_allocate_dev(struct device *dev,
} }
class_dev = netdev_priv(net_dev); class_dev = netdev_priv(net_dev);
if (!class_dev) {
dev_err(dev, "Failed to init netdev cdevate");
goto out;
}
class_dev->net = net_dev; class_dev->net = net_dev;
class_dev->dev = dev; class_dev->dev = dev;
SET_NETDEV_DEV(net_dev, dev); SET_NETDEV_DEV(net_dev, dev);
...@@ -1818,15 +1918,22 @@ int m_can_class_register(struct m_can_classdev *cdev) ...@@ -1818,15 +1918,22 @@ int m_can_class_register(struct m_can_classdev *cdev)
return ret; return ret;
} }
ret = m_can_dev_setup(cdev); if (cdev->is_peripheral) {
ret = can_rx_offload_add_manual(cdev->net, &cdev->offload,
M_CAN_NAPI_WEIGHT);
if (ret) if (ret)
goto clk_disable; goto clk_disable;
}
ret = m_can_dev_setup(cdev);
if (ret)
goto rx_offload_del;
ret = register_m_can_dev(cdev->net); ret = register_m_can_dev(cdev->net);
if (ret) { if (ret) {
dev_err(cdev->dev, "registering %s failed (err=%d)\n", dev_err(cdev->dev, "registering %s failed (err=%d)\n",
cdev->net->name, ret); cdev->net->name, ret);
goto clk_disable; goto rx_offload_del;
} }
devm_can_led_init(cdev->net); devm_can_led_init(cdev->net);
...@@ -1839,6 +1946,13 @@ int m_can_class_register(struct m_can_classdev *cdev) ...@@ -1839,6 +1946,13 @@ int m_can_class_register(struct m_can_classdev *cdev)
/* Probe finished /* Probe finished
* Stop clocks. They will be reactivated once the M_CAN device is opened * Stop clocks. They will be reactivated once the M_CAN device is opened
*/ */
m_can_clk_stop(cdev);
return 0;
rx_offload_del:
if (cdev->is_peripheral)
can_rx_offload_del(&cdev->offload);
clk_disable: clk_disable:
m_can_clk_stop(cdev); m_can_clk_stop(cdev);
...@@ -1848,6 +1962,8 @@ EXPORT_SYMBOL_GPL(m_can_class_register); ...@@ -1848,6 +1962,8 @@ EXPORT_SYMBOL_GPL(m_can_class_register);
void m_can_class_unregister(struct m_can_classdev *cdev) void m_can_class_unregister(struct m_can_classdev *cdev)
{ {
if (cdev->is_peripheral)
can_rx_offload_del(&cdev->offload);
unregister_candev(cdev->net); unregister_candev(cdev->net);
} }
EXPORT_SYMBOL_GPL(m_can_class_unregister); EXPORT_SYMBOL_GPL(m_can_class_unregister);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/can/core.h> #include <linux/can/core.h>
#include <linux/can/led.h> #include <linux/can/led.h>
#include <linux/can/rx-offload.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
...@@ -71,6 +72,7 @@ struct m_can_ops { ...@@ -71,6 +72,7 @@ struct m_can_ops {
struct m_can_classdev { struct m_can_classdev {
struct can_priv can; struct can_priv can;
struct can_rx_offload offload;
struct napi_struct napi; struct napi_struct napi;
struct net_device *net; struct net_device *net;
struct device *dev; struct device *dev;
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
......
...@@ -217,7 +217,7 @@ static void tx_failure_cleanup(struct net_device *ndev) ...@@ -217,7 +217,7 @@ static void tx_failure_cleanup(struct net_device *ndev)
int i; int i;
for (i = 0; i < RCAR_CAN_FIFO_DEPTH; i++) for (i = 0; i < RCAR_CAN_FIFO_DEPTH; i++)
can_free_echo_skb(ndev, i); can_free_echo_skb(ndev, i, NULL);
} }
static void rcar_can_error(struct net_device *ndev) static void rcar_can_error(struct net_device *ndev)
......
...@@ -617,7 +617,7 @@ static void rcar_canfd_tx_failure_cleanup(struct net_device *ndev) ...@@ -617,7 +617,7 @@ static void rcar_canfd_tx_failure_cleanup(struct net_device *ndev)
u32 i; u32 i;
for (i = 0; i < RCANFD_FIFO_DEPTH; i++) for (i = 0; i < RCANFD_FIFO_DEPTH; i++)
can_free_echo_skb(ndev, i); can_free_echo_skb(ndev, i, NULL);
} }
static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv) static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
......
...@@ -525,7 +525,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) ...@@ -525,7 +525,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT && if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT &&
!(status & SR_TCS)) { !(status & SR_TCS)) {
stats->tx_errors++; stats->tx_errors++;
can_free_echo_skb(dev, 0); can_free_echo_skb(dev, 0, NULL);
} else { } else {
/* transmission complete */ /* transmission complete */
stats->tx_bytes += stats->tx_bytes +=
......
...@@ -179,7 +179,7 @@ static void hi3110_clean(struct net_device *net) ...@@ -179,7 +179,7 @@ static void hi3110_clean(struct net_device *net)
net->stats.tx_errors++; net->stats.tx_errors++;
dev_kfree_skb(priv->tx_skb); dev_kfree_skb(priv->tx_skb);
if (priv->tx_len) if (priv->tx_len)
can_free_echo_skb(priv->net, 0); can_free_echo_skb(priv->net, 0, NULL);
priv->tx_skb = NULL; priv->tx_skb = NULL;
priv->tx_len = 0; priv->tx_len = 0;
} }
......
...@@ -276,7 +276,7 @@ static void mcp251x_clean(struct net_device *net) ...@@ -276,7 +276,7 @@ static void mcp251x_clean(struct net_device *net)
net->stats.tx_errors++; net->stats.tx_errors++;
dev_kfree_skb(priv->tx_skb); dev_kfree_skb(priv->tx_skb);
if (priv->tx_len) if (priv->tx_len)
can_free_echo_skb(priv->net, 0); can_free_echo_skb(priv->net, 0, NULL);
priv->tx_skb = NULL; priv->tx_skb = NULL;
priv->tx_len = 0; priv->tx_len = 0;
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
config CAN_MCP251XFD config CAN_MCP251XFD
tristate "Microchip MCP251xFD SPI CAN controllers" tristate "Microchip MCP251xFD SPI CAN controllers"
select REGMAP select REGMAP
select WANT_DEV_COREDUMP
help help
Driver for the Microchip MCP251XFD SPI FD-CAN controller Driver for the Microchip MCP251XFD SPI FD-CAN controller
family. family.
......
...@@ -6,3 +6,6 @@ mcp251xfd-objs := ...@@ -6,3 +6,6 @@ mcp251xfd-objs :=
mcp251xfd-objs += mcp251xfd-core.o mcp251xfd-objs += mcp251xfd-core.o
mcp251xfd-objs += mcp251xfd-crc16.o mcp251xfd-objs += mcp251xfd-crc16.o
mcp251xfd-objs += mcp251xfd-regmap.o mcp251xfd-objs += mcp251xfd-regmap.o
mcp251xfd-objs += mcp251xfd-timestamp.o
mcp251xfd-$(CONFIG_DEV_COREDUMP) += mcp251xfd-dump.o
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// //
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver // mcp251xfd - Microchip MCP251xFD Family CAN controller driver
// //
// Copyright (c) 2019, 2020 Pengutronix, // Copyright (c) 2019, 2020, 2021 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de> // Marc Kleine-Budde <kernel@pengutronix.de>
// //
// Based on: // Based on:
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -330,6 +329,7 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv) ...@@ -330,6 +329,7 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
struct mcp251xfd_tx_ring *tx_ring; struct mcp251xfd_tx_ring *tx_ring;
struct mcp251xfd_rx_ring *rx_ring, *prev_rx_ring = NULL; struct mcp251xfd_rx_ring *rx_ring, *prev_rx_ring = NULL;
struct mcp251xfd_tx_obj *tx_obj; struct mcp251xfd_tx_obj *tx_obj;
struct spi_transfer *xfer;
u32 val; u32 val;
u16 addr; u16 addr;
u8 len; u8 len;
...@@ -347,8 +347,6 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv) ...@@ -347,8 +347,6 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
addr, val, val); addr, val, val);
for (j = 0; j < ARRAY_SIZE(tef_ring->uinc_xfer); j++) { for (j = 0; j < ARRAY_SIZE(tef_ring->uinc_xfer); j++) {
struct spi_transfer *xfer;
xfer = &tef_ring->uinc_xfer[j]; xfer = &tef_ring->uinc_xfer[j];
xfer->tx_buf = &tef_ring->uinc_buf; xfer->tx_buf = &tef_ring->uinc_buf;
xfer->len = len; xfer->len = len;
...@@ -357,6 +355,15 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv) ...@@ -357,6 +355,15 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
} }
/* "cs_change == 1" on the last transfer results in an active
* chip select after the complete SPI message. This causes the
* controller to interpret the next register access as
* data. Set "cs_change" of the last transfer to "0" to
* properly deactivate the chip select at the end of the
* message.
*/
xfer->cs_change = 0;
/* TX */ /* TX */
tx_ring = priv->tx; tx_ring = priv->tx;
tx_ring->head = 0; tx_ring->head = 0;
...@@ -397,8 +404,6 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv) ...@@ -397,8 +404,6 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
addr, val, val); addr, val, val);
for (j = 0; j < ARRAY_SIZE(rx_ring->uinc_xfer); j++) { for (j = 0; j < ARRAY_SIZE(rx_ring->uinc_xfer); j++) {
struct spi_transfer *xfer;
xfer = &rx_ring->uinc_xfer[j]; xfer = &rx_ring->uinc_xfer[j];
xfer->tx_buf = &rx_ring->uinc_buf; xfer->tx_buf = &rx_ring->uinc_buf;
xfer->len = len; xfer->len = len;
...@@ -406,6 +411,15 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv) ...@@ -406,6 +411,15 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
xfer->cs_change_delay.value = 0; xfer->cs_change_delay.value = 0;
xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
} }
/* "cs_change == 1" on the last transfer results in an
* active chip select after the complete SPI
* message. This causes the controller to interpret
* the next register access as data. Set "cs_change"
* of the last transfer to "0" to properly deactivate
* the chip select at the end of the message.
*/
xfer->cs_change = 0;
} }
} }
...@@ -1097,6 +1111,7 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv) ...@@ -1097,6 +1111,7 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv)
return 0; return 0;
out_chip_stop: out_chip_stop:
mcp251xfd_dump(priv);
mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED); mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
return err; return err;
...@@ -1250,7 +1265,8 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv, ...@@ -1250,7 +1265,8 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
const struct mcp251xfd_hw_tef_obj *hw_tef_obj) const struct mcp251xfd_hw_tef_obj *hw_tef_obj)
{ {
struct net_device_stats *stats = &priv->ndev->stats; struct net_device_stats *stats = &priv->ndev->stats;
u32 seq, seq_masked, tef_tail_masked; struct sk_buff *skb;
u32 seq, seq_masked, tef_tail_masked, tef_tail;
seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK, seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK,
hw_tef_obj->flags); hw_tef_obj->flags);
...@@ -1266,9 +1282,13 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv, ...@@ -1266,9 +1282,13 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
if (seq_masked != tef_tail_masked) if (seq_masked != tef_tail_masked)
return mcp251xfd_handle_tefif_recover(priv, seq); return mcp251xfd_handle_tefif_recover(priv, seq);
tef_tail = mcp251xfd_get_tef_tail(priv);
skb = priv->can.echo_skb[tef_tail];
if (skb)
mcp251xfd_skb_set_timestamp(priv, skb, hw_tef_obj->ts);
stats->tx_bytes += stats->tx_bytes +=
can_rx_offload_get_echo_skb(&priv->offload, can_rx_offload_get_echo_skb(&priv->offload,
mcp251xfd_get_tef_tail(priv), tef_tail,
hw_tef_obj->ts, NULL); hw_tef_obj->ts, NULL);
stats->tx_packets++; stats->tx_packets++;
priv->tef->tail++; priv->tef->tail++;
...@@ -1365,25 +1385,20 @@ static int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv) ...@@ -1365,25 +1385,20 @@ static int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
if (len) { if (len) {
struct mcp251xfd_tef_ring *ring = priv->tef; struct mcp251xfd_tef_ring *ring = priv->tef;
struct mcp251xfd_tx_ring *tx_ring = priv->tx; struct mcp251xfd_tx_ring *tx_ring = priv->tx;
struct spi_transfer *last_xfer; int offset;
/* Increment the TEF FIFO tail pointer 'len' times in /* Increment the TEF FIFO tail pointer 'len' times in
* a single SPI message. * a single SPI message.
* *
* Note: * Note:
* * Calculate offset, so that the SPI transfer ends on
* "cs_change == 1" on the last transfer results in an * the last message of the uinc_xfer array, which has
* active chip select after the complete SPI * "cs_change == 0", to properly deactivate the chip
* message. This causes the controller to interpret * select.
* the next register access as data. Temporary set
* "cs_change" of the last transfer to "0" to properly
* deactivate the chip select at the end of the
* message.
*/ */
last_xfer = &ring->uinc_xfer[len - 1]; offset = ARRAY_SIZE(ring->uinc_xfer) - len;
last_xfer->cs_change = 0; err = spi_sync_transfer(priv->spi,
err = spi_sync_transfer(priv->spi, ring->uinc_xfer, len); ring->uinc_xfer + offset, len);
last_xfer->cs_change = 1;
if (err) if (err)
return err; return err;
...@@ -1432,7 +1447,7 @@ mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv, ...@@ -1432,7 +1447,7 @@ mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv,
} }
static void static void
mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv, mcp251xfd_hw_rx_obj_to_skb(struct mcp251xfd_priv *priv,
const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj, const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -1475,6 +1490,8 @@ mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv, ...@@ -1475,6 +1490,8 @@ mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv,
if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR)) if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR))
memcpy(cfd->data, hw_rx_obj->data, cfd->len); memcpy(cfd->data, hw_rx_obj->data, cfd->len);
mcp251xfd_skb_set_timestamp(priv, skb, hw_rx_obj->ts);
} }
static int static int
...@@ -1535,7 +1552,7 @@ mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv, ...@@ -1535,7 +1552,7 @@ mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
return err; return err;
while ((len = mcp251xfd_get_rx_linear_len(ring))) { while ((len = mcp251xfd_get_rx_linear_len(ring))) {
struct spi_transfer *last_xfer; int offset;
rx_tail = mcp251xfd_get_rx_tail(ring); rx_tail = mcp251xfd_get_rx_tail(ring);
...@@ -1556,19 +1573,14 @@ mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv, ...@@ -1556,19 +1573,14 @@ mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
* single SPI message. * single SPI message.
* *
* Note: * Note:
* * Calculate offset, so that the SPI transfer ends on
* "cs_change == 1" on the last transfer results in an * the last message of the uinc_xfer array, which has
* active chip select after the complete SPI * "cs_change == 0", to properly deactivate the chip
* message. This causes the controller to interpret * select.
* the next register access as data. Temporary set
* "cs_change" of the last transfer to "0" to properly
* deactivate the chip select at the end of the
* message.
*/ */
last_xfer = &ring->uinc_xfer[len - 1]; offset = ARRAY_SIZE(ring->uinc_xfer) - len;
last_xfer->cs_change = 0; err = spi_sync_transfer(priv->spi,
err = spi_sync_transfer(priv->spi, ring->uinc_xfer, len); ring->uinc_xfer + offset, len);
last_xfer->cs_change = 1;
if (err) if (err)
return err; return err;
...@@ -1592,23 +1604,22 @@ static int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv) ...@@ -1592,23 +1604,22 @@ static int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
return 0; return 0;
} }
static inline int mcp251xfd_get_timestamp(const struct mcp251xfd_priv *priv,
u32 *timestamp)
{
return regmap_read(priv->map_reg, MCP251XFD_REG_TBC, timestamp);
}
static struct sk_buff * static struct sk_buff *
mcp251xfd_alloc_can_err_skb(const struct mcp251xfd_priv *priv, mcp251xfd_alloc_can_err_skb(struct mcp251xfd_priv *priv,
struct can_frame **cf, u32 *timestamp) struct can_frame **cf, u32 *timestamp)
{ {
struct sk_buff *skb;
int err; int err;
err = mcp251xfd_get_timestamp(priv, timestamp); err = mcp251xfd_get_timestamp(priv, timestamp);
if (err) if (err)
return NULL; return NULL;
return alloc_can_err_skb(priv->ndev, cf); skb = alloc_can_err_skb(priv->ndev, cf);
if (skb)
mcp251xfd_skb_set_timestamp(priv, skb, *timestamp);
return skb;
} }
static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv) static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv)
...@@ -1760,6 +1771,7 @@ static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv) ...@@ -1760,6 +1771,7 @@ static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv)
if (!cf) if (!cf)
return 0; return 0;
mcp251xfd_skb_set_timestamp(priv, skb, timestamp);
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
if (err) if (err)
stats->rx_fifo_errors++; stats->rx_fifo_errors++;
...@@ -2277,6 +2289,7 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id) ...@@ -2277,6 +2289,7 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
out_fail: out_fail:
netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n", netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n",
err, priv->regs_status.intf); err, priv->regs_status.intf);
mcp251xfd_dump(priv);
mcp251xfd_chip_interrupts_disable(priv); mcp251xfd_chip_interrupts_disable(priv);
return handled; return handled;
...@@ -2493,6 +2506,7 @@ static int mcp251xfd_open(struct net_device *ndev) ...@@ -2493,6 +2506,7 @@ static int mcp251xfd_open(struct net_device *ndev)
if (err) if (err)
goto out_transceiver_disable; goto out_transceiver_disable;
mcp251xfd_timestamp_init(priv);
can_rx_offload_enable(&priv->offload); can_rx_offload_enable(&priv->offload);
err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq, err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq,
...@@ -2513,6 +2527,7 @@ static int mcp251xfd_open(struct net_device *ndev) ...@@ -2513,6 +2527,7 @@ static int mcp251xfd_open(struct net_device *ndev)
free_irq(spi->irq, priv); free_irq(spi->irq, priv);
out_can_rx_offload_disable: out_can_rx_offload_disable:
can_rx_offload_disable(&priv->offload); can_rx_offload_disable(&priv->offload);
mcp251xfd_timestamp_stop(priv);
out_transceiver_disable: out_transceiver_disable:
mcp251xfd_transceiver_disable(priv); mcp251xfd_transceiver_disable(priv);
out_mcp251xfd_ring_free: out_mcp251xfd_ring_free:
...@@ -2534,6 +2549,7 @@ static int mcp251xfd_stop(struct net_device *ndev) ...@@ -2534,6 +2549,7 @@ static int mcp251xfd_stop(struct net_device *ndev)
mcp251xfd_chip_interrupts_disable(priv); mcp251xfd_chip_interrupts_disable(priv);
free_irq(ndev->irq, priv); free_irq(ndev->irq, priv);
can_rx_offload_disable(&priv->offload); can_rx_offload_disable(&priv->offload);
mcp251xfd_timestamp_stop(priv);
mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED); mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
mcp251xfd_transceiver_disable(priv); mcp251xfd_transceiver_disable(priv);
mcp251xfd_ring_free(priv); mcp251xfd_ring_free(priv);
......
// SPDX-License-Identifier: GPL-2.0
//
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
//
// Copyright (c) 2020, 2021 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de>
// Copyright (C) 2015-2018 Etnaviv Project
//
#include <linux/devcoredump.h>
#include "mcp251xfd.h"
#include "mcp251xfd-dump.h"
struct mcp251xfd_dump_iter {
void *start;
struct mcp251xfd_dump_object_header *hdr;
void *data;
};
struct mcp251xfd_dump_reg_space {
u16 base;
u16 size;
};
struct mcp251xfd_dump_ring {
enum mcp251xfd_dump_object_ring_key key;
u32 val;
};
static const struct mcp251xfd_dump_reg_space mcp251xfd_dump_reg_space[] = {
{
.base = MCP251XFD_REG_CON,
.size = MCP251XFD_REG_FLTOBJ(32) - MCP251XFD_REG_CON,
}, {
.base = MCP251XFD_RAM_START,
.size = MCP251XFD_RAM_SIZE,
}, {
.base = MCP251XFD_REG_OSC,
.size = MCP251XFD_REG_DEVID - MCP251XFD_REG_OSC,
},
};
static void mcp251xfd_dump_header(struct mcp251xfd_dump_iter *iter,
enum mcp251xfd_dump_object_type object_type,
const void *data_end)
{
struct mcp251xfd_dump_object_header *hdr = iter->hdr;
unsigned int len;
len = data_end - iter->data;
if (!len)
return;
hdr->magic = cpu_to_le32(MCP251XFD_DUMP_MAGIC);
hdr->type = cpu_to_le32(object_type);
hdr->offset = cpu_to_le32(iter->data - iter->start);
hdr->len = cpu_to_le32(len);
iter->hdr++;
iter->data += len;
}
static void mcp251xfd_dump_registers(const struct mcp251xfd_priv *priv,
struct mcp251xfd_dump_iter *iter)
{
const int val_bytes = regmap_get_val_bytes(priv->map_rx);
struct mcp251xfd_dump_object_reg *reg = iter->data;
unsigned int i, j;
int err;
for (i = 0; i < ARRAY_SIZE(mcp251xfd_dump_reg_space); i++) {
const struct mcp251xfd_dump_reg_space *reg_space;
void *buf;
reg_space = &mcp251xfd_dump_reg_space[i];
buf = kmalloc(reg_space->size, GFP_KERNEL);
if (!buf)
goto out;
err = regmap_bulk_read(priv->map_reg, reg_space->base,
buf, reg_space->size / val_bytes);
if (err) {
kfree(buf);
continue;
}
for (j = 0; j < reg_space->size; j += sizeof(u32), reg++) {
reg->reg = cpu_to_le32(reg_space->base + j);
reg->val = cpu_to_le32p(buf + j);
}
kfree(buf);
}
out:
mcp251xfd_dump_header(iter, MCP251XFD_DUMP_OBJECT_TYPE_REG, reg);
}
static void mcp251xfd_dump_ring(struct mcp251xfd_dump_iter *iter,
enum mcp251xfd_dump_object_type object_type,
const struct mcp251xfd_dump_ring *dump_ring,
unsigned int len)
{
struct mcp251xfd_dump_object_reg *reg = iter->data;
unsigned int i;
for (i = 0; i < len; i++, reg++) {
reg->reg = cpu_to_le32(dump_ring[i].key);
reg->val = cpu_to_le32(dump_ring[i].val);
}
mcp251xfd_dump_header(iter, object_type, reg);
}
static void mcp251xfd_dump_tef_ring(const struct mcp251xfd_priv *priv,
struct mcp251xfd_dump_iter *iter)
{
const struct mcp251xfd_tef_ring *tef = priv->tef;
const struct mcp251xfd_tx_ring *tx = priv->tx;
const struct mcp251xfd_dump_ring dump_ring[] = {
{
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
.val = tef->head,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
.val = tef->tail,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
.val = 0,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
.val = 0,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
.val = 0,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
.val = tx->obj_num,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
.val = sizeof(struct mcp251xfd_hw_tef_obj),
},
};
mcp251xfd_dump_ring(iter, MCP251XFD_DUMP_OBJECT_TYPE_TEF,
dump_ring, ARRAY_SIZE(dump_ring));
}
static void mcp251xfd_dump_rx_ring_one(const struct mcp251xfd_priv *priv,
struct mcp251xfd_dump_iter *iter,
const struct mcp251xfd_rx_ring *rx)
{
const struct mcp251xfd_dump_ring dump_ring[] = {
{
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
.val = rx->head,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
.val = rx->tail,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
.val = rx->base,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
.val = rx->nr,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
.val = rx->fifo_nr,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
.val = rx->obj_num,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
.val = rx->obj_size,
},
};
mcp251xfd_dump_ring(iter, MCP251XFD_DUMP_OBJECT_TYPE_RX,
dump_ring, ARRAY_SIZE(dump_ring));
}
static void mcp251xfd_dump_rx_ring(const struct mcp251xfd_priv *priv,
struct mcp251xfd_dump_iter *iter)
{
struct mcp251xfd_rx_ring *rx_ring;
unsigned int i;
mcp251xfd_for_each_rx_ring(priv, rx_ring, i)
mcp251xfd_dump_rx_ring_one(priv, iter, rx_ring);
}
static void mcp251xfd_dump_tx_ring(const struct mcp251xfd_priv *priv,
struct mcp251xfd_dump_iter *iter)
{
const struct mcp251xfd_tx_ring *tx = priv->tx;
const struct mcp251xfd_dump_ring dump_ring[] = {
{
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
.val = tx->head,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
.val = tx->tail,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
.val = tx->base,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
.val = 0,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
.val = MCP251XFD_TX_FIFO,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
.val = tx->obj_num,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
.val = tx->obj_size,
},
};
mcp251xfd_dump_ring(iter, MCP251XFD_DUMP_OBJECT_TYPE_TX,
dump_ring, ARRAY_SIZE(dump_ring));
}
static void mcp251xfd_dump_end(const struct mcp251xfd_priv *priv,
struct mcp251xfd_dump_iter *iter)
{
struct mcp251xfd_dump_object_header *hdr = iter->hdr;
hdr->magic = cpu_to_le32(MCP251XFD_DUMP_MAGIC);
hdr->type = cpu_to_le32(MCP251XFD_DUMP_OBJECT_TYPE_END);
hdr->offset = cpu_to_le32(0);
hdr->len = cpu_to_le32(0);
/* provoke NULL pointer access, if used after END object */
iter->hdr = NULL;
}
void mcp251xfd_dump(const struct mcp251xfd_priv *priv)
{
struct mcp251xfd_dump_iter iter;
unsigned int rings_num, obj_num;
unsigned int file_size = 0;
unsigned int i;
/* register space + end marker */
obj_num = 2;
/* register space */
for (i = 0; i < ARRAY_SIZE(mcp251xfd_dump_reg_space); i++)
file_size += mcp251xfd_dump_reg_space[i].size / sizeof(u32) *
sizeof(struct mcp251xfd_dump_object_reg);
/* TEF ring, RX ring, TX rings */
rings_num = 1 + priv->rx_ring_num + 1;
obj_num += rings_num;
file_size += rings_num * __MCP251XFD_DUMP_OBJECT_RING_KEY_MAX *
sizeof(struct mcp251xfd_dump_object_reg);
/* size of the headers */
file_size += sizeof(*iter.hdr) * obj_num;
/* allocate the file in vmalloc memory, it's likely to be big */
iter.start = __vmalloc(file_size, GFP_KERNEL | __GFP_NOWARN |
__GFP_ZERO | __GFP_NORETRY);
if (!iter.start) {
netdev_warn(priv->ndev, "Failed to allocate devcoredump file.\n");
return;
}
/* point the data member after the headers */
iter.hdr = iter.start;
iter.data = &iter.hdr[obj_num];
mcp251xfd_dump_registers(priv, &iter);
mcp251xfd_dump_tef_ring(priv, &iter);
mcp251xfd_dump_rx_ring(priv, &iter);
mcp251xfd_dump_tx_ring(priv, &iter);
mcp251xfd_dump_end(priv, &iter);
dev_coredumpv(&priv->spi->dev, iter.start,
iter.data - iter.start, GFP_KERNEL);
}
/* SPDX-License-Identifier: GPL-2.0
*
* mcp251xfd - Microchip MCP251xFD Family CAN controller driver
*
* Copyright (c) 2019, 2020, 2021 Pengutronix,
* Marc Kleine-Budde <kernel@pengutronix.de>
*/
#ifndef _MCP251XFD_DUMP_H
#define _MCP251XFD_DUMP_H
#define MCP251XFD_DUMP_MAGIC 0x1825434d
enum mcp251xfd_dump_object_type {
MCP251XFD_DUMP_OBJECT_TYPE_REG,
MCP251XFD_DUMP_OBJECT_TYPE_TEF,
MCP251XFD_DUMP_OBJECT_TYPE_RX,
MCP251XFD_DUMP_OBJECT_TYPE_TX,
MCP251XFD_DUMP_OBJECT_TYPE_END = -1,
};
enum mcp251xfd_dump_object_ring_key {
MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
__MCP251XFD_DUMP_OBJECT_RING_KEY_MAX,
};
struct mcp251xfd_dump_object_header {
__le32 magic;
__le32 type;
__le32 offset;
__le32 len;
};
struct mcp251xfd_dump_object_reg {
__le32 reg;
__le32 val;
};
#endif
// SPDX-License-Identifier: GPL-2.0
//
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
//
// Copyright (c) 2021 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de>
//
#include <linux/clocksource.h>
#include <linux/workqueue.h>
#include "mcp251xfd.h"
static u64 mcp251xfd_timestamp_read(const struct cyclecounter *cc)
{
struct mcp251xfd_priv *priv;
u32 timestamp = 0;
int err;
priv = container_of(cc, struct mcp251xfd_priv, cc);
err = mcp251xfd_get_timestamp(priv, &timestamp);
if (err)
netdev_err(priv->ndev,
"Error %d while reading timestamp. HW timestamps may be inaccurate.",
err);
return timestamp;
}
static void mcp251xfd_timestamp_work(struct work_struct *work)
{
struct delayed_work *delayed_work = to_delayed_work(work);
struct mcp251xfd_priv *priv;
priv = container_of(delayed_work, struct mcp251xfd_priv, timestamp);
timecounter_read(&priv->tc);
schedule_delayed_work(&priv->timestamp,
MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ);
}
void mcp251xfd_skb_set_timestamp(struct mcp251xfd_priv *priv,
struct sk_buff *skb, u32 timestamp)
{
struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
u64 ns;
ns = timecounter_cyc2time(&priv->tc, timestamp);
hwtstamps->hwtstamp = ns_to_ktime(ns);
}
void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv)
{
struct cyclecounter *cc = &priv->cc;
cc->read = mcp251xfd_timestamp_read;
cc->mask = CYCLECOUNTER_MASK(32);
cc->shift = 1;
cc->mult = clocksource_hz2mult(priv->can.clock.freq, cc->shift);
timecounter_init(&priv->tc, &priv->cc, ktime_get_real_ns());
INIT_DELAYED_WORK(&priv->timestamp, mcp251xfd_timestamp_work);
schedule_delayed_work(&priv->timestamp,
MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ);
}
void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv)
{
cancel_delayed_work_sync(&priv->timestamp);
}
...@@ -15,9 +15,12 @@ ...@@ -15,9 +15,12 @@
#include <linux/can/rx-offload.h> #include <linux/can/rx-offload.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/timecounter.h>
#include <linux/workqueue.h>
/* MPC251x registers */ /* MPC251x registers */
...@@ -394,6 +397,9 @@ ...@@ -394,6 +397,9 @@
#define MCP251XFD_SYSCLOCK_HZ_MAX 40000000 #define MCP251XFD_SYSCLOCK_HZ_MAX 40000000
#define MCP251XFD_SYSCLOCK_HZ_MIN 1000000 #define MCP251XFD_SYSCLOCK_HZ_MIN 1000000
#define MCP251XFD_SPICLOCK_HZ_MAX 20000000 #define MCP251XFD_SPICLOCK_HZ_MAX 20000000
#define MCP251XFD_TIMESTAMP_WORK_DELAY_SEC 45
static_assert(MCP251XFD_TIMESTAMP_WORK_DELAY_SEC <
CYCLECOUNTER_MASK(32) / MCP251XFD_SYSCLOCK_HZ_MAX / 2);
#define MCP251XFD_OSC_PLL_MULTIPLIER 10 #define MCP251XFD_OSC_PLL_MULTIPLIER 10
#define MCP251XFD_OSC_STAB_SLEEP_US (3 * USEC_PER_MSEC) #define MCP251XFD_OSC_STAB_SLEEP_US (3 * USEC_PER_MSEC)
#define MCP251XFD_OSC_STAB_TIMEOUT_US (10 * MCP251XFD_OSC_STAB_SLEEP_US) #define MCP251XFD_OSC_STAB_TIMEOUT_US (10 * MCP251XFD_OSC_STAB_SLEEP_US)
...@@ -595,6 +601,10 @@ struct mcp251xfd_priv { ...@@ -595,6 +601,10 @@ struct mcp251xfd_priv {
struct mcp251xfd_ecc ecc; struct mcp251xfd_ecc ecc;
struct mcp251xfd_regs_status regs_status; struct mcp251xfd_regs_status regs_status;
struct cyclecounter cc;
struct timecounter tc;
struct delayed_work timestamp;
struct gpio_desc *rx_int; struct gpio_desc *rx_int;
struct clk *clk; struct clk *clk;
struct regulator *reg_vdd; struct regulator *reg_vdd;
...@@ -727,6 +737,12 @@ mcp251xfd_spi_cmd_write(const struct mcp251xfd_priv *priv, ...@@ -727,6 +737,12 @@ mcp251xfd_spi_cmd_write(const struct mcp251xfd_priv *priv,
return data; return data;
} }
static inline int mcp251xfd_get_timestamp(const struct mcp251xfd_priv *priv,
u32 *timestamp)
{
return regmap_read(priv->map_reg, MCP251XFD_REG_TBC, timestamp);
}
static inline u16 mcp251xfd_get_tef_obj_addr(u8 n) static inline u16 mcp251xfd_get_tef_obj_addr(u8 n)
{ {
return MCP251XFD_RAM_START + return MCP251XFD_RAM_START +
...@@ -837,5 +853,17 @@ int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv); ...@@ -837,5 +853,17 @@ int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv);
u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size, u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size,
const void *data, size_t data_size); const void *data, size_t data_size);
u16 mcp251xfd_crc16_compute(const void *data, size_t data_size); u16 mcp251xfd_crc16_compute(const void *data, size_t data_size);
void mcp251xfd_skb_set_timestamp(struct mcp251xfd_priv *priv,
struct sk_buff *skb, u32 timestamp);
void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv);
void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv);
#if IS_ENABLED(CONFIG_DEV_COREDUMP)
void mcp251xfd_dump(const struct mcp251xfd_priv *priv);
#else
static inline void mcp251xfd_dump(const struct mcp251xfd_priv *priv)
{
}
#endif
#endif #endif
...@@ -807,7 +807,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne ...@@ -807,7 +807,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
err = usb_submit_urb(urb, GFP_ATOMIC); err = usb_submit_urb(urb, GFP_ATOMIC);
if (unlikely(err)) { if (unlikely(err)) {
can_free_echo_skb(netdev, context->echo_index); can_free_echo_skb(netdev, context->echo_index, NULL);
usb_unanchor_urb(urb); usb_unanchor_urb(urb);
usb_free_coherent(dev->udev, size, buf, urb->transfer_dma); usb_free_coherent(dev->udev, size, buf, urb->transfer_dma);
......
...@@ -360,7 +360,7 @@ static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv, ...@@ -360,7 +360,7 @@ static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv,
can_get_echo_skb(netdev, context->echo_index, NULL); can_get_echo_skb(netdev, context->echo_index, NULL);
} else { } else {
stats->tx_errors++; stats->tx_errors++;
can_free_echo_skb(netdev, context->echo_index); can_free_echo_skb(netdev, context->echo_index, NULL);
} }
/* Release context */ /* Release context */
...@@ -793,7 +793,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb, ...@@ -793,7 +793,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
err = usb_submit_urb(urb, GFP_ATOMIC); err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) { if (err) {
can_free_echo_skb(netdev, context->echo_index); can_free_echo_skb(netdev, context->echo_index, NULL);
atomic_dec(&priv->active_tx_jobs); atomic_dec(&priv->active_tx_jobs);
usb_unanchor_urb(urb); usb_unanchor_urb(urb);
......
...@@ -533,7 +533,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, ...@@ -533,7 +533,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
if (unlikely(rc)) { /* usb send failed */ if (unlikely(rc)) { /* usb send failed */
atomic_dec(&dev->active_tx_urbs); atomic_dec(&dev->active_tx_urbs);
can_free_echo_skb(netdev, idx); can_free_echo_skb(netdev, idx, NULL);
gs_free_tx_context(txc); gs_free_tx_context(txc);
usb_unanchor_urb(urb); usb_unanchor_urb(urb);
......
...@@ -593,7 +593,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, ...@@ -593,7 +593,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
if (unlikely(err)) { if (unlikely(err)) {
spin_lock_irqsave(&priv->tx_contexts_lock, flags); spin_lock_irqsave(&priv->tx_contexts_lock, flags);
can_free_echo_skb(netdev, context->echo_index); can_free_echo_skb(netdev, context->echo_index, NULL);
context->echo_index = dev->max_tx_urbs; context->echo_index = dev->max_tx_urbs;
--priv->active_tx_contexts; --priv->active_tx_contexts;
netif_wake_queue(netdev); netif_wake_queue(netdev);
......
...@@ -364,7 +364,7 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb, ...@@ -364,7 +364,7 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK; return NETDEV_TX_OK;
xmit_failed: xmit_failed:
can_free_echo_skb(priv->netdev, ctx->ndx); can_free_echo_skb(priv->netdev, ctx->ndx, NULL);
mcba_usb_free_ctx(ctx); mcba_usb_free_ctx(ctx);
dev_kfree_skb(skb); dev_kfree_skb(skb);
stats->tx_dropped++; stats->tx_dropped++;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/ethtool.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
...@@ -40,6 +41,7 @@ ...@@ -40,6 +41,7 @@
#define PCAN_USB_CMD_REGISTER 9 #define PCAN_USB_CMD_REGISTER 9
#define PCAN_USB_CMD_EXT_VCC 10 #define PCAN_USB_CMD_EXT_VCC 10
#define PCAN_USB_CMD_ERR_FR 11 #define PCAN_USB_CMD_ERR_FR 11
#define PCAN_USB_CMD_LED 12
/* PCAN_USB_CMD_SET_BUS number arg */ /* PCAN_USB_CMD_SET_BUS number arg */
#define PCAN_USB_BUS_XCVER 2 #define PCAN_USB_BUS_XCVER 2
...@@ -248,6 +250,15 @@ static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff) ...@@ -248,6 +250,15 @@ static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff)
return pcan_usb_send_cmd(dev, PCAN_USB_CMD_EXT_VCC, PCAN_USB_SET, args); return pcan_usb_send_cmd(dev, PCAN_USB_CMD_EXT_VCC, PCAN_USB_SET, args);
} }
static int pcan_usb_set_led(struct peak_usb_device *dev, u8 onoff)
{
u8 args[PCAN_USB_CMD_ARGS_LEN] = {
[0] = !!onoff,
};
return pcan_usb_send_cmd(dev, PCAN_USB_CMD_LED, PCAN_USB_SET, args);
}
/* /*
* set bittiming value to can * set bittiming value to can
*/ */
...@@ -971,6 +982,40 @@ static int pcan_usb_probe(struct usb_interface *intf) ...@@ -971,6 +982,40 @@ static int pcan_usb_probe(struct usb_interface *intf)
return 0; return 0;
} }
static int pcan_usb_set_phys_id(struct net_device *netdev,
enum ethtool_phys_id_state state)
{
struct peak_usb_device *dev = netdev_priv(netdev);
int err = 0;
switch (state) {
case ETHTOOL_ID_ACTIVE:
/* call ON/OFF twice a second */
return 2;
case ETHTOOL_ID_OFF:
err = pcan_usb_set_led(dev, 0);
break;
case ETHTOOL_ID_ON:
fallthrough;
case ETHTOOL_ID_INACTIVE:
/* restore LED default */
err = pcan_usb_set_led(dev, 1);
break;
default:
break;
}
return err;
}
static const struct ethtool_ops pcan_usb_ethtool_ops = {
.set_phys_id = pcan_usb_set_phys_id,
};
/* /*
* describe the PCAN-USB adapter * describe the PCAN-USB adapter
*/ */
...@@ -1001,6 +1046,8 @@ const struct peak_usb_adapter pcan_usb = { ...@@ -1001,6 +1046,8 @@ const struct peak_usb_adapter pcan_usb = {
/* size of device private data */ /* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb), .sizeof_dev_private = sizeof(struct pcan_usb),
.ethtool_ops = &pcan_usb_ethtool_ops,
/* timestamps usage */ /* timestamps usage */
.ts_used_bits = 16, .ts_used_bits = 16,
.ts_period = 24575, /* calibration period in ts. */ .ts_period = 24575, /* calibration period in ts. */
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/ethtool.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
...@@ -371,7 +372,7 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb, ...@@ -371,7 +372,7 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb,
err = usb_submit_urb(urb, GFP_ATOMIC); err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) { if (err) {
can_free_echo_skb(netdev, context->echo_index); can_free_echo_skb(netdev, context->echo_index, NULL);
usb_unanchor_urb(urb); usb_unanchor_urb(urb);
...@@ -820,6 +821,9 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter, ...@@ -820,6 +821,9 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter,
netdev->flags |= IFF_ECHO; /* we support local echo */ netdev->flags |= IFF_ECHO; /* we support local echo */
/* add ethtool support */
netdev->ethtool_ops = peak_usb_adapter->ethtool_ops;
init_usb_anchor(&dev->rx_submitted); init_usb_anchor(&dev->rx_submitted);
init_usb_anchor(&dev->tx_submitted); init_usb_anchor(&dev->tx_submitted);
......
...@@ -46,6 +46,8 @@ struct peak_usb_adapter { ...@@ -46,6 +46,8 @@ struct peak_usb_adapter {
const struct can_bittiming_const * const data_bittiming_const; const struct can_bittiming_const * const data_bittiming_const;
unsigned int ctrl_count; unsigned int ctrl_count;
const struct ethtool_ops *ethtool_ops;
int (*intf_probe)(struct usb_interface *intf); int (*intf_probe)(struct usb_interface *intf);
int (*dev_init)(struct peak_usb_device *dev); int (*dev_init)(struct peak_usb_device *dev);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/ethtool.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
...@@ -773,6 +774,10 @@ static int pcan_usb_fd_encode_msg(struct peak_usb_device *dev, ...@@ -773,6 +774,10 @@ static int pcan_usb_fd_encode_msg(struct peak_usb_device *dev,
tx_msg_flags |= PUCAN_MSG_RTR; tx_msg_flags |= PUCAN_MSG_RTR;
} }
/* Single-Shot frame */
if (dev->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
tx_msg_flags |= PUCAN_MSG_SINGLE_SHOT;
tx_msg->flags = cpu_to_le16(tx_msg_flags); tx_msg->flags = cpu_to_le16(tx_msg_flags);
tx_msg->channel_dlc = PUCAN_MSG_CHANNEL_DLC(dev->ctrl_idx, dlc); tx_msg->channel_dlc = PUCAN_MSG_CHANNEL_DLC(dev->ctrl_idx, dlc);
memcpy(tx_msg->d, cfd->data, cfd->len); memcpy(tx_msg->d, cfd->data, cfd->len);
...@@ -1006,6 +1011,31 @@ static void pcan_usb_fd_free(struct peak_usb_device *dev) ...@@ -1006,6 +1011,31 @@ static void pcan_usb_fd_free(struct peak_usb_device *dev)
} }
} }
/* blink LED's */
static int pcan_usb_fd_set_phys_id(struct net_device *netdev,
enum ethtool_phys_id_state state)
{
struct peak_usb_device *dev = netdev_priv(netdev);
int err = 0;
switch (state) {
case ETHTOOL_ID_ACTIVE:
err = pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_FAST);
break;
case ETHTOOL_ID_INACTIVE:
err = pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_DEF);
break;
default:
break;
}
return err;
}
static const struct ethtool_ops pcan_usb_fd_ethtool_ops = {
.set_phys_id = pcan_usb_fd_set_phys_id,
};
/* describes the PCAN-USB FD adapter */ /* describes the PCAN-USB FD adapter */
static const struct can_bittiming_const pcan_usb_fd_const = { static const struct can_bittiming_const pcan_usb_fd_const = {
.name = "pcan_usb_fd", .name = "pcan_usb_fd",
...@@ -1037,7 +1067,7 @@ const struct peak_usb_adapter pcan_usb_fd = { ...@@ -1037,7 +1067,7 @@ const struct peak_usb_adapter pcan_usb_fd = {
.ctrl_count = PCAN_USBFD_CHANNEL_COUNT, .ctrl_count = PCAN_USBFD_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_FD | .ctrlmode_supported = CAN_CTRLMODE_FD |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_CC_LEN8_DLC, CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
.clock = { .clock = {
.freq = PCAN_UFD_CRYSTAL_HZ, .freq = PCAN_UFD_CRYSTAL_HZ,
}, },
...@@ -1047,6 +1077,8 @@ const struct peak_usb_adapter pcan_usb_fd = { ...@@ -1047,6 +1077,8 @@ const struct peak_usb_adapter pcan_usb_fd = {
/* size of device private data */ /* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_fd_device), .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
.ethtool_ops = &pcan_usb_fd_ethtool_ops,
/* timestamps usage */ /* timestamps usage */
.ts_used_bits = 32, .ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */ .ts_period = 1000000, /* calibration period in ts. */
...@@ -1110,7 +1142,7 @@ const struct peak_usb_adapter pcan_usb_chip = { ...@@ -1110,7 +1142,7 @@ const struct peak_usb_adapter pcan_usb_chip = {
.ctrl_count = PCAN_USBFD_CHANNEL_COUNT, .ctrl_count = PCAN_USBFD_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_FD | .ctrlmode_supported = CAN_CTRLMODE_FD |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_CC_LEN8_DLC, CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
.clock = { .clock = {
.freq = PCAN_UFD_CRYSTAL_HZ, .freq = PCAN_UFD_CRYSTAL_HZ,
}, },
...@@ -1120,6 +1152,8 @@ const struct peak_usb_adapter pcan_usb_chip = { ...@@ -1120,6 +1152,8 @@ const struct peak_usb_adapter pcan_usb_chip = {
/* size of device private data */ /* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_fd_device), .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
.ethtool_ops = &pcan_usb_fd_ethtool_ops,
/* timestamps usage */ /* timestamps usage */
.ts_used_bits = 32, .ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */ .ts_period = 1000000, /* calibration period in ts. */
...@@ -1183,7 +1217,7 @@ const struct peak_usb_adapter pcan_usb_pro_fd = { ...@@ -1183,7 +1217,7 @@ const struct peak_usb_adapter pcan_usb_pro_fd = {
.ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT, .ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_FD | .ctrlmode_supported = CAN_CTRLMODE_FD |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_CC_LEN8_DLC, CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
.clock = { .clock = {
.freq = PCAN_UFD_CRYSTAL_HZ, .freq = PCAN_UFD_CRYSTAL_HZ,
}, },
...@@ -1193,6 +1227,8 @@ const struct peak_usb_adapter pcan_usb_pro_fd = { ...@@ -1193,6 +1227,8 @@ const struct peak_usb_adapter pcan_usb_pro_fd = {
/* size of device private data */ /* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_fd_device), .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
.ethtool_ops = &pcan_usb_fd_ethtool_ops,
/* timestamps usage */ /* timestamps usage */
.ts_used_bits = 32, .ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */ .ts_period = 1000000, /* calibration period in ts. */
...@@ -1256,7 +1292,7 @@ const struct peak_usb_adapter pcan_usb_x6 = { ...@@ -1256,7 +1292,7 @@ const struct peak_usb_adapter pcan_usb_x6 = {
.ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT, .ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_FD | .ctrlmode_supported = CAN_CTRLMODE_FD |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_CC_LEN8_DLC, CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
.clock = { .clock = {
.freq = PCAN_UFD_CRYSTAL_HZ, .freq = PCAN_UFD_CRYSTAL_HZ,
}, },
...@@ -1266,6 +1302,8 @@ const struct peak_usb_adapter pcan_usb_x6 = { ...@@ -1266,6 +1302,8 @@ const struct peak_usb_adapter pcan_usb_x6 = {
/* size of device private data */ /* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_fd_device), .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
.ethtool_ops = &pcan_usb_fd_ethtool_ops,
/* timestamps usage */ /* timestamps usage */
.ts_used_bits = 32, .ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */ .ts_period = 1000000, /* calibration period in ts. */
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/ethtool.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
...@@ -36,6 +37,7 @@ ...@@ -36,6 +37,7 @@
#define PCAN_USBPRO_RTR 0x01 #define PCAN_USBPRO_RTR 0x01
#define PCAN_USBPRO_EXT 0x02 #define PCAN_USBPRO_EXT 0x02
#define PCAN_USBPRO_SS 0x08
#define PCAN_USBPRO_CMD_BUFFER_SIZE 512 #define PCAN_USBPRO_CMD_BUFFER_SIZE 512
...@@ -776,9 +778,13 @@ static int pcan_usb_pro_encode_msg(struct peak_usb_device *dev, ...@@ -776,9 +778,13 @@ static int pcan_usb_pro_encode_msg(struct peak_usb_device *dev,
flags = 0; flags = 0;
if (cf->can_id & CAN_EFF_FLAG) if (cf->can_id & CAN_EFF_FLAG)
flags |= 0x02; flags |= PCAN_USBPRO_EXT;
if (cf->can_id & CAN_RTR_FLAG) if (cf->can_id & CAN_RTR_FLAG)
flags |= 0x01; flags |= PCAN_USBPRO_RTR;
/* Single-Shot frame */
if (dev->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
flags |= PCAN_USBPRO_SS;
pcan_msg_add_rec(&usb_msg, data_type, 0, flags, len, cf->can_id, pcan_msg_add_rec(&usb_msg, data_type, 0, flags, len, cf->can_id,
cf->data); cf->data);
...@@ -906,7 +912,7 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev) ...@@ -906,7 +912,7 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev)
usb_if->dev[dev->ctrl_idx] = dev; usb_if->dev[dev->ctrl_idx] = dev;
/* set LED in default state (end of init phase) */ /* set LED in default state (end of init phase) */
pcan_usb_pro_set_led(dev, 0, 1); pcan_usb_pro_set_led(dev, PCAN_USBPRO_LED_DEVICE, 1);
kfree(bi); kfree(bi);
kfree(fi); kfree(fi);
...@@ -990,6 +996,35 @@ int pcan_usb_pro_probe(struct usb_interface *intf) ...@@ -990,6 +996,35 @@ int pcan_usb_pro_probe(struct usb_interface *intf)
return 0; return 0;
} }
static int pcan_usb_pro_set_phys_id(struct net_device *netdev,
enum ethtool_phys_id_state state)
{
struct peak_usb_device *dev = netdev_priv(netdev);
int err = 0;
switch (state) {
case ETHTOOL_ID_ACTIVE:
/* fast blinking forever */
err = pcan_usb_pro_set_led(dev, PCAN_USBPRO_LED_BLINK_FAST,
0xffffffff);
break;
case ETHTOOL_ID_INACTIVE:
/* restore LED default */
err = pcan_usb_pro_set_led(dev, PCAN_USBPRO_LED_DEVICE, 1);
break;
default:
break;
}
return err;
}
static const struct ethtool_ops pcan_usb_pro_ethtool_ops = {
.set_phys_id = pcan_usb_pro_set_phys_id,
};
/* /*
* describe the PCAN-USB Pro adapter * describe the PCAN-USB Pro adapter
*/ */
...@@ -1009,7 +1044,8 @@ const struct peak_usb_adapter pcan_usb_pro = { ...@@ -1009,7 +1044,8 @@ const struct peak_usb_adapter pcan_usb_pro = {
.name = "PCAN-USB Pro", .name = "PCAN-USB Pro",
.device_id = PCAN_USBPRO_PRODUCT_ID, .device_id = PCAN_USBPRO_PRODUCT_ID,
.ctrl_count = PCAN_USBPRO_CHANNEL_COUNT, .ctrl_count = PCAN_USBPRO_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY, .ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_ONE_SHOT,
.clock = { .clock = {
.freq = PCAN_USBPRO_CRYSTAL_HZ, .freq = PCAN_USBPRO_CRYSTAL_HZ,
}, },
...@@ -1018,6 +1054,8 @@ const struct peak_usb_adapter pcan_usb_pro = { ...@@ -1018,6 +1054,8 @@ const struct peak_usb_adapter pcan_usb_pro = {
/* size of device private data */ /* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_pro_device), .sizeof_dev_private = sizeof(struct pcan_usb_pro_device),
.ethtool_ops = &pcan_usb_pro_ethtool_ops,
/* timestamps usage */ /* timestamps usage */
.ts_used_bits = 32, .ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */ .ts_period = 1000000, /* calibration period in ts. */
......
...@@ -115,6 +115,12 @@ struct __packed pcan_usb_pro_devid { ...@@ -115,6 +115,12 @@ struct __packed pcan_usb_pro_devid {
__le32 serial_num; __le32 serial_num;
}; };
#define PCAN_USBPRO_LED_DEVICE 0x00
#define PCAN_USBPRO_LED_BLINK_FAST 0x01
#define PCAN_USBPRO_LED_BLINK_SLOW 0x02
#define PCAN_USBPRO_LED_ON 0x03
#define PCAN_USBPRO_LED_OFF 0x04
struct __packed pcan_usb_pro_setled { struct __packed pcan_usb_pro_setled {
u8 data_type; u8 data_type;
u8 channel; u8 channel;
......
...@@ -246,7 +246,7 @@ struct ucan_message_in { ...@@ -246,7 +246,7 @@ struct ucan_message_in {
*/ */
struct ucan_tx_complete_entry_t can_tx_complete_msg[0]; struct ucan_tx_complete_entry_t can_tx_complete_msg[0];
} __aligned(0x4) msg; } __aligned(0x4) msg;
} __packed; } __packed __aligned(0x4);
/* Macros to calculate message lengths */ /* Macros to calculate message lengths */
#define UCAN_OUT_HDR_SIZE offsetof(struct ucan_message_out, msg) #define UCAN_OUT_HDR_SIZE offsetof(struct ucan_message_out, msg)
...@@ -675,7 +675,7 @@ static void ucan_tx_complete_msg(struct ucan_priv *up, ...@@ -675,7 +675,7 @@ static void ucan_tx_complete_msg(struct ucan_priv *up,
can_get_echo_skb(up->netdev, echo_index, NULL); can_get_echo_skb(up->netdev, echo_index, NULL);
} else { } else {
up->netdev->stats.tx_dropped++; up->netdev->stats.tx_dropped++;
can_free_echo_skb(up->netdev, echo_index); can_free_echo_skb(up->netdev, echo_index, NULL);
} }
spin_unlock_irqrestore(&up->echo_skb_lock, flags); spin_unlock_irqrestore(&up->echo_skb_lock, flags);
} }
...@@ -843,7 +843,7 @@ static void ucan_write_bulk_callback(struct urb *urb) ...@@ -843,7 +843,7 @@ static void ucan_write_bulk_callback(struct urb *urb)
/* update counters an cleanup */ /* update counters an cleanup */
spin_lock_irqsave(&up->echo_skb_lock, flags); spin_lock_irqsave(&up->echo_skb_lock, flags);
can_free_echo_skb(up->netdev, context - up->context_array); can_free_echo_skb(up->netdev, context - up->context_array, NULL);
spin_unlock_irqrestore(&up->echo_skb_lock, flags); spin_unlock_irqrestore(&up->echo_skb_lock, flags);
up->netdev->stats.tx_dropped++; up->netdev->stats.tx_dropped++;
...@@ -1157,7 +1157,7 @@ static netdev_tx_t ucan_start_xmit(struct sk_buff *skb, ...@@ -1157,7 +1157,7 @@ static netdev_tx_t ucan_start_xmit(struct sk_buff *skb,
* frees the skb * frees the skb
*/ */
spin_lock_irqsave(&up->echo_skb_lock, flags); spin_lock_irqsave(&up->echo_skb_lock, flags);
can_free_echo_skb(up->netdev, echo_index); can_free_echo_skb(up->netdev, echo_index, NULL);
spin_unlock_irqrestore(&up->echo_skb_lock, flags); spin_unlock_irqrestore(&up->echo_skb_lock, flags);
if (ret == -ENODEV) { if (ret == -ENODEV) {
......
...@@ -691,7 +691,7 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb, ...@@ -691,7 +691,7 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
failed: failed:
can_free_echo_skb(netdev, context->echo_index); can_free_echo_skb(netdev, context->echo_index, NULL);
usb_unanchor_urb(urb); usb_unanchor_urb(urb);
usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
......
...@@ -1772,17 +1772,15 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1772,17 +1772,15 @@ static int xcan_probe(struct platform_device *pdev)
/* Getting the CAN can_clk info */ /* Getting the CAN can_clk info */
priv->can_clk = devm_clk_get(&pdev->dev, "can_clk"); priv->can_clk = devm_clk_get(&pdev->dev, "can_clk");
if (IS_ERR(priv->can_clk)) { if (IS_ERR(priv->can_clk)) {
if (PTR_ERR(priv->can_clk) != -EPROBE_DEFER) ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->can_clk),
dev_err(&pdev->dev, "Device clock not found.\n"); "device clock not found\n");
ret = PTR_ERR(priv->can_clk);
goto err_free; goto err_free;
} }
priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name); priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name);
if (IS_ERR(priv->bus_clk)) { if (IS_ERR(priv->bus_clk)) {
if (PTR_ERR(priv->bus_clk) != -EPROBE_DEFER) ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->bus_clk),
dev_err(&pdev->dev, "bus clock not found\n"); "bus clock not found\n");
ret = PTR_ERR(priv->bus_clk);
goto err_free; goto err_free;
} }
......
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2020 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de> /* Copyright (c) 2020 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
* Copyright (c) 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
*/ */
#ifndef _CAN_BITTIMING_H #ifndef _CAN_BITTIMING_H
...@@ -10,9 +11,83 @@ ...@@ -10,9 +11,83 @@
#define CAN_SYNC_SEG 1 #define CAN_SYNC_SEG 1
/* Kilobits and Megabits per second */
#define CAN_KBPS 1000UL
#define CAN_MBPS 1000000UL
/* Megahertz */
#define CAN_MHZ 1000000UL
/*
* struct can_tdc - CAN FD Transmission Delay Compensation parameters
*
* At high bit rates, the propagation delay from the TX pin to the RX
* pin of the transceiver causes measurement errors: the sample point
* on the RX pin might occur on the previous bit.
*
* To solve this issue, ISO 11898-1 introduces in section 11.3.3
* "Transmitter delay compensation" a SSP (Secondary Sample Point)
* equal to the distance, in time quanta, from the start of the bit
* time on the TX pin to the actual measurement on the RX pin.
*
* This structure contains the parameters to calculate that SSP.
*
* @tdcv: Transmitter Delay Compensation Value. Distance, in time
* quanta, from when the bit is sent on the TX pin to when it is
* received on the RX pin of the transmitter. Possible options:
*
* O: automatic mode. The controller dynamically measure @tdcv
* for each transmitted CAN FD frame.
*
* Other values: manual mode. Use the fixed provided value.
*
* @tdco: Transmitter Delay Compensation Offset. Offset value, in time
* quanta, defining the distance between the start of the bit
* reception on the RX pin of the transceiver and the SSP
* position such as SSP = @tdcv + @tdco.
*
* If @tdco is zero, then TDC is disabled and both @tdcv and
* @tdcf should be ignored.
*
* @tdcf: Transmitter Delay Compensation Filter window. Defines the
* minimum value for the SSP position in time quanta. If SSP is
* less than @tdcf, then no delay compensations occur and the
* normal sampling point is used instead. The feature is enabled
* if and only if @tdcv is set to zero (automatic mode) and @tdcf
* is configured to a value greater than @tdco.
*/
struct can_tdc {
u32 tdcv;
u32 tdco;
u32 tdcf;
};
/*
* struct can_tdc_const - CAN hardware-dependent constant for
* Transmission Delay Compensation
*
* @tdcv_max: Transmitter Delay Compensation Value maximum value.
* Should be set to zero if the controller does not support
* manual mode for tdcv.
* @tdco_max: Transmitter Delay Compensation Offset maximum value.
* Should not be zero. If the controller does not support TDC,
* then the pointer to this structure should be NULL.
* @tdcf_max: Transmitter Delay Compensation Filter window maximum
* value. Should be set to zero if the controller does not
* support this feature.
*/
struct can_tdc_const {
u32 tdcv_max;
u32 tdco_max;
u32 tdcf_max;
};
#ifdef CONFIG_CAN_CALC_BITTIMING #ifdef CONFIG_CAN_CALC_BITTIMING
int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
const struct can_bittiming_const *btc); const struct can_bittiming_const *btc);
void can_calc_tdco(struct net_device *dev);
#else /* !CONFIG_CAN_CALC_BITTIMING */ #else /* !CONFIG_CAN_CALC_BITTIMING */
static inline int static inline int
can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
...@@ -21,6 +96,10 @@ can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, ...@@ -21,6 +96,10 @@ can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
netdev_err(dev, "bit-timing calculation not available\n"); netdev_err(dev, "bit-timing calculation not available\n");
return -EINVAL; return -EINVAL;
} }
static inline void can_calc_tdco(struct net_device *dev)
{
}
#endif /* CONFIG_CAN_CALC_BITTIMING */ #endif /* CONFIG_CAN_CALC_BITTIMING */
int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt, int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
......
...@@ -39,19 +39,23 @@ struct can_priv { ...@@ -39,19 +39,23 @@ struct can_priv {
struct net_device *dev; struct net_device *dev;
struct can_device_stats can_stats; struct can_device_stats can_stats;
struct can_bittiming bittiming, data_bittiming;
const struct can_bittiming_const *bittiming_const, const struct can_bittiming_const *bittiming_const,
*data_bittiming_const; *data_bittiming_const;
const u16 *termination_const; struct can_bittiming bittiming, data_bittiming;
unsigned int termination_const_cnt; const struct can_tdc_const *tdc_const;
u16 termination; struct can_tdc tdc;
const u32 *bitrate_const;
unsigned int bitrate_const_cnt; unsigned int bitrate_const_cnt;
const u32 *bitrate_const;
const u32 *data_bitrate_const; const u32 *data_bitrate_const;
unsigned int data_bitrate_const_cnt; unsigned int data_bitrate_const_cnt;
u32 bitrate_max; u32 bitrate_max;
struct can_clock clock; struct can_clock clock;
unsigned int termination_const_cnt;
const u16 *termination_const;
u16 termination;
enum can_state state; enum can_state state;
/* CAN controller features - see include/uapi/linux/can/netlink.h */ /* CAN controller features - see include/uapi/linux/can/netlink.h */
......
...@@ -23,7 +23,8 @@ struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx, ...@@ -23,7 +23,8 @@ struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx,
u8 *len_ptr, unsigned int *frame_len_ptr); u8 *len_ptr, unsigned int *frame_len_ptr);
unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx, unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx,
unsigned int *frame_len_ptr); unsigned int *frame_len_ptr);
void can_free_echo_skb(struct net_device *dev, unsigned int idx); void can_free_echo_skb(struct net_device *dev, unsigned int idx,
unsigned int *frame_len_ptr);
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf); struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf);
struct sk_buff *alloc_canfd_skb(struct net_device *dev, struct sk_buff *alloc_canfd_skb(struct net_device *dev,
struct canfd_frame **cfd); struct canfd_frame **cfd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment