Merge patch series "can: m_can: set init flag earlier in probe"

This series fixes problems in the m_can_pci driver found on the Intel
Elkhart Lake processor.

Link: https://patch.msgid.link/e247f331cb72829fcbdfda74f31a59cbad1a6006.1728288535.git.matthias.schiffer@ew.tq-group.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
Marc Kleine-Budde 2024-12-18 09:32:14 +01:00
commit 87f54c1219
3 changed files with 28 additions and 10 deletions

View File

@ -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);
/* 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;
/* ACK all irqs */
m_can_write(cdev, M_CAN_IR, ir);
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)

View File

@ -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;

View File

@ -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);