Skip to content

Commit c757096

Browse files
can: rx-offload: add skb queue for use during ISR
Adding a skb to the skb_queue in rx-offload requires to take a lock. This commit avoids this by adding an unlocked skb queue that is appended at the end of the ISR. Having one lock at the end of the ISR should be OK as the HW is empty, not about to overflow. Link: https://lore.kernel.org/r/[email protected] Tested-by: Oleksij Rempel <[email protected]> Co-developed-by: Kurt Van Dijck <[email protected]> Signed-off-by: Kurt Van Dijck <[email protected]> Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent a08ec5f commit c757096

File tree

6 files changed

+48
-35
lines changed

6 files changed

+48
-35
lines changed

drivers/net/can/dev/rx-offload.c

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/* Copyright (c) 2014 Protonic Holland,
33
* David Jander
4-
* Copyright (C) 2014-2017 Pengutronix,
4+
* Copyright (C) 2014-2021 Pengutronix,
55
* Marc Kleine-Budde <[email protected]>
66
*/
77

@@ -174,10 +174,8 @@ can_rx_offload_offload_one(struct can_rx_offload *offload, unsigned int n)
174174
int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
175175
u64 pending)
176176
{
177-
struct sk_buff_head skb_queue;
178177
unsigned int i;
179-
180-
__skb_queue_head_init(&skb_queue);
178+
int received = 0;
181179

182180
for (i = offload->mb_first;
183181
can_rx_offload_le(offload, i, offload->mb_last);
@@ -191,26 +189,12 @@ int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
191189
if (IS_ERR_OR_NULL(skb))
192190
continue;
193191

194-
__skb_queue_add_sort(&skb_queue, skb, can_rx_offload_compare);
195-
}
196-
197-
if (!skb_queue_empty(&skb_queue)) {
198-
unsigned long flags;
199-
u32 queue_len;
200-
201-
spin_lock_irqsave(&offload->skb_queue.lock, flags);
202-
skb_queue_splice_tail(&skb_queue, &offload->skb_queue);
203-
spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
204-
205-
queue_len = skb_queue_len(&offload->skb_queue);
206-
if (queue_len > offload->skb_queue_len_max / 8)
207-
netdev_dbg(offload->dev, "%s: queue_len=%d\n",
208-
__func__, queue_len);
209-
210-
can_rx_offload_schedule(offload);
192+
__skb_queue_add_sort(&offload->skb_irq_queue, skb,
193+
can_rx_offload_compare);
194+
received++;
211195
}
212196

213-
return skb_queue_len(&skb_queue);
197+
return received;
214198
}
215199
EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_timestamp);
216200

@@ -226,13 +210,10 @@ int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload)
226210
if (!skb)
227211
break;
228212

229-
skb_queue_tail(&offload->skb_queue, skb);
213+
__skb_queue_tail(&offload->skb_irq_queue, skb);
230214
received++;
231215
}
232216

233-
if (received)
234-
can_rx_offload_schedule(offload);
235-
236217
return received;
237218
}
238219
EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_fifo);
@@ -241,7 +222,6 @@ int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
241222
struct sk_buff *skb, u32 timestamp)
242223
{
243224
struct can_rx_offload_cb *cb;
244-
unsigned long flags;
245225

246226
if (skb_queue_len(&offload->skb_queue) >
247227
offload->skb_queue_len_max) {
@@ -252,11 +232,8 @@ int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
252232
cb = can_rx_offload_get_cb(skb);
253233
cb->timestamp = timestamp;
254234

255-
spin_lock_irqsave(&offload->skb_queue.lock, flags);
256-
__skb_queue_add_sort(&offload->skb_queue, skb, can_rx_offload_compare);
257-
spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
258-
259-
can_rx_offload_schedule(offload);
235+
__skb_queue_add_sort(&offload->skb_irq_queue, skb,
236+
can_rx_offload_compare);
260237

261238
return 0;
262239
}
@@ -295,13 +272,33 @@ int can_rx_offload_queue_tail(struct can_rx_offload *offload,
295272
return -ENOBUFS;
296273
}
297274

298-
skb_queue_tail(&offload->skb_queue, skb);
299-
can_rx_offload_schedule(offload);
275+
__skb_queue_tail(&offload->skb_irq_queue, skb);
300276

301277
return 0;
302278
}
303279
EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail);
304280

