Skip to content

Commit d509d12

Browse files
author
Paolo Abeni
committed
Merge tag 'linux-can-fixes-for-6.14-20250314' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can
Marc Kleine-Budde says: ==================== pull-request: can 2025-03-14 this is a pull request of 6 patches for net/main. The first patch is by Vincent Mailhol and fixes an out of bound read in strscpy() in the ucan driver. Oliver Hartkopp contributes a patch for the af_can statistics to use atomic access in the hot path. The next 2 patches are by Biju Das, target the rcar_canfd driver and fix the page entries in the AFL list. The 2 patches by Haibo Chen for the flexcan driver fix the suspend and resume functions. linux-can-fixes-for-6.14-20250314 * tag 'linux-can-fixes-for-6.14-20250314' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can: can: flexcan: disable transceiver during system PM can: flexcan: only change CAN state when link up in system PM can: rcar_canfd: Fix page entries in the AFL list dt-bindings: can: renesas,rcar-canfd: Fix typo in pattern properties for R-Car V4M can: statistics: use atomic access in hot path can: ucan: fix out of bound read in strscpy() source ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents daa624d + 52d48a3 commit d509d12

File tree

7 files changed

+84
-77
lines changed

7 files changed

+84
-77
lines changed

Documentation/devicetree/bindings/net/can/renesas,rcar-canfd.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ allOf:
170170
const: renesas,r8a779h0-canfd
171171
then:
172172
patternProperties:
173-
"^channel[5-7]$": false
173+
"^channel[4-7]$": false
174174
else:
175175
if:
176176
not:

drivers/net/can/flexcan/flexcan-core.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2260,14 +2260,19 @@ static int __maybe_unused flexcan_suspend(struct device *device)
22602260

22612261
flexcan_chip_interrupts_disable(dev);
22622262

2263+
err = flexcan_transceiver_disable(priv);
2264+
if (err)
2265+
return err;
2266+
22632267
err = pinctrl_pm_select_sleep_state(device);
22642268
if (err)
22652269
return err;
22662270
}
22672271
netif_stop_queue(dev);
22682272
netif_device_detach(dev);
2273+
2274+
priv->can.state = CAN_STATE_SLEEPING;
22692275
}
2270-
priv->can.state = CAN_STATE_SLEEPING;
22712276

22722277
return 0;
22732278
}
@@ -2278,7 +2283,6 @@ static int __maybe_unused flexcan_resume(struct device *device)
22782283
struct flexcan_priv *priv = netdev_priv(dev);
22792284
int err;
22802285

2281-
priv->can.state = CAN_STATE_ERROR_ACTIVE;
22822286
if (netif_running(dev)) {
22832287
netif_device_attach(dev);
22842288
netif_start_queue(dev);
@@ -2292,12 +2296,20 @@ static int __maybe_unused flexcan_resume(struct device *device)
22922296
if (err)
22932297
return err;
22942298

2295-
err = flexcan_chip_start(dev);
2299+
err = flexcan_transceiver_enable(priv);
22962300
if (err)
22972301
return err;
22982302

2303+
err = flexcan_chip_start(dev);
2304+
if (err) {
2305+
flexcan_transceiver_disable(priv);
2306+
return err;
2307+
}
2308+
22992309
flexcan_chip_interrupts_enable(dev);
23002310
}
2311+
2312+
priv->can.state = CAN_STATE_ERROR_ACTIVE;
23012313
}
23022314

23032315
return 0;

drivers/net/can/rcar/rcar_canfd.c

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -787,22 +787,14 @@ static void rcar_canfd_configure_controller(struct rcar_canfd_global *gpriv)
787787
}
788788

789789
static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
790-
u32 ch)
790+
u32 ch, u32 rule_entry)
791791
{
792-
u32 cfg;
793-
int offset, start, page, num_rules = RCANFD_CHANNEL_NUMRULES;
792+
int offset, page, num_rules = RCANFD_CHANNEL_NUMRULES;
793+
u32 rule_entry_index = rule_entry % 16;
794794
u32 ridx = ch + RCANFD_RFFIFO_IDX;
795795

796-
if (ch == 0) {
797-
start = 0; /* Channel 0 always starts from 0th rule */
798-
} else {
799-
/* Get number of Channel 0 rules and adjust */
800-
cfg = rcar_canfd_read(gpriv->base, RCANFD_GAFLCFG(ch));
801-
start = RCANFD_GAFLCFG_GETRNC(gpriv, 0, cfg);
802-
}
803-
804796
/* Enable write access to entry */
805-
page = RCANFD_GAFL_PAGENUM(start);
797+
page = RCANFD_GAFL_PAGENUM(rule_entry);
806798
rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLECTR,
807799
(RCANFD_GAFLECTR_AFLPN(gpriv, page) |
808800
RCANFD_GAFLECTR_AFLDAE));
@@ -818,13 +810,13 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
818810
offset = RCANFD_C_GAFL_OFFSET;
819811

