mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 16:44:58 +02:00
linux-can-fixes-for-6.15-20250521
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEn/sM2K9nqF/8FWzzDHRl3/mQkZwFAmgtivcTHG1rbEBwZW5n dXRyb25peC5kZQAKCRAMdGXf+ZCRnHdfB/9xpi2QMYgjWn5CWHaRT5JAt1BTVTAW g7W1iddSkw18T/+FalxSjYPZKoE+6k2AcI/VTLbjEnv4bOPlmE48dItB8WsQnwHc 1Jjbvc861HTYL51UuYH3oqXH4MrY2BiPk2aoCOuT7vPDsn/PISbfIZ41eBK3noTS TCY3DLV7u6tnureaCqGnl2M9lBfgF86rtn+d5vza2IFDu49b2J+Cv41CRkEIbP9P kujiCAxStN+neCKd1LtZgFbmfy63xUujPtZR2h0oYiOK9X/Nz2bjmFu40zyC+vCn z9P0oSXx2yaJCHiDrdzMM1McHhdpU4rNjVlYMKFQBNy/WfEvFHt+Eydy =dV2M -----END PGP SIGNATURE----- Merge tag 'linux-can-fixes-for-6.15-20250521' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can Marc Kleine-Budde says: ==================== pull-request: can 2025-05-22 this is a pull request of 4 patches for net/main. The first 3 patches are by Axel Forsman and fix a ISR race condition in the kvaser_pciefd driver. The last patch is by Carlos Sanchez and fixes the reception of short error messages in the slcan driver. * tag 'linux-can-fixes-for-6.15-20250521' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can: can: slcan: allow reception of short error messages can: kvaser_pciefd: Continue parsing DMA buf after dropped RX can: kvaser_pciefd: Fix echo_skb race can: kvaser_pciefd: Force IRQ edge in case of nested IRQ ==================== Link: https://patch.msgid.link/20250522082344.490913-1-mkl@pengutronix.de Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
3fab2d2d90
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/netdevice.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/timer.h>
|
||||
#include <net/netdev_queues.h>
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_AUTHOR("Kvaser AB <support@kvaser.com>");
|
||||
|
|
@ -410,10 +411,13 @@ struct kvaser_pciefd_can {
|
|||
void __iomem *reg_base;
|
||||
struct can_berr_counter bec;
|
||||
u8 cmd_seq;
|
||||
u8 tx_max_count;
|
||||
u8 tx_idx;
|
||||
u8 ack_idx;
|
||||
int err_rep_cnt;
|
||||
int echo_idx;
|
||||
unsigned int completed_tx_pkts;
|
||||
unsigned int completed_tx_bytes;
|
||||
spinlock_t lock; /* Locks sensitive registers (e.g. MODE) */
|
||||
spinlock_t echo_lock; /* Locks the message echo buffer */
|
||||
struct timer_list bec_poll_timer;
|
||||
struct completion start_comp, flush_comp;
|
||||
};
|
||||
|
|
@ -714,6 +718,9 @@ static int kvaser_pciefd_open(struct net_device *netdev)
|
|||
int ret;
|
||||
struct kvaser_pciefd_can *can = netdev_priv(netdev);
|
||||
|
||||
can->tx_idx = 0;
|
||||
can->ack_idx = 0;
|
||||
|
||||
ret = open_candev(netdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -745,21 +752,26 @@ static int kvaser_pciefd_stop(struct net_device *netdev)
|
|||
timer_delete(&can->bec_poll_timer);
|
||||
}
|
||||
can->can.state = CAN_STATE_STOPPED;
|
||||
netdev_reset_queue(netdev);
|
||||
close_candev(netdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int kvaser_pciefd_tx_avail(const struct kvaser_pciefd_can *can)
|
||||
{
|
||||
return can->tx_max_count - (READ_ONCE(can->tx_idx) - READ_ONCE(can->ack_idx));
|
||||
}
|
||||
|
||||
static int kvaser_pciefd_prepare_tx_packet(struct kvaser_pciefd_tx_packet *p,
|
||||
struct kvaser_pciefd_can *can,
|
||||
struct can_priv *can, u8 seq,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct canfd_frame *cf = (struct canfd_frame *)skb->data;
|
||||
int packet_size;
|
||||
int seq = can->echo_idx;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
if (can->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
|
||||
if (can->ctrlmode & CAN_CTRLMODE_ONE_SHOT)
|
||||
p->header[1] |= KVASER_PCIEFD_TPACKET_SMS;
|
||||
|
||||
if (cf->can_id & CAN_RTR_FLAG)
|
||||
|
|
@ -782,7 +794,7 @@ static int kvaser_pciefd_prepare_tx_packet(struct kvaser_pciefd_tx_packet *p,
|
|||
} else {
|
||||
p->header[1] |=
|
||||
FIELD_PREP(KVASER_PCIEFD_RPACKET_DLC_MASK,
|
||||
can_get_cc_dlc((struct can_frame *)cf, can->can.ctrlmode));
|
||||
can_get_cc_dlc((struct can_frame *)cf, can->ctrlmode));
|
||||
}
|
||||
|
||||
p->header[1] |= FIELD_PREP(KVASER_PCIEFD_PACKET_SEQ_MASK, seq);
|
||||
|
|
@ -797,22 +809,24 @@ static netdev_tx_t kvaser_pciefd_start_xmit(struct sk_buff *skb,
|
|||
struct net_device *netdev)
|
||||
{
|
||||
struct kvaser_pciefd_can *can = netdev_priv(netdev);
|
||||
unsigned long irq_flags;
|
||||
struct kvaser_pciefd_tx_packet packet;
|
||||
unsigned int seq = can->tx_idx & (can->can.echo_skb_max - 1);
|
||||
unsigned int frame_len;
|
||||
int nr_words;
|
||||
u8 count;
|
||||
|
||||
if (can_dev_dropped_skb(netdev, skb))
|
||||
return NETDEV_TX_OK;
|
||||
if (!netif_subqueue_maybe_stop(netdev, 0, kvaser_pciefd_tx_avail(can), 1, 1))
|
||||
return NETDEV_TX_BUSY;
|
||||
|
||||
nr_words = kvaser_pciefd_prepare_tx_packet(&packet, can, skb);
|
||||
nr_words = kvaser_pciefd_prepare_tx_packet(&packet, &can->can, seq, skb);
|
||||
|
||||
spin_lock_irqsave(&can->echo_lock, irq_flags);
|
||||
/* Prepare and save echo skb in internal slot */
|
||||
can_put_echo_skb(skb, netdev, can->echo_idx, 0);
|
||||
|
||||
/* Move echo index to the next slot */
|
||||
can->echo_idx = (can->echo_idx + 1) % can->can.echo_skb_max;
|
||||
WRITE_ONCE(can->can.echo_skb[seq], NULL);
|
||||
frame_len = can_skb_get_frame_len(skb);
|
||||
can_put_echo_skb(skb, netdev, seq, frame_len);
|
||||
netdev_sent_queue(netdev, frame_len);
|
||||
WRITE_ONCE(can->tx_idx, can->tx_idx + 1);
|
||||
|
||||
/* Write header to fifo */
|
||||
iowrite32(packet.header[0],
|
||||
|
|
@ -836,14 +850,7 @@ static netdev_tx_t kvaser_pciefd_start_xmit(struct sk_buff *skb,
|
|||
KVASER_PCIEFD_KCAN_FIFO_LAST_REG);
|
||||
}
|
||||
|
||||
count = FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_CURRENT_MASK,
|
||||
ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NR_PACKETS_REG));
|
||||
/* No room for a new message, stop the queue until at least one
|
||||
* successful transmit
|
||||
*/
|
||||
if (count >= can->can.echo_skb_max || can->can.echo_skb[can->echo_idx])
|
||||
netif_stop_queue(netdev);
|
||||
spin_unlock_irqrestore(&can->echo_lock, irq_flags);
|
||||
netif_subqueue_maybe_stop(netdev, 0, kvaser_pciefd_tx_avail(can), 1, 1);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
|
@ -970,6 +977,8 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie)
|
|||
can->kv_pcie = pcie;
|
||||
can->cmd_seq = 0;
|
||||
can->err_rep_cnt = 0;
|
||||
can->completed_tx_pkts = 0;
|
||||
can->completed_tx_bytes = 0;
|
||||
can->bec.txerr = 0;
|
||||
can->bec.rxerr = 0;
|
||||
|
||||
|
|
@ -983,11 +992,10 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie)
|
|||
tx_nr_packets_max =
|
||||
FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_MAX_MASK,
|
||||
ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NR_PACKETS_REG));
|
||||
can->tx_max_count = min(KVASER_PCIEFD_CAN_TX_MAX_COUNT, tx_nr_packets_max - 1);
|
||||
|
||||
can->can.clock.freq = pcie->freq;
|
||||
can->can.echo_skb_max = min(KVASER_PCIEFD_CAN_TX_MAX_COUNT, tx_nr_packets_max - 1);
|
||||
can->echo_idx = 0;
|
||||
spin_lock_init(&can->echo_lock);
|
||||
can->can.echo_skb_max = roundup_pow_of_two(can->tx_max_count);
|
||||
spin_lock_init(&can->lock);
|
||||
|
||||
can->can.bittiming_const = &kvaser_pciefd_bittiming_const;
|
||||
|
|
@ -1201,7 +1209,7 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie,
|
|||
skb = alloc_canfd_skb(priv->dev, &cf);
|
||||
if (!skb) {
|
||||
priv->dev->stats.rx_dropped++;
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cf->len = can_fd_dlc2len(dlc);
|
||||
|
|
@ -1213,7 +1221,7 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie,
|
|||
skb = alloc_can_skb(priv->dev, (struct can_frame **)&cf);
|
||||
if (!skb) {
|
||||
priv->dev->stats.rx_dropped++;
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
can_frame_set_cc_len((struct can_frame *)cf, dlc, priv->ctrlmode);
|
||||
}
|
||||
|
|
@ -1231,7 +1239,9 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie,
|
|||
priv->dev->stats.rx_packets++;
|
||||
kvaser_pciefd_set_skb_timestamp(pcie, skb, p->timestamp);
|
||||
|
||||
return netif_rx(skb);
|
||||
netif_rx(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kvaser_pciefd_change_state(struct kvaser_pciefd_can *can,
|
||||
|
|
@ -1510,19 +1520,21 @@ static int kvaser_pciefd_handle_ack_packet(struct kvaser_pciefd *pcie,
|
|||
netdev_dbg(can->can.dev, "Packet was flushed\n");
|
||||
} else {
|
||||
int echo_idx = FIELD_GET(KVASER_PCIEFD_PACKET_SEQ_MASK, p->header[0]);
|
||||
int len;
|
||||
u8 count;
|
||||
unsigned int len, frame_len = 0;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (echo_idx != (can->ack_idx & (can->can.echo_skb_max - 1)))
|
||||
return 0;
|
||||
skb = can->can.echo_skb[echo_idx];
|
||||
if (skb)
|
||||
kvaser_pciefd_set_skb_timestamp(pcie, skb, p->timestamp);
|
||||
len = can_get_echo_skb(can->can.dev, echo_idx, NULL);
|
||||
count = FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_CURRENT_MASK,
|
||||
ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NR_PACKETS_REG));
|
||||
if (!skb)
|
||||
return 0;
|
||||
kvaser_pciefd_set_skb_timestamp(pcie, skb, p->timestamp);
|
||||
len = can_get_echo_skb(can->can.dev, echo_idx, &frame_len);
|
||||
|
||||
if (count < can->can.echo_skb_max && netif_queue_stopped(can->can.dev))
|
||||
netif_wake_queue(can->can.dev);
|
||||
/* Pairs with barrier in kvaser_pciefd_start_xmit() */
|
||||
smp_store_release(&can->ack_idx, can->ack_idx + 1);
|
||||
can->completed_tx_pkts++;
|
||||
can->completed_tx_bytes += frame_len;
|
||||
|
||||
if (!one_shot_fail) {
|
||||
can->can.dev->stats.tx_bytes += len;
|
||||
|
|
@ -1638,32 +1650,51 @@ static int kvaser_pciefd_read_buffer(struct kvaser_pciefd *pcie, int dma_buf)
|
|||
{
|
||||
int pos = 0;
|
||||
int res = 0;
|
||||
unsigned int i;
|
||||
|
||||
do {
|
||||
res = kvaser_pciefd_read_packet(pcie, &pos, dma_buf);
|
||||
} while (!res && pos > 0 && pos < KVASER_PCIEFD_DMA_SIZE);
|
||||
|
||||
/* Report ACKs in this buffer to BQL en masse for correct periods */
|
||||
for (i = 0; i < pcie->nr_channels; ++i) {
|
||||
struct kvaser_pciefd_can *can = pcie->can[i];
|
||||
|
||||
if (!can->completed_tx_pkts)
|
||||
continue;
|
||||
netif_subqueue_completed_wake(can->can.dev, 0,
|
||||
can->completed_tx_pkts,
|
||||
can->completed_tx_bytes,
|
||||
kvaser_pciefd_tx_avail(can), 1);
|
||||
can->completed_tx_pkts = 0;
|
||||
can->completed_tx_bytes = 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static u32 kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie)
|
||||
static void kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie)
|
||||
{
|
||||
void __iomem *srb_cmd_reg = KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG;
|
||||
u32 irq = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
|
||||
|
||||
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD0)
|
||||
kvaser_pciefd_read_buffer(pcie, 0);
|
||||
iowrite32(irq, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
|
||||
|
||||
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD1)
|
||||
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD0) {
|
||||
kvaser_pciefd_read_buffer(pcie, 0);
|
||||
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0, srb_cmd_reg); /* Rearm buffer */
|
||||
}
|
||||
|
||||
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD1) {
|
||||
kvaser_pciefd_read_buffer(pcie, 1);
|
||||
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1, srb_cmd_reg); /* Rearm buffer */
|
||||
}
|
||||
|
||||
if (unlikely(irq & KVASER_PCIEFD_SRB_IRQ_DOF0 ||
|
||||
irq & KVASER_PCIEFD_SRB_IRQ_DOF1 ||
|
||||
irq & KVASER_PCIEFD_SRB_IRQ_DUF0 ||
|
||||
irq & KVASER_PCIEFD_SRB_IRQ_DUF1))
|
||||
dev_err(&pcie->pci->dev, "DMA IRQ error 0x%08X\n", irq);
|
||||
|
||||
iowrite32(irq, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
|
||||
return irq;
|
||||
}
|
||||
|
||||
static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can)
|
||||
|
|
@ -1691,29 +1722,22 @@ static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev)
|
|||
struct kvaser_pciefd *pcie = (struct kvaser_pciefd *)dev;
|
||||
const struct kvaser_pciefd_irq_mask *irq_mask = pcie->driver_data->irq_mask;
|
||||
u32 pci_irq = ioread32(KVASER_PCIEFD_PCI_IRQ_ADDR(pcie));
|
||||
u32 srb_irq = 0;
|
||||
u32 srb_release = 0;
|
||||
int i;
|
||||
|
||||
if (!(pci_irq & irq_mask->all))
|
||||
return IRQ_NONE;
|
||||
|
||||
iowrite32(0, KVASER_PCIEFD_PCI_IEN_ADDR(pcie));
|
||||
|
||||
if (pci_irq & irq_mask->kcan_rx0)
|
||||
srb_irq = kvaser_pciefd_receive_irq(pcie);
|
||||
kvaser_pciefd_receive_irq(pcie);
|
||||
|
||||
for (i = 0; i < pcie->nr_channels; i++) {
|
||||
if (pci_irq & irq_mask->kcan_tx[i])
|
||||
kvaser_pciefd_transmit_irq(pcie->can[i]);
|
||||
}
|
||||
|
||||
if (srb_irq & KVASER_PCIEFD_SRB_IRQ_DPD0)
|
||||
srb_release |= KVASER_PCIEFD_SRB_CMD_RDB0;
|
||||
|
||||
if (srb_irq & KVASER_PCIEFD_SRB_IRQ_DPD1)
|
||||
srb_release |= KVASER_PCIEFD_SRB_CMD_RDB1;
|
||||
|
||||
if (srb_release)
|
||||
iowrite32(srb_release, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
|
||||
iowrite32(irq_mask->all, KVASER_PCIEFD_PCI_IEN_ADDR(pcie));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -1733,13 +1757,22 @@ static void kvaser_pciefd_teardown_can_ctrls(struct kvaser_pciefd *pcie)
|
|||
}
|
||||
}
|
||||
|
||||
static void kvaser_pciefd_disable_irq_srcs(struct kvaser_pciefd *pcie)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Masking PCI_IRQ is insufficient as running ISR will unmask it */
|
||||
iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IEN_REG);
|
||||
for (i = 0; i < pcie->nr_channels; ++i)
|
||||
iowrite32(0, pcie->can[i]->reg_base + KVASER_PCIEFD_KCAN_IEN_REG);
|
||||
}
|
||||
|
||||
static int kvaser_pciefd_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
struct kvaser_pciefd *pcie;
|
||||
const struct kvaser_pciefd_irq_mask *irq_mask;
|
||||
void __iomem *irq_en_base;
|
||||
|
||||
pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
|
||||
if (!pcie)
|
||||
|
|
@ -1805,8 +1838,7 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
|
|||
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IEN_REG);
|
||||
|
||||
/* Enable PCI interrupts */
|
||||
irq_en_base = KVASER_PCIEFD_PCI_IEN_ADDR(pcie);
|
||||
iowrite32(irq_mask->all, irq_en_base);
|
||||
iowrite32(irq_mask->all, KVASER_PCIEFD_PCI_IEN_ADDR(pcie));
|
||||
/* Ready the DMA buffers */
|
||||
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0,
|
||||
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
|
||||
|
|
@ -1820,8 +1852,7 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
|
|||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
/* Disable PCI interrupts */
|
||||
iowrite32(0, irq_en_base);
|
||||
kvaser_pciefd_disable_irq_srcs(pcie);
|
||||
free_irq(pcie->pci->irq, pcie);
|
||||
|
||||
err_pci_free_irq_vectors:
|
||||
|
|
@ -1844,35 +1875,26 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void kvaser_pciefd_remove_all_ctrls(struct kvaser_pciefd *pcie)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pcie->nr_channels; i++) {
|
||||
struct kvaser_pciefd_can *can = pcie->can[i];
|
||||
|
||||
if (can) {
|
||||
iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG);
|
||||
unregister_candev(can->can.dev);
|
||||
timer_delete(&can->bec_poll_timer);
|
||||
kvaser_pciefd_pwm_stop(can);
|
||||
free_candev(can->can.dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void kvaser_pciefd_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct kvaser_pciefd *pcie = pci_get_drvdata(pdev);
|
||||
unsigned int i;
|
||||
|
||||
kvaser_pciefd_remove_all_ctrls(pcie);
|
||||
for (i = 0; i < pcie->nr_channels; ++i) {
|
||||
struct kvaser_pciefd_can *can = pcie->can[i];
|
||||
|
||||
/* Disable interrupts */
|
||||
iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
|
||||
iowrite32(0, KVASER_PCIEFD_PCI_IEN_ADDR(pcie));
|
||||
unregister_candev(can->can.dev);
|
||||
timer_delete(&can->bec_poll_timer);
|
||||
kvaser_pciefd_pwm_stop(can);
|
||||
}
|
||||
|
||||
kvaser_pciefd_disable_irq_srcs(pcie);
|
||||
free_irq(pcie->pci->irq, pcie);
|
||||
pci_free_irq_vectors(pcie->pci);
|
||||
|
||||
for (i = 0; i < pcie->nr_channels; ++i)
|
||||
free_candev(pcie->can[i]->can.dev);
|
||||
|
||||
pci_iounmap(pdev, pcie->reg_base);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
|
|
|
|||
|
|
@ -71,12 +71,21 @@ MODULE_AUTHOR("Dario Binacchi <dario.binacchi@amarulasolutions.com>");
|
|||
#define SLCAN_CMD_LEN 1
|
||||
#define SLCAN_SFF_ID_LEN 3
|
||||
#define SLCAN_EFF_ID_LEN 8
|
||||
#define SLCAN_DATA_LENGTH_LEN 1
|
||||
#define SLCAN_ERROR_LEN 1
|
||||
#define SLCAN_STATE_LEN 1
|
||||
#define SLCAN_STATE_BE_RXCNT_LEN 3
|
||||
#define SLCAN_STATE_BE_TXCNT_LEN 3
|
||||
#define SLCAN_STATE_FRAME_LEN (1 + SLCAN_CMD_LEN + \
|
||||
SLCAN_STATE_BE_RXCNT_LEN + \
|
||||
SLCAN_STATE_BE_TXCNT_LEN)
|
||||
#define SLCAN_STATE_MSG_LEN (SLCAN_CMD_LEN + \
|
||||
SLCAN_STATE_LEN + \
|
||||
SLCAN_STATE_BE_RXCNT_LEN + \
|
||||
SLCAN_STATE_BE_TXCNT_LEN)
|
||||
#define SLCAN_ERROR_MSG_LEN_MIN (SLCAN_CMD_LEN + \
|
||||
SLCAN_ERROR_LEN + \
|
||||
SLCAN_DATA_LENGTH_LEN)
|
||||
#define SLCAN_FRAME_MSG_LEN_MIN (SLCAN_CMD_LEN + \
|
||||
SLCAN_SFF_ID_LEN + \
|
||||
SLCAN_DATA_LENGTH_LEN)
|
||||
struct slcan {
|
||||
struct can_priv can;
|
||||
|
||||
|
|
@ -176,6 +185,9 @@ static void slcan_bump_frame(struct slcan *sl)
|
|||
u32 tmpid;
|
||||
char *cmd = sl->rbuff;
|
||||
|
||||
if (sl->rcount < SLCAN_FRAME_MSG_LEN_MIN)
|
||||
return;
|
||||
|
||||
skb = alloc_can_skb(sl->dev, &cf);
|
||||
if (unlikely(!skb)) {
|
||||
sl->dev->stats.rx_dropped++;
|
||||
|
|
@ -281,7 +293,7 @@ static void slcan_bump_state(struct slcan *sl)
|
|||
return;
|
||||
}
|
||||
|
||||
if (state == sl->can.state || sl->rcount < SLCAN_STATE_FRAME_LEN)
|
||||
if (state == sl->can.state || sl->rcount != SLCAN_STATE_MSG_LEN)
|
||||
return;
|
||||
|
||||
cmd += SLCAN_STATE_BE_RXCNT_LEN + SLCAN_CMD_LEN + 1;
|
||||
|
|
@ -328,6 +340,9 @@ static void slcan_bump_err(struct slcan *sl)
|
|||
bool rx_errors = false, tx_errors = false, rx_over_errors = false;
|
||||
int i, len;
|
||||
|
||||
if (sl->rcount < SLCAN_ERROR_MSG_LEN_MIN)
|
||||
return;
|
||||
|
||||
/* get len from sanitized ASCII value */
|
||||
len = cmd[1];
|
||||
if (len >= '0' && len < '9')
|
||||
|
|
@ -456,8 +471,7 @@ static void slcan_bump(struct slcan *sl)
|
|||
static void slcan_unesc(struct slcan *sl, unsigned char s)
|
||||
{
|
||||
if ((s == '\r') || (s == '\a')) { /* CR or BEL ends the pdu */
|
||||
if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
|
||||
sl->rcount > 4)
|
||||
if (!test_and_clear_bit(SLF_ERROR, &sl->flags))
|
||||
slcan_bump(sl);
|
||||
|
||||
sl->rcount = 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user