Commit dbfca164 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge tag 'linux-can-fixes-for-6.13-20241218' of...

Merge tag 'linux-can-fixes-for-6.13-20241218' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can

Marc Kleine-Budde says:

====================
pull-request: can 2024-12-18

There are 2 patches by Matthias Schiffer for the m_can_pci driver that
handles the m_can cores found on the Intel Elkhart Lake processor.
They fix the initialization and the interrupt handling under high CAN
bus load.

* tag 'linux-can-fixes-for-6.13-20241218' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can:
  can: m_can: fix missed interrupts with m_can_pci
  can: m_can: set init flag earlier in probe
====================

Link: https://patch.msgid.link/20241218121722.2311963-1-mkl@pengutronix.de


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 5c964c8a 87f54c12
Loading
Loading
Loading
Loading
+26 −10
Original line number Diff line number Diff line
@@ -1220,20 +1220,32 @@ static void m_can_coalescing_update(struct m_can_classdev *cdev, u32 ir)
static int m_can_interrupt_handler(struct m_can_classdev *cdev)
{
	struct net_device *dev = cdev->net;
	u32 ir;
	u32 ir = 0, ir_read;
	int ret;

	if (pm_runtime_suspended(cdev->dev))
		return IRQ_NONE;

	ir = m_can_read(cdev, M_CAN_IR);
	m_can_coalescing_update(cdev, ir);
	if (!ir)
		return IRQ_NONE;
	/* The m_can controller signals its interrupt status as a level, but
	 * depending in the integration the CPU may interpret the signal as
	 * edge-triggered (for example with m_can_pci). For these
	 * edge-triggered integrations, we must observe that IR is 0 at least
	 * once to be sure that the next interrupt will generate an edge.
	 */
	while ((ir_read = m_can_read(cdev, M_CAN_IR)) != 0) {
		ir |= ir_read;

		/* ACK all irqs */
		m_can_write(cdev, M_CAN_IR, ir);

		if (!cdev->irq_edge_triggered)
			break;
	}

	m_can_coalescing_update(cdev, ir);
	if (!ir)
		return IRQ_NONE;

	if (cdev->ops->clear_interrupts)
		cdev->ops->clear_interrupts(cdev);

@@ -1695,6 +1707,14 @@ static int m_can_dev_setup(struct m_can_classdev *cdev)
		return -EINVAL;
	}

	/* Write the INIT bit, in case no hardware reset has happened before
	 * the probe (for example, it was observed that the Intel Elkhart Lake
	 * SoCs do not properly reset the CAN controllers on reboot)
	 */
	err = m_can_cccr_update_bits(cdev, CCCR_INIT, CCCR_INIT);
	if (err)
		return err;

	if (!cdev->is_peripheral)
		netif_napi_add(dev, &cdev->napi, m_can_poll);

@@ -1746,11 +1766,7 @@ static int m_can_dev_setup(struct m_can_classdev *cdev)
		return -EINVAL;
	}

	/* Forcing standby mode should be redundant, as the chip should be in
	 * standby after a reset. Write the INIT bit anyways, should the chip
	 * be configured by previous stage.
	 */
	return m_can_cccr_update_bits(cdev, CCCR_INIT, CCCR_INIT);
	return 0;
}

static void m_can_stop(struct net_device *dev)
+1 −0
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ struct m_can_classdev {
	int pm_clock_support;
	int pm_wake_source;
	int is_peripheral;
	bool irq_edge_triggered;

	// Cached M_CAN_IE register content
	u32 active_interrupts;
+1 −0
Original line number Diff line number Diff line
@@ -127,6 +127,7 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
	mcan_class->pm_clock_support = 1;
	mcan_class->pm_wake_source = 0;
	mcan_class->can.clock.freq = id->driver_data;
	mcan_class->irq_edge_triggered = true;
	mcan_class->ops = &m_can_pci_ops;

	pci_set_drvdata(pci, mcan_class);