820812
/* Accept all IDs */
821-
rcar_canfd_write(gpriv->base, RCANFD_GAFLID(offset, start), 0);
813+
rcar_canfd_write(gpriv->base, RCANFD_GAFLID(offset, rule_entry_index), 0);
822814
/* IDE or RTR is not considered for matching */
823-
rcar_canfd_write(gpriv->base, RCANFD_GAFLM(offset, start), 0);
815+
rcar_canfd_write(gpriv->base, RCANFD_GAFLM(offset, rule_entry_index), 0);
824816
/* Any data length accepted */
825-
rcar_canfd_write(gpriv->base, RCANFD_GAFLP0(offset, start), 0);
817+
rcar_canfd_write(gpriv->base, RCANFD_GAFLP0(offset, rule_entry_index), 0);
826818
/* Place the msg in corresponding Rx FIFO entry */
827-
rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLP1(offset, start),
819+
rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLP1(offset, rule_entry_index),
828820
RCANFD_GAFLP1_GAFLFDP(ridx));
829821

830822
/* Disable write access to page */
@@ -1851,6 +1843,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
18511843
unsigned long channels_mask = 0;
18521844
int err, ch_irq, g_irq;
18531845
int g_err_irq, g_recc_irq;
1846+
u32 rule_entry = 0;
18541847
bool fdmode = true; /* CAN FD only mode - default */
18551848
char name[9] = "channelX";
18561849
int i;
@@ -2023,7 +2016,8 @@ static int rcar_canfd_probe(struct platform_device *pdev)
20232016
rcar_canfd_configure_tx(gpriv, ch);
20242017

20252018
/* Configure receive rules */
2026-
rcar_canfd_configure_afl_rules(gpriv, ch);
2019+
rcar_canfd_configure_afl_rules(gpriv, ch, rule_entry);
2020+
rule_entry += RCANFD_CHANNEL_NUMRULES;
20272021
}
20282022

20292023
/* Configure common interrupts */

drivers/net/can/usb/ucan.c

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ union ucan_ctl_payload {
186186
*/
187187
struct ucan_ctl_cmd_get_protocol_version cmd_get_protocol_version;
188188

189-
u8 raw[128];
189+
u8 fw_str[128];
190190
} __packed;
191191

192192
enum {
@@ -424,18 +424,20 @@ static int ucan_ctrl_command_out(struct ucan_priv *up,
424424
UCAN_USB_CTL_PIPE_TIMEOUT);
425425
}
426426

427-
static int ucan_device_request_in(struct ucan_priv *up,
428-
u8 cmd, u16 subcmd, u16 datalen)
427+
static void ucan_get_fw_str(struct ucan_priv *up, char *fw_str, size_t size)
429428
{
430-
return usb_control_msg(up->udev,
431-
usb_rcvctrlpipe(up->udev, 0),
432-
cmd,
433-
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
434-
subcmd,
435-
0,
436-
up->ctl_msg_buffer,
437-
datalen,
438-
UCAN_USB_CTL_PIPE_TIMEOUT);
429+
int ret;
430+
431+
ret = usb_control_msg(up->udev, usb_rcvctrlpipe(up->udev, 0),
432+
UCAN_DEVICE_GET_FW_STRING,
433+
USB_DIR_IN | USB_TYPE_VENDOR |
434+
USB_RECIP_DEVICE,
435+
0, 0, fw_str, size - 1,
436+
UCAN_USB_CTL_PIPE_TIMEOUT);
437+
if (ret > 0)
438+
fw_str[ret] = '\0';
439+
else
440+
strscpy(fw_str, "unknown", size);
439441
}
440442