281+
void can_rx_offload_irq_finish(struct can_rx_offload *offload)
282+
{
283+
unsigned long flags;
284+
int queue_len;
285+
286+
if (skb_queue_empty_lockless(&offload->skb_irq_queue))
287+
return;
288+
289+
spin_lock_irqsave(&offload->skb_queue.lock, flags);
290+
skb_queue_splice_tail_init(&offload->skb_irq_queue, &offload->skb_queue);
291+
spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
292+
293+
queue_len = skb_queue_len(&offload->skb_queue);
294+
if (queue_len > offload->skb_queue_len_max / 8)
295+
netdev_dbg(offload->dev, "%s: queue_len=%d\n",
296+
__func__, queue_len);
297+
298+
can_rx_offload_schedule(offload);
299+
}
300+
EXPORT_SYMBOL_GPL(can_rx_offload_irq_finish);
301+
305302
static int can_rx_offload_init_queue(struct net_device *dev,
306303
struct can_rx_offload *offload,
307304
unsigned int weight)
@@ -312,6 +309,7 @@ static int can_rx_offload_init_queue(struct net_device *dev,
312309
offload->skb_queue_len_max = 2 << fls(weight);
313310
offload->skb_queue_len_max *= 4;
314311
skb_queue_head_init(&offload->skb_queue);
312+
__skb_queue_head_init(&offload->skb_irq_queue);
315313

316314
netif_napi_add(dev, &offload->napi, can_rx_offload_napi_poll, weight);
317315

@@ -373,5 +371,6 @@ void can_rx_offload_del(struct can_rx_offload *offload)
373371
{
374372
netif_napi_del(&offload->napi);
375373
skb_queue_purge(&offload->skb_queue);
374+
__skb_queue_purge(&offload->skb_irq_queue);
376375
}
377376
EXPORT_SYMBOL_GPL(can_rx_offload_del);

drivers/net/can/flexcan.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
11981198
}
11991199
}
12001200

1201+
if (handled)
1202+
can_rx_offload_irq_finish(&priv->offload);
1203+
12011204
return handled;
12021205
}
12031206

drivers/net/can/m_can/m_can.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,9 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)
10581058
}
10591059
}
10601060

1061+
if (cdev->is_peripheral)
1062+
can_rx_offload_irq_finish(&cdev->offload);
1063+
10611064
return IRQ_HANDLED;
10621065
}
10631066

drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2195,8 +2195,10 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
21952195
FIELD_GET(MCP251XFD_REG_INT_IE_MASK,
21962196
priv->regs_status.intf);
21972197

2198-
if (!(intf_pending))
2198+
if (!(intf_pending)) {
2199+
can_rx_offload_irq_finish(&priv->offload);
21992200
return handled;
2201+
}
22002202

22012203
/* Some interrupts must be ACKed in the
22022204
* MCP251XFD_REG_INT register.
@@ -2296,6 +2298,8 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
22962298
} while (1);
22972299

22982300
out_fail:
2301+
can_rx_offload_irq_finish(&priv->offload);
2302+
22992303
netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n",
23002304
err, priv->regs_status.intf);
23012305
mcp251xfd_dump(priv);

drivers/net/can/ti_hecc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,8 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
786786
int_status = hecc_read(priv, HECC_CANGIF0);
787787
}
788788

789+
can_rx_offload_irq_finish(&priv->offload);
790+
789791
return IRQ_HANDLED;
790792
}
791793

include/linux/can/rx-offload.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ struct can_rx_offload {
2020
bool drop);
2121

2222
struct sk_buff_head skb_queue;
23+
struct sk_buff_head skb_irq_queue;
2324
u32 skb_queue_len_max;
2425

2526
unsigned int mb_first;
@@ -48,6 +49,7 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
4849
unsigned int *frame_len_ptr);
4950
int can_rx_offload_queue_tail(struct can_rx_offload *offload,
5051
struct sk_buff *skb);
52+
void can_rx_offload_irq_finish(struct can_rx_offload *offload);
5153
void can_rx_offload_del(struct can_rx_offload *offload);
5254
void can_rx_offload_enable(struct can_rx_offload *offload);
5355

0 commit comments

Comments
 (0)