Skip to content

Commit ca965a7

Browse files
Merge patch series "can: m_can: fix pm_runtime and CAN state handling"
Marc Kleine-Budde <[email protected]> says: The first patch fixes a pm_runtime imbalance in the m_can_platform driver. The rest of this series fixes the CAN state handling in the m_can driver: - add the missing state transition from "Error Warning" back to "Error Active" (patch 2) - address the fact that in some SoCs (observed on the STM32MP15) the M_CAN IP core keeps the CAN state and CAN error counters over an internal reset cycle. Set the correct CAN state during ifup and system resume (patches 3+4) Link: https://patch.msgid.link/20250929-m_can-fix-state-handling-v4-0-682b49b49d9a@pengutronix.de Signed-off-by: Marc Kleine-Budde <[email protected]>
2 parents a12f0bc + a9e30a2 commit ca965a7

File tree

2 files changed

+37
-27
lines changed

2 files changed

+37
-27
lines changed

drivers/net/can/m_can/m_can.c

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,9 @@ static int m_can_handle_state_change(struct net_device *dev,
812812
u32 timestamp = 0;
813813

814814
switch (new_state) {
815+
case CAN_STATE_ERROR_ACTIVE:
816+
cdev->can.state = CAN_STATE_ERROR_ACTIVE;
817+
break;
815818
case CAN_STATE_ERROR_WARNING:
816819
/* error warning state */
817820
cdev->can.can_stats.error_warning++;
@@ -841,6 +844,12 @@ static int m_can_handle_state_change(struct net_device *dev,
841844
__m_can_get_berr_counter(dev, &bec);
842845

843846
switch (new_state) {
847+
case CAN_STATE_ERROR_ACTIVE:
848+
cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
849+
cf->data[1] = CAN_ERR_CRTL_ACTIVE;
850+
cf->data[6] = bec.txerr;
851+
cf->data[7] = bec.rxerr;
852+
break;
844853
case CAN_STATE_ERROR_WARNING:
845854
/* error warning state */
846855
cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
@@ -877,30 +886,33 @@ static int m_can_handle_state_change(struct net_device *dev,
877886
return 1;
878887
}
879888

880-
static int m_can_handle_state_errors(struct net_device *dev, u32 psr)
889+
static enum can_state
890+
m_can_state_get_by_psr(struct m_can_classdev *cdev)
881891
{
882-
struct m_can_classdev *cdev = netdev_priv(dev);
883-
int work_done = 0;
892+
u32 reg_psr;
884893

885-
if (psr & PSR_EW && cdev->can.state != CAN_STATE_ERROR_WARNING) {
886-
netdev_dbg(dev, "entered error warning state\n");
887-
work_done += m_can_handle_state_change(dev,
888-
CAN_STATE_ERROR_WARNING);
889-
}
894+
reg_psr = m_can_read(cdev, M_CAN_PSR);
890895

891-
if (psr & PSR_EP && cdev->can.state != CAN_STATE_ERROR_PASSIVE) {
892-
netdev_dbg(dev, "entered error passive state\n");
893-
work_done += m_can_handle_state_change(dev,
894-
CAN_STATE_ERROR_PASSIVE);
895-
}
896+
if (reg_psr & PSR_BO)
897+
return CAN_STATE_BUS_OFF;
898+
if (reg_psr & PSR_EP)
899+
return CAN_STATE_ERROR_PASSIVE;
900+
if (reg_psr & PSR_EW)
901+
return CAN_STATE_ERROR_WARNING;
896902

897-
if (psr & PSR_BO && cdev->can.state != CAN_STATE_BUS_OFF) {
898-
netdev_dbg(dev, "entered error bus off state\n");
899-
work_done += m_can_handle_state_change(dev,
900-
CAN_STATE_BUS_OFF);
901-
}
903+
return CAN_STATE_ERROR_ACTIVE;
904+
}
902905

903-
return work_done;
906+
static int m_can_handle_state_errors(struct net_device *dev)
907+
{
908+
struct m_can_classdev *cdev = netdev_priv(dev);
909+
enum can_state new_state;
910+
911+
new_state = m_can_state_get_by_psr(cdev);
912+
if (new_state == cdev->can.state)
913+
return 0;
914+
915+
return m_can_handle_state_change(dev, new_state);
904916
}
905917

906918
static void m_can_handle_other_err(struct net_device *dev, u32 irqstatus)
@@ -1031,8 +1043,7 @@ static int m_can_rx_handler(struct net_device *dev, int quota, u32 irqstatus)
10311043
}
10321044

10331045
if (irqstatus & IR_ERR_STATE)
1034-
work_done += m_can_handle_state_errors(dev,
1035-
m_can_read(cdev, M_CAN_PSR));
1046+
work_done += m_can_handle_state_errors(dev);
10361047

10371048
if (irqstatus & IR_ERR_BUS_30X)
10381049
work_done += m_can_handle_bus_errors(dev, irqstatus,
@@ -1606,7 +1617,7 @@ static int m_can_start(struct net_device *dev)
16061617
netdev_queue_set_dql_min_limit(netdev_get_tx_queue(cdev->net, 0),
16071618
cdev->tx_max_coalesced_frames);
16081619

1609-
cdev->can.state = CAN_STATE_ERROR_ACTIVE;
1620+
cdev->can.state = m_can_state_get_by_psr(cdev);
16101621

16111622
m_can_enable_all_interrupts(cdev);
16121623

@@ -2492,12 +2503,11 @@ int m_can_class_suspend(struct device *dev)
24922503
}
24932504

24942505
m_can_clk_stop(cdev);
2506+
cdev->can.state = CAN_STATE_SLEEPING;
24952507
}
24962508

24972509
pinctrl_pm_select_sleep_state(dev);
24982510

2499-
cdev->can.state = CAN_STATE_SLEEPING;
2500-
25012511
return ret;
25022512
}
25032513
EXPORT_SYMBOL_GPL(m_can_class_suspend);
@@ -2510,8 +2520,6 @@ int m_can_class_resume(struct device *dev)
25102520

25112521
pinctrl_pm_select_default_state(dev);
25122522

2513-
cdev->can.state = CAN_STATE_ERROR_ACTIVE;
2514-
25152523
if (netif_running(ndev)) {
25162524
ret = m_can_clk_start(cdev);
25172525
if (ret)
@@ -2529,6 +2537,8 @@ int m_can_class_resume(struct device *dev)
25292537
if (cdev->ops->init)
25302538
ret = cdev->ops->init(cdev);
25312539

2540+
cdev->can.state = m_can_state_get_by_psr(cdev);
2541+
25322542
m_can_write(cdev, M_CAN_IE, cdev->active_interrupts);
25332543
} else {
25342544
ret = m_can_start(ndev);

drivers/net/can/m_can/m_can_platform.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ static void m_can_plat_remove(struct platform_device *pdev)
180180
struct m_can_classdev *mcan_class = &priv->cdev;
181181

182182
m_can_class_unregister(mcan_class);
183-
183+
pm_runtime_disable(mcan_class->dev);
184184
m_can_class_free_dev(mcan_class->net);
185185
}
186186

0 commit comments

Comments
 (0)