441443
/* Parse the device information structure reported by the device and
@@ -1314,7 +1316,6 @@ static int ucan_probe(struct usb_interface *intf,
13141316
u8 in_ep_addr;
13151317
u8 out_ep_addr;
13161318
union ucan_ctl_payload *ctl_msg_buffer;
1317-
char firmware_str[sizeof(union ucan_ctl_payload) + 1];
13181319

13191320
udev = interface_to_usbdev(intf);
13201321

@@ -1527,17 +1528,6 @@ static int ucan_probe(struct usb_interface *intf,
15271528
*/
15281529
ucan_parse_device_info(up, &ctl_msg_buffer->cmd_get_device_info);
15291530

1530-
/* just print some device information - if available */
1531-
ret = ucan_device_request_in(up, UCAN_DEVICE_GET_FW_STRING, 0,
1532-
sizeof(union ucan_ctl_payload));
1533-
if (ret > 0) {
1534-
/* copy string while ensuring zero termination */
1535-
strscpy(firmware_str, up->ctl_msg_buffer->raw,
1536-
sizeof(union ucan_ctl_payload) + 1);
1537-
} else {
1538-
strcpy(firmware_str, "unknown");
1539-
}
1540-
15411531
/* device is compatible, reset it */
15421532
ret = ucan_ctrl_command_out(up, UCAN_COMMAND_RESET, 0, 0);
15431533
if (ret < 0)
@@ -1555,7 +1545,10 @@ static int ucan_probe(struct usb_interface *intf,
15551545

15561546
/* initialisation complete, log device info */
15571547
netdev_info(up->netdev, "registered device\n");
1558-
netdev_info(up->netdev, "firmware string: %s\n", firmware_str);
1548+
ucan_get_fw_str(up, up->ctl_msg_buffer->fw_str,
1549+
sizeof(up->ctl_msg_buffer->fw_str));
1550+
netdev_info(up->netdev, "firmware string: %s\n",
1551+
up->ctl_msg_buffer->fw_str);
15591552

15601553
/* success */
15611554
return 0;

net/can/af_can.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,8 @@ int can_send(struct sk_buff *skb, int loop)
287287
netif_rx(newskb);
288288

289289
/* update statistics */
290-
pkg_stats->tx_frames++;
291-
pkg_stats->tx_frames_delta++;
290+
atomic_long_inc(&pkg_stats->tx_frames);
291+
atomic_long_inc(&pkg_stats->tx_frames_delta);
292292

293293
return 0;
294294

@@ -647,8 +647,8 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
647647
int matches;
648648

649649
/* update statistics */
650-
pkg_stats->rx_frames++;
651-
pkg_stats->rx_frames_delta++;
650+
atomic_long_inc(&pkg_stats->rx_frames);
651+
atomic_long_inc(&pkg_stats->rx_frames_delta);
652652

653653
/* create non-zero unique skb identifier together with *skb */
654654
while (!(can_skb_prv(skb)->skbcnt))
@@ -669,8 +669,8 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
669669
consume_skb(skb);
670670

671671
if (matches > 0) {
672-
pkg_stats->matches++;
673-
pkg_stats->matches_delta++;
672+
atomic_long_inc(&pkg_stats->matches);
673+
atomic_long_inc(&pkg_stats->matches_delta);
674674
}
675675
}
676676

net/can/af_can.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ struct receiver {
6666
struct can_pkg_stats {
6767
unsigned long jiffies_init;
6868

69-
unsigned long rx_frames;
70-
unsigned long tx_frames;
71-
unsigned long matches;
69+
atomic_long_t rx_frames;
70+
atomic_long_t tx_frames;
71+
atomic_long_t matches;
7272

7373
unsigned long total_rx_rate;
7474
unsigned long total_tx_rate;
@@ -82,9 +82,9 @@ struct can_pkg_stats {
8282
unsigned long max_tx_rate;
8383
unsigned long max_rx_match_ratio;
8484

85-
unsigned long rx_frames_delta;
86-
unsigned long tx_frames_delta;
87-
unsigned long matches_delta;
85+
atomic_long_t rx_frames_delta;
86+
atomic_long_t tx_frames_delta;
87+
atomic_long_t matches_delta;
8888
};
8989

9090
/* persistent statistics */

net/can/proc.c

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,13 @@ void can_stat_update(struct timer_list *t)
118118
struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
119119
unsigned long j = jiffies; /* snapshot */
120120

121+
long rx_frames = atomic_long_read(&pkg_stats->rx_frames);
122+
long tx_frames = atomic_long_read(&pkg_stats->tx_frames);
123+
long matches = atomic_long_read(&pkg_stats->matches);
124+
long rx_frames_delta = atomic_long_read(&pkg_stats->rx_frames_delta);
125+
long tx_frames_delta = atomic_long_read(&pkg_stats->tx_frames_delta);
126+
long matches_delta = atomic_long_read(&pkg_stats->matches_delta);
127+
121128
/* restart counting in timer context on user request */
122129
if (user_reset)
123130
can_init_stats(net);
@@ -127,35 +134,33 @@ void can_stat_update(struct timer_list *t)
127134
can_init_stats(net);
128135

129136
/* prevent overflow in calc_rate() */
130-
if (pkg_stats->rx_frames > (ULONG_MAX / HZ))
137+
if (rx_frames > (LONG_MAX / HZ))
131138
can_init_stats(net);
132139

133140
/* prevent overflow in calc_rate() */
134-
if (pkg_stats->tx_frames > (ULONG_MAX / HZ))
141+
if (tx_frames > (LONG_MAX / HZ))
135142
can_init_stats(net);
136143

137144
/* matches overflow - very improbable */
138-
if (pkg_stats->matches > (ULONG_MAX / 100))
145+
if (matches > (LONG_MAX / 100))
139146
can_init_stats(net);
140147

141148
/* calc total values */
142-
if (pkg_stats->rx_frames)
143-
pkg_stats->total_rx_match_ratio = (pkg_stats->matches * 100) /
144-
pkg_stats->rx_frames;
149+
if (rx_frames)
150+
pkg_stats->total_rx_match_ratio = (matches * 100) / rx_frames;
145151

146152
pkg_stats->total_tx_rate = calc_rate(pkg_stats->jiffies_init, j,
147-
pkg_stats->tx_frames);
153+
tx_frames);
148154
pkg_stats->total_rx_rate = calc_rate(pkg_stats->jiffies_init, j,
149-
pkg_stats->rx_frames);
155+
rx_frames);
150156

151157
/* calc current values */
152-
if (pkg_stats->rx_frames_delta)
158+
if (rx_frames_delta)
153159
pkg_stats->current_rx_match_ratio =
154-
(pkg_stats->matches_delta * 100) /
155-
pkg_stats->rx_frames_delta;
160+
(matches_delta * 100) / rx_frames_delta;
156161

157-
pkg_stats->current_tx_rate = calc_rate(0, HZ, pkg_stats->tx_frames_delta);
158-
pkg_stats->current_rx_rate = calc_rate(0, HZ, pkg_stats->rx_frames_delta);
162+
pkg_stats->current_tx_rate = calc_rate(0, HZ, tx_frames_delta);
163+
pkg_stats->current_rx_rate = calc_rate(0, HZ, rx_frames_delta);
159164

160165
/* check / update maximum values */
161166
if (pkg_stats->max_tx_rate < pkg_stats->current_tx_rate)
@@ -168,9 +173,9 @@ void can_stat_update(struct timer_list *t)
168173
pkg_stats->max_rx_match_ratio = pkg_stats->current_rx_match_ratio;
169174

170175
/* clear values for 'current rate' calculation */
171-
pkg_stats->tx_frames_delta = 0;
172-
pkg_stats->rx_frames_delta = 0;
173-
pkg_stats->matches_delta = 0;
176+
atomic_long_set(&pkg_stats->tx_frames_delta, 0);
177+
atomic_long_set(&pkg_stats->rx_frames_delta, 0);
178+
atomic_long_set(&pkg_stats->matches_delta, 0);
174179

175180
/* restart timer (one second) */
176181
mod_timer(&net->can.stattimer, round_jiffies(jiffies + HZ));
@@ -214,9 +219,12 @@ static int can_stats_proc_show(struct seq_file *m, void *v)
214219
struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
215220

216221
seq_putc(m, '\n');
217-
seq_printf(m, " %8ld transmitted frames (TXF)\n", pkg_stats->tx_frames);
218-
seq_printf(m, " %8ld received frames (RXF)\n", pkg_stats->rx_frames);
219-
seq_printf(m, " %8ld matched frames (RXMF)\n", pkg_stats->matches);
222+
seq_printf(m, " %8ld transmitted frames (TXF)\n",
223+
atomic_long_read(&pkg_stats->tx_frames));
224+
seq_printf(m, " %8ld received frames (RXF)\n",
225+
atomic_long_read(&pkg_stats->rx_frames));
226+
seq_printf(m, " %8ld matched frames (RXMF)\n",
227+
atomic_long_read(&pkg_stats->matches));
220228

221229
seq_putc(m, '\n');
222230

0 commit comments

Comments
 (0)